venerdì 12 maggio 2017

Lettura Stock SAP da foglio Excel.

Volevo preparare un foglio Excel che, dato un codice materiale, premendo un pulsante visualizzi le giacenze di magazzino per una divisione.

Pensavo che esistesse una funzione o una BAPI da chiamare (simile alla MMBE per intenderci), ma non sono riuscito a trovare qualcosa di adatto. Pertanto mi sono costruito una semplice funzione che restituisce una tabella con le giacenze di magazzino. Ho operato alcune semplificazioni, che descriverò dopo, se avete delle necessità differenti potete utilizzare il mio codice come modello e modificarlo secondo i vostri scopi.

Parte 1 : Costruzione Function Module


Nome : Z_READ_STOCK

questi i parametri di ingresso, di uscita e le tabelle di interfaccia:




Da notare che, se volete poter chiamare la funzione via RFC, si deve impostare come "Modulo accessibile in remoto"


questo il codice

FUNCTION z_read_stock.
*"----------------------------------------------------------------------
*"*"Interfaccia locale:
*"  IMPORTING
*"     VALUE(I_WERKS) TYPE  WERKS_D
*"     VALUE(I_MATNR) TYPE  MATNR
*"     VALUE(I_LGORT) TYPE  LGORT_D OPTIONAL
*"  EXPORTING
*"     VALUE(O_MAKTX) TYPE  MAKTX
*"  TABLES
*"      CNSTOCK STRUCTURE  CNSTOCK
*"----------------------------------------------------------------------
* Autore     : Fabio Giacobbe - 11/05/2017                             |
* Descrizione: FM per lettura stock per chiamata da foglio Excel.      |
*----------------------------------------------------------------------+
* Modifiche  :            by                                           |
* Note       :                                                         |
*----------------------------------------------------------------------+
* parametri
*   ingresso:
*      I_WERKS : Divisione
*      I_MATNR : Materiale
*      I_LGORT : Magazzino (facoltativo)
*   uscita:
*      O_MAKTX : Descrizione materiale in lingua di logon
*   tabelle:
*      CNSTOCK : Struttura per riepilogo stock
*----------------------------------------------------------------------+
* Descrizione funzionamento:
*   Trova giacenza di magazzino (Libera, in CQ e bloccata) nella MARD e
*   cerca conto deposito fornitore, conti lavoro, deposito presso
*   clienti e materiale a commessa
*----------------------------------------------------------------------+
  Data: wa_CNSTOCK LIKE CNSTOCK.

  RANGES: s_lgort FOR mard-lgort.

* Se viene passato il magazzino popolo il range per la select
  IF NOT i_lgort IS INITIAL.
    s_lgort-sign   = 'I'.
    s_lgort-option = 'EQ'.
    s_lgort-low    = i_lgort.
    APPEND s_lgort.
  ENDIF.

* Trovo descrizione
  SELECT SINGLE maktx FROM makt INTO o_maktx
                     WHERE matnr = i_matnr
                       AND spras = sy-langu.

* Trovo unità di misura di base
  SELECT SINGLE meins FROM mara INTO cnstock-meins
                     WHERE matnr = i_matnr.

* scrivo UM in un campo char per poterla utilizzare nel foglio Excel
  WRITE cnstock-meins to cnstock-PSPNR.

* leggo MARD
  SELECT lgort labst insme speme FROM mard
                           INTO CORRESPONDING FIELDS OF cnstock
                          WHERE werks  = i_werks
                            AND matnr  = i_matnr
                            AND lgort IN s_lgort
                            AND ( labst > 0 OR
                                  insme > 0 OR
                                  speme > 0   ).
    APPEND cnstock.
  ENDSELECT.

* leggo MKOL per conto deposito fornitore
  CLEAR: cnstock-INSME, cnstock-INSME, cnstock-SPEME.

  SELECT SLABS SINSM SSPEM FROM MKOL
                           INTO (wa_cnstock-LABST, wa_cnstock-INSME, wa_cnstock-SPEME)
                          WHERE werks  = i_werks
                            AND matnr  = i_matnr
                            AND lgort IN s_lgort
                            AND sobkz  = 'K'
                            AND ( SLABS > 0 OR
                                  SINSM > 0 OR
                                  SSPEM > 0   ).
    add wa_cnstock-LABST to cnstock-LABST.
    add wa_cnstock-INSME to cnstock-INSME.
    add wa_cnstock-SPEME to cnstock-SPEME.
  ENDSELECT.
  IF sy-subrc = 0.
    cnstock-LGORT = 'C/D'.
    APPEND cnstock.
  ENDIF.

* trovo il materiale in conto lavoro presso i fornitori
  CLEAR: cnstock-INSME, cnstock-INSME, cnstock-SPEME.

  SELECT LBLAB LBINS FROM mslb
                     INTO (wa_cnstock-LABST, wa_cnstock-INSME)
                    WHERE werks  = i_werks
                      AND matnr  = i_matnr
                      AND sobkz EQ 'O'
                      AND ( LBLAB > 0 OR
                            LBINS > 0   ).
    add wa_cnstock-LABST to cnstock-LABST.
    add wa_cnstock-INSME to cnstock-INSME.
  ENDSELECT.
  IF sy-subrc = 0.
    cnstock-LGORT = 'C/L'.
    APPEND cnstock.
  ENDIF.

* trovo il materiale in deposito da clienti
  CLEAR: cnstock-INSME, cnstock-INSME, cnstock-SPEME.

  SELECT KULAB KUINS FROM msku
                     INTO (wa_cnstock-LABST, wa_cnstock-INSME)
                    WHERE werks  = i_werks
                      AND matnr  = i_matnr
                      AND sobkz EQ 'W'
                      AND ( KULAB > 0 OR
                            KUINS > 0   ).
    add wa_cnstock-LABST to cnstock-LABST.
    add wa_cnstock-INSME to cnstock-INSME.
  ENDSELECT.
  IF sy-subrc = 0.
    cnstock-LGORT = 'CDCL'.
    APPEND cnstock.
  ENDIF.

* trovo il materiale su commessa
  CLEAR: cnstock-INSME, cnstock-INSME, cnstock-SPEME.

  SELECT KALAB KAINS KASPE FROM mska
                           INTO (wa_cnstock-LABST, wa_cnstock-INSME, wa_cnstock-SPEME)
                          WHERE werks  = i_werks
                            AND matnr  = i_matnr
                            AND sobkz EQ 'E'
                            AND ( KALAB > 0 OR
                                  KAINS > 0 OR
                                  KASPE > 0   ).
    add wa_cnstock-LABST to cnstock-LABST.
    add wa_cnstock-INSME to cnstock-INSME.
    add wa_cnstock-SPEME to cnstock-SPEME.
  ENDSELECT.
  IF sy-subrc = 0.
    cnstock-LGORT = 'Comm'.
    APPEND cnstock.
  ENDIF.

ENDFUNCTION.

Queste le semplificazioni di cui parlavo:

  • Ci sono molte altre giacenze: in transito, progetto, resi, etc. Per semplicità, e visto che praticamente noi usiamo solo questi, ho considerato solo gli stock: utilizzo libero, in controllo qualità, bloccato.
  • Per esportare l'unità di misura convertita in modo leggibile mi sono appoggiato al campo PSPNR della struttura CNSTOCK che avrebbe un altro uso (Numero del documento commerciale).
  • Il conto deposito fornitore e lo stock su ordine cliente (a commessa) hanno il dettaglio per magazzino, io invece ho raggruppato tutto come fossero un magazzino separato.
  • Da notare che se non viene specificato il magazzino vengono visualizzate le quantità di tutti, mentre se si specifica un magazzino l'output è solo di quello.
  • Questi i raggruppamenti che ho fatto e vengono mostrati come magazzini separati:

    C/D  = conto deposito fornitori  (di proprietà del fornitore)
    CDCL = conto deposito presso clienti (ns. materiale presso clienti)
    Comm = materiali a commessa 
    C/L  = Conto Lavoro presso fornitori


Parte 2: Foglio Excel 


Nome File: Read_Stock_SAP.xls

Nel foglio Logon inserire i vostri dati di accesso:


L'operatore deve inserire il codice materiale (la divisione si può lasciare fissa) e premere il pulsante per la lettura dei dati in SAP. Se viene inserito anche il magazzino si cerca la giacenza solo in quel magazzino.


Questa la macro associata al pulsante:

Sub main()

Dim R3 As Object

Set R3 = CreateObject("SAP.Functions")

zlogin R3

readStock R3

R3.Connection.Logoff

End Sub

questa la funzione di login:

Sub zlogin(R3 As Object)

R3.Connection.ApplicationServer = Sheets("Logon").Cells(1, 2).Value
R3.Connection.SystemNumber = Sheets("Logon").Cells(2, 2).Value
R3.Connection.User = Sheets("Logon").Cells(3, 2).Value
R3.Connection.Password = Sheets("Logon").Cells(4, 2).Value
R3.Connection.client = Sheets("Logon").Cells(5, 2).Value
R3.Connection.Language = Sheets("Logon").Cells(6, 2).Value

'Finally, try to logon to the specified system and check if the connection established
If R3.Connection.Logon(0, True) <> True Then
  MsgBox "Cannot Log on to SAP" 'Issue message if cannot logon
  Exit Sub
Else
  'MsgBox "Logged on to SAP!"
End If

End Sub

Questa la funzione di chiamata FM e scrittura dei dati nel foglio:

Sub readStock(R3 As Object)

  ' Cancello dati precedenti
  Sheets("Stock").Select
  Range("C6:F100").Select
  Selection.ClearContents
  Range("C2:F2").Select
  Selection.ClearContents
  Range("B2:B2").Select
    
  ' Definizione funzione per leggere Stock
  Set myFuncZRS = R3.Add("Z_READ_STOCK")

  ' Definizione degli oggetti di interfaccia
  Dim i_werks, i_matnr, i_lgort, o_maktx, CNSTOCK  As Object

  ' Parametri in ingresso
  Set i_werks = myFuncZRS.exports("I_WERKS")
  Set i_matnr = myFuncZRS.exports("I_MATNR")
  Set i_lgort = myFuncZRS.exports("I_LGORT")

  ' Valorizzo i parametri in ingresso con i campi del foglio
  i_werks.Value = Sheets("Stock").Cells(1, 2).Value
  i_matnr.Value = Sheets("Stock").Cells(2, 2).Value
  i_lgort.Value = Sheets("Stock").Cells(3, 2).Value

  ' Chiamata alla funzione SAP
  If myFuncZRS.call = False Then
    MsgBox myFuncZRS.Exception
  End If

  ' Ricevo i valori di ritorno dalla funzione
  Set o_maktx = myFuncZRS.imports("O_MAKTX")
  Set CNSTOCK = myFuncZRS.tables("CNSTOCK")

  ' Riporto nel foglio la descrizione del materiale
  Sheets("Stock").Cells(2, 3) = o_maktx.Value
  
  ' Salvo data e ora della lettura
  Sheets("Stock").Cells(4, 2) = Now
    
  For j = 1 To CNSTOCK.RowCount
    
    Sheets("Stock").Cells(j + 5, 3) = CNSTOCK.Value(j, "LGORT")      'Magazzino
    Sheets("Stock").Cells(j + 5, 4) = Val(CNSTOCK.Value(j, "LABST")) 'Utilizzo libero
    Sheets("Stock").Cells(j + 5, 5) = Val(CNSTOCK.Value(j, "INSME")) 'Controllo Qualità
    Sheets("Stock").Cells(j + 5, 6) = Val(CNSTOCK.Value(j, "SPEME")) 'Bloccato
        
    Sheets("Stock").Cells(2, 6) = CNSTOCK.Value(j, "PSPNR")          'UM

  Next
    
  Set myFuncZRS = Nothing
    
End Sub

Potete scaricare il foglio excel di esempio: Read_Stock_SAP.xls

Alcune annotazioni generali:


  • Di norma includo le informazioni di Logon nel codice VBA e poi lo proteggo con una password poichè altrimenti sono in chiaro. Anche così non è che sia una protezione molto solida, ma mi sembra il minimo.
  • nel PC deve essere installata la SAPGUI (che contiene le DLL per poter attivare il collegamento).
  • se nel server SAP è attivo il firewall deve essere aperta in ingresso la porta tcp 33nn (nn=<system number>), normalmente per le connessioni sapgui è aperta la 32nn.
  • consiglio di definire un utente di tipo S (servizio) che, in pratica, non può effettuare il logon da GUI.

Nessun commento:

Posta un commento