以下以销售订单批导为例展示一个完整的常规批导程序。
一、选择屏幕部分
*&---缓存类型定义
TYPES:BEGIN OF ty_temp,
number TYPE zenumber, "排序号
id TYPE icon_d, "成功/失败
msg TYPE bapi_msg, "消息
total TYPE int2, "总条目
curr TYPE int2, "当前条目
END OF ty_temp.
*----------------------------------------------------------------------*
* 全局变量定义
*----------------------------------------------------------------------*
DATA:gt_data TYPE REF TO data.
*&---缓存表
DATA:gt_temp TYPE TABLE OF ty_temp,
gs_temp TYPE ty_temp.
*&---进度条
DATA:gv_per TYPE p,
gv_stxt TYPE string,
gv_num TYPE i VALUE 0, "数据总数
gv_sign TYPE i VALUE 0. "当前的进度
*----------------------------------------------------------------------*
* 常量定义
*----------------------------------------------------------------------*
*----------------------------------------------------------------------*
* ALV定义
*----------------------------------------------------------------------*
DATA: gt_fieldcat TYPE lvc_t_fcat,
gs_fieldcat TYPE lvc_s_fcat,
gt_events TYPE slis_t_event, "事件存储内表
gs_events TYPE slis_alv_event.
DATA:gs_layout TYPE lvc_s_layo.
*----------------------------------------------------------------------*
* FIELD-SYMBOLS定义
*----------------------------------------------------------------------*
FIELD-SYMBOLS:<ft_data> TYPE STANDARD TABLE,
<fs_temp> TYPE ty_temp,
<fs_data>,
<fs_value>.
*----------------------------------------------------------------------*
* 选择屏幕
*----------------------------------------------------------------------*
SELECTION-SCREEN BEGIN OF BLOCK blk WITH FRAME TITLE TEXT-t01.
PARAMETERS:rb_down TYPE char1 RADIOBUTTON GROUP grp1 USER-COMMAND cre,
rb_upld TYPE char1 RADIOBUTTON GROUP grp1 DEFAULT 'X'.
PARAMETERS:p_path TYPE rlgrap-filename MODIF ID m2 .
SELECTION-SCREEN END OF BLOCK blk.
SELECTION-SCREEN BEGIN OF BLOCK blk2 WITH FRAME TITLE TEXT-t02.
PARAMETERS:p_a RADIOBUTTON GROUP grp2 DEFAULT 'X' MODIF ID m3,
p_b RADIOBUTTON GROUP grp2 MODIF ID m3,
p_c RADIOBUTTON GROUP grp2 MODIF ID m3.
SELECTION-SCREEN END OF BLOCK blk2.
*&-----------------------------------------------------------------*
*& 初始化处理
*&-----------------------------------------------------------------*
INITIALIZATION.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_path.
CALL FUNCTION 'KD_GET_FILENAME_ON_F4'
CHANGING
file_name = p_path.
*&-----------------------------------------------------------------*
*& 选择屏幕控制
*&-----------------------------------------------------------------*
AT SELECTION-SCREEN OUTPUT.
LOOP AT SCREEN.
IF screen-group1 = 'M2'.
IF rb_upld = 'X'.
screen-active = 1.
ELSE.
screen-active = 0.
ENDIF.
MODIFY SCREEN.
ENDIF.
ENDLOOP.
*&-----------------------------------------------------------------*
*& 程序开始处理
*&-----------------------------------------------------------------*
START-OF-SELECTION.
IF rb_down = 'X'.
"下载模板
PERFORM frm_download_file.
ELSEIF rb_upld = 'X'.
"获取数据
PERFORM frm_get_data.
"处理数据
PERFORM frm_process_data.
"ALV展示
PERFORM frm_display_alv.
ENDIF.
*&------------------------------------------------------------------*
*& 程序结束处理
*&------------------------------------------------------------------*
END-OF-SELECTION.
二、FORM部分
1、下载模板
使用的是事务码SMW0中导入的模板
FORM frm_download_file .
DATA: lv_file TYPE rlgrap-filename,
lv_objid TYPE wwwdata-objid,
ls_key LIKE wwwdatatab,
lv_subrc TYPE sy-subrc,
lv_filename TYPE string,
lv_path TYPE string,
lv_fullpath TYPE string,
lv_default_file_name TYPE string.
lv_objid = sy-repid.
*&--------获得要保存文件的路径名
CASE 'X'.
WHEN p_a.
lv_default_file_name = TEXT-001 && '.xlsx'.
lv_objid = lv_objid && '_A'.
WHEN p_b.
lv_default_file_name = TEXT-002 && '.xlsx'.
lv_objid = lv_objid && '_B'.
WHEN p_c.
lv_default_file_name = TEXT-003 && '.xlsx'.
lv_objid = lv_objid && '_C'.
WHEN OTHERS.
ENDCASE.
CALL METHOD cl_gui_frontend_services=>file_save_dialog
EXPORTING
window_title = '请选择路径'
default_file_name = lv_default_file_name
file_filter = 'Excel 文件 (*.xlsx)'
CHANGING
filename = lv_filename
path = lv_path
fullpath = lv_fullpath
EXCEPTIONS
cntl_error = 1
error_no_gui = 2
not_supported_by_gui = 3
OTHERS = 4.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
lv_file = lv_fullpath.
IF lv_fullpath IS NOT INITIAL.
SELECT SINGLE *
FROM wwwdata
INTO CORRESPONDING FIELDS OF ls_key
WHERE objid = lv_objid
AND relid = 'MI'.
CALL FUNCTION 'DOWNLOAD_WEB_OBJECT'
EXPORTING
key = ls_key
destination = lv_file
IMPORTING
rc = lv_subrc.
IF lv_subrc = 0.
MESSAGE '模板下载成功' TYPE 'S'.
ENDIF.
ELSE.
MESSAGE '下载取消!' TYPE 'S' DISPLAY LIKE 'E'.
ENDIF.
ENDFORM.
2、获取数据
FORM frm_get_data .
DATA:lt_return TYPE bapiret2_t,
ls_return TYPE bapiret2,
lv_msg TYPE char220.
"获取内表字段
CALL FUNCTION 'ZFM_GET_FIELDCAT'
EXPORTING
i_path = p_path
i_end_col = 50
TABLES
et_fieldcat = gt_fieldcat
et_return = lt_return.
IF lt_return IS NOT INITIAL.
"返回报错处理
LOOP AT lt_return INTO ls_return WHERE type = 'E'.
lv_msg = lv_msg && ls_return-message.
ENDLOOP.
IF lv_msg IS NOT INITIAL.
MESSAGE lv_msg TYPE 'S' DISPLAY LIKE 'E'.
STOP.
ENDIF.
ENDIF.
"创建动态内表
CALL METHOD cl_alv_table_create=>create_dynamic_table
EXPORTING
it_fieldcatalog = gt_fieldcat
IMPORTING
ep_table = gt_data.
ASSIGN gt_data->* TO <ft_data>.
"获取内表值
CALL FUNCTION 'ZFM_GET_UPLOAD_DATA'
TABLES
et_data = <ft_data>.
"删除字段选择框
DELETE gt_fieldcat WHERE fieldname = 'CHECK'.
ENDFORM.
3、ALV展示
FORM frm_display_alv .
*&---LAYOUT定义
CLEAR gs_layout.
gs_layout-box_fname = 'CHECK'.
gs_layout-zebra = 'X'. "设置Grid的行颜色变换显示
gs_layout-cwidth_opt = 'X'. "设置Grid的字段列宽度自动适应
*&---ALV显示
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
EXPORTING
i_callback_program = sy-repid
i_callback_pf_status_set = 'FRM_SET_PF_STATUS'
i_callback_user_command = 'FRM_USER_COMMAND'
is_layout_lvc = gs_layout
it_fieldcat_lvc = gt_fieldcat
* IT_EVENTS = I_EVENTS[]
i_save = 'A'
TABLES
t_outtab = <ft_data>
EXCEPTIONS
program_error = 1
OTHERS = 2.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
ENDFORM.
4、GUI状态和标题栏
FORM frm_set_pf_status USING pt_extab TYPE slis_t_extab.
DATA lv_title TYPE char20.
CASE 'X'.
WHEN p_a.
lv_title = TEXT-004.
WHEN p_b.
lv_title = TEXT-005.
WHEN p_c.
lv_title = TEXT-006.
WHEN OTHERS.
ENDCASE.
SET PF-STATUS 'STANDARD' .
SET TITLEBAR 'TITLE_STD' WITH lv_title.
ENDFORM.
5、usercommand
FORM frm_user_command USING pv_ucomm LIKE sy-ucomm
ps_selfield TYPE slis_selfield.
DATA: lv_grid TYPE REF TO cl_gui_alv_grid.
DATA: lv_flag TYPE c.
*&将变更的数据刷新
CALL FUNCTION 'GET_GLOBALS_FROM_SLVC_FULLSCR'
IMPORTING
e_grid = lv_grid.
CALL METHOD lv_grid->check_changed_data.
ps_selfield-refresh = 'X'.
CASE pv_ucomm.
WHEN 'ZLOAD'. "导入
PERFORM frm_save_data.
ENDCASE.
CALL METHOD lv_grid->refresh_table_display.
ENDFORM.
6、处理数据
FORM frm_process_data .
DATA:lt_sort TYPE abap_sortorder_tab,
ls_sort TYPE abap_sortorder.
IF <ft_data> IS NOT INITIAL.
LOOP AT <ft_data> ASSIGNING <fs_data>.
"单位转换
CALL FUNCTION 'ZFM_CONVERSION_EXIT'
EXPORTING
iv_fieldname = 'KMEIN'
iv_exit = zgl0_cunit_in
CHANGING
cs_data = <fs_data>.
CALL FUNCTION 'ZFM_CONVERSION_EXIT'
EXPORTING
iv_fieldname = 'VRKME'
iv_exit = zgl0_cunit_in
CHANGING
cs_data = <fs_data>.
ENDLOOP.
"针对动态内表排序
ls_sort-name = 'NUMBER'.
ls_sort-descending = ''.
APPEND ls_sort TO lt_sort.
"针对动态内表排序
ls_sort-name = 'POSNR'.
ls_sort-descending = ''.
APPEND ls_sort TO lt_sort.
SORT <ft_data> BY (lt_sort).
ENDIF.
ENDFORM.
7、导入按钮逻辑
FORM frm_save_data .
DATA:lv_flag TYPE char1,
lv_number TYPE zenumber,
lv_field TYPE fieldname VALUE 'NUMBER',
lv_index TYPE i.
DATA:ls_req TYPE zssdi001_req,
ls_item TYPE zssdi001_item_in,
ls_cond TYPE zssdi001_cond_in,
ls_config TYPE zssdi001_config_in,
ls_schedule TYPE zssdi001_schedule_in,
ls_resp TYPE zsrest_out,
lv_etenr TYPE vbep-etenr.
"导入前检查
PERFORM frm_before_import CHANGING lv_flag.
CHECK lv_flag IS INITIAL.
READ TABLE gt_fieldcat TRANSPORTING NO FIELDS WITH KEY fieldname = 'VC_FLAG'.
IF sy-subrc = 0.
lv_index = sy-tabix + 1.
ENDIF.
LOOP AT <ft_data> ASSIGNING <fs_data>.
PERFORM frm_convent_data_out USING <fs_data> 'NUMBER' CHANGING lv_number.
READ TABLE gt_temp ASSIGNING <fs_temp> WITH KEY number = lv_number BINARY SEARCH.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.
AT NEW (lv_field).
CLEAR:ls_req,ls_resp.
MOVE-CORRESPONDING <fs_data> TO ls_req-req-head.
ENDAT.
AT NEW ('POSNR').
CLEAR:ls_item.
MOVE-CORRESPONDING <fs_data> TO ls_item.
"特征值
CLEAR:lv_flag.
PERFORM frm_convent_data_out USING <fs_data> 'VC_FLAG' CHANGING lv_flag.
IF lv_flag = 'X'.
LOOP AT gt_fieldcat INTO gs_fieldcat FROM lv_index.
CLEAR:ls_config.
ls_config-charc = gs_fieldcat-fieldname.
PERFORM frm_convent_data_out USING <fs_data> gs_fieldcat-fieldname CHANGING ls_config-value_long.
APPEND ls_config TO ls_item-config.
ENDLOOP.
ENDIF.
ENDAT.
"条件类型
CLEAR:ls_cond.
MOVE-CORRESPONDING <fs_data> TO ls_cond.
IF ls_cond-kschl IS NOT INITIAL.
APPEND ls_cond TO ls_item-cond.
ENDIF.
"计划行
CLEAR:lv_etenr.
PERFORM frm_convent_data_out USING <fs_data> 'ETENR' CHANGING lv_etenr.
IF lv_etenr <> 0.
MOVE-CORRESPONDING <fs_data> TO ls_schedule.
APPEND ls_schedule TO ls_item-schedule.
ENDIF.
AT END OF ('POSNR').
IF ls_item-posnr IS NOT INITIAL.
APPEND ls_item TO ls_req-req-item.
ENDIF.
ENDAT.
AT END OF (lv_field).
"调用函数生成凭证
CALL FUNCTION 'ZFM_SDI001'
EXPORTING
i_req = ls_req
IMPORTING
o_resp = ls_resp.
"更改缓存表消息及状态字段
IF ls_resp-msgty = 'S'.
<fs_temp>-id = icon_led_green.
ELSE.
<fs_temp>-id = icon_led_red.
ENDIF.
<fs_temp>-msg = ls_resp-msgtx.
"显示进度条
gv_sign = gv_sign + 1 ."每次进度+1
gv_per = gv_sign / gv_num * 100 . "进度/总数*100得到百分比
gv_stxt = |当前条目 { gv_sign } / 总条目 { gv_num }|.
CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR'
EXPORTING
percentage = gv_per
text = gv_stxt.
ENDAT.
ENDLOOP.
"回写ALV
LOOP AT <ft_data> ASSIGNING <fs_data>.
CLEAR:lv_number.
PERFORM frm_convent_data_out USING <fs_data> 'NUMBER' CHANGING lv_number.
READ TABLE gt_temp ASSIGNING <fs_temp> WITH KEY number = lv_number BINARY SEARCH.
IF sy-subrc = 0.
"状态
PERFORM frm_convent_data_in USING 'ID' <fs_temp>-id CHANGING <fs_data>.
"消息
PERFORM frm_convent_data_in USING 'MSG' <fs_temp>-msg CHANGING <fs_data>.
ENDIF.
ENDLOOP.
ENDFORM.
8、获取和写入动态结构的字段值
FORM frm_convent_data_out USING p_data
p_fieldname
CHANGING c_value.
ASSIGN COMPONENT p_fieldname OF STRUCTURE p_data TO <fs_value>.
IF sy-subrc = 0.
c_value = <fs_value>.
ENDIF.
ENDFORM.
FORM frm_convent_data_in USING p_fieldname
p_value
CHANGING p_data.
ASSIGN COMPONENT p_fieldname OF STRUCTURE p_data TO <fs_value>.
IF sy-subrc = 0.
<fs_value> = p_value.
ENDIF.
ENDFORM.
9、导入前数据的处理
FORM frm_before_import CHANGING p_flag.
DATA:lv_number TYPE zenumber,
lv_checkbox TYPE char1,
lv_id TYPE icon-id.
CLEAR:gt_temp.
*&---筛选出选中的数据
LOOP AT <ft_data> ASSIGNING <fs_data>.
CLEAR:lv_checkbox,lv_id.
PERFORM frm_convent_data_out USING <fs_data> 'CHECK' CHANGING lv_checkbox.
PERFORM frm_convent_data_out USING <fs_data> 'ID' CHANGING lv_id.
"判断当前行选中且数据未被导入
IF lv_checkbox = 'X' AND lv_id <> icon_led_green.
CLEAR:gs_temp.
PERFORM frm_convent_data_out USING <fs_data> 'NUMBER' CHANGING gs_temp-number.
APPEND gs_temp TO gt_temp.
ENDIF.
ENDLOOP.
*&---去掉重复数据
IF gt_temp IS NOT INITIAL.
SORT gt_temp BY number.
DELETE ADJACENT DUPLICATES FROM gt_temp COMPARING number.
"进度条-总条数
CLEAR:gv_sign,gv_per,gv_stxt,gv_num.
gv_num = lines( gt_temp ).
"选中所有相同序列行
LOOP AT <ft_data> ASSIGNING <fs_data>.
CLEAR:lv_number.
PERFORM frm_convent_data_out USING <fs_data> 'NUMBER' CHANGING lv_number.
READ TABLE gt_temp TRANSPORTING NO FIELDS WITH KEY number = lv_number.
IF sy-subrc = 0.
PERFORM frm_convent_data_in USING 'CHECK' 'X' CHANGING <fs_data>.
ENDIF.
ENDLOOP.
ELSE.
p_flag = 'X'.
MESSAGE s001(zgl01) DISPLAY LIKE 'E' .
ENDIF.
ENDFORM.