与基于源码的出口不同的是,该类出口将依据函数结构指定具体的输入/输出参数。SAP已经为每一个该类出口对象分配了对应的函数,程序执行中,会调用该函数检查其对应的代码。如果需要实现某个程序的增强,首先必须找到其对应的出口。
1、出口所对应函数的查找
这里介绍一种逆向的查找法,首先通过源码找到函数,然后通过函数来找到出口对象。
函数名称有三个部分组成,命名规则为:EXIT_<程序名>_<3位数字>。
首四个字母一定是固定的EXIT,表示用户出口;
第二个部分为程序名;
第三个部分为3位数字的序列号。
基于函数的出口在程序中通过引用代码“CALL CUSTOMER-FUNCTION <3位数字>”来调用,以VA01的主程序SAPMV45A为例,在程序中查找包含“CALL CUSTOMER-FUNCTION”的字符串,可以找到例如代码“ call customer-function '003'”,具体如下图所示:
根据出口的命名规则,可以判定这个出口所对应的函数名称为“EXIT_SAPMV45A_003”,然后通过SE37开启这个函数,可以看到这个函数中指定了一个预留的程序,名称为“ZXVVAU05”,具体如下图所示:
程序名“ZXVVAU05”为SAP的预留程序名,以Z开头的程序可以在SAP中直接创建和维护。在代码中双击该程序名,若程序没有被创建,系统将提示在系统中按该名称进行创建新的程序。
2、通过函数来查找出口对象
上面我们介绍了如何通过程序源码来查找出口所对应的函数,但是程序执行中并不会直接调用该函数,必须先确认该函数所对应的出口对象是否被激活,再通过该对象来引用函数。函数与出口对象的关系是一一对应的,该对应关系被保存在透明表MODSAP中,其中NAME字段为出口对象的名称,TYPE为出口对象的类型(E:功能退出,S:屏幕,T:表,C:GUI代码),MEMBER为出口对应的函数名称,通过该表可以查找到函数“EXIT_SAPMV45A_003”所对应的出口对象名称为“V45A0003”。
需要注意的是,一个函数只会对应一个出口,但是一个出口对应可以对应多个函数,如“V45A0003”可以同时对应“EXIT_SAPMV45A_003”和“EXIT_SAPMV45A_004”两个函数。
出口对象的描述则保存在表MODSAPT表中,具体如下图所示:
3、出口对象的查看和维护
这里我们介绍一下如何查看和修改该出口对象属性及参数。
通过事务代码SMOD可以查看并修改该出口对象。
单击工具栏的执行按钮可以输入出口对象所包含的函数清单,并可以查看该出口对象目前的状态,若该出口对象未被激活,其输出清单将会由红色的图标来表示,否则会显示绿色的图标,可以通过工具栏按钮来激活该对象,可以被激活的对象才可以在程序执行的时候被调用,如下图所示:
返回到初始页面,单击“显示”按钮,查看该出口对象的属性,如下图所示:
单击工具栏中的“组件”按钮,可以查看该出口对象所包含的组件清单,如下图所示:
双击组件清单中功能模块名称则可以直接进入该函数的维护页面,通过该页面可以看到该函数的具体结构。
4、通过CMOD实现销售订单控制增强实例
那么找到了出口之后我们该如何应用呢?下面将通过一个实例介绍如何在出口中实现SAP标准程序的增强。
要应用基于函数的出口首先必须先维护一个自定义的CMOD项目对象,输入事务代码CMOD进入项目管理维护工具。首先需要建立一个项目对象,具体步骤如下:
<1>因为本出口是针对SD模块功能的,所以首先需要在项目字段中输入自定义名称“ZSD01”,具体如下图所示:
<2>单击CMOD为维护屏幕中的“创建”按钮,进入CMOD的属性维护界面。
从属性页面可以看到,其工具栏包括三个按钮,首先为“编辑”按钮,用户切换该对象的编辑状态,另外两个工具栏按钮属性简介如下。
增强分配(Enhancement assignments):分配增强的组件对象。
组件(Parts):列出组件中所对应的功能函数。
<3>保存属性设置之后,首先单击“增强分配”按钮,系统进入组件对象维护页面,可以在一个项目中同时输入对个增强组件对象,需要注意的是,一个组件对象只能被引用一次,若在本CMOD项目中被引用了,那么这个组件就不可能在其他的CMOD中输入。
本例就输入之前我们找到的组件对象“V45A0003”,如下图所示:
<4>保存所输入的组件对象后,单击维护页面中的“组件”按钮,系统进入到组件列表页面。该页面中将列出组件所包含的功能函数,如组件对象“V45A0003”包含了“EXIT_SAPMV45A_003”和“EXIT_SAPMV45A_004”两个功能函数,若同时维护了多个组件对象,则会在该页面中将所有的函数对象按顺序列出来。
从页面中也可以看到组件对象的状态,在组件所对应的列表表头,会有一个指示图标来标示该对象的状态。组件对象必须激活才能使用,若未激活,将显示一个红色的指示图标,激活后则是一个绿色的图标。在函数一栏,也会有一个图标指示该函数的Include程序是否被激活,具体如下图所示:
<5>以“EXIT_SAPMV45A_003”函数为例,双击该函数名称进入到函数维护页面,双击该函数中预留的程序“ZXVVAU05”,若该程序还未被创建,系统将会提示:
<6>我们创建上面这个对象,系统中创建“ZXVVAU05”这个程序,“ZXVVAU05"为一个include程序,其属性与普通程序基本类似。接下来首先要了解一下“EXIT_SAPMV45A_003”函数的结构,其接口参数如下。
Importing参数:
XVBAK:用于保存订单的表头数据。
XVBUK:用于保存订单抬头的状态等数据。
XKOMK:用户保存订单中行项目的定价等信息。
Tables:
XVBKD:保存表头相关凭证信息。
XVBFA:保存行项目凭证流信息。
XVBAP:保存订单行项目物料相关信息。
XVBUP:保存行项目的状态信息。
该出口在订单保存时候被调用,调用时,接口将传递订单相关数据,同之前一讲,我们也是对订单的类型做控制。
if xvbak-auart = 'ZOR1' and xvbkd-bstkd is initial.
message '该类型下采购订单编码为必输!' type 'E'.
endif.
修改代码后,务必要激活所新建的CMOD项目,否则出口是不会在被执行时识别,接下来可以通过实际的业务操作来测试增强效果。
5、通过程序查找CMOD出口
下面介绍一下如何直接通过数据表中的信息来查找某事务代码所有相关的出口信息。
在SAP中,所有程序名称及事务代码以及程序中所包含的对象信息都会被保存在数据表TADIR中,其中主要字段包含:
PGMID:为请求和任务中的程序标示,目前SAP程序中的所有资源对象都是以”R3TR“来标示的;
OBJECT:表示对象类型,如PROG为程序,TRAN为事务代码,SMOD为增强类型等;
OBJ_NAME:表示对象名称;
DEVCLASS:表示开发类。
在SAP的标准程序设计逻辑中,所有的程序、事务代码、增强都是用了相同的开发类,所以可以根据程序名称或者事务代码先找到它定义的开发类,再根据开发类来查找其对应的SMOD增强对象,至于对象的描述,可以从数据库表MODSAPT中获取,下面分享一个查找的实例给大家。
REPORT ZEXIT.
TABLES : TSTC,
TADIR,
MODSAPT,
MODACT,
TRDIR,
TFDIR,
ENLFDIR,
SXS_ATTRT ,
TSTCT.
DATA : JTAB LIKE TADIR OCCURS 0 WITH HEADER LINE.
DATA : FIELD1(30).
DATA : V_DEVCLASS LIKE TADIR-DEVCLASS.
PARAMETERS : P_TCODE LIKE TSTC-TCODE,
P_PGMNA LIKE TSTC-PGMNA.
DATA WA_TADIR TYPE TADIR.
START-OF-SELECTION.
IF NOT P_TCODE IS INITIAL.
SELECT SINGLE * FROM TSTC WHERE TCODE EQ P_TCODE.
ELSEIF NOT P_PGMNA IS INITIAL.
TSTC-PGMNA = P_PGMNA.
ENDIF.
IF SY-SUBRC EQ 0.
SELECT SINGLE * FROM TADIR
WHERE PGMID = 'R3TR'
AND OBJECT = 'PROG'
AND OBJ_NAME = TSTC-PGMNA.
MOVE : TADIR-DEVCLASS TO V_DEVCLASS.
IF SY-SUBRC NE 0.
SELECT SINGLE * FROM TRDIR
WHERE NAME = TSTC-PGMNA.
IF TRDIR-SUBC EQ 'F'.
SELECT SINGLE * FROM TFDIR
WHERE PNAME = TSTC-PGMNA.
SELECT SINGLE * FROM ENLFDIR
WHERE FUNCNAME = TFDIR-FUNCNAME.
SELECT SINGLE * FROM TADIR
WHERE PGMID = 'R3TR'
AND OBJECT = 'FUGR'
AND OBJ_NAME EQ ENLFDIR-AREA.
MOVE : TADIR-DEVCLASS TO V_DEVCLASS.
ENDIF.
ENDIF.
SELECT * FROM TADIR INTO TABLE JTAB
WHERE PGMID = 'R3TR'
AND OBJECT IN ('SMOD', 'SXSD')
AND DEVCLASS = V_DEVCLASS.
SELECT SINGLE * FROM TSTCT
WHERE SPRSL EQ SY-LANGU
AND TCODE EQ P_TCODE.
FORMAT COLOR COL_POSITIVE INTENSIFIED OFF.
WRITE:/(19) 'Transaction Code - ',
20(20) P_TCODE,
45(50) TSTCT-TTEXT.
SKIP.
IF NOT JTAB[] IS INITIAL.
WRITE:/(105) SY-ULINE.
FORMAT COLOR COL_HEADING INTENSIFIED ON.
* Sorting the internal Table
SORT JTAB BY OBJECT.
DATA : WF_TXT(60) TYPE C,
WF_SMOD TYPE I,
WF_BADI TYPE I,
WF_OBJECT2(30) TYPE C.
CLEAR : WF_SMOD, WF_BADI , WF_OBJECT2.
* Get the total SMOD.
LOOP AT JTAB INTO WA_TADIR.
AT FIRST.
FORMAT COLOR COL_HEADING INTENSIFIED ON.
WRITE:/1 SY-VLINE,
2 'Enhancement/ Business Add-in',
41 SY-VLINE ,
42 'Description',
105 SY-VLINE.
WRITE:/(105) SY-ULINE.
ENDAT.
CLEAR WF_TXT.
AT NEW OBJECT.
IF WA_TADIR-OBJECT = 'SMOD'.
WF_OBJECT2 = 'Enhancement' .
ELSEIF WA_TADIR-OBJECT = 'SXSD'.
WF_OBJECT2 = ' Business Add-in'.
ENDIF.
FORMAT COLOR COL_GROUP INTENSIFIED ON.
WRITE:/1 SY-VLINE,
2 WF_OBJECT2,
105 SY-VLINE.
ENDAT.
CASE WA_TADIR-OBJECT.
WHEN 'SMOD'.
WF_SMOD = WF_SMOD + 1.
SELECT SINGLE MODTEXT INTO WF_TXT
FROM MODSAPT
WHERE SPRSL = SY-LANGU
AND NAME = WA_TADIR-OBJ_NAME.
FORMAT COLOR COL_NORMAL INTENSIFIED OFF.
WHEN 'SXSD'.
* For BADis
WF_BADI = WF_BADI + 1 .
SELECT SINGLE TEXT INTO WF_TXT
FROM SXS_ATTRT
WHERE SPRSL = SY-LANGU
AND EXIT_NAME = WA_TADIR-OBJ_NAME.
FORMAT COLOR COL_NORMAL INTENSIFIED ON.
ENDCASE.
WRITE:/1 SY-VLINE,
2 WA_TADIR-OBJ_NAME HOTSPOT ON,
41 SY-VLINE ,
42 WF_TXT,
105 SY-VLINE.
AT END OF OBJECT.
WRITE : /(105) SY-ULINE.
ENDAT.
ENDLOOP.
WRITE:/(105) SY-ULINE.
SKIP.
FORMAT COLOR COL_TOTAL INTENSIFIED ON.
WRITE:/ 'No.of Exits:' , WF_SMOD.
WRITE:/ 'No.of BADis:' , WF_BADI.
ELSE.
FORMAT COLOR COL_NEGATIVE INTENSIFIED ON.
WRITE:/(105) 'No userexits or BADis exist'.
ENDIF.
ELSE.
FORMAT COLOR COL_NEGATIVE INTENSIFIED ON.
WRITE:/(105) 'Transaction does not exist'.
ENDIF.
AT LINE-SELECTION.
DATA : WF_OBJECT TYPE TADIR-OBJECT.
CLEAR WF_OBJECT.
GET CURSOR FIELD FIELD1.
CHECK FIELD1(8) EQ 'WA_TADIR'.
READ TABLE JTAB WITH KEY OBJ_NAME = SY-LISEL+1(20).
MOVE JTAB-OBJECT TO WF_OBJECT.
CASE WF_OBJECT.
WHEN 'SMOD'.
SET PARAMETER ID 'MON' FIELD SY-LISEL+1(10).
CALL TRANSACTION 'SMOD' AND SKIP FIRST SCREEN.
WHEN 'SXSD'.
SET PARAMETER ID 'EXN' FIELD SY-LISEL+1(20).
CALL TRANSACTION 'SE18' AND SKIP FIRST SCREEN.
ENDCASE.
执行效果如下:
最后若我们需要删除该CMOD项目增强,必须先取消激活状态方可删除。