订阅卖实物时,很多人天然觉得“每期自动开票”就已经把业务做完了。可一旦货真要发出去,你会发现财务周期和物流周期根本不是同一件事:票开了,不代表拣货、出库也已经正确生成。
这篇文章主要参考了以下企业版源码入口:
enterprise/sale_subscription_stock/models/sale_order.py
一、这篇功能真正解决什么问题
sale_subscription_stock 解决的是订阅开票链路和库存履约链路如何重新接上。普通订阅偏服务,开票之后往往已经接近闭环;但 recurring storable product 还需要继续走出库逻辑,这就要求系统在订阅周期推进时补上库存动作。
二、核心链路怎么走
1. upsell 场景先显式跳过 procurement
_upsell_context() 会在上下文里加 skip_procurement = True。这说明官方知道 upsell 不是立即发货动作,至少在某些扩容场景下,不该让库存规则立刻跟着跑。
2. 真正难点发生在开票后的库存钩子
当订阅开票后的库存后处理失败时,_handle_post_invoice_hook_exception() 会检查相关订阅行是否存在要触发 stock rule 的对象。如果有,它不会假装没事,而是准备一条明确的失败摘要与说明。
3. 失败后用活动提醒人工补救
模块不会把错误吞掉,也不会自动重试到用户看不见;它会给负责该订阅的用户安排 warning activity,提示“Subscription: Generate delivery” 这条人工补救路径。企业现场最需要的,恰恰就是这种可追踪的失败交接。
三、新手最容易踩的坑
- 以为 recurring storable product 和普通服务订阅一样,只要自动开票就够了。
- 以为库存后处理失败只是技术日志,不影响业务交付。实际上它意味着这一期货可能根本没出。
- 以为系统出错后应该完全自动修复。对真实履约链来说,能及时通知责任人比“悄悄重试”更可靠。
四、实战落地时最该盯的点
- 上线订阅实物前,先和仓储团队确认每一期到底是自动履约、半自动履约还是人工审单后履约。
- 如果门店或仓库反馈“客户已开票但没出库”,直接查 post-invoice hook 与 warning activity,不要只盯发票状态。
- 培训销售和客服理解:订阅续费成功不代表物流一定成功,两个闭环必须分别验证。
五、结论
订阅型实物之所以更难,是因为它把订阅周期、财务开票和库存履约硬绑在一起。sale_subscription_stock 的价值,不在于让流程更隐形,而在于在关键失败点把责任显性化。
DISCUSSION
评论区