Files
one-pipe-system/openspec/changes/add-employee-collection/design.md
2026-09-12 11:27:50 +08:00

89 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Context
员工代收款是 8 月迭代新增的财务能力,普通员工与超级管理员共用同一套接口,靠登录态区分数据范围。后台管理端需要新增三类页面,并复用已有的表格、搜索、详情与上传组件。`docs/admin-openapi.yaml` 未随仓库提供,接口字段以后端契约(需求文档 + 创建订单接口 OpenAPI 片段)为准,类型集中在一个文件便于联调收敛。
## Goals / Non-Goals
**Goals**
- 在财务管理下提供收款方式、员工代收款账单、核销申请三类页面。
- 复用 `ArtTableFullScreen``ArtSearchBar``ArtTableHeader``ArtTable``DetailPage``VoucherUpload``PaymentVoucherDialog``useCheckedColumns` 等既有组件与约定。
- 复用既有企微审批场景配置能力,仅新增业务类型。
**Non-Goals**
- 不实现后端接口、数据库、Worker、企微回调。
- 不实现 H5/C 端页面与支付流程。
- 不新增导出任务场景(需求文档未要求)。
## Decisions
### 接口契约
| 能力 | 关键字段 |
|---|---|
| 统一响应 | `{ code, data, msg, timestamp }` |
| 列表分页 | 账单列表返回 `{ items, total, page, size }`,取数处对 `items` / `list` / `records` 做兼容 |
| 收款方式 | `{ id, code, name, sort, enabled, remark, created_at, updated_at }`,列表接口返回 `{ items, page, size, total }`,支持 `page` / `page_size` / `enabled` / `keyword` 筛选 |
| 账单列表项 | `{ id, source_type, source_type_name, source_no, debtor_snapshot, customer_snapshot, receivable_amount, received_amount, reserved_amount, remaining_amount, status, status_name, approval_pending, closed_reason, created_at, updated_at }` |
| 账单详情 | `data``{ bill, refunds, allocations, applications }``refunds` 为退款冲销(`refund_id``source_order_id``refund_amount``reduced_amount``bill_receivable_amount``outcome_name``allocations` 为账单侧分摊(含 `application_id` / `application_status_name` / `attempt_id``applications` 内嵌该申请的 `attempts` |
| 账单统计 | `{ receivable_total, received_total, unsettled_total, pending_bill_count }` |
| 账单筛选 | `page``page_size``source_type``source_no``status``debtor_account_id``customer_id``created_from``YYYY-MM-DD`)、`created_to``YYYY-MM-DD` |
| 核销申请请求体 | `{ payment_method_id, paid_amount, paid_at, payer_name, external_transaction_no, payment_voucher_keys, remark, allocations: [{ bill_id, amount }], acting_reason }` |
| 核销申请列表项 | `{ id, applicant_account_id, acting_operator_id, payment_method_id, payment_method_name, paid_amount, payer_name, external_transaction_no, status, status_name, terminal_reason, decided_at, created_at, updated_at }` |
| 核销申请详情 | `data``{ application, allocations, attempts }``attempts` 保存每次提交的完整材料快照,重新提交不清空历史 |
账单状态为数字枚举 `0` 待核销 / `1` 部分核销 / `2` 已核销 / `3` 已关闭;申请状态为数字枚举 `0` 审批中 / `1` 已通过 / `2` 已驳回 / `3` 已撤销或已关闭;两者展示均优先使用后端 `status_name`
### 页面与路由组织
`/finance` 下新增:
| 路由 | 页面 | 说明 |
|---|---|---|
| `/finance/employee-collection/bills` | 员工代收款账单 | 统计 + 列表 |
| `/finance/employee-collection/bills/detail/:id` | 账单详情 | 隐藏菜单 |
| `/finance/employee-collection/applications` | 核销申请 | 列表 + 创建 |
| `/finance/employee-collection/applications/detail/:id` | 核销申请详情 | 隐藏菜单 |
| `/finance/employee-collection/payment-methods` | 收款方式管理 | 仅超管 |
账单与申请拆分为独立菜单,符合项目「列表页 + 详情页」的既有组织方式,避免单页堆叠过多交互。账单列表的「店铺」筛选用远程搜索复用 `ShopService.getShops`,与退款列表一致。
账单详情与核销申请详情保持只读:页面只在顶部保留「返回」导航,创建核销申请、关闭账单、修改并重新提交等操作入口统一放在列表页的操作列,详情页不出现业务操作按钮。
### 权限编码
新增 `src/config/constants/augustIteration.ts`,沿用 `模块:动作` 风格,例如 `employee_collection:bill_close``employee_collection:application_create`。页面级 `permissions` 用于菜单可见性,按钮级编码用于 `hasAuth()` / `v-permission`
### 金额、时间与附件
- 金额统一以「分」传输,展示时通过 `fenToYuan` / `formatCurrency` 转换,与退款、代理充值保持一致。
- 所有时间字段统一通过 `formatDateTime` 格式化为 `YYYY-MM-DD HH:mm:ss`,不在模板中直接输出后端原始时间字符串。
- 附件仅返回对象 Key`payment_voucher_keys`),展示复用 `PaymentVoucherDialog`,由预签名下载接口换取访问地址。
### 核销申请分摊
创建申请时按账单逐条录入核销金额,并填写付款事实(付款金额、付款方名称、付款时间、外部交易流水号),前端校验:
- 至少选择 1 张账单,最多 N 张;
- 单张核销金额不得大于账单未核销金额,且大于 0
- 付款金额(`paid_amount`,分)不得小于各账单分摊之和(允许存在差额);
- 超管代办时 `acting_reason` 必填;
- 付款凭证至少 1 个 Key。
提交成功后自动发起企微审批;仅已驳回申请可再次进入弹窗修改并重新提交,重新提交生成新的审批实例,历史审批记录只读展示。未配置企微审批场景时后端返回 503前端展示「企微审批场景未配置请联系管理员」并保留已填内容。
### 企微审批场景
`WecomBusinessType` 增加 `employee_collection_approval`,企微审批场景页面下拉新增「员工代收款审批」。模板控件同步、字段查询、字段映射保存全部复用既有 `WecomService`
### 订单付款凭证规则
线下订单创建时,满足「平台账号(`user_type` 为 1 或 2操作 + 非赠送套餐 + 实际收款金额大于 0」条件的订单会生成员工代收款账单此时 `payment_voucher_key` 非必填,字段结构不变,付款凭证改在核销申请中提交。前端以当前登录账号类型、所选套餐是否赠送、套餐有效价格(`effective_retail_price` / `suggested_retail_price` / `retail_price`)判断是否展示提示并放宽必填;赠送套餐或其他非平台账号的线下订单仍需上传凭证。
## Risks / Trade-offs
- **接口字段以契约文档为准**`docs/admin-openapi.yaml` 未入库,字段来自需求文档与创建订单接口片段;类型集中在一个文件,便于联调时收敛修改。
- **员工/超管同接口**:前端不做数据范围过滤,仅做展示与操作可见性控制,数据隔离以后端为准。
- **关闭账单与审批中申请**:前端依据 `approval_pending` 与状态字段禁用关闭按钮,最终一致性以后端校验为准。