企业 销售订阅

Odoo 企业版销售:订阅为什么必须同时有周期和 recurring line

sale_subscription 的很多约束看上去“太严格”,比如有 recurring line 就必须有 plan,有 plan 又不能没有

企业 销售
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 3 阅读

订阅单最怕的不是字段多,而是语义不一致:明明有 recurring 产品却没有周期,或者挂了计划却找不到任何 recurring line。短期看似还能保存,长期一定会把续约、开票和分析全拖偏。

这篇文章主要参考了以下企业版源码入口:

  • enterprise/sale_subscription/models/sale_order.py

一、这篇功能真正解决什么问题

sale_subscription 的核心任务是把销售订单变成一台可持续推进的订阅状态机。要做到这一点,订单上所有关键字段都必须彼此解释得通:有没有 recurring 语义、属于什么 plan、当前处在什么订阅状态、是不是续约单或 upsell 单。

二、核心链路怎么走

1. is_subscription 不是手填标签,而是由 plan 驱动

_compute_is_subscription() 的逻辑很直接:没有 plan_id,或者当前状态是 upsell,就不被认定为标准订阅。也就是说,plan 不是附属属性,而是让订单进入订阅世界的入口。

2. subscription_state 取决于订单状态与父子关系

_compute_subscription_state() 会根据 stateis_subscriptionsubscription_id 判断当前是新订阅报价、续约报价还是别的形态。这让普通销售单、续约单、upsell 单不会混成一锅。

3. 真正兜底的是一组硬约束

_constraint_subscription_plan() 明确规定:确认态订阅若有 recurring line 就必须有 plan;若有 plan 却没有 recurring line 也不行;upsell 还不能跨币种。表面上这些规则很“较真”,实际上它们是在防止未来 next_invoice_date、MRR、续约链路失去依据。

三、新手最容易踩的坑

  • 把 plan 当作可有可无的标签,结果 recurring 产品根本没有统一周期语义。
  • 以为订阅状态能手工随便改。很多状态都是计算字段,背后依赖订单生命周期。
  • 以为 upsell 只是普通报价的另一种叫法。源码对 upsell 的币种和订阅识别都给了特殊边界。

四、实战落地时最该盯的点

  • 产品、模板和销售流程设计时就要决定 recurring line 从哪里来,不要等订单确认后再补 plan。
  • 如果项目里经常出现“订阅单保存不了”的抱怨,先查是不是行和计划语义不一致,而不是先怀疑权限。
  • 做数据迁移时,宁可慢一点把历史单梳理干净,也不要留下“有 recurring line 但无 plan”的灰色数据。

五、结论

订阅之所以必须同时有周期和 recurring line,不是因为 Odoo 爱设门槛,而是因为它要保证状态机、开票节奏和收入分析始终站在同一套事实之上。少了任何一个锚点,订阅单都会变成不可解释的半成品。

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。