催款跟进

Odoo 催款为什么不该只盯“是否逾期”:follow-up levels、payment_date、no_followup 与 activity 接力讲透

很多团队把催款理解成“发票逾期后发邮件”,但 Odoo 的设计更像一条分层链:先决定哪些应收行进入 follow-up,再根据 payment_date 识别当前节点,再把提醒动作和 activity 接起来。本文从核心字段与源码边界出发,把这条链讲清。

会计
进阶 开发者 2 分钟阅读
0 评论 0 点赞 0 收藏 5 阅读

很多人说到 Odoo 催款,脑海里的画面只有一件事:

  • 发票到期;
  • 系统判逾期;
  • 发邮件催客户。

但如果你真的想把 Odoo 的应收跟进跑稳,光盯“overdue”远远不够。

/home/ubuntu/odoo-temp/addons/account/models/account_move_line.pyaccount_move.py 能看到,官方在基础层先处理的是:

  • 哪些 journal item / move 应该参与 follow-up
  • 当前应优先看的日期到底是 payment_date 还是 date_maturity
  • 哪些单据根本应该被排除在 follow-up 之外;
  • 跟进动作需要如何落到 activity 这种可闭环对象上。

所以催款不是一个“发不发提醒”的按钮,而是一条分层链:先筛对象,再识别当前催款节点,再决定提醒级别,最后把动作挂到负责人的 activity 上。

一、no_followup 说明官方首先在做“对象筛选”

account.move.line 上有 no_followup,帮助文本直接写着:

Exclude this journal item from follow-up reports.

并且 _compute_no_followup() 默认会让 journal_id.type == 'general' 的行标成不参与 follow-up。

这背后是个非常现实的判断:

  • 不是所有会计分录都适合进入应收催款视角;
  • 只有真正属于客户欠款、待回款语义的 receivable 项,才应该进入 follow-up;
  • 纯总账调整、手工杂项分录如果一股脑塞进催款体系,只会让列表失真。

误区 1:以为所有带 receivable / payable 的行都应该被催

未必。

Odoo 明确给了排除入口,就是承认某些行虽然会计上挂在相关科目,业务上却不该进入催款节奏。

二、move.no_followup 说明它不是“单行技巧”,而是单据级语义

account_move_line.py_inverse_no_followup() 很有意思:

  • 如果一张 invoice 某条 line 被改成 no_followup;
  • 系统会把这个语义提升回 move 层;
  • 再同步到这张单相关的应收应付行。

这说明官方不希望 follow-up 规则停留在“某一条 journal item 的小修小补”,而更希望它表达:

这张业务单据整体要不要参与后续催款。

这对实施很重要。

如果你们经常做:

  • 内部冲账单;
  • 特殊争议账款;
  • 暂不催收的协议单;
  • 已转人工法务流程的应收;

那更合理的处理不是在报表里手工忽略,而是明确利用 no_followup 这类语义边界。

三、payment_date 说明 follow-up 看的不是单一 due date

account_move_line.py 里,_search_payment_date() 的逻辑很值得反复看。

它不是简单拿 date_maturity 搜索,而是分三段:

  1. 如果 discount_date 还没过,就按 discount_date 来判断;
  2. 如果 discount_date 已过,就退回 date_maturity
  3. 如果压根没有 discount_date,就直接用 date_maturity

这意味着 follow-up 基础层看的是:

当前最值得行动的付款节点。

所以一张启用了提前付款折扣的发票,虽然法律到期日在月底,但在折扣窗口还有效时,系统会优先把“折扣即将失效”的那天当成当前 follow-up 节点。

误区 2:把 follow-up 的日期理解成永远等于 due date

这在普通付款条款下大致成立,但在 early discount 场景下就会错。

你如果只拿 date_maturity 理解催款,就会觉得系统“提醒太早”; 其实系统在说的不是“正式逾期”,而是“当前最值得催的付款窗口”。

四、follow-up levels 的意义,本质是给不同风险阶段配置不同动作强度

虽然当前本地源码仓库没有完整的 follow-up enterprise 模块,但结合 Odoo 的核心应收字段设计,follow-up levels 的角色其实很好理解:

  • 刚到关键 payment date 时,动作轻一点;
  • 继续未付时,提醒更强;
  • 再往后,可能升级为电话、人工介入、责任人待办。

也就是说,follow-up level 不是“第几封邮件”的技术字段,而是逾期风险分层

它的价值在于把提醒动作标准化,而不是让每个财务人员按个人习惯自由发挥。

五、为什么 activity 比单纯邮件更像真正的催款闭环

如果你只发 follow-up email,会发生什么?

  • 邮件发出去了;
  • 客户没回;
  • 团队内部没人明确接下一步;
  • 结果还是要靠群里吼一声“谁跟一下”。

而 Odoo 更稳的协同机制一直是 mail.activity

这点在其他模块已经非常明显,在应收催款里同样成立:

  • email 解决“对外通知”;
  • activity 解决“对内归责”;
  • 二者结合,才是完整 follow-up。

所以当某个 follow-up level 不再只是温和提醒,而需要:

  • 销售跟客户确认;
  • 财务电话追款;
  • 客服核对争议;
  • 负责人复盘异常账款;

activity 才是真正能把下一步落到人头上的对象。

六、为什么“逾期提醒”和“责任分派”必须拆开看

许多团队做催款失败,是因为把两件事混为一谈:

  1. 客户有没有被提醒
  2. 内部有没有人接着推进

前者靠 follow-up message 就够; 后者必须靠 activity、owner、deadline 这类机制。

所以如果你看到:

  • 催款邮件按时发;
  • 但老账还是没人接;

问题往往不是 follow-up levels 不够多,而是 activity 链根本没接上。

七、实战上更稳的 follow-up 设计方式

一个更健康的做法通常是:

第一层:先清理对象边界

利用 no_followup 排掉不该进催款报表的单据。

第二层:确认 payment_date 语义

尤其是 early payment discount 场景,不要只盯 date_maturity

第三层:把 follow-up levels 当作动作强度分级

轻提醒、正式催收、升级处理,各自定义清楚。

第四层:把高等级 follow-up 接成 activity

否则系统只是在“发消息”,不是“推进回款”。

八、排查“为什么催款逻辑总让人觉得不对”时该看什么

建议按这个顺序:

  1. 这条应收是否本来就应该参与 follow-up;
  2. 是否被 no_followup 排除了;
  3. 当前看的是 payment_date 还是 date_maturity
  4. 是否存在 early discount 导致关键日期前移;
  5. follow-up level 配的是消息动作还是责任动作;
  6. 有没有把高风险阶段接到 activity;
  7. 团队是否把“发出提醒”错当成“完成跟进”。

一句话记忆

Odoo 催款不是“逾期就发邮件”,而是“先筛出该催的应收,再按当前 payment_date 判断风险阶段,用 follow-up levels 设定提醒强度,并在需要时把下一步交给 activity 负责人”的分层链路。

DISCUSSION

评论区

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