Wednesday, 5 November 2025

SAP ABAP - Upload Count PID dengan BAPI

Upload Count PID dengan BAPI di ABAP — Contoh Program YMMC100

Upload Count PID dengan BAPI di ABAP — Program YMMC100

ABAP BAPI_MATPHYSINV_COUNT Estimated reading time: 6–8 menit

Ringkasan (TL;DR): Program YMMC100 membaca data count fisik (PID) dari file Excel, memvalidasi tiap baris (material, dokumen PID, status item), menampilkan hasil di ALV, lalu melakukan post count ke SAP lewat BAPI_MATPHYSINV_COUNT.

Outline

  1. Penjelasan singkat fungsi program
  2. Struktur source (includes & main)
  3. Penjelasan tiap bagian include
  4. Format Excel yang diharapkan
  5. Flow proses (read → validate → display → post)
  6. Best practices & troubleshooting
  7. Code (lengkap)
  8. Kesimpulan & CTA

1. Fungsi singkat program

Program YMMC100 otomatis mengunggah hasil count PID dari Excel ke SAP. Alur utamanya:

  • Upload file Excel (.xls) ke internal table dengan ALSM_EXCEL_TO_INTERNAL_TABLE.
  • Mapping kolom Excel ke struktur lt_data.
  • Validasi master data (material, dokumen PID, status already-counted).
  • Tampilkan hasil di ALV untuk review user.
  • Jika OK, panggil BAPI_MATPHYSINV_COUNT untuk post count.

2. Struktur source

Program utama memanggil beberapa include:

  • YMMC100_TOP : type, data deklarasi, GUI objects
  • YMMC100_SEL : selection screen & F4
  • YMMC100_F01 : status screen & user command
  • YMMC100_F02 : read excel & validation
  • YMMC100_F03 : ALV display setup
  • YMMC100_F04 : posting ke BAPI

3. Penjelasan tiap include

Catatan teknis singkat: Kode ini menggunakan ALSM_EXCEL_TO_INTERNAL_TABLE sehingga cocok untuk file .xls klasik. Untuk .xlsx gunakan cl_fdt_xl_spreadsheet atau sejenis.

4. Format Excel yang diharapkan

Kolom (mulai dari kolom A) minimal:

  • IBLNR (Physical Inv Doc)
  • GJAHR (Fiscal year)
  • XLDAT (Count date) — format: DD-MM-YYYY atau sesuai parsing di kode
  • ZEILI (Item)
  • MATNR (Material)
  • CHARG (Batch)
  • MENGE (Entry count)
  • MEINS (UoM)
  • XNULL (Zero-count indicator — optional)

Header di baris 1, data mulai baris 2 (default p_line = 2).

5. Alur proses (detail)

  1. User pilih file → tekan READ.
  2. Program baca Excel → mapping ke ls_data.
  3. Validasi material (MAKT), dokumen PID (IKPF), dan status item (ISEG-xzael).
  4. Jika ada error, diberi ikon error dan message di ALV.
  5. User review di ALV → tekan POST untuk upload tiap dokumen via BAPI.

6. Best practices & troubleshooting

  • Jika user pakai .xlsx, migrasi ke cl_fdt_xl_spreadsheet.
  • Pastikan conversion ALPHA sesuai untuk material dan dokumen.
  • Tampilkan semua pesan BAPI saat error untuk debug yang lengkap.
  • Test di sandbox/QAS sebelum produksi.

7. Code (lengkap — copy-paste ready)

Paste semua block di bawah ke program & include sesuai nama.

Program utama: YMMC100

&*&---------------------------------------------------------------------*&
&*& Report YMMC100
&*&---------------------------------------------------------------------*&
&*&---------------------------------------------------------------------*&
REPORT ymmc100.

INCLUDE ymmc100_top.
INCLUDE ymmc100_sel.
INCLUDE ymmc100_f01.
INCLUDE ymmc100_f02.
INCLUDE ymmc100_f03.
INCLUDE ymmc100_f04.

START-OF-SELECTION.
  CALL SCREEN 100.

Include: YMMC100_TOP

&*&---------------------------------------------------------------------*&
&*& Include          YMMC100_TOP
&*&---------------------------------------------------------------------*&
TYPES:
  BEGIN OF ty_excel,
    iblnr TYPE ikpf-iblnr,
    gjahr TYPE ikpf-gjahr,
    xldat TYPE char30,
    zeili TYPE iseg-zeili,
    matnr TYPE matnr,
    charg TYPE charg_d,
    menge TYPE menge_d,
    meins TYPE meins,
    xnull TYPE iseg-xnull,
  END OF ty_excel,

  BEGIN OF ty_data,
    icons LIKE icon-id,
    snote TYPE char255,
    ccell TYPE lvc_t_scol,
    cstyl TYPE lvc_t_styl,
    cline TYPE char4,

    iblnr TYPE ikpf-iblnr,
    gjahr TYPE ikpf-gjahr,
    zldat TYPE ikpf-zldat,
    zeili TYPE iseg-zeili,
    matnr TYPE matnr,
    maktx TYPE maktx,
    charg TYPE charg_d,
    menge TYPE menge_d,
    meins TYPE meins,
    xnull TYPE iseg-xnull,
  END OF ty_data,

  BEGIN OF zstab,
    field TYPE char10,
  END OF zstab.

DATA:
  lt_excel TYPE TABLE OF ty_excel,
  ls_excel TYPE ty_excel,
  lt_data  TYPE TABLE OF ty_data,
  ls_data  TYPE ty_data,
  stab     TYPE TABLE OF zstab,
  itab     TYPE TABLE OF  alsmex_tabline WITH HEADER LINE.

DATA:
  ob_container TYPE REF TO cl_gui_custom_container,
  ob_grid      TYPE REF TO cl_gui_alv_grid,
  lt_fieldcat  TYPE lvc_t_fcat,
  ls_fieldcat  LIKE LINE OF lt_fieldcat,
  is_lyout     TYPE lvc_s_layo,
  lt_message   TYPE TABLE OF bdcmsgcoll,
  ls_message   LIKE LINE OF lt_message,
  ld_mode      TYPE c VALUE 'N'.

DATA:
  zz_pid   TYPE char80,
  lv_matnr TYPE matnr18.

DATA:   bdcdata LIKE bdcdata    OCCURS 0 WITH HEADER LINE.
*       messages of call transaction
DATA:   messtab LIKE bdcmsgcoll OCCURS 0 WITH HEADER LINE.
*       error session opened (' ' or 'X')
DATA:   e_group_opened.
*       message texts
TABLES: t100.

Include: YMMC100_SEL

&*&---------------------------------------------------------------------*&
&*& Include          YMMC100_SEL
&*&---------------------------------------------------------------------*&

"Selection Screen
SELECTION-SCREEN BEGIN OF SCREEN 101 AS SUBSCREEN.
  PARAMETERS:
*    p_bukrs  TYPE bukrs OBLIGATORY,
    filename TYPE localfile MEMORY ID zfile,
    p_line   TYPE i DEFAULT 2,
    p_total  TYPE i.

SELECTION-SCREEN END OF SCREEN 101 .

AT SELECTION-SCREEN ON VALUE-REQUEST FOR filename.
  CALL FUNCTION 'KD_GET_FILENAME_ON_F4'
    EXPORTING
      static    = 'X'
      mask      = '*.xls'
    CHANGING
      file_name = filename.

AT SELECTION-SCREEN OUTPUT.
  GET PARAMETER ID 'ZFILE' FIELD zz_pid.

  LOOP AT SCREEN.
    IF lt_data IS NOT INITIAL AND
    ( screen-name CS 'P_LINE' OR screen-name CS 'P_BUKRS' OR screen-name CS 'FILENAME').
      screen-input = 0.
    ELSE.
      screen-input = 1.
    ENDIF.

    IF screen-name CS 'P_TOTAL'.
      screen-input = 0.
    ENDIF.
    MODIFY SCREEN.
  ENDLOOP.

Include: YMMC100_F01

&*&---------------------------------------------------------------------*&
&*& Include          YMMC100_F01
&*&---------------------------------------------------------------------*&
MODULE status_0100 OUTPUT.
  REFRESH stab.
  IF lt_data IS INITIAL.
    APPEND 'POST' TO stab.
    APPEND 'CLRD'  TO stab.
  ELSE.
    APPEND 'READ' TO stab.
  ENDIF.

  SET PF-STATUS 'PF100' EXCLUDING stab.
  SET TITLEBAR  'TL100' WITH 'Upload Count PID'.

  PERFORM initial_screen.
ENDMODULE.
*&*---------------------------------------------------------------------*
*&      Module  USER_COMMAND_0100  INPUT
*&*---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
MODULE user_command_0100 INPUT.
  CASE sy-ucomm.
    WHEN 'BACK' OR 'EXIT' OR 'CNCL'.
      LEAVE PROGRAM.
    WHEN 'READ'.
      CLEAR p_total.
      PERFORM read_excel USING filename '1' p_line '70' '65536'.
      DESCRIBE TABLE lt_data LINES p_total.
    WHEN 'CLRD'.
      REFRESH : lt_data, lt_excel.
    WHEN 'POST'.
      READ TABLE lt_data WITH KEY icons = '@0A@' TRANSPORTING NO FIELDS.
      IF sy-subrc = 0.
        MESSAGE 'Please check your input' TYPE 'S' DISPLAY LIKE 'E'.
      ELSE.
        PERFORM post_count_pid.
      ENDIF.

  ENDCASE.
ENDMODULE.

Include: YMMC100_F02

&*&---------------------------------------------------------------------*&
&*& Include          YMMC100_F02
&*&---------------------------------------------------------------------*&
FORM read_excel USING p_file p_bcol p_brow p_ecol p_erow.
*  CALL FUNCTION 'ALSM_EXCEL_TO_INTERNAL_TABLE'
  CALL FUNCTION 'ALSM_EXCEL_TO_INTERNAL_TABLE'
    EXPORTING
      filename                = p_file
      i_begin_col             = p_bcol
      i_begin_row             = p_brow
      i_end_col               = p_ecol
      i_end_row               = p_erow
    TABLES
      intern                  = itab[]
    EXCEPTIONS
      inconsistent_parameters = 1
      upload_ole              = 2
      OTHERS                  = 3.

  DATA lv_index TYPE i.
  FIELD-SYMBOLS <fs>.

  LOOP AT itab.
    MOVE itab-col TO lv_index.
    ASSIGN COMPONENT lv_index OF STRUCTURE ls_excel TO <fs>.
    MOVE itab-value TO <fs>.
    AT END OF row.
      CLEAR ls_data.
*      ls_data-icons = '@08@'.
      ls_data-icons = '@08@'.
      MOVE-CORRESPONDING ls_excel TO ls_data.

      ls_data-zldat = |{ ls_excel-xldat+6(4) }{ ls_excel-xldat+3(2) }{ ls_excel-xldat(2) }|.


*      CLEAR ls_check.

      PERFORM data_validation.

      APPEND ls_data TO lt_data.
      CLEAR ls_excel.
    ENDAT.
  ENDLOOP.
ENDFORM.

FORM data_validation.
  CLEAR lv_matnr.
  lv_matnr = |{ ls_data-matnr ALPHA = IN }|.
  SELECT SINGLE maktx FROM makt
    INTO ls_data-maktx
      WHERE matnr = lv_matnr AND spras = sy-langu.

  IF ls_data-maktx IS INITIAL.
    ls_data-icons = '@0A@'.
    ls_data-snote = 'Material not found'.
  ENDIF.

  ls_data-iblnr = |{ ls_data-iblnr ALPHA = IN }|.
  SELECT SINGLE iblnr FROM ikpf
    INTO @DATA(lv_iblnr)
      WHERE iblnr = @ls_data-iblnr AND gjahr = @ls_data-gjahr.
  IF lv_iblnr IS INITIAL.
    ls_data-icons = '@0A@'.
    ls_data-snote = 'PID Document not found'.
  ENDIF.



  SELECT SINGLE xzael FROM iseg
    INTO @DATA(lv_xzael)
      WHERE iblnr = @ls_data-iblnr AND gjahr = @ls_data-gjahr AND zeili = @ls_data-zeili.

  IF lv_xzael = 'X'.
    ls_data-icons = '@0A@'.
    ls_data-snote = 'PID Item already counted'.
  ENDIF.

  ls_data-iblnr = |{ ls_data-iblnr ALPHA = OUT }|.
  CLEAR: lv_iblnr, lv_xzael.
ENDFORM.

Include: YMMC100_F03

&*&---------------------------------------------------------------------*&
&*& Include          YMMC100_F03
&*&---------------------------------------------------------------------*&
FORM initial_screen.
  IF ob_container IS INITIAL.
    CREATE OBJECT ob_container
      EXPORTING
        container_name = 'CONTAINER'.

    CREATE OBJECT ob_grid
      EXPORTING
        i_parent = ob_container.
  ENDIF.

  PERFORM set_fieldcat.
  PERFORM set_lyout.
  PERFORM alv_displ_out.

  CALL METHOD ob_grid->refresh_table_display.
ENDFORM.

FORM set_fieldcat.
  REFRESH lt_fieldcat.
  PERFORM :
  append_fieldcat USING 'ICONS'    'Status'           'CHAR' '' '' '5'  '' 'X' 'LT_DATA' '1',
  append_fieldcat USING 'SNOTE'    'Message'          'CHAR' '' '' '40' '' 'X' 'LT_DATA' '1',
  append_fieldcat USING 'IBLNR'    'Phys. Inv. Doc.'  'CHAR' '' '' '10' '' 'X' 'IKPF' '1',
  append_fieldcat USING 'GJAHR'    'Year'             'NUMC' '' '' '40' '' 'X' 'IKPF' '1',
  append_fieldcat USING 'ZLDAT'    'Count Date'       'DATS' '' '' '40' '' '' 'IKPF' '1',
  append_fieldcat USING 'ZEILI'    'Item'             'NUMC' '' '' '40' '' '' 'ISEG' '1',
  append_fieldcat USING 'MATNR'    'Material'         'CHAR' '' '' '40' '' '' 'ISEG' '1',
  append_fieldcat USING 'MAKTX'    'Description'      'CHAR' '' '' '40' '' '' 'LT_DATA' '1',
  append_fieldcat USING 'CHARG'    'Batch Number'     'CHAR' '' '' '40' '' '' 'ISEG' '1',
  append_fieldcat USING 'MENGE'    'Entry Count'      'QUAN' 'MEINS' '' '40' '' '' '' '1',
  append_fieldcat USING 'MEINS'    'Entry Uom'        'UNIT' '' '' '40' '' '' '' '1',
  append_fieldcat USING 'XNULL'    'Zero Count Ind'   'CHAR' '' '' '40' '' '' '' '1'
        .

*  CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
*    EXPORTING
*      i_structure_name = 'ZSFIC001'
*    CHANGING
*      ct_fieldcat      = lt_fieldcat.

ENDFORM.

FORM append_fieldcat USING p_fname p_fdesc p_dtype p_qfield p_cfield p_olen p_sum p_key p_tabname p_act.
  DATA irows TYPE i.
  CLEAR irows.

  DESCRIBE TABLE lt_fieldcat LINES irows.
  irows = irows + 1.
  CLEAR ls_fieldcat.
  IF p_fname = 'ICONS'.
    ls_fieldcat-icon = 'X'.
    ls_fieldcat-just = 'C'.
  ENDIF.
  ls_fieldcat-col_pos    = irows.
  ls_fieldcat-key        = p_key.
  ls_fieldcat-fieldname  = p_fname.
  ls_fieldcat-scrtext_l  = p_fdesc.
  ls_fieldcat-scrtext_m  = p_fdesc.
  ls_fieldcat-scrtext_s  = p_fdesc.
  ls_fieldcat-datatype   = p_dtype.
  ls_fieldcat-qfieldname = p_qfield.
  ls_fieldcat-cfieldname = p_cfield.
  ls_fieldcat-outputlen  = p_olen.
  ls_fieldcat-do_sum     = p_sum.
  ls_fieldcat-tabname    = p_tabname.

  APPEND ls_fieldcat TO lt_fieldcat.
ENDFORM.

FORM set_lyout .
  CLEAR is_lyout.
  is_lyout-zebra        = 'X'.
  is_lyout-cwidth_opt   = 'X'.
  is_lyout-box_fname    = 'ZBOX'.
*  is_lyout-no_rowins    = 'X'.
  is_lyout-stylefname   = 'CSTYL'.
  is_lyout-info_fname   = 'CLINE'.
  is_lyout-ctab_fname   = 'CCELL'.
ENDFORM.

FORM alv_displ_out.
  CALL METHOD ob_grid->set_table_for_first_display
    EXPORTING
*     is_variant                    = is_varnt      "DISVARIANT
      i_save                        = 'A'           "CHAR1 - X:Global - U:User - A:All - Space:No
      i_default                     = 'X'           "CHAR1 - X:Allowed - Space:not
      is_layout                     = is_lyout      "LVC_S_LAYO
*     is_print                      = is_print      "LVC_S_PRNT
*     it_toolbar_excluding          = it_excld      "UI_FUNCTIONS
    CHANGING
      it_outtab                     = lt_data
      it_fieldcatalog               = lt_fieldcat      "LVC_T_FCAT
*     it_sort                       = it_sort       "LVC_T_SORT
    EXCEPTIONS
      invalid_parameter_combination = 1
      program_error                 = 2
      too_many_lines                = 3
      OTHERS                        = 4.
ENDFORM.

Include: YMMC100_F04

&*&---------------------------------------------------------------------*&
&*& Include          YMMC100_F04
&*&---------------------------------------------------------------------*&
DATA:
  physinventory	      TYPE ikpf-iblnr,
  fiscalyear          TYPE ikpf-gjahr,
  percentage_variance	TYPE iikpf-abwei,
  count_date          TYPE iikpf-zldat,

  lt_items            TYPE TABLE OF bapi_physinv_count_items,
  ls_items            TYPE bapi_physinv_count_items,
  lt_return	          TYPE TABLE OF	bapiret2,
  ls_return	          TYPE bapiret2.

FORM post_count_pid.

  DATA(xhead) = lt_data.
  SORT xhead BY iblnr gjahr.

  DELETE ADJACENT DUPLICATES FROM xhead COMPARING iblnr gjahr.

  LOOP AT xhead INTO DATA(ls_head).
    REFRESH : lt_items, lt_return.
    CLEAR ls_data.
    LOOP AT lt_data INTO ls_data
      WHERE iblnr = ls_head-iblnr AND gjahr = ls_head-gjahr.
      CLEAR: ls_items, lv_matnr.
      lv_matnr = |{ ls_data-matnr ALPHA = IN }|.
      ls_items-item       = ls_data-zeili.
      ls_items-material   = |{ ls_data-matnr ALPHA = IN }|.
*      ls_items-material_long = |{ ls_data-matnr ALPHA = IN }|.
      ls_items-batch      = ls_data-charg.
      ls_items-entry_qnt  = ls_data-menge.
      ls_items-entry_uom  = |{ ls_data-meins ALPHA = IN }|.
      ls_items-zero_count = ls_data-xnull.
      APPEND ls_items TO lt_items.
      CLEAR ls_data.
    ENDLOOP.

*    BREAK-POINT.
    physinventory = |{ ls_head-iblnr ALPHA = IN }|.
    fiscalyear    = ls_head-gjahr.
    count_date    = ls_head-zldat.

    CALL FUNCTION 'BAPI_MATPHYSINV_COUNT'
      EXPORTING
        physinventory = physinventory
        fiscalyear    = fiscalyear
*       PERCENTAGE_VARIANCE       =
        count_date    = count_date
      TABLES
        items         = lt_items
        return        = lt_return
*       SERIALNUMBERS =
*       EXTENSIONIN   =
*       ITEMS_CWM     =
      .

    CLEAR ls_return.
    READ TABLE lt_return INTO ls_return WITH KEY type = 'E'.
    IF sy-subrc = 0.
      DELETE lt_return WHERE number = 724.
      CLEAR ls_return.
      READ TABLE lt_return INTO ls_return WITH KEY type = 'E'.
      ls_data-snote = ls_return-message.
      ls_data-icons = '@0A@'.
    ELSE.
      CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
        EXPORTING
          wait = 'X'.

      ls_data-snote = 'PID Counted'.
      ls_data-icons = '@5Y@'.
    ENDIF.

    MODIFY lt_data FROM ls_data TRANSPORTING snote icons
      WHERE iblnr = ls_head-iblnr AND gjahr = ls_head-gjahr.
    CLEAR ls_head.
  ENDLOOP.
ENDFORM.

Output Program

SAP ABAP - Upload Count PID dengan BAPI

Upload Count PID dengan BAPI di ABAP — Contoh Program YMMC100 Upload Count PID dengan BAPI di ABAP — Progr...