# API v1 创建销售单（/api/v1/sales-orders/）

> 视图位置：`api_v1.views.business.sales.views.SalesOrderView.post`  
> 服务逻辑：`business.services.create_sales_order`（含事务，主单与明细同事务创建）

## 请求

- 方法：`POST`
- 路径：`/api/v1/sales-orders/`
- Body（JSON）
  - `customer` *(int, 必填)*：客户 ID
  - `warehouse` *(int, 必填)*：仓库 ID
  - `order_date` *(string, 必填)*：日期，`YYYY-MM-DD`
  - `remarks` *(string, 可选)*
  - `items` *(array, 必填，至少 1 条)*：销售明细
    - 通用字段：
      - `product_id` *(int, 必填)*
      - `price` *(string/number, 必填)*
      - `unit` *(string, 可选；默认产品单位或“米”)*
      - `empty_diff_percent` *(string/number, 可选，默认 0)*
      - `color` / `batch_number` / `remarks` / `spec` *(可选)*
      - `printing_job` *(int, 可选)*：绑定印染任务 ID  
        - 校验：存在且产品一致；若传入销售客户，需与任务的 `printing_order.customer` 一致。
    - 数量字段取决于仓库模式：
      - 宽进/宽出 (`UNRESTRICTED`)：`quantity`、`num_of_rolls`
      - 严进宽出 (`RESTRICT_IN`)：`numbers` 数组（每条数值为正），自动汇总数量
      - 严进严出 (`RESTRICT_IN_OUT`)：出库需 `consume_detail_ids` 数组 + `quantity`；入库需 `numbers`

## 响应

- 成功 `201 Created`：`{"id": <销售单ID>, "status": <状态枚举>, "message": "销售单创建成功，等待审批"}`
- 失败 `400 Bad Request`：缺参、格式或校验不通过（含 printing_job 校验）。

## 示例

### 严进严出（出库）示例
```json
{
  "customer": 12,
  "warehouse": 3,
  "order_date": "2025-12-20",
  "items": [
    {
      "product_id": 501,
      "price": "18.50",
      "quantity": 30,
      "unit": "米",
      "consume_detail_ids": [101, 102],
      "printing_job": 88
    }
  ],
  "remarks": "严进严出示例"
}
```

### 宽进宽出示例
```json
{
  "customer": 12,
  "warehouse": 5,
  "order_date": "2025-12-20",
  "items": [
    {
      "product_id": 501,
      "price": "15.00",
      "quantity": 90,
      "num_of_rolls": 3,
      "printing_job": 88
    }
  ]
}
```

## 关键行为说明

- 事务：主单与明细在同一 `transaction.atomic()` 中，任一失败整体回滚。
- 校验：
  - 仓库模式决定数量字段（`numbers` / `consume_detail_ids` / `quantity`）。
  - `printing_job` 可选；如提供需满足产品与客户一致性校验，否则返回 400。
- 明细创建：服务层使用 `bulk_create` 写入 `SalesOrderItem`。***
