forked from erp-dev/erp
feat: salesitem can change/soft delete
This commit is contained in:
@@ -40,6 +40,7 @@
|
||||
| `KhID` | 外部客户 ID | `PrintingOrder.external_customer_id` | 原样保存 |
|
||||
| `customer.KhName` | 外部客户名 | `PrintingOrder.external_customer_name` | 原样保存 |
|
||||
| `HpName` | 布料名 | `PrintingOrder.fabric` | 原样保存到订单面料字段 |
|
||||
| `area` | 地区/区域 | `PrintingOrder.area` | 原样保存;取不到时回退为空字符串 `""` |
|
||||
| `CaoZY` | 外部操作员/业务员 | `PrintingOrder.created_by` / `PrintingOrder.external_employee_name` | 若能匹配到内部员工且员工绑定了系统用户,则 `created_by` 取该用户,`external_employee_name` 置空;否则 `created_by` 取固定同步用户,`external_employee_name` 保留原文 |
|
||||
| `SHDZ` | 布料来源 + 工艺 | `PrintingOrder.fabric_source` / `PrintingOrder.craft` | 以空白字符 split;第 1 段为 `fabric_source`,剩余重新拼接为 `craft` |
|
||||
| `SeHao` | 幅宽 | `PrintingOrder.width` | 原样保存 |
|
||||
@@ -52,6 +53,7 @@
|
||||
补充说明:
|
||||
|
||||
- 外部 `HpName` 已作为布料名使用,直接写入 `PrintingOrder.fabric`
|
||||
- 外部 `area` 直接写入 `PrintingOrder.area`;若外部未返回或为空,则统一写入空字符串
|
||||
- `BianHaoKD`、`RiQi` 等当前未单独属性化的字段,保留在 `external_raw` 中
|
||||
- `BianHaoKD` 当前样例值类似 `"1.27"`,不按日期强解析
|
||||
|
||||
|
||||
164
docs/sales_item_delete_api.md
Normal file
164
docs/sales_item_delete_api.md
Normal file
@@ -0,0 +1,164 @@
|
||||
# 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}/`
|
||||
- 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."
|
||||
}
|
||||
```
|
||||
@@ -5,6 +5,8 @@
|
||||
## 目录
|
||||
|
||||
- [查询出货单](#查询出货单)
|
||||
- [出货单状态流转接口](./shipment_status_api.md)
|
||||
- [销售品删除接口](./sales_item_delete_api.md)
|
||||
- [创建出货单](#创建出货单)
|
||||
- [查询有待出货销售品的客户](#查询有待出货销售品的客户)
|
||||
- [按客户查询销售品](#按客户查询销售品)
|
||||
|
||||
132
docs/shipment_status_api.md
Normal file
132
docs/shipment_status_api.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# Shipment Status API 文档
|
||||
|
||||
本文档仅说明 `Shipment` 出货单状态流转接口。
|
||||
|
||||
## 接口信息
|
||||
|
||||
- URL: `/api/v1/shipment/shipments/{id}/status/`
|
||||
- Method: `PATCH` / `PUT`
|
||||
- 认证: 需要登录(JWT Token)
|
||||
|
||||
说明:
|
||||
|
||||
- 该接口只负责修改 `Shipment.status`
|
||||
- 业务字段修改仍然使用 `/api/v1/shipment/shipments/{id}/`
|
||||
- `PATCH` 与 `PUT` 当前行为一致,都是按请求体中的 `status` 执行状态流转
|
||||
|
||||
## 请求体
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 2
|
||||
}
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
- `status`: 目标状态
|
||||
- `1 = 草稿(未发布)`
|
||||
- `2 = 已发布`
|
||||
- `3 = 已取消`
|
||||
- `4 = 已驳回`
|
||||
- `5 = 已审核`
|
||||
|
||||
## 状态机规则
|
||||
|
||||
- `草稿(未发布)` 只能流转到 `已发布`
|
||||
- `已发布` 可以流转到 `已审核` / `已驳回` / `已取消`
|
||||
- `已驳回` 可以流转到 `已审核` / `已取消`
|
||||
- `已审核` 可以流转到 `已取消`
|
||||
- `已取消` 不可再流转
|
||||
- 重复设置同一状态时保持幂等
|
||||
|
||||
附加规则:
|
||||
|
||||
- 进入 `已审核` 时,接口会自动将当前 `request.user` 写入 `approved_by`
|
||||
- 进入 `已取消` 时,接口会自动将当前 `request.user` 写入 `cancelled_by`
|
||||
- 每次成功状态流转都会更新 `status_modified_at`
|
||||
|
||||
## 请求示例
|
||||
|
||||
### 1. 草稿发布
|
||||
|
||||
```http
|
||||
PATCH /api/v1/shipment/shipments/12/status/
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"status": 2
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 已发布审核
|
||||
|
||||
```http
|
||||
PUT /api/v1/shipment/shipments/12/status/
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"status": 5
|
||||
}
|
||||
```
|
||||
|
||||
## 成功响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 12,
|
||||
"merchant_id": 1,
|
||||
"merchant_name": "测试印花厂",
|
||||
"customer": 8,
|
||||
"customer_name": "客户A",
|
||||
"shipment_date": "2026-04-06",
|
||||
"address": "",
|
||||
"contact_name": "",
|
||||
"contact_phone": "",
|
||||
"area": "",
|
||||
"remark": "",
|
||||
"status": 5,
|
||||
"status_display": "已审核",
|
||||
"external_id": null,
|
||||
"status_modified_at": "2026-04-06T14:30:00+08:00",
|
||||
"cancelled_by_id": null,
|
||||
"cancelled_by_name": null,
|
||||
"approved_by_id": 3,
|
||||
"approved_by_name": "测试员工",
|
||||
"items_count": 2,
|
||||
"sales_items": [],
|
||||
"external_finished_products": [],
|
||||
"created_by_id": 3,
|
||||
"created_by_name": "测试员工",
|
||||
"created_at": "2026-04-06T10:00:00+08:00",
|
||||
"updated_at": "2026-04-06T14:30:00+08:00"
|
||||
}
|
||||
```
|
||||
|
||||
## 错误响应示例
|
||||
|
||||
### 1. 非法流转
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "不允许将出货单状态从 草稿(未发布) 修改为 已审核"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 越权或对象不存在
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "Not found."
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 请求体不合法
|
||||
|
||||
```json
|
||||
{
|
||||
"status": [
|
||||
"\"99\" is not a valid choice."
|
||||
]
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user