SAP EXCEL DOI 详解

什么是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.

相关推荐
uhakadotcom12 分钟前
MQTT入门:轻量级物联网通信协议
后端·面试·github
我不会编程55536 分钟前
Python Cookbook-5.1 对字典排序
开发语言·数据结构·python
李少兄37 分钟前
Unirest:优雅的Java HTTP客户端库
java·开发语言·http
ONE_Gua1 小时前
chromium魔改——navigator.webdriver 检测
前端·后端·爬虫
可乐加.糖1 小时前
一篇关于Netty相关的梳理总结
java·后端·网络协议·netty·信息与通信
Kagol1 小时前
macOS 和 Windows 操作系统下如何安装和启动 MySQL / Redis 数据库
redis·后端·mysql
无名之逆1 小时前
Rust 开发提效神器:lombok-macros 宏库
服务器·开发语言·前端·数据库·后端·python·rust
9号达人1 小时前
java9新特性详解与实践
java·后端·面试
似水এ᭄往昔1 小时前
【C语言】文件操作
c语言·开发语言
Aurora_NeAr1 小时前
深入理解Java虚拟机-类加载机制
后端