宫斗龙老师,还记得您说SAP ECC标准事务码的代码,看不懂很正常么?
看不懂SAP标准事务码的ABAP代码,很多代码就像是盲人摸象。还是应该看懂比较好,下面我们来研究一个事务码MB51.
事务码MB51的样子如下:
作用主要是查看 物料凭证
运行结果的样子是这样:
注意看MvT这个字段,含义是移动类型
采购入库阶段,主要的移动类型(BWART)是103和105
生产订单投料阶段,主要的移动类型(BWART)是261和262
我对这个事务码很感兴趣,它很好用,我决定写一个类似的事务码,因此,我需要先看懂MB51的ABAP代码。
注意看到MB59和MB51使用同一个“程序”
看到归根结底,MB51这个事务码对应的程序叫做 RM07DOCS
上图用SE38看属性,看到这个RM07DOCS 的属性如上图所示。
程序开头注释明确表示,MB51的功能。下面逐行看该程序代码:
代码共5900行,其中从第1行至921行,都是声明变量
493行include rm07docs_generated 代码用于显示MB51屏幕1000上的前两个selection-screen
如上图,屏幕1000的元素全部显示出来
然后代码进入INITIALIZATION
第一个陌生的语法BREAK-POINT
Debugging ABAP programs using Log Point ID and Break Point ID CheckPoint Group (SAAB tcode) commands makes ABAP debugging easier for programmers. SAP SAAB transaction is used to create new CheckPoint group and activate a checkpoint group for a specified time range and for selected users. In this ABAP tutorial, I'll try to show how to use CheckPoint groups using SAAB transaction and the ABAP code syntax of Log-Point Id and Break-Point Id commands.Using Break-Point Id enables ABAP debugger to activate break points set into the code whenever required. If the Break Points are not activated using the SAAB transaction, they will not hit during the execution of the ABAP program. But if the debugging user has activated the Checkpoint Group for Breakpoints using SAP SAAB transaction, the code execution will stop at the "BREAK-POINT ID" statement line for the specified users.
简单地说,在这里放一个debug的点,是否启用取决于SAAB这个事务码中对这个BREAK-POINT的配置。详细的用法,单独写博客,过。
到1638行,代码就结束了,从1639至5915都是form也就是 子例程。
事件流(6个):
INITIALIZATION(初始化)
AT SELECTION-SCREEN(屏幕跳出前)
START-OF-SELECTION(取数据)
END-OF-SELECTION(展示数据)
TOP-OF-PAGE(普通报表输出页头)
END-OF-PAGE(普通报表输出页尾)
AT SELECTION-SCREEN 的解释:
(1).其实就像一个FORM,所以在这个事件里声明的变量都是局部变量。
(2).根据SY-UCOMM这个系统变量可以判断用户的命令
(3).在这个事件里响应的是屏幕上选择条件中的事件,例如CHECKBOX的选择与否,RADIOBUTTON的选择,LISTBOX的选择等等。所以分为以下几个方面:
1). ... ON psel :在PARAMETER变化是触发的事件
2). ... ON END OF sel :SELECT-OPTION触发的事件
3). ... ON VALUE-REQUEST FOR psel_low_high :选择的帮助(F4)
4). ... ON HELP-REQUEST FOR psel_low_high :选择的帮助(F1)
5). ... ON RADIOBUTTON GROUP radi :单选按钮事件
6). ... ON BLOCK block :框架的触发事件
7). ... OUTPUT :响应屏幕上的事件,修改选择屏幕的唯一方法
1264行,未执行
1270行,未执行
1280行,执行了结果如下:
1294行,database = x 所以执行了,如下
注意到其中1302行为select语句准备字段列表的 form fields_for_selectrion很骚气:
执行之后,将需要select到的字段存储到了g_t_fields中
执行到1309行之后:
将要执行RM07DOCS中的子例程DATA_SELECTION
下面运行到1324行,没有执行
下面运行到1334行,没有执行
下面运行到1343行,没有执行
下面运行到1352行,没有执行
1367执行了,但是没有实质内容,略过
下面进入END-OF-SELECTION
rx的定义如下图:
rx是一个宏,定义在RM07DOCS_CONTROL中
宏是一种单纯源代码复用技术,不存在参数传递机制,宏比include形式更为简单,往往只是为了增强程序的可读性。宏可以在程序中定义,再进行调用使用,此宏只在本程序中可用。也可以将宏定义存贮在Macros库Trmac(se11中查看)中,这样可以在任何程序中直接调用。
Define macro_name.
End-of-definition.
必须在Define和End-of-definition之间指定完整的语句,这些语句最多包含9个占位符,即&1-&9。占位符的意义在于暂时不指定代码,调用的时候进行代码替换。
定义一个宏:
-
Define a macro
DEFINE CATALOG. L_INDEX = L_INDEX + 1. CLEAR LS_FIELDCAT. LS_FIELDCAT-COL_POS = L_INDEX. LS_FIELDCAT-TABNAME = 'GT_LIST'. LS_FIELDCAT-DDICTXT = 'M'. LS_FIELDCAT-FIELDNAME = &1. LS_FIELDCAT-SELTEXT_M = &2. LS_FIELDCAT-OUTPUTLEN = &3. LS_FIELDCAT-KEY = &4. LS_FIELDCAT-REF_TABNAME = &5. LS_FIELDCAT-REF_FIELDNAME = &6. LS_FIELDCAT-JUST = &7. LS_FIELDCAT-QFIELDNAME = &8. LS_FIELDCAT-CURRENCY = &9. APPEND LS_FIELDCAT TO PT_FIELDCAT. END-OF-DEFINITION.
-
Use the macro
CATALOG:'PERNR' TEXT-001 '12' '' '' '' '' '' '', 'ENAME' TEXT-002 '10' '' '' '' '' '' '', 'ZYEAR' TEXT-003 '04' '' '' '' '' '' '', 'BEGDA' TEXT-004 '10' '' '' '' '' '' '', 'ENDDA' TEXT-005 '10' '' '' '' '' '' '', 'PERIOD' TEXT-006 '21' '' '' '' '' '' '', 'ORGEH' TEXT-007 '08' '' '' '' '' '' '', 'ORGTX' TEXT-008 '20' '' '' '' '' '' '', 'RATING' TEXT-010 '10' '' '' '' '' '' '', 'RTEXT' TEXT-009 '08' '' '' '' '' '' '', 'ID' TEXT-011 '08' '' '' '' '' '' '', 'TSTEXT' TEXT-012 '15' '' '' '' '' '' ''.
具体位置如下:
在主程序中的位置,远远在INITIALIZATION之前
看看下面这段语法,写的多么简洁:
数据首先被存储在RTT中,然后LOOP rtt,将其中的内容通过ls_col_fields转移到 gt_col_fields中
说实话,我也懒得继续往下看了,归根结底
上图所示的内表中的数据,与最终显示的表一致
也就是说ITAB这个内表中的内容就是我们需要的数据来源
回顾一下ITAB这个表的数据来源、
其中(g_t_fields)
代码中include的位置
最终确认,事务码MB51的数据源就是MSEG和MKPF
SQL语句的写法如上图所示:
select (g_t_fields)
into corresponding fields of table itab
from mkpf inner join mseg
on mkpf~mandt = mseg~mandt
and mkpf~mblnr = mseg~mblnr
and mkpf~mjahr = mseg~mjahr
for all entries in matnr
where matnr = matnr-low
and MKPF~BUDAT in BUDAT
and MSEG~BWART in BWART
and MSEG~CHARG in CHARG
and MSEG~KUNNR in KUNNR
and MSEG~LGORT in LGORT
and MSEG~LIFNR in LIFNR
and MSEG~MAT_KDAUF in MAT_KDAU
and MSEG~MAT_KDPOS in MAT_KDPO
and MSEG~SOBKZ in SOBKZ
and MKPF~USNAM in USNAM
and MKPF~VGART in VGART
and MSEG~WERKS in WERKS
and MKPF~XBLNR in XBLNR.
append 'MSEG~ANLN1' to g_t_fields.
append 'MSEG~ANLN2' to g_t_fields.
append 'MSEG~APLZL' to g_t_fields.
append 'MSEG~AUFNR' to g_t_fields.
append 'MSEG~AUFPL' to g_t_fields.
append 'MKPF~BKTXT' to g_t_fields.
append 'MKPF~BLDAT' to g_t_fields.
append 'MSEG~BPMNG' to g_t_fields.
append 'MSEG~BPRME' to g_t_fields.
append 'MSEG~BSTME' to g_t_fields.
append 'MSEG~BSTMG' to g_t_fields.
append 'MKPF~BUDAT' to g_t_fields.
append 'MSEG~BUKRS' to g_t_fields.
append 'MSEG~BWART' to g_t_fields.
append 'MSEG~BWTAR' to g_t_fields.
append 'MSEG~CHARG' to g_t_fields.
append 'MKPF~CPUDT' to g_t_fields.
append 'MKPF~CPUTM' to g_t_fields.
append 'MSEG~DMBTR' to g_t_fields.
append 'MSEG~EBELN' to g_t_fields.
append 'MSEG~EBELP' to g_t_fields.
append 'MSEG~ERFME' to g_t_fields.
append 'MSEG~ERFMG' to g_t_fields.
append 'MSEG~EXBWR' to g_t_fields.
append 'MSEG~EXVKW' to g_t_fields.
append 'MSEG~GRUND' to g_t_fields.
append 'MSEG~KDAUF' to g_t_fields.
append 'MSEG~KDEIN' to g_t_fields.
append 'MSEG~KDPOS' to g_t_fields.
append 'MSEG~KOSTL' to g_t_fields.
append 'MSEG~KUNNR' to g_t_fields.
append 'MSEG~KZBEW' to g_t_fields.
append 'MSEG~KZVBR' to g_t_fields.
append 'MSEG~KZZUG' to g_t_fields.
append 'MSEG~LGORT' to g_t_fields.
append 'MSEG~LIFNR' to g_t_fields.
append 'MSEG~MATNR' to g_t_fields.
append 'MSEG~MAT_KDAUF' to g_t_fields.
append 'MSEG~MAT_KDPOS' to g_t_fields.
append 'MKPF~MBLNR' to g_t_fields.
append 'MSEG~MEINS' to g_t_fields.
append 'MSEG~MENGE' to g_t_fields.
append 'MKPF~MJAHR' to g_t_fields.
append 'MSEG~NPLNR' to g_t_fields.
append 'MSEG~PS_PSP_PNR' to g_t_fields.
append 'MSEG~RSNUM' to g_t_fields.
append 'MSEG~RSPOS' to g_t_fields.
append 'MSEG~SHKZG' to g_t_fields.
append 'MSEG~SOBKZ' to g_t_fields.
append 'MKPF~USNAM' to g_t_fields.
append 'MKPF~VGART' to g_t_fields.
append 'MSEG~VKWRT' to g_t_fields.
append 'MSEG~WAERS' to g_t_fields.
append 'MSEG~WERKS' to g_t_fields.
append 'MKPF~XABLN' to g_t_fields.
append 'MSEG~XAUTO' to g_t_fields.
append 'MKPF~XBLNR' to g_t_fields.
append 'MSEG~ZEILE' to g_t_fields.
append 'MSEG~MAA_URZEI' to g_t_fields.
append 'MSEG~XMACC' to g_t_fields.
下面我们重点看一下