# 酒店-餐厅对账功能 > status: in-progress > created: 2026-09-30 > complexity: ⭐⭐⭐中等 > 需求依据:用户口述 + 需求汇总讨论(2026-09-30) --- ## 1. 背景与目标 ### 1.1 业务背景 酒店与餐厅为独立法人实体(同一老板、不同公司),属于合作关系。顾客在酒店房间扫码点餐,钱付给酒店(通过支付宝等渠道)。酒店需要**按月**与餐厅对账,确认应付金额后付款给餐厅。 ### 1.2 目标 - 酒店端按月自动生成对账单,汇总该月顾客点餐订单 - 退款订单单独标注,系统提供「排除」能力(排除后自动重算应付金额) - 餐厅端可查看、确认对账单 - 双方均可导出 Excel - 对账单状态流转:待确认 → 已确认 → 已结算 ### 1.3 不做的事 - ❌ 不实现平台抽成/服务费计算(暂不扣除) - ❌ 不实现线上签字/电子签章 - ❌ 不按餐厅维度拆分(目前只有一个餐厅) - ❌ 不改动现有订单模块逻辑 --- ## 2. 多租户架构(方案一:受控跨租户) 对账单数据归属**酒店租户**,餐厅通过后端受控跨租户访问。 ``` 酒店端(tenant_id = A): 生成对账单 / 排除订单 / 标记结算 / 导出 → 正常操作,TenantLine 自动追加 tenant_id = A 餐厅端(tenant_id = B): 查看对账单 / 确认 / 导出 → 后端 TenantContextHolder.executeWithTenant(A, ...) 切到酒店租户 → 仅暴露对账相关接口,不暴露订单/支付等其他数据 ``` 安全边界: - 餐厅角色仅配 `hotel:reconciliation:partner:*` 权限 - 餐厅仅能访问 `/hotel/reconciliation/partner/**` 专用接口 - 跨租户接口内部写死只查对账相关表 --- ## 3. 功能点 ### 3.1 酒店端 | # | 功能 | 说明 | |---|------|------| | F1 | 生成对账单 | 选月份 → 自动拉取该月已完成订单(status=6),生成对账单 | | F2 | 对账单列表 | 按月查看,状态筛选(待确认/已确认/已结算) | | F3 | 对账单详情 | 查看每笔订单明细:订单号、房间号、联系人、金额、订单状态、退款状态 | | F4 | 排除订单 | 对争议订单点击「排除」,排除后自动重算应付金额 | | F5 | 导出 Excel | 导出对账单明细(含排除标记) | | F6 | 标记已结算 | 餐厅确认后,酒店财务标记结算完成,填写结算备注 | ### 3.2 餐厅端 | # | 功能 | 说明 | |---|------|------| | F7 | 查看对账单列表 | 只看到「已确认」和「已结算」的对账单(待确认的还没提交) | | F8 | 查看对账单详情 | 查看明细(含被排除的订单,排除订单标注) | | F9 | 确认对账单 | 核对无误后点击确认 | | F10 | 导出 Excel | 同酒店端导出内容 | --- ## 4. 业务规则 | 规则 | 内容 | |------|------| | R1 | 对账范围:仅顾客点餐订单(`hotel_order` 中 `status = 6` 已完成的订单) | | R2 | 对账单编号格式:`DZ-YYYYMM-NNN`(如 `DZ-202609-001`) | | R3 | 同一月份只能生成一张对账单(重复生成提示已存在) | | R4 | 退款订单默认包含在对账单中,酒店可手动排除 | | R5 | 排除订单需填写排除原因 | | R6 | 应付金额 = 订单总额 - 排除金额(自动重算) | | R7 | 状态流转:待确认(0) → 已确认(1) → 已结算(2),单向不可逆 | | R8 | 餐厅端只能看到「已确认」和「已结算」状态的对账单 | | R9 | 只有「已确认」状态的对账单才能被酒店标记为「已结算」 | | R10 | 对账单生成后,对应的订单数据快照到明细表,后续订单状态变更不影响已生成的对账单 | --- ## 5. 数据库设计 ### 5.1 hotel_reconciliation(对账单主表) | 字段 | 类型 | 说明 | |------|------|------| | id | bigint NOT NULL | 主键(雪花算法) | | tenant_id | bigint NOT NULL DEFAULT 1 | 租户ID(酒店租户) | | reconciliation_no | varchar(20) NOT NULL | 对账单编号(DZ-YYYYMM-NNN) | | period_start | date NOT NULL | 对账周期开始 | | period_end | date NOT NULL | 对账周期结束 | | order_count | int NOT NULL DEFAULT 0 | 订单总笔数(含排除) | | total_amount | decimal(10,2) NOT NULL DEFAULT 0 | 订单总额 | | excluded_count | int NOT NULL DEFAULT 0 | 排除笔数 | | excluded_amount | decimal(10,2) NOT NULL DEFAULT 0 | 排除金额 | | settlement_amount | decimal(10,2) NOT NULL DEFAULT 0 | 应付金额 = total - excluded | | status | tinyint NOT NULL DEFAULT 0 | 0=待确认 / 1=已确认 / 2=已结算 | | confirmed_by | bigint DEFAULT NULL | 确认人 | | confirmed_time | datetime DEFAULT NULL | 确认时间 | | settled_by | bigint DEFAULT NULL | 结算操作人 | | settled_time | datetime DEFAULT NULL | 结算时间 | | settled_remark | varchar(500) DEFAULT NULL | 结算备注 | | del_flag | bigint NOT NULL DEFAULT 0 | 逻辑删除 | | create_by / create_time / create_dept / update_by / update_time | — | 审计字段 | ### 5.2 hotel_reconciliation_item(对账单明细) | 字段 | 类型 | 说明 | |------|------|------| | id | bigint NOT NULL | 主键 | | tenant_id | bigint NOT NULL DEFAULT 1 | 租户ID | | reconciliation_id | bigint NOT NULL | 对账单ID | | order_id | bigint NOT NULL | 关联 hotel_order.id | | order_no | varchar(30) | 冗余订单号 | | room_no | varchar(10) | 冗余房间号 | | contact_name | varchar(50) | 联系人 | | pay_amount | decimal(10,2) | 实付金额 | | order_status | tinyint | 订单状态(冗余快照) | | refund_status | tinyint | 退款状态(冗余快照,0/1/2) | | excluded | tinyint NOT NULL DEFAULT 0 | 是否排除(0=否 / 1=是) | | exclude_reason | varchar(200) DEFAULT NULL | 排除原因 | | del_flag | bigint NOT NULL DEFAULT 0 | 逻辑删除 | | create_by / create_time / create_dept / update_by / update_time | — | 审计字段 | ### 5.3 字典 | 字典类型 | dict_value | dict_label | list_class | |---------|-----------|-----------|-----------| | hotel_reconciliation_status | 0 | 待确认 | warning | | hotel_reconciliation_status | 1 | 已确认 | primary | | hotel_reconciliation_status | 2 | 已结算 | success | --- ## 6. 后端接口设计 ### 6.1 酒店端(/hotel/reconciliation) | 方法 | 路径 | 说明 | 权限 | |------|------|------|------| | GET | /page | 对账单分页列表 | hotel:reconciliation:query | | GET | /detail | 对账单详情(含明细列表) | hotel:reconciliation:query | | POST | /generate | 生成对账单 | hotel:reconciliation:generate | | POST | /excludeItem | 排除/恢复明细 | hotel:reconciliation:exclude | | POST | /settle | 标记已结算 | hotel:reconciliation:settle | | GET | /export | 导出 Excel | hotel:reconciliation:export | ### 6.2 餐厅端(/hotel/reconciliation/partner) | 方法 | 路径 | 说明 | 权限 | |------|------|------|------| | GET | /page | 对账单分页列表(仅已确认+已结算) | hotel:reconciliation:partner:query | | GET | /detail | 对账单详情 | hotel:reconciliation:partner:query | | POST | /confirm | 确认对账单 | hotel:reconciliation:partner:confirm | | GET | /export | 导出 Excel | hotel:reconciliation:partner:export | --- ## 7. 前端页面设计 ### 7.1 酒店端 reconciliation.vue - AiCrudPage 列表(隐藏新增/批量删除/选择列) - 工具栏:生成对账单按钮 - 搜索筛选:状态(DictSelect)、月份范围 - 表格列:对账单编号、周期、订单笔数、总额、排除笔数/金额、应付金额、状态(DictTag)、操作 - 操作列:详情(text-info)、排除管理(text-warning,仅待确认)、导出(text-success)、确认提交(仅待确认→提交给餐厅看)、标记结算(text-primary,仅已确认) - 详情弹窗:汇总信息 + 明细表格(排除订单灰显+标注原因) - 排除弹窗:选择要排除的订单 + 填写原因 ### 7.2 餐厅端 reconciliationPartner.vue - AiCrudPage 列表(只读,隐藏新增/批量删除/选择列) - 搜索筛选:状态(仅已确认+已结算) - 表格列:同酒店端(去掉排除管理操作) - 操作列:详情(text-info)、确认(text-success,仅已确认)、导出(text-success) - 详情弹窗:同酒店端(排除订单灰显标注) --- ## 8. 菜单与权限 ``` 对账管理(一级菜单,sort=12,与餐厅管理同级) ├── 对账单(酒店端) path=/hotel/reconciliation component=hotel/reconciliation │ └── 按钮权限:hotel:reconciliation:query / generate / exclude / settle / export / submit └── 对账单(餐厅端) path=/hotel/reconciliation/partner component=hotel/reconciliationPartner └── 按钮权限:hotel:reconciliation:partner:query / confirm / export ``` --- ## 9. Excel 导出配置 config_key: `hotel_reconciliation_export` data_source_bean: `hotelReconciliationServiceImpl` query_method: `queryExportList` 导出列:对账单编号、周期、订单笔数、总额、排除笔数、排除金额、应付金额、状态、确认时间、结算时间 --- ## 10. 技术决策 | 决策 | 说明 | |------|------| | 多租户方案 | 方案一:受控跨租户。对账单归酒店租户,餐厅通过 `TenantContextHolder.executeWithTenant()` 访问 | | 对账单编号生成 | 按月份查当前最大序号 +1,格式 `DZ-YYYYMM-NNN` | | 订单数据快照 | 生成对账单时将订单关键信息复制到 `hotel_reconciliation_item`,后续订单变更不影响已生成对账单 | | 退款订单处理 | 默认包含,酒店可排除;排除后自动重算应付金额 | | 餐厅可见范围 | 餐厅只能看到「已确认」和「已结算」的对账单,酒店需先「提交」才推送给餐厅 | | 导出方式 | 复用 `sys_excel_export_config` + `sys_excel_column_config` 配置化导出 | --- ## 11. 对现有模块的影响 | 模块 | 影响 | |------|------| | hotel_order | **只读**,生成对账单时 SELECT 该月已完成订单 | | hotel_order_item | **只读**,取明细金额 | | 租户/角色/菜单 | 新增对账菜单 + 按钮权限(Flyway 脚本) | | 现有代码 | **零改动**,纯增量开发 | --- ## 12. 代码结构 ``` reconciliation/ ├── controller/ │ ├── HotelReconciliationController.java # 酒店端 /hotel/reconciliation/** │ └── HotelReconciliationPartnerController.java # 餐厅端 /hotel/reconciliation/partner/** ├── domain/ │ ├── HotelReconciliation.java │ └── HotelReconciliationItem.java ├── dto/ │ └── ReconciliationGenerateDTO.java # 生成请求(yearMonth) ├── vo/ │ ├── HotelReconciliationVO.java │ └── ReconciliationDetailVO.java # 含明细列表 ├── mapper/ │ ├── HotelReconciliationMapper.java │ └── HotelReconciliationItemMapper.java └── service/ ├── HotelReconciliationService.java └── impl/ └── HotelReconciliationServiceImpl.java ``` 前端: - `forge-admin-ui/src/views/hotel/reconciliation.vue` — 酒店端 - `forge-admin-ui/src/views/hotel/reconciliationPartner.vue` — 餐厅端 - `forge-admin-ui/src/api/hotel.js` — 追加对账相关 API 函数