开灵科技 › 费控报销系统 › 凭证规则引擎怎么设计

凭证规则引擎设计:报销转凭证不只是一张映射表

开灵科技 · 2026-09-05

报销单记的是「谁、因何事、花了多少钱」,凭证要的是「借贷科目、金额、辅助核算维度」。中间那层翻译不是一张表能解决的——同一个费用类型,不同部门、不同项目、不同票种,出来的科目都不一样。真正需要的是一个可配置、可追溯、可试算的规则引擎。

引擎要从单据里推导四类信息

推导目标决定因素说明
借方科目费用类型 + 部门 / 项目等维度费用的归属,最核心也最复杂
贷方科目支付方式由「谁先垫付了钱」决定
税额拆分票种 + 费用类型可抵扣性 + 税率决定费用金额是否含税
辅助核算维度单据字段直接透传不需映射,但要校验完整性

四类里只有第一类需要复杂规则,但它恰恰是决定整个方案成败的部分。

最容易犯的设计错误:把条件写成固定列

很多实现会把匹配条件设计成规则表上的固定列——一列 dept_id、一列 project_id、一列 invoice_type。这样做的后果是:每增加一个匹配维度就要改表结构、改代码、重新发版。

正确的做法是规则与条件分两张表,条件行数不限,之间是 AND 关系:

voucher_rule 映射规则主表 rule_type 规则类型:借方科目 / 贷方科目 / 税额处理 target_subject 命中后使用的会计科目编码 priority 优先级,数值越小越优先 effective_from 生效日期 effective_to 失效日期(空 = 长期有效) enabled 是否启用 remark 业务含义说明(供财务人员阅读) voucher_rule_cond 规则条件表(一条规则可含多个条件,AND) rule_id 所属规则 field 字段名:expense_type / dept / project_type / pay_method ... operator 运算符:= / in / like / is_null value 条件值

这样设计之后,新增一个匹配维度只需在 field 的枚举里增加取值,无需变更表结构,也无需发版。

科目主数据不能省

科目不能只在规则表里存一个编码字符串,必须有独立的主数据表。关键是 required_dims 这个字段——它让系统能在凭证生成阶段就完成维度完整性校验,而不是等推送到总账后被拒绝。

subject 会计科目主数据 code 科目编码 name 科目名称 is_leaf 是否末级科目(只有末级科目允许记账) direction 余额方向:借 / 贷 required_dims 必需的辅助核算维度,如 ["dept", "project"] effective_from 启用日期

优先级不要让财务手工填

让财务人员手工填写优先级数字,几乎必然出错——他们需要在脑子里比较所有规则的精确程度。更可靠的做法是由系统按条件数量自动计算:条件越多的规则越精确,优先级越高。

priority = 1000 - (条件数量 × 100) 规则A:费用类型=差旅费 AND 部门=销售部 → 2 个条件 → priority 800 规则B:费用类型=差旅费 → 1 个条件 → priority 900 规则C:(无条件,兜底) → 0 个条件 → priority 1000 销售部的差旅费同时命中 A、B、C,按 priority 升序取 A

在自动计算的基础上保留人工微调入口,用于处理同条件数但需要区分先后的特殊情况。

必须有兜底规则

匹配流程是:筛选候选规则(类型匹配、已启用、单据日期落在生效期间)→ 逐条判断所有条件是否全部满足 → 命中多条按 priority 升序取第一条 → 无命中走兜底规则。

兜底规则不能省。如果没有它,客户新增一个费用类型就会导致凭证生成失败,而此时报销单已经审批通过、无法回退,业务直接卡死。兜底科目(如「待分类费用」)能让业务先流转,财务事后调整。

试算功能同样不能省

引擎必须提供试算能力:输入一张历史报销单,输出完整的推导链条——命中了哪条规则、为什么命中、最终生成什么科目。

试算输出项内容示例
输入摘要费用类型=差旅费-住宿,部门=销售部,票种=专票,税率 6%
候选规则命中 3 条:规则A(800) / 规则B(900) / 兜底(1000)
最终采用规则A —— 条件「费用类型=差旅费」「部门=销售部」均满足
推导结果借方 660101 销售费用——差旅费

缺少这个功能,规则配错只能等到生成凭证报错时才发现,排查成本极高,财务人员也无法自助验证。

历史凭证不能被规则变更影响

半年后财务调整了映射规则,你仍需能解释「这张历史凭证当时为何是这个科目」。这依赖两项机制:规则表的 effective_from / effective_to 生效期间,以及凭证分录上记录 hit_rule_id 规则快照。

凭证生成时按「单据日期」所处期间选取规则版本,而不是按当前时间。

这个场景在开灵科技费控系统里怎么处理

规则与条件分离的数据模型,新增匹配维度不改表结构不发版;优先级按条件数量自动计算并保留人工微调;内置兜底规则与试算工具,财务可自助输入历史单据查看完整推导链条;凭证分录记录命中规则快照,规则变更不影响已生成的历史凭证。

了解开灵科技费控报销系统 →

常见问题

报销转凭证用一张映射表不行吗?

不行。同一费用类型在不同部门、不同项目、不同票种下科目都可能不同,一对一映射表无法表达多条件匹配和优先级。

优先级为什么不能让财务填?

财务需要在脑中比较所有规则的精确程度,规则一多必然出错。按条件数量自动计算更可靠,再保留人工微调处理特例。

兜底规则会不会导致科目乱记?

会有少量单据进入待分类费用,但这比凭证生成失败、已审批的报销单卡死要好得多。财务可事后集中调整。

规则改了,以前的凭证会变吗?

不会。规则表有生效期间,凭证分录上记录了当时命中的规则 ID,按单据日期选取规则版本,历史凭证可完整追溯。