未清项数据统计与明细查询报表



&---------------------------------------------------------------------
*& Report: ZGRFI_OPEN_ITEMS_REP
*&
&---------------------------------------------------------------------
*& Report ZFI_OPEN_ITEMS_REP
*& Description: 未清项数据统计与明细查询报表 (BSIK/BSID)
*&
&---------------------------------------------------------------------
*** Revision Request Date Name Description
*** -------- ----------- --------- ----------- -------------------------
*** 000 DV1K9A1*** 20251201 **** S 2000007***: Program Cr
&---------------------------------------------------------------------
REPORT zgrfi_open_items_rep.
----------------------------------------------------------------------
- TABLES & DATA DECLARATION
----------------------------------------------------------------------
TABLES: bsik, bsid, lfa1, kna1, skat.
" 定义数据统计 (汇总) ALV 结构
TYPES: BEGIN OF ty_summary,
bukrs TYPE bsik-bukrs,
lifnr TYPE bsik-lifnr,
lifnr_txt TYPE lfa1-name1,
kunnr TYPE bsid-kunnr,
kunnr_txt TYPE kna1-name1,
hkont TYPE bsik-hkont,
hkont_txt TYPE skat-txt50,
waers TYPE bsik-waers,
cnt_tot TYPE i, " 总数据条目
cnt_pre TYPE i, " N-3 年前数据条目
cnt_y2 TYPE i, " N-2 年数据条目
cnt_y1 TYPE i, " N-1 年数据条目
cnt_y0 TYPE i, " N 年数据条目
amt_tot TYPE bsik-wrbtr, " 总金额
amt_pre TYPE bsik-wrbtr, " N-3 年前数据金额
amt_y2 TYPE bsik-wrbtr, " N-2 年数据金额
amt_y1 TYPE bsik-wrbtr, " N-1 年数据金额
amt_y0 TYPE bsik-wrbtr, " N 年数据金额
END OF ty_summary.
" 定义数据明细 ALV 结构
TYPES: BEGIN OF ty_detail,
bukrs TYPE bsik-bukrs,
prctr TYPE bsik-prctr,
gjahr TYPE bsik-gjahr,
blart TYPE bsik-blart,
belnr TYPE bsik-belnr,
buzei TYPE bsik-buzei,
bldat TYPE bsik-bldat,
budat TYPE bsik-budat,
xblnr TYPE bsik-xblnr,
zuonr TYPE bsik-zuonr,
lifnr TYPE bsik-lifnr,
lifnr_txt TYPE lfa1-name1,
kunnr TYPE bsid-kunnr,
kunnr_txt TYPE kna1-name1,
hkont TYPE bsik-hkont,
hkont_txt TYPE skat-txt50,
waers TYPE bsik-waers,
shkzg TYPE bsik-shkzg,
wrbtr TYPE bsik-wrbtr,
dmbtr TYPE bsik-dmbtr,
sgtxt TYPE bsik-sgtxt,
zterm TYPE bsik-zterm,
zfbdt TYPE bsik-zfbdt,
zbd1t TYPE bsik-zbd1t,
END OF ty_detail.
DATA: gt_summary TYPE STANDARD TABLE OF ty_summary,
gs_summary TYPE ty_summary,
gt_detail TYPE STANDARD TABLE OF ty_detail,
gs_detail TYPE ty_detail.
" 临时表用于取数
DATA: gt_bsik TYPE STANDARD TABLE OF bsik,
gs_bsik TYPE bsik,
gt_bsid TYPE STANDARD TABLE OF bsid,
gs_bsid TYPE bsid.
" 描述缓存表
DATA: BEGIN OF gs_lfa1,
lifnr TYPE lfa1-lifnr,
name1 TYPE lfa1-name1,
END OF gs_lfa1,
gt_lfa1 LIKE HASHED TABLE OF gs_lfa1 WITH UNIQUE KEY lifnr.
DATA: BEGIN OF gs_kna1,
kunnr TYPE kna1-kunnr,
name1 TYPE kna1-name1,
END OF gs_kna1,
gt_kna1 LIKE HASHED TABLE OF gs_kna1 WITH UNIQUE KEY kunnr.
DATA: BEGIN OF gs_skat,
saknr TYPE skat-saknr,
txt50 TYPE skat-txt50,
END OF gs_skat,
gt_skat LIKE HASHED TABLE OF gs_skat WITH UNIQUE KEY saknr.
- ALV 相关变量
DATA: gt_fieldcat TYPE lvc_t_fcat,
gs_layout TYPE lvc_s_layo.
----------------------------------------------------------------------
- SELECTION SCREEN
----------------------------------------------------------------------
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE text-001.
PARAMETERS: p_gjahr TYPE gjahr DEFAULT sy-datum(4) OBLIGATORY.
SELECT-OPTIONS: s_bukrs FOR bsik-bukrs,
s_hkont FOR bsik-hkont,
s_prctr FOR bsik-prctr,
s_gjahr FOR bsik-gjahr,
s_budat FOR bsik-budat.
SELECTION-SCREEN END OF BLOCK b1.
SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE text-002.
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERS: p_sum RADIOBUTTON GROUP rg1 DEFAULT 'X' USER-COMMAND uc1.
SELECTION-SCREEN COMMENT 5(20) text-t01 FOR FIELD p_sum. " 数据统计
PARAMETERS: p_det RADIOBUTTON GROUP rg1.
SELECTION-SCREEN COMMENT 30(20) text-t02 FOR FIELD p_det. " 明细查询
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN END OF BLOCK b2.
SELECTION-SCREEN BEGIN OF BLOCK b3 WITH FRAME TITLE text-003.
PARAMETERS: p_vend RADIOBUTTON GROUP rg2 DEFAULT 'X'. " 勾选供应商 (BSIK)
PARAMETERS: p_cust RADIOBUTTON GROUP rg2. " 勾选客户 (BSID)
SELECT-OPTIONS: s_lifnr FOR bsik-lifnr.
SELECT-OPTIONS: s_kunnr FOR bsid-kunnr.
SELECTION-SCREEN END OF BLOCK b3.
SELECTION-SCREEN BEGIN OF BLOCK b4 WITH FRAME TITLE text-004.
SELECTION-SCREEN BEGIN OF LINE.
" 输出方式:ALV 展示 还是 CSV 导出
PARAMETERS: p_alv RADIOBUTTON GROUP rg3 DEFAULT 'X' .
SELECTION-SCREEN COMMENT 5(20) text-t03 FOR FIELD p_alv. " ALV展示
PARAMETERS: p_csv RADIOBUTTON GROUP rg3.
SELECTION-SCREEN COMMENT 30(20) text-t04 FOR FIELD p_csv. " CSV导出本地
SELECTION-SCREEN END OF LINE.
" 存放下载路径
PARAMETERS: p_path TYPE string LOWER CASE MODIF ID csv.
SELECTION-SCREEN END OF BLOCK b4.
----------------------------------------------------------------------
- AT SELECTION-SCREEN ON VALUE-REQUEST
----------------------------------------------------------------------
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_path.
PERFORM frm_get_fullpath CHANGING p_path .
----------------------------------------------------------------------
-
START-OF-SELECTION
----------------------------------------------------------------------
START-OF-SELECTION.
" 1. 获取基础数据
PERFORM frm_get_data.
PERFORM frm_get_text ." 2. 处理数据逻辑
IF p_sum = 'X'.
PERFORM frm_process_summary.
ELSEIF p_det = 'X'.
PERFORM frm_process_detail.
ENDIF." 3. 判断输出方式
IF p_alv = 'X'.
PERFORM frm_display_alv.
ELSEIF p_csv = 'X'.
IF p_path IS INITIAL.
MESSAGE '请先选择文件导出路径!' TYPE 'S' DISPLAY LIKE 'E'.
EXIT.
ENDIF.
PERFORM frm_export_csv USING p_path.
ENDIF.
&---------------------------------------------------------------------
*& Form FRM_GET_DATA
*& 取数逻辑
&---------------------------------------------------------------------
FORM frm_get_data.
DATA: lv_lines_bsik TYPE i,
lv_lines_bsid TYPE i,
lv_lines_tot TYPE i.CLEAR: gt_bsik, gt_bsid.
" 获取 BSIK 数据
IF p_vend = 'X'.
SELECT * INTO TABLE gt_bsik
FROM bsik
WHERE bukrs IN s_bukrs
AND hkont IN s_hkont
AND prctr IN s_prctr
AND gjahr IN s_gjahr
AND budat IN s_budat
AND lifnr IN s_lifnr.
ENDIF." 获取 BSID 数据
IF p_cust = 'X'.
SELECT * INTO TABLE gt_bsid
FROM bsid
WHERE bukrs IN s_bukrs
AND hkont IN s_hkont
AND prctr IN s_prctr
AND gjahr IN s_gjahr
AND budat IN s_budat
AND kunnr IN s_kunnr.
ENDIF." 超100万行提醒 (兼容老语法)
IF p_det = 'X'.
DESCRIBE TABLE gt_bsik LINES lv_lines_bsik.
DESCRIBE TABLE gt_bsid LINES lv_lines_bsid.
lv_lines_tot = lv_lines_bsik + lv_lines_bsid.IF lv_lines_tot > 1000000.
MESSAGE '导出提示:明细超过100W行,可能存在性能问题或需要多次导出!' TYPE 'I'.
ENDIF.
ENDIF.
ENDFORM. "frm_get_data
&---------------------------------------------------------------------
*& Form FRM_PROCESS_SUMMARY
*& 汇总数据处理逻辑 (兼容旧语法)
&---------------------------------------------------------------------
FORM frm_process_summary.
DATA: lv_y0 TYPE i,
lv_y1 TYPE i,
lv_y2 TYPE i,
lv_pre TYPE i,
lv_item_year TYPE i.
FIELD-SYMBOLS <fs_summary> TYPE ty_summary.
CLEAR gt_summary.
" 提前算好基准年份,避免在 IF 判断中做减法报错
lv_y0 = p_gjahr.
lv_y1 = p_gjahr - 1.
lv_y2 = p_gjahr - 2.
lv_pre = p_gjahr - 3.
" 处理 BSIK
LOOP AT gt_bsik INTO gs_bsik.
CLEAR gs_summary.
gs_summary-bukrs = gs_bsik-bukrs.
gs_summary-lifnr = gs_bsik-lifnr.
gs_summary-hkont = gs_bsik-hkont.
gs_summary-waers = gs_bsik-waers.
IF gs_bsik-shkzg = 'H'.
gs_bsik-wrbtr = gs_bsik-wrbtr * -1.
ENDIF.
gs_summary-cnt_tot = 1.
gs_summary-amt_tot = gs_bsik-wrbtr.
" 比较提前算好的年份变量
lv_item_year = gs_bsik-gjahr.
IF lv_item_year <= lv_pre. " N-3 年及以前
gs_summary-cnt_pre = 1.
gs_summary-amt_pre = gs_bsik-wrbtr.
ELSEIF lv_item_year = lv_y2. " N-2 年
gs_summary-cnt_y2 = 1.
gs_summary-amt_y2 = gs_bsik-wrbtr.
ELSEIF lv_item_year = lv_y1. " N-1 年
gs_summary-cnt_y1 = 1.
gs_summary-amt_y1 = gs_bsik-wrbtr.
ELSEIF lv_item_year = lv_y0. " N 年 (基准年)
gs_summary-cnt_y0 = 1.
gs_summary-amt_y0 = gs_bsik-wrbtr.
ENDIF.
COLLECT gs_summary INTO gt_summary.
ENDLOOP.
" 处理 BSID
LOOP AT gt_bsid INTO gs_bsid.
CLEAR gs_summary.
gs_summary-bukrs = gs_bsid-bukrs.
gs_summary-kunnr = gs_bsid-kunnr.
gs_summary-hkont = gs_bsid-hkont.
gs_summary-waers = gs_bsid-waers.
IF gs_bsid-shkzg = 'H'.
gs_bsid-wrbtr = gs_bsid-wrbtr * -1.
ENDIF.
gs_summary-cnt_tot = 1.
gs_summary-amt_tot = gs_bsid-wrbtr.
lv_item_year = gs_bsid-gjahr.
IF lv_item_year <= lv_pre. " N-3 年及以前
gs_summary-cnt_pre = 1.
gs_summary-amt_pre = gs_bsid-wrbtr.
ELSEIF lv_item_year = lv_y2. " N-2 年
gs_summary-cnt_y2 = 1.
gs_summary-amt_y2 = gs_bsid-wrbtr.
ELSEIF lv_item_year = lv_y1. " N-1 年
gs_summary-cnt_y1 = 1.
gs_summary-amt_y1 = gs_bsid-wrbtr.
ELSEIF lv_item_year = lv_y0. " N 年 (基准年)
gs_summary-cnt_y0 = 1.
gs_summary-amt_y0 = gs_bsid-wrbtr.
ENDIF.
COLLECT gs_summary INTO gt_summary.
ENDLOOP.
LOOP AT gt_summary ASSIGNING <fs_summary> .
READ TABLE gt_lfa1 INTO gs_lfa1 WITH TABLE KEY lifnr = <fs_summary>-lifnr .
IF sy-subrc = 0.
<fs_summary>-lifnr_txt = gs_lfa1-name1.
ENDIF.
READ TABLE gt_skat INTO gs_skat WITH TABLE KEY saknr = <fs_summary>-hkont .
IF sy-subrc = 0.
<fs_summary>-hkont_txt = gs_skat-txt50.
ENDIF.
READ TABLE gt_kna1 INTO gs_kna1 WITH TABLE KEY kunnr = <fs_summary>-kunnr .
IF sy-subrc = 0.
<fs_summary>-kunnr_txt = gs_kna1-name1.
ENDIF.
ENDLOOP .
ENDFORM. "frm_process_summary
&---------------------------------------------------------------------
*& Form FRM_PROCESS_DETAIL
&---------------------------------------------------------------------
FORM frm_process_detail.
CLEAR gt_detail.
LOOP AT gt_bsik INTO gs_bsik.
CLEAR gs_detail.
MOVE-CORRESPONDING gs_bsik TO gs_detail.
CLEAR: gs_detail-kunnr, gs_detail-kunnr_txt.
READ TABLE gt_lfa1 INTO gs_lfa1 WITH TABLE KEY lifnr = gs_bsik-lifnr.
IF sy-subrc = 0. gs_detail-lifnr_txt = gs_lfa1-name1. ENDIF.
READ TABLE gt_skat INTO gs_skat WITH TABLE KEY saknr = gs_bsik-hkont.
IF sy-subrc = 0. gs_detail-hkont_txt = gs_skat-txt50. ENDIF.
IF gs_detail-shkzg = 'H'.
gs_detail-wrbtr = gs_detail-wrbtr * -1.
gs_detail-dmbtr = gs_detail-dmbtr * -1.
ENDIF.
APPEND gs_detail TO gt_detail.
ENDLOOP.
LOOP AT gt_bsid INTO gs_bsid.
CLEAR gs_detail.
MOVE-CORRESPONDING gs_bsid TO gs_detail.
CLEAR: gs_detail-lifnr, gs_detail-lifnr_txt.
READ TABLE gt_kna1 INTO gs_kna1 WITH TABLE KEY kunnr = gs_bsid-kunnr.
IF sy-subrc = 0. gs_detail-kunnr_txt = gs_kna1-name1. ENDIF.
READ TABLE gt_skat INTO gs_skat WITH TABLE KEY saknr = gs_bsid-hkont.
IF sy-subrc = 0. gs_detail-hkont_txt = gs_skat-txt50. ENDIF.
IF gs_detail-shkzg = 'H'.
gs_detail-wrbtr = gs_detail-wrbtr * -1.
gs_detail-dmbtr = gs_detail-dmbtr * -1.
ENDIF.
APPEND gs_detail TO gt_detail.
ENDLOOP.
ENDFORM. "frm_process_detail
&---------------------------------------------------------------------
*& Form FRM_DISPLAY_ALV
&---------------------------------------------------------------------
FORM frm_display_alv.
CLEAR gt_fieldcat.
IF p_sum = 'X'.
DATA: lv_y0_n(4) TYPE n, lv_y1_n(4) TYPE n, lv_y2_n(4) TYPE n, lv_pre_n(4) TYPE n.
DATA: lv_txt TYPE string.
DATA: lv_year_str(2) TYPE c. " 用于提取两位数的年份,用在CONCATENATE中
lv_y0_n = p_gjahr.
lv_y1_n = p_gjahr - 1.
lv_y2_n = p_gjahr - 2.
lv_pre_n = p_gjahr - 3.
" ---------- 汇总视图表头 ----------
PERFORM add_fcat USING 'BUKRS' '公司代码'.
CASE p_vend.
WHEN 'X'.
PERFORM add_fcat USING 'LIFNR' '供应商'.
PERFORM add_fcat USING 'LIFNR_TXT' '供应商描述'.
WHEN OTHERS.
PERFORM add_fcat USING 'KUNNR' '客户'.
PERFORM add_fcat USING 'KUNNR_TXT' '客户描述'.
ENDCASE.
PERFORM add_fcat USING 'HKONT' '科目'.
PERFORM add_fcat USING 'HKONT_TXT' '科目描述'.
PERFORM add_fcat USING 'WAERS' '币种'.
PERFORM add_fcat USING 'CNT_TOT' '总数据条目'.
" 拼装列名 (采用 CONCATENATE 兼容老系统)
lv_year_str = lv_pre_n+2(2).
CONCATENATE lv_year_str '年前数据条目' INTO lv_txt.
PERFORM add_fcat USING 'CNT_PRE' lv_txt.
lv_year_str = lv_y2_n+2(2).
CONCATENATE lv_year_str '年数据条目' INTO lv_txt.
PERFORM add_fcat USING 'CNT_Y2' lv_txt.
lv_year_str = lv_y1_n+2(2).
CONCATENATE lv_year_str '年数据条目' INTO lv_txt.
PERFORM add_fcat USING 'CNT_Y1' lv_txt.
lv_year_str = lv_y0_n+2(2).
CONCATENATE lv_year_str '年数据条目' INTO lv_txt.
PERFORM add_fcat USING 'CNT_Y0' lv_txt.
PERFORM add_fcat USING 'AMT_TOT' '总金额'.
lv_year_str = lv_pre_n+2(2).
CONCATENATE lv_year_str '年前数据金额' INTO lv_txt.
PERFORM add_fcat USING 'AMT_PRE' lv_txt.
lv_year_str = lv_y2_n+2(2).
CONCATENATE lv_year_str '年数据金额' INTO lv_txt.
PERFORM add_fcat USING 'AMT_Y2' lv_txt.
lv_year_str = lv_y1_n+2(2).
CONCATENATE lv_year_str '年数据金额' INTO lv_txt.
PERFORM add_fcat USING 'AMT_Y1' lv_txt.
lv_year_str = lv_y0_n+2(2).
CONCATENATE lv_year_str '年数据金额' INTO lv_txt.
PERFORM add_fcat USING 'AMT_Y0' lv_txt.
gs_layout-zebra = 'X'.
gs_layout-cwidth_opt = 'X'.
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
EXPORTING
i_callback_program = sy-repid
is_layout_lvc = gs_layout
it_fieldcat_lvc = gt_fieldcat
i_callback_pf_status_set = 'FRM_SET_PF_STATUS'
i_callback_user_command = 'FRM_USER_COMMAND'
TABLES
t_outtab = gt_summary
EXCEPTIONS
program_error = 1
OTHERS = 2.
ELSEIF p_det = 'X'.
" ---------- 明细视图表头 ----------
PERFORM add_fcat USING 'BUKRS' '公司代码'.
PERFORM add_fcat USING 'PRCTR' '利润中心'.
PERFORM add_fcat USING 'GJAHR' '会计年度'.
PERFORM add_fcat USING 'BLART' '凭证类型'.
PERFORM add_fcat USING 'BELNR' '凭证号'.
PERFORM add_fcat USING 'BUZEI' '凭证行'.
PERFORM add_fcat USING 'BLDAT' '凭证日期'.
PERFORM add_fcat USING 'BUDAT' '过账日期'.
PERFORM add_fcat USING 'XBLNR' '参照'.
PERFORM add_fcat USING 'ZUONR' '分配'.
CASE p_vend.
WHEN 'X'.
PERFORM add_fcat USING 'LIFNR' '供应商'.
PERFORM add_fcat USING 'LIFNR_TXT' '供应商描述'.
WHEN OTHERS.
PERFORM add_fcat USING 'KUNNR' '客户'.
PERFORM add_fcat USING 'KUNNR_TXT' '客户描述'.
ENDCASE.
PERFORM add_fcat USING 'HKONT' '科目'.
PERFORM add_fcat USING 'HKONT_TXT' '科目描述'.
PERFORM add_fcat USING 'WAERS' '币种'.
PERFORM add_fcat USING 'SHKZG' '借/贷标识'.
PERFORM add_fcat USING 'WRBTR' '金额'.
PERFORM add_fcat USING 'DMBTR' '本位币金额'.
PERFORM add_fcat USING 'SGTXT' '文本'.
PERFORM add_fcat USING 'ZTERM' '付款条件'.
PERFORM add_fcat USING 'ZFBDT' '起算日期'.
PERFORM add_fcat USING 'ZBD1T' '天数1'.
gs_layout-zebra = 'X'.
gs_layout-cwidth_opt = 'X'.
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
EXPORTING
i_callback_program = sy-repid
is_layout_lvc = gs_layout
it_fieldcat_lvc = gt_fieldcat
i_callback_pf_status_set = 'FRM_SET_PF_STATUS'
i_callback_user_command = 'FRM_USER_COMMAND'
TABLES
t_outtab = gt_detail
EXCEPTIONS
program_error = 1
OTHERS = 2.
ENDIF.
ENDFORM. "frm_display_alv
&---------------------------------------------------------------------
*& ALV frm_set_pf_status
&---------------------------------------------------------------------
FORM frm_set_pf_status USING rt_extab TYPE slis_t_extab.
" 调用您在第一步SE41中创建的GUI Status
SET PF-STATUS 'STANDARD' EXCLUDING rt_extab.
ENDFORM. "frm_set_pf_status
&---------------------------------------------------------------------
*& ALV frm_user_command
&---------------------------------------------------------------------
FORM frm_user_command USING r_ucomm LIKE sy-ucomm rs_selfield TYPE slis_selfield.
CASE r_ucomm.
WHEN 'ZCSV'. " 您刚才在工具栏加的按钮代码
PERFORM frm_choose_path_and_export.
ENDCASE.
ENDFORM. "frm_user_command
&---------------------------------------------------------------------
*& 弹出路径选择框并导出 CSV
&---------------------------------------------------------------------
FORM frm_choose_path_and_export.
DATA lv_fullpath TYPE string .
PERFORM frm_get_fullpath CHANGING lv_fullpath .
IF sy-subrc = 0 AND lv_fullpath IS NOT INITIAL.
" 2. 执行真正的文本写入
PERFORM frm_export_csv USING lv_fullpath.
ELSE.
MESSAGE '已取消导出操作。' TYPE 'S'.
ENDIF.
ENDFORM. "frm_choose_path_and_export
&---------------------------------------------------------------------
*& Form ADD_FCAT
&---------------------------------------------------------------------
FORM add_fcat USING p_fieldname p_seltext.
DATA: ls_fcat TYPE lvc_s_fcat.
ls_fcat-fieldname = p_fieldname.
ls_fcat-scrtext_l = p_seltext.
ls_fcat-scrtext_m = p_seltext.
ls_fcat-scrtext_s = p_seltext.
ls_fcat-coltext = p_seltext.
IF p_fieldname CS 'AMT_' OR p_fieldname = 'WRBTR' OR p_fieldname = 'DMBTR'.
ls_fcat-do_sum = 'X'.
ENDIF.
APPEND ls_fcat TO gt_fieldcat.
ENDFORM. "add_fcat
&---------------------------------------------------------------------
*& Form FRM_GET_TEXT
&---------------------------------------------------------------------
- text
---------------------------------------------------------------------- - --> p1 text
- <-- p2 text
----------------------------------------------------------------------
FORM frm_get_text .
DATA: lt_lifnr TYPE TABLE OF lifnr,
lt_kunnr TYPE TABLE OF kunnr,
lt_saknr TYPE TABLE OF saknr.
LOOP AT gt_bsik INTO gs_bsik.
APPEND gs_bsik-lifnr TO lt_lifnr.
APPEND gs_bsik-hkont TO lt_saknr.
ENDLOOP.
LOOP AT gt_bsid INTO gs_bsid.
APPEND gs_bsid-kunnr TO lt_kunnr.
APPEND gs_bsid-hkont TO lt_saknr.
ENDLOOP.
SORT lt_lifnr. DELETE ADJACENT DUPLICATES FROM lt_lifnr.
SORT lt_kunnr. DELETE ADJACENT DUPLICATES FROM lt_kunnr.
SORT lt_saknr. DELETE ADJACENT DUPLICATES FROM lt_saknr.
IF lt_lifnr IS NOT INITIAL.
SELECT lifnr name1 INTO TABLE gt_lfa1 FROM lfa1 FOR ALL ENTRIES IN lt_lifnr WHERE lifnr = lt_lifnr-table_line.
ENDIF.
IF lt_kunnr IS NOT INITIAL.
SELECT kunnr name1 INTO TABLE gt_kna1 FROM kna1 FOR ALL ENTRIES IN lt_kunnr WHERE kunnr = lt_kunnr-table_line.
ENDIF.
IF lt_saknr IS NOT INITIAL.
SELECT saknr txt50 INTO TABLE gt_skat FROM skat FOR ALL ENTRIES IN lt_saknr WHERE saknr = lt_saknr-table_line AND spras = sy-langu.
ENDIF.
ENDFORM. " FRM_GET_TEXT
&---------------------------------------------------------------------
*& Form FRM_EXPORT_CSV
&---------------------------------------------------------------------
FORM frm_export_csv USING p_filepath TYPE string.
DATA: lt_out TYPE TABLE OF string,
lv_line TYPE string.
" 动态计算具体年份
DATA: lv_y0_n TYPE n LENGTH 4,
lv_y1_n TYPE n LENGTH 4,
lv_y2_n TYPE n LENGTH 4,
lv_pre_n TYPE n LENGTH 4.
" 准备动态表头变量
DATA: txt_c_pre TYPE string, txt_c_y2 TYPE string, txt_c_y1 TYPE string, txt_c_y0 TYPE string.
DATA: txt_a_pre TYPE string, txt_a_y2 TYPE string, txt_a_y1 TYPE string, txt_a_y0 TYPE string.
" ----------------- 导出汇总数据 -----------------
IF p_sum = 'X'.
lv_y0_n = p_gjahr. " 当年 (N年)
lv_y1_n = p_gjahr - 1. " N-1年
lv_y2_n = p_gjahr - 2. " N-2年
lv_pre_n = p_gjahr - 3. " N-3年前
" 拼接条目表头 (例如: '2021年前条目', '2022年条目'...)
CONCATENATE lv_pre_n '年前条目' INTO txt_c_pre.
CONCATENATE lv_y2_n '年条目' INTO txt_c_y2.
CONCATENATE lv_y1_n '年条目' INTO txt_c_y1.
CONCATENATE lv_y0_n '年条目' INTO txt_c_y0.
" 拼接金额表头 (例如: '2021年前金额', '2022年金额'...)
CONCATENATE lv_pre_n '年前金额' INTO txt_a_pre.
CONCATENATE lv_y2_n '年金额' INTO txt_a_y2.
CONCATENATE lv_y1_n '年金额' INTO txt_a_y1.
CONCATENATE lv_y0_n '年金额' INTO txt_a_y0.
" 生成最终的 CSV 表头行
IF p_cust = 'X'.
CONCATENATE '公司代码'
'客户' '客户描述'
'科目' '科目描述' '币种'
'总数据条目' txt_c_pre txt_c_y2 txt_c_y1 txt_c_y0
'总金额' txt_a_pre txt_a_y2 txt_a_y1 txt_a_y0
INTO lv_line SEPARATED BY ','.
ELSE.
CONCATENATE '公司代码'
'供应商' '供应商描述'
'科目' '科目描述' '币种'
'总数据条目' txt_c_pre txt_c_y2 txt_c_y1 txt_c_y0
'总金额' txt_a_pre txt_a_y2 txt_a_y1 txt_a_y0
INTO lv_line SEPARATED BY ','.
ENDIF.
APPEND lv_line TO lt_out.
" 2. 拼装行项目
LOOP AT gt_summary INTO gs_summary.
CLEAR lv_line.
*
" 处理各个金额
DATA: lv_amt_tot_c TYPE string, lv_amt_pre_c TYPE string.
DATA: lv_amt_y2_c TYPE string, lv_amt_y1_c TYPE string, lv_amt_y0_c TYPE string.
" 调用独立的子程序进行金额格式化
PERFORM frm_format_amt USING gs_summary-amt_tot gs_summary-waers CHANGING lv_amt_tot_c.
PERFORM frm_format_amt USING gs_summary-amt_pre gs_summary-waers CHANGING lv_amt_pre_c.
PERFORM frm_format_amt USING gs_summary-amt_y2 gs_summary-waers CHANGING lv_amt_y2_c.
PERFORM frm_format_amt USING gs_summary-amt_y1 gs_summary-waers CHANGING lv_amt_y1_c.
PERFORM frm_format_amt USING gs_summary-amt_y0 gs_summary-waers CHANGING lv_amt_y0_c.
" 拼接成一行 (注意数字字段要把前面的空格清掉)
DATA: lv_cnt_tot TYPE string, lv_cnt_pre TYPE string.
DATA: lv_cnt_y2 TYPE string, lv_cnt_y1 TYPE string, lv_cnt_y0 TYPE string.
lv_cnt_tot = gs_summary-cnt_tot. CONDENSE lv_cnt_tot.
lv_cnt_pre = gs_summary-cnt_pre. CONDENSE lv_cnt_pre.
lv_cnt_y2 = gs_summary-cnt_y2. CONDENSE lv_cnt_y2.
lv_cnt_y1 = gs_summary-cnt_y1. CONDENSE lv_cnt_y1.
lv_cnt_y0 = gs_summary-cnt_y0. CONDENSE lv_cnt_y0.
REPLACE ALL OCCURRENCES OF ',' IN gs_detail-lifnr_txt WITH ' '.
REPLACE ALL OCCURRENCES OF ',' IN gs_detail-kunnr_txt WITH ' '.
REPLACE ALL OCCURRENCES OF ',' IN gs_detail-hkont_txt WITH ' '.
IF p_cust = 'X'.
CONCATENATE gs_summary-bukrs
gs_summary-kunnr gs_summary-kunnr_txt
gs_summary-hkont gs_summary-hkont_txt
gs_summary-waers
lv_cnt_tot lv_cnt_pre lv_cnt_y2 lv_cnt_y1 lv_cnt_y0
lv_amt_tot_c lv_amt_pre_c lv_amt_y2_c lv_amt_y1_c lv_amt_y0_c
INTO lv_line SEPARATED BY ','.
ELSE.
CONCATENATE gs_summary-bukrs
gs_summary-lifnr gs_summary-lifnr_txt
gs_summary-hkont gs_summary-hkont_txt
gs_summary-waers
lv_cnt_tot lv_cnt_pre lv_cnt_y2 lv_cnt_y1 lv_cnt_y0
lv_amt_tot_c lv_amt_pre_c lv_amt_y2_c lv_amt_y1_c lv_amt_y0_c
INTO lv_line SEPARATED BY ','.
ENDIF.
APPEND lv_line TO lt_out.
ENDLOOP.
" ----------------- 导出明细数据 -----------------
ELSEIF p_det = 'X'.
" 1. 拼装表头
IF p_cust = 'X'.
CONCATENATE '公司代码' '利润中心' '会计年度' '凭证类型' '凭证号' '凭证行'
'凭证日期' '过账日期' '参照' '分配'
'客户' '客户描述' '科目' '科目描述' '币种' '借贷标识'
'金额' '本币金额' '文本' '付款条件' '起算日期' '天数'
INTO lv_line SEPARATED BY ',' .
ELSE.
CONCATENATE '公司代码' '利润中心' '会计年度' '凭证类型' '凭证号' '凭证行'
'凭证日期' '过账日期' '参照' '分配'
'供应商' '供应商描述' '科目' '科目描述' '币种' '借贷标识'
'金额' '本币金额' '文本' '付款条件' '起算日期' '天数'
INTO lv_line SEPARATED BY ','.
ENDIF.
APPEND lv_line TO lt_out.
" 2. 拼装行项目
LOOP AT gt_detail INTO gs_detail.
CLEAR lv_line.
" 金额处理(负号提前)
DATA: lv_wrbtr_c TYPE string, lv_dmbtr_c TYPE string.
DATA: lv_zbd1t_c TYPE string .
" 调用独立的子程序进行金额格式化
PERFORM frm_format_amt USING gs_detail-wrbtr gs_detail-waers CHANGING lv_wrbtr_c.
PERFORM frm_format_amt USING gs_detail-dmbtr gs_detail-waers CHANGING lv_dmbtr_c.
lv_zbd1t_c = gs_detail-zbd1t . CONDENSE lv_zbd1t_c NO-GAPS.
" 凭证行号去空格
DATA: lv_buzei TYPE string.
lv_buzei = gs_detail-buzei. CONDENSE lv_buzei.
" 文本中如果有逗号,会破坏CSV格式,将文本中的逗号替换为空格
REPLACE ALL OCCURRENCES OF ',' IN gs_detail-sgtxt WITH ' '.
REPLACE ALL OCCURRENCES OF ',' IN gs_detail-lifnr_txt WITH ' '.
REPLACE ALL OCCURRENCES OF ',' IN gs_detail-kunnr_txt WITH ' '.
REPLACE ALL OCCURRENCES OF ',' IN gs_detail-hkont_txt WITH ' '.
" 日期格式转换 (YYYMMDD -> YYYY-MM-DD,如果需要的话。为了性能此处直接原样输出)
IF p_cust = 'X'.
CONCATENATE gs_detail-bukrs gs_detail-prctr
gs_detail-gjahr gs_detail-blart
gs_detail-belnr lv_buzei
gs_detail-bldat gs_detail-budat
gs_detail-xblnr gs_detail-zuonr
gs_detail-kunnr gs_detail-kunnr_txt
gs_detail-hkont gs_detail-hkont_txt
gs_detail-waers gs_detail-shkzg
lv_wrbtr_c lv_dmbtr_c
gs_detail-sgtxt gs_detail-zterm
gs_detail-zfbdt lv_zbd1t_c
INTO lv_line SEPARATED BY ','.
ELSE.
CONCATENATE gs_detail-bukrs gs_detail-prctr
gs_detail-gjahr gs_detail-blart
gs_detail-belnr lv_buzei
gs_detail-bldat gs_detail-budat
gs_detail-xblnr gs_detail-zuonr
gs_detail-lifnr gs_detail-lifnr_txt
gs_detail-hkont gs_detail-hkont_txt
gs_detail-waers gs_detail-shkzg
lv_wrbtr_c lv_dmbtr_c
gs_detail-sgtxt gs_detail-zterm
gs_detail-zfbdt lv_zbd1t_c
INTO lv_line SEPARATED BY ','.
ENDIF.
APPEND lv_line TO lt_out.
ENDLOOP.
ENDIF.
" 3. 调用标准的下载函数
CALL FUNCTION 'GUI_DOWNLOAD'
EXPORTING
filename = p_filepath
filetype = 'DAT' " 对于字符串表,DAT或者ASC都可以
codepage = '8400' " 8400: GBK中文编码 / 4110: UTF-8 (根据你本地Excel环境选择,8400避免中文乱码)
TABLES
data_tab = lt_out
EXCEPTIONS
file_write_error = 1
no_batch = 2
gui_refuse_filetransfer = 3
invalid_type = 4
no_authority = 5
unknown_error = 6
OTHERS = 7.
IF sy-subrc = 0.
MESSAGE '文件导出成功!' TYPE 'S'.
ELSE.
MESSAGE '文件导出失败!请检查路径是否被占用。' TYPE 'S' DISPLAY LIKE 'E'.
ENDIF.
ENDFORM. "frm_export_csv
&---------------------------------------------------------------------
*& Form FRM_FORMAT_AMT
*& 描述:格式化金额,去千分位、改负号、防逗号破坏CSV
&---------------------------------------------------------------------
FORM frm_format_amt USING p_amt TYPE any
p_waers TYPE waers
CHANGING p_out TYPE string.
DATA: lv_char TYPE c LENGTH 20.
" 1. 【核心修复】:增加 NO-GROUPING,强制系统不要输出千分位分隔符!
" 比如 1,234,567.89 会被转成纯净的 1234567.89
WRITE p_amt TO lv_char CURRENCY p_waers NO-GROUPING.
" 2. 调用 SAP 标准函数:把末尾的负号移动到最前面
CALL FUNCTION 'CLOI_PUT_SIGN_IN_FRONT'
CHANGING
value = lv_char.
" 3. 去掉所有多余的空格
CONDENSE lv_char NO-GAPS.
" 4. 【终极防线】:如果部分用户的 SU01 设置为欧洲数字格式(小数点显示为逗号),
" 因为上面已经去掉了千分位,此时如果还有逗号,那绝对是欧洲格式的小数点!
" 必须强制把这个逗号替换为标准的点号,彻底杜绝 CSV 错位!
REPLACE ALL OCCURRENCES OF ',' IN lv_char WITH '.'.
p_out = lv_char.
ENDFORM. "frm_format_amt
&---------------------------------------------------------------------
*& Form FRM_GET_FULLPATH
&---------------------------------------------------------------------
-
text
---------------------------------------------------------------------- -
<--P_P_PATH text
----------------------------------------------------------------------
FORM frm_get_fullpath CHANGING cv_path.
DATA: lv_filename TYPE string,
lv_path TYPE string,
lv_fullpath TYPE string.lv_filename = '未清项报表数据-' && sy-datum && '_' && sy-uzeit && '.csv'.
CALL METHOD cl_gui_frontend_services=>file_save_dialog
EXPORTING
window_title = '选择保存路径'
default_extension = 'csv'
default_file_name = lv_filename
file_filter = 'CSV Files (.csv)|.csv|All Files (.)|.'
CHANGING
filename = lv_filename
path = lv_path
fullpath = lv_fullpath
EXCEPTIONS
OTHERS = 1.
IF sy-subrc = 0.
cv_path = lv_fullpath .
ENDIF.
ENDFORM. " FRM_GET_FULLPATH
浙公网安备 33010602011771号