1
0
forked from erp-dev/erp

feat: app verion && some field modify (printing & shipment)

This commit is contained in:
2026-07-08 20:36:51 +08:00
parent ddbf798665
commit 36e4bb6de6
32 changed files with 3465 additions and 26 deletions

View File

@@ -0,0 +1,224 @@
# API v1 Customer Address API
## Scope
客户地址 API 用于维护客户的一对多地址资料。地址归属 `basic_info.Customer`,并通过 `merchant` 做商户隔离。
所有接口需要登录。普通员工只能访问自己可见客户的地址;拥有 `basic_info.view_all_customers` 权限的员工可以访问本商户全部客户地址superuser 可以访问全部数据。
## Data Model
| Field | Type | Description |
| --- | --- | --- |
| `id` | integer | 客户地址 ID |
| `merchant` | integer | 所属商户 ID创建时由后端根据客户自动写入 |
| `merchant_name` | string | 所属商户名称,只读 |
| `customer` | integer | 客户 ID |
| `customer_name` | string | 客户名称,只读 |
| `address` | string | 地址 |
| `contact_name` | string | 联系人,可为空字符串 |
| `contact_phone` | string | 联系电话,可为空字符串 |
| `area` | string | 地区,可为空字符串 |
| `coordinates` | string/null | 经纬度字符串,格式由调用方决定 |
| `is_default` | boolean | 是否默认地址 |
| `remark` | string | 备注,可为空字符串 |
| `extra` | object/null | 扩展 JSON |
| `created_by` | integer/null | 创建员工 ID只读 |
| `created_by_name` | string/null | 创建员工姓名,只读 |
| `deleted_at` | datetime/null | 软删除时间,只读 |
| `deleted_by` | integer/null | 删除员工 ID只读 |
| `deleted_by_name` | string/null | 删除员工姓名,只读 |
| `created_at` | datetime | 创建时间,只读 |
| `updated_at` | datetime | 更新时间,只读 |
## Endpoints
| Method | Path | Description |
| --- | --- | --- |
| GET | `/api/v1/customer-addresses/` | 查询客户地址列表 |
| POST | `/api/v1/customer-addresses/` | 创建客户地址 |
| GET | `/api/v1/customer-addresses/{id}/` | 查询客户地址详情 |
| PUT | `/api/v1/customer-addresses/{id}/` | 完整更新客户地址 |
| PATCH | `/api/v1/customer-addresses/{id}/` | 部分更新客户地址 |
| DELETE | `/api/v1/customer-addresses/{id}/` | 软删除客户地址 |
| POST | `/api/v1/customer-address/{id}/set-default/` | 将客户地址设为默认地址 |
## Visibility Rules
普通员工可访问的客户地址必须同时满足:
- 地址所属商户等于当前员工商户。
- 地址所属客户对当前员工可见。
客户可见性规则:
- `customer.created_by == 当前员工`
- 或当前员工在 `customer.visible_employees` 中。
权限例外:
- `basic_info.view_all_customers`:可访问本商户全部客户地址。
- superuser可访问全部客户地址。
创建地址时,`customer` 也必须在当前用户可访问范围内。`merchant` 不由前端传入,后端使用客户所属商户自动写入。
## Query Parameters
`GET /api/v1/customer-addresses/` 支持以下查询参数:
| Parameter | Description |
| --- | --- |
| `customer` | 按客户 ID 精确过滤 |
| `customer_name` | 按客户名称模糊过滤 |
| `address` | 按地址模糊过滤 |
| `contact_name` | 按联系人模糊过滤 |
| `contact_phone` | 按联系电话模糊过滤 |
| `area` | 按地区模糊过滤 |
| `is_default` | 按默认地址过滤,支持 `true/false/1/0/yes/no` |
| `include_deleted` | 是否包含软删除记录,支持 `true/false/1/0/yes/no` |
| `only_deleted` | 是否只查询软删除记录,支持 `true/false/1/0/yes/no` |
| `search` | 对客户名称、地址、联系人、电话、地区、备注做模糊搜索 |
| `ordering` | 排序字段,支持 `id``created_at``updated_at``is_default` 及其 `-` 倒序形式 |
| `limit` | 分页数量 |
| `offset` | 分页偏移 |
默认行为:
- 不传 `include_deleted``only_deleted` 时,只返回未删除地址。
- `only_deleted=true` 优先于 `include_deleted=true`
## Create
`POST /api/v1/customer-addresses/`
Request body:
```json
{
"customer": 3,
"address": "杭州市测试路 1 号",
"contact_name": "张三",
"contact_phone": "13800138000",
"area": "杭州",
"coordinates": "120.1,30.2",
"is_default": true,
"remark": "默认收货地址",
"extra": {
"source": "manual"
}
}
```
Success response: HTTP 201
```json
{
"id": 10,
"merchant": 1,
"merchant_name": "测试印花厂",
"customer": 3,
"customer_name": "客户A",
"address": "杭州市测试路 1 号",
"contact_name": "张三",
"contact_phone": "13800138000",
"area": "杭州",
"coordinates": "120.1,30.2",
"is_default": true,
"remark": "默认收货地址",
"extra": {
"source": "manual"
},
"created_by": 5,
"created_by_name": "业务员A",
"deleted_at": null,
"deleted_by": null,
"deleted_by_name": null,
"created_at": "2026-07-07T12:00:00Z",
"updated_at": "2026-07-07T12:00:00Z"
}
```
## Update
`PATCH /api/v1/customer-addresses/{id}/`
Example:
```json
{
"address": "杭州市更新路 2 号",
"contact_phone": "13900139000",
"coordinates": null
}
```
Notes:
- 不允许修改 `customer`
- 不允许修改 `merchant`
- `created_by``deleted_at``deleted_by` 为只读字段。
## Default Address
同一客户最多一个未删除默认地址。
以下操作会自动取消同一客户其他未删除地址的默认状态:
- 创建地址时传 `is_default=true`
- 更新地址时传 `is_default=true`
- 调用 `set-default` 接口。
`POST /api/v1/customer-address/{id}/set-default/`
Success response: HTTP 200返回更新后的地址对象。
如果地址已经软删除,返回 HTTP 400。
## Soft Delete
`DELETE /api/v1/customer-addresses/{id}/`
删除是软删除,不会物理删除记录。后端会写入:
- `deleted_at`
- `deleted_by`
- `is_default=false`
Success response: HTTP 204。
查询软删除记录:
```http
GET /api/v1/customer-addresses/?include_deleted=true
GET /api/v1/customer-addresses/?only_deleted=true
```
## Error Cases
| Condition | Status | Notes |
| --- | --- | --- |
| 未登录 | 401 | 全部接口需要登录 |
| 查询不可见地址详情 | 404 | 不暴露不可见数据存在性 |
| 给不可见客户创建地址 | 400 | `customer` 字段校验失败 |
| 修改 `customer` | 400 | 不允许地址跨客户移动 |
| 已删除地址设为默认 | 400 | 通过 `set-default` 接口返回校验错误 |
## Test Coverage
Dedicated tests:
```bash
docker compose exec -T -e DB_HOST=postgres -e DB_PORT=5432 web uv run python manage.py test api_v1.test_customer_address_api --keepdb --noinput
```
Covered behavior:
- 商户隔离和客户可见性。
- `visible_employees` 授权后可见。
- `basic_info.view_all_customers` 可访问本商户全部客户地址。
- 创建地址时自动写入 `merchant``created_by`
- 不可见客户创建地址失败。
- 默认地址互斥。
- `set-default` 接口互斥设置默认地址。
- 软删除和 `include_deleted` / `only_deleted` 查询。
- 常用过滤参数。