企业 销售订阅工时

Odoo 企业版订阅按工时计费为什么不是“timesheet 填了就能开票”而已:postpaid line、delivered qty 与发票回链讲透

sale_subscription_timesheet 解决的是订阅、项目工时和开票三者之间的精确衔接:哪些订阅行算 postpaid、哪些 timesheet

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

订阅按工时收费最容易出错的地方,是“记录了工时”不等于“这次就该开票”,更不等于“这张票以后还能追溯到哪几条工时”。

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

  • enterprise/sale_subscription_timesheet/models/sale_order_line.py
  • enterprise/sale_subscription_timesheet/models/account_move.py
  • enterprise/sale_subscription_timesheet/tests/test_sale_subscription_timesheet.py

一、这个模块真正解决的不是表面动作,而是跨模块语义对齐

sale_subscription_timesheet 解决的是订阅、项目工时和开票三者之间的精确衔接:哪些订阅行算 postpaid、哪些 timesheet 要进入 delivered qty、生成发票后又怎么反向关联回工时记录。

如果只看 UI,很容易把它理解成一个按钮、一张表或一个新视图。但从 sale_subscription_timesheet 的模型、测试和桥接关系看,官方真正关心的是:前台动作发生以后,后端主链路能不能继续保持同一套业务语义

二、核心机制链路

1. 先判断是不是 postpaid line

sale_order_line._is_postpaid_line() 先把该按后付逻辑处理的订阅行挑出来,避免一次性收费、预付费和按工时后付混成一团。

2. delivered qty 依赖 timesheet 取数范围

_get_timesheet_subscription_lines()、_compute_qty_delivered() 与 account_move._get_range_dates(order) 说明,不是所有 timesheet 都进这期,而是先按订阅账期截窗,再算 delivered。

3. 开票后还要能追溯回来

test_sub_link_timesheet_to_invoice 和 test_invoice_orders_if_delivery_qty 表明,工时进入发票不是终点;后续仍要知道哪几条 timesheet 已被哪张发票消费。

三、最容易被误解的边界

  • 把所有 timesheet 都累计到当前订阅周期,忽略账期窗口。
  • 不区分 postpaid line 和其他订阅行,导致 delivered qty 混乱。
  • 发票开完就断链,后续无法解释为什么这几小时已经计费。

这些误解之所以常见,往往是因为大家只看见“入口动作”,却没有继续追到模型方法、状态切换、聚合口径和测试场景里去看 Odoo 究竟把什么当成事实、把什么当成辅助信息。

四、实施与排查时,建议按这个顺序看

  • 先看订阅行是否命中 postpaid 判断。
  • 再核对 timesheet 落入的 range dates 是否正确。
  • 最后追查 invoice 与 timesheet 的反向链接是否建立。

对企业版功能来说,排查顺序非常重要。很多看似是“结果不对”的问题,真正根因往往更早:字段上下文没带过去、桥接对象没建、状态机没推进、或者权限/公司边界一开始就错了。

五、结论

按工时计费的订阅,真正重要的不是“能不能从工时开发票”,而是 delivered qty、账期窗口与回链都要同时成立。

DISCUSSION

评论区

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