### 文档说明 本文档描述 `api_v2` 中 **PrintingJob 批量推进流程状态**的两个接口(preview + submit),用于前端生成批量表单与提交批量推进。 ### 背景与术语 - **PrintingJob**:概念上等同于“订单明细对象”,归属一个 `PrintingOrder`。 - **Stateflow**:PrintingJob 通过 `business_object`(`stateflow.BusinessObject`)承载流程实例;推进逻辑复用 `stateflow.services.advance_to_next_state(...)`。 - **批量推进**:对多个 PrintingJob(要求同一订单、同一待执行节点)使用同一份工艺参数推进一个节点。 ### 权限与鉴权 - **鉴权**:需要登录(`IsAuthenticated`),使用系统统一 JWT 认证。 - **业务权限**:需要印染工厂身份(`IsPrintingFactory`),即 `request.user.employee.merchant.type == FACTORY`。 ### 路由与代码位置 - **Base**:`/api/v2/` - **实现文件**:`api_v2/views/printing.py` - **路由定义**:`api_v2/urls.py` ### 统一校验规则(preview 与 submit 共用) 批量推进(或预览)必须同时满足: - **ID 存在**:`printing_job_ids` 全部存在,否则 400。 - **同一订单**:所有 job 必须属于同一个 `printing_order`,否则 400。 - **必须绑定流程实例**:每个 job 必须有 `business_object`,否则 400。 - **同一待执行节点**:所有 job 的 `next_pending_state` 必须一致,否则 400。 - **可推进**:任一 job 的 `next_pending_state` 为 `None`(流程已完成或无节点)则 400。 > 备注:当前 **不做 preview→submit 竞态处理**(例如 preview 通过后,期间有人推进了其中部分 job)。submit 会重新校验;如需更好的用户体验,后续可引入 snapshot token / 幂等键。 --- ## 批量推进预览(用于生成批量表单) ### Endpoint - **POST** `api/v2/printing-jobs/batch-advance/preview/` ### Request Body ```json { "printing_job_ids": [101, 102, 103] } ``` ### Response(200) 返回下一待执行节点(统一)及其工艺参数定义: ```json { "printing_order_id": 55, "printing_job_ids": [101, 102, 103], "next_state": { "id": 7, "name": "染色", "description": "染色工序", "order": 0, "parameters": [ { "id": 12, "key": "temperature", "value": "", "attachment": null, "attachment_url": null, "description": "温度(必填)", "is_required": true, "is_image_path": false } ] } } ``` ### 典型错误(400) 返回 `{"detail": "<原因>"}` 或字段级错误,例如: - 不同订单:`所选明细不属于同一个 printing_order,无法批量推进` - 缺 business_object:`以下 printing_job 未关联流程实例(business_object),无法推进: ...` - next_state 不一致:`所选明细当前待执行节点不一致,无法批量推进...` - 已完成/无节点:`没有待执行节点(流程已完成或无节点)` --- ## 批量推进提交(全成功/全失败) ### Endpoint - **POST** `api/v2/printing-jobs/batch-advance/` ### 语义(重要) - **事务全成功/全失败**:接口使用数据库事务包裹: - 创建批量推进记录(审计表) - 逐个调用 `stateflow.services.advance_to_next_state(...)` 推进每个 job 的 `business_object` - 任意一个 job 推进失败:**整体回滚**(不会产生任何 stateflow 日志,也不会产生批量记录) ### Request Body ```json { "printing_job_ids": [101, 102, 103], "parameters": { "temperature": "25.5", "operator": "张三" } } ``` 说明: - `parameters` 会作为 `**kwargs` 传入 `stateflow.services.advance_to_next_state(...)`。 - 若下一节点存在必填参数(`is_required=true`),则必须提供对应 key,否则返回 400(错误信息形如 `缺失必填参数: temperature`)。 ### Response(200) ```json { "detail": "已完成状态: 染色", "batch_id": 9, "printing_order_id": 55, "printing_job_ids": [101, 102, 103], "jobs": [ { "id": 101, "printing_order": 55, "product": { "id": 1, "...": "..." }, "work_state": 0, "quantity": 10, "width": "150cm", "fabric": "棉", "unit": "米", "size": null, "pieces": null, "description": null, "business_object_id": 888, "created_at": "2025-12-12T10:00:00+08:00", "updated_at": "2025-12-12T10:01:00+08:00", "billed_quantity": "0.00" } ] } ``` 说明: - `jobs` 使用 `PrintingJobV2Serializer`:其中 `product` 为嵌套对象(不是纯 ID)。 ### 典型错误(400) - 参数缺失:`{"detail": "缺失必填参数: temperature"}` - 不满足一致性校验:同 preview 的错误列表。 --- ## 批量推进审计表:PrintingJobBatchAdvanceRecord ### 模型 `printing.models.PrintingJobBatchAdvanceRecord` ### 字段(核心) - `created_at` / `updated_at`:来自 `ModelBase` - `created_by`:操作人(可空,删除用户后保留记录) - `printing_order`:所属主订单 - `state`:本次被“完成”的流程节点(推进时的 next_pending_state) - `parameters`:本次批量推进提交的参数(JSON) - `printing_jobs`:本次批量推进涉及的明细集合(ManyToMany) ### 迁移 - `printing/migrations/0024_printingjobbatchadvancerecord.py` --- ## 前端联调建议 - 先调用 preview 获取 `next_state.parameters` 生成批量表单(必填项根据 `is_required`)。 - 表单提交调用 submit;如返回 400,提示 `detail` 并建议用户刷新列表后重试。 - 当前未实现竞态 token/幂等键;如需要防重复提交,建议后续加 `Idempotency-Key`(前端生成 UUID,后端在批量记录表上做去重)。