ABAP 上传文件批导模板

主要实现了以下步骤:

1、让用户下载模板。

2、根据模板填写数据选择文件进行上传。

3、根据用户数据进行存在性判断,存在则可以改,不存在不可以修改。

4、通过BAPI或者BDC实现程序自动批量修改。

5、将修改结果显示给用户,失败给出失败信息,消息灯变红,成功显示成功,消息灯为绿。

具体的实现代码的解释请看注释,需要进行修改的地方也在注释的地方进行了标注。

博客中的代码是用BAPI对PO的短文本进行批量修改,在进行批量操作时能用BAPI就尽量用BAPI。可以先查一下有没有系统给的,没有的话再用BDC或者LSMW。

一、主程序

主要是进行初始化和子例程调用。

*&---------------------------------------------------------------------*
*& Report ZVIA_ME22_PRO
*&---------------------------------------------------------------------*
REPORT zvia_me22_pro MESSAGE-ID zvia_msg.

* 变量定义 *
INCLUDE zvia_me22_pro_d01.
* 屏幕定义 *
INCLUDE zvia_me22_pro_s01.
* 功能定义 *
INCLUDE zvia_me22_pro_f01.
* ALV相关功能定义 *
INCLUDE zvia_me22_pro_f02.

* 初始化 *
INITIALIZATION.
  sscrfields-functxt_01 = icon_xlv && TEXT-000."下载模板按钮

* 响应事件 *
AT SELECTION-SCREEN.
  CASE sy-ucomm."存储用户在 SAP GUI 界面上触发的事件或操作命令
    WHEN 'FC01'."不知道是什么可以调试点按钮看SY-UCOMM的值是什么
      PERFORM frm_download."下载导入模板
  ENDCASE.

AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_path.
* 给文件路径添加搜索帮助,让用户可以选择自己的电脑文件而不是需要复制地址 *
* 选择上传文件路径 *
  PERFORM frm_get_path.

START-OF-SELECTION.
  IF p_path IS INITIAL.
    MESSAGE s008 DISPLAY LIKE 'E'.
    LEAVE LIST-PROCESSING."终止start-of-selection的执行
  ELSE.
    PERFORM frm_upload_excel.
    IF gt_upload IS NOT INITIAL.
* 将excel数据转换到ALV输出内表 *
      PERFORM frm_get_output."upload->output
    ELSE.
      MESSAGE s009 DISPLAY LIKE 'E'."上传文件内容为空
      LEAVE LIST-PROCESSING."终止START-OF-SELECTION
    ENDIF.
  ENDIF.

END-OF-SELECTION."显示数据用的事件
  PERFORM frm_display_alv.

二、变量的定义

主要定义了模板的名字(自己上传的模板的名字),上传数据的格式,以及在ALV显示的时候行项目的格式以及fieldcat。

*&---------------------------------------------------------------------*
*& 包含               ZVIA_ME22_PRO_D01
*&---------------------------------------------------------------------*
TYPE-POOLS : icon.
TABLES : sscrfields.

* 需要修改,这里的VALUE是上传到系统的模板的名字 *
CONSTANTS : "常量
  gc_objid TYPE wwwdatatab-objid VALUE 'ZVIA_PO_DBC'.

TYPES :
* 需要进行修改,对应自己的字段 *
  BEGIN OF ty_upload, "接收excel上传数据的格式
    ebeln TYPE ekpo-ebeln,
    ebelp TYPE ekpo-ebelp,
    txz01 TYPE ekpo-txz01,
    menge TYPE ekpo-menge,
  END OF ty_upload,
* 需要进行修改,对应自己的字段,其中消息灯、消息文本、选择框不要动 *
  BEGIN OF ty_output,
    status TYPE icon_d, "消息灯
    ebeln  TYPE ekpo-ebeln, "分组时用到的key,需要在前几个
    ebelp  TYPE ekpo-ebelp,
    txz01  TYPE ekpo-txz01,
    menge  TYPE ekpo-menge,
    msg    TYPE bapi_msg, "消息文本
    sel(1) TYPE c, "选择?
  END OF ty_output.
"ty_t_output TYPE STANDARD TABLE OF ty_output.

DATA :
  gt_upload TYPE TABLE OF ty_upload, "excel上传数据存放的内表
  "gt_output TYPE ty_t_output."ALV输出数据
  gt_output TYPE TABLE OF ty_output. "ALV输出数据

DATA :"ALV FIELDCATLOG
  gt_fieldcat TYPE lvc_t_fcat,
  gs_layout   TYPE lvc_s_layo,
  gv_import   TYPE boole_d.

三、屏幕定义 

导入模板的屏幕较为简单。

*&---------------------------------------------------------------------*
*& 包含               ZVIA_ME22_PRO_S01
*&---------------------------------------------------------------------*
SELECTION-SCREEN BEGIN OF BLOCK BLK WITH FRAME TITLE text-001.
  PARAMETERS :
    p_path TYPE rlgrap-filename MODIF ID fl."上传文件路径
SELECTION-SCREEN END OF BLOCK BLK.

SELECTION-SCREEN FUNCTION KEY 1."添加一个特定的功能键 KEY 1 按下KEY1后会触发特定操作

四、功能定义

定义了一些功能,主要是对下载模板,上传文件以及行项目分析和修改逻辑的实现。

*&---------------------------------------------------------------------*
*& 包含               ZVIA_ME22_PRO_F01
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*& Form frm_download
*&---------------------------------------------------------------------*
*& 用户下载模板
*&---------------------------------------------------------------------*
FORM frm_download.
  DATA : lv_fullpath    TYPE string,
         lv_filename    TYPE string,
         lv_path        TYPE string,
         ls_objnam      TYPE string ##NEEDED,
         lo_objdata     TYPE wwwdatatab,
         ls_destination LIKE rlgrap-filename,
         lv_rc          TYPE i.

* 下载模板 需要对模板所用到的格式进行修改,代码中的.xls部分,与自己的模板保持一致 *
  CONCATENATE gc_objid '.xls' INTO ls_objnam."gc_objid在D01里面进行定义 concatenate用于拼接字符串
  CONDENSE ls_objnam NO-GAPS.
  lv_filename = ls_objnam.
  CALL METHOD cl_gui_frontend_services=>file_save_dialog "弹出选择文件保存地址的对话框
    EXPORTING
      default_extension = 'XLS'
      default_file_name = lv_filename
    CHANGING
      filename          = lv_filename "文件名
      path              = lv_path "文件地址
      fullpath          = lv_fullpath.
  IF lv_fullpath IS INITIAL.
    RETURN.
  ENDIF.

  IF sy-subrc = 0.
    SELECT SINGLE relid objid
      INTO CORRESPONDING FIELDS OF lo_objdata
      FROM wwwdata
      WHERE srtf2 = 0
      AND relid = 'FL'
      AND objid = gc_objid.
    IF sy-subrc <> 0 OR lo_objdata-objid IS INITIAL.
      RETURN.
    ENDIF.
    ls_destination = lv_fullpath.
* template download *
    CALL FUNCTION 'DOWNLOAD_WEB_OBJECT' "调用FUNCTION进行下载
      EXPORTING
        key         = lo_objdata
        destination = ls_destination
      IMPORTING
        rc          = lv_rc.
    IF lv_rc <> 0.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      RETURN.
    ENDIF.
  ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_get_path
*&---------------------------------------------------------------------*
*& 让用户选择文件路径
*&---------------------------------------------------------------------*
FORM frm_get_path .
  DATA : lt_filetable    TYPE filetable,
         ls_filetable    TYPE file_table,
         lv_rc           TYPE sy-subrc,
         lv_filename     TYPE string,
         lv_initial_path TYPE string VALUE 'C:\'. "默认打开c盘
  CLEAR lv_filename.
  lv_filename = p_path."文件路径
  CALL METHOD cl_gui_frontend_services=>file_open_dialog
    EXPORTING
      default_filename        = lv_filename
      initial_directory       = lv_initial_path
    CHANGING
      file_table              = lt_filetable
      rc                      = lv_rc
    EXCEPTIONS
      file_open_dialog_failed = 1
      cntl_error              = 2
      error_no_gui            = 3
      not_supported_by_gui    = 4.
  IF sy-subrc NE 0 OR lv_rc LT 0.
  ELSE.
    IF lv_rc = 1.
      READ TABLE lt_filetable INTO ls_filetable INDEX 1.
      p_path = ls_filetable-filename.
    ELSE.
      EXIT.
    ENDIF.
  ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_upload_excel
*&---------------------------------------------------------------------*
*& 读取用户上传的excel 需要修改,主要是读取的列按照自己的习惯,看是读取文本行再删除还是直接不读
*&---------------------------------------------------------------------*
FORM frm_upload_excel .
  DATA : lt_excel_data TYPE STANDARD TABLE OF alsmex_tabline." row col value 三个组件
  DATA : ls_upload TYPE ty_upload."自己定义的列
  DATA : lv_index TYPE i.
  FIELD-SYMBOLS : <lfs_value> TYPE any.
  IF p_path IS NOT INITIAL.
    CALL FUNCTION 'ALSM_EXCEL_TO_INTERNAL_TABLE'
      EXPORTING
        filename    = p_path "本地文件
        "从第1行第1列
        i_begin_col = 1
        i_begin_row = 1
        "读到第65536行第255列
        i_end_col   = 255
        i_end_row   = 65536
      TABLES
        intern      = lt_excel_data. "将excel的数据读到lt_excel_data中
    IF sy-subrc = 0.
      DELETE lt_excel_data WHERE row = 1."删除字段名行 即删除第一行 也可在上面的时候直接不读非数据行
      LOOP AT lt_excel_data INTO DATA(ls_excel_data).
        lv_index = ls_excel_data-col.
        ASSIGN COMPONENT lv_index OF STRUCTURE ls_upload TO <lfs_value>."给ls_upload的第lv_index个字段的数值和<lfs_value>关联
        SHIFT ls_excel_data-value LEFT DELETING LEADING space."去除空格
        <lfs_value> = ls_excel_data-value."给<lfs_value>赋值就会修改响应的结构体类似于 filed-symbol
        AT END OF row."一行读完之后插入内表
          APPEND ls_upload TO gt_upload.
          CLEAR : ls_upload.
        ENDAT.
      ENDLOOP.
    ELSE.
      PERFORM frm_disp_sys_msg.
      RETURN.
    ENDIF.
  ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_get_output
*&---------------------------------------------------------------------*
*& 1、对用户的数据进行检查 2、转换成ALV显示的格式 需要修改,判断数据存在的逻辑按照自己的表进行
*&---------------------------------------------------------------------*
FORM frm_get_output .
  DATA : ls_output TYPE ty_output.
  LOOP AT gt_upload INTO DATA(ls_upload).
    MOVE-CORRESPONDING ls_upload TO ls_output.
* 1、检查数据 看采购凭证是否是存在的 存在的才可以修改 *
    SELECT SINGLE ebeln,ebelp
      FROM ekpo"采购凭证表
      WHERE ebeln = @ls_upload-ebeln
        AND ebelp = @ls_upload-ebelp
      INTO @DATA(lw_ekpo).
    IF sy-subrc <> 0.
      ls_output-status = icon_led_red."行项目标注红灯
      MESSAGE s010
        WITH ls_output-ebeln ls_output-ebelp
        INTO ls_output-msg."消息显示在行项目MSG列上
    ELSE."存在采购凭证记录 可以进行修改
      ls_output-status = icon_led_green."行项目标注绿灯
    ENDIF.
    APPEND ls_output TO gt_output.
  ENDLOOP.
ENDFORM.

FORM frm_disp_sys_msg.
  MESSAGE ID sy-msgid TYPE 'S' NUMBER sy-msgno
    WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 DISPLAY LIKE 'E'.
ENDFORM.

*&---------------------------------------------------------------------*
*& Form frm_import_data
*&---------------------------------------------------------------------*
*& 导入数据 修改PO的数据
*& 根据gt_output即显示在ALV里面的数据进行修改 消息灯是红的不改 绿的改
*& 需要修改,这里调用BAPI的子例程填自己的
*&---------------------------------------------------------------------*
FORM frm_import_data .
* 存在消息灯是红灯的数据 不允许进行修改,只有全部绿灯才可以进行修改 *
  LOOP AT gt_output INTO DATA(ls_output) WHERE status = icon_led_red.
    MESSAGE e011.
  ENDLOOP.

* 如果没有错误,则进行修改 *
  LOOP AT gt_output ASSIGNING FIELD-SYMBOL(<fs_output>).
    PERFORM frm_change_po_by_bapi CHANGING <fs_output>.
  ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_change_po_by_bapi
*&---------------------------------------------------------------------*
*& 根据传入的数据用BAPI对PO进行批量修改
*& 需要修改 调用BAPI、BDC写自己的逻辑
*&---------------------------------------------------------------------*
FORM frm_change_po_by_bapi CHANGING is_output TYPE ty_output.
  DATA : lt_return TYPE STANDARD TABLE OF bapiret2,
         ls_item   TYPE bapimepoitem,
         lt_item   TYPE STANDARD TABLE OF bapimepoitem, "TYPE 从函数BAPI_PO_CHANGE里面得来
         ls_itemx  TYPE bapimepoitemx,
         lt_itemx  TYPE STANDARD TABLE OF bapimepoitemx.
* 和SE37测试函数时需要给的数据保持一致 *
  ls_item-po_item = is_output-ebelp.
  ls_item-short_text = is_output-txz01.
  APPEND ls_item TO lt_item."因为参数类型是表类型,所以这里必须用表来传数据
  ls_itemx-po_item = is_output-ebelp.
  ls_itemx-short_text = 'X'.
  APPEND ls_itemx TO lt_itemx.
  CALL FUNCTION 'BAPI_PO_CHANGE'
    EXPORTING
      purchaseorder = is_output-ebeln
    TABLES
      return        = lt_return
      poitem        = lt_item
      poitemx       = lt_itemx.
* 检查BAPI的调用是否正确 le_return中不能有TYPE是A/X/E的 *
  LOOP AT lt_return INTO DATA(ls_return).
    IF ls_return-type = 'A' OR ls_return-type = 'E' OR ls_return-type = 'X'.
      "本条数据没有更新成功
      is_output-status = icon_led_red.
      is_output-msg = ls_return-message.
    ENDIF.
    IF is_output-status = icon_led_red.
      CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'."出现错误回滚
    ELSE.
      is_output-status = icon_led_green.
      is_output-msg = '更新成功'.
      CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'."没有错误提交
    ENDIF.
  ENDLOOP.
ENDFORM.

五、ALV相关

几乎不用改,主要是对显示的列进行修改,改成自己的和屏幕进行创建并且需要添加一个更新PO按钮。

*&---------------------------------------------------------------------*
*& 包含               ZVIA_ME22_PRO_F02
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*& Form frm_display_alv
*&---------------------------------------------------------------------*
*& ALV显示读取到的excel数据
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
FORM frm_display_alv .
  DATA : lv_cnt_str TYPE string.
  CLEAR lv_cnt_str.
  lv_cnt_str = lines( gt_upload ).

* 上传条目记录 *
* MESSAGE s304 with lv_cnt_str *
  PERFORM frm_build_layout.
  PERFORM frm_build_fieldcat.

  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
    EXPORTING
      i_bypassing_buffer       = abap_true
      i_callback_program       = sy-cprog
      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
      i_save                   = 'A'
    TABLES
      t_outtab                 = gt_output
    EXCEPTIONS
      program_error            = 1
      OTHERS                   = 2.
  IF sy-subrc <> 0.
* Implement suitable error handling here
  ENDIF.

ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_build_layout
*&---------------------------------------------------------------------*
FORM frm_build_layout .
  CLEAR gs_layout.
  gs_layout-zebra = abap_true.
  gs_layout-col_opt = abap_true.
  gs_layout-cwidth_opt = abap_true.
  gs_layout-box_fname = 'SEL'.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_build_fieldcat
*&---------------------------------------------------------------------*
*& 需要修改,改成自己的列 消息灯、消息不用改
*&---------------------------------------------------------------------*
FORM frm_build_fieldcat .
  DATA : lv_struct   LIKE dd02l-tabname,
         ls_fieldcat TYPE lvc_s_fcat.
  REFRESH gt_fieldcat.

* 宏
  gt_fieldcat = VALUE #(
     ( fieldname = 'STATUS' coltext = TEXT-002 no_zero = ' ' edit = ' ' just = 'C' key = abap_true )"消息灯
     ( fieldname = 'MSG'    coltext = TEXT-003 no_zero = ' ' edit = ' ' just = 'C' key = abap_true )"消息
     ( fieldname = 'EBELN'  coltext = TEXT-004 no_zero = ' ' edit = ' ' just = 'C' key = abap_true )"采购订单
     ( fieldname = 'EBELP'  coltext = TEXT-005 no_zero = ' ' edit = ' ' just = 'C' key = abap_true )"采购订单行项目
     ( fieldname = 'TXZ01'  coltext = TEXT-006 no_zero = ' ' edit = ' ' just = 'C' key = abap_true )"短文本
     ( fieldname = 'MENGE'  coltext = TEXT-007 no_zero = ' ' edit = ' ' just = 'C' key = abap_true )"采购订单数量
  ).
ENDFORM.

* 双击进行屏幕创建,需要添加一个更新PO按钮 *
##CALLED
FORM frm_set_pf_status USING extab TYPE slis_t_extab.
  SET PF-STATUS 'ZSTANDARD_FULLSCREEN'.
ENDFORM.

* 需要修改,检查自己的UPDATE按钮名是否和屏幕创建的按钮是一致的 * 
FORM frm_user_command USING r_ucomm LIKE sy-ucomm rs_selfield TYPE slis_selfield ##called ##NEEDED.
  DATA : lr_grid TYPE REF TO cl_gui_alv_grid.
  DATA : ls_output LIKE LINE OF gt_output.
  DATA : lv_flg_sel TYPE boole_d,
         lv_flg_red TYPE boole_d.
  CALL FUNCTION 'GET_GLOBALS_FROM_SLVC_FULLSCR'
    IMPORTING
      e_grid = lr_grid.
  CALL METHOD lr_grid->check_changed_data.
  rs_selfield-refresh = abap_true.
  rs_selfield-col_stable = abap_true.
  rs_selfield-row_stable = abap_true.
  CASE r_ucomm.
    WHEN '&UPDATE'."和PF里面的UPDATE按钮名称保持一致
      PERFORM frm_import_data.
      PERFORM frm_refresh_alv.
  ENDCASE.
ENDFORM.

*&---------------------------------------------------------------------*
*& Form frm_refresh_data
*&---------------------------------------------------------------------*
*& 每次有改变刷新ALV表单
*&---------------------------------------------------------------------*
FORM frm_refresh_alv .
  DATA : lr_grid   TYPE REF TO cl_gui_alv_grid,
         ls_stable TYPE lvc_s_stbl,
         ls_layout TYPE lvc_s_layo.
  CALL FUNCTION 'GET_GLOBALS_FROM_SLVC_FULLSCR'
    IMPORTING
      e_grid = lr_grid.
  lr_grid->get_frontend_layout(
    IMPORTING
      es_layout = ls_layout ).
  ls_layout-cwidth_opt = 'X'.
  lr_grid->set_frontend_layout( is_layout = ls_layout ).
  ls_stable-row = abap_true.
  ls_stable-col = abap_true.
  CALL METHOD lr_grid->refresh_table_display
    EXPORTING
      is_stable = ls_stable
      i_soft_refresh = abap_true
    EXCEPTIONS
      finished = 1
      OTHERS = 2.
  IF sy-subrc ne 0.
    PERFORM frm_disp_sys_msg.
  ENDIF.
  CALL METHOD cl_gui_cfw=>flush
    EXCEPTIONS
      cntl_system_error = 1
      cntl_error = 2.
  IF sy-subrc ne 0.
    PERFORM frm_disp_sys_msg.
  ENDIF.
ENDFORM.

双击 ZSTANDARD_FULLSCREEN后创建屏幕、添加按钮过程。

这里取什么名字,在 frm_user_command子例程里面的按钮就要叫什么,不然点击触发不了后续子例程。

附:上传模板过程。 

1、先准备好模板,演示里面用的模板如图。

2、事务码SWM0选择二进制数据, 点按钮。

3、选包,点执行。

4、点创建。

5、写对象名称、描述,点下一步。

6、选文件,选包,按确认就行了。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值