目录
开发类型:
新增批导程序,实现用户批量上传EXCEL数据并展示到ALV报表(这是简易基础版本,只实现下载模板功能、选择文件上传功能、上传的文件转换为alv展示功能)
开发申请:
整个开发申请的逻辑:用户使用事务代码进入选择屏幕界面>用户下载excel数据模板>用户填写数据后上传模板>系统进行数据校验、展示数据>校验失败则提示并退出>数据校验成功则调用BDC批量生成销售订单>生成成功则返回成功消息,失败则返回失败消息
(批导功能一般会和其它功能联合使用,比如将上传的数据储存到后台表、使用上传的数据进行BAPI的调用,使用上传的数据进行BDC调用等等,涉及的东西太多,但都是根据批导功能展开,本次只讲解批导功能一个点,为后续开发打下基础)
开发步骤:
笼统来说,开发批导程序分为两步:1、准备EXCEL导入文件模板 2、写程序
1、准备EXCEL导入文件模板
一般情况下,开发申请里会附上文件模板,我们只需要将其复制下来,单独放入一个新的excel文件中就可以了,然后使用SAP事务代码SMW0,导入到SAP系统中就可以使用了。
模板设置完成后,保存并关闭文件,打开SAP系统,在首页输入SMW0事务代码,将该excel模板存入SAP系统以供使用(可供用户后续下载该模板使用)
点击右下角按钮,根据系统提示,选择我们刚才新建的EXCEL模板
可以看到在资源库中,我们已经将刚才的excel模板导入成功。
1.1 准备后台存储数据的透明表
(如果不需要储存导入的数据则不用建立,跳过这个步骤就好)
根据开发申请,我们使用SE11在SAP新建一个透明表。(一般情况下,该后台表的字段会和刚才EXCEL导入模板的字段相同,但是有些需求更加细致,比如会让后台表额外添加创建人、创建日期、创建时间、更改人、更改日期、更改时间等字段,以供后期人员运维时,判断数据来源与准确性)
创建透明表的过程不再累述,只是需要注意一个字段MANDT字段,该字段是系统自带的字段,是为了区分不同SAP环境(不同client)数据而存在的,一般情况下,都需要添加该字段,开发申请上面不会写,但是需要由开发人员自行添加。成功激活后,准备工作完成,可以进行程序编写。
1.2 程序建立
批量导入程序是类似于报表的程序,所以还是由SE38进行开发。需要注意的是,一般情况下,从外围传过来的数据是没有前导零的,如果要进行后续的数据查询,要添加前导零。
2、代码编写
这是简化版本,只实现下载模板功能、选择文件上传功能、上传的文件转换为SAP内表功能、ALV展示功能,代码运行的顺序如下:
首先定义结构、声明全局变量灯:定义上传上来的EXCEL的表结构TY_TABLE,需要和EXCEL的字段顺序一样并且一一对应,否则在SAP转换的时候会出现错位或遗漏的情况。
声明全局变量:
内表GT_TABLE,工作区GS_TABLE 储存用户上传上来的EXCEL的数据和工作区。
内表GT_ALV,工作区GS_ALV 是ALV报表展示的数据和工作区。
2.1 下载模板功能
选择屏幕的效果如下:点击"下载模板"按钮,将我们刚刚上传到SAP系统的文件"ZTFI0127"下载到用户指定的地点。
首先进行功能码(即下载模板按钮)的设置
在添加功能码之前需要引入模块池:放在代码最前面就可以
TABLES:SSCRFIELDS.(不写会报错,重要)
添加功能码:
SELECTION-SCREEN:FUNCTION KEY 1.
定义功能码的图标、ID、文本:(在定义前需要先初始化)
INITIALIZATION.(初始化,不写不显示,重要)
FUNCTXT-ICON_ID = ICON_EXPORT.(不写不显示,重要)
FUNCTXT-QUICKINFO = '下载模板'.
FUNCTXT-ICON_TEXT = '下载模板'.(不写没文本,重要)
SSCRFIELDS-FUNCTXT_01 = FUNCTXT.(不写不显示,重要)
为按钮添加子例程:(可以将将其单独写成进子例程FRM_BEFORE_EXECUTE,使其更加规范,也可以直接放入AT SELECTION-SCREEN下面。)
AT SELECTION-SCREEN .(选择屏幕的触发事件声明,重要)
PERFORM FRM_BEFORE_EXECUTE.
FORM FRM_BEFORE_EXECUTE.
CASE SSCRFIELDS-UCOMM. (用户操作)
WHEN 'FC01'. (当用户按FC01按钮)
PERFORM FRM_BEFORE_EXE. "点击按钮时调用的子例程逻辑
EXIT. (退出)
WHEN OTHERS.
ENDCASE.
ENDFORM.
下载模板的子例程的代码流程为:调用静态方法弹出保存路径弹框、下载模板文件(这一步就已经下载文件到本地了)、文件名分割、下载时一般性校验,代码截图如下:(代码比较多,后面会单独放在【附件-批导代码】里面)
调用静态方法弹出保存路径弹框 下载、分割、校验可以配套使用,根据情况而定,正常情况下,在下载模板文件这一函数"DOWNLOAD_WEB_OBJECT"调用完毕之后,文件就已经下载到本地了,后面两个函数"SO_SPLIT_FILE_AND_PATH"和"GUI_RUN"是一般性的校验,为了使整个逻辑与权限更加完整。
至此,就可以在首页点击“下载模块”功能码,实现模板下载功能,第一个功能就实现了,截图中有许多变量的声明没有显示完全,可以检查一下代码,看系统在哪些地方提示报错,再根据报错提示修改。激活代码后效果如下: 可将其下载到用户指定的文件路径下。
2.2 选择文件上传功能
这个功能实际上是选择屏幕中按钮的一个搜索帮助功能,和普通的搜索帮助不同,其它的搜索帮助是数据元素自带的或者是一些字段,而这个本地选择文件的搜索帮助需要将其转换为文件格式展示给用户,从而实现用户更加直观地选择。
设置单选按钮的搜索帮助,系统中有标准的语句,PAI事件里面的
AT SELECTION-SCREEN ON VALUE-REQUEST FOR P_FILE."P_FILE是单选按钮的名字
PERFORM FRM_F4_FILEPATH. "选择上传路径
将子例程"FRM_F4_FILEPATH"直接放入AT SELECTION-SCREEN ON VALUE-REQUEST FOR 下面,就可以实现用户在点击搜索帮助时,自动进入该子例程,调用标准功能"WS_FILENAME_GET"获取用户选择的文件名称,子例程的代码如下:
至此,就可以实现用户选择文件上传功能,激活后效果如下:
2.3 上传的EXCEL文件转化为SAP内表功能
将该子例程放在START-OF-SELECTION事件下,响应PAI用户点击事件后,第一个执行。转换的方式有很多,系统标准的函数可以使用'TEXT_CONVERT_XLS_TO_SAP'其实从函数名称就可以看出是将XLS转换为SAP内部数据的一个函数功能。
2.4 ALV展示功能
展示ALV报表,首先需要定义ALV的宏,再添加ALV字段,最后调用"REUSE_ALV_GRID_DISPLAY_LVC"即可展示。代码如下:
至此,本次批导-转换-展示功能全部完成。
代码如下:
*&---------------------------------------------------------------------*
*& Report ZFIR0113
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT ZFIR0113.
TABLES:ZTFI0127,SSCRFIELDS.
"定义上传上来的表结构
"因为上传上来的表结构和展示的ALV的结构一样,我们可以直接使用同一个结构
TYPES: BEGIN OF TY_TABLE,
VBELN TYPE VBRP-VBELN,
FKDAT TYPE VBRP-FKDAT_ANA,
MATNR TYPE VBRP-MATNR,
ARKTX TYPE VBRP-ARKTX,
FKIMG TYPE VBRP-FKIMG,
CMPRE1 TYPE VBRP-CMPRE,
NETWR TYPE VBRP-NETWR,
CMPRE2 TYPE VBRP-CMPRE,
ALLWR TYPE VBRP-NETWR,
MWSBP TYPE VBRP-MWSBP, "
END OF TY_TABLE.
DATA: GT_FCAT TYPE LVC_T_FCAT,
GS_FCAT TYPE LVC_S_FCAT,
GS_LAYO TYPE LVC_S_LAYO.
DATA:FUNCTXT TYPE SMP_DYNTXT,
FUNCTXT1 TYPE SMP_DYNTXT,
FUNCTXT2 TYPE SMP_DYNTXT.
DATA:LT_SELTAB TYPE STANDARD TABLE OF VIMSELLIST.
DATA:GV_SAVE_PATH TYPE STRING,
GT_RET TYPE STANDARD TABLE OF BAPIRET2,
GT_TABLE TYPE STANDARD TABLE OF TY_TABLE,
GS_TABLE TYPE TY_TABLE,
GT_ALV TYPE STANDARD TABLE OF TY_TABLE,
GS_ALV TYPE TY_TABLE.
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
DEFINE MACRO_ADD_FIELDCAT. "添加显示字段 定义ALV的宏
CLEAR: GS_FCAT.
GS_FCAT-FIELDNAME = &1.
GS_FCAT-SCRTEXT_L = &2.
GS_FCAT-SCRTEXT_M = &2.
GS_FCAT-SCRTEXT_S = &2.
GS_FCAT-REPTEXT = &2.
GS_FCAT-REF_TABLE = &3.
GS_FCAT-REF_FIELD = &4.
APPEND GS_FCAT TO GT_FCAT.
END-OF-DEFINITION.
SELECTION-SCREEN:FUNCTION KEY 1. "在屏幕定义功能码
INITIALIZATION.
FUNCTXT-ICON_ID = ICON_EXPORT.
FUNCTXT-QUICKINFO = '下载模板'.
FUNCTXT-ICON_TEXT ='下载模板'.
SSCRFIELDS-FUNCTXT_01 = FUNCTXT.
SELECTION-SCREEN BEGIN OF BLOCK BLK1 WITH FRAME TITLE TEXT-002 .
SELECTION-SCREEN:SKIP.
PARAMETERS:P_FILE LIKE RLGRAP-FILENAME OBLIGATORY DEFAULT 'C:\upload.xls' MODIF ID M1.
SELECTION-SCREEN END OF BLOCK BLK1.
AT SELECTION-SCREEN .
PERFORM FRM_BEFORE_EXECUTE."下载模板子例程
AT SELECTION-SCREEN OUTPUT.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR P_FILE."搜索帮助
PERFORM FRM_F4_FILEPATH. "选择上传路径
START-OF-SELECTION.
PERFORM FRM_UPLOAD_FILE. "上传Excel转化为SAP内表
PERFORM FRM_DISPLAY_DATA."展示上传上来的数据
END-OF-SELECTION.
FORM FRM_F4_FILEPATH .
DATA: LV_FILENAME LIKE RLGRAP-FILENAME.
CALL FUNCTION 'WS_FILENAME_GET'
EXPORTING
MASK = ',*.* ,*.*.'
MODE = '0'
TITLE = '请选择要上传的信息文件'
IMPORTING
FILENAME = LV_FILENAME
EXCEPTIONS
INV_WINSYS = 1
NO_BATCH = 2
SELECTION_CANCEL = 3
SELECTION_ERROR = 4
OTHERS = 5.
IF SY-SUBRC <> 0.
ENDIF.
P_FILE = LV_FILENAME.
ENDFORM.
FORM FRM_BEFORE_EXECUTE.
CASE SSCRFIELDS-UCOMM.
WHEN 'FC01'.
PERFORM FRM_BEFORE_EXE. "下载模板
EXIT.
WHEN OTHERS.
ENDCASE.
ENDFORM.
FORM FRM_BEFORE_EXE .
DATA: LS_KEY TYPE WWWDATATAB,
LV_DOWN TYPE RLGRAP-FILENAME,
LV_NAME TYPE RLGRAP-FILENAME,
LV_PATH TYPE RLGRAP-FILENAME,
LV_PATH_S TYPE STRING,
LV_NAME_S TYPE STRING,
LV_PATH_F TYPE STRING,
LV_ACTION TYPE I,
LV_TITLE TYPE STRING,
LV_FILENAME TYPE STRING.
CLEAR: LS_KEY.
LS_KEY-RELID = 'MI'. "二进制对象
LS_KEYOBJID = 'ZTFI0127'. "SMW0的名称
" CONCATENATE '' SY-DATUM '.xlsx' INTO LV_FILENAME.
LV_TITLE = TEXT-010.
CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_SAVE_DIALOG
EXPORTING
WINDOW_TITLE = LV_TITLE
DEFAULT_EXTENSION = 'xlsx'
DEFAULT_FILE_NAME = '销售流维护(终端客户)批导模板.xlsx'
FILE_FILTER = 'Excel Files(2007/2010/2013)|*.xlsx|Excel Files(2003)|*.xls'
INITIAL_DIRECTORY = GV_SAVE_PATH
CHANGING
FILENAME = LV_NAME_S
PATH = LV_PATH_S
FULLPATH = LV_PATH_F
USER_ACTION = LV_ACTION
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.
RETURN.
ELSE.
GV_SAVE_PATH = LV_PATH_S.
IF LV_ACTION EQ CL_GUI_FRONTEND_SERVICES=>ACTION_CANCEL.
MESSAGE S004(ZSD01).
RETURN.
ENDIF.
ENDIF.
LV_DOWN = LV_PATH_F.
CALL FUNCTION 'DOWNLOAD_WEB_OBJECT'
EXPORTING
KEY = LS_KEY
DESTINATION = LV_DOWN.
CALL FUNCTION 'SO_SPLIT_FILE_AND_PATH'
EXPORTING
FULL_NAME = LV_DOWN
IMPORTING
STRIPPED_NAME = LV_NAME
FILE_PATH = LV_PATH.
CALL FUNCTION 'GUI_RUN'
EXPORTING
COMMAND = 'EXCEL'
PARAMETER = LV_NAME
CD = LV_PATH.
ENDFORM.
FORM FRM_UPLOAD_FILE .
DATA LT_RAW TYPE TRUXS_T_TEXT_DATA .
DATA LV_PATH TYPE RLGRAP-FILENAME .
DATA LT_LINE TYPE C VALUE 1.
LV_PATH = P_FILE .
CALL FUNCTION 'TEXT_CONVERT_XLS_TO_SAP'
EXPORTING
I_FIELD_SEPERATOR = 'X'
I_LINE_HEADER = LT_LINE "第一行不读
I_TAB_RAW_DATA = LT_RAW "必输参数
I_FILENAME = LV_PATH "路径
TABLES
I_TAB_CONVERTED_DATA = GT_ALV[] "读取EXCEL数据到内表
EXCEPTIONS
CONVERSION_FAILED = 1
OTHERS = 2.
IF SY-SUBRC <> 0.
* Implement suitable error handling here
ENDIF.
IF GT_ALV[] IS INITIAL.
MESSAGE: '导入文件为空' TYPE 'S'.
ENDIF.
ENDFORM.
FORM FRM_DISPLAY_DATA .
CLEAR: GT_FCAT.
MACRO_ADD_FIELDCAT:
'VBELN' '发票号' '' '' ,
'FKDAT' '开票日期' '' '' ,
'MATNR' '物料号' 'MARA' 'MATNR',
'ARKTX' '物料描述' 'vbrp' 'arktx',
'FKIMG' '数量' 'vbrp' 'FKIMG',
'CMPRE1' '单价(不含税)' 'vbrp' 'CMPRE1',
'NETWR' '净值' 'vbrp' 'NETWR',
'MWSBP' '税额' 'vbrp' 'MWSBP',
'CMPRE2' '单价(含税)' 'vbrp' 'CMPRE',
'ALLWR' '金额(含税)' 'vbrp' 'NETWR'.
GS_LAYO-CWIDTH_OPT = 'X'.
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
EXPORTING
I_CALLBACK_PROGRAM = SY-REPID
IS_LAYOUT_LVC = GS_LAYO
IT_FIELDCAT_LVC = GT_FCAT
I_DEFAULT = 'X'
I_SAVE = 'A'
TABLES
T_OUTTAB = GT_ALV.
IF SY-SUBRC <> 0.
* Implement suitable error handling here
ENDIF.
ENDFORM.