11 KiB
11 KiB
schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
| schema | ticket | title | consumer | author | change_type | backend_status | gateway_status | frontend_status | frontend_owner | frontend_ref | target_release | verified_at | status_note | updated_at | base |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hl-changelog/v2 | 8689 | 核销管理后端落地:坏账核销/债务豁免 5 端点(#8689) | admin | yst(GIT) | 新增接口 | merged | not_required | implemented | hl-admin(claude-opus-4-8) | 01436d457302207d2684584c48c50818936fdecf | v2.1 | 2026-10-02 | 核销管理(API §6.5 设计稿)本期提前落地。核销=往来账面抹债不动资金(无资金流水、不改账户结存、不过出纳),与支付本质区别:支付是钱真动了,核销只是账认了这笔损失/对冲。本期落地 SUPPLIER 债务豁免(冲减应付)+ CUSTOMER 坏账核销(冲减应收)两类;STAFF 员工·司导往来不做。新增 /admin/finance/writeoffs 5 端点(两页签列表/发起核销/提交审批/批准/驳回)。审批本期本地手工批(企微审批流留 TODO),金额≥阈值(默认 5000)落待审批、<阈值建单即入账。坏账核销只落往来台账留痕、不回改订单侧应收金额。前端已交付(用户拍板已部署立项):新建核销管理页(hiddenRoute 先行,核销审批/核销记录双页签懒加载,批准二次确认+驳回原因必填,LOG 筛选仅用契约 keyword/ledgerType/status 三参,原型类型/日期筛选与页签角标契约无入参不渲染);发起核销弹窗页内+供应商往来账行「核销」两入口共用(账套→类型一对一联动,供应商走档案弹窗带 refId、客户按名聚合不传 refId,阈值分流以响应 needApproval 为准不前端预判);submit 手工批仅守卫不暴露按钮;错误码全走拦截器透 message。页 spec 5 例+弹窗 spec 6 例+供应商往来账 wiring 1 例,21 例全绿。 | 2026-10-01 | 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+ BodyWriteoffRejectReqVO:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| 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
{ "ledgerType": "SUPPLIER", "writeoffType": "DEBT_WAIVER", "refId": 101, "refName": "嘉世豪酒店", "amount": 800.00, "reason": "供应商同意减免尾款" }
响应
{ "code": 0, "data": { "writeoffId": "1234567890", "writeoffNo": "HX-202610010001", "status": "POSTED", "needApproval": 0 }, "msg": "" }
8.2 边界(金额 ≥ 阈值 → 落待审批)
请求 POST /admin/finance/writeoffs
{ "ledgerType": "CUSTOMER", "writeoffType": "BAD_DEBT", "refName": "张三", "amount": 6000.00, "reason": "客户失联认损" }
响应
{ "code": 0, "data": { "writeoffId": "1234567891", "writeoffNo": "HX-202610010002", "status": "PENDING_APPROVAL", "needApproval": 1 }, "msg": "" }
8.3 业务失败(核销金额超净往来)
响应
{ "code": 596001, "msg": "核销金额超过该对象净往来", "data": null }
9. 业务边界
- ✅ 核销只动往来账面:在该对象台账记一行反向对冲(净额减)
- ❌ 核销不产生资金流水、不改账户结存、不过出纳
- ❌ 坏账核销不回改订单侧应收金额——核销是财务账面认损失,订单应收仍在;CUSTOMER 按客户名聚合校验+回扣已核销防重复
- ⚠️ 同名客户本期算一起(应收台账行无 customerId),将来补 customerId 后升级按 ID
13. 关联 / 联系人
- Issue: #8689
- PR: #8697
- Merge commit: 04e7ff6025
- 后端负责人: @yaosutu