domenica 22 settembre 2019

Svuotamento Kanban SAP da Excel.

Per lo svuotamento, o comunque il cambio stato, di un contenitore Kanban di SAP ci sono varie transazioni standard.

Ho pensato che sarebbe stato comodo anche un semplice foglio Excel dove l'operatore inserisce il numero cartellino (ID kanban), letto magari con un barcode-reader, poi un tasto per procedere allo svuotamento, con gestione dei messaggi ed eventuali errori di ritorno.

In questo post la spiegazione di come realizzarlo.


Si deve prima costruire un Function Module, chiamabile da remoto, che effettua i controlli, esegue l'operazione e gestisce i messaggi all'operatore.

Definizione del FM Z_EMPTY_KANBAN:


Nota Bene: è necessario definire che il modulo sia accessibile da remoto.

Importazione:


Esportazione:


Più sotto trovate il codice.

Questo è come si presenta il foglio Excel all'avvio (una macro automatica cancella eventuali dati precedenti)


L'operatore inserisce il suo CID (eventualmente da togliere se non codificato in SAP), l'ID del Kanban e preme il pulsante.


La macro VBA esegue:

  1. Logon al sistema SAP.
  2. Chiama il FM Z_EMPTY_KANBAN.
  3. Gestione messaggi di ritorno.

Questo il messaggio di esito corretto, dove viene riportato materiale, descrizione e quantità Kanban.


Il file Excel contiene un foglio dove devono essere inseriti i dati di logon:



Potete scaricare il foglio excel di esempio: Z_SVUOTA_KANBAN.xls

Password di protezione foglio: kanban

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.

Elenco codice VBA Excel:

Public ok_login As Integer

Sub main()

Dim R3 As Object

Set R3 = CreateObject("SAP.Functions")

zlogin R3

If ok_login = 0 Then
  callRFC R3
  R3.Connection.Logoff
End If

End Sub

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

'R3.Connection.ApplicationServer = ""
'R3.Connection.SystemNumber = nn
'R3.Connection.User = ""
'R3.Connection.Password = ""
'R3.Connection.client = nnn
'R3.Connection.Language = ""

' Logon a SAP e controllo se la connessione è stabilita
If R3.Connection.Logon(0, True) <> True Then
  MsgBox "Impossibile collegarsi a SAP!" 'Messaggio di errore
  ok_login = 1
  Exit Sub
Else
  'MsgBox "OK: Collegato a SAP!"
  ok_login = 0
End If

End Sub

Sub Auto_Open()
'
' Auto_Open Macro
' Macro all'avvio
'
' Pulisco celle
Sheets("Kanban").Select
Range("B1:B2").Select
Selection.ClearContents
Range("D1:D2").Select
Selection.ClearContents
Range("B1:B1").Select

End Sub

Sub callRFC(R3 As Object)

  ' Cancello esito precedente
  Sheets("Kanban").Select
  Range("D2:D2").Select
  Selection.ClearContents
    
  Range("B2:B2").Select
  
  ' Definizione funzione RFC
  Set myFuncRFC = R3.Add("Z_EMPTY_KANBAN")

  ' Definizione degli oggetti di interfaccia
  Dim i_PKKEY As Object
  Dim i_PERNR As Object

  ' Parametri in ingresso
  Set i_PKKEY = myFuncRFC.exports("I_PKKEY")
  Set i_PERNR = myFuncRFC.exports("I_PERNR")

  ' Valorizzo i parametri in ingresso con i campi del foglio
  i_PKKEY.Value = Sheets("Kanban").Cells(2, 2).Value
  i_PERNR.Value = Sheets("Kanban").Cells(1, 2).Value
  
  wa_ID = Sheets("Kanban").Cells(2, 2).Value
  wa_CID = Sheets("Kanban").Cells(1, 2).Value
  
  If wa_CID = "" Then
    MsgBox "Inserire CID operatore!"
    Range("B1:B1").Select
    Exit Sub
  End If
  
  If wa_ID = "" Then
    MsgBox "Inserire ID Kanban!"
    Exit Sub
  End If
  
  ' Chiamata alla funzione SAP
  If myFuncRFC.call = False Then
    MsgBox myFuncRFC.Exception
    Exit Sub
  End If

  ' Ricevo i valori di ritorno dalla funzione
  Set O_ESITO = myFuncRFC.imports("O_ESITO")
  Set O_MATNR = myFuncRFC.imports("O_MATNR")
  Set O_MAKTX = myFuncRFC.imports("O_MAKTX")
  Set O_BEHMG = myFuncRFC.imports("O_BEHMG")
  Set O_NOME = myFuncRFC.imports("O_NOME")
  Set O_MESSAGGIO = myFuncRFC.imports("O_MESSAGGIO")
  
  ' Porto i valori di ritorno nel foglio
  Sheets("Kanban").Cells(1, 4) = O_NOME
  Sheets("Kanban").Cells(2, 4) = O_MESSAGGIO
  
  Dim w_mess As String
    
  If O_ESITO = 0 Then
    w_mess = O_MESSAGGIO & vbCrLf & vbCrLf & "Materiale : " & O_MATNR & vbCrLf & "Descrizione: " & O_MAKTX & vbCrLf & "Quantità : " & O_BEHMG
  Else
    w_mess = O_MESSAGGIO
  End If
  
  MsgBox w_mess   'Messaggio all'operatore

  ' Se esito positivo cancello ID Kanban
  If O_ESITO = 0 Then
    Sheets("Kanban").Select
    Range("B2:B2").Select
    Selection.ClearContents
  End If

  Set myFuncRFC = Nothing
    
End Sub


Codice FM Z_EMPTY_KANBAN

FUNCTION z_empty_kanban.
*"----------------------------------------------------------------------
*"*"Interfaccia locale:
*"  IMPORTING
*"     VALUE(I_PKKEY) TYPE  PKKEY
*"     VALUE(I_PERNR) TYPE  PERSNO OPTIONAL
*"  EXPORTING
*"     VALUE(O_ESITO) TYPE  CHAR01
*"     VALUE(O_MATNR) TYPE  MATNR
*"     VALUE(O_MAKTX) TYPE  MAKTX
*"     VALUE(O_BEHMG) TYPE  CHAR20
*"     VALUE(O_NOME) TYPE  CHAR40
*"     VALUE(O_MESSAGGIO) TYPE  CHAR80
*"----------------------------------------------------------------------
* Autore     : Fabio Giacobbe - 26/08/2019                             |
* Descrizione: Dichiarazione di svuotamento Kanban pieno               |
*----------------------------------------------------------------------+
* Modifiche  :            by                                           |
* Note       :                                                         |
*----------------------------------------------------------------------+
* parametri
*   ingresso:
*      I_PKKEY : ID kanban
*      I_PERNR : C.I.D.
*
*   uscita:
*      O_ESITO: 0 = Operazione eseguita correttamente.
*               1 = Errore di lettura dati.
*               2 = Kanban non PIENO.
*               3 = Il Kanban non può cambiare stato per tempo attesa
*               4 = Lock di dati
*               9 = errore generico.
*      O_MATNR: Codice materiale
*      O_MAKTX: Testo breve materiale
*      O_BEHMG: Qtà Kanban
*      O_NOME : Nome Operatore
*      O_MESSAGGIO: Messaggio
*----------------------------------------------------------------------+
  DATA: wa_pkhd       LIKE pkhd,
        wa_pkps       LIKE pkps,
        wa_tpk01      LIKE tpk01,
        wa_tpk02      LIKE tpk02,
        wa_tpk03      LIKE tpk03,
        wa_tpk00      LIKE tpk00,
        wa_qta_int    TYPE p DECIMALS 0,
        wa_nextstatus LIKE pkps-pkbst,
        return        LIKE bapiret2,
        kanban_pieno  TYPE pkbst VALUE '5',
        l_nachn       TYPE pa0002-nachn,
        l_vorna       TYPE pa0002-vorna.

* Lettura ID cartellino Kanban
  SELECT SINGLE * FROM pkps INTO wa_pkps
                 WHERE pkkey = i_pkkey.
  IF sy-subrc NE 0.
    MESSAGE ID 'ZPP_KANBAN' TYPE 'S' NUMBER 004 WITH i_pkkey INTO o_messaggio.
    o_esito = 1.
    EXIT.
  ENDIF.

* Lettura ciclo di controllo Kanban
  SELECT SINGLE * FROM pkhd INTO wa_pkhd
                 WHERE pknum = wa_pkps-pknum.
  IF sy-subrc NE 0.
    MESSAGE ID 'ZPP_KANBAN' TYPE 'S' NUMBER 015 WITH wa_pkps-pknum INTO o_messaggio.
    o_esito = 1.
    EXIT.
  ENDIF.

* Verifico CID operatore
  IF i_pernr IS NOT INITIAL.
    SELECT SINGLE nachn vorna INTO (l_nachn,l_vorna) FROM pa0002
        WHERE pernr EQ i_pernr
          AND sprps EQ ''         "Non bloccato
          AND begda LE sy-datum AND endda GE sy-datum.
    IF sy-subrc = 0.
      CONCATENATE l_nachn l_vorna
             INTO o_nome SEPARATED BY space.
    ELSE.
      MESSAGE ID 'ZPP_KANBAN' TYPE 'S' NUMBER 017 WITH i_pernr INTO o_messaggio.
      o_esito = 1.
      EXIT.
    ENDIF.
  ENDIF.

  o_matnr = wa_pkhd-matnr.

* Riporto q.tà kanban in uscita usando un campo di testo
  wa_qta_int = wa_pkhd-behmg.
  IF wa_qta_int = wa_pkhd-behmg.
    WRITE wa_qta_int    TO o_behmg.
  ELSE.
    WRITE wa_pkhd-behmg TO o_behmg.
  ENDIF.
  CONDENSE o_behmg.

* ricerco descrizione per lingua logon
  SELECT SINGLE maktx FROM makt INTO o_maktx
                     WHERE matnr = o_matnr
                       AND spras = sy-langu.
  IF sy-subrc <> 0.
    IF sy-langu <> 'IT'.
      IF sy-langu <> 'EN'.
        SELECT SINGLE maktx FROM makt INTO o_maktx
                           WHERE matnr = o_matnr
                             AND spras = 'EN'.
        IF sy-subrc <> 0.
          SELECT SINGLE maktx FROM makt INTO o_maktx
                             WHERE matnr = o_matnr
                               AND spras = 'IT'.
        ENDIF.
      ENDIF.
    ENDIF.
  ENDIF.

* controllo stato
  IF wa_pkps-pkbst NE kanban_pieno.
    DATA tab_a LIKE  dd07v OCCURS 0 WITH HEADER LINE.
    DATA tab_n LIKE  dd07v OCCURS 0 WITH HEADER LINE.
    CALL FUNCTION 'DD_DOMA_GET'
      EXPORTING
        domain_name   = 'PKBST'
      TABLES
        dd07v_tab_a   = tab_a
        dd07v_tab_n   = tab_n
      EXCEPTIONS
        illegal_value = 1
        op_failure    = 2
        OTHERS        = 3.
    LOOP AT tab_a WHERE domvalue_l = kanban_pieno.

    ENDLOOP.

    MESSAGE ID 'ZPP_KANBAN' TYPE 'S' NUMBER 005
                            WITH i_pkkey kanban_pieno tab_a-ddtext
                            INTO o_messaggio.
    o_esito = 2.
    EXIT.
  ENDIF.

* controllo che lo stato sia modificabile
  CALL FUNCTION 'Z_CHECK_KANBAN'
    EXPORTING
      i_pkkey = i_pkkey
    IMPORTING
      esito   = o_esito.
  IF o_esito <> 0.
    MESSAGE ID 'ZPP_KANBAN' TYPE 'S' NUMBER 016
                            INTO o_messaggio.
    o_esito = 3.
    EXIT.
  ENDIF.

* Verifico che il Kanban non abbia blocchi
  CALL FUNCTION 'PK_ENQUEUE_KANBAN'
    EXPORTING
      i_scope       = '2'
      i_pkkey       = i_pkkey
    EXCEPTIONS
      error_message = 1.
  IF sy-subrc <> 0.
    MESSAGE ID 'ZPP_KANBAN' TYPE 'E' NUMBER 014 WITH i_pkkey INTO o_messaggio.
    o_esito = 4.
    EXIT.
  ENDIF.

* Trovo lo stato successivo previsto da ciclo Kanban
  IF NOT wa_pkhd-pkste IS INITIAL.
    SELECT SINGLE * FROM tpk01 INTO wa_tpk01
                   WHERE werks EQ wa_pkhd-werks
                     AND pkste EQ wa_pkhd-pkste.
    MOVE-CORRESPONDING wa_tpk01 TO wa_tpk00.
  ELSEIF NOT wa_pkhd-pkstf IS INITIAL.
    SELECT SINGLE * FROM tpk02 INTO wa_tpk02
           WHERE werks EQ wa_pkhd-werks
             AND pkstf EQ wa_pkhd-pkstf.
    MOVE-CORRESPONDING wa_tpk02 TO wa_tpk00.
  ELSEIF NOT wa_pkhd-pkstu IS INITIAL.
    SELECT SINGLE * FROM tpk03 INTO wa_tpk03
                   WHERE werks EQ wa_pkhd-werks
                     AND  pkstu EQ wa_pkhd-pkstu.
    MOVE-CORRESPONDING wa_tpk03 TO wa_tpk00.
  ENDIF.

  CALL FUNCTION 'PK_GET_STATUS'
    EXPORTING
      pksae_iv      = wa_tpk01-pksae
      pkhd_is       = wa_pkhd
      pkps_is       = wa_pkps
      tpk00_is      = wa_tpk00
*     no_status_restr_iv = exclude_status_restriction
    IMPORTING
      nextstatus_ev = wa_nextstatus
    EXCEPTIONS
      error_message = 1.

  IF wa_nextstatus IS INITIAL.
    MESSAGE ID 'ZPP_KANBAN' TYPE 'S' NUMBER 019 INTO o_messaggio.
    o_esito = 9.
  ENDIF.

* chiamo FM per cambio stato
  CALL FUNCTION 'BAPI_KANBAN_CHANGESTATUS1'
    EXPORTING
      kanbanidnumber = i_pkkey
      nextstatus     = wa_nextstatus
    IMPORTING
      return         = return.
  IF return-type IS INITIAL.
    MESSAGE ID 'ZPP_KANBAN' TYPE 'S' NUMBER 018 INTO o_messaggio.
    o_esito = 0.
    CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
      EXPORTING
        wait = 'X'.

  ELSE.
    MESSAGE ID return-id
                TYPE return-type
    NUMBER return-number
    WITH
    return-message_v1
    return-message_v2
    return-message_v3
    return-message_v4 INTO return-message.
    o_messaggio = return-message.
    o_esito = 9.

  ENDIF.

ENDFUNCTION.

Codifica messaggi:

004 Il Numero Identificativo &1 non esiste
005 Identificativo &1 non ha lo stato &2 &3
014 ID &1 blocc.!
015 Ciclo Kanban &1 inesistente.
016 Stato non modificabile per tempo attesa.
017 C.I.D. &1 non trovato.
018 Operazione eseguita correttamente.
019 Errore generico.

Nota: all'interno del codice uso una funzione Z (Z_CHECK_KANBAN) che controlla se è possibile effettuare il cambio stato di un cartellino verificando il tempo minimo di attesa previsto. (Vedi questo post per come è definito). Si può anche commentare tutta questa parte se non si vuole definire il FM di controllo.

Nessun commento:

Posta un commento