什么是DOI
DOI是Desktop Office Integration
的缩写,是SAP提供的解决与Office集成的开发技术。早期SAP用于解决Office集成,使用的是OLE技术。
OLE有两个比较大的缺点:
一是语法参照VBA,在ABAP中使用各种VBA的方法(method),语法的友好性差;
二是数据写入到Excel中,速度特别慢,慢得难以接受。
DOI是SAP提供的OLE的替代品,用面向对象的方式实现。很好的解决了上面所说的两个问题。
请参考:Desktop Office Integration官方帮助
DOI开发的要点
涉及的关对象
SAP和Office集成,可以通过代码创建Excel文档,也可以将Excel模板文档放在应用程序服务器上。DOI打开这个文档,然后对文档进行操作。我们先介绍创建Excel文档的方式。
为了操作Excel文档,至少需要四个对象:
Container: 存放excel电子表格(spreadsheet)的容器。这个开发人员应该比较容易理解,展示spreadsheet肯定需要一个容器来存放。这个容器一般在dialog screen中定义,也可以直接使用ABAP程序默认的screen(即screen号码为1000的屏幕)
container control: 容器中用于创建和管理其他Office集成所需要的对象。container control是一个接口,类型是
i_oi_container_control
。document proxy: 每一个document proxy的实例代表用office application打开的文档,可以是excel,也可以是word。如果想打开多个文档,需要定义多个实例。document proxy是一个接口,类型为
i_oi_document_proxy
。spreadsheet: spreadsheet接口,代表最终要操作的excel文档。spreadhseet的类型是
i_oi_spreadsheet
如果读取服务器上的文档模板,需要cl_bds_document_set
类:
- business document set: bds是
business document set
的缩写。business document set用于管理后续要操作的文档,可以包含一个或多个文档。
DOI操作文档的步骤
- 获取container
- 创建container control对象实例并初始化
- 创建document proxy对象的实例
- 打开一个服务器上的模板文档或新建一个excel文档
- 操作excel文档,设置excel的属性
- 退出时关闭excel文档,释放资源
我们的第一个例子,不使用dialog screen,新建一个excel文档,在屏幕1000中显示。
开始编码
定义公共变量
* desktop office integration interface data: gr_container type ref to cl_gui_container, gr_control type ref to i_oi_container_control, gr_document type ref to i_oi_document_proxy, gr_spreadsheet type ref to i_oi_spreadsheet.
这些就是我们前面提到的四个必须的对象。
获取container
cl_gui_container
类的静态方法screen0
获取屏幕1000,并赋值给gr_container。
form get_container.
gr_container = gr_container = cl_gui_container=>screen0.
endform. "get_container
创建container control对象实例并初始化
form create_container_control.
* create container control
call method c_oi_container_control_creator=>get_container_control
importing
control = gr_control.
* initialize control
call method gr_control->init_control
exporting
inplace_enabled = 'X '
inplace_scroll_documents = 'X'
register_on_close_event = 'X'
register_on_custom_event = 'X'
r3_application_name = 'DOI demo by Stone Wang'
parent = gr_container.
endform.
代码比较直观,不多说。
创建document proxy对象的实例
form create_excel_document.
call method gr_control->get_document_proxy
exporting
document_type = 'Excel.Sheet'
no_flush = 'X'
importing
document_proxy = gr_document.
call method gr_document->create_document
exporting
document_title = 'DOI test by Stone Wang '
no_flush = 'X '
open_inplace = 'X'.
endform. "create_excel_document
open_inplace参数控制excel文档是独立显示还是在SAP GUI中嵌入显示。如果嵌入显示,gr_control的init_control方法中,inplace_enabled参数要设为X
。
将以上代码综合在一起:
form main.
skip 1.
perform get_container.
perform create_container_control.
perform create_excel_document.
endform.
注意第一句skip 1必须,否则不能创建屏幕。
完整代码
report zdoi_hello.
type-pools: soi.
data: gr_container type ref to cl_gui_container,
gr_control type ref to i_oi_container_control,
gr_document type ref to i_oi_document_proxy,
gr_spreadsheet type ref to i_oi_spreadsheet.
start-of-selection.
perform main.
form get_container.
gr_container = gr_container = cl_gui_container=>screen0.
endform. "get_container
form create_container_control.
* create container control
call method c_oi_container_control_creator=>get_container_control
importing
control = gr_control.
* initialize control
call method gr_control->init_control
exporting
inplace_enabled = 'X '
inplace_scroll_documents = 'X'
register_on_close_event = 'X'
register_on_custom_event = 'X'
r3_application_name = 'DOI demo by Stone Wang'
parent = gr_container.
endform. "create_container_control
form create_excel_document.
call method gr_control->get_document_proxy
exporting
document_type = 'Excel.Sheet'
no_flush = 'X'
importing
document_proxy = gr_document.
call method gr_document->create_document
exporting
document_title = 'DOI test by Stone Wang '
no_flush = 'X '
open_inplace = 'X'.
endform. "create_excel_document
form main.
skip 1.
perform get_container.
perform create_container_control.
perform create_excel_document.
endform.
应用案例1
*&---------------------------------------------------------------------*
*& Report ZFI1029_D01
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zfi1029_d01.TABLES:zsfi0277,faglflext,ztfi1000_01.
INCLUDE zfi_authority_check.**************************************************************************
*--------------------------------变量定义--------------------------------*
**************************************************************************TYPES:
BEGIN OF ty_all,
bukrs TYPE ztfi0005-hcode,
butxt TYPE ztfi0005-hname,
bbzt TYPE char6, "保存状态
itab TYPE zsfi0319_t,
END OF ty_all,
BEGIN OF ty_output_meta,
sheet_name TYPE char10,
row TYPE i,
column TYPE i,
value TYPE char100,
END OF ty_output_meta,BEGIN OF ty_datum,
datum TYPE char20,
END OF ty_datum.DATA:
gv_message TYPE char100,
gv_bbzt TYPE char6,
gv_zpath TYPE localfile, "文件路径
g_fname TYPE string,
gv_ok TYPE i,
gt_output_meta TYPE TABLE OF ty_output_meta,
gt_datum TYPE TABLE OF ty_datum, "查询期间
gt_itab TYPE TABLE OF zsfi0319, "非重复的往来公司
gt_all TYPE TABLE OF ty_all. "全部公司的报表数据DATA:
go_table TYPE REF TO data. "期末数
**************************************************************************
*--------------------------------选择画面--------------------------------*
**************************************************************************
SELECT-OPTIONS:
s_bukrs FOR ztfi1000_01-bukrs OBLIGATORY MEMORY ID buk.
PARAMETERS:
p_gjahr TYPE ztfi1000_01-gjahr OBLIGATORY,
p_monat TYPE ztfi1000_01-monat OBLIGATORY.
*SELECTION-SCREEN BEGIN OF BLOCK b01 WITH FRAME TITLE TEXT-t01.
*PARAMETERS:
* p_total AS CHECKBOX ,
* p_bg AS CHECKBOX USER-COMMAND uc1,
* p_mail TYPE ad_smtpadr,
* p_subj TYPE so_obj_des.
*
*SELECTION-SCREEN END OF BLOCK b01.* 公司代码帮助专用
SELECT-OPTIONS:
s_accgrp FOR zsfi0277-parentaccgroup NO-DISPLAY,
s_acc FOR faglflext-racct NO-DISPLAY.INITIALIZATION.
DATA(l_period) = zcl_fi_utility=>get_default_closing_period( ).
p_gjahr = l_period+0(4).
p_monat = l_period+4(2).AT SELECTION-SCREEN OUTPUT.
* LOOP AT SCREEN.
* IF screen-name CP '*P_MAIL*'
* OR screen-name CP '*P_SUBJ*' .
* IF p_bg = ''.
* screen-active = 0.
* ELSE.
* screen-active = 1.
* ENDIF.
* MODIFY SCREEN.
* ENDIF.
* ENDLOOP.**************************************************************************
*----------------------------------事件----------------------------------*
**************************************************************************
AT SELECTION-SCREEN ON VALUE-REQUEST FOR s_bukrs-low.
PERFORM f4_bukrs USING 'S_BUKRS-LOW'.AT SELECTION-SCREEN ON VALUE-REQUEST FOR s_bukrs-high.
PERFORM f4_bukrs USING 'S_BUKRS-HIGH'.AT SELECTION-SCREEN.
“公司代码权限检查START-OF-SELECTION.
* IF p_bg IS NOT INITIAL. "后台模式
* IF p_mail IS INITIAL.
* MESSAGE TEXT-e01 TYPE 'S' DISPLAY LIKE 'E'.
* STOP.
* ENDIF.
* PERFORM frm_run_as_job.
* " no need to return the current program, as it's already submit as background job
* STOP.
* ENDIF.
* 取得权益占用统计报表
PERFORM frm_impotr_zfi1000_r01.* 编辑模板第一列数据
PERFORM frm_edit_col.* 编辑模板表内容
PERFORM frm_edit_data.* 取得路径
PERFORM frm_get_oath.IF gv_zpath IS INITIAL AND sy-batch IS INITIAL.
MESSAGE '操作已取消' TYPE 'S'.
LEAVE LIST-PROCESSING.
ENDIF.* 导出excel
* PERFORM frm_download_meta_data.
* PERFORM frm_export_excel_xlsm.
PERFORM frm_export_excel.**************************************************************************
*---------------------------------主处理---------------------------------*
***************************************************************************&---------------------------------------------------------------------*
*& Form F4_BUKRS
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
FORM f4_bukrs USING iv_field.DATA: lv_flag TYPE c,
lv_fd(132) TYPE c.DATA: ls_accgrp LIKE LINE OF s_accgrp,
ls_acc LIKE LINE OF s_acc.DATA: lt_tree TYPE zfi_t_account_tree_alv,
lt_tree_selected LIKE lt_tree,
ls_tree LIKE LINE OF lt_tree.DATA ls_bukrs LIKE LINE OF s_bukrs.
DATA: lv_dyname TYPE d020s-prog,
lv_dynumb TYPE d020s-dnum,
lt_dynpfields TYPE STANDARD TABLE OF dynpread,
ls_dynpfields LIKE LINE OF lt_dynpfields.CONSTANTS lc_dynnr_sel TYPE sy-dynnr VALUE '1000'.
CONSTANTS lc_group TYPE ktopl VALUE 'VK00'.
CONSTANTS: lc_sign LIKE ls_bukrs-sign VALUE 'I',
lc_option LIKE ls_bukrs-option VALUE 'EQ'.* Search help only allowed in standard selection screen
IF sy-dynnr <> lc_dynnr_sel.
GET CURSOR FIELD lv_fd.
CALL FUNCTION 'F4IF_FIELD_VALUE_REQUEST'
EXPORTING
tabname = 'T001'
fieldname = 'BUKRS'
searchhelp = 'C_T001'
dynpprog = sy-repid
dynpnr = sy-dynnr
dynprofield = lv_fd.RETURN.
ENDIF.
* Get old select from selection screen other elements
ls_tree-finalflag = abap_true.
LOOP AT s_accgrp INTO ls_accgrp.ls_tree-accgroup = ls_accgrp-low.
APPEND ls_tree TO lt_tree_selected.ENDLOOP.
CLEAR ls_tree-finalflag.
LOOP AT s_acc INTO ls_acc.ls_tree-accgroup = ls_acc-low.
APPEND ls_tree TO lt_tree_selected.ENDLOOP.
REFRESH: s_accgrp,
s_acc.CALL FUNCTION 'ZFI_BUKRS_TREE_HELP'
EXPORTING
iv_group = lc_group
iv_sub = abap_true
it_selected_acc = lt_tree_selected
IMPORTING
ct_acc_tree = lt_tree
cv_exit = lv_flag.
IF lv_flag IS NOT INITIAL.
EXIT.
ELSE.
REFRESH s_bukrs.
ENDIF.IF NOT lt_tree IS INITIAL.
ls_bukrs-sign = lc_sign.
ls_bukrs-option = lc_option.LOOP AT lt_tree INTO ls_tree
WHERE finalflag IS INITIAL.ls_bukrs-low = ls_tree-accgroup.
APPEND ls_bukrs TO s_bukrs.ENDLOOP.
* Update selection screen backup elements
ls_accgrp-sign = lc_sign.
ls_accgrp-option = lc_option.ls_acc-sign = lc_sign.
ls_acc-option = lc_option.LOOP AT lt_tree INTO ls_tree.
IF ls_tree-finalflag = abap_true.
ls_accgrp-low = ls_tree-accgroup.
APPEND ls_accgrp TO s_accgrp.ELSE.
ls_acc-low = ls_tree-accgroup.
APPEND ls_acc TO s_acc.ENDIF.
ENDLOOP.
ENDIF.
* Sychronize S_HKONT-LOW with first account
lv_dyname = sy-repid.
lv_dynumb = sy-dynnr.ls_dynpfields-fieldname = iv_field.
READ TABLE s_bukrs INDEX 1 INTO ls_bukrs.
IF sy-subrc = 0.ls_dynpfields-fieldvalue = ls_bukrs-low.
ENDIF.
APPEND ls_dynpfields TO lt_dynpfields.CALL FUNCTION 'DYNP_VALUES_UPDATE'
EXPORTING
dyname = lv_dyname
dynumb = lv_dynumb
TABLES
dynpfields = lt_dynpfields
EXCEPTIONS
invalid_abapworkarea = 1
invalid_dynprofield = 2
invalid_dynproname = 3
invalid_dynpronummer = 4
invalid_request = 5
no_fielddescription = 6
undefind_error = 7
OTHERS = 8.
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.
*&---------------------------------------------------------------------*
*& Form FRM_IMPOTR_ZFI1000_R01
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
FORM frm_impotr_zfi1000_r01 .DATA:
lt_t001 TYPE TABLE OF t001, "所有公司代码
ls_t001 LIKE LINE OF lt_t001,
lt_rspar TYPE TABLE OF rsparams,
ls_rspar LIKE LINE OF lt_rspar,
lt_fcat TYPE lvc_t_fcat,
ls_fcat TYPE lvc_s_fcat,
lt_itab TYPE TABLE OF zsfi0319,
ls_all LIKE LINE OF gt_all.CLEAR:gt_datum,gt_itab ,gt_all.
SELECT *
INTO TABLE lt_t001
FROM t001
WHERE bukrs IN s_bukrs.* 权限检查已经chenk过,不会失败
CHECK sy-subrc = 0.
SORT lt_t001 BY bukrs ASCENDING.
DESCRIBE TABLE lt_t001 LINES gv_ok.ls_fcat-fieldname = 'MARK'. "标识列,区分公司属于哪种往来类型,输出时会删掉
ls_fcat-datatype = 'ZE_ZYXT1'.
ls_fcat-intlen = 100.
APPEND ls_fcat TO lt_fcat.ls_fcat-fieldname = 'NAME'. "字段ID列,项目名称存在重复的,靠此字段区分,输出时会删掉
ls_fcat-datatype = 'ZE_ZYXT1'.
ls_fcat-intlen = 100.
APPEND ls_fcat TO lt_fcat.ls_fcat-fieldname = 'XM'. "项目
ls_fcat-datatype = 'ZE_ZYXT1'.
ls_fcat-intlen = 100.
APPEND ls_fcat TO lt_fcat.ls_fcat-fieldname = 'SUM'. "合计
ls_fcat-datatype = 'ZE_ZYXT1'.
ls_fcat-intlen = 100.
APPEND ls_fcat TO lt_fcat.LOOP AT lt_t001 INTO ls_t001.
ls_fcat-fieldname = ls_t001-bukrs. "字段ID为公司代码
ls_fcat-datatype = 'ZE_ZYXT1'.
ls_fcat-intlen = 100.
APPEND ls_fcat TO lt_fcat.
ENDLOOP.* 创建动态内表
PERFORM frm_create_table USING lt_fcat.LOOP AT lt_t001 INTO ls_t001.
CLEAR:lt_itab[].
* 编辑传入参数
ls_rspar-selname = 'P_BUKRS'.
ls_rspar-kind = 'P'.
ls_rspar-low = ls_t001-bukrs.
APPEND ls_rspar TO lt_rspar.CLEAR:ls_rspar.
ls_rspar-selname = 'P_GJAHR'.
ls_rspar-kind = 'P'.
ls_rspar-low = p_gjahr.
APPEND ls_rspar TO lt_rspar.CLEAR:ls_rspar.
ls_rspar-selname = 'P_MONAT'.
ls_rspar-kind = 'P'.
ls_rspar-low = p_monat.
APPEND ls_rspar TO lt_rspar.CLEAR:ls_rspar.
ls_rspar-selname = 'P_EXPORT'.
ls_rspar-kind = 'P'.
ls_rspar-low = 'X'. "传输数据专用
APPEND ls_rspar TO lt_rspar.* 调用程序:权益占用统计报表
SUBMIT zfi1000_r01 WITH SELECTION-TABLE lt_rspar AND RETURN.* 来源程序:ZFI1000_R01
IMPORT p1 = lt_itab "所得税计算明细表
p2 = gv_bbzt "所得税费用表
FROM MEMORY ID 'ZFI1000_R01'.DELETE FROM MEMORY ID 'ZFIR029'.
* 保存所有往来公司
APPEND LINES OF lt_itab TO gt_itab.* 存储所有公司数据
ls_all-bukrs = ls_t001-bukrs.
ls_all-butxt = ls_t001-butxt.
ls_all-bbzt = gv_bbzt.
ls_all-itab = lt_itab[].
APPEND ls_all TO gt_all.ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form FRM_CREATE_TABLE
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
FORM frm_create_table USING it_fcat TYPE lvc_t_fcat.CLEAR:go_table.
* 期末数
cl_alv_table_create=>create_dynamic_table(
EXPORTING
it_fieldcatalog = it_fcat
IMPORTING
ep_table = go_table
EXCEPTIONS
generate_subpool_dir_full = 1
OTHERS = 2
).ENDFORM.
*&---------------------------------------------------------------------*
*& Form FRM_EDIT_COL
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
FORM frm_edit_col .DATA:
lv_mark TYPE char1,
ls_all LIKE LINE OF gt_all,
ls_itab LIKE LINE OF ls_all-itab,
ls_itab_g LIKE LINE OF gt_itab.FIELD-SYMBOLS:
<fs_table> TYPE STANDARD TABLE,
<fs_st> TYPE any,
<fs_value> TYPE any.* MARK,EDIT都不为空,且fieldname是空的表行,就是往来公司的数据行
DELETE gt_itab WHERE mark IS INITIAL OR edit IS INITIAL OR fieldname IS NOT INITIAL.* 排除重复的往来公司
SORT gt_itab BY mark ASCENDING pname ASCENDING.
DELETE ADJACENT DUPLICATES FROM gt_itab COMPARING mark pname.ASSIGN go_table->* TO <fs_table>.
* 初始化导出动态内表第一列
APPEND INITIAL LINE TO <fs_table> ASSIGNING <fs_st>. "第1行
ASSIGN COMPONENT 'XM' OF STRUCTURE <fs_st> TO <fs_value>.
IF sy-subrc = 0 AND <fs_value> IS ASSIGNED.
<fs_value> = '项目'.
ENDIF.ASSIGN COMPONENT 'SUM' OF STRUCTURE <fs_st> TO <fs_value>.
IF sy-subrc = 0 AND <fs_value> IS ASSIGNED.
<fs_value> = '合计'.
ENDIF.APPEND INITIAL LINE TO <fs_table> ASSIGNING <fs_st>. "第2行
ASSIGN COMPONENT 'XM' OF STRUCTURE <fs_st> TO <fs_value>.
IF sy-subrc = 0 AND <fs_value> IS ASSIGNED.
<fs_value> = '项目'.
ENDIF.ASSIGN COMPONENT 'SUM' OF STRUCTURE <fs_st> TO <fs_value>.
IF sy-subrc = 0 AND <fs_value> IS ASSIGNED.
<fs_value> = '合计'.
ENDIF.APPEND INITIAL LINE TO <fs_table> ASSIGNING <fs_st>. "第3行
ASSIGN COMPONENT 'XM' OF STRUCTURE <fs_st> TO <fs_value>.
IF sy-subrc = 0 AND <fs_value> IS ASSIGNED.
<fs_value> = '报表状态'.
ENDIF.* 随便取的一家公司数据,编辑模板第一列
READ TABLE gt_all INTO ls_all INDEX 1.* 删除这家公司的所有往来公司行,模板的往来公司行使用内表gt_itab编辑
DELETE ls_all-itab WHERE mark IS NOT INITIAL AND edit IS NOT INITIAL AND fieldname IS INITIAL.
LOOP AT ls_all-itab INTO ls_itab.CLEAR:lv_mark.
* 全角空格转半角
CALL FUNCTION 'SJIS_DBC_TO_SBC'
EXPORTING
special = 'X'
CHANGING
text = ls_itab-pname
EXCEPTIONS
overflow = 1
OTHERS = 2.CONDENSE ls_itab-pname NO-GAPS.
APPEND INITIAL LINE TO <fs_table> ASSIGNING <fs_st>.
ASSIGN COMPONENT 'XM' OF STRUCTURE <fs_st> TO <fs_value>.
IF sy-subrc = 0 AND <fs_value> IS ASSIGNED.
<fs_value> = ls_itab-pname.
ENDIF.ASSIGN COMPONENT 'MARK' OF STRUCTURE <fs_st> TO <fs_value>.
IF sy-subrc = 0 AND <fs_value> IS ASSIGNED.
<fs_value> = ls_itab-mark.
ENDIF.ASSIGN COMPONENT 'NAME' OF STRUCTURE <fs_st> TO <fs_value>.
IF sy-subrc = 0 AND <fs_value> IS ASSIGNED.
<fs_value> = ls_itab-fieldname.
ENDIF.CASE ls_itab-pname.
WHEN '1、往来'.
lv_mark = '1'.
WHEN '2、股东借款'.
lv_mark = '2'.
WHEN '3、加计占用'.
lv_mark = '3'.
WHEN '合作方往来'.
lv_mark = '4'.
WHEN '权益部分代总部投资'.
lv_mark = '5'.
WHEN OTHERS.
CONTINUE.
ENDCASE.LOOP AT gt_itab INTO ls_itab_g WHERE mark = lv_mark.
* 全角空格转半角
CALL FUNCTION 'SJIS_DBC_TO_SBC'
EXPORTING
special = 'X'
CHANGING
text = ls_itab_g-pname
EXCEPTIONS
overflow = 1
OTHERS = 2.CONDENSE ls_itab_g-pname NO-GAPS.
APPEND INITIAL LINE TO <fs_table> ASSIGNING <fs_st>.
ASSIGN COMPONENT 'XM' OF STRUCTURE <fs_st> TO <fs_value>.
IF sy-subrc = 0 AND <fs_value> IS ASSIGNED.
<fs_value> = ls_itab_g-pname.
ENDIF.ASSIGN COMPONENT 'MARK' OF STRUCTURE <fs_st> TO <fs_value>.
IF sy-subrc = 0 AND <fs_value> IS ASSIGNED.
<fs_value> = ls_itab_g-mark.
ENDIF.ENDLOOP.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form FRM_EDIT_DATA
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
FORM frm_edit_data .DATA:
lv_datum TYPE char20,
ls_all LIKE LINE OF gt_all,
ls_itab LIKE LINE OF ls_all-itab.FIELD-SYMBOLS:
<fs_table> TYPE STANDARD TABLE,
<fs_st> TYPE any,
<fs_value> TYPE any,
<fs_sum> TYPE any.ASSIGN go_table->* TO <fs_table>.
LOOP AT gt_all INTO ls_all.
READ TABLE <fs_table> ASSIGNING <fs_st> INDEX 1.
ASSIGN COMPONENT ls_all-bukrs OF STRUCTURE <fs_st> TO <fs_value>.
IF sy-subrc = 0 AND <fs_value> IS ASSIGNED.
<fs_value> = ls_all-bukrs.
ENDIF.READ TABLE <fs_table> ASSIGNING <fs_st> INDEX 2.
ASSIGN COMPONENT ls_all-bukrs OF STRUCTURE <fs_st> TO <fs_value>.
IF sy-subrc = 0 AND <fs_value> IS ASSIGNED.
<fs_value> = ls_all-butxt.
ENDIF.READ TABLE <fs_table> ASSIGNING <fs_st> INDEX 3.
ASSIGN COMPONENT ls_all-bukrs OF STRUCTURE <fs_st> TO <fs_value>.
IF sy-subrc = 0 AND <fs_value> IS ASSIGNED.
<fs_value> = ls_all-bbzt.
ENDIF.LOOP AT ls_all-itab INTO ls_itab.
* 全角空格转半角
CALL FUNCTION 'SJIS_DBC_TO_SBC'
EXPORTING
special = 'X'
CHANGING
text = ls_itab-pname
EXCEPTIONS
overflow = 1
OTHERS = 2.CONDENSE ls_itab-pname NO-GAPS.
READ TABLE <fs_table> ASSIGNING <fs_st> WITH KEY ('XM') = ls_itab-pname
('MARK') = ls_itab-mark
('NAME') = ls_itab-fieldname.IF sy-subrc = 0.
ASSIGN COMPONENT ls_all-bukrs OF STRUCTURE <fs_st> TO <fs_value>.
IF sy-subrc = 0 AND <fs_value> IS ASSIGNED.
<fs_value> = ls_itab-dmbtr.
CONDENSE <fs_value> NO-GAPS.
CALL FUNCTION 'CLOI_PUT_SIGN_IN_FRONT' "负号提前
CHANGING
value = <fs_value>.
ELSE. "动态表创建逻辑不改的话,这里不会失败
CONTINUE.
ENDIF.* 比例不用合计
IF ls_itab-pname = '一、权益比例(%)'.
<fs_value> = <fs_value> / 100.
CONTINUE.
ENDIF.ASSIGN COMPONENT 'SUM' OF STRUCTURE <fs_st> TO <fs_sum>.
IF sy-subrc = 0 AND <fs_sum> IS ASSIGNED.
<fs_sum> = <fs_sum> + ls_itab-dmbtr.
CONDENSE <fs_sum> NO-GAPS.
CALL FUNCTION 'CLOI_PUT_SIGN_IN_FRONT' "负号提前
CHANGING
value = <fs_sum>.
ENDIF.ENDIF.
ENDLOOP.
ENDLOOP.
* 编辑查询期间
CONCATENATE '查询期间:' p_gjahr '年' p_monat '月' INTO lv_datum.INSERT INITIAL LINE INTO <fs_table> INDEX 1 ASSIGNING <fs_st>.
ASSIGN COMPONENT 'XM' OF STRUCTURE <fs_st> TO <fs_value>.
IF sy-subrc = 0 AND <fs_value> IS ASSIGNED.
<fs_value> = lv_datum.
ENDIF.ENDFORM.
*&---------------------------------------------------------------------*
*& Form FRM_GET_OATH
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
FORM frm_get_oath .DATA:
lv_bukrs TYPE char100,
lv_fname TYPE string,
lv_path TYPE string,
lv_temp1 TYPE string,
lv_temp2 TYPE string,
lv_fpath TYPE string.CONCATENATE '权益占用统计汇总表' '_' p_gjahr p_monat '.XLSX'
INTO g_fname.CLEAR:gv_zpath.
lv_fname = g_fname.CALL METHOD cl_gui_frontend_services=>get_desktop_directory
CHANGING
desktop_directory = lv_path
EXCEPTIONS
cntl_error = 0
error_no_gui = 0
not_supported_by_gui = 0
OTHERS = 0.CALL METHOD cl_gui_frontend_services=>file_save_dialog
EXPORTING
default_file_name = lv_fname
file_filter = cl_gui_frontend_services=>filetype_excel
initial_directory = lv_path
prompt_on_overwrite = 'X'
CHANGING
filename = lv_temp1
path = lv_temp2
fullpath = lv_fpath
EXCEPTIONS
cntl_error = 0
error_no_gui = 0
not_supported_by_gui = 0
invalid_default_file_name = 0
OTHERS = 0.gv_zpath = lv_fpath.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form FRM_EXPORT_EXCEL
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
FORM frm_export_excel.DATA:
lo_iref_template TYPE REF TO cl_bds_document_set,
lo_oref_container TYPE REF TO cl_gui_custom_container,
lo_iref_document TYPE REF TO i_oi_document_proxy,
lo_iref_error TYPE REF TO i_oi_error,
lo_iref_spreadsheet TYPE REF TO i_oi_spreadsheet,
lo_iref_control TYPE REF TO i_oi_container_control.DATA:
lv_message TYPE char200,
lv_text TYPE char50,
lv_table TYPE char20,
lv_last_row TYPE i,
lv_last_col TYPE i,
lt_fields TYPE STANDARD TABLE OF rfc_fields,
lt_signature TYPE sbdst_signature,
ls_signature TYPE bapisignat,
lt_uri TYPE sbdst_uri,
ls_uri TYPE bapiuri,
lt_sheet TYPE soi_sheets_table,
ls_sheet TYPE soi_sheets,
lv_retcode TYPE soi_ret_string.* 批量导出的内表
FIELD-SYMBOLS:
<fs_table> TYPE STANDARD TABLE.* 初始化容器
CALL METHOD c_oi_container_control_creator=>get_container_control
IMPORTING
control = lo_iref_control
retcode = lv_retcode.IF lv_retcode <> c_oi_errors=>ret_ok.
MESSAGE '容器初始化失败' TYPE 'S' DISPLAY LIKE 'E'.
LEAVE LIST-PROCESSING.
ENDIF.CALL METHOD lo_iref_control->init_control
EXPORTING
r3_application_name = 'ZFI1029'
inplace_enabled = 'X'
inplace_scroll_documents = 'X'
parent = lo_oref_container
IMPORTING
retcode = lv_retcode.IF lv_retcode <> c_oi_errors=>ret_ok.
MESSAGE '容器初始化失败' TYPE 'S' DISPLAY LIKE 'E'.
LEAVE LIST-PROCESSING.
ENDIF.PERFORM frm_progress_indicator USING 10 '正在打开excel...'.
* 下载模板
CREATE OBJECT lo_iref_template.
ls_signature-prop_name = 'BDS_KEYWORD'.
ls_signature-prop_value = 'ZFI1029'.
APPEND ls_signature TO lt_signature.CLEAR:lt_uri[].
CALL METHOD lo_iref_template->get_with_url
EXPORTING
classname = 'SOFFICEINTEGRATION'
classtype = 'OT'
object_key = 'ZFI'
CHANGING
uris = lt_uri
signature = lt_signature
EXCEPTIONS
nothing_found = 1
error_kpro = 2
internal_error = 3
parameter_error = 4
not_authorized = 5
not_allowed = 6.READ TABLE lt_uri INTO ls_uri INDEX 1.
IF lv_retcode <> c_oi_errors=>ret_ok OR sy-subrc <> 0.
MESSAGE '模板下载失败' TYPE 'S' DISPLAY LIKE 'E'.
LEAVE LIST-PROCESSING.
ENDIF.* 打开文件
CALL METHOD lo_iref_control->get_document_proxy
EXPORTING
document_type = 'Excel.Sheet'
IMPORTING
document_proxy = lo_iref_document
retcode = lv_retcode.
IF lv_retcode <> c_oi_errors=>ret_ok.
MESSAGE '文件对象初始化失败' TYPE 'S' DISPLAY LIKE 'E'.
LEAVE LIST-PROCESSING.
ENDIF.CALL METHOD lo_iref_document->open_document
EXPORTING
document_url = ls_uri-uri
open_inplace = 'X'
IMPORTING
retcode = lv_retcode.
IF lv_retcode <> c_oi_errors=>ret_ok.
MESSAGE '文件打开失败' TYPE 'S' DISPLAY LIKE 'E'.
LEAVE LIST-PROCESSING.
ENDIF.* 获取sheet信息
FREE:lo_iref_error.
CALL METHOD lo_iref_document->get_spreadsheet_interface
IMPORTING
error = lo_iref_error
sheet_interface = lo_iref_spreadsheet.CALL METHOD lo_iref_spreadsheet->get_sheets
IMPORTING
sheets = lt_sheet
error = lo_iref_error.READ TABLE lt_sheet INTO ls_sheet INDEX 1.
IF lo_iref_error->error_code <> c_oi_errors=>ret_ok OR ls_sheet IS INITIAL.
MESSAGE 'sheet信息取得失败' TYPE 'S' DISPLAY LIKE 'E'.
LEAVE LIST-PROCESSING.
ENDIF.CONCATENATE '正在填充excel:' ls_sheet-sheet_name INTO lv_text.
ASSIGN go_table->* TO <fs_table>.
CHECK <fs_table> IS ASSIGNED.* 激活sheet
CALL METHOD lo_iref_spreadsheet->select_sheet
EXPORTING
name = ls_sheet-sheet_name
IMPORTING
error = lo_iref_error.CHECK lo_iref_error->error_code = c_oi_errors=>ret_ok.
PERFORM frm_progress_indicator USING 30 lv_text.
* 获取输出内表列项目
CLEAR:lt_fields[].
CALL FUNCTION 'DP_GET_FIELDS_FROM_TABLE'
TABLES
data = <fs_table>
fields = lt_fields.* 删除标识列:MARK
DELETE lt_fields INDEX 1.* 删除标识列:NAME
DELETE lt_fields INDEX 1.* 计算输出内容所需要和行数和列数
lv_last_row = lines( <fs_table> ).
lv_last_col = lines( lt_fields ).* 在sheet中选取范围
CALL METHOD lo_iref_spreadsheet->set_selection
EXPORTING
left = 2
top = 2
rows = lv_last_row
columns = lv_last_col.CALL METHOD lo_iref_spreadsheet->insert_range
EXPORTING
columns = lv_last_col
rows = lv_last_row
name = ls_sheet-sheet_name.* 输入内表数据至所选取范围
CALL METHOD lo_iref_spreadsheet->insert_one_table
EXPORTING
data_table = <fs_table>
fields_table = lt_fields
rangename = ls_sheet-sheet_name.
PERFORM frm_progress_indicator USING 90 '正在保存excel...'.* 存储excel至本地
CALL METHOD lo_iref_document->save_as
EXPORTING
file_name = gv_zpath
IMPORTING
retcode = lv_retcode.
IF lv_retcode <> c_oi_errors=>ret_ok.
MESSAGE '保存Excel文件出错' TYPE 'S' DISPLAY LIKE 'E'.
LEAVE LIST-PROCESSING.
ELSE.
lv_message = gv_ok && '家公司全部导出成功'.
MESSAGE lv_message TYPE 'S'.
ENDIF.* 释放所有对象
CALL METHOD lo_iref_document->release_document
IMPORTING
retcode = lv_retcode.FREE: lo_iref_spreadsheet,
lo_iref_document.CALL METHOD lo_iref_control->release_all_documents.
CALL METHOD lo_iref_control->destroy_control.
ENDFORM.
FORM frm_export_excel_xlsm .DATA:
lt_ranges TYPE soi_range_list,
lt_contents TYPE soi_generic_table,lo_iref_template TYPE REF TO cl_bds_document_set,
lo_oref_container TYPE REF TO cl_gui_custom_container,
lo_iref_document TYPE REF TO i_oi_document_proxy,
lo_iref_error TYPE REF TO i_oi_error,
lo_iref_spreadsheet TYPE REF TO i_oi_spreadsheet,
lo_iref_control TYPE REF TO i_oi_container_control.DATA:
lv_message TYPE char200,
lv_text TYPE char50,
lv_table TYPE char20,
lv_last_row TYPE i,
lv_last_col TYPE i,
l_col_from TYPE i, " 每一批次需要输出的起始列,以500列为一批次,例如: 1, 501,1001,...
l_col_to TYPE i, " 每一批次需要输出的结束列,以500列为一批次,例如: 500,1000,1500, ...
l_cols TYPE i, " 每一批次需要输出的列数
l_left TYPE i, " 输出区域的起始位置
l_range_name TYPE char100,
lt_fields TYPE STANDARD TABLE OF rfc_fields,
lt_fields_tmp LIKE lt_fields,
lt_signature TYPE sbdst_signature,
ls_signature TYPE bapisignat,
lt_uri TYPE sbdst_uri,
ls_uri TYPE bapiuri,
lt_sheet TYPE soi_sheets_table,
ls_sheet TYPE soi_sheets,
lv_retcode TYPE soi_ret_string.* 批量导出的内表
FIELD-SYMBOLS:
<fs_table> TYPE STANDARD TABLE.* 初始化容器
CALL METHOD c_oi_container_control_creator=>get_container_control
IMPORTING
control = lo_iref_control
retcode = lv_retcode.IF lv_retcode <> c_oi_errors=>ret_ok.
MESSAGE '容器初始化失败' TYPE 'S' DISPLAY LIKE 'E'.
LEAVE LIST-PROCESSING.
ENDIF.CALL METHOD lo_iref_control->init_control
EXPORTING
r3_application_name = 'ZFI1029'
inplace_enabled = 'X'
inplace_scroll_documents = 'X'
parent = lo_oref_container
IMPORTING
retcode = lv_retcode.IF lv_retcode <> c_oi_errors=>ret_ok.
MESSAGE '容器初始化失败' TYPE 'S' DISPLAY LIKE 'E'.
LEAVE LIST-PROCESSING.
ENDIF.PERFORM frm_progress_indicator USING 10 '正在打开excel...'.
* 下载模板
CREATE OBJECT lo_iref_template.
ls_signature-prop_name = 'BDS_KEYWORD'.
* ls_signature-prop_value = 'ZFI1029'.
ls_signature-prop_value = 'ZFI1029_XLSM'.
APPEND ls_signature TO lt_signature.CLEAR:lt_uri[].
CALL METHOD lo_iref_template->get_with_url
EXPORTING
classname = 'SOFFICEINTEGRATION'
classtype = 'OT'
object_key = 'ZFI'
CHANGING
uris = lt_uri
signature = lt_signature
EXCEPTIONS
nothing_found = 1
error_kpro = 2
internal_error = 3
parameter_error = 4
not_authorized = 5
not_allowed = 6.READ TABLE lt_uri INTO ls_uri INDEX 1.
IF lv_retcode <> c_oi_errors=>ret_ok OR sy-subrc <> 0.
MESSAGE '模板下载失败' TYPE 'S' DISPLAY LIKE 'E'.
LEAVE LIST-PROCESSING.
ENDIF.* 打开文件
CALL METHOD lo_iref_control->get_document_proxy
EXPORTING
document_type = 'Excel.Sheet'
IMPORTING
document_proxy = lo_iref_document
retcode = lv_retcode.
IF lv_retcode <> c_oi_errors=>ret_ok.
MESSAGE '文件对象初始化失败' TYPE 'S' DISPLAY LIKE 'E'.
LEAVE LIST-PROCESSING.
ENDIF.CALL METHOD lo_iref_document->open_document
EXPORTING
document_url = ls_uri-uri
open_inplace = 'X'
IMPORTING
retcode = lv_retcode.
IF lv_retcode <> c_oi_errors=>ret_ok.
MESSAGE '文件打开失败' TYPE 'S' DISPLAY LIKE 'E'.
LEAVE LIST-PROCESSING.
ENDIF.* 获取sheet信息
FREE:lo_iref_error.
CALL METHOD lo_iref_document->get_spreadsheet_interface
IMPORTING
error = lo_iref_error
sheet_interface = lo_iref_spreadsheet.CALL METHOD lo_iref_spreadsheet->get_sheets
IMPORTING
sheets = lt_sheet
error = lo_iref_error.READ TABLE lt_sheet INTO ls_sheet INDEX 1.
IF lo_iref_error->error_code <> c_oi_errors=>ret_ok OR ls_sheet IS INITIAL.
MESSAGE 'sheet信息取得失败' TYPE 'S' DISPLAY LIKE 'E'.
LEAVE LIST-PROCESSING.
ENDIF.CONCATENATE '正在填充excel:' ls_sheet-sheet_name INTO lv_text.
ASSIGN go_table->* TO <fs_table>.
CHECK <fs_table> IS ASSIGNED.* 激活sheet
CALL METHOD lo_iref_spreadsheet->select_sheet
EXPORTING
name = ls_sheet-sheet_name
IMPORTING
error = lo_iref_error.CHECK lo_iref_error->error_code = c_oi_errors=>ret_ok.
PERFORM frm_progress_indicator USING 30 lv_text.
lo_iref_spreadsheet->insert_range_dim( EXPORTING name = 'INTERFACE' top = 1 left = 1 rows = 1 columns = 1 no_flush = 'X'
IMPORTING error = lo_iref_error ) .lt_ranges = VALUE soi_range_list( ( name = 'INTERFACE' rows = 1 columns = 1 code = 0 ) ).
APPEND INITIAL LINE TO lt_contents ASSIGNING FIELD-SYMBOL(<fs_content>).
<fs_content>-row = 1 .<fs_content>-column = '1' . <fs_content>-value = g_fname.lo_iref_spreadsheet->set_ranges_data(
EXPORTING
ranges = lt_ranges
contents = lt_contents
* no_flush = 'X'
IMPORTING error = lo_iref_error
).CALL METHOD lo_iref_document->execute_macro
EXPORTING
macro_string = 'Module1.ExportData'
* no_flush = space
IMPORTING
error = lo_iref_error.PERFORM frm_progress_indicator USING 90 '正在保存excel...'.
* 存储excel至本地
CALL METHOD lo_iref_document->save_as
EXPORTING
file_name = gv_zpath
IMPORTING
retcode = lv_retcode.
IF lv_retcode <> c_oi_errors=>ret_ok.
MESSAGE '保存Excel文件出错' TYPE 'S' DISPLAY LIKE 'E'.
LEAVE LIST-PROCESSING.
ELSE.
lv_message = gv_ok && '家公司全部导出成功'.
MESSAGE lv_message TYPE 'S'.
ENDIF.* 释放所有对象
CALL METHOD lo_iref_document->release_document
IMPORTING
retcode = lv_retcode.FREE: lo_iref_spreadsheet,
lo_iref_document.CALL METHOD lo_iref_control->release_all_documents.
CALL METHOD lo_iref_control->destroy_control.
zcl_base_utility=>delete_file( g_fname ).ENDFORM.
*&---------------------------------------------------------------------*
*& Form FRM_PROGRESS_INDICATOR
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
FORM frm_progress_indicator USING iv_percentage TYPE i
iv_text TYPE c.CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR'
EXPORTING
percentage = iv_percentage
text = iv_text.ENDFORM.
*&---------------------------------------------------------------------*
*& Form FRM_DOWNLOAD_META_DATA
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
FORM frm_download_meta_data .
FIELD-SYMBOLS:
<fs_table> TYPE STANDARD TABLE.DATA :
ls_output_meta TYPE ty_output_meta,
lo_data_table TYPE REF TO cl_abap_tabledescr,
lo_struc TYPE REF TO cl_abap_structdescr.ASSIGN go_table->* TO <fs_table>.
lo_data_table ?= cl_abap_typedescr=>describe_by_data( <fs_table> ).
lo_struc ?= lo_data_table->get_table_line_type( ).ls_output_meta-sheet_name = '1'.
LOOP AT <fs_table> ASSIGNING FIELD-SYMBOL(<fs_output>).
ls_output_meta-row = sy-tabix + 1." 动态内表的第一行数据,对应输出到EXCEL第2行
LOOP AT lo_struc->components ASSIGNING FIELD-SYMBOL(<fs_comp>) FROM 3.
DATA(l_col) = sy-tabix - 1. " 动态内表的第一个字段,对应输出到EXCEL第2列
ASSIGN COMPONENT <fs_comp>-name OF STRUCTURE <fs_output> TO FIELD-SYMBOL(<fs_d>).
IF sy-subrc = 0.
IF <fs_d> = '' OR <fs_d> = '0.0000'.
CONTINUE.
ENDIF.
ls_output_meta-column = l_col .
ls_output_meta-value = <fs_d>.
ENDIF.
APPEND ls_output_meta TO gt_output_meta.
ENDLOOP.
ENDLOOP.
g_fname = zcl_base_utility=>download_file( CHANGING it_data = gt_output_meta ).ENDFORM.