# SalesItem 修改与删除 API 文档

本文档说明 `SalesItem` 销售品的修改、重建与软删除接口。

## 修改接口

### 接口信息

- URL: `/api/v1/shipment/sales-items/{id}/`
- Method: `PATCH`
- 认证: 需要登录（JWT Token）

说明：

- 该接口仅允许修改部分非关系字段
- 当前允许修改的字段只有：
  - `quantity`
  - `remark`
  - `position`
- 不允许修改 `name`、`unit`、`shipment`、`customer_id`、`printing_job_id` 等字段
- 成功修改后会自动写入 `SalesItemChangeRecord`

### 请求体示例

```json
{
  "quantity": "120.50",
  "remark": "补充备注",
  "position": "A3-02"
}
```

### 成功响应示例

```json
{
  "id": 15,
  "name": "测试销售品",
  "quantity": "120.50",
  "unit": 1,
  "unit_display": "米",
  "position": "A3-02",
  "remark": "补充备注",
  "printing_job_id": 123,
  "printing_order_id": 45,
  "external_order_id": "EXT-2026-001",
  "customer_id": 8,
  "customer_name": "客户A",
  "shipment_id": null,
  "shipment_date": null,
  "created_at": "2026-04-06T10:00:00+08:00",
  "created_by_id": 3,
  "created_by_name": "测试员工",
  "product_image_url": null
}
```

### 修改审计记录

每次成功修改时，会新增一条 `SalesItemChangeRecord`，记录：

- `sales_item`
- `operator`
- `operated_at`
- `before_values`
- `after_values`

### 错误响应示例

#### 1. 传入了不允许修改的字段

```json
{
  "detail": "销售品仅允许修改以下字段: position, quantity, remark；不支持字段: customer_id, name"
}
```

#### 2. 数量格式非法

```json
{
  "detail": "数量 abc 格式无效: [具体异常信息]"
}
```

#### 3. 对象不存在或无权访问

```json
{
  "detail": "Not found."
}
```

## 重建接口

### 接口信息

- URL: `/api/v1/shipment/sales-items/{id}/rebuild/`
- Method: `POST`
- 认证: 需要登录（JWT Token）

说明：

- 该接口本质上等同于“软删除旧销售品 + 基于新的 `printing_job` 重建一个新销售品”
- 只有旧销售品的 `created_by` 本人才能执行这个操作
- 新销售品会保留旧销售品的 `created_by`
- 旧销售品若已关联出货单，则不允许重建

### 请求体

```json
{
  "new_printing_job_id": 456,
  "quantity": "66.50"
}
```

字段说明：

- `new_printing_job_id`: 必填，新的生产任务 ID
- `quantity`: 可选，新的数量；未传时沿用旧销售品数量

### 成功响应示例

```json
{
  "detail": "销售品已重建",
  "old_sales_item_id": 15,
  "new_sales_item_id": 18,
  "rebuild_record_id": 3,
  "data": {
    "id": 18,
    "name": "测试销售品",
    "quantity": "66.50",
    "unit": 1,
    "unit_display": "米",
    "position": "A3-02",
    "remark": "补充备注",
    "printing_job_id": 456,
    "printing_order_id": 80,
    "external_order_id": "EXT-2026-010",
    "customer_id": 8,
    "customer_name": "客户A",
    "shipment_id": null,
    "shipment_date": null,
    "created_at": "2026-04-06T16:00:00+08:00",
    "created_by_id": 3,
    "created_by_name": "测试员工",
    "product_image_url": null
  }
}
```

### 重建审计记录

每次成功重建时，会新增一条 `SalesItemRebuildRecord`，记录：

- `old_sales_item`
- `new_sales_item`
- `operator`
- `rebuilt_at`
- `old_printing_job_id`
- `new_printing_job_id`
- `old_quantity`
- `new_quantity`

### 错误响应示例

#### 1. 不是原创建者

```json
{
  "detail": "只有销售品创建者才能执行重建"
}
```

#### 2. 旧销售品已关联出货单

```json
{
  "detail": "已关联出货单的销售品不允许删除"
}
```

#### 3. 新生产任务无效

```json
{
  "detail": "生产任务 999 不存在或不属于当前商户"
}
```

## 删除接口

### 接口信息

- URL: `/api/v1/shipment/sales-items/{id}/`
- Method: `DELETE`
- 认证: 需要登录（JWT Token）

说明：

- 该接口为软删除，不会物理删除数据库记录
- 删除后销售品会从常规查询接口中隐藏
- 删除操作需要独立 Django 权限：`shipment.soft_delete_salesitem`

### 软删除字段

`SalesItem` 通过以下字段记录删除信息：

- `delete_at`: 删除时间
- `delete_by`: 删除人

### 权限要求

调用方需要具备：

- `shipment.soft_delete_salesitem`

无该权限时返回 `403 Forbidden`。

### 请求示例

```http
DELETE /api/v1/shipment/sales-items/15/
Authorization: Bearer <token>
```

### 成功响应

```json
{
  "detail": "销售品已标记为删除"
}
```

### 行为说明

- 软删除后，`SalesItem` 不再出现在以下常规接口结果中：
  - 销售品详情
  - 按客户查询销售品
  - 按生产订单查询销售品
  - 未出货销售品客户反查
  - 出货单详情 / 列表中的嵌套销售品
- 重复删除当前实现保持幂等；由于对象在常规查询中已隐藏，后续再次调用通常会得到 `404`

### 错误响应示例

#### 1. 无权限

```json
{
  "detail": "没有权限删除销售品"
}
```

#### 2. 对象不存在或无权访问

```json
{
  "detail": "Not found."
}
```
