三个月精通ABAP(6)

时间:2021-05-02 23:16:46

3. 再谈建立Validation操作.(7-9)

[1]删除Prerequisite和Check代码.

[2]合并字符字段

[3]比如对line Validation,BKFF,BSEG,SYST(如想By Tcode选SYST-TCODE做条件)三对象可使用.

[4]选择rule做Prerequisite和Check(参考图7-5).

[5]可使用User Exit做Prerequisite和Check.(参考 8 例凭证的退代).

[6]一些常用逻辑表达式.

[7]通常使用的是Constant(常量).

1.读者也许有这样的疑问,Validation究竟是怎么工作的? 很好,使用SE37在Function

FI_VALIDATION_HEADERFI_VALIDATION_ITEM合适位置设置断点,就可知道更详细的程序逻辑.

另外,相关Table T001D|和相关程序GBTDMFI0|RGUGBR00,有兴趣的读者不妨研究一下.

2.另一个留给读者的疑问是,一个Validation可有多个Steps,不妨假设一Line Validation有俩Steps-STEP1和Step2,它们的Prerequisite都是:BKPF-BUKRS = 5100,但是Check却不同甚至是矛盾的,Step1 check是BSEG-DMBTR <=1000.而Step2-check却是BSEG-DMBTR > 1000,结果会如何?

3.财务凭证的退代(Substitution)

和Validation一样,凭证的退代在多个模块中能找到,IMG Path(IMG Path如图7-1标号2).

比较实用的Substitution IMG T-code有: OBBH:AP/AR/GL Doc.| OACS:AM Create Assets|OA02:Mass change Assets|GCVY:Global Substitution(In SPL,Company Level)|GCVX:Local Substitution(In SPL,Company code Level).

和Validation不同的是,Validation只做检测,一般不做相应数据的修改,Substitution弥补了这反面的缺陷,甚至允许和user_exit相结合.

假设用户希望在产生APAR凭证能将vendor,customer 或其它信息比如写入Assignment(BSEG-ZUONR)字段,或者希望某些P&L科目在记入某些特定成本中心时将些分析信息写入TEXT(BSEG-SGTXT)字段,可使用退代.

下面举一个最简单实例假设在公司代码5100中,如使用现金类科目10010120记帐,在Text(BSEG-SGTXT)写入信息,同时在期初,可能会将一些凭证post到上期间,使用退代假设是post到上期间的凭证Posting Date换成上期间最后一天.

此简单实例是为了说明问题,其中有些步骤和第7例Validation相同,就不再一一讲解,希望读者在实际业务中能举一反三,发挥退代作用.

1. 自定义的退代程序.

相关Tcode:GCX2. (图9-2)

[1]App. Area 选择GBLS

[2]输入自定义程序名ZSTSUB(Copy并取代SAP默认的标准程序RGGBS000)

*** 自定义的程序名称最好不超过8位,在OBBH似乎只能显示程序名的前8位.

相关表格函数和程序.

相关表格GB01|T001Q|T80D|GB03|GB03T|GB31|GB31T||GB907|GB90|GB92|GB922|GB901

|OXT_GENOBJDTL|,相关函数FI_SUBSTITUTION_ACTIVE|FI_SUBSTITUTION_DOC

|FI_SUBSTITUTION_HEADER|FI_SUBSTITUTION_ITEM.相关程序ZSTSUB(自定义)| GBTDMFI0| GBTDMFIJ|RGUGBR00

*** 使用 GCX2 退换标准的 RGGBS000 这样就无需申请 Access Key, 另外一个 GCX1 是跨 Client 端的 , 一般用于特殊总帐 SPL 中给 Field movement 定义用户出口 .

2. 建立退代步骤

同Validation一样,也需为其建立Step,一个Step包括先决条件和退代(如图9-3).

[1]凭证头退代,在凭证抬头回车回保存凭证时满足条件时生效.

[2]凭证行项目退代.

[3]增加删除一个退代

***在本例中,使用only exit U100(对应ZSTSUB子程序U100)修改line item的Text.

[4]使用用户出口做退代. (关于怎么选Form规则请看本例思考).

[5]字段级退代.

假设ZSTSUB Form U100的source code如下,那么在满足先决条件时,行项目的Text都写成了Record Payment Text.

FORM u100. "#EC CALLED

***U100 如只是用于 line item退代. 所以改变XBLNR不会成功 .

***U100如果同事用于header和line item,则俩句都会成功执行.

BKPF-XBLNR = 'Reference For STONE Test'.

BSEG-SGTXT = 'Record Payment Text ' .

ENDFORM.

读者可思考下面几个问题:

思考:

1如果先决条件没有输入任何值,是否退代会无条件执行?

2在ZSTSUB(本人自定义),用户可参考SAP标准程序RGGBS000, RGGBS000的Form

会以什么规则在不同级别的(header,Line,Complete doc)退代中做Exit ,用户能否自定义自己的field exit,header exit,line exit 和complete exit?

请看此FORM get_exit_titles TABLES etab,有类似语句.

这些由参数c_exit_param_none, c_exit_param_fieldc_exit_param_class 决定

exits-name = 'U100'.

exits-param = c_exit_param_none. " 能用在Field exit,only exit等任何地方

exits-title = text-100.

APPEND exits.

exits-name = 'U101'.

exits-param = c_exit_param_field." 此Form只用于字段exit

exits-title = text-101.

APPEND exits.

exits-name = 'U801'.

exits-param = c_exit_param_class .

"Form U801 只能在Callup point 3 complete doc才可使用.

exits-title = text-101. "Cost center from CSKS

APPEND exits.

3 BKPF,BSEG什么样的值才可应用在退代程序中?

4为什么有些字段即使在退代中更改了但是不生效

下面再以举一实例,彻底剖析退代的运行规则同时解释上面3,4提出的问题.

首先在FI_SUBSTITUTION_HEADER|FI_SUBSTITUTION_ITEM|ZSTSUB(自定义)| GBTDMFI0| GBTDMFIJ设置断点你能进行跟踪. 从技术上讲,在回车或保存触发退代前在屏幕上输入的一些值就已经保存在一些内表中,然后才执行退代去根据用户设置的条件去退换一些值而已.

实例:通常企业在期初未关帐前可能需要在上期间记帐.如用户需要假设posting date是上期间某个日期,自动将此日期退换成上期间最后一天.使用抬头退代.

1确定当新增退代时BKPF-BUDAT是否可见

如在此看不到,即使你写了代码也是无效的.如图9-6.

[1]使用only exit U100,也可使用field exit . [2]BKPF-BUDAT可见.

***使用下面参考代码将BCLTAB和BCLFIELD稍微更改就可将BKPF,BSEG任何字段用于退代编码.

1所有退代字段关系在GB01表中,可使用下面代码使用BUDAT可用于退代.

在本人的机器上GB01建立了维护视图,因此实际上可直接使用SE16修改GB01,如果企业可能大量使用退代和确定,可以考虑用SE11为表GB01建立维护视图,否则就使用下面程序.

Report ZMODGB01.

DATA ZGB01 LIKE GB01 .

SELECT SINGLE * INTO ZGB01 FROM GB01

WHERE BOOLCLASS = '008'

AND CLASSTYPE = 'S'

AND BCLTAB = 'BKPF'

AND BCLFIELD = 'BUDAT' .

* AND BCLTAB = 'BSEG'

* AND BCLFIELD = 'PRCTR' .

ZGB01-BEXCLUDE = ''.

MODIFY GB01 FROM ZGB01 .

2 在凭证的退代和确定中,有几个比较有用的Tcode.

GGB0: All Validations.

GGB1: All Substitutions

GGB2: All Rule Class

GGB3:没有这样的Tcode,嘿嘿,你自己造一个吧.

GGB4: 激活

2 检查退代代码自动生成.

退代代码是自动生产的,这样的自动生成程序的实际应用很多,比如在CO-PA中,相关表,结构和程序很多是自动生成的,关于程序自动生产请参考拙作ABAP 百谈.

记得在OBBH画面当新建一退代时,有如图9-7的画面.

[1]退代名 [2]退代class,这个将对应到自动生成程序GBTDMFIJ.

在GBTDMFIG中读者能看到四个子程序FORM EXP_TAB_008_BKPF(class 8,callpnt1),FORM EXP_TAB_009_BSEG(class 9,callpnt2), FORM EXP_TAB_015_BKPF和FORM EXP_TAB_015_BSEG(Class 15,Callpnt 3).

现在以FORM EXP_TAB_008_BKPF为例.如果读者不能在此子程序的一个结构TEMP_STRUCT发现想退代的字段(原因就不细解),很明显,必须重新生成退代程序.

*** 如果您的退代不工作可以这样找原因,在GBTDMFIG程序中的上面提到的四个Form的TEMP_STRUCT结构没有看是否有相应的字段.比如在TEMP_STRUCT结构中没有BKPF-BUDAT,当然posting date的退代代码就会不起作用,此时执行下面步骤3运行RGUGBR00吧.

原因很简单,在退代程序中定义的BKPF,BSEG相当于内表,退代代码按用户的逻辑修改了BKPF后如TEMP_STRUCT(实际对应的是可用做退代的全不字段)中没有,BKPF就被Reset回.

3 重新生成程序.

SE38运行RGUGBR00, 将能选的全选上的选项再运行吧(图略).

4. 编写代码

下面是参考程序,判断Posting Date如在上期间(非上月,以月为期间只是期间的一特例,国外企业似乎都不这样采用,关于期间请参考第4刀SAP期间概念)自动将其退换成上期最后一天(对其他期间无效,读者可能需要修改才可满足贵企业需求).

FORM u100.

*同一Exit(Form)可用于head(Line item)或Filed 退代,互不影响.

*具体原理可跟踪GBTDMFIG(有GBTDMFI0动态调用)

*此程序由Yueming Li编写,如有必要读者可能需要改动.

Form 100.

BSEG-SGTXT = 'TEST TeXT'.

*BKPF-BUDAT

TABLES: T009B.

DATA: BEGIN OF T_T009B OCCURS 10,

BUMON LIKE T009B-BUMON,

BUTAG LIKE T009B-BUTAG,

END OF T_T009B.

DATA: L_DATE(8) TYPE C,

L_YEAR(4) TYPE C,

L_MONTH(2) TYPE C,

L_DAY(2) TYPE C,

L_PERMONTH(2) TYPE C,

L_CURYEAR(4) TYPE C,

L_CURMONTH(2) TYPE C,

L_CURDAY(2) TYPE C.

L_DATE = SY-DATUM.

L_CURYEAR = L_DATE(4).

L_CURMONTH = L_DATE+4(2).

L_CURDAY = L_DATE+6(2).

L_CURMONTH = L_CURMONTH - 0.

L_PERMONTH = L_CURMONTH - 1.

L_DATE = BKPF-BUDAT.

L_YEAR = L_DATE(4).

L_MONTH = L_DATE+4(2).

L_DAY = L_DATE+6(2).

L_MONTH = L_MONTH - 0.

IF L_CURYEAR NE L_YEAR.

BKPF-BUDAT = L_DATE.

EXIT.

ENDIF.

IF L_MONTH NE L_CURMONTH

AND L_MONTH NE L_PERMONTH.

BKPF-BUDAT = L_DATE.

EXIT.

ENDIF.

SELECT BUMON BUTAG

INTO T_T009B

FROM T009B

WHERE PERIV EQ 'Z1'

AND BDATJ EQ L_YEAR " year

AND ( BUMON EQ L_CURMONTH "Month

OR BUMON EQ L_PERMONTH ).

IF T_T009B-BUMON EQ L_PERMONTH.

APPEND T_T009B.

ENDIF.

IF T_T009B-BUMON EQ L_CURMONTH

AND T_T009B-BUTAG LE L_CURDAY.

APPEND T_T009B.

ENDIF.

ENDSELECT.

SORT T_T009B.

LOOP AT T_T009B.

IF T_T009B-BUMON EQ L_MONTH.

IF T_T009B-BUTAG GE L_DAY.

CONCATENATE L_YEAR T_T009B-BUMON T_T009B-BUTAG INTO L_DATE.

EXIT.

ENDIF.

ENDIF.

IF T_T009B-BUMON GT L_MONTH.

IF T_T009B-BUTAG GE L_DAY.

EXIT.

ENDIF.

ENDIF.

ENDLOOP.

BKPF-BUDAT = L_DATE.

ENDFORM. "U100

使用函数的.

FORM u100. "#EC CALLED

*同一个Form可用做header和line 退代而互不影响.

BSEG-SGTXT = 'Line Item Text'. "For Line Sub.

DATA:Z_PSTDATE TYPE SY-DATUM,

Z_CURPER LIKE T009B-POPER,

Z_CURYEAR LIKE T009B-BDATJ,

Z_PSTPER LIKE T009B-POPER,

Z_PSTYEAR LIKE T009B-BDATJ,

Z_PERLSTDAY LIKE SY-DATUM.

*实际永远不会发生记帐到上年和上上期间的.

*check posting date's period and fiscal year

CALL FUNCTION 'DETERMINE_PERIOD'

EXPORTING

DATE = BKPF-BUDAT

VERSION = 'Z1' "Fiscal Year Var.

IMPORTING

PERIOD = Z_PSTPER

YEAR = Z_PSTYEAR .

*check sysdate's period and fiscal year

CALL FUNCTION 'DETERMINE_PERIOD'

EXPORTING

DATE = SY-DATUM

VERSION = 'Z1' "Fiscal Year Var.

IMPORTING

PERIOD = Z_CURPER

YEAR = Z_CURYEAR.

*能否在输入的posting date记帐让系统去判断.

CHECK Z_CURYEAR <> Z_PSTYEAR OR Z_PSTPER <> Z_CURPER.

*如posting date不在本期间得到其期间最后一##

Z_PSTPER = Z_PSTPER + 1 .

CALL FUNCTION 'FIRST_DAY_IN_PERIOD_GET'

EXPORTING

I_GJAHR = Z_PSTYEAR

I_PERIV = 'Z1'

I_POPER = Z_PSTPER

IMPORTING

E_DATE = Z_PERLSTDAY .

BKPF-BUDAT = Z_PERLSTDAY - 1 .

BKPF-MONAT = Z_PSTPER . "如果Edit options允许看到期间的话也要改.