IDoc 平文件的解析与校验
目标
把 SAP IDoc 平面文件拆分为控制记录和数据记录,按照段布局解析并验证 SDATA,再转换为内部标准 JSON。
为什么重要
在韩国大型企业项目中,几乎总会遇到 ERP 集成。会议上一旦有人说“用 IDoc 接收即可”,如果不了解其结构,就无法作出任何决定。实际上,IDoc 解析就是根据段名称查找布局,再按位置截取长达 1000 个字符的 SDATA,与前一模块中的定长解析完全相同。此外,只要知道生产环境中最常见的状态码 51 并非“传输失败”,而是“SAP 内部业务处理失败”,就能打破集成双方长期各说各话的局面。
步骤
- 原始文件:
/opt/lab/fixtures/eai/idoc/ORDERS05.txt, 布局:/opt/lab/fixtures/eai/idoc/segments.md - 创建
/root/idoc,把控制记录单独保存到/root/idoc/control.txt,把数据记录单独保存到/root/idoc/data.txt。两个文件的行数之和必须等于原始文件的行数。 - 创建
/root/idoc/ctrl.csv。第一行为docnum,idoctyp,mestyp,sndprn,rcvprn,credat。每条控制记录占一行,按docnum升序排列。 - 创建
/root/idoc/segstat.csv。第一行为segnam,count。按段名称统计数量,先按数量降序,数量相同时按名称升序写入。 - 解析
E1EDK01段,创建/root/idoc/header.csv。第一行为docnum,belnr,curcy,netwr。netwr是表头总金额。 - 解析
E1EDP01段,创建/root/idoc/items.csv。第一行为docnum,posex,matnr,menge,netpr,amount。amount等于menge × netpr。 - 创建
/root/idoc/validate.sh。执行时不带参数;把表头netwr与项目amount合计不同的 IDoc 的docnum逐行输出。只要存在一条,就以非 0 退出码结束。将运行结果保存到/root/idoc/mismatch.txt。(存在1 条。) - 创建
/root/idoc/status.csv。第一行为code,meaning,action。必须包含03,12,51,53,64,68六个代码,action是정상,대기,조사,재전송之一。 - 创建
/root/idoc/orders.json。顶层为数组,各元素采用以下结构,并按docnum升序排列。{ "docnum": "...", "belnr": "...", "currency": "...", "netAmount": <숫자>, "items": [ { "posex": "...", "matnr": "...", "qty": <숫자>, "price": <숫자> }, ... ] }
参考
- 使用 Python 切片处理定长字段很方便:
line[10:30](定义文档中的位置从 1 开始,因此索引需要减 1) - 使用 jq 检查结构:
jq '.[0].items | length' orders.json - 常见错误 1:把定义文档中从 1 开始的位置直接用于从 0 开始的索引。
- 常见错误 2:没有明确数量和金额字段开头的 0 以及小数点处理方式。
- 常见错误 3:把状态码 51 解释为“传输失败”。 数据已经到达,只是 SAP 内部业务处理失败。
分离控制记录与数据记录
创建 /root/idoc,把控制记录单独保存到 /root/idoc/control.txt,把数据记录单独保存到 /root/idoc/data.txt。两个文件的行数之和必须等于原始文件的行数。
记录类型通过每行开头的标识符区分。先目视检查文件结构,再确定拆分标准。
解析控制记录
创建 /root/idoc/ctrl.csv。第一行为 docnum,idoctyp,mestyp,sndprn,rcvprn,credat。每条控制记录占一行,按 docnum 升序排列。
控制记录说明该文档是什么,以及从谁发送给谁。必须按照布局定义文档中的位置截取。
段统计
创建 /root/idoc/segstat.csv。第一行为 segnam,count。按段名称统计数量,先按数量降序,数量相同时按名称升序写入。
统计各段名称出现的次数,就能看出文档结构。表头类段通常有一条,项目类段通常有多条。
解析表头段
解析 E1EDK01 段,创建 /root/idoc/header.csv。第一行为 docnum,belnr,curcy,netwr。netwr 是表头总金额。
SDATA 是定长字符串。各段的布局不同,因此必须在定义文档中找到对应的段。
解析项目段
解析 E1EDP01 段,创建 /root/idoc/items.csv。第一行为 docnum,posex,matnr,menge,netpr,amount。amount 等于 menge × netpr。
项目有多条。提取每条的数量和单价并预先计算金额,供下一步使用。
验证表头与项目金额
创建 /root/idoc/validate.sh。执行时不带参数;把表头 netwr 与项目 amount 合计不同的 IDoc 的 docnum 逐行输出。只要存在一条,就以非 0 退出码结束。将运行结果保存到 /root/idoc/mismatch.txt。(存在1 条。)
表头记载的总额与项目合计不同时,不应处理该文档。请通过编号指出哪个 IDoc 有问题。
状态码映射表
创建 /root/idoc/status.csv。第一行为 code,meaning,action。必须包含 03, 12, 51, 53, 64, 68 六个代码,action 是 정상, 대기, 조사, 재전송 之一。
“传输失败”与“SAP 内部业务处理失败”并不相同。无法区分两者时,双方负责人会一直各说各话。
转换为内部标准 JSON
创建 /root/idoc/orders.json。顶层为数组,各元素采用以下结构,并按 docnum 升序排列。
{ "docnum": "...", "belnr": "...", "currency": "...",
"netAmount": <숫자>,
"items": [ { "posex": "...", "matnr": "...",
"qty": <숫자>, "price": <숫자> }, ... ] }
保留段的层级,把项目作为数组放在表头之下。应当能够使用 jq 验证结构。