## API v2:PlateOrder 批量更新(batch-update) ### 1. 概述 用于把**同一份更新数据**(`data`)批量应用到多条开版订单(`PlateOrder`)。 - **一致性**:全成功 / 全失败(任意 id 不存在或校验失败则全部不更新) - **字段控制**:仅允许更新“白名单字段”(服务端控制,前端不可越权更新) - **不触发流程副作用**:内部使用 `queryset.update()` 批量写库,不会触发 `save()` 逻辑(例如自动创建/更新流程实例等) - **支持 dry_run**:只校验与预览,不实际写库 ### 2. Endpoint - **Method**:POST - **Path**:`/api/v2/plate-orders/batch-update/` - **Content-Type**:`application/json` ### 3. 权限要求 - 需要登录(`IsAuthenticated`) - 需要工厂用户(`IsPrintingFactory`) - 需要权限:`printing.change_plateorder` - 若 `data` 包含 `is_invalid`: - `is_invalid=true` 额外需要 `printing.can_invalidate_plateorder` - `is_invalid=false` 额外需要 `printing.can_activate_plateorder` ### 4. 请求参数(Body) #### 4.1 JSON Schema ```json { "plate_order_ids": [1, 2, 3], "data": { "urgency_level": "加急", "designer": 10 }, "dry_run": false } ``` #### 4.2 字段说明 - **plate_order_ids**:`int[]`(必填) - 需要更新的 PlateOrder id 列表 - 会自动去重(保持首个出现顺序) - 任意一个 id 不存在:直接 400(不做部分更新) - **data**:`object`(必填) - 仅包含需要更新的字段键值对(字段必须在“白名单字段”中) - 只要 `data` 校验失败:直接 400,且不会更新任何订单 - **dry_run**:`boolean`(可选,默认 `false`) - `true`:仅校验、返回匹配到的 id 与原始 data,不写库 ### 5. 允许批量更新的字段(白名单) > 只允许更新以下字段;其它字段(例如 `process`/`business_object`/`created_by`/`plate_image` 等)都会被拒绝。 | 字段名 | 类型 | 示例 | 备注 | |---|---|---|---| | original_id | int \| null | 12345 | 克隆来源订单ID | | design_code | string \| null | "D20251218" | 设计编号 | | plate_type | string \| null | "首版" | 起版情况 | | plate_date | datetime \| null | "2025-12-18T10:00:00Z" | 下版时间 | | plate_method | string \| null | "圆网" | 开版方式 | | image_name | string \| null | "图A" | 图片名称 | | plate_notes | string \| null | "注意事项" | 打版注意事项 | | reprint_reason | string \| null | "复版原因" | 复版原因 | | urgency_level | string | "正常"/"加急" | 紧急程度 | | is_invalid | boolean | true/false | 作废/恢复(有额外权限要求) | | customer | int | 100 | 客户ID(不可为 null) | | area | string \| null | "广州" | 区域 | | default_address | string \| null | "XX路" | 默认地址 | | salesperson | int \| null | 11 | 销售员 Employee ID | | merchandiser | int \| null | 12 | 跟单员 Employee ID | | designer | int \| null | 13 | 设计师 Employee ID | | style_name | string \| null | "S1" | 款号名称 | | fabric | string \| null | "棉" | 布料 | | fabric_source | string \| null | "现货" | 布料来源 | | width | string \| null | "150cm" | 幅宽 | | production_method | string \| null | "现货" | 做货方式 | | is_mark_frame | boolean | true/false | 是否套唛架 | | drawing_rating | string \| null | "A" | 画图评级 | | color_matching_rating | string \| null | "B" | 调色评级 | | sample_rating | string \| null | "C" | 套样评级 | | difficulty_rating | string \| null | "简单" | 难度评级 | | sample_meter | string \| null | "5米" | 米样(文本) | | required_sample_meters | number \| null | 12.5 | 客户要求米样米数(Decimal) | | required_completion_date | datetime \| null | "2025-12-20T00:00:00Z" | 要求完成时间 | | completion_date | datetime \| null | "2025-12-19T12:00:00Z" | 完成时间 | | approval_result | string \| null | "通过" | 审批结果 | | is_ordered | boolean | true/false | 是否已下单 | | customer_feedback | string \| null | "请改色" | 客户修改意见 | > datetime 建议使用 ISO 8601 字符串(Django/DRF 默认可解析)。 ### 6. 响应 #### 6.1 成功(dry_run=false) - **HTTP 200** ```json { "detail": "批量更新成功", "updated_count": 3, "plate_order_ids": [1, 2, 3] } ``` #### 6.2 成功(dry_run=true) - **HTTP 200** ```json { "dry_run": true, "plate_order_ids": [1, 2, 3], "matched_count": 3, "data": { "urgency_level": "加急", "designer": 10 } } ``` ### 7. 错误返回 #### 7.1 字段不在白名单 - **HTTP 400** ```json { "detail": "不支持批量更新字段: process", "allowed_fields": ["..." ] } ``` #### 7.2 部分 id 不存在 - **HTTP 400** ```json { "detail": "以下 PlateOrder 不存在: 999999" } ``` #### 7.3 权限不足 - **HTTP 403** ```json { "detail": "您没有权限批量更新开版订单" } ``` 或(作废/恢复权限不足): ```json { "detail": "您没有权限作废开版订单" } ``` #### 7.4 字段类型/外键校验失败(DRF 校验错误) - **HTTP 400**(典型结构示例) ```json { "data": { "designer": ["Invalid pk \"999\" - object does not exist."] } } ``` ### 8. 使用建议 - 批量更新是“同一份 data 应用到多个订单”。如果每个订单需要不同字段值,请拆成多次调用或使用单条更新接口。