Upload Count PID dengan BAPI di ABAP — Program YMMC100
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
- Penjelasan singkat fungsi program
- Struktur source (includes & main)
- Penjelasan tiap bagian include
- Format Excel yang diharapkan
- Flow proses (read → validate → display → post)
- Best practices & troubleshooting
- Code (lengkap)
- 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_COUNTuntuk post count.
2. Struktur source
Program utama memanggil beberapa include:
YMMC100_TOP: type, data deklarasi, GUI objectsYMMC100_SEL: selection screen & F4YMMC100_F01: status screen & user commandYMMC100_F02: read excel & validationYMMC100_F03: ALV display setupYMMC100_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)
- User pilih file → tekan READ.
- Program baca Excel → mapping ke
ls_data. - Validasi material (MAKT), dokumen PID (IKPF), dan status item (ISEG-xzael).
- Jika ada error, diberi ikon error dan message di ALV.
- User review di ALV → tekan POST untuk upload tiap dokumen via BAPI.
6. Best practices & troubleshooting
- Jika user pakai
.xlsx, migrasi kecl_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.




