From c5a6d1e458572c08728605ef78d268a007ffd82b Mon Sep 17 00:00:00 2001 From: amos Date: Mon, 1 Dec 2025 17:54:53 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E9=A1=B9=E7=9B=AE=E7=BB=86?= =?UTF-8?q?=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +- docs/BUSINESS_MODEL_DESIGN.md | 526 ++++++++++++++++++++++++++++++++++ 2 files changed, 529 insertions(+), 1 deletion(-) create mode 100644 docs/BUSINESS_MODEL_DESIGN.md diff --git a/.gitignore b/.gitignore index 6d4eefb..3f68da2 100644 --- a/.gitignore +++ b/.gitignore @@ -40,4 +40,6 @@ logs/ ### SQL Files ### *.sql -*.md \ No newline at end of file +*.md +# 允许 docs 目录下的文档 +!docs/**/*.md \ No newline at end of file diff --git a/docs/BUSINESS_MODEL_DESIGN.md b/docs/BUSINESS_MODEL_DESIGN.md new file mode 100644 index 0000000..1fbfb70 --- /dev/null +++ b/docs/BUSINESS_MODEL_DESIGN.md @@ -0,0 +1,526 @@ +# 业务模型设计文档 + +> **项目**: Travel (Tech Mall) - 旅游线路交易系统 +> **最后更新**: 2025-12-01 +> **状态**: 设计确认 ✅ + +--- + +## 📋 业务概述 + +本系统是一个**旅游线路预订和票务管理平台**,支持固定班次和滚动班次两种运营模式,为用户提供线路查询、在线下单、支付、电子凭证和核销等完整服务。 + +--- + +## 🎯 核心业务共识 + +### 1. 班次类型 + +#### 固定班次 (FixedSchedule) +- 管理后台设置具体出行时间段 +- 每个班次有独立的座位限制 +- 示例:2025-12-01 08:00 出发,2025-12-01 18:00 返回 + +#### 滚动班次 (RollingSchedule) +- 按固定频率发车(如每 5 分钟一班) +- 配置运营时间段和单次座位数 +- 示例:08:00-18:00 运营,每 5 分钟一班,每班 20 座 + +### 2. 库存管理策略 + +**方案**: 线路级别库存 + 班次级别座位限制 + +``` +线路总库存池: 100 张 +├── 固定班次 A (08:00): 座位限制 40 座 +├── 固定班次 B (14:00): 座位限制 40 座 +└── 滚动班次: 单次座位 20 座 +``` + +**规则**: +- ✅ 线路维护总库存池 +- ✅ 固定班次设置座位上限(不能超过线路库存) +- ✅ 滚动班次按单次座位数消耗库存 +- ✅ 所有班次共享线路库存池 +- ✅ 库存操作需记录日志(锁定、扣减、释放、退还) + +### 3. 票种系统 + +支持多种票种,每种票种价格不同: + +| 票种代码 | 票种名称 | 价格策略 | 适用人群 | +|---------|---------|---------|---------| +| ADULT | 成人票 | 基准价格 100% | 成年人 | +| CHILD | 儿童票 | 基准价格 50% | 儿童 | +| STUDENT | 学生票 | 基准价格 70% | 学生 | +| SENIOR | 老人票 | 基准价格 80% | 老年人 | + +### 4. 座位管理 + +**明确**: 本系统**不提供座位选择功能** +- 无需座位号管理 +- 先到先得原则 +- 仅控制总人数 + +### 5. 购票流程 + +用户购票时必须选择: +1. **出行日期** - 具体哪一天出行 +2. **班次** - 选择固定班次或滚动班次 +3. **票种** - 成人/儿童/学生/老人 +4. **购买数量** - 购买张数 + +### 6. 多租户 + +**明确**: 系统**不需要考虑多租户**架构 + +--- + +## 🏗️ 领域模型 + +### 核心实体关系 + +```mermaid +graph TB + subgraph "线路域 Route Domain" + R[线路 Route
- 线路编码
- 线路名称
- 起止点
- 总库存] + FS[固定班次 FixedSchedule
- 班次编号
- 出发/到达时间
- 座位限制
- 票价配置] + RS[滚动班次 RollingSchedule
- 滚动班次编号
- 运营时间段
- 发车间隔
- 单次座位数
- 票价配置] + IL[库存日志 InventoryLog
- 操作类型
- 操作数量
- 关联订单] + + R --> FS + R --> RS + R --> IL + end + + subgraph "交易域 Trade Domain" + O[订单 Order
- 订单号
- 用户编号
- 班次信息
- 票种/数量
- 订单状态
- 金额] + P[支付 Payment
- 支付单号
- 支付方式
- 支付状态
- 支付金额] + RF[退款 Refund
- 退款单号
- 退款状态
- 退款金额] + + O --> P + O --> RF + end + + subgraph "履约域 Perform Domain" + T[凭证 Ticket
- 凭证号
- 订单号
- 票种
- 凭证状态
- 可用日期] + V[核销记录 Verification
- 凭证号
- 核销时间
- 核销地点] + + T --> V + end + + FS -.订购.-> O + RS -.订购.-> O + O -.生成.-> T + + style R fill:#e1f5ff + style O fill:#fff4e1 + style T fill:#f0ffe1 +``` + +--- + +## 📊 核心实体详细设计 + +### 1. 线路 (Route) + +**表名**: `route` + +| 字段 | 类型 | 说明 | +|-----|------|-----| +| id | BIGINT | 主键 | +| route_code | VARCHAR(50) | 线路编码,唯一 | +| route_name | VARCHAR(200) | 线路名称 | +| start_point | VARCHAR(100) | 出发地 | +| end_point | VARCHAR(100) | 目的地 | +| route_type | VARCHAR(20) | 线路类型:SHORT/MEDIUM/LONG | +| total_inventory | INT | 总库存数量 | +| remaining_inventory | INT | 剩余库存数量 | +| responsible_user | VARCHAR(50) | 责任用户 | +| status | VARCHAR(20) | 状态:ACTIVE/INACTIVE | +| create_time | DATETIME | 创建时间 | +| update_time | DATETIME | 更新时间 | +| deleted | TINYINT | 逻辑删除标识 | + +--- + +### 2. 固定班次 (FixedSchedule) + +**表名**: `fixed_schedule` + +| 字段 | 类型 | 说明 | +|-----|------|-----| +| id | BIGINT | 主键 | +| schedule_code | VARCHAR(50) | 班次编号,唯一 | +| route_code | VARCHAR(50) | 关联线路编码 | +| departure_time | DATETIME | 出发时间 | +| arrival_time | DATETIME | 到达时间 | +| seat_limit | INT | 座位限制 | +| remaining_seats | INT | 剩余座位 | +| adult_price | DECIMAL(10,2) | 成人票价 | +| child_price | DECIMAL(10,2) | 儿童票价 | +| student_price | DECIMAL(10,2) | 学生票价 | +| senior_price | DECIMAL(10,2) | 老人票价 | +| status | VARCHAR(20) | 状态:AVAILABLE/FULL/CANCELLED | +| create_time | DATETIME | 创建时间 | +| update_time | DATETIME | 更新时间 | +| deleted | TINYINT | 逻辑删除标识 | + +--- + +### 3. 滚动班次 (RollingSchedule) + +**表名**: `rolling_schedule` + +| 字段 | 类型 | 说明 | +|-----|------|-----| +| id | BIGINT | 主键 | +| rolling_schedule_code | VARCHAR(50) | 滚动班次编号,唯一 | +| route_code | VARCHAR(50) | 关联线路编码 | +| operation_mode | VARCHAR(20) | 运营模式:FIXED_INTERVAL | +| operation_start_time | TIME | 运营开始时间 | +| operation_end_time | TIME | 运营结束时间 | +| interval_minutes | INT | 发车间隔(分钟) | +| seats_per_batch | INT | 单次座位数 | +| adult_price | DECIMAL(10,2) | 成人票价 | +| child_price | DECIMAL(10,2) | 儿童票价 | +| student_price | DECIMAL(10,2) | 学生票价 | +| senior_price | DECIMAL(10,2) | 老人票价 | +| status | VARCHAR(20) | 状态:ACTIVE/INACTIVE | +| create_time | DATETIME | 创建时间 | +| update_time | DATETIME | 更新时间 | +| deleted | TINYINT | 逻辑删除标识 | + +--- + +### 4. 订单 (Order) + +**表名**: `order` + +| 字段 | 类型 | 说明 | +|-----|------|-----| +| id | BIGINT | 主键 | +| order_no | VARCHAR(50) | 订单号,唯一 | +| user_no | VARCHAR(50) | 用户编号 | +| route_code | VARCHAR(50) | 线路编码 | +| order_type | VARCHAR(20) | 订单类型:FIXED/ROLLING | +| schedule_code | VARCHAR(50) | 固定班次编号(固定班次时) | +| rolling_schedule_code | VARCHAR(50) | 滚动班次编号(滚动班次时) | +| travel_date | DATE | 出行日期 | +| ticket_type | VARCHAR(20) | 票种:ADULT/CHILD/STUDENT/SENIOR | +| quantity | INT | 购买数量 | +| unit_price | DECIMAL(10,2) | 单价 | +| original_amount | DECIMAL(10,2) | 原始金额 | +| actual_amount | DECIMAL(10,2) | 实付金额 | +| order_status | VARCHAR(20) | 订单状态 | +| create_time | DATETIME | 创建时间 | +| expire_time | DATETIME | 支付超时时间 | +| pay_time | DATETIME | 支付时间 | +| update_time | DATETIME | 更新时间 | +| deleted | TINYINT | 逻辑删除标识 | + +**订单状态枚举** (OrderStatus): +- `PENDING_PAYMENT` - 待支付 +- `PAID` - 已支付 +- `COMPLETED` - 已完成 +- `CANCELLED` - 已取消 +- `REFUNDING` - 退款中 +- `REFUNDED` - 已退款 + +--- + +### 5. 支付 (Payment) + +**表名**: `payment` + +| 字段 | 类型 | 说明 | +|-----|------|-----| +| id | BIGINT | 主键 | +| payment_no | VARCHAR(50) | 支付单号,唯一 | +| order_no | VARCHAR(50) | 关联订单号 | +| payment_method | VARCHAR(20) | 支付方式:ALIPAY/WECHAT/BANK | +| payment_amount | DECIMAL(10,2) | 支付金额 | +| payment_status | VARCHAR(20) | 支付状态 | +| third_party_no | VARCHAR(100) | 第三方支付流水号 | +| create_time | DATETIME | 创建时间 | +| pay_time | DATETIME | 支付完成时间 | +| update_time | DATETIME | 更新时间 | +| deleted | TINYINT | 逻辑删除标识 | + +--- + +### 6. 退款 (Refund) + +**表名**: `refund` + +| 字段 | 类型 | 说明 | +|-----|------|-----| +| id | BIGINT | 主键 | +| refund_no | VARCHAR(50) | 退款单号,唯一 | +| order_no | VARCHAR(50) | 关联订单号 | +| payment_no | VARCHAR(50) | 关联支付单号 | +| refund_amount | DECIMAL(10,2) | 退款金额 | +| refund_reason | VARCHAR(500) | 退款原因 | +| refund_status | VARCHAR(20) | 退款状态 | +| third_party_refund_no | VARCHAR(100) | 第三方退款流水号 | +| create_time | DATETIME | 创建时间 | +| refund_time | DATETIME | 退款完成时间 | +| update_time | DATETIME | 更新时间 | +| deleted | TINYINT | 逻辑删除标识 | + +> **TODO**: 退款详细规则待定 +> - 退款时效限制(出行前多久可退?) +> - 退款手续费计算规则 +> - 部分退票支持 +> - 库存回退处理 +> - 凭证状态更新 + +--- + +### 7. 凭证 (Ticket) + +**表名**: `ticket` + +| 字段 | 类型 | 说明 | +|-----|------|-----| +| id | BIGINT | 主键 | +| ticket_no | VARCHAR(50) | 凭证号,唯一 | +| order_no | VARCHAR(50) | 关联订单号 | +| route_code | VARCHAR(50) | 线路编码 | +| schedule_info | VARCHAR(200) | 班次信息(具体时间) | +| ticket_type | VARCHAR(20) | 票种 | +| ticket_status | VARCHAR(20) | 凭证状态 | +| issue_time | DATETIME | 出票时间 | +| usable_date | DATE | 可用日期 | +| verification_time | DATETIME | 核销时间 | +| create_time | DATETIME | 创建时间 | +| update_time | DATETIME | 更新时间 | +| deleted | TINYINT | 逻辑删除标识 | + +**凭证状态枚举** (TicketStatus): +- `UNUSED` - 未使用 +- `USED` - 已使用 +- `REFUNDED` - 已退票 +- `EXPIRED` - 已过期 + +--- + +### 8. 核销记录 (TicketVerification) + +**表名**: `ticket_verification` + +| 字段 | 类型 | 说明 | +|-----|------|-----| +| id | BIGINT | 主键 | +| ticket_no | VARCHAR(50) | 凭证号 | +| verification_time | DATETIME | 核销时间 | +| verification_location | VARCHAR(100) | 核销地点 | +| operator | VARCHAR(50) | 操作人 | +| create_time | DATETIME | 创建时间 | +| deleted | TINYINT | 逻辑删除标识 | + +--- + +### 9. 库存日志 (InventoryLog) + +**表名**: `inventory_log` + +| 字段 | 类型 | 说明 | +|-----|------|-----| +| id | BIGINT | 主键 | +| route_code | VARCHAR(50) | 线路编码 | +| operation_type | VARCHAR(20) | 操作类型:LOCK/DEDUCT/RELEASE/REFUND | +| related_order_no | VARCHAR(50) | 关联订单号 | +| quantity | INT | 操作数量 | +| before_amount | INT | 操作前库存 | +| after_amount | INT | 操作后库存 | +| operation_time | DATETIME | 操作时间 | +| operator | VARCHAR(50) | 操作人 | +| remark | VARCHAR(500) | 备注 | +| create_time | DATETIME | 创建时间 | +| deleted | TINYINT | 逻辑删除标识 | + +**操作类型枚举** (OperationType): +- `LOCK` - 锁定库存(下单时) +- `DEDUCT` - 扣减库存(支付成功) +- `RELEASE` - 释放库存(订单取消/超时) +- `REFUND` - 退还库存(退款成功) + +--- + +## 🔄 核心业务流程 + +### 购票流程 + +```mermaid +sequenceDiagram + participant U as 用户 + participant TC as Trade Controller + participant TS as Trade Service + participant RS as Route Service + participant MQ as RocketMQ + participant PS as Perform Service + + U->>TC: 1. 创建订单请求 + TC->>TS: 2. 处理订单 + + rect rgb(240, 248, 255) + Note over TS: LiteFlow 流程编排 + TS->>TS: 3. 参数校验 + TS->>RS: 4. 检查线路库存 + RS-->>TS: 库存充足 + TS->>RS: 5. 锁定库存 + RS->>RS: 记录库存日志(LOCK) + RS-->>TS: 锁定成功 + TS->>TS: 6. 创建订单(PENDING_PAYMENT) + end + + TS-->>U: 7. 返回订单信息 + + U->>TC: 8. 支付订单 + TC->>TS: 9. 处理支付 + TS->>TS: 10. 更新订单状态(PAID) + TS->>RS: 11. 扣减库存 + RS->>RS: 记录库存日志(DEDUCT) + TS->>MQ: 12. 发送支付成功消息 + + MQ->>PS: 13. 监听支付成功 + PS->>PS: 14. 生成电子凭证 + PS-->>U: 凭证生成完成 +``` + +### 核销流程 + +```mermaid +sequenceDiagram + participant D as 检票设备/APP + participant PS as Perform Service + + D->>PS: 1. 扫描凭证号 + PS->>PS: 2. 查询凭证信息 + + alt 凭证状态 = UNUSED + PS->>PS: 3. 更新凭证状态(USED) + PS->>PS: 4. 记录核销日志 + PS-->>D: ✅ 核销成功 + else 凭证状态 = USED + PS-->>D: ❌ 凭证已使用 + else 凭证状态 = REFUNDED + PS-->>D: ❌ 凭证已退票 + else 凭证状态 = EXPIRED + PS-->>D: ❌ 凭证已过期 + end +``` + +### 订单超时取消流程 + +```mermaid +sequenceDiagram + participant T as 定时任务 + participant TS as Trade Service + participant RS as Route Service + + T->>TS: 1. 扫描超时订单 + TS->>TS: 2. 查询 PENDING_PAYMENT 订单 + + loop 每个超时订单 + TS->>TS: 3. 更新订单状态(CANCELLED) + TS->>RS: 4. 释放库存 + RS->>RS: 5. 记录库存日志(RELEASE) + end +``` + +--- + +## 📋 业务规则清单 + +### 库存规则 +1. ✅ 线路总库存 ≥ 所有固定班次座位限制之和 +2. ✅ 下单时先锁定库存,支付成功后扣减库存 +3. ✅ 订单取消/超时,释放已锁定库存 +4. ✅ 退款成功,退还已扣减库存 +5. ✅ 所有库存操作必须记录日志 + +### 订单规则 +1. ✅ 订单创建后 30 分钟内未支付自动取消 +2. ✅ 订单状态流转:待支付 → 已支付 → 已完成 +3. ✅ 订单支付后才能生成凭证 +4. ✅ 一个订单对应多张凭证(根据购买数量) + +### 凭证规则 +1. ✅ 凭证号全局唯一 +2. ✅ 凭证绑定出行日期和班次信息 +3. ✅ 未使用的凭证才能核销 +4. ✅ 凭证核销后不可重复使用 + +### 票种规则 +1. ✅ 每个班次配置各票种价格 +2. ✅ 一个订单只能购买一种票种 +3. ✅ 票种价格独立设置,不强制比例 + +--- + +## 🎨 枚举类型定义 + +### OrderTypeEnum (订单类型) +```java +FIXED("FIXED", "固定班次订单"), +ROLLING("ROLLING", "滚动班次订单"); +``` + +### TicketTypeEnum (票种类型) +```java +ADULT("ADULT", "成人票"), +CHILD("CHILD", "儿童票"), +STUDENT("STUDENT", "学生票"), +SENIOR("SENIOR", "老人票"); +``` + +### OrderStatusEnum (订单状态) +```java +PENDING_PAYMENT("PENDING_PAYMENT", "待支付"), +PAID("PAID", "已支付"), +COMPLETED("COMPLETED", "已完成"), +CANCELLED("CANCELLED", "已取消"), +REFUNDING("REFUNDING", "退款中"), +REFUNDED("REFUNDED", "已退款"); +``` + +### TicketStatusEnum (凭证状态) +```java +UNUSED("UNUSED", "未使用"), +USED("USED", "已使用"), +REFUNDED("REFUNDED", "已退票"), +EXPIRED("EXPIRED", "已过期"); +``` + +### OperationTypeEnum (库存操作类型) +```java +LOCK("LOCK", "锁定库存"), +DEDUCT("DEDUCT", "扣减库存"), +RELEASE("RELEASE", "释放库存"), +REFUND("REFUND", "退还库存"); +``` + +--- + +## 🚀 后续待办事项 + +### 业务规则待明确 +- [ ] 退款时效规则(出行前多久可退?) +- [ ] 退款手续费计算规则 +- [ ] 是否支持部分退票 +- [ ] 凭证有效期规则 +- [ ] 库存预警机制 + +### 技术实现待补充 +- [ ] 分布式锁实现(防止超卖) +- [ ] 定时任务实现(订单超时取消) +- [ ] 消息幂等性处理 +- [ ] 分布式事务处理方案 + +--- + +> **文档维护**: 本文档应随业务演进持续更新 +> **最后审核**: 2025-12-01 +> **审核状态**: ✅ 业务方案已确认