原创 Tab Zhu [ SAP TAB ](javascript:void\(0\);)
ABAP 业务Debug 之前写过一篇 [ debug的简单操作
](https://mp.weixin.qq.com/s?__biz=MzUxODI4MTQyMg==&mid=2247483738&idx=1&sn=accb99d6355f0ffa9dd85131298c6516&chksm=f98a00fbcefd89ed5243c6c78a9fac3a00a2a5569a4ee58c9c3656d32cb33ee71f7ddd03f817&token=1362387291&lang=zh_CN&scene=21#wechat_redirect)
,讲述的是如何去debug,今天写一下如何根据具体的业务报错,来一步步找到问题所在
在E-invoice 功能中,在点击display->Preview XML,系统会进行报错,提示的是街道名称不存在
但是其对应的用户地址已有street的内容维护了,让我们看下为啥程序还是报这个错误
一般对于这种报Message的错误,我们会直接按照 [ ABAP随便-简单Debug
](https://mp.weixin.qq.com/s?__biz=MzUxODI4MTQyMg==&mid=2247483738&idx=1&sn=accb99d6355f0ffa9dd85131298c6516&chksm=f98a00fbcefd89ed5243c6c78a9fac3a00a2a5569a4ee58c9c3656d32cb33ee71f7ddd03f817&token=1362387291&lang=zh_CN&scene=21#wechat_redirect)
中描述的消息断点进行debug 首先我们双击一下这个Message Text来确定这个message的ID和Number为EDOCUMENT_IT(007)
我们在 **EDOC_COCKPIT** 初始界面,输入invoice之后,在左上方搜索栏中输入/H,然后点击display
这时我们会进入debug界面:点击F9,然后点击消息/Message页签,输入我们刚才的消息号点击回车确认
然后我们点击F8,直接执行,这个时候会直接结束debug返回EDOC_COCKPIT初始界面,我们再次点击Display->Display/Preview
XML
然后系统会自动在Message触发的地方展现Debug界面
我们会发现是这个变量<ls_fattura>-fattura_elettronica_header-cessionario_committente-
sede-indirizzo为空,所以导致的错误message的抛出
根据12行的代码,我们可以知道这个<ls_fattura>是从外部传进这个类的;所以我们先点击下F7(跳出当前的方法),这时我们看到is_out_struct也是从外部传入
同理 我们再点击F7跳出这个方法:
我们这时可以看到out_struct,可以得出<ls_fattura>-fattura_elettronica_header-
cessionario_committente-sede-indirizzo
这个值一定是在这之前赋值的,其实debug的思路就是从message出发,一步一步向前找到indirizzo赋值的地方,而且其中有很多的地方需要大胆推测小心求证(连蒙带猜)。比如当前的function
moudule的名称是EDOC_AIF_GENERIC_CHECK,所我们认为这个函数大概率只是检查数据,所以我们再点F7跳出函数,然后我们可以看到进入了函数/AIF/FILE_TRANSFORM_DATA中
在代码处点击右击选择Goto Source Code,这时会弹出一个新的GUI界面显示函数/AIF/FILE_TRANSFORM_DATA,
然后我们在弹出的界面中双击OUT_STRUCT变量,然后到跳到该函数输入输出的地方:
我们可以看到这是一个输出变量,那么我们需要的<ls_fattura>-fattura_elettronica_header-
cessionario_committente-sede-indirizzo
然后我们可以看到在548行的地方调用了一个函数,其中OUT_STRUCT为Changing变量,由上方542行注释也可以判断出,这里应该是将RAW_STRUCT数据放置到OUT_STRUCT中的一个作用。又由于548行的ls_finf-
fuba_init_trans是一个变量,所以我们返回到Debug界面,双击一下该行变量,我们即可在右侧变量栏位中看到函数的名称为:EDOC_AIF_INIT_REQUEST_MAPPING
(使用Desktop 3页签)
所以我们在另一个GUI界面SE37看一下这个函数:OUT_STRUCT实参对应函数的形参是DATA
然后我们可以在这个函数中看到Data变量在98行作为cl_edoc_map_aif=>map_interface这个方法的输出实参
同理,我们继续进一步在cl_edoc_map_aif=>map_interface中找到做为es_target的形参在77行和84行进行了输出
由于这个是变量,而我们刚才又debug到该代码后面去了,所以我们需要在这个方法cl_edoc_map_aif=>map_interface中打个断点,然后重新执行GUI上的功能:
当我们程序停在这个断点(71行)的时候,我们按下F5,我们可以看到接下来执行的类是:CL_EDOC_MAP_IT_SD 方法为:MAP_INVOUT2
所以我们在另一个GUI界面查看这个类方法:
我们可以从最后的54行的语句中看到类全局变量ms_target_121赋值给了es_target,说明我们所需要的indirizzo
是在这个类中赋值的,但是这个类中掉了一堆的方法,如init_mapping(),fill_fattura_header_121(),fill_fattura_body_121()等都可以能对indirizzo进行赋值,那要如何去定位呢?
所以我这里找了一个正确的invoice去跑,发现ms_target_121-fattura_elettronica_header-
cessionario_committente-sede-indirizzo 在执行fill_fattura_header_121()方法时进行了赋值
所以我们在另一个GUI窗口中双击fill_fattura_header_121()进行查看:幸运的是,我看到了fill_cessionario_committ_121(
),看名称和结构中的cessionario_committente很相似,所以大胆点进去看
果然,我们在fill_cc_sede_121( )中看到了indirizzo的赋值 = ms_source-addr_customer-street.
所以我继续找ms_source-addr_customer-
street的赋值再何处,其实已经可以猜到了,肯定在CL_EDOC_MAP_IT_SD->MAP_INVOUT2方法的init_mapping(
)方法中,根据正确的invoice的debug我们也可以看出:在执行完init_mapping( )之后,ms_source-addr_customer-
street有值了 所以我们继续查看init_mapping( )这个方法:通过正确的invoice查看,我们可以确定在方法init_mapping(
)中的函数EDOC_IT_FATTURAFI_INIT_MAPPING完成了ms_source-addr_customer-
street的赋值:我们查看该函数中99行EDOC_IT_GET_CUSTOMER_ADDRESS函数和322行 MOVE-CORRESPONDING
ls_adrc_cust TO ls_raw-addr_customer的赋值语句
我们可以知道street就是通过这2处来赋值的,所以我们去debug那个错误的INVOICE,这是发现在函数EDOC_IT_GET_CUSTOMER_ADDRESS的输出实参中LS_ADRC_CUST-
STREET是有值的
然后我们继续往下执行,发现在该函数173行除直接退出了,所以造成了没有street的赋值,进而引发了后面一系列的报错
至此,该问题已经debug完成。
总结下:其实Debug的过程是一种类似推理的过程,说简单也简单,说难也难,很多时候需要猜测和根据经验判断,先根据一个message的报错消息,定位到消息出发的地方,然后根据其出发的条件,不断向前面的代码打上断点来一次次Debug。