1
0
forked from erp-dev/erp
Files
erpnew/business/ARCHITECTURE.md

68 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# business 模块结构与设计说明
本文档记录业务模块当前的结构、关键约定以及未来演进需要遵循的决策背景,防止在迭代中遗失设计意图。
## 1. 模块职责
`business` 负责“业务单据”领域目前包含采购单PurchaseOrder与销售单SalesOrder同时保留可扩展至退货单等更多对象的通用框架。核心职责
- 聚合与校验业务明细数据
- 通过服务层触发库存stock、财务等下游模块
- 统一处理审批、作废等状态流转
## 2. 模型抽象
### 2.1 OrderItemsAggregationMixin
封装订单明细聚合逻辑,默认访问 `items` 关联,可通过 `order_items_accessor` 指定其他关联名。提供:
- `get_total_amount()`
- `get_total_quantity()`
- `get_total_diff_quantity()`
这些方法仅关心明细结构,不关心订单方向。
### 2.2 OrderDirectionMixin
用于获取带方向的金额,约定:
- `get_direction()` 返回 `1`(正向/入库)或 `-1`(负向/出库)
- `get_signed_total_amount()` 在内部调用 `get_total_amount()` 并乘以方向
任何需要“正负金额”的业务(财务统计、库存红冲)都应依赖此能力,而不是重复编写正负逻辑。
### 2.3 OrderCounterpartyMixin
对外暴露统一的 `get_counterparty()` 接口,通过 `get_counterparty_field_name()`(或 `counterparty_field_name` 属性)确定具体业务主体字段。这样采购单/销售单分别返回 `Supplier``Customer`,但调用方只需面对一个接口。
### 2.4 订单类型
当前业务对象覆盖:
- **PurchaseOrder**(采购单):`direction=1``counterparty=supplier`,含库存明细。
- **SalesOrder**(销售单):`direction=-1``counterparty=customer`,含库存明细;严进严出模式需记录 `consume_detail_ids`
- **PurchaseReturnOrder**(采购退货单):`direction=-1``counterparty=supplier`,仓库出库、供应商欠款减少,可选关联原采购单。
- **SalesReturnOrder**(销售退货单):`direction=1``counterparty=customer`,仓库入库、客户欠款减少,可选关联原销售单。
- **PaymentOrder**(付款单):`direction=-1``counterparty=supplier`,仅金额字段,不触发库存。
- **ReceiptOrder**(收款单):`direction=-1``counterparty=customer`,仅金额字段,不触发库存。
- **SupplierBalance / CustomerBalance**:实时维护供应商应付、客户应收余额,所有审批通过的带金额单据都会写入,供查询接口和报表使用。
- **BalanceChangeRecord**(余额变动记录):仿照 `stock.StockSnapshot` 的“流水 + 快照”模式,记录每一次余额写入的来源、方向、前后余额与可能的冲抵关系,为财务审计与未来的红冲能力提供依据。
通过 mixin所有单据都具备
- 统一的金额聚合与方向计算(资金/库存可共用 `get_signed_total_amount()`
- 一致的业务主体接口(供应商/客户)
- 可扩展的服务与序列化模式(有无库存由具体模型决定)
## 3. 服务层约定
- `business.services` 负责 orchestration与 API 解耦。审批、作废、触发库存等流程必须先在服务层实现,再暴露给 API。
- 任何涉及库存的逻辑都必须通过 `stock.services.StockFlowService`,不得直接操作库存模型,保持模块边界清晰。
- 红冲/对冲等高级动作应由业务模块提供入口(例如 `PurchaseOrder` 红冲),但最终仍调用库存服务完成实际库存变动。
## 4. 未来演进建议
1. **新增单据**:若未来出现调拨单、退货单或更多资金类单据,优先复用 `OrderDirectionMixin + OrderCounterpartyMixin`(如有明细再叠加 `OrderItemsAggregationMixin`),仅通过 `get_direction()` / `get_counterparty_field_name()` 区别方向与主体,减少重复实现。
2. **审批/状态机**:采购与销售如需共享状态流转,可提炼状态机或 service 层 mixin而无需在模型层合并。
3. **统计与报表**:财务/库存统计应依赖 `get_signed_total_amount()` / `get_direction()`,确保采购/销售、退货/正向都能通过统一接口处理。
4. **余额审计**:任何会写入 Supplier/CustomerBalance 的流程必须通过 `BalanceService`,以便自动生成 `BalanceChangeRecord`。审批通过后禁止作废,若未来需要冲销,必须新建红冲记录并维护 `offset_to/offset_id` 链路。
5. **文档同步**:新增单据或服务时必须更新本文件,描述新增模型如何复用 mixin、如何影响下游模块保持设计透明。
以上约定的目标是:**保持各类业务单据的独立性,同时通过 mixin/服务层抽象复用绝大多数公共逻辑**。如需变更此架构,请在评估后更新本文件,说明原因与迁移方案。