# SalesItem 创建 API 文档 ## 概述 当自动转化销售品开关(`AUTO_CREATE_SALESITEM_FROM_PRINT_ORDER`)关闭时,通过此 API 手动创建销售品。 ## API 端点 ``` POST /api/v1/shipment/sales-items/ ``` ## 请求头 ``` Authorization: Bearer Content-Type: application/json ``` ## 请求参数 | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | printing_job_id | integer | 是 | 生产任务ID | | name | string | 是 | 销售品名称(最大200字符) | | quantity | string | 是 | 数量(支持小数,如:"100.50") | | unit | integer | 是 | 单位(见下方单位可选值) | | customer_id | integer | 否 | 客户ID(默认从生产订单获取) | | remark | string | 否 | 备注(最大200字符) | | position | string | 否 | 货位(最大200字符) | ## 单位可选值 | 值 | 单位 | 说明 | |----|------|------| | 1 | 米 | 默认单位 | | 2 | 件 | - | | 3 | 码 | - | | 4 | 个 | - | ## 请求示例 ```json { "printing_job_id": 123, "name": "产品A-2026-03", "quantity": "150.50", "unit": 1, "customer_id": 456, "remark": "加急订单", "position": "A1-01" } ``` ## 响应示例 ### 成功响应(201 Created) ```json { "id": 1, "name": "产品A-2026-03", "quantity": "150.50", "unit": 1, "unit_display": "米", "position": "A1-01", "remark": "加急订单", "printing_job_id": 123, "customer_id": 456, "shipment_id": null, "shipment_date": null, "created_at": "2026-03-05T10:30:00Z", "created_by_id": 1, "created_by_name": "张三" } ``` **注意**:`shipment_id` 为 `null` 表示该销售品处于"待分配"状态,尚未关联出货单。 ### 错误响应 #### 400 Bad Request - 缺少必填字段 ```json { "printing_job_id": ["此字段为必填项。"], "name": ["此字段为必填项。"], "quantity": ["此字段为必填项。"], "unit": ["此字段为必填项。"] } ``` #### 400 Bad Request - 生产任务不存在 ```json { "detail": "生产任务 123 不存在或不属于当前商户" } ``` #### 400 Bad Request - 单位值无效 ```json { "unit": ["单位值无效。可选值:{1: '米', 2: '件', 3: '码', 4: '个'}"] } ``` #### 400 Bad Request - 数量格式无效 ```json { "detail": "数量 abc 格式无效: invalid literal for int() with base 10: 'abc'" } ``` #### 403 Forbidden - 用户未关联商户 ```json { "detail": "用户未关联商户,无法创建销售品" } ``` #### 401 Unauthorized - 未认证 ```json { "detail": "身份认证信息未提供。" } ``` ## 权限说明 - **认证要求**:需要登录用户(`IsAuthenticated`) - **商户隔离**:自动从当前用户的 `employee.merchant` 获取商户信息 - **Django权限**:需要 `shipment.add_salesitem` 权限(遵循Django表级权限) - **生产任务验证**:必须验证生产任务属于当前商户 ## 业务逻辑 ### 创建流程 1. **验证用户商户**:从 `request.user.employee.merchant` 获取当前商户 2. **验证生产任务**:确认生产任务存在且属于当前商户 3. **数据转换**:将数量字符串转换为 Decimal 4. **获取客户ID**:如果未提供,自动从生产订单获取 5. **创建销售品**: - `shipment = null`(待分配状态) - `printing_job_id` 关联生产任务 - `merchant` 设置为当前商户 ### 状态说明 销售品没有独立的状态字段,通过 `shipment` 字段判断: - **待分配**:`shipment = null` - **已关联出货单**:`shipment != null` 创建后的销售品处于"待分配"状态,可通过出货单 API 关联到出货单。 ## 使用场景 ### 场景1:自动转化开关关闭时 当 `AUTO_CREATE_SALESITEM_FROM_PRINT_ORDER = False` 时,系统不会自动创建销售品。此时需要通过此 API 手动创建: ```python # 生产任务完成后,手动创建销售品 POST /api/v1/shipment/sales-items/ { "printing_job_id": 123, "name": "产品A", "quantity": "100", "unit": 1 } ``` ### 场景2:补充创建销售品 即使自动转化开关开启,也可以通过此 API 手动创建额外的销售品(用于特殊情况)。 ### 场景3:修正销售品 如果自动创建的销售品信息有误,可以: 1. 删除自动创建的销售品 2. 使用此 API 手动创建正确的销售品 ## 相关 API ### 查询销售品 ``` GET /api/v1/shipment/sales-items/by-printing-order//?include_already_has_shipment=false ``` ### 创建出货单并关联销售品 ``` POST /api/v1/shipment/shipments/ { "customer": 1, "shipment_date": "2026-03-05", "sales_items": [1, 2, 3] } ``` ## 注意事项 1. **商户隔离**:只能为当前用户所属商户创建销售品 2. **生产任务验证**:必须提供有效的生产任务ID,且该任务必须属于当前商户 3. **数量格式**:支持小数,使用字符串传递避免精度丢失 4. **单位验证**:必须提供有效的单位值(1/2/3/4) 5. **重复创建**:同一个生产任务可以创建多个销售品(如果业务需要) ## 测试示例 ### curl 命令 ```bash curl -X POST http://localhost:8000/api/v1/shipment/sales-items/ \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "printing_job_id": 123, "name": "测试产品", "quantity": "100.50", "unit": 1, "remark": "测试备注" }' ``` ### Python 示例 ```python import requests data = { "printing_job_id": 123, "name": "产品A-2026-03", "quantity": "150.50", "unit": 1, # 米 "customer_id": 456, "remark": "加急订单", "position": "A1-01" } response = requests.post( "http://localhost:8000/api/v1/shipment/sales-items/", json=data, headers={"Authorization": "Bearer YOUR_TOKEN"} ) if response.status_code == 201: sales_item = response.json() print(f"创建成功:{sales_item['name']} x {sales_item['quantity']} {sales_item['unit_display']}") else: print(f"错误:{response.json()}") ``` ## 更新日志 - **2026-03-05**: API 首次创建,支持手动创建销售品