@@ -0,0 +1,218 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "8689"
|
||||
title: "核销管理后端落地:坏账核销/债务豁免 5 端点(#8689)"
|
||||
consumer: "admin"
|
||||
author: "yst(GIT)"
|
||||
change_type: "新增接口"
|
||||
backend_status: "merged"
|
||||
gateway_status: "not_required"
|
||||
frontend_status: "pending"
|
||||
frontend_owner: ""
|
||||
frontend_ref: ""
|
||||
target_release: "v2.1"
|
||||
verified_at: "2026-10-01"
|
||||
status_note: "核销管理(API §6.5 设计稿)本期提前落地。核销=往来账面抹债不动资金(无资金流水、不改账户结存、不过出纳),与支付本质区别:支付是钱真动了,核销只是账认了这笔损失/对冲。本期落地 SUPPLIER 债务豁免(冲减应付)+ CUSTOMER 坏账核销(冲减应收)两类;STAFF 员工·司导往来不做。新增 /admin/finance/writeoffs 5 端点(两页签列表/发起核销/提交审批/批准/驳回)。审批本期本地手工批(企微审批流留 TODO),金额≥阈值(默认 5000)落待审批、<阈值建单即入账。坏账核销只落往来台账留痕、不回改订单侧应收金额。"
|
||||
updated_at: "2026-10-01"
|
||||
base: "dev-v3"
|
||||
---
|
||||
|
||||
# finance:核销管理后端落地(坏账核销/债务豁免 5 端点)(管理后台)
|
||||
|
||||
> **PR**: #8697 | **服务**: hl-order-service-v3(hl-finance 编译其中) | **更新时间**: 2026-10-01
|
||||
|
||||
## 1. 接口背景
|
||||
|
||||
财务往来账上会有「收不回的应收(坏账)」和「不用付的应付(债务豁免)」,需要从账面轧掉认损。这就是**核销**。
|
||||
|
||||
核销与支付的本质区别:
|
||||
- **支付**:钱真的动了(产生资金流水、账户结存变动、过出纳)
|
||||
- **核销**:只是账面抹债——**不动资金、无资金流水、不改账户结存、不过出纳**,只在该对象的往来台账上记一笔反向对冲行(净额减)
|
||||
|
||||
本期落地两类核销:
|
||||
| 核销类型 | 账套 | 作用 |
|
||||
|---|---|---|
|
||||
| 债务豁免 `DEBT_WAIVER` | 供应商 `SUPPLIER` | 冲减应付(不用付了的应付款轧掉) |
|
||||
| 坏账核销 `BAD_DEBT` | 客户 `CUSTOMER` | 冲减应收(收不回的应收款认损失) |
|
||||
|
||||
> **STAFF 员工·司导往来本期不做**(该账套属后续 Epic、净往来无来源)。报销冲抵不进本表(走费用域闭环)。
|
||||
|
||||
此前核销管理只有设计稿(API §6.5),本次后端正式落地 5 个端点。
|
||||
|
||||
## 2. 变更清单
|
||||
|
||||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||||
|---|------|------|------|----------|------|
|
||||
| 1 | 核销分页(两页签) | GET | /admin/finance/writeoffs/page | 新增 | PENDING 待审批 / LOG 全量记录 |
|
||||
| 2 | 发起核销 | POST | /admin/finance/writeoffs | 新增 | 建核销单,按金额阈值分流 |
|
||||
| 3 | 提交审批 | POST | /admin/finance/writeoffs/{id}/submit | 新增 | 本期本地手工批,仅守卫 |
|
||||
| 4 | 批准核销 | POST | /admin/finance/writeoffs/{id}/approve | 新增 | 入账:写台账对冲行 |
|
||||
| 5 | 驳回核销 | POST | /admin/finance/writeoffs/{id}/reject | 新增 | 驳回不动账 |
|
||||
|
||||
## 3. 接口详情
|
||||
|
||||
### 3.1 核销分页(两页签)
|
||||
|
||||
- **使用场景**:核销管理页两页签——「待审批」列待批核销单,「核销记录」列全量(已入账+已驳回)
|
||||
- **认证**:需登录,财务查看权限
|
||||
- **入参(Query)**:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| tab | String | ✅ | 页签:`PENDING` 待审批 / `LOG` 核销记录(其他值报 596013) |
|
||||
| ledgerType | String | ❌ | 账套过滤:`SUPPLIER` / `CUSTOMER` |
|
||||
| status | String | ❌ | 状态过滤;**LOG 页签仅允许 `POSTED`/`REJECTED`**(传其他报 596013),PENDING 页签忽略 |
|
||||
| keyword | String | ❌ | 核销单号 / 往来对象名 模糊 |
|
||||
| pageNo / pageSize | int | ✅ | 分页 |
|
||||
|
||||
- **出参**:`PageResult<WriteoffRowRespVO>`
|
||||
|
||||
### 3.2 发起核销
|
||||
|
||||
- **使用场景**:财务在某往来对象上发起一笔核销
|
||||
- **入参(Body,WriteoffCreateReqVO)**:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 | 校验 |
|
||||
|------|------|------|------|------|
|
||||
| ledgerType | String | ✅ | 账套:`SUPPLIER` / `CUSTOMER` | |
|
||||
| writeoffType | String | ✅ | 核销类型:`DEBT_WAIVER`(SUPPLIER)/ `BAD_DEBT`(CUSTOMER) | 与账套不匹配报 596014 |
|
||||
| refId | Long | 见说明 | 往来对象 ID(SUPPLIER 必填) | |
|
||||
| refName | String | ✅ | 往来对象名(CUSTOMER 按客户名聚合) | |
|
||||
| amount | BigDecimal | ✅ | 核销金额 | >0(596012)、@Digits(16,2)、≤ 该对象净往来(596001) |
|
||||
| reason | String | ✅ | 核销原因 | |
|
||||
| sourceType / sourceId / sourceNo | String/Long/String | ❌ | 来源单据(可选追溯) | |
|
||||
|
||||
- **分流**:金额 < 阈值(默认 5000)→ 直接 `POSTED` 入账;≥ 阈值 → `PENDING_APPROVAL` 待审批
|
||||
- **出参**:`WriteoffCreateRespVO`(writeoffId / writeoffNo / status / needApproval)
|
||||
|
||||
### 3.3 提交审批
|
||||
|
||||
- **使用场景**:≥阈值核销单提交走审批
|
||||
- **本期说明**:审批为**本地手工批**(对齐费用/支付),企微审批流留 TODO 不接;submit 仅做状态守卫、状态不变,返回空串实例 ID
|
||||
- **入参**:路径 `id`
|
||||
- **出参**:`WriteoffSubmitRespVO`(approvalInstanceId 本期恒空串)
|
||||
|
||||
### 3.4 批准核销
|
||||
|
||||
- **使用场景**:批准一笔待审批核销 → 入账
|
||||
- **动作**:`PENDING_APPROVAL` → `POSTED`,写一行往来台账反向对冲行(净额减),回写核销单 statement_entry_id + posted_at + 审批人快照
|
||||
- **防超额**:批准时会**重算该对象当前净往来**,若 PENDING 期间净额已被其他入账冲减到不够核销,报 596001 不予入账
|
||||
- **入参**:路径 `id`
|
||||
|
||||
### 3.5 驳回核销
|
||||
|
||||
- **使用场景**:驳回一笔待审批核销(不动账)
|
||||
- **动作**:`PENDING_APPROVAL` → `REJECTED`,记驳回原因 + 审批人快照
|
||||
- **入参**:路径 `id` + Body `WriteoffRejectReqVO`:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| reason | String | ✅ | 驳回原因 |
|
||||
|
||||
## 5. 出参(核销行 WriteoffRowRespVO)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | Long | 核销单 ID(字符串化) |
|
||||
| writeoffNo | String | 核销单号(HX- 开头) |
|
||||
| ledgerType | String | 账套 SUPPLIER/CUSTOMER |
|
||||
| ledgerTypeName | String | 账套中文名 |
|
||||
| writeoffType | String | 核销类型 DEBT_WAIVER/BAD_DEBT |
|
||||
| writeoffTypeName | String | 核销类型中文名 |
|
||||
| refId | Long | 往来对象 ID |
|
||||
| refName | String | 往来对象名 |
|
||||
| amount | BigDecimal | 核销金额 |
|
||||
| reason | String | 核销原因 |
|
||||
| status | String | 状态 PENDING_APPROVAL/POSTED/REJECTED |
|
||||
| statusName | String | 状态中文名 |
|
||||
| needApproval | Integer | 是否需审批 0/1 |
|
||||
| operatorName | String | 经办人 |
|
||||
| approverName | String | 审批人(本期手工批回填) |
|
||||
| rejectReason | String | 驳回原因 |
|
||||
| postedAt | String | 入账时间 |
|
||||
| createTime | String | 创建时间 |
|
||||
|
||||
## 6. 枚举 / 数据字典
|
||||
|
||||
### 6.1 ledgerType(账套)
|
||||
| 值 | 中文 | 说明 |
|
||||
|----|------|------|
|
||||
| SUPPLIER | 供应商 | 应付侧 |
|
||||
| CUSTOMER | 客户 | 应收侧 |
|
||||
|
||||
### 6.2 writeoffType(核销类型)
|
||||
| 值 | 中文 | 适用账套 |
|
||||
|----|------|----------|
|
||||
| DEBT_WAIVER | 债务豁免 | SUPPLIER |
|
||||
| BAD_DEBT | 坏账核销 | CUSTOMER |
|
||||
|
||||
### 6.3 status(核销单状态)
|
||||
| 值 | 中文 | 说明 |
|
||||
|----|------|------|
|
||||
| PENDING_APPROVAL | 待审批 | ≥阈值待批 |
|
||||
| POSTED | 已入账 | 已写台账对冲行 |
|
||||
| REJECTED | 已驳回 | 审批驳回 |
|
||||
|
||||
### 6.4 tab(页签)
|
||||
| 值 | 中文 |
|
||||
|----|------|
|
||||
| PENDING | 待审批 |
|
||||
| LOG | 核销记录 |
|
||||
|
||||
## 7. 错误码
|
||||
|
||||
| code | 含义 | 触发场景 |
|
||||
|------|------|----------|
|
||||
| 596001 | 核销金额超过该对象净往来 | 发起 / 批准时金额 > 净往来 |
|
||||
| 596002 | 核销单状态不允许该操作 | 对非待审批单做 submit/approve/reject |
|
||||
| 596004 | 往来对象不存在 | 供应商/客户查无(SUPPLIER 无任何期初与流水) |
|
||||
| 596011 | 核销单不存在 | id 查无 |
|
||||
| 596012 | 核销金额无效须>0 | amount ≤0 |
|
||||
| 596013 | 核销页签非法 / LOG 页签 status 非法 | tab 非 PENDING/LOG;LOG 传非 POSTED/REJECTED |
|
||||
| 596014 | 核销类型与账套不匹配 | SUPPLIER 传 BAD_DEBT / CUSTOMER 传 DEBT_WAIVER |
|
||||
| 596015 | 核销单号取号撞号耗尽 | HX- 取号并发耗尽(极少) |
|
||||
|
||||
## 8. 示例
|
||||
|
||||
### 8.1 典型成功(发起一笔供应商债务豁免,<阈值直接入账)
|
||||
|
||||
**请求** POST /admin/finance/writeoffs
|
||||
```json
|
||||
{ "ledgerType": "SUPPLIER", "writeoffType": "DEBT_WAIVER", "refId": 101, "refName": "嘉世豪酒店", "amount": 800.00, "reason": "供应商同意减免尾款" }
|
||||
```
|
||||
**响应**
|
||||
```json
|
||||
{ "code": 0, "data": { "writeoffId": "1234567890", "writeoffNo": "HX-202610010001", "status": "POSTED", "needApproval": 0 }, "msg": "" }
|
||||
```
|
||||
|
||||
### 8.2 边界(金额 ≥ 阈值 → 落待审批)
|
||||
|
||||
**请求** POST /admin/finance/writeoffs
|
||||
```json
|
||||
{ "ledgerType": "CUSTOMER", "writeoffType": "BAD_DEBT", "refName": "张三", "amount": 6000.00, "reason": "客户失联认损" }
|
||||
```
|
||||
**响应**
|
||||
```json
|
||||
{ "code": 0, "data": { "writeoffId": "1234567891", "writeoffNo": "HX-202610010002", "status": "PENDING_APPROVAL", "needApproval": 1 }, "msg": "" }
|
||||
```
|
||||
|
||||
### 8.3 业务失败(核销金额超净往来)
|
||||
|
||||
**响应**
|
||||
```json
|
||||
{ "code": 596001, "msg": "核销金额超过该对象净往来", "data": null }
|
||||
```
|
||||
|
||||
## 9. 业务边界
|
||||
|
||||
- ✅ 核销只动往来账面:在该对象台账记一行反向对冲(净额减)
|
||||
- ❌ 核销**不产生资金流水、不改账户结存、不过出纳**
|
||||
- ❌ 坏账核销**不回改订单侧应收金额**——核销是财务账面认损失,订单应收仍在;CUSTOMER 按客户名聚合校验+回扣已核销防重复
|
||||
- ⚠️ 同名客户本期算一起(应收台账行无 customerId),将来补 customerId 后升级按 ID
|
||||
|
||||
## 13. 关联 / 联系人
|
||||
|
||||
- **Issue**: [#8689](https://git.1814.love/wx/HL/issues/8689)
|
||||
- **PR**: [#8697](https://git.1814.love/wx/HL/pulls/8697)
|
||||
- **Merge commit**: [04e7ff6025](https://git.1814.love/wx/HL/commit/04e7ff60250f9199684856801452bd1d0062e46a)
|
||||
- **后端负责人**: @yaosutu
|
||||
在新工单中引用
屏蔽一个用户