1
0
forked from erp-dev/erp
Files
erpnew/docs/statements.md
2026-05-19 23:41:34 +08:00

194 lines
7.9 KiB
Markdown
Raw Permalink 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.
# Statements 对账单 API
本文件专门描述客户与供应商对账单接口的请求与响应结构。所有接口均位于 `/api/v1/`,默认需要登录并具备员工身份,且只返回当前员工所属商户的数据。
---
## 1. 功能概览
- **客户对账单**:聚合指定客户的销售单、销售退货单、收款单,以及外部来源的 statement-only 业务依据,统一展示正负金额、当前余额以及累欠金额。
- **供应商对账单**:聚合指定供应商的采购单、采购退货单、付款单,展示待付金额的增减与余额。
- **排序规则**:固定按 `occurred_at -> recorded_at -> source_id` 倒序排列,不支持外部修改。
- **金额方向**
- 客户:销售单记入 `positive_amount`(增加应收),销售退货/收款记入 `negative_amount`(减少应收)。
- 供应商:采购单记入 `positive_amount`(增加待付),采购退货/付款记入 `negative_amount`(减少待付)。
- **余额来源**:供应商对账单直接使用余额表;客户对账单在存在外部 statement-only 业务依据时,会基于余额表做一次“仅用于 statement 展示”的临时口径修正。
### 1.1 外部 statement-only 业务依据
当客户的历史 `sale` / `sale_return` 来自外部系统、且不希望落入核心 `SalesOrder` / `SalesReturnOrder` 时,系统会把它们存入:
- `business.ExternalCustomerStatementOrder`
这些记录:
- 只参与客户对账单计算
- 不参与库存流转
- 不参与核心销售单审批链
- 不修改持久化 `CustomerBalance`
在对账单响应中,它们会以以下 `source_type` 出现:
- `external_sales_order`
- `external_sales_return_order`
---
## 2. 接口列表
| API | 方法 | 描述 |
|-----|------|------|
| `/customers/<id>/statements/` | GET | 指定客户的销售、销退、收款对账单 |
| `/suppliers/<id>/statements/` | GET | 指定供应商的采购、采退、付款对账单 |
| `/statements/record/` | GET | 通过主体 + 单据信息查询单条对账记录 |
请求无需额外参数;分页暂不开放(按时间倒序返回全部记录)。单条记录查询则必须提供如下 Query 参数:
| 参数 | 说明 |
|------|------|
| `counterparty_type` | 业务主体类型,`customer``supplier` |
| `counterparty_id` | 对应客户或供应商 ID |
| `order_type` | 单据类型,取值与 `source_type` 一致,例如 `sales_order``purchase_order` 等 |
| `order_id` | 单据 ID |
> ⚠️ 由于底层仍需构建完整对账单后再筛选匹配记录,在大体量数据下应谨慎调用此接口。
---
## 3. 响应结构
```json
{
"counterparty": 6,
"counterparty_name": "杭州零售商",
"records": [
{
"source_type": "sales_order",
"source_label": "销售单",
"source_id": 1024,
"occurred_at": "2025-11-30",
"recorded_at": "2025-12-01T03:26:18.815992Z",
"status": 2,
"status_label": "审批通过",
"counterparty": 6,
"counterparty_name": "杭州零售商",
"positive_amount": "3200.00",
"negative_amount": "0.00",
"cumulative_amount": "0.00",
"current_balance": "1850.00",
"arrears_amount": "1850.00"
},
{
"source_type": "receipt_order",
"source_label": "收款单",
"source_id": 2001,
"occurred_at": "2025-12-05",
"recorded_at": "2025-12-05T02:11:07.441982Z",
"status": 2,
"status_label": "审批通过",
"counterparty": 6,
"counterparty_name": "杭州零售商",
"positive_amount": "0.00",
"negative_amount": "1500.00",
"cumulative_amount": "3200.00",
"current_balance": "1850.00",
"arrears_amount": "-335.00"
}
],
"summary": {
"positive_total": "3200.00",
"negative_total": "1500.00"
}
}
```
### 3.1 单条记录查询示例
`GET /api/v1/statements/record/?counterparty_type=customer&counterparty_id=6&order_type=sales_order&order_id=1024`
返回结构与对账单列表保持一致,仅 `records` 数组只包含匹配的那一条记录,`summary` 会基于该数组重新计算。
### 字段说明
| 字段 | 说明 |
|------|------|
| `source_type` / `source_label` | 业务来源及可读名称(`sales_order``payment_order` 等)。 |
| `source_id` | 业务单据 ID。 |
| `occurred_at` | 业务日期(如 `sales_date``return_date``receipt_date` 等)。 |
| `recorded_at` | 系统记录时间(`created_at`)。 |
| `status` / `status_label` | 业务单据当前状态(仅返回 `APPROVED` 的记录)。 |
| `counterparty` / `counterparty_name` | 客户或供应商信息。 |
| `positive_amount` / `negative_amount` | 金额正负值(字符串形式的 Decimal。 |
| `cumulative_amount` | 当前记录输出前累计的对账金额(正负抵消)。 |
| `current_balance` | 余额表的最新应收/待付款快照;每条记录重复提供,便于表格展示。 |
| `arrears_amount` | 累欠金额,等于 `current_balance - cumulative_amount`,表示该记录时刻的实时欠款/待付款。 |
| `remarks` | 统一备注字段。所有 record 都会返回;无备注时为空字符串。 |
| `extra` | 预留字段,后续可扩展批次、仓库等信息。 |
| `summary` | 记录集中正负金额的求和,供前端快速展示。 |
对于外部 statement-only 业务依据,`extra` 当前会额外包含:
- `external_source_id`
- `external_customer_id`
- `settlement_method`
对客户对账单来说,当前还可能出现两种新的 `source_type`
- `external_sales_order`
- `external_sales_return_order`
`remarks` 的来源统一如下:
- 本地采购/销售/退货/收付款单:直接取对应单据的 `remarks`
- 外部 statement-only 业务依据:取 `ExternalCustomerStatementOrder.remarks`,其中会包含同步时整理过的 `BeiZhu` / `BeiZhuC` / `BeiZhuD` / `MeoD` 文本
---
## 4. 业务规则
1. **审批依赖**:只有审批通过的单据才会出现在对账单中;审批完成后若需冲销则需走红冲流程。
2. **数据一致性**:在纯本地业务场景下,对账单直接基于审批后的业务单据和余额表计算,因此账面数据与业务状态保持一致。
3. **幂等保障**`BalanceService` 在审批中使用行级锁和 `select_for_update`,避免重复写入;对账单查询为只读操作,不影响事务。
4. **扩展字段**:如需在对账单中加入汇总、备注、仓库信息,可在视图构建 `extra` 字段或通过 serializer context 注入新的统计字段。
### 4.1 客户余额口径边界
这是本次修正最重要的边界说明。
当客户存在 `ExternalCustomerStatementOrder` 时:
- `GET /customers/<id>/balance/` 仍返回数据库中持久化的 `CustomerBalance.balance`
- `GET /customers/<id>/statements/` 中每条记录的 `current_balance` / `arrears_amount`,会基于“本地余额 + 外部业务来源净额”做一次临时口径修正
因此,在存在外部 statement-only 业务依据的客户上:
- 余额接口和对账单接口的余额展示,可能暂时不完全一致
这是当前设计的有意结果,因为:
- 我们需要让对账单拥有完整的“应收业务依据”
- 但又不希望把外部历史业务单写入核心销售链,进而污染库存与审批语义
换句话说:
- `CustomerBalance` 代表 ERP 内部正式余额账
- 客户对账单在此场景下代表“兼容外部历史业务依据后的展示口径”
---
## 5. 场景示例
### 5.1 客户账龄视图
前端可使用 `cumulative_amount``arrears_amount` 直接绘制折线或柱状图;由于排序固定为最新在前,可反向遍历展示账龄。
### 5.2 供应商对账
供应商 API 返回结构与客户完全一致,只是正负金额对应采购维度,方便在采购结算或付款审批前快速核对余款。
---
如需拓展分页、过滤、导出等能力,请在提交需求时同步更新本文件,保持文档的单一来源。