本体(Ontology)建模,在华为 MetaERP 语境里就是给 PTP(Procure-to-Pay,采购到付款)里的应付子域建一套“机器可读的业务语义底座”,不是画传统 ER 图,而是定义类 / 属性 / 关系 / 公理规则,让系统能推理“什么情况下允许生成应付、什么情况下禁止付款”。
下面用“供应商送货→开票→三单匹配→应付入账→付款核销”一个完整例子讲透。
一、应付模块本体的分层思路(MetaERP 风格)
层 | 作用 | 应付模块举例 |
|---|---|---|
主数据类 MasterData | 全局复用实体 |
|
单据类 Document | 业务凭证(名词) |
|
事务类 BusinessTransaction | 跨单据动作(动词) |
|
公理 Axiom | 业务强约束 | 未匹配通过禁止生成应付、付款不能超应付余额 |
💡 关键区别:传统表设计存“字段”,本体存“语义+规则”,比如“发票必须关联PO且匹配通过才能产生应付”是一条公理,不是代码 if-else。
二、定义应付域核心类(Class)
Thing ├─ MasterData │ ├─ Supplier (供应商 S007) │ ├─ Material (物料 M1001) │ └─ CostCenter (成本中心 CC202) ├─ ProcurementDocument │ ├─ PurchaseOrder (PO1005) │ ├─ GoodsReceiptNote (GRN023) │ └─ SupplierInvoice (INV0098) ├─ FinancialDocument │ └─ AccountPayable (AP3076) ├─ PaymentDocument │ └─ PaymentOrder (PAY6012) └─ BusinessTransaction ├─ ThreeWayMatch (Match001) └─ SupplierPayment (PayTrans01)三、定义属性(Property)
1)对象属性(实体间关系)
属性名 | 域 | 值域 | 含义 |
|---|---|---|---|
| 单据类 |
| PO/发票/付款单都挂同一供应商 |
|
|
| 发票引用采购单 |
|
|
| 匹配绑定PO |
|
|
| 匹配绑定收货单 |
|
|
| 匹配绑定发票 |
|
|
| 匹配通过后产出应付 |
|
|
| 应付来源发票 |
|
|
| 付款核销应付 |
|
|
| 付款事务关联付款单 |
2)数据属性(字段值)
SupplierInvoice : invoiceNo(xsd:string), invoiceDate(xsd:date), amount(xsd:decimal), currency(xsd:string) AccountPayable : remainAmount(xsd:decimal), status("未付"|"部分付"|"已清") ThreeWayMatch : matchStatus("通过"|"差异"|"异常")四、写公理(这是本体建模的灵魂)
公理1:三单匹配完整性
ThreeWayMatch subClassOf (matchWithPO exactly 1 PurchaseOrder) and (matchWithGRN min 1 GoodsReceiptNote) and (matchWithInvoice exactly 1 SupplierInvoice)公理2:只有匹配通过才允许生成应付
ThreeWayMatch subClassOf (matchStatus value 通过) only (produceAP some AccountPayable)推理效果:若
Match001缺 GRN,或匹配状态=差异,推理机直接禁止produceAP关系存在,前端不能点“生成应付”。
公理3:付款只能核销“已匹配通过”的应付,且不能超余额
SupplierPayment subClassOf (clearAP only (AccountPayable and sourceInvoice some (matchStatus value 通过)))再加一条数值约束(可用 SWRL 表达):
AccountPayable(?ap) ∧ hasRemain(?ap, ?r) ∧ SupplierPayment(?p) ∧ payAmount(?p, ?amt) ∧ swrlb:greaterThan(?amt, ?r) → IllegalOverPayment(?p)五、具体实例走一遍(含三元组)
业务场景
向供应商「华芯电子 S007」采购服务器 10 台,PO1005 单价 5万;收货 GRN023 实收 10 台;供应商开票 INV0098 金额 50万(含税),系统做三单匹配后入应付,到期付 50万。
实例化三元组(RDF 风格)
PO1005 rdf:type PurchaseOrder . PO1005 hasSupplier S007 . PO1005 totalAmount "500000"^^xsd:decimal . GRN023 rdf:type GoodsReceiptNote . GRN023 referencesPO PO1005 . GRN023 receivedQty "10"^^xsd:int . INV0098 rdf:type SupplierInvoice . INV0098 referencesPO PO1005 . INV0098 hasSupplier S007 . INV0098 amount "500000"^^xsd:decimal . INV0098 matchStatus "通过" . Match001 rdf:type ThreeWayMatch . Match001 matchWithPO PO1005 . Match001 matchWithGRN GRN023 . Match001 matchWithInvoice INV0098 . Match001 matchStatus "通过" . Match001 produceAP AP3076 . AP3076 rdf:type AccountPayable . AP3076 sourceInvoice INV0098 . AP3076 remainAmount "500000"^^xsd:decimal . AP3076 status "未付" . PAY6012 rdf:type PaymentOrder . PAY6012 hasSupplier S007 . PAY6012 amount "500000"^^xsd:decimal . PayTrans01 rdf:type SupplierPayment . PayTrans01 usePaymentOrder PAY6012 . PayTrans01 clearAP AP3076 . # 推理后:AP3076.remainAmount = 0,status -> 已清反例看推理拦截
假如GRN023只收了 8 台,匹配状态=差异:
Match002 matchStatus "差异" → 公理2触发 → 不允许 produceAP → 前端“生成应付”按钮置灰 → 若强行调接口,本体校验抛 422六、和传统数据模型对照(帮你落地时不跑偏)
传统 AP 表设计 | 本体建模做法 |
|---|---|
|
|
代码里写“if 匹配通过 then 入应付” | 写成 OWL 公理,推理机统一兜底 |
视图关联 PO/GR/INV | 对象属性 |
付款超付靠后台校验脚本 | SWRL 规则 + 余额公理实时推理 |
多系统叫法不一(供应商/客商/乙方) | 统一映射到 |
七、在 MetaERP 里的落地建议
- 先建 PTP 顶层本体,应付模块挂在
FinancialDocument+BusinessTransaction下,别单独造孤岛。 - 单据=类实例,动作=事务类,三单匹配、核销必须抽成事务类,不要塞进发票表里。
- 规则外置成本体公理:三单匹配、暂挂、超付、税差分摊、PPV 都进公理层。
- 知识图谱存实例(PO1005 这种),本体存模型,大模型基于本体做问答/异常诊断。
- 迁移老 EBS/Oracle 模型时:发票头/分配行用
part-of,付款批用聚合而非组合。
一句话总结
应付模块本体建模 = 把“PO、收货、发票、应付、付款”定义成类,把“谁关联谁”定义成对象属性,把“三单通过才入应付、付款不超余额”写成公理,再用具体业务单据灌成实例让推理机跑校验。