1
0
forked from erp-dev/erp
Files
erpnew/docs/cost/api.md
2026-07-01 11:51:13 +08:00

400 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# API v2 成本模块接口文档
本文档面向前端,描述 `cost` 成本模块的 API。
## 2026-06-30 前端变更摘要
本次支出明细接口兼容新增“倍数型支出”字段。支出类目接口无变化,按类目汇总接口的响应结构无变化,但汇总金额仍来自 `amount`
**新增字段(支出明细列表、详情、创建、修改均涉及):**
| 字段 | 类型 | 位置 | 说明 |
|------|------|------|------|
| `unit_amount` | decimal string / null | request + response | 单价 / 基数金额,如临时工日薪。响应中为字符串,如 `"200.0000"` |
| `quantity` | decimal string / null | request + response | 数量 / 倍数,如 `"3.0000"` |
| `unit_name` | string | request + response | 单位名称,如 `人天``小时``件`,可为空字符串 |
**兼容规则:**
- 普通支出:继续传 `amount`,不传 `unit_amount``quantity` 即可。
- 倍数型支出:传 `unit_amount + quantity``amount` 可不传;后端保存时计算 `amount = unit_amount * quantity`
- 如果同时传 `amount``unit_amount + quantity`,后端以公式计算结果为准,返回的 `amount` 是计算后的最终金额。
- `unit_amount``quantity` 必须同时填写或同时为 `null`/不传;只传一个会返回 `400`
- 将倍数型支出改回普通支出时PUT 需要同时传:`amount``unit_amount: null``quantity: null``unit_name` 可传空字符串。
---
## 基本约定
- Base URL: `/api/v2`
- 认证所有接口都需要登录JWT
- 人员身份:后端使用 `request.user.employee` 作为当前员工身份。
- 多商户隔离:所有类目、支出明细只允许访问当前员工所属商户的数据;可通过 `?merchant_id=` 参数跨商户查询(如果权限允许)。
- 时间格式:请求参数中的日期使用 `YYYY-MM-DD`(如 `2026-06-01`),响应中的日期时间使用 ISO 8601。
---
## 1. 支出类目
### 1.1 类目列表
```
GET /api/v2/cost-categories/
```
查询参数:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `merchant_id` | int | 否 | 按商户筛选,不传则使用当前员工的商户 |
成功响应 `200`
```json
[
{
"id": 1,
"merchant_id": 1,
"unique_key": "electricity",
"name": "电费",
"parent_id": null,
"description": "每月电费支出",
"created_at": "2026-06-06T10:00:00Z",
"updated_at": "2026-06-06T10:00:00Z"
}
]
```
### 1.2 创建类目
```
POST /api/v2/cost-categories/
```
请求体JSON
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `unique_key` | string | **是** | 唯一标识键,同商户不可重复,如 `electricity` |
| `name` | string | **是** | 类目名称 |
| `parent_id` | int | 否 | 父类目 ID用于层级 |
| `description` | string | 否 | 描述 |
请求示例:
```json
{
"unique_key": "electricity",
"name": "电费",
"description": "每月电费支出"
}
```
成功响应 `201`
```json
{
"id": 1,
"merchant_id": 1,
"unique_key": "electricity",
"name": "电费",
"parent_id": null,
"description": "每月电费支出",
"created_at": "2026-06-06T10:00:00Z",
"updated_at": "2026-06-06T10:00:00Z"
}
```
错误响应 `400`:缺少必填字段时返回校验错误。
### 1.3 类目详情
```
GET /api/v2/cost-categories/{category_id}/
```
成功响应 `200`:返回单个类目对象,结构同上。
错误响应 `404`:类目不存在或不属于当前商户。
### 1.4 修改类目
```
PUT /api/v2/cost-categories/{category_id}/
```
请求体JSON所有字段可选
| 字段 | 类型 | 说明 |
|------|------|------|
| `unique_key` | string | 唯一标识键 |
| `name` | string | 类目名称 |
| `parent_id` | int | 父类目 ID`null` 清除 |
| `description` | string | 描述 |
成功响应 `200`:返回更新后的类目对象。
### 1.5 删除类目
```
DELETE /api/v2/cost-categories/{category_id}/
```
成功响应 `204`(无响应体)。
错误响应 `404`:类目不存在或不属于当前商户。
---
## 2. 支出明细
### 2.1 支出明细列表
```
GET /api/v2/cost-entries/
```
查询参数:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `merchant_id` | int | 否 | 按商户筛选 |
| `category_id` | int | 否 | 按支出类目筛选 |
| `start` | date | 否 | 发生日期起始,格式 `YYYY-MM-DD` |
| `end` | date | 否 | 发生日期截止,格式 `YYYY-MM-DD` |
默认按 `occurred_at` 降序排列。
成功响应 `200`
```json
[
{
"id": 1,
"merchant_id": 1,
"category_id": 1,
"category_name": "电费",
"amount": "350.00",
"unit_amount": null,
"quantity": null,
"unit_name": "",
"occurred_at": "2026-06-01",
"operator_id": 12,
"image1": "",
"image2": "",
"source_module": "",
"source_id": "",
"remarks": "六月份电费",
"created_at": "2026-06-06T10:00:00Z",
"updated_at": "2026-06-06T10:00:00Z"
}
]
```
字段说明:
| 字段 | 类型 | 说明 |
|------|------|------|
| `amount` | string | 最终支出金额 / 统计金额Decimal 转字符串,前端展示时注意格式化) |
| `unit_amount` | string/null | 单价 / 基数金额;普通支出为 `null` |
| `quantity` | string/null | 数量 / 倍数;普通支出为 `null` |
| `unit_name` | string | 单位名称;普通支出为空字符串 |
| `occurred_at` | string | 发生日期,`YYYY-MM-DD` |
| `operator_id` | int | 经办人 ID自动从当前登录用户获取 |
| `image1` | string | 凭证图片 URL七牛云 CDN无则为空字符串 |
| `image2` | string | 备用凭证图片 URL无则为空字符串 |
| `source_module` | string | 来源模块名,手工录入时为空 |
| `source_id` | string | 来源记录 ID手工录入时为空 |
### 2.2 创建支出明细
```
POST /api/v2/cost-entries/
```
Content-Type: `multipart/form-data`(支持图片上传)或 `application/json`
请求体:
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `category_id` | int | **是** | 支出类目 ID |
| `amount` | decimal | 条件必填 | 普通支出必填;倍数型支出可不传。最终统计金额,如 `"350.00"` |
| `unit_amount` | decimal | 否 | **新增**。单价 / 基数金额;和 `quantity` 必须同时填写或同时为空 |
| `quantity` | decimal | 否 | **新增**。数量 / 倍数;和 `unit_amount` 必须同时填写或同时为空 |
| `unit_name` | string | 否 | **新增**。单位名称,如 `人天``小时``件` |
| `occurred_at` | date | **是** | 发生日期,`YYYY-MM-DD` |
| `image1` | file | 否 | 凭证图片 |
| `image2` | file | 否 | 备用凭证图片 |
| `source_module` | string | 否 | 来源模块名 |
| `source_id` | string | 否 | 来源记录 ID |
| `remarks` | string | 否 | 备注 |
请求示例JSON普通支出
```json
{
"category_id": 1,
"amount": "350.00",
"occurred_at": "2026-06-01",
"remarks": "六月份电费"
}
```
请求示例JSON**新增:倍数型支出**
```json
{
"category_id": 2,
"unit_amount": "200.00",
"quantity": "3",
"unit_name": "人天",
"occurred_at": "2026-06-01",
"remarks": "临时工 3 人天"
}
```
倍数型支出成功响应中的 `amount` 会是后端计算后的最终金额,例如 `"600.00"`
成功响应 `201`:返回创建的支出明细对象。
错误响应 `400`:校验失败。
错误响应 `404``category_id` 不存在或不属于当前商户。
### 2.3 支出明细详情
```
GET /api/v2/cost-entries/{entry_id}/
```
成功响应 `200`:返回单个支出明细对象,含 `category_name`
错误响应 `404`:明细不存在或不属于当前商户。
### 2.4 修改支出明细
```
PUT /api/v2/cost-entries/{entry_id}/
```
Content-Type: `multipart/form-data``application/json`
请求体(所有字段可选):
| 字段 | 类型 | 说明 |
|------|------|------|
| `category_id` | int | 切换类目 |
| `amount` | decimal/null | 普通支出金额;倍数型支出若公式字段存在,会被后端公式结果覆盖 |
| `unit_amount` | decimal/null | **新增**。单价 / 基数金额;传 `null` 可清除公式字段 |
| `quantity` | decimal/null | **新增**。数量 / 倍数;传 `null` 可清除公式字段 |
| `unit_name` | string | **新增**。单位名称;可传空字符串清空 |
| `occurred_at` | date | 发生日期 |
| `image1` | file | 凭证图片 |
| `image2` | file | 备用凭证图片 |
| `source_module` | string | 来源模块名 |
| `source_id` | string | 来源记录 ID |
| `remarks` | string | 备注 |
成功响应 `200`:返回更新后的支出明细对象。
修改倍数型支出数量示例:
```json
{
"quantity": "4"
}
```
后端会按已有 `unit_amount * quantity` 重算并返回新的 `amount`
将倍数型支出改回普通支出示例:
```json
{
"amount": "550.00",
"unit_amount": null,
"quantity": null,
"unit_name": ""
}
```
### 2.5 删除支出明细
```
DELETE /api/v2/cost-entries/{entry_id}/
```
成功响应 `204`
错误响应 `404`:明细不存在或不属于当前商户。
---
## 3. 按类目汇总
```
GET /api/v2/cost-summary/by-category/
```
查询参数:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `merchant_id` | int | 否 | 按商户筛选 |
| `start` | date | 否 | 发生日期起始 |
| `end` | date | 否 | 发生日期截止 |
`total_amount` 降序排列。
成功响应 `200`
```json
{
"merchant_id": 1,
"start_date": "2026-06-01",
"end_date": "2026-06-30",
"results": [
{
"category_id": 1,
"category_name": "电费",
"category_key": "electricity",
"total_amount": "500.00",
"entry_count": 2
},
{
"category_id": 2,
"category_name": "水费",
"category_key": "water",
"total_amount": "80.00",
"entry_count": 1
}
]
}
```
字段说明:
| 字段 | 类型 | 说明 |
|------|------|------|
| `total_amount` | string | 该类别在查询时间段内的总金额 |
| `entry_count` | integer | 该类别在查询时间段内的记录数 |
| `category_key` | string | 类目唯一键,可用于前端做图表的 key 映射 |
---
## 快速参考
| Method | URL | 说明 |
|--------|-----|------|
| GET | `/api/v2/cost-categories/` | 类目列表 |
| POST | `/api/v2/cost-categories/` | 创建类目 |
| GET | `/api/v2/cost-categories/{id}/` | 类目详情 |
| PUT | `/api/v2/cost-categories/{id}/` | 修改类目 |
| DELETE | `/api/v2/cost-categories/{id}/` | 删除类目 |
| GET | `/api/v2/cost-entries/` | 支出明细列表 |
| POST | `/api/v2/cost-entries/` | 创建支出明细 |
| GET | `/api/v2/cost-entries/{id}/` | 支出明细详情 |
| PUT | `/api/v2/cost-entries/{id}/` | 修改支出明细 |
| DELETE | `/api/v2/cost-entries/{id}/` | 删除支出明细 |
| GET | `/api/v2/cost-summary/by-category/` | 按类目汇总 |