[SAP ABAP] Excel批量维护货源清单

在SAP中,货源清单是控制物料只能从特定供应商处采购的主数据,它定义了物料与供应商、工厂、采购组织之间的合法供应关系

相对于逐条使用事务代码 ME01 维护货源清单,开发自定义程序,通过Excel批量维护货源清单,能够降低用户的使用门槛,同时提升用户的工作效率

Excel导入模板

效果展示

用户在Excel导入模板填写相关信息以后,进行文件上传操作

点击执行按钮,效果如下所示:

提示Tips:自定义程序,增设了数据校验逻辑,当用户执行Excel文件上传以后,会进行ALV报表呈现用户上传的结果,如果消息灯报红灯,表明Excel填写的信息在SAP系统里面不存在,或者格式输入不正确,点击【批量导入】按钮创建维护货源清单的时候,消息灯报红的那一行明细是无法创建或更新货源清单的

点击【批量导入】按钮,执行结果呈现如下图所示

我们可以看到ALV报表的消息灯报绿灯,表明Excel指定的那行明细已经成功导入到SAP系统中了,我们可以使用ME01 或者 ME03 去查看成功导入的那行明细信息

完整代码如下所示

主程序(zrs0513)

复制代码
*&---------------------------------------------------------------------*
*& Report  ZRS0513                                                     *
*&---------------------------------------------------------------------*

************************************************************************
* Program ID: ZRS0513
* Program Description: Excel批量維護貨源清單
* Programmer Name : Andy
* Create Date: 2026/08/17
* Change History:
*----------------------------------------------------------------------*
* Ver.     SR/Project     Date        Author       Description
*------- --------------- ------------ ---------- ----------------------*
* V001                    2026/08     Andy        Excel批量維護貨源清單
*----------------------------------------------------------------------*

REPORT  zrs0513.

INCLUDE zrs0513_top. " 數據定義

INCLUDE zrs0513_f01. " 子例程


*----------------------------------------------------------------------*
*  DESC: INITIALIZATION
*----------------------------------------------------------------------*
INITIALIZATION.


*----------------------------------------------------------------------*
*  DESC: AT SELECTION-SCREEN ON VALUE-REQUEST FOR [field] 事件
*----------------------------------------------------------------------*
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_path.  " 為選擇屏幕的自定義字段提供搜索幫助
  PERFORM frm_get_path.


*----------------------------------------------------------------------*
*  DESC: AT SELECTION-SCREEN
*----------------------------------------------------------------------*
AT SELECTION-SCREEN.


*----------------------------------------------------------------------*
*  DESC: START-OF-SELECTION
*----------------------------------------------------------------------*
START-OF-SELECTION.
  PERFORM frm_upload_excel.  " 解析Excel文件中的數据
  PERFORM frm_get_output.    " 將Upload數据存放到呈現ALV的相關內表


*----------------------------------------------------------------------*
*  DESC: END-OF-SELECTION
*----------------------------------------------------------------------*
END-OF-SELECTION.
  PERFORM frm_display_alv.   " ALV呈現數据

INCLUDE程序(zrs0513_top)

复制代码
*&---------------------------------------------------------------------*
*& 包含               ZRS0513_TOP
*&---------------------------------------------------------------------*

TYPE-POOLS: slis.

TABLES: eord.

* 選擇屏幕
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001.

  PARAMETERS: p_path TYPE rlgrap-filename.  " 上傳文件路徑

SELECTION-SCREEN END OF BLOCK b1.


* 自定義數據類型
TYPES: BEGIN OF ty_upload,
         werks TYPE eord-werks,    " Plant
         matnr TYPE eord-matnr,    " Material
         lifnr TYPE eord-lifnr,    " Vendor
         vdatu TYPE eord-vdatu,    " Valid From
         bdatu TYPE eord-bdatu,    " Valid To
         ekorg TYPE eord-ekorg,    " POrg
       END OF ty_upload.

TYPES: BEGIN OF ty_output,
         werks  TYPE eord-werks,    " Plant
         matnr  TYPE eord-matnr,    " Material
         lifnr  TYPE eord-lifnr,    " Vendor
         vdatu  TYPE eord-vdatu,    " Valid From
         bdatu  TYPE eord-bdatu,    " Valid To
         ekorg  TYPE eord-ekorg,    " POrg
         msg    TYPE bapi_msg,     " 消息
         status TYPE icon_d,       " 消息燈
         sel(1) TYPE c,            " 選擇標志
       END OF ty_output.


* 定義內表和結構體變量
DATA: gs_upload TYPE ty_upload,
      gt_upload TYPE STANDARD TABLE OF ty_upload,   " gt_upload內表用于存儲解析上傳的Excel文件數据
      gs_output TYPE ty_output,
      gt_output TYPE STANDARD TABLE OF ty_output.   " gt_output內表用于存儲展示在ALV報表的數据


* ALV參數定義
DATA: gs_layout TYPE lvc_s_layo,                    " 用于定義ALV表單的相關格式、屬性
      gs_fcat   TYPE lvc_s_fcat,                    " 字段目錄工作區
      gt_fcat   LIKE TABLE OF gs_fcat.              " 字段目錄內表

INCLUDE程序(zrs0513_f01)

复制代码
*&---------------------------------------------------------------------*
*& 包含               ZRS0513_F01
*&---------------------------------------------------------------------*

*&---------------------------------------------------------------------*
*&      Form  frm_get_path
*&---------------------------------------------------------------------*
*       獲取文件上傳路徑
*----------------------------------------------------------------------*
form frm_get_path.
  data: lt_file_table	type filetable,
        lv_rc           type i,
        lv_initial_path type string value 'C:\',
        ls_file         type file_info.

  " ABAP對象模式(調用類的方法)---提供文件選擇對話框的方式獲取文件的完整路徑
  call method cl_gui_frontend_services=>file_open_dialog
    exporting
      initial_directory       = lv_initial_path  " 默認上傳路徑
    changing
      file_table              = lt_file_table    " 上傳文件的完整路徑
      rc                      = lv_rc
    exceptions
      file_open_dialog_failed = 1
      cntl_error              = 2
      error_no_gui            = 3
      not_supported_by_gui    = 4
      others                  = 5.
  if sy-subrc = 0.
    read table lt_file_table into ls_file index 1.
    if sy-subrc = 0.
      p_path = ls_file-filename.  " 文件路徑賦值
    endif.
  endif.

endform.                    "frm_get_path


*&---------------------------------------------------------------------*
*&      Form  frm_upload_excel
*&---------------------------------------------------------------------*
*       解析Excel文件中的數据
*----------------------------------------------------------------------*
form frm_upload_excel.
  data: lv_filename type rlgrap-filename,
        lt_data type standard table of alsmex_tabline,
        ls_data type alsmex_tabline.

  field-symbols: <lfv_value> type any.  " 顯式聲明字段符號

  if p_path is not initial.  " 判斷文件路徑是否不為空
    lv_filename = p_path.    " 賦值

    " 調用函數,讀取Excel文件中的數据存放到內表中
    call function 'ALSM_EXCEL_TO_INTERNAL_TABLE'
      exporting
        filename                = lv_filename    " 導入的文件名稱路徑
        i_begin_col             = 2              " 導入單元格的開始列
        i_begin_row             = 2              " 導入單元格的開始行
        i_end_col               = 255            " 導入單元格的結束列
        i_end_row               = 65536          " 導入單元格的結束行
      tables
        intern                  = lt_data        " 內表,存儲單元格中的內容
      exceptions
        inconsistent_parameters = 1
        upload_ole              = 2
        others                  = 3.

    " 將內表lt_data中的值轉換到內表gt_upload中
    loop at lt_data into ls_data.
      assign component ls_data-col of structure gs_upload to <lfv_value>.
      shift ls_data-value left deleting leading space.  " 去除空格
      <lfv_value> = ls_data-value.  " 賦值
      at end of row.
        append gs_upload to gt_upload.
        clear  gs_upload.
      endat.
    endloop.
  else.
    message '文件路徑為空,請上傳文件!' type 'I'.
  endif.
endform.                    " frm_upload_excel


*&---------------------------------------------------------------------*
*&      Form  frm_get_output
*&---------------------------------------------------------------------*
*       將Upload數据存放到呈現ALV的相關內表
*----------------------------------------------------------------------*
form frm_get_output.

  " 校驗用的變量
  data: lv_plant_check  like t001w-werks,
        lv_matnr_check  like mara-matnr,
        lv_marc_check   like mara-matnr,
        lv_lifnr_check  like lfa1-lifnr,
        lv_lfm1_check   like lfa1-lifnr,
        lv_ekorg_check  like t024e-ekorg.

  constants: lv_icon_red   type char4 value '@0A@'.   " 紅色LED圖標代碼
  constants: lv_icon_green type char4 value '@08@'.   " 綠色LED圖標代碼

  refresh gt_output.

  loop at gt_upload into gs_upload.
    " 供應商增加前導零
    call function 'CONVERSION_EXIT_ALPHA_INPUT'
      exporting
        input  = gs_upload-lifnr
      importing
        output = gs_upload-lifnr. " 補0后的結果

    move-corresponding gs_upload to gs_output.   " 賦值
    append gs_output to gt_output.
    clear: gs_upload, gs_output.
  endloop.

  field-symbols: <lfs_output> type ty_output.

* 數據校驗
  if gt_output is not initial.
    loop at gt_output assigning <lfs_output>.
*     校驗工廠
      if <lfs_output>-werks is initial.
        <lfs_output>-status = lv_icon_red.
        message e000(zrs0513_msg) into <lfs_output>-msg. " Plant 必填
        continue.
      else.
        select single werks from t001w
          into lv_plant_check
          where werks = <lfs_output>-werks.
        if sy-subrc <> 0.
          <lfs_output>-status = lv_icon_red.
          message e001(zrs0513_msg) with <lfs_output>-werks into <lfs_output>-msg. " Plant &1不存在
          continue.
        endif.
      endif.

*     校驗物料
      if <lfs_output>-matnr is initial.
        <lfs_output>-status = lv_icon_red.
        message e002(zrs0513_msg) into <lfs_output>-msg. " Matnr 必填
        continue.
      else.
        select single matnr from mara
          into lv_matnr_check
          where matnr = <lfs_output>-matnr.
        if sy-subrc <> 0.
          <lfs_output>-status = lv_icon_red.
          message e003(zrs0513_msg) with <lfs_output>-matnr into <lfs_output>-msg. " Material &1不存在
          continue.
        else.
          " 檢查物料是否在工厂下維護
          select single matnr from marc
            into lv_marc_check
            where matnr = <lfs_output>-matnr
              and werks = <lfs_output>-werks.
          if sy-subrc <> 0.
            <lfs_output>-status = lv_icon_red.
            message e004(zrs0513_msg) with <lfs_output>-matnr <lfs_output>-werks into <lfs_output>-msg. " Material &1 未在廠別 &2 下維護
            continue.
          endif.
        endif.
      endif.

*     校驗供應商
      if <lfs_output>-lifnr is initial.
        <lfs_output>-status = lv_icon_red.
        message e005(zrs0513_msg) into <lfs_output>-msg. " Vendor 必填
        continue.
      else.
        select single lifnr from lfa1
          into lv_lifnr_check
          where lifnr = <lfs_output>-lifnr.
        if sy-subrc <> 0.
          <lfs_output>-status = lv_icon_red.
          message e006(zrs0513_msg) with <lfs_output>-lifnr into <lfs_output>-msg. " 供應商 &1不存在
          continue.
        else.
          " 檢查供應商是否在采購組織下維護
          select single lifnr from lfm1
            into lv_lfm1_check
            where lifnr = <lfs_output>-lifnr
              and ekorg = <lfs_output>-ekorg.
          if sy-subrc <> 0.
            <lfs_output>-status = lv_icon_red.
            message e007(zrs0513_msg) with <lfs_output>-lifnr <lfs_output>-ekorg into <lfs_output>-msg. " 供應商 &1 未在採購組織 &2 下維護
            continue.
          endif.
        endif.
      endif.

*     校驗採購組織
      if <lfs_output>-ekorg is initial.
        <lfs_output>-status = lv_icon_red.
        message e008(zrs0513_msg) into <lfs_output>-msg. " POrg 必填
        continue.
      else.
        select single ekorg from t024e
          into lv_ekorg_check
          where ekorg = <lfs_output>-ekorg.
        if sy-subrc <> 0.
          <lfs_output>-status = lv_icon_red.
          message e009(zrs0513_msg) with <lfs_output>-ekorg into <lfs_output>-msg. " 採購組織 &1不存在
          continue.
        endif.
      endif.

*     校驗日期
      if <lfs_output>-vdatu is initial.
        <lfs_output>-status = lv_icon_red.
        message e010(zrs0513_msg) into <lfs_output>-msg. " Valid from 必填
        continue.
      else.
        call function 'DATE_CHECK_PLAUSIBILITY'
          exporting
            date                      = <lfs_output>-vdatu
          exceptions
            plausibility_check_failed = 1
            others                    = 2.
        if sy-subrc <> 0.
          <lfs_output>-status = lv_icon_red.
          message e011(zrs0513_msg) with <lfs_output>-vdatu into <lfs_output>-msg. " 起始日期 &1 無效
          continue.
        endif.
      endif.

      if <lfs_output>-bdatu is initial.
        <lfs_output>-status = lv_icon_red.
        message e012(zrs0513_msg) into <lfs_output>-msg. " Valid to 必填
        continue.
      else.
        call function 'DATE_CHECK_PLAUSIBILITY'
          exporting
            date                      = <lfs_output>-bdatu
          exceptions
            plausibility_check_failed = 1
            others                    = 2.
        if sy-subrc <> 0.
          <lfs_output>-status = lv_icon_red.
          message e013(zrs0513_msg) with <lfs_output>-bdatu into <lfs_output>-msg. " 截止日期 &1 無效
          continue.
        endif.
      endif.

      " 檢查起始日期是否小于等于截止日期
      if <lfs_output>-vdatu is not initial and <lfs_output>-bdatu is not initial.
        if <lfs_output>-vdatu > <lfs_output>-bdatu.
          <lfs_output>-status = lv_icon_red.
          message e014(zrs0513_msg) into <lfs_output>-msg. " 起始日期不能大于截止日期
          continue.
        endif.
      endif.

    endloop.
  endif.


endform.                    " frm_get_output


*&---------------------------------------------------------------------*
*&      Form  frm_display_alv
*&---------------------------------------------------------------------*
*       ALV呈現數据
*----------------------------------------------------------------------*
form frm_display_alv.
  perform frm_alv_set_fields.

  " 調用函數顯示ALV數据
  call function 'REUSE_ALV_GRID_DISPLAY_LVC'
    exporting
      i_callback_program       = sy-cprog
      i_callback_pf_status_set = 'FRM_SET_PF_STATUS'  " 子例程(設置狀態欄)
      i_callback_user_command  = 'FRM_USER_COMMAND'   " 子例程(用戶指令響應)
      i_bypassing_buffer       = abap_true
      is_layout_lvc            = gs_layout            " 設置ALV布局
      it_fieldcat_lvc          = gt_fcat              " 設置ALV列屬性
      i_save                   = 'A'
    tables
      t_outtab                 = gt_output            " 內表數据
    exceptions
      program_error            = 1
      others                   = 2.
endform.                    " frm_display_alv


*&---------------------------------------------------------------------*
*&      Form  frm_alv_set_fields
*&---------------------------------------------------------------------*
*       設置ALV樣式和字段屬性
*----------------------------------------------------------------------*
form frm_alv_set_fields.

* 設置行的屬性(alv界面格式)
  clear gs_layout.
  gs_layout-box_fname  = 'SEL'.      " 選擇標識
  gs_layout-zebra      = abap_true.  " 斑馬條紋顯示
  gs_layout-cwidth_opt = abap_true.  " 优化列寬設置
  gs_layout-col_opt    = abap_true.

* ALV字段處理宏
  define catalog.
    gs_fcat-fieldname     = &1.  " 設置要輸出的表格列的值,在內表中定義的字段名(必須大寫)
    gs_fcat-scrtext_l     = &2.  " 設置要輸出的表格列的列名,即ALV報表顯示的列名
    gs_fcat-no_zero       = &3.  " 去除前導零
    gs_fcat-edit          = &4.  " 可編輯
    gs_fcat-just          = &5.  " 對齊方式
    gs_fcat-key           = &6.  " 關鍵字段

    append gs_fcat to gt_fcat.
  end-of-definition.

*     &1          &2                    &3     &4       &5             &6
  catalog:
    'STATUS'     '消息燈'               ''     ''      'C'        'abap_true',     " 消息燈
    'MSG'        '消息'                 ''     ''      ''         'abap_true',     " 消息
    'WERKS'      '廠別'                 ''     ''      ''         'abap_true',     " Plant
    'MATNR'      '物料編碼'             ''     ''      ''         'abap_true',     " Material
    'LIFNR'      '供應商編碼'           ''     ''      ''         'abap_true',     " Vendor
    'VDATU'      '有效期起'             ''     ''      ''         'abap_true',     " Valid From
    'BDATU'      '有效期止'             ''     ''      ''         'abap_true',     " Valid To
    'EKORG'      '採購組織'             ''     ''      ''         'abap_true'.     " POrg
endform.                    " frm_alv_set_fields


* 設置狀態欄
form frm_set_pf_status using ct_extab type slis_t_extab.
  set pf-status 'ZSTALV' excluding ct_extab.
endform.                    "frm_set_pf_status


* 設置用戶指令響應
form frm_user_command using pv_ucomm like sy-ucomm
                            ps_selfield type slis_selfield.

  case pv_ucomm.
    when '&ZUPLOAD'.
      perform frm_import_data.
  endcase.

  ps_selfield-refresh = 'X'. " 強制刷新

endform.                    "frm_user_command


*&---------------------------------------------------------------------*
*&      Form  frm_import_data
*&---------------------------------------------------------------------*
*       批量導入維護貨源清單
*----------------------------------------------------------------------*
form frm_import_data.

  data: lt_eordu like table of eordu with header line.

  constants: lv_icon_red   type char4 value '@0A@'.     " 紅色LED圖標代碼
  constants: lv_icon_green type char4 value '@08@'.     " 綠色LED圖標代碼

  data: lv_zeord type eord-zeord,
        lv_infnr type eine-infnr.

* 調用函數之前需要對數据進行排序
  sort gt_output by werks matnr.  " 排序

  field-symbols: <lfs_output> type ty_output.

* ALV獲取可以進行批導的數据(消息燈不報紅的數据)
  loop at gt_output assigning <lfs_output> where status is initial.

    clear: lt_eordu, lt_eordu[], lv_zeord, lv_infnr.
    refresh lt_eordu.

    " 檢查貨源清單是否存在
    select single zeord
      from eord
      into lv_zeord
      where matnr = <lfs_output>-matnr
        and lifnr = <lfs_output>-lifnr
        and werks = <lfs_output>-werks
        and ekorg = <lfs_output>-ekorg.

    move-corresponding <lfs_output> to lt_eordu.  " 賦值
    lt_eordu-erdat = sy-datum.
    lt_eordu-ernam = sy-uname.

    if sy-subrc = 0 and lv_zeord is not initial.
      " 記錄已存在,更新
      lt_eordu-kz = 'U'.
      lt_eordu-zeord = lv_zeord.   " 更新時傳入系統記錄號
    else.
      " 記錄不存在,新增
      lt_eordu-kz = 'I'.
    endif.

    append lt_eordu.

    call function 'ME_INITIALIZE_SOURCE_LIST'.  " 源清單維護初始化

    call function 'ME_DIRECT_INPUT_SOURCE_LIST'
      exporting
        i_matnr          = lt_eordu-matnr
        i_werks          = lt_eordu-werks
      tables
        t_eord           = lt_eordu[]
      exceptions
        plant_missing    = 1
        material_missing = 2
        error_message    = 4
        others           = 3.
    if sy-subrc ne 0.
      call function 'BAPI_TRANSACTION_ROLLBACK'.
      <lfs_output>-status = lv_icon_red.     " 消息燈報紅
      message id sy-msgid type 'E' number sy-msgno with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 into <lfs_output>-msg.
    else.
      call function 'ME_POST_SOURCE_LIST_NEW'
        exporting
          i_matnr = lt_eordu-matnr.

      call function 'BAPI_TRANSACTION_COMMIT'
        exporting
          wait = 'X'.
      <lfs_output>-status = lv_icon_green.   " 消息燈報綠

      if lt_eordu-kz = 'U'.
        <lfs_output>-msg = '貨源清單更新成功'.
      else.
        <lfs_output>-msg = '貨源清單創建成功'.
      endif.
    endif.
  endloop.
endform.                    " frm_import_data

上述代码涉及的消息类以及文本元素如下所示
消息类(ZRS0513_MSG)文本内容
TEXT-001文本内容

GUI STATUS状态栏

相关推荐
山茶花开时。1 天前
[SAP ABAP] ALV报表练习5
sap·sap abap·alv报表
SAP_奥维奥科技2 天前
化工企业SAP ERP怎么选?从第一次没做成,到连续做到第八期
sap
Henry-SAP5 天前
具身智能新突破:开源生态与IPO热潮
人工智能·云原生·sap·erp
Henry-SAP7 天前
SAP引领ERP智能化转型
人工智能·云原生·sap·erp
爱喝水的鱼丶8 天前
SAP-ABAP:BAPI 基础认知:SAP 标准业务对象接口的核心逻辑与调用入门
信息可视化·性能优化·sap·abap·bapi·开发交流·交流学习
Henry-SAP9 天前
SAP S/4HANA引领物流ERP新生态
人工智能·云原生·sap·erp
rm -rf * && haha.sh9 天前
【ABAP】SUBMIT 用法详解
sap·abap·abap开发
爱喝水的鱼丶11 天前
SAP-ABAP:性能优化效果验证与回归测试:优化前后性能对比、业务逻辑兼容性校验方案
性能优化·sap·abap·回归测试·开发交流·交流学习
Henry-SAP11 天前
SAP MRP类型如何影响计划订单生成
人工智能·云原生·sap·erp