forked from erp-dev/erp
1121 lines
24 KiB
Markdown
1121 lines
24 KiB
Markdown
# API Documentation
|
||
|
||
Base URL:
|
||
|
||
```text
|
||
http://<host>:<port>
|
||
```
|
||
|
||
Response content type:
|
||
|
||
```text
|
||
application/json; charset=utf-8
|
||
```
|
||
|
||
## Authorization
|
||
|
||
所有 API 都要求固定的 `Authorization` 请求头。
|
||
|
||
配置文件:
|
||
|
||
```yaml
|
||
auth:
|
||
secret: "your-fixed-authorization-secret"
|
||
```
|
||
|
||
请求示例:
|
||
|
||
```http
|
||
Authorization: your-fixed-authorization-secret
|
||
```
|
||
|
||
说明:
|
||
|
||
- 服务端会把 `Authorization` 头的原始值与 `auth.secret` 做精确匹配
|
||
- 如果你想使用 `Bearer xxx` 风格,也可以直接把 `auth.secret` 配成完整的 `Bearer xxx`
|
||
|
||
未授权响应:
|
||
|
||
```json
|
||
{
|
||
"error": "unauthorized"
|
||
}
|
||
```
|
||
|
||
## Logging
|
||
|
||
服务端会输出两级日志:
|
||
|
||
- `WARNING`
|
||
- `ERROR`
|
||
|
||
当前会重点记录:
|
||
|
||
- 未授权访问
|
||
- 参数错误
|
||
- 数据库相关失败
|
||
- 图片查找失败
|
||
|
||
当图片不存在时,日志里会带上尝试过的完整路径,便于排查 Windows 部署目录问题。
|
||
|
||
## 1. Health Check
|
||
|
||
`GET /healthz`
|
||
|
||
用途:
|
||
|
||
- 检查 API 进程是否存活
|
||
- 检查数据库连接是否可用
|
||
|
||
成功响应:
|
||
|
||
```json
|
||
{
|
||
"ok": true
|
||
}
|
||
```
|
||
|
||
## 2. Query Records
|
||
|
||
`GET /api/v1/records`
|
||
|
||
### 2.1 增量同步模式
|
||
|
||
不传 `id_start` / `id_end` 时,接口按当前游标做增量读取:
|
||
|
||
- 条件:`ID > cursor`
|
||
- 排序:`ORDER BY ID ASC`
|
||
- 默认 `limit=100`
|
||
- 默认 `update_cursor=true`
|
||
- 如果查到数据且 `update_cursor=true`,游标推进到本次结果最后一条记录的 `ID`
|
||
- 返回结果会自动补上主表里的 `KhID`,并额外附带客户表 `dbo.B_Khzl` 的客户信息
|
||
- 返回结果会根据客户表 `KHLbID` 自动关联地区表 `dbo.B_Khlb`,并平铺返回 `area`
|
||
- 返回结果也会根据订单表 `HpID` 自动关联布料表 `dbo.B_Hpzl`,并平铺返回 `HpName`
|
||
|
||
参数:
|
||
|
||
- `update_cursor`: 可选,布尔值,默认 `true`
|
||
- `limit`: 可选,正整数,默认 `100`
|
||
|
||
示例:
|
||
|
||
```http
|
||
GET /api/v1/records
|
||
Authorization: your-fixed-authorization-secret
|
||
```
|
||
|
||
```http
|
||
GET /api/v1/records?update_cursor=false&limit=20
|
||
Authorization: your-fixed-authorization-secret
|
||
```
|
||
|
||
成功响应示例:
|
||
|
||
```json
|
||
{
|
||
"mode": "incremental",
|
||
"cursor_before": 1200,
|
||
"cursor_after": 1250,
|
||
"origin_cursor": 1000,
|
||
"last_record_id": 1250,
|
||
"updated": true,
|
||
"count": 50,
|
||
"records": [
|
||
{
|
||
"ID": 1201,
|
||
"KhID": 88,
|
||
"BianHaoID": "...",
|
||
"area": "华东地区",
|
||
"HpName": "某某布料",
|
||
"customer": {
|
||
"KhID": 88,
|
||
"KhName": "某某客户"
|
||
}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
字段说明:
|
||
|
||
- `mode`: 固定为 `incremental`
|
||
- `cursor_before`: 本次请求开始前的游标
|
||
- `cursor_after`: 本次请求完成后的游标。如果 `update_cursor=false`,这里会返回本次结果最后一条记录的 ID,但不会实际写入状态文件
|
||
- `origin_cursor`: 最近一次手工修改游标前的值;自动增量同步不会改它
|
||
- `last_record_id`: 本次返回结果中的最后一条记录 ID;无数据时不存在
|
||
- `updated`: 本次是否实际更新了游标状态
|
||
- `count`: 返回记录数
|
||
- `records[].KhID`: 主表记录中的客户 ID
|
||
- `records[].customer`: 客户表补充信息,当前默认包含 `KhID` 和 `KhName`
|
||
- `records[].area`: 客户地区,来自 `dbo.B_Khlb` 的 `MingCheng`
|
||
- `records[].HpName`: 布料表 `dbo.B_Hpzl` 中关联到的布料名称
|
||
|
||
### 2.2 范围查询模式
|
||
|
||
传了 `id_start` 和 `id_end` 时,接口进入范围查询模式:
|
||
|
||
- 条件:`ID >= id_start AND ID <= id_end`
|
||
- 排序:`ORDER BY ID ASC`
|
||
- 不会更新游标
|
||
- 必须显式传 `update_cursor=false`
|
||
|
||
参数:
|
||
|
||
- `id_start`: 必填,非负整数
|
||
- `id_end`: 必填,非负整数
|
||
- `update_cursor`: 必填,且必须为 `false`
|
||
- `limit`: 可选,正整数,默认 `100`
|
||
|
||
示例:
|
||
|
||
```http
|
||
GET /api/v1/records?id_start=2000&id_end=2100&update_cursor=false
|
||
Authorization: your-fixed-authorization-secret
|
||
```
|
||
|
||
成功响应示例:
|
||
|
||
```json
|
||
{
|
||
"mode": "range",
|
||
"cursor_before": 1250,
|
||
"cursor_after": 1250,
|
||
"origin_cursor": 1000,
|
||
"last_record_id": 2050,
|
||
"updated": false,
|
||
"count": 51,
|
||
"id_start": 2000,
|
||
"id_end": 2100,
|
||
"records": [
|
||
{
|
||
"ID": 2000,
|
||
"BianHaoID": "..."
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 2.3 参数校验规则
|
||
|
||
- `limit` 必须大于 0
|
||
- `id_start` 和 `id_end` 必须同时出现
|
||
- `id_start` 和 `id_end` 必须是非负整数
|
||
- `id_start` 不能大于 `id_end`
|
||
- 范围查询模式必须显式传 `update_cursor=false`
|
||
|
||
## 3. Query Current Order Snapshot
|
||
|
||
`GET /api/v1/records/by-order`
|
||
|
||
用途:
|
||
|
||
- 按 `external_order_id` 精确查询当前整单快照
|
||
- 返回该 `BianHaoID` 下当前全部 records
|
||
- 不读取 cursor,也不推进 cursor
|
||
- 返回字段会继续附带现有的 `customer`、`area`、`HpName`
|
||
|
||
参数:
|
||
|
||
- `external_order_id`: 必填,字符串,精确对应主表 `D_KhDhd.BianHaoID`
|
||
|
||
示例:
|
||
|
||
```http
|
||
GET /api/v1/records/by-order?external_order_id=KD20432358
|
||
Authorization: your-fixed-authorization-secret
|
||
```
|
||
|
||
成功响应示例:
|
||
|
||
```json
|
||
{
|
||
"mode": "snapshot",
|
||
"external_order_id": "KD20432358",
|
||
"status": "active",
|
||
"snapshot_at": "2026-04-16T10:12:34Z",
|
||
"total_count": 3,
|
||
"records": [
|
||
{
|
||
"ID": 1000001,
|
||
"BianHaoID": "KD20432358",
|
||
"KhID": "KH00999",
|
||
"HpName": "120克本白四面弹单定",
|
||
"area": "周边",
|
||
"customer": {
|
||
"KhID": "KH00999",
|
||
"KhName": "鸿烨服饰"
|
||
}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
字段说明:
|
||
|
||
- `mode`: 固定为 `snapshot`
|
||
- `external_order_id`: 当前查询的订单号
|
||
- `status`: 当前快照状态;查询命中时固定为 `active`
|
||
- `snapshot_at`: 服务端生成本次快照响应的时间
|
||
- `total_count`: 当前订单快照下 records 数量
|
||
- `records`: 当前订单下的全部 records,字段宽度与现有 `GET /api/v1/records` 保持一致
|
||
|
||
未命中响应示例:
|
||
|
||
```json
|
||
{
|
||
"external_order_id": "KD20432358",
|
||
"status": "not_found",
|
||
"message": "未找到该 external_order_id 对应的订单"
|
||
}
|
||
```
|
||
|
||
## 4. Query Customer Orders
|
||
|
||
`GET /api/v1/records/by-customer`
|
||
|
||
用途:
|
||
|
||
- 按客户名精确查询该客户名下全部订单
|
||
- 底层先查询 `D_KhDhd` 明细,再按 `BianHaoID` 聚合为订单主体
|
||
- 每个订单主体下的明细结构与现有 `GET /api/v1/records/by-order` 完全一致
|
||
- 不读取 cursor,也不推进 cursor
|
||
- 结果按配置项 `customer_orders.sort_column` 倒序排列,默认 `KdRiQi`
|
||
|
||
参数:
|
||
|
||
- `customer_name_b64`: 必填,客户名的 Base64URL 编码;精确匹配客户表 `dbo.B_Khzl.KhName`
|
||
|
||
示例:
|
||
|
||
```http
|
||
GET /api/v1/records/by-customer?customer_name_b64=6bi_54OI5pyN6aWw
|
||
Authorization: your-fixed-authorization-secret
|
||
```
|
||
|
||
成功响应示例:
|
||
|
||
```json
|
||
{
|
||
"mode": "customer_orders",
|
||
"customer_name": "鸿烨服饰",
|
||
"status": "active",
|
||
"snapshot_at": "2026-05-09T10:12:34Z",
|
||
"total_orders": 2,
|
||
"orders": [
|
||
{
|
||
"mode": "snapshot",
|
||
"external_order_id": "KD20432358",
|
||
"status": "active",
|
||
"snapshot_at": "2026-05-09T10:12:34Z",
|
||
"total_count": 2,
|
||
"records": [
|
||
{
|
||
"ID": 1000001,
|
||
"BianHaoID": "KD20432358",
|
||
"KhID": "KH00999",
|
||
"HpName": "120克本白四面弹单定",
|
||
"area": "周边",
|
||
"customer": {
|
||
"KhID": "KH00999",
|
||
"KhName": "鸿烨服饰"
|
||
}
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
字段说明:
|
||
|
||
- `mode`: 固定为 `customer_orders`
|
||
- `customer_name`: 当前查询的客户名
|
||
- `status`: 查询命中时固定为 `active`
|
||
- `snapshot_at`: 服务端生成本次响应的时间
|
||
- `total_orders`: 当前客户名下聚合后的订单数
|
||
- `orders`: 订单列表;每个订单元素的结构与 `GET /api/v1/records/by-order` 返回结构保持一致
|
||
|
||
未命中响应示例:
|
||
|
||
```json
|
||
{
|
||
"customer_name": "鸿烨服饰",
|
||
"status": "not_found",
|
||
"message": "未找到该 customer_name 对应的订单"
|
||
}
|
||
```
|
||
|
||
配置:
|
||
|
||
```yaml
|
||
customer_orders:
|
||
sort_column: "KdRiQi"
|
||
```
|
||
|
||
- `sort_column` 用于控制订单聚合结果的排序字段,默认值为 `KdRiQi`
|
||
|
||
## 5. Query Customer List
|
||
|
||
`GET /api/v1/customers`
|
||
|
||
用途:
|
||
|
||
- 按客户主档表 `dbo.B_Khzl` 拉取客户列表
|
||
- 每次固定返回 `10` 个客户
|
||
- 只返回 `KhID` 和 `KhName`
|
||
- 用于外部系统按客户维度做同步
|
||
- 使用游标参数 `cursor_id` 续拉,不使用 `page` / `pageSize`
|
||
|
||
排序与游标规则:
|
||
|
||
- 底层按 `ZZRQ ASC, KhID ASC` 排序
|
||
- `ZZRQ` 越早的客户越先返回,避免从新到旧翻页时遗漏新数据
|
||
- `cursor_id` 传上一页最后一条客户的 `KhID`
|
||
- 服务端会先查出该 `KhID` 对应的 `ZZRQ`,再从 `(ZZRQ, KhID)` 这个排序位置之后继续取下一批 `10` 条
|
||
- 如果多个客户 `ZZRQ` 相同,会继续用 `KhID` 做稳定次序
|
||
|
||
参数:
|
||
|
||
- `cursor_id`: 可选,上一页最后一条客户的 `KhID`
|
||
|
||
示例:
|
||
|
||
```http
|
||
GET /api/v1/customers
|
||
Authorization: your-fixed-authorization-secret
|
||
```
|
||
|
||
```http
|
||
GET /api/v1/customers?cursor_id=KH01485
|
||
Authorization: your-fixed-authorization-secret
|
||
```
|
||
|
||
成功响应示例:
|
||
|
||
```json
|
||
{
|
||
"mode": "customers",
|
||
"cursor_id": "KH01485",
|
||
"next_cursor_id": "KH01495",
|
||
"snapshot_at": "2026-05-14T15:00:00Z",
|
||
"count": 10,
|
||
"customers": [
|
||
{
|
||
"customer_id": "KH01486",
|
||
"customer_name": "A亿佳服饰"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
字段说明:
|
||
|
||
- `mode`: 固定为 `customers`
|
||
- `cursor_id`: 本次请求使用的游标;首批为空
|
||
- `next_cursor_id`: 本页最后一条客户的 `KhID`;下一页继续传它即可
|
||
- `snapshot_at`: 服务端生成本次响应的时间
|
||
- `count`: 当前返回客户数,最大固定为 `10`
|
||
- `customers[].customer_id`: 客户 ID,对应 `dbo.B_Khzl.KhID`
|
||
- `customers[].customer_name`: 客户名称,对应 `dbo.B_Khzl.KhName`
|
||
|
||
未命中游标响应示例:
|
||
|
||
```json
|
||
{
|
||
"cursor_id": "KH99999",
|
||
"status": "not_found",
|
||
"message": "未找到该 cursor_id 对应的客户"
|
||
}
|
||
```
|
||
|
||
## 6. Query I_Sale Records By BianHaoID
|
||
|
||
`GET /api/v1/i-sale/by-bianhao`
|
||
|
||
用途:
|
||
|
||
- 按 `BianHaoID` 查询 `dbo.I_Sale` 中的业务明细记录
|
||
- 为收款和退款记录补充对应业务单据的信息
|
||
- 返回 `I_Sale` 的全量字段
|
||
- 不读取 cursor,也不推进 cursor
|
||
|
||
注意:
|
||
|
||
- 同一个 `BianHaoID` 在 `I_Sale` 中可能命中多条明细行
|
||
- 因此该接口返回的是 `records[]`,不是单对象详情
|
||
|
||
参数:
|
||
|
||
- `bianhao_id`: 必填,精确匹配 `dbo.I_Sale.BianHaoID`
|
||
|
||
示例:
|
||
|
||
```http
|
||
GET /api/v1/i-sale/by-bianhao?bianhao_id=XT20203911
|
||
Authorization: your-fixed-authorization-secret
|
||
```
|
||
|
||
成功响应示例:
|
||
|
||
```json
|
||
{
|
||
"mode": "i_sale_records",
|
||
"bianhao_id": "XT20203911",
|
||
"status": "active",
|
||
"snapshot_at": "2026-05-14T15:10:00Z",
|
||
"total_count": 1,
|
||
"records": [
|
||
{
|
||
"BianHaoID": "XT20203911",
|
||
"DanType": "客户退货单",
|
||
"KhID": "KH01204"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
字段说明:
|
||
|
||
- `mode`: 固定为 `i_sale_records`
|
||
- `bianhao_id`: 当前查询的业务单号
|
||
- `status`: 查询命中时固定为 `active`
|
||
- `snapshot_at`: 服务端生成本次响应的时间
|
||
- `total_count`: 当前 `BianHaoID` 命中的 `I_Sale` 明细行数
|
||
- `records`: `I_Sale` 全量字段明细列表
|
||
|
||
未命中响应示例:
|
||
|
||
```json
|
||
{
|
||
"bianhao_id": "XT404",
|
||
"status": "not_found",
|
||
"message": "未找到该 bianhao_id 对应的 I_Sale 记录"
|
||
}
|
||
```
|
||
|
||
## 7. Query I_Sale Records By Customer
|
||
|
||
`GET /api/v1/i-sale/by-customer`
|
||
|
||
用途:
|
||
|
||
- 按客户 ID 查询 `dbo.I_Sale` 中的业务明细记录
|
||
- 用于补足按客户统计时对 `I_Sale` 的直接拉取能力
|
||
- 不分页、不使用游标;一次返回当前客户在指定分类下的全部命中记录
|
||
- 返回字段不是 `I_Sale` 全 119 列,而是“核心标识 + 全部金额字段 + 全部数量字段 + 备注字段”
|
||
|
||
当前分类策略:
|
||
|
||
- `sale`:只取 `DanType = '成品销售单' AND BianHaoID LIKE 'XS%'`
|
||
- `sale_return`:只取 `DanType = '客户退货单' AND BianHaoID LIKE 'XT%'`
|
||
|
||
当前实现决策:
|
||
|
||
- 用户明确接受低频调用,因此本接口不做分页和游标
|
||
- 但为了避免把 `I_Sale` 全 119 列直接暴露给同步方,当前只返回与统计/业务核对最相关的字段组
|
||
- 该字段组已结合项目内 `I_SALE_FIELD_ANALYSIS.md` 与线上 `db/columns` 验证
|
||
|
||
参数:
|
||
|
||
- `customer_id`: 必填,精确匹配 `dbo.I_Sale.KhID`
|
||
- `category`: 必填,当前只支持 `sale`、`sale_return`
|
||
|
||
示例:
|
||
|
||
```http
|
||
GET /api/v1/i-sale/by-customer?customer_id=KH00308&category=sale
|
||
Authorization: your-fixed-authorization-secret
|
||
```
|
||
|
||
```http
|
||
GET /api/v1/i-sale/by-customer?customer_id=KH00308&category=sale_return
|
||
Authorization: your-fixed-authorization-secret
|
||
```
|
||
|
||
成功响应示例:
|
||
|
||
```json
|
||
{
|
||
"mode": "i_sale_customer_records",
|
||
"customer_id": "KH00308",
|
||
"category": "sale",
|
||
"status": "active",
|
||
"snapshot_at": "2026-05-14T20:00:00Z",
|
||
"total_count": 2,
|
||
"records": [
|
||
{
|
||
"SubID": 1,
|
||
"BianHaoID": "XS20367431",
|
||
"DanType": "成品销售单",
|
||
"KhID": "KH00308",
|
||
"RiQi": "2026-05-14T00:00:00Z",
|
||
"KdRiQi": "2026-05-14T19:08:23Z",
|
||
"JieSunFS": "欠款",
|
||
"HpID": "HP00001",
|
||
"JianShu": "1.00",
|
||
"ShuLiang": "20.00",
|
||
"ShuLiangT": "20.00",
|
||
"DanJia": "32.000000",
|
||
"JinE": "640.000000",
|
||
"DingJin": "0.00",
|
||
"YfJinE": "0.00",
|
||
"SfJinE": "0.00",
|
||
"ZkJinE": "0.00",
|
||
"LjQK": "0.00",
|
||
"BeiZhu": "",
|
||
"BeiZhuC": "",
|
||
"BeiZhuD": "",
|
||
"MeoD": "普通单据"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
字段说明:
|
||
|
||
- `mode`: 固定为 `i_sale_customer_records`
|
||
- `customer_id`: 当前查询的客户 ID
|
||
- `category`: 当前查询的分类
|
||
- `status`: 查询命中时固定为 `active`
|
||
- `snapshot_at`: 服务端生成本次响应的时间
|
||
- `total_count`: 当前客户在该分类下命中的 `I_Sale` 明细行数
|
||
- `records`: 当前字段集包含以下几类字段
|
||
|
||
核心标识字段:
|
||
|
||
- `SubID`
|
||
- `BianHaoID`
|
||
- `DanType`
|
||
- `KhID`
|
||
- `RiQi`
|
||
- `KdRiQi`
|
||
- `JieSunFS`
|
||
- `HpID`
|
||
- `JiJiaDW`
|
||
|
||
数量相关字段:
|
||
|
||
- `JianShu`
|
||
- `ShuLiang`
|
||
- `ShuLiangZ`
|
||
- `ShuLiangK`
|
||
- `ShuLiangS`
|
||
- `JianShuT`
|
||
- `ShuLiangT`
|
||
- `ShuLiangZT`
|
||
- `ShuLiangKT`
|
||
- `ShuLiangST`
|
||
- `Sl1` ~ `Sl10`
|
||
|
||
金额相关字段:
|
||
|
||
- `DingJin`
|
||
- `YfJinE`
|
||
- `SfJinE`
|
||
- `ZkJinE`
|
||
- `LjQK`
|
||
- `DanJia`
|
||
- `JinE`
|
||
- `DanJiaT`
|
||
- `JinET`
|
||
- `DanJiaCB`
|
||
- `JinECB`
|
||
- `JinE_SL`
|
||
|
||
备注相关字段:
|
||
|
||
- `BeiZhu`
|
||
- `BeiZhuC`
|
||
- `BeiZhuD`
|
||
- `MeoA`
|
||
- `MeoB`
|
||
- `MeoC`
|
||
- `MeoD`
|
||
|
||
未命中响应示例:
|
||
|
||
```json
|
||
{
|
||
"customer_id": "KH00308",
|
||
"category": "sale",
|
||
"status": "not_found",
|
||
"message": "未找到该 customer_id 和 category 对应的 I_Sale 记录"
|
||
}
|
||
```
|
||
|
||
参数错误:
|
||
|
||
- `customer_id` 为空时返回 `400`
|
||
- `category` 非 `sale` / `sale_return` 时返回 `400`
|
||
|
||
## 7. Query Customer Finance Records
|
||
|
||
`GET /api/v1/finance/by-customer`
|
||
|
||
用途:
|
||
|
||
- 按客户名精确查询该客户名下的财务记录
|
||
- 当前销售/销退只认 `dbo.I_Sale`
|
||
- 当前收款/退款只认 `dbo.F_Skd`
|
||
- 支持按记录类型筛选,并支持控制是否包含真实资金变动、是否包含挂账/欠款调整
|
||
- 不读取 cursor,也不推进 cursor
|
||
|
||
参数:
|
||
|
||
- `customer_name_b64`: 必填,客户名的 Base64URL 编码;精确匹配客户表 `dbo.B_Khzl.KhName`
|
||
- `record_types`: 可选,逗号分隔;支持 `sale`、`sale_return`、`receipt`、`refund`;不传默认全部
|
||
- `include_cash_movement`: 可选,布尔值;默认 `true`
|
||
- `include_adjustments`: 可选,布尔值;默认 `false`
|
||
- `filter_sk`: 可选,布尔值;默认 `false`;当前 `receipt` 口径下保留该参数但不生效
|
||
|
||
当前口径:
|
||
|
||
- `sale`: `I_Sale.DanType = '成品销售单'`
|
||
- `sale_return`: `I_Sale.DanType = '客户退货单'`
|
||
- `receipt`: 仅纳入 `F_Skd.BianHaoID LIKE 'SK%'` 的收款流水,不纳入 `XS%` 记录
|
||
- `refund`: `F_Skd.sType = 1 AND F_Skd.BianHaoID LIKE 'XT%'`
|
||
- `receipt` 的返回金额字段仍保留 `F_Skd.FkJinE`、`F_Skd.ZkJinE` 等原始值,但当前口径不再使用 `FkJinE` 作为筛选条件
|
||
- `refund` 的统计和筛选金额字段为 `F_Skd.YfJinE`
|
||
- `include_cash_movement` 与 `include_adjustments` 当前仅影响 `refund`;`receipt` 统一按 `SK%` 全量统计
|
||
- `include_cash_movement=true` 时,`refund` 取 `YfJinE < 0`
|
||
- `include_adjustments=true` 时,`refund` 额外包含 `YfJinE = 0` 的挂账/欠款调整记录
|
||
|
||
当前已验证的 `sType` 规则:
|
||
|
||
- `sType = 1`:当前财务 API 使用的业务单据关联流水,样本中覆盖 `XS...` 与 `XT...`
|
||
- `sType = 0`:当前样本对应 `SK...` 型独立收款流水;当前 `receipt` 查询会纳入它,`refund` 不会
|
||
|
||
示例:
|
||
|
||
```http
|
||
GET /api/v1/finance/by-customer?customer_name_b64=6bi_54OI5pyN6aWw&record_types=sale,receipt,refund&include_cash_movement=true&include_adjustments=false
|
||
Authorization: your-fixed-authorization-secret
|
||
```
|
||
|
||
成功响应示例:
|
||
|
||
```json
|
||
{
|
||
"mode": "customer_finance",
|
||
"customer_name": "鸿烨服饰",
|
||
"customer_ids": [
|
||
"KH00999"
|
||
],
|
||
"record_types": [
|
||
"sale",
|
||
"receipt",
|
||
"refund"
|
||
],
|
||
"include_cash_movement": true,
|
||
"include_adjustments": false,
|
||
"status": "active",
|
||
"snapshot_at": "2026-05-10T21:30:00Z",
|
||
"total_count": 3,
|
||
"sales_count": 1,
|
||
"sale_returns_count": 0,
|
||
"receipts_count": 1,
|
||
"refunds_count": 1,
|
||
"sales": [
|
||
{
|
||
"BianHaoID": "XS20366749",
|
||
"DanType": "成品销售单",
|
||
"KhID": "KH00999"
|
||
}
|
||
],
|
||
"sale_returns": [],
|
||
"receipts": [
|
||
{
|
||
"BianHaoID": "XS20215718",
|
||
"FkJinE": "378.00",
|
||
"JieSunFS": "微信"
|
||
}
|
||
],
|
||
"refunds": [
|
||
{
|
||
"BianHaoID": "XT20200743",
|
||
"YfJinE": "-2201.00",
|
||
"FkJinE": "0.00",
|
||
"JieSunFS": "微信"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
未命中响应示例:
|
||
|
||
```json
|
||
{
|
||
"customer_name": "鸿烨服饰",
|
||
"status": "not_found",
|
||
"message": "未找到该 customer_name 对应的财务记录"
|
||
}
|
||
```
|
||
|
||
参数错误示例:
|
||
|
||
```json
|
||
{
|
||
"error": "record_types contains unsupported value"
|
||
}
|
||
```
|
||
|
||
## 6. Database Inspect Permission Check
|
||
|
||
`GET /api/v1/db/permissions`
|
||
|
||
用途:
|
||
|
||
- 检查当前数据库账号是否具备数据库分析所需的基础能力
|
||
- 尝试验证数据库连接、获取当前库名、列出可见表、读取字段元数据、读取 `sys` 元数据、检查 `VIEW DEFINITION`、以及对所有可见表执行 `SELECT TOP (1)`
|
||
- 返回总体是否可用,以及各项检查结果
|
||
|
||
配置开关:
|
||
|
||
```yaml
|
||
db_inspect:
|
||
enabled: true
|
||
```
|
||
|
||
成功响应示例:
|
||
|
||
```json
|
||
{
|
||
"can_inspect": true,
|
||
"database_name": "RCYH2020",
|
||
"visible_table_count": 32,
|
||
"checks": [
|
||
{
|
||
"name": "database_connection",
|
||
"ok": true
|
||
},
|
||
{
|
||
"name": "list_base_tables",
|
||
"ok": true
|
||
},
|
||
{
|
||
"name": "read_all_visible_table_columns",
|
||
"ok": true
|
||
},
|
||
{
|
||
"name": "select_top_1_from_all_visible_tables",
|
||
"ok": true
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
字段说明:
|
||
|
||
- `can_inspect`: 是否满足数据库分析所需的整体权限和可读能力
|
||
- `database_name`: 当前连接到的数据库名
|
||
- `visible_table_count`: 当前账号可见的基础表数量
|
||
- `checks`: 分项检查结果
|
||
- `failed_column_tables`: 无法读取字段元数据的表清单,仅检查失败时出现
|
||
- `failed_select_tables`: 无法执行 `SELECT TOP (1)` 的表清单,仅检查失败时出现
|
||
|
||
## 7. List Database Tables
|
||
|
||
`GET /api/v1/db/tables`
|
||
|
||
用途:
|
||
|
||
- 返回当前数据库中当前账号可见的所有基础表
|
||
|
||
成功响应示例:
|
||
|
||
```json
|
||
{
|
||
"count": 2,
|
||
"tables": [
|
||
{
|
||
"schema": "dbo",
|
||
"name": "D_KhDhd",
|
||
"full_name": "dbo.D_KhDhd"
|
||
},
|
||
{
|
||
"schema": "dbo",
|
||
"name": "B_Khzl",
|
||
"full_name": "dbo.B_Khzl"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
## 8. List Table Columns
|
||
|
||
`GET /api/v1/db/columns`
|
||
|
||
参数:
|
||
|
||
- `table`: 必填,表名,格式为 `schema.table` 或 `db.schema.table`
|
||
|
||
用途:
|
||
|
||
- 返回指定表的字段列表
|
||
- 返回字段名、类型、是否可空、长度、精度、顺序等信息
|
||
|
||
示例:
|
||
|
||
```http
|
||
GET /api/v1/db/columns?table=dbo.D_KhDhd
|
||
Authorization: your-fixed-authorization-secret
|
||
```
|
||
|
||
成功响应示例:
|
||
|
||
```json
|
||
{
|
||
"table": "dbo.D_KhDhd",
|
||
"count": 2,
|
||
"columns": [
|
||
{
|
||
"name": "ID",
|
||
"data_type": "int",
|
||
"nullable": false,
|
||
"ordinal_position": 1
|
||
},
|
||
{
|
||
"name": "BianHaoID",
|
||
"data_type": "nvarchar",
|
||
"nullable": true,
|
||
"max_length": 50,
|
||
"ordinal_position": 2
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
## 9. Generic Table Select
|
||
|
||
`GET /api/v1/db/select`
|
||
|
||
参数:
|
||
|
||
- `table`: 必填,表名,格式为 `schema.table` 或 `db.schema.table`
|
||
- `columns`: 必填,逗号分隔的字段名列表,例如 `ID,BianHaoID`
|
||
- `where`: 可选,受限条件表达式;支持 `=` `!=` `<>` `>` `>=` `<` `<=` `LIKE` `IS NULL` `IS NOT NULL`,多个条件只支持用 `AND` 连接;字符串字面量必须写成单引号,例如 `DanType = '客户退货单'`
|
||
- `limit`: 可选,正整数;不传时使用默认值,并受服务端上限限制
|
||
|
||
用途:
|
||
|
||
- 对指定表执行通用只读查询
|
||
- 仅返回请求中指定的字段集合
|
||
- 当前实现固定为 `SELECT TOP (limit)`,支持受限 `WHERE`,不支持自定义 SQL
|
||
|
||
示例:
|
||
|
||
```http
|
||
GET /api/v1/db/select?table=dbo.D_KhDhd&columns=ID,BianHaoID&limit=10
|
||
Authorization: your-fixed-authorization-secret
|
||
```
|
||
|
||
```http
|
||
GET /api/v1/db/select?table=dbo.I_Sale&columns=BianHaoID,DanType,ShuLiang&where=DanType%20%3D%20%27%E5%AE%A2%E6%88%B7%E9%80%80%E8%B4%A7%E5%8D%95%27%20AND%20ShuLiang%20%3C%200&limit=10
|
||
Authorization: your-fixed-authorization-secret
|
||
```
|
||
|
||
成功响应示例:
|
||
|
||
```json
|
||
{
|
||
"table": "dbo.D_KhDhd",
|
||
"columns": [
|
||
"ID",
|
||
"BianHaoID"
|
||
],
|
||
"count": 2,
|
||
"rows": [
|
||
{
|
||
"ID": 1001,
|
||
"BianHaoID": "KD20432358"
|
||
},
|
||
{
|
||
"ID": 1002,
|
||
"BianHaoID": "KD20432359"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
参数错误示例:
|
||
|
||
```json
|
||
{
|
||
"error": "where is invalid"
|
||
}
|
||
```
|
||
|
||
当配置关闭时:
|
||
|
||
```json
|
||
{
|
||
"error": "db inspect api is disabled"
|
||
}
|
||
```
|
||
|
||
## 10. Get Current Cursor
|
||
|
||
`GET /api/v1/cursor`
|
||
|
||
用途:
|
||
|
||
- 查看当前游标值
|
||
- 查看最近一次人工修改游标前的 `origin_cursor`
|
||
|
||
示例:
|
||
|
||
```http
|
||
GET /api/v1/cursor
|
||
Authorization: your-fixed-authorization-secret
|
||
```
|
||
|
||
成功响应示例:
|
||
|
||
```json
|
||
{
|
||
"cursor": 1500,
|
||
"origin_cursor": 1250
|
||
}
|
||
```
|
||
|
||
## 11. Set Cursor
|
||
|
||
`POST /api/v1/cursor/set`
|
||
|
||
用途:
|
||
|
||
- 人工把游标改到指定值
|
||
- 每次手工修改时,都会把修改前的游标保存到 `origin_cursor`
|
||
|
||
请求体:
|
||
|
||
```json
|
||
{
|
||
"value": 1500
|
||
}
|
||
```
|
||
|
||
规则:
|
||
|
||
- `value` 必须是非负整数
|
||
- 调用成功后:
|
||
- `cursor` 更新为 `value`
|
||
- `origin_cursor` 保存修改前的 `cursor`
|
||
|
||
请求示例:
|
||
|
||
```http
|
||
POST /api/v1/cursor/set
|
||
Authorization: your-fixed-authorization-secret
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"value": 1500
|
||
}
|
||
```
|
||
|
||
成功响应示例:
|
||
|
||
```json
|
||
{
|
||
"cursor_before": 1250,
|
||
"cursor_after": 1500,
|
||
"origin_cursor": 1250,
|
||
"updated": true
|
||
}
|
||
```
|
||
|
||
## 12. Get Image
|
||
|
||
`GET /api/v1/image`
|
||
|
||
用途:
|
||
|
||
- 根据给定文件名,从配置的图片目录读取对应文件
|
||
- 找到后返回图片内容的 Base64 字符串
|
||
- 找不到时返回 `404`
|
||
|
||
配置文件:
|
||
|
||
```yaml
|
||
image:
|
||
directory: "./images"
|
||
```
|
||
|
||
参数:
|
||
|
||
- `name`: 可选,原始文件名,必须是纯文件名,不能包含路径
|
||
- `name_b64`: 可选,文件名的 Base64URL 编码;当文件名包含 `#` 等 URL 特殊字符时推荐使用
|
||
- 如果 `name` 不带后缀,服务端会按 `.jpg`、`.png` 的顺序自动尝试
|
||
|
||
说明:
|
||
|
||
- `name` 和 `name_b64` 二选一即可
|
||
- 如果文件名里包含 `#`,很多客户端会在真正发请求前把它后面的内容当作 URL fragment 截掉,因此推荐使用 `name_b64`
|
||
|
||
示例:
|
||
|
||
```http
|
||
GET /api/v1/image?name=test
|
||
Authorization: your-fixed-authorization-secret
|
||
```
|
||
|
||
```http
|
||
GET /api/v1/image?name_b64=YWJjIzEyMw
|
||
Authorization: your-fixed-authorization-secret
|
||
```
|
||
|
||
上面的 `name_b64=YWJjIzEyMw` 对应原始文件名:
|
||
|
||
```text
|
||
abc#123
|
||
```
|
||
|
||
成功响应示例:
|
||
|
||
```json
|
||
{
|
||
"name": "test.jpg",
|
||
"content_type": "image/jpeg",
|
||
"data": "/9j/4AAQSkZJRgABAQ..."
|
||
}
|
||
```
|
||
|
||
错误响应示例:
|
||
|
||
```json
|
||
{
|
||
"error": "image not found"
|
||
}
|
||
```
|
||
|
||
说明:
|
||
|
||
- `data` 是图片二进制内容的 Base64 编码
|
||
- `content_type` 会优先根据文件扩展名推断,推断不出来时会回退到内容检测
|
||
- 如果 `name` 没有后缀,会优先查找 `name.jpg`,找不到再查 `name.png`
|
||
- 如果文件名中含有 `#`、空格等特殊字符,优先使用 `name_b64`
|
||
- 为了安全,`name` 不能带目录分隔符,也不能包含 `..`
|
||
|
||
## 13. Cursor State File
|
||
|
||
默认文件:
|
||
|
||
```text
|
||
./data/cursor-state.json
|
||
```
|
||
|
||
文件内容示例:
|
||
|
||
```json
|
||
{
|
||
"cursor": 1500,
|
||
"origin_cursor": 1250
|
||
}
|
||
```
|
||
|
||
说明:
|
||
|
||
- `cursor`: 当前增量同步游标
|
||
- `origin_cursor`: 最近一次人工修改游标前的值
|