日期:2026-06-17
状态:已实现
需求来源:客户在「满月待办管理」中新增开票申请;财务在「缴退费财务确认」中处理并回传发票。
关联页面:
web-admin/src/views/cell-storage/protocol-audit/FullmoonTodoTab.vue(业务发起 + 查看)web-admin/src/views/cell-storage/payment-confirm/index.vue(新增 Tab)web-admin/src/views/cell-storage/payment-confirm/InvoiceRequestTab.vue参考实现:
FullmoonTodoTab.vueRefundConfirmTab.vueProtocolFinanceConfirmFields + finance-attachments.tsbiz_channel_invoice / biz_checkup_institution_invoice细胞存储「采集协议单管理」→「满月待办管理」目前已有保险办理能力。客户希望对已财务确认的缴费发起开票申请,由财务集中开票并上传发票附件,业务侧可查看反馈。
目标:
Σ transfer_amount),明细行金额只读,合计只读。已确认的产品决策:
| 议题 | 决策 |
|---|---|
| 申请时开票信息(抬头、税号等) | 提供完整字段区块,全部选填 |
| 财务完成开票 | 仅上传发票附件 + 财务备注,不填发票号/开票日期等结构化字段 |
| 申请与缴费关系 | 主表 + 明细子表:一次申请可含 1~N 条缴费明细,合并开一张发票;子表保证每条明细不重复纳入 |
| 财务驳回流程 | 本期不做;仅 待开票 → 已开票 两态 |
biz_collection_protocol(采集协议单)
└── biz_protocol_payment(缴费主表)
└── biz_protocol_payment_detail(缴费明细)
└── biz_protocol_invoice_request_item(开票申请明细,N:1)
└── biz_protocol_invoice_request(开票申请主表,一张发票)
| 角色 | 菜单路径 | 现状 |
|---|---|---|
| 业务 | 细胞存储 → 采集协议单管理 → 满月待办管理 | 列表 + 办理保险 |
| 财务 | 细胞存储 → 缴退费财务确认 | Tab:缴费确认 | 退费确认 |
docs/中科兴皖需求V0.3.md §2.2 已描述缴费确认、退费确认、满月保险,未描述开票申请。本设计为新增能力,不改变既有缴退费状态机。
| 状态码 | 含义 | 触发 |
|---|---|---|
dkp |
待开票 | 业务提交开票申请 |
ykp |
已开票 | 财务上传发票附件并确认 |
biz_protocol_payment_detail.pay_status = yjf(已缴费)dfj、jfqrz、tfqrz、ytf,或该明细已出现在任一有效申请的子表中(主表 del_flag=0 且 status IN (dkp, ykp))业务(满月待办 · 同一弹窗)
→ 多选 1~N 条可开票缴费明细 + 选填开票信息
→ 一次提交 → 生成 1 条 dkp 申请(含 N 条明细子表)
→ 主表 invoice_amount = 各期实缴之和
财务(缴退费财务确认 · 开票申请 Tab)
→ 待开票列表(一条申请对应一张待开发票)
→ 查看申请内各期明细 + 合计金额
→ 上传 1 份发票附件 + 财务备注 → status=ykp
同时满足:
payment_detail.collection_protocol_id = 当前协议单pay_status = yjfpayment_detail_id 未出现在任何有效申请的子表 biz_protocol_invoice_request_item 中tenant_no 与当前用户租户一致transfer_amount,申请时只读invoice_amount = 所选明细 transfer_amount 之和,主表只读展示line_amount 快照;主表 invoice_amount = Σ line_amounttransfer_amount| 场景 | 行为 |
|---|---|
| 趸交(dj) | 1 条 yjf 明细 → 1 条申请、1 行子表 |
| 分期(fq) | 可只开第 1 期;也可多选多期一次提交,合并为 1 条申请、1 张发票 |
| 一次多选 N 期 | 1 条主表申请 + N 行子表;财务待办 1 条;发票附件 1 份 |
| 已开过票的期数 | 不可再勾选(已在其他有效申请的子表中) |
| 剩余期数 | 可另起一次新申请(例如第 1~2 期已开,第 3 期单独再申请) |
弹窗展示:已选 N 期 · 合计开票金额 ¥xxx。
必选:
payment_detail_ids(多选,至少 1 条;el-table 勾选列)选填(写入主表申请):
| 展示标签 | 字段 | 说明 |
|---|---|---|
| 发票抬头 | invoice_title |
对齐渠道开票信息 |
| 税号 | tax_no |
|
| 单位地址 | company_address |
|
| 电话 | company_phone |
|
| 开户银行 | bank_name |
|
| 银行账号 | bank_account |
|
| 申请备注 | apply_remark |
弹窗中同步只读展示:客户姓名、协议号、期数、应缴/实缴金额、转账时间、转账方式。
必填:
invoice_attachments(至少 1 个附件,逗号分隔 MinIO URL)选填:
finance_remark不提供:发票号码、开票日期、发票类型等输入项。
ytf(已退费)明细不可出现在可开票列表ykp 后发生退费:本期不实现发票冲红/作废;由线下处理(范围外)biz_protocol_invoice_request一张物理发票对应一条申请主记录。
CREATE TABLE `biz_protocol_invoice_request` (
`id` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '主键ID',
`collection_protocol_id` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '采集协议单ID',
`invoice_amount` decimal(18,2) NOT NULL COMMENT '开票合计金额(子表实缴之和)',
`invoice_title` varchar(200) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '发票抬头',
`tax_no` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '税号',
`company_address` varchar(512) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '单位地址',
`company_phone` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '电话',
`bank_name` varchar(200) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '开户银行',
`bank_account` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '银行账号',
`apply_remark` varchar(512) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '申请备注',
`invoice_attachments` text COLLATE utf8mb4_unicode_ci COMMENT '财务上传发票附件逗号分隔URL',
`finance_remark` varchar(512) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '财务备注',
`status` varchar(8) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'dkp' COMMENT 'dkp待开票 ykp已开票',
`finance_handle_time` datetime DEFAULT NULL COMMENT '财务处理时间',
`tenant_no` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
`order_num` int(11) DEFAULT NULL COMMENT '排序号',
`remark` varchar(512) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '备注',
`create_by` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '创建人id',
`create_dept_id` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '创建人部门ID',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '更新人id',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`del_flag` tinyint(4) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
PRIMARY KEY (`id`),
KEY `idx_inv_req_protocol` (`collection_protocol_id`,`del_flag`),
KEY `idx_inv_req_status` (`tenant_no`,`status`,`del_flag`,`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采集协议单开票申请主表';
biz_protocol_invoice_request_item申请与缴费明细的多对一关联;每条缴费明细在有效申请中最多出现一次。
CREATE TABLE `biz_protocol_invoice_request_item` (
`id` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '主键ID',
`invoice_request_id` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '开票申请主表ID',
`payment_id` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '缴费主表ID',
`payment_detail_id` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '缴费明细ID',
`installment_no` int(11) DEFAULT NULL COMMENT '期数快照,趸交为空',
`line_amount` decimal(18,2) NOT NULL COMMENT '该行开票金额(实缴快照)',
`tenant_no` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
`order_num` int(11) DEFAULT NULL COMMENT '排序号',
`remark` varchar(512) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '备注',
`create_by` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '创建人id',
`create_dept_id` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '创建人部门ID',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '更新人id',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`del_flag` tinyint(4) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
PRIMARY KEY (`id`),
KEY `idx_inv_item_req` (`invoice_request_id`,`del_flag`),
KEY `idx_inv_item_detail` (`payment_detail_id`,`del_flag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采集协议单开票申请明细';
唯一性:创建时校验 payment_detail_id 不得存在于任何有效主表(status IN (dkp,ykp), del_flag=0)下的有效子表行中。
collection_protocol_idpayment_detail_id + 关联主表状态installmentSummary(如「第1、2、3期」)及 itemCount,详情展开子表明细遵循 database-conventions:业务字段 → 公共字段。
路由注册:app/api/collection_protocol.py(或独立 protocol_invoice.py,与现有缴退费接口同模块)。
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /web/admin/collection-protocols/{protocolId}/invoice-eligible-payments |
可开票缴费明细列表 |
| GET | /web/admin/collection-protocols/{protocolId}/invoice-requests |
某协议单开票申请历史 |
| POST | /web/admin/collection-protocols/{protocolId}/invoice-requests |
提交开票申请(paymentDetailIds[] → 1 主表 + N 子表) |
| GET | /web/admin/protocol-invoice-requests |
财务列表(status=dkp\|ykp,分页筛选) |
| GET | /web/admin/protocol-invoice-requests/pending-count |
待开票数量(Tab 角标) |
| PUT | /web/admin/protocol-invoice-requests/{id}/complete |
财务确认已开票 |
status:dkp / ykpkeyword:母亲姓名、身份证号、新生儿姓名、新生儿身份证号(与缴退费财务确认一致)create_time 范围(可选)关联协议单与客户信息,供列表/卡片展示:
motherName、motherIdCard、newbornName、protocolNoinvoiceAmount(合计)、itemCount、installmentSummary(如「第1、2、3期」)items[]:installmentNo、lineAmount、transferTime、transferType 等status、createTime、financeHandleTimetenant_no 来自当前用户apply_data_scope 对齐 list_receipt_confirmed_detailspaymentDetailIds 非空、无重复;每条明细满足 §4.1;同事务插入 1 主表 + N 子表;金额校验见 §4.2dkp 可完成;invoice_attachments 非空_row_to_dict 与 Schema_invoice_request_to_dict + _invoice_request_item_to_dict;详情/列表返回嵌套 itemsformData 对齐python scripts/check_field_consistency.py| 区域 | 模式 | 参考 |
|---|---|---|
| 满月待办开票 | P06 复杂列表 + 弹窗 | FullmoonTodoTab.vue |
| 财务开票 Tab | P21 财务确认双区(待办 + 已办) | RefundConfirmTab.vue |
FullmoonTodoTab.vue操作列(fixed="right",min-width 增至约 320px):
交互决策(2026-06-17):不单独提供「查看开票」按钮。用户只点「开票申请」,弹窗内上半区查看历史、下半区发起新申请。
统一弹窗「开票申请」(dialog-form-layout,建议 width 约 800~900px):
打开时并行请求:
GET .../invoice-requests(历史)GET .../invoice-eligible-payments(可新开票的缴费明细)弹窗自上而下分三块:
| 区块 | 内容 | 说明 |
|---|---|---|
| 摘要 | 只读:客户姓名、协议号、新生儿等 | 固定顶部 |
| 申请记录 | el-table |
申请时间、包含期数(installmentSummary)、合计金额、状态 Tag、财务处理时间;ykp 展示发票附件;可展开查看各行期数/金额 |
| 新增申请 | 表单区 | 有可开票明细时展示;否则展示提示「暂无可开票缴费记录」并隐藏提交 |
新增申请表单(label-position="top"、form-grid-2):
el-table 多选勾选列;已开过票 / 非 yjf 的行不可选)已选 N 条 · 合计 ¥xxx,只读)底栏:取消 / 提交申请(生成 1 条合并申请)
列表列(可选增强):
1/3 已开票,非必须首期实现payment-confirm/index.vue:
invoicePendingBadge,挂载时拉取 pending-count<InvoiceRequestTab v-if="mainTab === 'invoice'" @action-done="loadTabPendingCounts" />InvoiceRequestTab.vue(结构对齐 RefundConfirmTab.vue):
| 区块 | 内容 |
|---|---|
| 待开票 | 卡片网格 + 关键词筛选 + 分页;操作「处理开票」 |
| 已开票 | 表格 + 筛选 + 分页;操作「查看」 |
处理弹窗:
查看弹窗(已开票):只读展示全部信息 + 附件。
dkp → warning 待开票,ykp → success 已开票@element-plus/icons-vue 图标modal-class="protocol-dialog-mask"formatMoneyDisplay + ¥ 前缀web-admin/src/api/collection-protocol.ts 新增对应 fetch* 函数。
cell-storage:fullmoon-todo:list;若需细粒度可增加 cell-storage:fullmoon-todo:invoicecell-storage:payment-confirm:invoice| 场景 | 预期 |
|---|---|
| 趸交已缴费 | 可发起 1 次申请,金额=实缴 |
| 分期 3 期均已缴费 | 可一次多选 3 期 → 1 条申请、合计金额=三期实缴之和、财务 1 份附件 |
| 分期部分已开 | 第 1~2 期已在申请 A 中,则仅第 3 期可勾选并另起申请 B |
| 多期合并 | 子表 3 行、主表 1 行;installmentSummary=「第1、2、3期」 |
| 同一明细重复申请 | 第二次提交失败 |
| 未缴费 / 确认中明细 | 不出现在可开票列表 |
| 已退费明细 | 不可申请 |
| 财务无附件提交 | 校验失败 |
| 财务完成后业务查看 | 可见附件与备注 |
| 租户 / 数据权限 | 跨租户不可见 |
| 层级 | 文件 |
|---|---|
| SQL | docs/sql/protocol_invoice_request.sql(主表 + 子表) |
| Backend Model | backend/app/models/models.py |
| Backend CRUD | backend/app/crud/collection_protocol.py 或新文件 |
| Backend API | backend/app/api/collection_protocol.py |
| Backend Schema | backend/app/schemas/collection_protocol.py |
| Frontend API | web-admin/src/api/collection-protocol.ts |
| Frontend 业务 | FullmoonTodoTab.vue |
| Frontend 财务 | InvoiceRequestTab.vue、payment-confirm/index.vue |
完成后执行 ./scripts/update-graph.sh frontend 与 backend(如有新模块)。
| 日期 | 决策 |
|---|---|
| 2026-06-17 | 开票信息字段提供但全部选填 |
| 2026-06-17 | 财务仅上传附件 + 备注 |
| 2026-06-17 | 两态流转 dkp/ykp;满月待办单一「开票申请」弹窗(申请+查看) |
| 2026-06-17 | 缴费明细支持多选;一次提交生成 1 条申请 |
| 2026-06-17 | 多期合并一张发票:主表+子表;财务 1 份附件;子表防重复纳入 |