开票与回款关联(先开票后回款) - 前端联调方案
本次调整(最新):回款创建表单的【关联开票】与【回款期数】由必填改为**选填**,支持「未关联开票 / 未关联回款计划」直接录入回款。
后端已放开(invoiceId 不再强制),前端需去掉这两个字段的必填校验,详见文末「本次调整」章节。
涉及页面
- 回款管理列表页
- 回款创建 / 编辑表单
- 回款详情页
- 开票管理列表页、开票详情页(**前端目前缺失,需新建**)
- 合同管理列表页、合同详情页(上个任务已接入"已开票金额/未开票金额",本次不涉及)
业务流程与数据带入
- 开票 → 回款:开票单审批通过 + 上传发票附件后,才会出现在回款创建表单的"关联开票"下拉中。
- 回款创建:选择客户 → 选择合同 → 选择关联开票(自动带入客户、合同)→(可选)选择回款计划 → 填回款金额(可预填为该开票的剩余可回款金额)。
- 合同下拉(simple-list):已返回
totalInvoicePrice(已开票金额,含审批中),用于展示合同剩余可开额度。
- 开票下拉(simple-list):返回
remainingInvoicePrice(该开票剩余可回款金额),用于创建回款时预填金额。
API
1. 新增接口:按合同查询可选开票
| 方法 |
路径 |
说明 |
| GET |
/crm/invoice/simple-list?contractId= |
回款创建时选择关联开票,只返回合格开票 |
筛选规则(后端已实现):审批通过 + 已上传发票附件 + 剩余可回款金额 > 0。
响应示例:
{
"code": 0,
"data": [
{
"id": 1,
"no": "KP20260810000001",
"invoiceNo": "02564178",
"invoiceTitle": "XX科技有限公司",
"price": 1090.00,
"customerId": 1,
"contractId": 31,
"auditStatus": 20,
"hasAttachment": true,
"remainingInvoicePrice": 1090.00
}
]
}
2. 变更接口:回款创建 / 更新
| 方法 |
路径 |
说明 |
| POST |
/crm/receivable/create |
请求体新增 invoiceId(**选填**) |
| PUT |
/crm/receivable/update |
请求体新增 invoiceId(可修改) |
请求参数新增:
| 参数 |
类型 |
必填 |
说明 |
| invoiceId |
Long |
否 |
关联的开票编号。填写时必须为审批通过且已上传附件的开票;不填表示该笔回款暂不关联开票 |
| planId |
Long |
否 |
关联的回款计划编号。不填表示不占用回款计划期数 |
3. 变更接口:回款查询(响应新增字段)
| 方法 |
路径 |
新增响应字段 |
| GET |
/crm/receivable/page |
invoiceId、invoice(嵌套对象) |
| GET |
/crm/receivable/get |
invoiceId、invoice(嵌套对象) |
| GET |
/crm/receivable/page-by-customer |
invoiceId、invoice(嵌套对象) |
invoice 嵌套对象关键字段: id、no(开票编号)、invoiceNo(发票号码)、invoiceTitle(发票抬头)、price(开票金额)。
4. 变更接口:开票查询(响应新增字段)
| 方法 |
路径 |
新增响应字段 |
| GET |
/crm/invoice/page |
hasAttachment、remainingInvoicePrice |
| GET |
/crm/invoice/get |
hasAttachment、remainingInvoicePrice |
说明:
- hasAttachment(Boolean):是否已上传发票附件,用于列表快速判断哪些开票可被回款关联。
- remainingInvoicePrice(BigDecimal):剩余可回款金额 = 开票金额 - 该开票已回款金额(统计草稿 + 审批中 + 审批通过的回款)。
字段展示规则
| 字段 |
展示位置 |
说明 |
| 关联开票 |
回款列表列、回款详情页 |
展示 invoice.no / invoice.invoiceNo / invoice.price |
| 关联开票选择器 |
回款创建/编辑表单 |
选择后带入客户、合同、预填回款金额为 remainingInvoicePrice |
| 剩余可回款金额 |
开票列表列、开票详情页 |
开票金额 - 该开票已回款金额 |
| 是否已上传附件 |
开票列表列 |
辅助判断开票是否可回款(需审批通过 + 已上传附件) |
本次调整(【关联开票】【回款期数】改为选填)
变更点
| 项 |
调整前 |
调整后 |
| 关联开票(invoiceId) |
必填,不选无法保存 |
选填;不选即录入一笔不关联开票的回款 |
| 回款期数(planId) |
必填,不选无法保存 |
选填;不选即不占用回款计划期数 |
| 合同(contractId) |
必填 |
仍为必填(金额上限校验依赖合同) |
| 回款金额、回款日期 |
必填 |
仍为必填 |
前端的改动点(去必填)
- 回款创建/编辑表单的【关联开票】【回款期数】两个字段,去掉必填校验规则即可,其余联动逻辑(选合同后加载开票/期数选项、选中后带入客户与金额)保持不变。
- 建议取消必填后,字段提示文案相应改为「可不选」类表述,避免用户误以为漏填。
不填时的后端行为
| 场景 |
行为 |
| 不选关联开票 |
跳过「开票是否审批通过 / 是否已上传附件 / 是否与合同一致」及「不超过该开票剩余可回款金额」两组校验 |
| 不选关联开票时的金额上限 |
仍受**合同级**校验约束:累计回款不得超过合同总金额 |
| 不选回款期数 |
不更新任何回款计划的已回款标记,回款计划列表中该期仍显示未回款 |
| 编辑既有回款 |
未提交 invoiceId 时保留原关联关系(不会因漏传而被清空);如需解除关联,需显式清空该字段(当前前端编辑态该字段为禁用,如需支持解除需另行开放) |
业务规则说明
| 场景 |
规则 |
| 审批中的开票 |
不可选为回款依据(后端拦截:关联开票不是审批通过状态) |
| 未上传发票附件的开票 |
不可选为回款依据(后端拦截:关联开票未上传发票附件) |
| 已全部回款的开票 |
从"关联开票"下拉过滤(剩余可回款 ≤ 0) |
| 回款金额超限 |
后端拦截:回款金额超出该开票剩余可回款金额 |
| 开票与合同不匹配 |
后端拦截:所选开票与回款合同不一致 |
| 编辑回款时改开票 |
草稿/审批中状态可修改关联开票,改后重新按新开票校验金额 |
前端缺口(需新建)
后端开票模块已完整(含审批流程、附件上传),但前端尚无开票页面与 API,需前端新建。
- 开票管理页:
views/crm/invoice/(列表、创建/编辑、审批提交、发票附件上传与展示)。
- 开票 API:
api/crm/invoice/(page / get / create / update / delete / submit / audit-count / export-excel / simple-list)。
- 回款表单开票选择器:选合同后调用
/crm/invoice/simple-list?contractId=,展示"开票编号 / 发票号码 / 开票金额 / 剩余可回款",选中后预填金额。
- 菜单:已由后端 SQL 配置完成(营销管理 -> 开票管理,
component = crm/invoice/index),前端建好页面后菜单即可用。
注意事项
invoiceId、planId 均为**选填**;填了开票就按开票校验,不填只受合同金额上限约束。
invoice、remainingInvoicePrice、hasAttachment 均为后端计算的只读字段,前端**不要**提交。
- 回款金额建议在选中开票后预填为
remainingInvoicePrice,避免超限被后端拦截。
- 存量回款数据若未关联开票(
invoiceId 为空),编辑保存时不再被要求补选开票。
- 开票列表展示"剩余可回款金额"时,文案建议用"剩余可回款金额(含审批中)"避免歧义,与合同"已开票金额(含审批中)"口径一致。