forked from erp-dev/erp
feat: mes module
This commit is contained in:
@@ -11,99 +11,103 @@
|
||||
### 认证方式
|
||||
|
||||
```
|
||||
Authorization: <AGENT_ACCESS_KEY>
|
||||
# API v2 Agent 接口
|
||||
|
||||
本文档描述 `api/v2/ai/...` 下供内部 agent 调用的简化鉴权接口。
|
||||
|
||||
## 鉴权方式
|
||||
|
||||
- 使用请求头 `Authorization`
|
||||
- 直接传入固定密钥
|
||||
- 不使用 `Bearer` 前缀
|
||||
|
||||
示例:
|
||||
|
||||
```bash
|
||||
curl -X GET \
|
||||
'https://api.example.com/api/v2/ai/mes/devices/?merchant_id=1' \
|
||||
-H 'Authorization: your-agent-access-key'
|
||||
```
|
||||
|
||||
`AGENT_ACCESS_KEY` 由后端部署时通过同名环境变量配置。未配置时所有请求均返回 `401`。
|
||||
配置项:
|
||||
|
||||
- [`AGENT_ACCESS_KEY`](/home/f/coding/flower/flower/settings.py)
|
||||
|
||||
---
|
||||
|
||||
## 数据结构
|
||||
## 查询未进入送货单的出货单
|
||||
|
||||
### TransportVehicle
|
||||
- **URL**: `/api/v2/ai/shipments/unshipped/`
|
||||
- **Method**: `GET`
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"merchant_id": 10,
|
||||
"name": "大卡车",
|
||||
"license_plate": "粤A12345",
|
||||
"material_capacities": [
|
||||
{"id": 1, "material_name": "坯布", "capacity": 500},
|
||||
{"id": 2, "material_name": "成品", "capacity": 300}
|
||||
],
|
||||
"created_at": "2026-04-01T08:00:00+08:00",
|
||||
"updated_at": "2026-04-01T08:00:00+08:00"
|
||||
}
|
||||
```
|
||||
|
||||
### Shipment(出货单)
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 100,
|
||||
"merchant_id": 10,
|
||||
"customer": 5,
|
||||
"customer_name": "客户A",
|
||||
"fabric": "棉布 40S",
|
||||
"order_description": "滚筒预警",
|
||||
"shipment_date": "2026-04-14",
|
||||
"address": "广州市天河区",
|
||||
"contact_name": "张三",
|
||||
"contact_phone": "13800000000",
|
||||
"area": "华东",
|
||||
"remark": "备注",
|
||||
"status": "pending",
|
||||
"status_display": "待出货",
|
||||
"external_id": null,
|
||||
"geo_coordinates": {"lat": 23.1291, "lng": 113.2644},
|
||||
"delivery_id": null,
|
||||
"delivery": null,
|
||||
"sales_items": [
|
||||
{
|
||||
"id": 201,
|
||||
"name": "销售品甲",
|
||||
"quantity": "50.00",
|
||||
"unit": 1,
|
||||
"unit_display": "件",
|
||||
"position": "A-01",
|
||||
"remark": "",
|
||||
"printing_job_id": 88,
|
||||
"printing_job_width": "150cm"
|
||||
},
|
||||
{
|
||||
"id": 202,
|
||||
"name": "销售品乙",
|
||||
"quantity": "10.00",
|
||||
"unit": 1,
|
||||
"unit_display": "件",
|
||||
"position": "",
|
||||
"remark": "",
|
||||
"printing_job_id": null,
|
||||
"printing_job_width": null
|
||||
}
|
||||
],
|
||||
"created_at": "2026-04-14T10:00:00+08:00",
|
||||
"updated_at": "2026-04-14T10:00:00+08:00"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 运输车辆列表
|
||||
|
||||
- URL: `/api/v2/ai/transport-vehicles/`
|
||||
- Method: `GET`
|
||||
|
||||
查询参数:
|
||||
### 查询参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `merchant_id` | int | 是 | 商户 ID |
|
||||
| `limit` | int | 否 | 分页每页数量(默认由服务端决定) |
|
||||
| `offset` | int | 否 | 分页偏移量 |
|
||||
| `area` | string | 是 | 地区,精确匹配 |
|
||||
| `limit` | int | 否 | 分页大小 |
|
||||
| `offset` | int | 否 | 分页偏移 |
|
||||
|
||||
响应为分页结构,`results` 中每条为 `TransportVehicle`,包含该车辆的所有物料容量。
|
||||
### 错误响应
|
||||
|
||||
#### 401 Unauthorized
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "AGENT_ACCESS_KEY 无效"
|
||||
}
|
||||
```
|
||||
|
||||
#### 400 Bad Request
|
||||
|
||||
```json
|
||||
{
|
||||
"merchant_id": ["This field is required."]
|
||||
}
|
||||
```
|
||||
|
||||
## 查询 MES 设备列表
|
||||
|
||||
- **URL**: `/api/v2/ai/mes/devices/`
|
||||
- **Method**: `GET`
|
||||
|
||||
### 查询参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `merchant_id` | int | 是 | 商户 ID |
|
||||
| `limit` | int | 否 | 分页大小 |
|
||||
| `offset` | int | 否 | 分页偏移 |
|
||||
|
||||
### 说明
|
||||
|
||||
- 返回当前商户下全部 MES 设备
|
||||
- 每条记录包含所属设备分类信息
|
||||
- 使用与其他 agent 接口相同的固定密钥鉴权方式,不走 JWT
|
||||
|
||||
## 查询指定日期范围内的 MES 生产安排
|
||||
|
||||
- **URL**: `/api/v2/ai/mes/production-assignments/`
|
||||
- **Method**: `GET`
|
||||
|
||||
### 查询参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `merchant_id` | int | 是 | 商户 ID |
|
||||
| `start_date` | date | 是 | 开始日期,格式 `YYYY-MM-DD` |
|
||||
| `end_date` | date | 是 | 结束日期,格式 `YYYY-MM-DD` |
|
||||
| `device_id` | int | 否 | 设备 ID,可选筛选 |
|
||||
| `status` | int | 否 | 状态值,可选筛选 |
|
||||
| `limit` | int | 否 | 分页大小 |
|
||||
| `offset` | int | 否 | 分页偏移 |
|
||||
|
||||
### 当前实现说明
|
||||
|
||||
- 当前 MES 模型没有单独的排产日期字段
|
||||
- 所以本接口当前是按 `created_at` 的日期范围过滤生产安排
|
||||
- 也就是说,它查的是“这个时间范围内创建的生产安排”
|
||||
|
||||
说明:
|
||||
|
||||
|
||||
@@ -24,70 +24,266 @@ curl -X GET \
|
||||
|
||||
## 查询未进入送货单的出货单
|
||||
|
||||
- **URL**: `/api/v2/ai/shipments/unshipped/`
|
||||
- **Method**: `GET`
|
||||
# API v2 Agent 接口文档
|
||||
|
||||
### 查询参数
|
||||
本文档面向 AI Agent 及外部自动化调用方,描述 `/api/v2/ai/` 前缀下的所有接口。
|
||||
|
||||
## 基本约定
|
||||
|
||||
- Base URL: `/api/v2/ai`
|
||||
- 认证:所有接口使用固定 API Key,通过 `Authorization` 请求头直接传入,无 `Bearer` 前缀
|
||||
- 多商户隔离:每个接口均需传入 `merchant_id` 查询参数,后端以此确定数据范围
|
||||
|
||||
### 认证方式
|
||||
|
||||
```text
|
||||
Authorization: <AGENT_ACCESS_KEY>
|
||||
```
|
||||
|
||||
`AGENT_ACCESS_KEY` 由后端部署时通过同名环境变量配置。未配置时所有请求均返回 `401`。
|
||||
|
||||
---
|
||||
|
||||
## 数据结构
|
||||
|
||||
### TransportVehicle
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"merchant_id": 10,
|
||||
"name": "大卡车",
|
||||
"license_plate": "粤A12345",
|
||||
"material_capacities": [
|
||||
{"id": 1, "material_name": "坯布", "capacity": 500},
|
||||
{"id": 2, "material_name": "成品", "capacity": 300}
|
||||
],
|
||||
"created_at": "2026-04-01T08:00:00+08:00",
|
||||
"updated_at": "2026-04-01T08:00:00+08:00"
|
||||
}
|
||||
```
|
||||
|
||||
### Shipment
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 100,
|
||||
"merchant_id": 10,
|
||||
"customer": 5,
|
||||
"customer_name": "客户A",
|
||||
"fabric": "棉布 40S",
|
||||
"order_description": "滚筒预警",
|
||||
"shipment_date": "2026-04-14",
|
||||
"address": "广州市天河区",
|
||||
"contact_name": "张三",
|
||||
"contact_phone": "13800000000",
|
||||
"area": "华东",
|
||||
"remark": "备注",
|
||||
"status": "pending",
|
||||
"status_display": "待出货",
|
||||
"external_id": null,
|
||||
"geo_coordinates": {"lat": 23.1291, "lng": 113.2644},
|
||||
"delivery_id": null,
|
||||
"delivery": null,
|
||||
"sales_items": [
|
||||
{
|
||||
"id": 201,
|
||||
"name": "销售品甲",
|
||||
"quantity": "50.00",
|
||||
"unit": 1,
|
||||
"unit_display": "件",
|
||||
"position": "A-01",
|
||||
"remark": "",
|
||||
"printing_job_id": 88,
|
||||
"printing_job_width": "150cm"
|
||||
}
|
||||
],
|
||||
"created_at": "2026-04-14T10:00:00+08:00",
|
||||
"updated_at": "2026-04-14T10:00:00+08:00"
|
||||
}
|
||||
```
|
||||
|
||||
### MesDevice
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"merchant": 10,
|
||||
"category": {
|
||||
"id": 2,
|
||||
"merchant": 10,
|
||||
"name": "打印机",
|
||||
"created_at": "2026-05-01T08:00:00+08:00",
|
||||
"updated_at": "2026-05-01T08:00:00+08:00"
|
||||
},
|
||||
"name": "A-01",
|
||||
"peak_capacity": 120,
|
||||
"capacity_unit": 1,
|
||||
"capacity_unit_label": "米",
|
||||
"extra": {"capacity": {"per_hour": 120}},
|
||||
"created_at": "2026-05-01T08:00:00+08:00",
|
||||
"updated_at": "2026-05-01T08:00:00+08:00"
|
||||
}
|
||||
```
|
||||
|
||||
### MesProductionAssignment
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 100,
|
||||
"merchant": 10,
|
||||
"device": {
|
||||
"id": 1,
|
||||
"merchant": 10,
|
||||
"category": {
|
||||
"id": 2,
|
||||
"merchant": 10,
|
||||
"name": "打印机",
|
||||
"created_at": "2026-05-01T08:00:00+08:00",
|
||||
"updated_at": "2026-05-01T08:00:00+08:00"
|
||||
},
|
||||
"name": "A-01",
|
||||
"peak_capacity": 120,
|
||||
"capacity_unit": 1,
|
||||
"capacity_unit_label": "米",
|
||||
"extra": null,
|
||||
"created_at": "2026-05-01T08:00:00+08:00",
|
||||
"updated_at": "2026-05-01T08:00:00+08:00"
|
||||
},
|
||||
"content_type": 45,
|
||||
"object_id": 9001,
|
||||
"assigner": {"id": 20, "name": "张三", "merchant_id": 10},
|
||||
"assignee": {"id": 21, "name": "李四", "merchant_id": 10},
|
||||
"production_quantity": 300,
|
||||
"status": 2,
|
||||
"status_label": "已发布",
|
||||
"extra": {"batch": "A1"},
|
||||
"created_at": "2026-05-02T10:00:00+08:00",
|
||||
"updated_at": "2026-05-02T10:00:00+08:00"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 运输车辆列表
|
||||
|
||||
- URL: `/api/v2/ai/transport-vehicles/`
|
||||
- Method: `GET`
|
||||
|
||||
查询参数:
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `merchant_id` | int | 是 | 商户 ID |
|
||||
| `area` | string | 是 | 地区,精确匹配 |
|
||||
| `limit` | int | 否 | 分页大小 |
|
||||
| `offset` | int | 否 | 分页偏移 |
|
||||
| `limit` | int | 否 | 分页每页数量 |
|
||||
| `offset` | int | 否 | 分页偏移量 |
|
||||
|
||||
### 业务定义
|
||||
说明:
|
||||
|
||||
这里的“未出货”定义为:
|
||||
- `material_capacities` 表示该车辆对不同物料的最大装载量
|
||||
- 只返回 `merchant_id` 对应商户的车辆
|
||||
|
||||
- `Shipment.delivery_id is null`
|
||||
响应为分页结构,`results` 中每条为 `TransportVehicle`。
|
||||
|
||||
也就是该出货单尚未进入送货单。
|
||||
## 运输车辆详情
|
||||
|
||||
### 响应示例
|
||||
- URL: `/api/v2/ai/transport-vehicles/<license_plate>/`
|
||||
- Method: `GET`
|
||||
|
||||
```json
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 101,
|
||||
"merchant_id": 1,
|
||||
"customer": 12,
|
||||
"customer_name": "客户A",
|
||||
"shipment_date": "2026-04-14",
|
||||
"address": "",
|
||||
"contact_name": "张三",
|
||||
"contact_phone": "13800000000",
|
||||
"area": "华东",
|
||||
"remark": "目标记录",
|
||||
"status": 1,
|
||||
"status_display": "草稿(未发布)",
|
||||
"external_id": null,
|
||||
"delivery": null,
|
||||
"created_at": "2026-04-14T10:00:00Z",
|
||||
"updated_at": "2026-04-14T10:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
路径参数:
|
||||
|
||||
### 错误响应
|
||||
| 参数 | 说明 |
|
||||
|------|------|
|
||||
| `license_plate` | 车牌号码 |
|
||||
|
||||
#### 401 Unauthorized
|
||||
查询参数:
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "AGENT_ACCESS_KEY 无效"
|
||||
}
|
||||
```
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `merchant_id` | int | 是 | 商户 ID |
|
||||
|
||||
#### 400 Bad Request
|
||||
说明:
|
||||
|
||||
```json
|
||||
{
|
||||
"merchant_id": ["This field is required."]
|
||||
}
|
||||
```
|
||||
- 同一商户内 `license_plate` 唯一
|
||||
- 不同商户可能存在相同车牌号,`merchant_id` 是必须的
|
||||
- 车辆不存在时返回 `404`
|
||||
|
||||
## 未出货出货单列表
|
||||
|
||||
- URL: `/api/v2/ai/shipments/unshipped/`
|
||||
- Method: `GET`
|
||||
|
||||
查询参数:
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `merchant_id` | int | 是 | 商户 ID |
|
||||
| `area` | string | 是 | 地区筛选,精确匹配 |
|
||||
| `limit` | int | 否 | 分页每页数量 |
|
||||
| `offset` | int | 否 | 分页偏移量 |
|
||||
|
||||
说明:
|
||||
|
||||
- “未出货”定义:`delivery` 为空,即尚未关联送货单
|
||||
- `delivery_id` 未关联时返回 `null`
|
||||
- 结果按 `created_at` 降序排列
|
||||
- 只返回 `merchant_id` 对应商户的数据
|
||||
|
||||
响应为分页结构,`results` 中每条为 `Shipment`。
|
||||
|
||||
## MES 设备列表
|
||||
|
||||
- URL: `/api/v2/ai/mes/devices/`
|
||||
- Method: `GET`
|
||||
|
||||
查询参数:
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `merchant_id` | int | 是 | 商户 ID |
|
||||
| `limit` | int | 否 | 分页每页数量 |
|
||||
| `offset` | int | 否 | 分页偏移量 |
|
||||
|
||||
说明:
|
||||
|
||||
- 使用与其他 agent API 相同的 `AGENT_ACCESS_KEY` 鉴权,不走 JWT
|
||||
- 返回当前商户下全部 MES 设备
|
||||
- 每条设备记录都带完整的设备分类信息
|
||||
|
||||
响应为分页结构,`results` 中每条为 `MesDevice`。
|
||||
|
||||
## MES 生产安排列表
|
||||
|
||||
- URL: `/api/v2/ai/mes/production-assignments/`
|
||||
- Method: `GET`
|
||||
|
||||
查询参数:
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `merchant_id` | int | 是 | 商户 ID |
|
||||
| `start_date` | date | 是 | 开始日期,格式 `YYYY-MM-DD` |
|
||||
| `end_date` | date | 是 | 结束日期,格式 `YYYY-MM-DD` |
|
||||
| `device_id` | int | 否 | 设备 ID,可选筛选 |
|
||||
| `status` | int | 否 | 生产安排状态,可选筛选 |
|
||||
| `limit` | int | 否 | 分页每页数量 |
|
||||
| `offset` | int | 否 | 分页偏移量 |
|
||||
|
||||
说明:
|
||||
|
||||
- 当前模型没有单独的“计划生产日期”字段
|
||||
- 因此该接口当前按 `created_at` 所在日期做范围过滤
|
||||
- 也就是“查询指定日期范围内创建的生产安排”
|
||||
- `device_id` 和 `status` 都是可选筛选条件
|
||||
|
||||
状态值:
|
||||
|
||||
| 值 | 显示值 |
|
||||
|------|------|
|
||||
| `1` | `Draft` |
|
||||
| `2` | `已发布` |
|
||||
| `3` | `已接收` |
|
||||
| `4` | `已取消` |
|
||||
| `5` | `已完工` |
|
||||
|
||||
响应为分页结构,`results` 中每条为 `MesProductionAssignment`。
|
||||
|
||||
378
docs/api_v2_mes_api.md
Normal file
378
docs/api_v2_mes_api.md
Normal file
@@ -0,0 +1,378 @@
|
||||
# API v2 MES 模块接口文档
|
||||
|
||||
本文档面向前端和业务评审,描述当前已经开放的 `MES` 公开接口,以及每个接口当前真实可用的字段。
|
||||
|
||||
## 基本约定
|
||||
|
||||
- Base URL: `/api/v2/mes`
|
||||
- 认证:所有接口都需要登录。
|
||||
- 人员身份:后端使用 `request.user.employee` 作为当前员工身份。
|
||||
- 多商户隔离:所有接口只允许访问当前员工所属商户的数据。
|
||||
- 创建审计:`created_by` 由当前登录用户自动写入。
|
||||
- 操作审计:`operator` 由当前登录员工自动写入。
|
||||
- `extra`:自由结构 JSON 字段,后端不解释业务内容。
|
||||
|
||||
## 枚举定义
|
||||
|
||||
### 产能单位 `capacity_unit`
|
||||
|
||||
| 值 | 显示值 |
|
||||
|------|------|
|
||||
| `1` | `米` |
|
||||
| `2` | `码` |
|
||||
|
||||
### 生产指派状态 `status`
|
||||
|
||||
| 值 | 显示值 |
|
||||
|------|------|
|
||||
| `1` | `Draft` |
|
||||
| `2` | `已发布` |
|
||||
| `3` | `已接收` |
|
||||
| `4` | `已取消` |
|
||||
| `5` | `已完工` |
|
||||
|
||||
## 返回对象
|
||||
|
||||
### DeviceCategory 对象
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"merchant": 10,
|
||||
"name": "打印机",
|
||||
"created_by": {
|
||||
"id": 5,
|
||||
"username": "admin"
|
||||
},
|
||||
"operator": {
|
||||
"id": 20,
|
||||
"name": "张三",
|
||||
"merchant_id": 10
|
||||
},
|
||||
"created_at": "2026-05-08T12:00:00+08:00",
|
||||
"updated_at": "2026-05-08T12:00:00+08:00"
|
||||
}
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `id` | integer | 主键 |
|
||||
| `merchant` | integer | 所属商户 ID |
|
||||
| `name` | string | 设备分类名称 |
|
||||
| `created_by` | object | 创建用户信息,包含 `id`、`username` |
|
||||
| `operator` | object | 操作员工信息,包含 `id`、`name`、`merchant_id` |
|
||||
| `created_at` | datetime string | 创建时间 |
|
||||
| `updated_at` | datetime string | 更新时间 |
|
||||
|
||||
### Device 对象
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 100,
|
||||
"merchant": 10,
|
||||
"category": 1,
|
||||
"category_name": "打印机",
|
||||
"name": "A-01",
|
||||
"peak_capacity": 120,
|
||||
"capacity_unit": 1,
|
||||
"capacity_unit_label": "米",
|
||||
"extra": {
|
||||
"capacity": {
|
||||
"per_hour": 120
|
||||
}
|
||||
},
|
||||
"created_by": {
|
||||
"id": 5,
|
||||
"username": "admin"
|
||||
},
|
||||
"operator": {
|
||||
"id": 20,
|
||||
"name": "张三",
|
||||
"merchant_id": 10
|
||||
},
|
||||
"created_at": "2026-05-08T12:00:00+08:00",
|
||||
"updated_at": "2026-05-08T12:00:00+08:00"
|
||||
}
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `id` | integer | 主键 |
|
||||
| `merchant` | integer | 所属商户 ID |
|
||||
| `category` | integer | 设备分类 ID |
|
||||
| `category_name` | string | 设备分类名称 |
|
||||
| `name` | string | 设备名称 |
|
||||
| `peak_capacity` | integer | 峰值产能,必须大于 `0` |
|
||||
| `capacity_unit` | integer | 产能单位枚举值 |
|
||||
| `capacity_unit_label` | string | 产能单位显示值 |
|
||||
| `extra` | object/null | 自由结构 JSON 扩展字段 |
|
||||
| `created_by` | object | 创建用户信息,包含 `id`、`username` |
|
||||
| `operator` | object | 操作员工信息,包含 `id`、`name`、`merchant_id` |
|
||||
| `created_at` | datetime string | 创建时间 |
|
||||
| `updated_at` | datetime string | 更新时间 |
|
||||
|
||||
### ProductionAssignment 对象
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 200,
|
||||
"merchant": 10,
|
||||
"device": 100,
|
||||
"device_name": "A-01",
|
||||
"content_type": 45,
|
||||
"object_id": 9001,
|
||||
"assigner": {
|
||||
"id": 20,
|
||||
"name": "张三",
|
||||
"merchant_id": 10
|
||||
},
|
||||
"assignee": {
|
||||
"id": 21,
|
||||
"name": "李四",
|
||||
"merchant_id": 10
|
||||
},
|
||||
"production_quantity": 300,
|
||||
"status": 1,
|
||||
"status_label": "Draft",
|
||||
"extra": {
|
||||
"batch": "A1"
|
||||
},
|
||||
"created_by": {
|
||||
"id": 5,
|
||||
"username": "admin"
|
||||
},
|
||||
"operator": {
|
||||
"id": 20,
|
||||
"name": "张三",
|
||||
"merchant_id": 10
|
||||
},
|
||||
"created_at": "2026-05-08T12:00:00+08:00",
|
||||
"updated_at": "2026-05-08T12:00:00+08:00"
|
||||
}
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `id` | integer | 主键 |
|
||||
| `merchant` | integer | 所属商户 ID |
|
||||
| `device` | integer | 设备 ID |
|
||||
| `device_name` | string | 设备名称 |
|
||||
| `content_type` | integer | 关联业务对象类型 ID |
|
||||
| `object_id` | integer | 关联业务对象主键 |
|
||||
| `assigner` | object | 指派者员工信息,包含 `id`、`name`、`merchant_id` |
|
||||
| `assignee` | object/null | 被指派人员工信息,包含 `id`、`name`、`merchant_id`,可空 |
|
||||
| `production_quantity` | integer | 生产数量,必须大于 `0`,单位跟随设备 `capacity_unit` |
|
||||
| `status` | integer | 状态枚举值 |
|
||||
| `status_label` | string | 状态显示值 |
|
||||
| `extra` | object/null | 自由结构 JSON 扩展字段 |
|
||||
| `created_by` | object | 创建用户信息,包含 `id`、`username` |
|
||||
| `operator` | object | 操作员工信息,包含 `id`、`name`、`merchant_id` |
|
||||
| `created_at` | datetime string | 创建时间 |
|
||||
| `updated_at` | datetime string | 更新时间 |
|
||||
|
||||
## 设备分类接口
|
||||
|
||||
### 设备分类列表
|
||||
|
||||
- URL: `/api/v2/mes/device-categories/`
|
||||
- Method: `GET`
|
||||
|
||||
查询参数:
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `name` | string | 否 | 按名称模糊匹配 |
|
||||
|
||||
### 创建设备分类
|
||||
|
||||
- URL: `/api/v2/mes/device-categories/`
|
||||
- Method: `POST`
|
||||
|
||||
请求字段:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `name` | string | 是 | 设备分类名称 |
|
||||
|
||||
### 设备分类详情
|
||||
|
||||
- URL: `/api/v2/mes/device-categories/{category_id}/`
|
||||
- Method: `GET`
|
||||
|
||||
### 更新设备分类
|
||||
|
||||
- URL: `/api/v2/mes/device-categories/{category_id}/`
|
||||
- Method: `PATCH`
|
||||
|
||||
请求字段:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `name` | string | 否 | 设备分类名称 |
|
||||
|
||||
### 删除设备分类
|
||||
|
||||
- URL: `/api/v2/mes/device-categories/{category_id}/`
|
||||
- Method: `DELETE`
|
||||
|
||||
错误示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "设备分类已被设备引用,不能删除"
|
||||
}
|
||||
```
|
||||
|
||||
## 设备接口
|
||||
|
||||
### 设备列表
|
||||
|
||||
- URL: `/api/v2/mes/devices/`
|
||||
- Method: `GET`
|
||||
|
||||
查询参数:
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `name` | string | 否 | 按设备名称模糊匹配 |
|
||||
| `category` | integer | 否 | 按设备分类 ID 过滤 |
|
||||
| `extra_path` | string | 否 | `extra` 中的 JSON 路径,使用 `.` 分隔,例如 `capacity.per_hour` |
|
||||
| `extra_value` | string | 否 | 与 `extra_path` 配套使用,支持 JSON 字面量字符串,例如 `120`、`"A1"`、`true` |
|
||||
|
||||
说明:
|
||||
|
||||
- `extra_path` 和 `extra_value` 必须同时传入。
|
||||
- 当前仅支持精确匹配。
|
||||
- 后端不解释 `extra` 的业务语义,只按路径和值匹配。
|
||||
|
||||
### 创建设备
|
||||
|
||||
- URL: `/api/v2/mes/devices/`
|
||||
- Method: `POST`
|
||||
|
||||
请求字段:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `name` | string | 是 | 设备名称 |
|
||||
| `category` | integer | 是 | 设备分类 ID |
|
||||
| `peak_capacity` | integer | 是 | 峰值产能,必须大于 `0` |
|
||||
| `capacity_unit` | integer | 否 | 产能单位,省略时默认 `1=米` |
|
||||
| `extra` | object/null | 否 | 自由结构 JSON 扩展字段 |
|
||||
|
||||
### 设备详情
|
||||
|
||||
- URL: `/api/v2/mes/devices/{device_id}/`
|
||||
- Method: `GET`
|
||||
|
||||
### 更新设备
|
||||
|
||||
- URL: `/api/v2/mes/devices/{device_id}/`
|
||||
- Method: `PATCH`
|
||||
|
||||
请求字段:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `name` | string | 否 | 设备名称 |
|
||||
| `category` | integer | 否 | 设备分类 ID |
|
||||
| `peak_capacity` | integer | 否 | 峰值产能,必须大于 `0` |
|
||||
| `capacity_unit` | integer | 否 | 产能单位 |
|
||||
| `extra` | object/null | 否 | 传 `null` 可清空扩展字段 |
|
||||
|
||||
补充说明:
|
||||
|
||||
- 模型层历史迁移曾使用一次性兼容默认值处理旧数据,但前端不应依赖省略 `peak_capacity` 让系统自动补值。
|
||||
|
||||
### 删除设备
|
||||
|
||||
- URL: `/api/v2/mes/devices/{device_id}/`
|
||||
- Method: `DELETE`
|
||||
|
||||
- 成功返回 `204 No Content`
|
||||
|
||||
## 生产指派接口
|
||||
|
||||
### 生产指派列表
|
||||
|
||||
- URL: `/api/v2/mes/production-assignments/`
|
||||
- Method: `GET`
|
||||
|
||||
查询参数:
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `device` | integer | 否 | 按设备 ID 过滤 |
|
||||
| `content_type` | integer | 否 | 按关联对象类型 ID 过滤 |
|
||||
| `object_id` | integer | 否 | 按关联对象 ID 过滤 |
|
||||
| `status` | integer | 否 | 按状态过滤 |
|
||||
|
||||
### 创建生产指派
|
||||
|
||||
- URL: `/api/v2/mes/production-assignments/`
|
||||
- Method: `POST`
|
||||
|
||||
请求字段:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `device` | integer | 是 | 设备 ID |
|
||||
| `content_type` | integer | 是 | 关联业务对象类型 ID |
|
||||
| `object_id` | integer | 是 | 关联业务对象主键 |
|
||||
| `assigner` | integer | 是 | 指派者员工 ID |
|
||||
| `assignee` | integer/null | 否 | 被指派人员工 ID,可空 |
|
||||
| `production_quantity` | integer | 是 | 生产数量,必须大于 `0` |
|
||||
| `status` | integer | 否 | 状态,省略时默认 `1=Draft` |
|
||||
| `extra` | object/null | 否 | 自由结构 JSON 扩展字段 |
|
||||
|
||||
说明:
|
||||
|
||||
- `device`、`assigner`、`assignee` 必须属于当前商户。
|
||||
- `production_quantity` 单位跟随设备 `capacity_unit`。
|
||||
|
||||
### 生产指派详情
|
||||
|
||||
- URL: `/api/v2/mes/production-assignments/{assignment_id}/`
|
||||
- Method: `GET`
|
||||
|
||||
### 更新生产指派
|
||||
|
||||
- URL: `/api/v2/mes/production-assignments/{assignment_id}/`
|
||||
- Method: `PATCH`
|
||||
|
||||
请求字段:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `device` | integer | 否 | 设备 ID |
|
||||
| `assignee` | integer/null | 否 | 被指派人员工 ID,可空 |
|
||||
| `production_quantity` | integer | 否 | 生产数量,必须大于 `0` |
|
||||
| `status` | integer | 否 | 目标状态 |
|
||||
| `extra` | object/null | 否 | 扩展字段,传 `null` 可清空 |
|
||||
|
||||
状态流转说明:
|
||||
|
||||
- 主流程:`Draft -> 已发布 -> 已接收 -> 已完工`
|
||||
- `Draft` 可以改为 `已取消`
|
||||
- `已发布` 可以改为 `已取消`
|
||||
- `已接收` 和 `已完工` 不能改为 `已取消`
|
||||
- `已取消` 和 `已完工` 视为终态,不能回退
|
||||
|
||||
错误示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "当前状态不允许变更为目标状态"
|
||||
}
|
||||
```
|
||||
|
||||
### 删除生产指派
|
||||
|
||||
- URL: `/api/v2/mes/production-assignments/{assignment_id}/`
|
||||
- Method: `DELETE`
|
||||
185
docs/mes_module_structure.md
Normal file
185
docs/mes_module_structure.md
Normal file
@@ -0,0 +1,185 @@
|
||||
# MES 模块结构说明
|
||||
|
||||
本文档用于业务评审和联调前核对,描述当前 `MES` 模块已经落地的代码结构、数据对象、公开边界和暂未进入本轮范围的能力。
|
||||
|
||||
## 当前模块目标
|
||||
|
||||
当前 `MES` 模块的落点是两个基础能力:
|
||||
|
||||
- 设备分类管理
|
||||
- 设备管理
|
||||
- 生产指派管理
|
||||
|
||||
它们共同服务于后续更深入的排产、派工、产能统计,但当前阶段还没有实现复杂的汇总、排程算法和业务编排。
|
||||
|
||||
## 目录结构
|
||||
|
||||
当前 `mes` app 目录如下:
|
||||
|
||||
| 路径 | 说明 |
|
||||
|------|------|
|
||||
| `mes/apps.py` | Django app 注册入口 |
|
||||
| `mes/models.py` | MES 核心模型定义,包含枚举、设备分类、设备、生产指派 |
|
||||
| `mes/services.py` | 服务层,封装 CRUD、校验、状态流转和商户隔离规则 |
|
||||
| `mes/tests.py` | service 层测试 |
|
||||
| `mes/migrations/` | 数据库迁移文件 |
|
||||
|
||||
对外 API 入口位于:
|
||||
|
||||
| 路径 | 说明 |
|
||||
|------|------|
|
||||
| `api_v2/views/mes.py` | MES 对外 API 视图、序列化和请求参数解析 |
|
||||
| `api_v2/urls.py` | MES API 路由注册 |
|
||||
| `api_v2/test_mes_api.py` | API 层测试 |
|
||||
| `docs/api_v2_mes_api.md` | 当前公开 API 文档 |
|
||||
|
||||
## 数据对象
|
||||
|
||||
### 1. DeviceCategory
|
||||
|
||||
用途:设备分类,例如打印机、滚筒机等。
|
||||
|
||||
当前字段:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `id` | bigint | 主键 |
|
||||
| `merchant` | FK | 所属商户 |
|
||||
| `name` | string | 分类名称,同商户下唯一 |
|
||||
| `created_by` | FK | 创建用户 |
|
||||
| `operator` | FK | 当前操作员工 |
|
||||
| `created_at` | datetime | 创建时间 |
|
||||
| `updated_at` | datetime | 更新时间 |
|
||||
|
||||
当前规则:
|
||||
|
||||
- `operator` 必须属于当前商户。
|
||||
- `merchant + name` 唯一。
|
||||
|
||||
### 2. Device
|
||||
|
||||
用途:具体生产设备。
|
||||
|
||||
当前字段:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `id` | bigint | 主键 |
|
||||
| `merchant` | FK | 所属商户 |
|
||||
| `category` | FK | 设备分类 |
|
||||
| `name` | string | 设备名称,同商户下唯一 |
|
||||
| `peak_capacity` | integer | 峰值产能,必须大于 0 |
|
||||
| `capacity_unit` | integer enum | 产能单位,当前 `1=米`、`2=码` |
|
||||
| `extra` | json/null | 扩展参数,后端不解释内容 |
|
||||
| `created_by` | FK | 创建用户 |
|
||||
| `operator` | FK | 当前操作员工 |
|
||||
| `created_at` | datetime | 创建时间 |
|
||||
| `updated_at` | datetime | 更新时间 |
|
||||
|
||||
当前规则:
|
||||
|
||||
- `category` 必须属于当前商户。
|
||||
- `operator` 必须属于当前商户。
|
||||
- `peak_capacity > 0`。
|
||||
- 支持按 `extra` 指定 JSON 路径和值做精确筛选。
|
||||
|
||||
### 3. ProductionAssignment
|
||||
|
||||
用途:把某个业务对象指派到某台设备,并记录指派数量和状态。
|
||||
|
||||
当前字段:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `id` | bigint | 主键 |
|
||||
| `merchant` | FK | 所属商户 |
|
||||
| `device` | FK | 被指派设备 |
|
||||
| `content_type` | FK | 关联业务对象类型 |
|
||||
| `object_id` | bigint | 关联业务对象 ID |
|
||||
| `content_object` | GenericForeignKey | 运行时关联对象,不单独出现在 API 请求体中 |
|
||||
| `assigner` | FK | 指派者 |
|
||||
| `assignee` | FK/null | 被指派人,可空 |
|
||||
| `production_quantity` | integer | 生产数量,必须大于 0,单位跟随设备 `capacity_unit` |
|
||||
| `status` | integer enum | 状态,当前 `1=Draft`、`2=已发布`、`3=已接收`、`4=已取消`、`5=已完工` |
|
||||
| `extra` | json/null | 扩展参数,后端不解释内容 |
|
||||
| `created_by` | FK | 创建用户 |
|
||||
| `operator` | FK | 当前操作员工 |
|
||||
| `created_at` | datetime | 创建时间 |
|
||||
| `updated_at` | datetime | 更新时间 |
|
||||
|
||||
当前规则:
|
||||
|
||||
- `device`、`assigner`、`assignee`、`operator` 必须属于当前商户。
|
||||
- `content_type + object_id` 指向的对象必须存在。
|
||||
- 如果目标对象带 `merchant_id`,则必须与当前商户一致。
|
||||
- `production_quantity > 0`。
|
||||
|
||||
## 当前状态机
|
||||
|
||||
`ProductionAssignment.status` 当前是简单状态机:
|
||||
|
||||
| 状态值 | 显示值 | 含义 |
|
||||
|------|------|------|
|
||||
| `1` | `Draft` | 草稿 |
|
||||
| `2` | `已发布` | 已正式发出指派 |
|
||||
| `3` | `已接收` | 执行方已接收 |
|
||||
| `4` | `已取消` | 指派取消 |
|
||||
| `5` | `已完工` | 指派完成 |
|
||||
|
||||
当前允许流转:
|
||||
|
||||
- `Draft -> Draft / 已发布 / 已取消`
|
||||
- `已发布 -> 已发布 / 已接收 / 已取消`
|
||||
- `已接收 -> 已接收 / 已完工`
|
||||
- `已取消 -> 已取消`
|
||||
- `已完工 -> 已完工`
|
||||
|
||||
当前明确禁止:
|
||||
|
||||
- `已接收 -> 已取消`
|
||||
- `已完工 -> 已取消`
|
||||
- 任意终态回退到前置状态
|
||||
|
||||
## 服务层职责
|
||||
|
||||
`mes/services.py` 当前负责:
|
||||
|
||||
- 统一商户隔离校验
|
||||
- 统一名称、数量、状态值校验
|
||||
- 设备分类 CRUD
|
||||
- 设备 CRUD
|
||||
- 生产指派 CRUD
|
||||
- 生产指派状态流转校验
|
||||
- 设备 `extra` JSON 路径筛选
|
||||
|
||||
这意味着当前 API 层主要是参数适配和错误转译,核心业务校验已经集中到 service 层。
|
||||
|
||||
## 当前公开 API 边界
|
||||
|
||||
当前已经公开到 `api_v2` 的接口包括:
|
||||
|
||||
- 设备分类:列表、创建、详情、更新、删除
|
||||
- 设备:列表、创建、详情、更新、删除
|
||||
- 生产指派:列表、创建、详情、更新、删除
|
||||
|
||||
当前 API 文档见:`docs/api_v2_mes_api.md`
|
||||
|
||||
## 当前未进入本轮范围的能力
|
||||
|
||||
以下能力尚未在本轮实现,业务评审时需要明确它们仍属于后续扩展:
|
||||
|
||||
- 设备产能利用率汇总
|
||||
- 指派数量聚合统计
|
||||
- 更复杂的排产/排队/冲突检测
|
||||
- 基于业务对象类型的定制校验规则
|
||||
- 更细粒度的状态副作用,例如发布后自动通知、接收后自动开工等
|
||||
|
||||
## 评审建议
|
||||
|
||||
如果你要先去业务部门开会和做实验,建议重点确认这几件事:
|
||||
|
||||
- `production_quantity` 的业务口径是否始终跟随设备 `capacity_unit`
|
||||
- `ProductionAssignment` 的五个状态是否够用
|
||||
- `assignee` 是否允许为空,以及在哪个环节允许为空
|
||||
- `extra` 里是否会出现需要前端按路径筛选的高频字段
|
||||
- `content_type + object_id` 是否符合业务上“一个指派对应一个目标对象”的表达方式
|
||||
Reference in New Issue
Block a user