forked from erp-dev/erp
feat: sales_order api
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
- 采购单在创建时默认进入 `PENDING`(审批中)状态,不再立即创建出入库记录。
|
||||
- `business.services.review_purchase_order` 统一处理审批通过 (`APPROVED`) 与作废 (`CANCELLED`) 的业务规则。
|
||||
- `api_v1/views/purchase_order.py` 暴露 `POST /api/v1/purchase-orders/<id>/review/` 接口作为唯一入口,便于前端、自动化流程和第三方系统统一调用。
|
||||
- `api_v1/business/purchase/views.py` 暴露 `POST /api/v1/purchase-orders/<id>/review/` 接口作为唯一入口,便于前端、自动化流程和第三方系统统一调用。
|
||||
|
||||
## 2. 审批流程总览
|
||||
|
||||
|
||||
67
docs/sales_order_approval_and_red_flush.md
Normal file
67
docs/sales_order_approval_and_red_flush.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# 销售单审批流程与红冲规划
|
||||
|
||||
## 1. 背景
|
||||
|
||||
- 销售单在创建时同样进入 `PENDING` 状态,审批通过后才会触发出库流程。
|
||||
- `business.services.review_sales_order` 统一处理审批通过 (`APPROVED`) 与作废 (`CANCELLED`) 的业务规则。
|
||||
- `api_v1/business/sales/views.py` 暴露 `POST /api/v1/sales-orders/<id>/review/` 接口,供前端、自动化和第三方系统一致调用。
|
||||
|
||||
## 2. 审批流程总览
|
||||
|
||||
| 步骤 | 说明 |
|
||||
|------|------|
|
||||
| 1 | 前端调用 `POST /api/v1/sales-orders/<id>/review/`, body: `{"action": "approve"}` 或 `{"action": "cancel"}` |
|
||||
| 2 | API 层校验员工身份、订单归属商户、`action` 可选项 |
|
||||
| 3 | API 调用 `review_sales_order`,根据 `action` 映射到 `SalesOrderStatusEnum.APPROVED` / `CANCELLED` |
|
||||
| 4 | Service 端根据状态调用 `_approve_sales_order` 或 `_cancel_sales_order`,并在必要时抛出业务异常(如重复审批、已有出入库记录等) |
|
||||
| 5 | API 返回最新的 `SalesOrderSerializer` 数据,供前端刷新详情 |
|
||||
|
||||
## 3. 审批通过触发的事务
|
||||
|
||||
1. `_approve_sales_order` 构建 `stock_flow_items`(结构与采购单一致)。
|
||||
2. 在事务内将 `sales_order.status` 更新为 `APPROVED`。
|
||||
3. 读取商户设置 `auto_create_stock_change_tasks`:
|
||||
- 未配置或为 `False` 时,仅更新状态。
|
||||
- 为 `True` 时投递 `business.tasks.create_sales_order_stock_entries` Celery 任务。
|
||||
4. Celery 任务执行 `StockFlowService.stock_out`:
|
||||
- 依据仓库模式创建出库 `StockChangeRecord` / `StockChangeDetail`。
|
||||
- `stock.services.make_stock_change_completed` 会在自动完成开启时写入 `Inventory` 并生成 `StockSnapshot`。
|
||||
5. 任务返回 `stock_change_record_id` 与明细信息,并写日志用于审计。
|
||||
|
||||
## 4. 作废流程约束
|
||||
|
||||
1. 仍通过 `POST /api/v1/sales-orders/<id>/review/`, body: `{"action": "cancel"}`。
|
||||
2. `_cancel_sales_order` 会检查 `source_type = SALES` 且 `source_id = 销售单ID` 的 `StockChangeRecord` 是否存在。
|
||||
3. 若已经生成出库记录,则抛出 `ValueError('销售单已生成出入库记录,无法作废')`,API 返回 `400` 提示前端。
|
||||
4. 若未生成记录,则在事务内将状态更新为 `CANCELLED`,且不会触发 Celery 任务。
|
||||
|
||||
## 5. 常见异常与返回
|
||||
|
||||
- 缺少 `customer` 字段:`400` + `{"error": "缺少客户 ID"}`。
|
||||
- 审批重复:保持幂等,直接返回当前状态。
|
||||
- 已作废单据审批:`ValueError('作废状态的销售单无法再次审批')` -> `400`。
|
||||
- 作废时已有出库记录:`ValueError('销售单已生成出入库记录,无法作废')` -> `400`。
|
||||
- ID 不存在或不属于当前商户:`404`。
|
||||
|
||||
## 6. 创建接口参数约定
|
||||
|
||||
销售单创建接口沿用采购单的参数格式,根据仓库模式填写 `items`:
|
||||
|
||||
| 仓库模式 | 出库模式 | `items` 必填字段 |
|
||||
|----------|----------|------------------|
|
||||
| `UNRESTRICTED`(宽出) | 无需指定入库明细 | `product_id`, `quantity`, `num_of_rolls`, `price`, `unit` |
|
||||
| `RESTRICT_IN`(严进宽出) | 无需指定入库明细 | `product_id`, `numbers` (list[int]), `price`, `unit` |
|
||||
| `RESTRICT_IN_OUT`(严出) | 必须指定要消耗的入库明细 | `product_id`, `consume_detail_ids` (list[int]), `quantity`, `price`, `unit` |
|
||||
|
||||
> 说明:在严出模式下,`consume_detail_ids` 列表中的 ID 必须为同仓库、同商户且未被消耗的入库明细 ID。系统会在审批通过时逐条扣减对应库存。
|
||||
|
||||
## 6. 红冲(对冲)规划
|
||||
|
||||
与采购单一致,后续将通过库存红冲入口(`StockFlowService.offset_stock_change` 占位方法)实现销售单出库的反向抵销。关键原则:
|
||||
|
||||
- 采用新增反向记录的方式,保留所有历史变动。
|
||||
- 红冲记录需要指向原 `StockChangeRecord` / `StockSnapshot`,保证审计可追溯。
|
||||
- 红冲需与业务对象绑定,避免孤立库存操作。
|
||||
|
||||
文档与测试应在红冲能力落地时同步更新,确保审批、出库、红冲形成闭环。
|
||||
|
||||
Reference in New Issue
Block a user