docs: 新增收款流水多次认领与作废口径梳理文档

This commit is contained in:
刘泉佳
2026-10-16 15:27:10 +08:00
parent 709c633dbb
commit 576847396e
@@ -0,0 +1,130 @@
# 收款流水(认领通知单)多次认领与作废口径梳理
> 日期:2026-10-16
> 范围:`tms-api` blade-transport 收款流水认领、认领记录模块;`tms-erp-web` 认领记录页面
---
## 一、结论速览
| 问题 | 结论 |
| --- | --- |
| 一个通知单能被多次认领,每次认领生成一条还是多条认领记录? | **每次认领操作生成一条认领主单**(`blade_receipt_claim`),多次认领即多条主单;每次认领同时按所选拆分生成 N 条结算单分摊明细(`blade_receipt_claim_settlement`) |
| 认领记录页面是一条一条显示还是只显示一条? | **一条认领主单一行,逐条显示**,不按通知单合并;同一通知单认领 3 次就显示 3 行,每行"认领金额"只是该次认领的金额 |
| 作废是逐条作废归还金额,还是整个通知单全部作废? | **逐条作废、按条归还金额**:作废入口在单条认领记录上,回退金额 = 该条认领主单的 `claim_amount`,流水已认领金额只减这一条;其余认领记录不受影响 |
---
## 二、数据模型
```
blade_kingdee_receipt_flow(收款流水 / 认领通知单,1)
│ receipt_flow_id
├─< blade_receipt_claim(认领主单,N) ← 每次认领一条
│ claim_amount 本次认领总金额
│ claimer_id 认领人(记录页面按本人过滤)
│ claim_status claimed / voided
│ voided_by / voided_time 作废人 / 作废时间
│
└─< blade_receipt_claim_settlement(分摊明细,N × M) ← 每次认领按结算单拆行
receipt_claim_id 归属哪次认领
formal_settlement_id/no 关联应收正式结算单
allocated_receipt_amount 本次分摊金额
claimed_receipt_amount 认领前该结算单已认领金额
status 1 有效 / 0 无效(作废置 0,不物理删除)
```
关键点:**认领主单的粒度是"一次认领操作"**,不是通知单。通知单维度只有累计金额(`claimed_amount`)和状态(`claim_status`:unclaimed / partial / claimed),由每次认领/作废累加回退得出。
---
## 三、认领:一次操作生成一条主单 + N 条分摊
代码:`ReceiptFlowServiceImpl#claim(ReceiptClaimRequest)`
1. 锁定流水(通知单)与所选结算单。
2. 校验两条累计上限:
- 每张结算单:已有累计认领 + 本次分摊 ≤ 结算总应收含税金额;
- 流水:已有累计认领(`flowClaimedAmount`,只算未作废记录)+ 本次总额 ≤ 公告未认领金额(`unclaimed_amount`,A301-2 口径)。
3. **插入一条** `ReceiptClaim` 主单:`claim_amount` = 本次分摊总额,`claim_status = claimed`。
4. 按所选结算单逐张**插入 N 条** `ReceiptClaimSettlement` 分摊明细。
5. 累加流水 `claimed_amount`,按累计值重算流水状态(< 未认领金额 → partial,= → claimed)。
6. 只登记本地,不推送金蝶;推送由定时任务/手动按钮触发。
所以:**同一通知单第二次认领是再插一条新主单**,不存在"找已有主单合并金额"的逻辑;校验全部按"未作废记录累计"实时计算,天然支持多次认领。
### 认领按钮的显示条件(为什么有些行没有"认领")
收款流水列表操作列(`receipt-flow.vue` → `canClaim(row)`):
```js
canClaim(row) {
return this.hasPermission('receipt_flow_claim') && Number(row.remainingAmount || 0) > 0;
}
```
两个条件同时满足才显示"认领"按钮:
1. **按钮权限**:当前用户拥有 `receipt_flow_claim` 按钮权限(admin 直接放行,普通用户取决于菜单按钮配置);
2. **剩余可认领金额 > 0**:`remainingAmount` 由后端 `ReceiptFlowWrapper` 统一计算:
```
remainingAmount = max(公告未认领金额 unclaimed_amount − 累计认领金额 claimed_amount, 0)
```
按认领状态换算:
| 流水认领状态 | remainingAmount | 认领按钮 |
| --- | --- | --- |
| unclaimed 未认领(公告金额 > 0) | = 公告未认领金额 > 0 | 显示 |
| partial 部分认领 | > 0 | 显示 |
| claimed 认领完成 | = 0(累计 ≥ 公告金额) | **不显示** |
| 公告未认领金额为 0 的流水 | = 0 | **不显示** |
| 无 `receipt_flow_claim` 权限 | — | **不显示** |
即:**按钮显隐只看金额余额与权限,不看认领状态字段本身**;`claimed` 状态的行因为剩余额度为 0 自然不显示按钮。按钮不显示且不满足"推送金蝶"条件时,操作列显示"-"。
注意:顶部"批量认领"按钮只判断权限与是否勾选行(`receipt_flow_claim` + `selectedRows.length`),**不按行剩余金额过滤**;对无剩余额度的流水发起批量认领时,进入批量页面后由提交校验/后端 `claim()` 兜底拦截。
---
## 四、认领记录页面:逐条显示
后端:`ReceiptClaimMapper.xml#selectClaimRecordPage` → `FROM blade_receipt_claim c JOIN blade_kingdee_receipt_flow f`,固定条件 `c.claimer_id = 当前用户`。
- **列表一行 = 一条认领主单**,无按流水/通知单的 GROUP BY 合并;
- 同一通知单多次认领 → 多行,各行的认领金额、认领日期、金蝶单号都是当次认领自己的;
- 关联结算单列用 `GROUP_CONCAT(分摊明细.结算单号)` 拼成一串展示(只展示,不参与合并);
- 详情页(`selectClaimRecordDetail` + 分摊明细列表)展示的也是**该次认领**的分摊明细,明细里的"认领前已认领金额"记录的是认领那一刻结算单的累计值,可还原多次认领的先后关系;
- 前端 `receipt-claim-record.vue` 列表 + 行级"作废"按钮(`api.voidClaim(row.id)`),确认文案为"作废后将回退本次认领金额"——与逐条口径一致。
另:收款流水列表的详情弹窗里有一个"认领记录"区块,展示的是该流水的**操作日志**(`blade_receipt_flow_record`,action_type = claim/push),按时间线展示每次认领/推送动作,同样不是合并视图。
---
## 五、作废:逐条作废、按条归还金额
代码:`ReceiptClaimRecordServiceImpl#voidClaim(Long id)`,入参就是**单条认领主单 id**。
流程(单事务):
1. 锁定该条认领主单,校验:本人记录、`claim_status = claimed`(已作废不可再作废)。
2. 锁定关联流水,校验:**未推送金蝶**——已推送的不允许作废,提示"请在金蝶侧人工处置"。
3. 取该主单名下有效分摊明细(status=1),全部置 `status = 0`(保留审计,不删行)。
4. 批量刷新相关结算单收款汇总(`refreshPaymentSummaries`)。
5. **流水 `claimed_amount` 只减去本条主单的 `claim_amount`**(下限 0),并按减后累计重算流水认领状态(0 → unclaimed,< 未认领金额 → partial,≥ → claimed)。
6. 主单置 `voided`,记录作废人、作废时间;写 `void_claim` 操作日志(金额 = 本次回退金额)。
7. **不生成金蝶认领冲单**:金蝶单号/状态保留原值,金蝶侧冲销/红红由人工处置;冲单逻辑代码已注释保留(`buildKingdeeBillNo`),后续迭代可放开。
边界与影响:
- 作废某一条,只归还这一条的金额,**同一通知单的其他认领记录不受影响**,仍正常显示、仍可单独作废;
- 作废后该条记录仍在列表中(状态"已作废"),不允许再改附件、不可重复作废;
- 归还后的金额空间立即可被再次认领(认领校验按未作废累计实时计算);
- 附件/操作日志/分摊明细均保留,金额回退可追溯。
---
## 六、一句话总结
通知单(收款流水)是"累计额度"维度,认领记录是"每次操作"维度:**认领一次记一条、页面逐条展示、作废按条回退金额**;整单性质的只有流水上的累计已认领金额与认领状态,由各条记录的认领/作废实时推导,没有任何"按通知单整体作废"的入口。