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