做 SEPA 直接借记时,业务最容易说的一句话是:“客户不是签过授权了吗,为什么还不能扣?” 这个问题刚好暴露了 account_sepa_direct_debit 的真实价值:它不是帮你导一个银行文件,而是在系统里维护授权是否有效、何时生效、是否满足发起扣款的法定与流程条件。
主要参考:
enterprise/account_sepa_direct_debit/models/sdd_mandate.pyenterprise/account_sepa_direct_debit/wizard/account_payment_register.pyenterprise/account_sepa_direct_debit/tests/test_sdd.py
一、mandate 是状态机,不是客户主数据附属字段
sdd_mandate.py 里最重要的不是几个基础字段,而是状态、签署日期、伙伴银行账户与关闭逻辑。一个 mandate 在业务上会经历草稿、有效、失效、关闭等阶段;系统必须知道当前处于哪一步,才能决定付款登记向导是否允许继续。
二、付款登记向导会主动拦截“不该扣”的场景
很多人以为只要发票上是可收款状态,就能在 register payment 里走 SEPA。企业版并不是这么设计的。account_payment_register.py 会检查适用付款方式、客户银行信息、授权状态等条件;缺任何一个,用户看到的就不是“部分可用”,而是直接不能走这条链路。
三、测试的重点在异常,不在成功
test_sdd.py 很有代表性:它不仅验证 XML 或 payment order 能生成,更会覆盖无授权、授权失效、银行账号不匹配等边界。因为真实项目里最难的不是一次成功扣款,而是系统能不能在错误数据进入银行前就拦住。
四、常见误区
- 把 mandate 当联系人标签。 实际上它绑定的是扣款合法性与账户关系。
- 只录签署日期,不管状态迁移。 这样后续很容易出现“看起来有授权,系统却拒绝”的情况。
- 认为付款方式是发票级配置。 对直接借记来说,客户银行、mandate 与 payment register 是联动的。
五、实施建议
- mandate 编号、签署日期、银行账户来源要统一,别让销售、客服、财务各存一套。
- 在测试库里演练“授权过期 / 银行改号 / 客户停用授权”三类异常。
- 培训财务时重点讲“为什么不能扣”,而不是只讲“怎么导文件”。
六、结论
SEPA 直接借记不是支付按钮,而是一条受监管约束的授权链。account_sepa_direct_debit 的价值,在于把这条链路的前置条件写死在系统里,而不是靠财务人员自己记。
DISCUSSION
评论区