接手过EBS供应链项目的朋友应该都有这种感觉:销售订单发运(Ship Confirm)是整个订单履约链路里最容易出问题、也最容易被低估的环节。很多业务顾问把关注点放在订单录入、价格条件、ATP检查上,到了发运这一步就开始含糊,而开发人员呢,经常被一句“帮我写个发运的API”搞得一头雾水。实际上,发运流程横跨订单管理(OM)、库存管理(INV)、发运执行(WSH)、应收(AR)好几个模块,业务上要处理挑库、发运确认、交接、事务处理,技术上要面对一堆接口表和API。这篇先讲“把流程吃透”这件事,把从订单创建到发运完成的业务逻辑、核心表结构、配置要点一次讲清楚,API的调用细节放在系列下篇展开。
这个系列适合两类人:一类是做EBS实施的业务顾问,需要搞清楚发运流程到底有哪些状态、哪些单据、哪些参数;另一类是负责EBS二次开发的技术顾问,要写报表、做接口、排查发运异常,必须要知道数据是怎么流转的。读完这一篇,你能做到三件事:第一,说清楚一张销售订单从预订到发运确认经历了哪些关键节点;第二,看到异常数据时能快速定位是订单问题、库存问题还是发运接口问题;第三,对EBS发运相关的API体系有一个整体认知,为下篇实际调用API打好基础。
1. 先搞懂发运在EBS订单链路里的位置
1.1 发运流程到底管什么
先说一个容易混淆的概念。在EBS里,我们平时说的“发运”其实覆盖了三个阶段的业务动作:一是订单行从“已预订”变成“已挑库”,这是仓库执行动作;二是从“已挑库”变成“已发运”,这是所有权转移动作;三是发运确认后产生的一系列后续事务,包括库存扣减、应收事务创建、成本更新。换句话说,发运不是一个单点操作,而是一条业务子链。
这条子链的核心价值在于“履约”。订单答应客户哪天发货,仓库按什么规则配货,交接给谁,这些信息都要在系统里留痕。EBS把这套逻辑拆给了不同模块:OM负责记录“答应客户什么”,INV负责管理“仓库里有什么”,WSH负责执行“怎么把货交出去”。如果一个项目里只上了OM和INV,没启用WSH,那发运确认通常就是直接做Inventory Transaction;如果启用了WSH,那流程就会走挑库发放、发运事务、发运确认这套标准路径。这两条路径没有绝对好坏,但很多企业从简单模式切换到完整模式时,最容易出现数据不一致,核心原因就是没有理解各模块的职责边界。
我做实施时最喜欢用的一个类比是快递发货:订单头就是快递面单,订单行是面单上的商品明细,挑库发放是仓库拿着拣货单去货架取货,发运确认是快递员扫码出仓,而交接则是把包裹交给承运商的签字动作。这个类比虽然简单,但对业务方沟通特别有效,因为大家都有寄快递的经历。
1.2 参与发运的角色与权限边界
发运流程涉及的角色很多,每个角色看到的界面和关注的字段不一样。
订单录入员管的是订单头、订单行的录入与预订,他们通常不关心仓库实际有没有货,只看订单状态。计划员或发运文员负责挑库发放和创建发运事务,他们关心的是哪些订单行满足发运条件、怎么合并成一个交运单(Delivery)、交给哪个承运商。仓库操作员做实物拣货和发运确认,他们关心的是物料、批次、序列号、货位这些库存维度的信息。财务同事则在后台看事务处理、应收发票和成本更新结果。
权限这块有个常见的坑:很多项目为了省事,给一个职责同时挂上订单录入、发运文员、库存事务处理的菜单权限,结果用户在操作时很容易误操作,比如订单还没预订完就被挑库了,或者发运确认后库存事务处理又做了一次。我的建议是角色权限按流程阶段划分,至少要把“创建发运事务”和“发运确认”这两个职责分开,避免同一个人既当运动员又当裁判。这不仅是权限管理问题,更是流程内部控制的要求。
2. 从订单到发运:一条完整的业务路径拆解
2.1 订单行状态流转的底层逻辑
要理解发运流程,第一步是看懂订单行状态码(Flow Status Code)的流转。EBS里订单行从进入系统到最后关闭,会经历若干个状态,笼统地说就是:
Entered(已输入)→ Booked(已预订)→ Picked(已挑库)→ Shipped(已发运)→ Closed(已关闭)
每个状态转换都有触发点,不是随便就能跳过去的。从Entered到Booked要靠“预订(Book Order)”动作,系统会做ATP检查(Available to Promise),看看有没有足够的可用量来承诺这个订单;如果启用了ATP规则,预订时就会校验交期能不能满足。从Booked到Picked要靠“挑库发放(Pick Release)”,系统把符合条件的订单行释放给仓库去拣货。从Picked到Shipped靠“发运确认(Ship Confirm)”,这是整个流程里最重要的一步,它会把库存从仓库移到发运中转区或者直接减少,同时更新订单行状态。
这里我要强调一个容易被忽略的点:状态流转不是自动的,每个动作背后可能有多种触发方式。以预订为例,可以手工在订单界面上点Book,也可以通过订单导入API创建订单时带上booked标志,还可以通过后台请求自动预订。不同的触发方式对数据的校验要求不一样,比如API预订通常要求在导入时就把所有必填字段补齐,如果漏了字段,订单可能停留在Entered状态,导致后续流程卡住。很多企业上线后抱怨“订单导入成功了但一直不能挑库”,十有八九就是预订状态没走对。
2.2 挑库发放与拣货的几种模式
挑库发放(Pick Release)是发运流程的分水岭。在标准EBS里,挑库发放可以针对订单号、订单行、交运单、物料、仓库等条件执行,系统根据预先定义的挑库规则(Pick Line Rules)和子库存规则(Subinventory Rules)自动生成挑库单(Move Order)。这一步的核心是“定仓库、定货位、定拣货方式”。
先说仓库维度。每个订单行在预订后,系统会根据订单上的Warehouse(库存组织)找到对应的子库存,再根据该子库存是否启用了货位控制来决定是否生成货位建议。对于启用了货位控制的仓库,挑库发放时可以指定“建议货位”策略,系统自动按先进先出或货位顺序生成拣货路线;对于没有货位控制的仓库,拣货相对简单,直接在子库存层面操作即可。
再讲拣货方式。EBS支持标准拣货、直接发运、交叉转运等不同模式。标准拣货是:挑库发放生成Move Order → 仓库拣货 → 移入Staging(发运暂存区)→ 发运确认。直接发运是:不经过Staging区,直接从仓库发运,常用于紧急订单或大宗直发客户的情况,设置上通常需要在订单行或挑库规则里指定“直接发运”。交叉转运则是把收货和发运合并处理,货物到库后不做存储,直接按销售订单分拨发运,这种模式在分销行业很常见,配置稍复杂,但能显著降低仓储成本。
挑库发放后有一步很多项目会漏掉:发运事务(Delivery)的创建。挑库完成后,系统只是把货物移到了暂存区,还没有生成最终的“交运单”。需要发运文员在“发运事务”界面把已挑库的订单行手动或自动分配到一个Delivery下,或者按系统设置自动分组。这个Delivery就是后面做发运确认和打印装箱单、运输单的基础。
2.3 发运确认内部到底做了什么
发运确认(Ship Confirm)是让所有业务数据“落账”的关键动作。很多业务顾问以为Ship Confirm只是改个状态,实际上它在后台做了一系列操作:
第一,移动库存。如果是标准拣货流程,库存从Staging区“移出”并“发运”,系统生成库存事务(Inventory Transaction)。如果是直接发运,库存直接从仓库子库存扣减。这里要注意,发运确认的库存扣减不需要用户再手工做杂项事务,系统会自动调用INV的事务处理引擎。
第二,更新订单行状态。订单行从Picked变成Shipped,同时记录下实际发运数量、发运日期、承运商、跟踪号等信息。如果有包装信息,比如箱子、托盘,也会在这个环节写入对应表。
第三,生成或更新财务信息。发运确认后,订单行进入应收(AR)接口,后续由“应收接口导入”请求把事务推送到AR模块,生成应收发票。同时,成本管理模块会根据发运事务更新销售成本(COGS),这些数据在月末关账时特别重要。
第四,触发后续流程。比如打印装箱单、生成ASN(Advanced Shipping Notice)、更新CRM或DW系统数据。如果接了外围系统,发运确认往往是触发EDI报文或webhook通知的时机。
我在项目里经常遇到一种错误操作:用户在发运确认后发现“库存没有减少”,于是手工做了一笔杂项发货,结果库存越调越乱。其实发运确认后库存是否减少,取决于发运事务上的“Source Type”和库存组织设置,大多数情况下是自动扣减的,只是用户没有刷新界面。
3. 发运核心表结构:不懂这些表,写不了查询和报表
3.1 从订单表到发运表的连接链
做EBS开发,绕不开数据表。发运流程的核心数据,分布在OM和WSH两张“网”里。OM这边的主表是OE_ORDER_HEADERS_ALL(订单头)和OE_ORDER_LINES_ALL(订单行),订单行的状态、数量、物料、发货仓库都在订单行表里。WSH这边,核心表是WSH_DELIVERIES(交运单头)、WSH_DELIVERY_DETAILS(交运单明细)、WSH_PICKING_BATCHES(挑库批次)、WSH_PICKING_BATCH_LINES(批次行)。
订单行和发运明细是通过OE_ORDER_LINES_ALL的LINE_ID与WSH_DELIVERY_DETAILS的SOURCE_LINE_ID关联的,SOURCE_CODE通常等于“OE”。这是一个非常基础的关联条件,写发运报表时最常见的SQL就是从这两张表join起。如果订单行做了部分发运,那一条订单行会对应多条发运明细,因此写报表时要注意一对多的数据膨胀问题,通常需要按订单行做汇总或者用分析函数去重。
WSH_DELIVERY_DETAILS是整个发运流程里信息最丰富的明细表,它记录了每个发运行的物料、数量、挑库批次、来源订单、发运状态、暂存货位、分配到的交运单号等。几乎任何发运相关的问题排查,第一站都应该是这张表。
3.2 WSH_DELIVERIES和WSH_DELIVERY_DETAILS的状态逻辑
WSH_DELIVERIES是交运单头,类似“一辆车上的所有货物”的汇总。这张表里的STATUS_CODE字段代表整个交运单的处理状态,常见的有“OP”(Open,已创建未确认)、“CL”(Closed,已确认)、“CO”(Cancelled,已取消)。
WSH_DELIVERY_DETAILS的STATUS_CODE更细,包括:
- "OP":明细行打开,等待分配或发运
- "RE":已释放到仓库拣货(Released)
- "PK":已拣货(Picked)
- "SH":已发运(Shipped)
- "CT":已取消(Cancelled)
排查问题时,一定要区分这两个状态。经常出现的情况是:交运单头已经是CL了,但明细行的状态还停在PK,或者反过来,头状态OP但明细已经SH。这种数据不一致,通常是因为发运确认请求执行到一半报了错,或者有人手工改了后台数据。处理方法是找到对应状态的事务历史记录,还原当时的操作顺序,而不是盲目地去改状态字段。
3.3 发运事务处理记录表
发运确认后会生成库存事务,对应的表是MTL_MATERIAL_TRANSACTIONS(库存事务头)和MTL_TRANSACTION_LOT_NUMBERS、MTL_SERIAL_NUMBERS(批次、序列号明细)。MTL_MATERIAL_TRANSACTIONS里有几个字段对排查特别有用:TRANSACTION_SOURCE_TYPE_ID(事务来源类型,发运确认对应的值通常是11或12,具体与设置相关)、TRANSACTION_SOURCE_ID(来源ID,一般指向订单头或发运事务)、TRANSACTION_SOURCE_NAME(来源名称,比如交运单号)。
如果业务启用了序列号管理,发运确认时系统会校验序列号是否已经分配、是否在正确的库存组织下。序列号问题是最常见的发运确认失败原因之一,EBS的报错往往比较隐晦,比如“序列号无效”或“序列号已被占用”。排查这类问题要靠MTL_SERIAL_NUMBERS表加上事务历史(MTL_TRANSACTION_FLOW_CONTROL)来追踪序列号当前状态。
很多开发人员习惯一上来就查这两张表,但我的建议是先看接口日志,再看事务记录,最后才查主数据。因为发运确认是一个多步骤事务,一旦中间某一步失败,整个事务都会回滚,但接口管理器里会留下日志,能看到具体卡在哪一步。
4. 配置与实操细节:让发运真正跑起来
4.1 关键配置文件:发运参数与事务类型
流程跑不起来,很多时候不是代码问题,是配置没到位。发运相关的配置,我优先检查这几个地方:
订单管理系统(OM)的发运参数(Shipping Parameters)决定了发运事务的默认行为,包括是否自动创建交运单、是否自动做发运确认、是否在确认时校验序列号等。这个配置文件的位置在“订单管理”的“设置”下面,很多项目上线后改过一次就不再动它,但如果业务变化了(比如从非序列号管理变为序列号管理),这里的参数必须同步调整。
库存事务类型(Inventory Transaction Types)决定了发运确认生成的库存事务如何影响库存和会计科目。在“库存”模块的“事务类型”设置里,会有针对发运的“销售订单发运”事务类型,需要确认它的“允许负库存”选项、会计分类等是否符合业务要求。
WSH的设置里,挑库规则(Pick Line Rules)和子库存规则(Subinventory Rules)是生成拣货策略的源头。挑库规则决定“按什么顺序分配货位”“是否允许部分挑库”“拣货是否支持容器化”;子库存规则决定“从哪个子库存发运”。这两个规则表很直观,但很多人忽略了一个细节:规则是按“库存组织 + 订单类型 + 订单行类型”组合生效的,配置时要确保优先级顺序符合业务预期,否则可能出现“明明设置了A仓库发货,系统却从B仓库挑库”的情况。
4.2 两种典型发运场景的配置示范
为了方便理解,我整理两个最常见的场景:
场景一:标准分销发货。客户下单后,仓库在接到挑库发放时先拣货到暂存区,再统一装车发运。这种场景的配置要点:挑库发放时生成Move Order,拣货完成后手动发运确认。子库存规则指向仓库的“STAGING”暂存区,挑库发放的“Supply Source”设置成“Inventory”,发运确认后系统自动扣减库存。这个场景非常适合大多数制造和分销企业。
场景二:直接发运(Direct Shipment)。客户订单下达后,货物直接从供应商发货到客户,不需要进自己仓库。配置要点:订单行上指定“Direct Shipment”类型,发运事务可以从采购订单(PO)收货后直接流转到订单发运,不需要经过挑库发放环节。这种模式在MRO(维护、维修、运营)行业和代发业务里很常见,关键是PO和SO的联动设置,一旦设置错,经常出现收货完成了但订单行状态没有更新。
4.3 打印与包装的实用建议
发运流程不只是数据流转,还有物理单据流。装箱单(Packing Slip)、运单(Bill of Lading)、报关单这些单据,都是从WSH表里取数后通过XML Publisher或Oracle Reports打印的。打印模板建议以WSH_DELIVERY_DETAILS为数据源,而不是以订单行表为数据源,因为一份交运单可能合并多个订单,如果直接从订单行表取数,会出现同一次发运的产品信息被拆散的尴尬。定制装箱单模板时,还要注意容器(Container)信息的取出方式,因为WSH里容器和明细行是父子关系,报表要能展成多层级结构。
另外一个实操细节:启用了“发运事务自动分组”的企业,系统会按照“同一个订单、同一个仓库、同一个承运商”等条件自动把挑库后的明细行归到一个交运单下。如果业务上希望“一单一车”,就要在自动分组规则里设置好分组维度;如果希望“多单合车”,就要允许不同的订单合并到同一个交运单。这个配置直接关系到物流费用分摊和后续成本结算,务必在项目上线前和业务确认清楚。
5. API概览与自动化思路:下篇的钥匙在这里
5.1 EBS发运相关API全景图
因为系列标题里有“API详解”,我先把发运相关的API体系整体梳理一遍。EBS对外提供标准API的方式主要有三种:一是PL/SQL包形式的开放接口(Public APIs),比如订单导入、发运接口;二是基于XML Gateway或集成存储库的SOAP服务;三是通过Open Interface表加并发请求的方式做数据交互,本质上也是一种API。对于发运流程,最常用的集中在以下几个包和接口:
订单创建和预订单导入对应的是OE_ORDER_IMPORT_PUB(订单导入API)。通过这个API可以从外围OMS、电商平台把订单导入EBS,导入时可以控制是否自动预订。这是整个发运流程的第一道门。
挑库发放对应的是INV_PICK_WAVE_PUB或WSH_PICK_WAVE_PUB里的相关API。这类API用得相对少,因为大多数项目通过并发请求跑挑库发放,而不是直接调API。但如果是自动化拣货系统对接,就需要调用这些接口来触发放行。
发运确认对应的API比较繁琐,一般涉及WSH_CONTAINER_PUB(容器/发运事务接口)和INV_TRANSFER_ORDER_PUB(库存转移接口)的组合调用。在标准EBS里,一次发运确认的动作至少涉及“创建/更新交运单”“发运确认”“库存事务处理”三层逻辑,所以开发时要理解这些API之间的调用顺序,不能只调一个包就觉得万事大吉。
库存事务处理对应INV_ITEM_UTIL_PUB或INV_TRANSACTIONS_PUB,负责生成发运确认后的库存移动和会计事务。
应收接口对应AR_RECEIABLES_API_PUB或RA_CUSTOMER_TRX_API,用于在发运确认后创建应收事务,把收入确认到财务系统。
5.2 调用API前必须想清楚的三件事
第一,数据校验逻辑不能省。EBS的标准API对必填字段、状态流转、业务规则都有严格校验,调用前必须先在测试环境用接口数据跑通。很多开发在上线后发现“订单导不进去、发运确认失败”,都是因为忽略了API内部的校验链。比如订单导入时漏了Customer PO Number,可能能导入成功,但到后续发运确认时却报错;再比如发运确认API要求订单行状态必须是Picked,如果之前挑库没完成,接口直接报错。
第二,要考虑事务提交和回滚语义。API不是一个操作一个提交,有些API内部有嵌套事务,有些需要外部程序中显式提交。如果调用顺序不对,容易出现数据部分提交、部分没有提交的中间状态。排查这种问题,最有效的工具是接口管理器(Interface Manager)的事务日志,它会把每一个API调用的请求、响应、校验结果记录在案。
第三,要搞清楚标准API和定制报表的边界。EBS的标准API是“开箱即用”的,但发运流程本身和行业关系密切,零售、分销、制造、跨境贸易对发运的要求差异很大。标准API解决的是“通用流程”,如果你要做特殊业务,比如多级容器嵌套、按箱发运、部分发运拦截等,可能需要二次封装,而不是硬改标准包。很多项目在二次开发时改了标准API的代码,导致后续EBS升级异常痛苦,这一点一定要谨慎。
下篇我会重点拆解OE_ORDER_IMPORT_PUB和发运确认相关的API调用细节,包括参数说明、调试方法、报错处理,这里先点到为止。
6. 高频问题排查:常见报错与处理思路
6.1 发运相关典型问题速查表
以下这些场景,是我在项目和社区交流里见到最多的发运问题,整理成速查表方便大家对照:
| 现象 | 可能原因 | 排查切入点 |
|---|---|---|
| 订单行一直停在Booked,无法挑库 | 预订未完成、字段校验失败、仓库未定义 | 排查订单导入日志、检查订单行状态、确认仓库和子库存是否匹配 |
| 挑库发放生成不了Move Order | 挑库规则没配、库存组织错误、子库存规则冲突 | 调出并发请求日志查看缺哪个参数 |
| 发运确认时报“库存不足” | 暂存区库存数量不够、发运数量超过已挑库数量 | 到库存事务里查看Staging区现有量 |
| 发运确认后订单行仍显示Picked | 接口请求执行失败、数据状态未刷新、交运单头状态异常 | 查接口管理器日志、看WSH明细状态 |
| 发运后应收没有发票 | AR接口请求未跑、应收事务类型没设、COGS配置缺失 | 运行“应收接口导入”请求,查看AR接口表记录 |
| 序列号冲突报错 | 序列号已被其他事务占用或不在正确货位 | 用MTL_SERIAL_NUMBERS查询序列号状态,反查事务历史 |
6.2 独门排查口诀:三步定位发运问题
碰到复杂的发运问题,我通常用“三步定位法”,这套方法在项目里救过很多次。
第一步,看接口请求日志。EBS里发运确认、挑库发放、订单导入都是通过请求(Concurrent Request)跑的,请求日志里会明确记录执行到哪一步失败、错误代码是什么。很多新手一上来就去查业务表,结果绕了半天,其实日志已经写明了错误原因。
第二步,查数据流中间态。确认请求的执行情况后,沿着“订单行→发运明细→交运单→库存事务→AR接口”的顺序,逐张表确认数据的状态和数量。比如订单行是Picked,但发运明细还没生成,说明挑库发放后的Deliveries创建环节没走完,而不是发运确认有问题。
第三步,做反向验证。修复数据后,不要急着重新执行整个流程,先在一个测试订单上手工执行一遍,确认各环节正常,再放开批量处理。这个“先小后大”的思路能有效避免二次污染。
6.3 一条非常实用的经验
最后分享一个经验:EBS发运流程的问题,十有八九出在状态不一致,而不是功能缺陷。状态不一致的根因,又多半是接口或请求在中间环节被中断、或者事务提交顺序不对。所以排查问题时要养成的习惯是:先用接口日志还原操作顺序,再动手改数据。直接改后台数据是最快的解法,也往往是最容易埋雷的解法——系统里大量的事务处理、状态码约束和日志记录,改一个字段可能引起连锁反应。
后期做数据修复时,我会建议用标准事务处理来纠正数据,而不是直接update状态字段。比如某个订单行被错误地关闭了,优先考虑用订单状态历史或“重新打开”功能处理,实在没有标准功能才写脚本,并且要保留完整的数据变更记录。这样既保证数据可靠,也为后续审计留了痕迹。
发运这块内容确实很多,流程、配置、表结构、API,每一个方向都能写好几篇。这一篇侧重把发运全流程讲透,API部分只做了全景性的铺垫。我个人在实际项目中的体会是,把流程理解透,再去看API和代码,一切都会清晰很多;反过来的话,只盯着代码和SQL,很容易在发运这种多模块协同的场景里迷路。下一篇我们专门聊OE_ORDER_IMPORT_PUB的调用细节,包括INBOUND参数怎么设置、报错怎么处理、性能怎么优化,到时见。