# 业务域 API 文档（Purchase & Sales）

所有接口均位于 `/api/v1/` 前缀下，要求用户已登录且具备员工身份。除特殊说明外，返回值为 JSON，错误时返回 `{"error": "...", ...}`。

## 通用约定
- **分页**：列表接口使用 `limit` / `offset`（默认 `limit=20`，最大 `100`）。
- **items 结构**：与仓库模式相关  
  - 严进/严进严出仓库：`numbers: [int, ...]`  
  - 宽进宽出仓库：`quantity: number` + `num_of_rolls: int`
- **状态枚举**：`PENDING=1`、`APPROVED=2`、`CANCELLED=3`。

---

## 1. 采购单（PurchaseOrder）

### 1.1 列表
- **GET** `/api/v1/purchase-orders/`
- **查询参数**：`limit`、`offset`
- **返回**：`{"count": int, "next": url|null, "previous": url|null, "results": [PurchaseOrder]}`  
  每个 `PurchaseOrder` 记录包含 `supplier_name / operator_name / warehouse_name / total_amount / total_quantity / items[...]` 等字段。

### 1.2 创建
- **POST** `/api/v1/purchase-orders/`
- **请求体**

| 字段 | 类型 | 说明 |
|------|------|------|
| `supplier` | int | 供应商 ID（必填） |
| `warehouse` | int | 仓库 ID，或使用 `warehouse_id`（必填） |
| `order_date` | str (`YYYY-MM-DD`) | 采购日期 |
| `items` | list | 产品明细（至少 1 条） |
| `remarks` | str | 备注，可选 |

明细字段：

| 仓库模式 | 必填字段 |
|----------|----------|
| 严进/严进严出 | `product_id`, `numbers` (list[int]), `price`, `unit` |
| 宽进宽出 | `product_id`, `quantity`, `num_of_rolls`, `price`, `unit` |

- **成功返回**：`201` + `{"id": int, "status": 1, "message": "采购单创建成功，等待审批"}`。

### 1.3 审批 / 作废
- **POST** `/api/v1/purchase-orders/<id>/review/`
- **请求体**：`{"action": "approve" | "cancel"}`
- **返回**：最新的 `PurchaseOrder` 序列化结果。  
  - `approve`：当商户开启自动入库时，会异步创建入库任务。  
  - `cancel`：若已生成入库记录，返回 `400`。

---

## 2. 销售单（SalesOrder）

接口与采购单保持一致，仅字段差异：
- 关联主体：`customer`（客户 ID）
- 日期字段：`order_date` 映射到 `sales_date`
- 审批通过后触发**出库**任务，库存方向为 “出库/负数”。

### 2.1 列表
- **GET** `/api/v1/sales-orders/`
- **返回**：同采购列表，但字段为 `customer_name` 等。

### 2.2 创建
- **POST** `/api/v1/sales-orders/`
- **请求体**：

| 字段 | 类型 | 说明 |
|------|------|------|
| `customer` | int | 客户 ID |
| `warehouse` | int | 仓库 ID（或 `warehouse_id`） |
| `order_date` | str | 销售日期 |
| `items` | list | 产品明细，与采购单格式一致 |
| `remarks` | str | 可选 |

`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` |

- **成功返回**：`201` + `{"id": int, "status": 1, "message": "销售单创建成功，等待审批"}`。

### 2.3 审批 / 作废
- **POST** `/api/v1/sales-orders/<id>/review/`
- **请求体**：`{"action": "approve" | "cancel"}`
- **返回**：`SalesOrder` 序列化数据。  
  - `approve`：若开启自动出库，则投递 `create_sales_order_stock_entries`。  
  - `cancel`：若已生成出库记录（`StockChangeRecord`），返回 `400`。

---

## 3. 响应字段说明（节选）

| 字段 | 说明 |
|------|------|
| `total_amount` | 明细金额合计（未带方向） |
| `diff_quantity` | 空差数量合计 |
| `total_quantity` | 原始数量合计 |
| `items[].quantity_of_rolls` | 严进模式下的各条数明细（字符串，以逗号分隔） |
| `items[].num_of_rolls` | 条数 |
| `status` | 1=审批中、2=通过、3=作废 |

---

## 4. 付款单（PaymentOrder）

### 4.1 列表
- **GET** `/api/v1/payment-orders/`
- 返回字段：`supplier_name`、`payment_date`、`amount`、`status`、`is_external_source`、`external_source_id` 等。

### 4.2 创建
- **POST** `/api/v1/payment-orders/`

| 字段 | 类型 | 说明 |
|------|------|------|
| `supplier` | int | 供应商 ID |
| `payment_date` | str (`YYYY-MM-DD`) | 付款日期 |
| `amount` | decimal | 付款金额（必须 > 0） |
| `remarks` | str | 可选 |

列表/详情响应补充字段：

- `is_external_source`：是否来源于外部系统同步。
- `external_source_id`：外部系统记录 ID，用于关联与审计。

### 4.3 审批 / 作废
- **POST** `/api/v1/payment-orders/<id>/review/`
- `{"action": "approve"}` 或 `{"action": "cancel"}`

---

## 5. 收款单（ReceiptOrder）

接口与付款单类似，只是主体为 `customer`：

- **GET** `/api/v1/receipt-orders/`
- **POST** `/api/v1/receipt-orders/`：需要 `customer`、`receipt_date`、`amount`
- **POST** `/api/v1/receipt-orders/<id>/review/`

审批通过表示“确认收款”，作废则恢复为初始状态。

列表/详情响应同样包含：

- `is_external_source`
- `external_source_id`

---

## 6. 错误示例

| 场景 | HTTP | 返回体 |
|------|------|--------|
| 未登录 | 401 | `{"detail": "Authentication credentials were not provided."}` |
| 缺少必填字段 | 400 | `{"error": "缺少供应商 ID"}` 等 |
| 无权限访问他商户单据 | 403 | `{"error": "无权限访问"}` |
| 单据不存在 | 404 | `{"error": "采购单不存在"}` / `{"error": "销售单不存在"}` |
| 已有库存记录仍尝试作废 | 400 | `{"error": "采购单已生成出入库记录，无法作废"}`（销售单同理） |

---

## 7. 客户欠款查询

- **GET** `/api/v1/customers/<id>/balance/`
- **描述**：返回指定客户当前的应收余额（审批通过的销售单金额累加减去收款单金额），数据来源于余额表，因此查询为 O(1)。
- **响应**：`{"customer": 12, "customer_name": "张三", "balance": "1234.50"}`
  - `balance` 为字符串格式的十进制数，正数表示客户欠款，应收；负数表示已收超额。

如需对 `items` 结构、仓库模式、审批流程或红冲 API 做深入了解，请参阅：
- `docs/2026-06-12_business_red_flush_api.md`
- `docs/2026-06-12_business_red_flush_design.md`
- `docs/purchase_order_approval_and_red_flush.md`
- `docs/sales_order_approval_and_red_flush.md`

