forked from erp-dev/erp
4.9 KiB
4.9 KiB
销售单审批流程与红冲规划
1. 背景
- 销售单在创建时同样进入
PENDING状态,审批通过后才会触发出库流程。 business.services.review_sales_order统一处理审批通过 (APPROVED) 与作废 (CANCELLED) 的业务规则。api_v1/views/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. 审批通过触发的事务
_approve_sales_order构建stock_flow_items(结构与采购单一致)。- 在事务内将
sales_order.status更新为APPROVED。 - 读取商户设置
auto_create_stock_change_tasks:- 未配置或为
False时,仅更新状态。 - 为
True时投递business.tasks.create_sales_order_stock_entriesCelery 任务。
- 未配置或为
- Celery 任务执行
StockFlowService.stock_out:- 依据仓库模式创建出库
StockChangeRecord/StockChangeDetail。 stock.services.make_stock_change_completed会在自动完成开启时写入Inventory并生成StockSnapshot。
- 依据仓库模式创建出库
- 任务返回
stock_change_record_id与明细信息,并写日志用于审计。
4. 作废流程约束
- 仍通过
POST /api/v1/sales-orders/<id>/review/, body:{"action": "cancel"}。 _cancel_sales_order会检查source_type = SALES且source_id = 销售单ID的StockChangeRecord是否存在。- 若已经生成出库记录,则抛出
ValueError('销售单已生成出入库记录,无法作废'),API 返回400提示前端。 - 若未生成记录,则在事务内将状态更新为
CANCELLED,且不会触发 Celery 任务。
5. 常见异常与返回
- 缺少
customer字段:400+{"error": "缺少客户 ID"}。 - 审批重复:保持幂等,直接返回当前状态。
- 已作废单据审批:
ValueError('作废状态的销售单无法再次审批')->400。 - 作废时已有出库记录:
ValueError('销售单已生成出入库记录,无法作废')->400。 - ID 不存在或不属于当前商户:
404。
6. 销售退货(销退)流程补充
- API:
/api/v1/sales-return-orders/(创建、列表)与/review/审批接口,与销售单保持完全一致的认证/权限。 - 创建时字段改为
return_date,其余items结构与销售单一致(根据仓库 mode 填写numbers或quantity/num_of_rolls)。严进严出仓在退货场景下视为“入库”,故无需consume_detail_ids。 - 审批通过:
- 事务锁定单据与明细。
- 状态置为
APPROVED。 - 调用
BalanceService.adjust_customer_balance(delta=-total_amount, source=SALES_RETURN_ORDER),写BalanceChangeRecord,减少客户欠款。 - 根据商户设置触发
create_sales_return_order_stock_entries,底层走StockFlowService.stock_in(source=SALES_RETURN)。
- 作废:同销售单,只允许
PENDING且未生成StockChangeRecord的单据作废;审批后不可逆。
7. 创建接口参数约定
销售单创建接口沿用采购单的参数格式,根据仓库模式填写 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。系统会在审批通过时逐条扣减对应库存。
8. 红冲(对冲)落地状态
与采购单一致,销售单已支持整单红冲。已审批销售单可通过 POST /api/v1/sales-orders/<id>/red-flush/ 触发,生成反向余额记录和反向库存记录。关键原则:
- 采用新增反向记录的方式,保留所有历史变动。
- 红冲记录需要指向原
StockChangeRecord/StockSnapshot,保证审计可追溯。 - 红冲需与业务对象绑定,避免孤立库存操作。
红冲能力已补充独立 API 文档与定向测试,确保审批、出库、红冲形成闭环。详细 API 见 docs/2026-06-12_business_red_flush_api.md。