系列文章目录
前言
承接上篇财务三大报表_2-进阶(资产负债表-数据表结构、取数逻辑),本篇继续详细介绍利润表的相关数据表结构、取数逻辑等(事实上,两个报表的逻辑、处理顺序都是一致的)
写的不周到的地方还请大家批评指正,互相学习
一、利润表
TCODE:ZFIR003
选择公司代码、会计年度、期间,即可看到该公司在某一会计年度某一期间的详细利润表,如下:
可以清楚看到行项目包括:
营业收入、营业成本、税金附加、销管研财费用、信用减值损失、资产减值损失、公允价值变动收益、投资收益、其他收益、资产处置收益、营业利润、营业外收入、营业外支出、利润总额、所得税费用、净利润
二、利润表的数据表结构
1、核心数据表
同资产负债表一样,
- faglflext:是SAP中的通用财务数据表,用于存储总账科目的财务数据,这里主要用于获取每个科目的发生额
关键字段包括:科目代码racct,借贷方向drcrk,期末数和年初数的余额hsl01、hslvt - zfit009:是自定义的表,是财务三大报表存储表
关键字段包括:公司代码bukrs,报表类型ztype(IS是利润表),列标识zcolumn(用于区分不同的列),行标识zrow,借方标识和贷方标识zjfbs、zdfbs,计算公式formula,正负反转reversal
2、内部数据结构
- 三个结构体类型:typ_fag,typ_dmbtr, typ_dmbtr1
- gt_fag和gs_fag:分别用于存储从faglflext表中检索的财务数据的表和内表记录。
gt_fit003和gs_fit003:用于存储从配置表zfit009中检索的配置数据,这些数据定义了利润表的格式和计算方式。
gt_dmbtr和gs_dmbtr/gt_dmbtr1和gs_dmbtr1:用于存储处理后的利润表数据。
vid1、list1、value1用于选择屏幕的下拉框数据处理。
gs_fieldcatalog和gt_fieldcatalog:用于定义ALV表格的列属性,如列名、数据类型、对齐方式等。
gt_alv_sort:用于定义ALV表格的排序规则。
gt_header和gs_header:用于定义ALV表格的标题或页眉信息。
三、利润表的取数逻辑
1、获取用户输入
通过选择屏幕获取用户输入的公司代码(p_bukrs)和会计年度(p_ryear)和期间( p_rpmax)
2、构建查询条件并获取数据
根据用户输入,构建查询faglflext表的条件。同时,根据配置表zfit009中的信息,确定需要获取哪些科目的数据
使用构建的查询条件,从faglflext表中获取对应期间、科目和功能范围的数据。
事实上就是资产负债表中写到的:获取财务数据和配置数据
3、数据处理
zfit009表字段如下:
TCODE:SE11里查
配置数据维护如下:
- 数据获取
在START-OF-SELECTION事件中, 程序首先执行权限校验(PERFORM CHECK_AUTHORITY),然后调用sub_get_data来获取数据。(这部分数据主要来源于faglflext表,通过拼接查询条件来获取指定公司代(rbukrs)、年份(ryear)、期间(rpmax)条件下的发生额数据。)
核心代码如下:
FORM check_authority .
AUTHORITY-CHECK OBJECT 'F_BKPF_BUK'
ID 'BUKRS' FIELD p_bukrs
ID 'ACTVT' FIELD '03'.
IF sy-subrc <> 0.
MESSAGE '没有查看该公司的权限' TYPE 'S' DISPLAY LIKE 'E'.
LEAVE LIST-PROCESSING .
ENDIF.
ENDFORM
FORM sub_get_data .
DATA: tp_cond TYPE string,
tp_field TYPE c LENGTH 5.
DATA tp_perio TYPE char3 .
DATA: tp_monat TYPE c LENGTH 2 VALUE '00'.
CLEAR: tp_perio .
IF p_rpmax = 12 .
tp_perio = p_rpmax + 4 .
ELSE .
tp_perio = p_rpmax .
ENDIF.
CLEAR: tp_cond,tp_monat . "整合查询条件
DO tp_perio TIMES.
tp_monat = tp_monat + 1 .
SHIFT tp_monat RIGHT DELETING TRAILING space .
OVERLAY tp_monat WITH '00' .
CLEAR: tp_field .
CONCATENATE 'HSL' tp_monat INTO tp_field .
CONCATENATE tp_cond tp_field INTO tp_cond SEPARATED BY space .
ENDDO.
CONCATENATE 'RBUKRS' 'RYEAR' 'RPMAX' 'RACCT' 'RTCUR' 'DRCRK' 'RFAREA' 'HSLVT'
tp_cond 'RCNTR' INTO tp_cond SEPARATED BY space .
SELECT (tp_cond) "查询发生额数据
INTO CORRESPONDING FIELDS OF TABLE gt_fag
FROM faglflext
WHERE rbukrs = p_bukrs
AND ( ryear = p_ryear OR ryear = tp_year )
AND rldnr = '0L'
AND prctr IN s_prctr.
**** DELETE gt_fag WHERE racct BETWEEN '0066010003' AND '0066019999' AND rcntr = '0000300031'.
SELECT *
INTO CORRESPONDING FIELDS OF TABLE gt_fit003
FROM zfit009
WHERE ztype = 'IS'
AND langu = sy-langu . "只获取IS类
SORT gt_fit003 BY ztype zcolumn zrow .
ENDFORM.
-
数据汇总和计算
获取数据后,程序进入sub_deal_data处理(根据gt_fit003中的信息对获取到的发生额数据进行汇总和计算)- 非公式项汇总:程序会根据配置表中的科目号、起始范围等,对发生额进行分类汇总;该自开发程序中使用了RNGES对象来定义科目号和起始范围的选择条件,通过LOOP AT GT_FAG循环遍历发生额数据,使用ADD或collect操作将数据累加到对应的报表项中。nmhsl表示当期,nyhsl表示本年累计
FORM sub_deal_data .
FIELD-SYMBOLS: <hsl> TYPE any .
RANGES: r_saknr FOR faglflext-racct. "科目号
RANGES: r_rfarea FOR zfit009-frfarea . "起始范围
RANGES: r_drcrk FOR faglflext-drcrk .
CLEAR: gt_dmbtr[],it_zfit13,it_zfit13[].
LOOP AT gt_fit003 ASSIGNING <gs_fit003> ."根据配置表数据 把取出的发生额加以汇总 得到报表项数据
CLEAR: gs_dmbtr .
MOVE-CORRESPONDING <gs_fit003> TO gs_dmbtr .
IF <gs_fit003>-formula = '' . "不是通过公式计算
IF ( ( <gs_fit003>-fsaknr <> '' OR <gs_fit003>-tsaknr <> '' ) AND
( <gs_fit003>-zjfbs <> '' OR <gs_fit003>-zdfbs <> '' ) ) .
*---组织整合条件
*-----------------------------------------------------------------------------
CLEAR:r_saknr[],r_drcrk[],r_rfarea[] . "资产负债表没有功能范围
*-----------------------------------------------------------------------*“科目范围
CLEAR: r_saknr .
IF <gs_fit003>-fsaknr <> '' AND <gs_fit003>-tsaknr = '' .
r_saknr-sign = 'I'.
r_saknr-option = 'EQ'.
r_saknr-low = <gs_fit003>-fsaknr .
APPEND r_saknr .
ELSEIF <gs_fit003>-fsaknr = '' AND <gs_fit003>-tsaknr <> '' .
r_saknr-sign = 'I' .
r_saknr-option = 'EQ'.
r_saknr-low = <gs_fit003>-tsaknr .
APPEND r_saknr .
ELSEIF <gs_fit003>-fsaknr <> '' AND <gs_fit003>-tsaknr <> '' .
r_saknr-sign = 'I' .
r_saknr-option = 'BT'.
r_saknr-low = <gs_fit003>-fsaknr .
r_saknr-high = <gs_fit003>-tsaknr.
APPEND r_saknr .
ENDIF.
*-----------------------------------------------------------------------*"功能范围
CLEAR: r_rfarea.
IF <gs_fit003>-frfarea <> '' AND <gs_fit003>-trfarea = '' .
r_rfarea(3) = 'IEQ'.
r_rfarea-low = <gs_fit003>-frfarea .
APPEND r_rfarea .
ELSEIF <gs_fit003>-frfarea = '' AND <gs_fit003>-trfarea <> '' .
r_rfarea(3) = 'IEQ' .
r_rfarea-low = <gs_fit003>-trfarea .
APPEND r_rfarea .
ELSEIF <gs_fit003>-frfarea <> '' AND <gs_fit003>-trfarea <> '' .
r_rfarea-sign = 'I' .
r_rfarea-option = 'BT'.
r_rfarea-low = <gs_fit003>-frfarea .
r_rfarea-high = <gs_fit003>-trfarea.
APPEND r_rfarea .
ENDIF.
*-----------------------------------------------------------------------*”借贷标识
CLEAR:r_drcrk .
IF <gs_fit003>-zjfbs = 'X' .
r_drcrk(3) = 'IEQ' .
r_drcrk-low = 'S' .
APPEND r_drcrk .
ENDIF .
IF <gs_fit003>-zdfbs = 'X'.
r_drcrk(3) = 'IEQ' .
r_drcrk-low = 'H' .
APPEND r_drcrk .
ENDIF.
*-----------------------------------------------------------------------*
IF p_ryear = '2017' AND p_rpmax LT '6'.
ELSE.
IF p_ryear = '2017' AND p_rpmax >= '6'.
ENDIF.
LOOP AT gt_fag INTO gs_fag WHERE racct IN r_saknr[] AND
rfarea IN r_rfarea[] AND drcrk IN r_drcrk[] .
IF gs_fag-ryear = p_ryear . "当年
DO 16 TIMES.
ASSIGN COMPONENT ( sy-index + 8 ) OF STRUCTURE gs_fag TO <hsl> .
CHECK sy-subrc EQ 0 .
IF p_rpmax = 12 .
IF sy-index >= 12 .
ADD <hsl> TO gs_dmbtr-nmhsl . "当期
ENDIF.
ELSE .
IF sy-index = p_rpmax .
ADD <hsl> TO gs_dmbtr-nmhsl ."当期
ENDIF.
ENDIF.
ADD <hsl> TO gs_dmbtr-nyhsl . "当年累计
ENDDO.
ELSE . "上年
DO 16 TIMES.
ASSIGN COMPONENT ( sy-index + 8 ) OF STRUCTURE gs_fag TO <hsl> .
CHECK sy-subrc EQ 0 .
IF p_rpmax = 12 .
IF sy-index >= 12 .
ADD <hsl> TO gs_dmbtr-lmhsl . "上年同期
ENDIF.
ELSE .
IF sy-index = p_rpmax .
ADD <hsl> TO gs_dmbtr-lmhsl ."上年同期
ENDIF.
ENDIF.
ADD <hsl> TO gs_dmbtr-lyhsl . "上年累计
ENDDO.
ENDIF.
ENDLOOP.
ENDIF.
- 公式项计算:程序调用caculate_results子例程进行计算,根据配置表中的公式对已有数据进行计算,并更新报表项的值。lmhsl表示上年同期,lyhsl表示上年累计
核心代码如下:(不完整)
formula_len = strlen( p_formula ) . "计算公式长度
CLEAR:tp_lmhsl,tp_lyhsl,tp_nmhsl,tp_nyhsl,tp_char,l_row .
CONDENSE p_formula NO-GAPS .
DO formula_len TIMES.
last = sy-index - 1 .
tp_char = p_formula+last(1) .
IF tp_char CO '0123456789' . "为数字
CONCATENATE l_row tp_char INTO l_row .
CLEAR: tp_char .
ENDIF .
IF tp_char CO '+-*/' OR sy-index = formula_len ."为计算符号
SHIFT l_row RIGHT DELETING TRAILING '' .
OVERLAY l_row WITH '000' .
CLEAR: wa_dmbtr .
READ TABLE gt_dmbtr INTO wa_dmbtr WITH KEY zrow = l_row .
* IF sy-subrc = 0 .
CLEAR:tp_value .
tp_value = wa_dmbtr-lmhsl .
CALL FUNCTION 'CLOI_PUT_SIGN_IN_FRONT' "负数负号前置
CHANGING
value = tp_value.
CONCATENATE tp_lmhsl '(' tp_value ')' tp_char INTO tp_lmhsl .
CLEAR:tp_value .
tp_value = wa_dmbtr-lyhsl .
CALL FUNCTION 'CLOI_PUT_SIGN_IN_FRONT' "负数负号前置
CHANGING
value = tp_value.
CONCATENATE tp_lyhsl '(' tp_value ')' tp_char INTO tp_lyhsl .
CLEAR:tp_value .
tp_value = wa_dmbtr-nmhsl .
CALL FUNCTION 'CLOI_PUT_SIGN_IN_FRONT' "负数负号前置
CHANGING
value = tp_value.
CONCATENATE tp_nmhsl '(' tp_value ')' tp_char INTO tp_nmhsl .
CLEAR:tp_value .
tp_value = wa_dmbtr-nyhsl .
CALL FUNCTION 'CLOI_PUT_SIGN_IN_FRONT' "负数负号前置
CHANGING
value = tp_value.
CONCATENATE tp_nyhsl '(' tp_value ')' tp_char INTO tp_nyhsl .
* ENDIF.
CLEAR: l_row .
ENDIF.
ENDDO.
IF tp_lmhsl <> '' .
CLEAR: l_value .
CALL FUNCTION 'CHECK_FORMULA'
EXPORTING
formula = tp_lmhsl.
IF sy-subrc = 0.
CALL FUNCTION 'EVAL_FORMULA'
EXPORTING
formula = tp_lmhsl
IMPORTING
value = l_value.
p_lmhsl = l_value .
ENDIF.
ENDIF.
IF tp_lyhsl <> '' .
CLEAR: l_value .
CALL FUNCTION 'CHECK_FORMULA'
EXPORTING
formula = tp_lyhsl.
IF sy-subrc = 0.
CALL FUNCTION 'EVAL_FORMULA'
EXPORTING
formula = tp_lyhsl
IMPORTING
value = l_value.
p_lyhsl = l_value .
ENDIF.
ENDIF.
IF tp_nmhsl <> '' .
CLEAR: l_value .
CALL FUNCTION 'CHECK_FORMULA'
EXPORTING
formula = tp_nmhsl.
IF sy-subrc = 0.
CALL FUNCTION 'EVAL_FORMULA'
EXPORTING
formula = tp_nmhsl
IMPORTING
value = l_value.
p_nmhsl = l_value .
ENDIF.
ENDIF.
IF tp_nyhsl <> '' .
CLEAR: l_value .
CALL FUNCTION 'CHECK_FORMULA'
EXPORTING
formula = tp_nyhsl.
IF sy-subrc = 0.
CALL FUNCTION 'EVAL_FORMULA'
EXPORTING
formula = tp_nyhsl
IMPORTING
value = l_value.
p_nyhsl = l_value .
ENDIF.
ENDIF.
- 数据计算和调整
在sub_deal_data的后续处理中,程序还会对报表项数据进行一些计算和调整----再次计算公式项:为了避免一些公式取后面值失败的情况,程序会再次遍历表gt_fit003,对公式计算项进行二次计算,这次计算会覆盖之前的结果
4、数据存储和报表生成
汇总和计算后,报表项数据存储在表gt_dmbtr中,后续会根据该表生成ALV报表,或者导出到excel中