简介
本设计文档聚焦于 DouPHP 优惠券功能模块的数据库表结构设计,围绕优惠券主表、领取/使用记录表以及订单关联表展开,详细说明优惠券类型、面额设置、使用条件、有效期管理、状态流转、领取限制与使用规则的数据建模方式,并提供表关系图与性能优化建议,面向电商运营人员与开发者提供完整参考。
项目结构与范围
- 优惠券主表定义与字段说明来源于模块备份 SQL 与系统表结构 SQL。
- 订单侧优惠券使用明细通过订单模块中的关联表体现。
- 业务逻辑(资格判定、折扣计算、状态判断)由服务层实现,并与表结构紧密对应。
graph TB
A["优惠券主表<br/>dou_coupon"] --> B["领取/使用记录表<br/>dou_coupon_log"]
A --> C["订单-优惠券关联表<br/>dou_order_coupon"]
B --> C
核心数据模型
本节对三张核心表进行结构化说明,涵盖字段含义、约束与业务语义。
-
优惠券主表(dou_coupon)
- 关键字段:id、name、coupon_sn、type、face_value、max_discount、limit_per_user、total_quantity、issued_quantity、is_stackable、is_first_order_only、condition、scope_type、scope_value、start_at、end_at、brief、image、sort、status、created_at
- 业务要点:
- type 支持“金额减免”和“百分比减免”,由表单校验限定为 money/percent。
- condition 为使用门槛金额;start_at/end_at 控制有效期。
- limit_per_user 控制每人限领数量;total_quantity/issued_quantity 控制总量与已发放量。
- is_stackable 控制是否可叠加;is_first_order_only 控制是否仅限首单。
- scope_type/scope_value 用于限定适用范围(如商品/分类等)。
-
领取/使用记录表(dou_coupon_log)
- 关键字段:id、user_id、coupon_id、claimed_at、used_at、order_sn、ip、status、created_at
- 业务要点:
- claimed_at 记录领取时间;used_at 记录使用时间;order_sn 关联订单号。
- status 表示该条记录的状态(例如未用、已用、过期等),配合服务层状态机展示。
-
订单-优惠券关联表(dou_order_coupon)
- 关键字段:id、order_id、coupon_id、coupon_log_id、amount、type、created_at
- 业务要点:
- amount 为该订单行使用的优惠金额;type 与券类型一致(money/percent)。
- 通过 order_id/coupon_id/coupon_log_id 建立订单、券模板、券实例之间的关联。
架构总览
优惠券系统的数据流与服务交互如下:
sequenceDiagram
participant U as "用户"
participant F as "前端/接口"
participant S as "优惠券服务"
participant DB as "数据库"
U->>F : 浏览/领取优惠券
F->>S : 查询可用券列表/领取
S->>DB : 读取 dou_coupon(有效期/状态/限额)
DB-->>S : 券信息
S->>DB : 写入 dou_coupon_log(领取记录)
DB-->>S : 成功
S-->>F : 返回券状态/列表
U->>F : 下单并选择优惠券
F->>S : 计算优惠/资格校验
S->>DB : 读取 dou_coupon/dou_coupon_log
S->>DB : 写入 dou_order_coupon(使用明细)
DB-->>S : 成功
S-->>F : 返回折后金额/使用结果
详细组件分析
优惠券主表(dou_coupon)设计
- 类型与面额
- type:枚举值 money/percent,分别表示固定金额减免与百分比减免。
- face_value:当 type=percent 时代表百分比数值;当 type=money 时代表减免金额。
- max_discount:百分比券的最大减免上限,防止过度折扣。
- 使用条件
- condition:满足订单金额达到该阈值方可使用。
- is_first_order_only:是否仅限首单使用。
- scope_type/scope_value:限定适用商品/分类等范围。
- 有效期与状态
- start_at/end_at:券的生效时间段。
- status:启用/禁用控制。
- 发放与限制
- total_quantity:发行总量;issued_quantity:已发放数量。
- limit_per_user:每人限领数量。
- is_stackable:是否允许与其他券叠加使用。
- 其他
- coupon_sn:唯一编号,便于追踪与展示。
- brief/image/sort:展示与排序相关字段。
classDiagram
class Coupon {
+int id
+string name
+string coupon_sn
+string type
+decimal face_value
+decimal max_discount
+smallint limit_per_user
+int total_quantity
+int issued_quantity
+tinyint is_stackable
+tinyint is_first_order_only
+decimal condition
+string scope_type
+text scope_value
+datetime start_at
+datetime end_at
+string brief
+string image
+tinyint sort
+tinyint status
+datetime created_at
}
领取/使用记录表(dou_coupon_log)设计
- 关键字段
- user_id:会员ID。
- coupon_id:券模板ID。
- claimed_at:领取时间。
- used_at:使用时间(为空表示未使用)。
- order_sn:使用时的订单号。
- ip:领取或使用时IP。
- status:记录级状态(结合服务层状态机)。
- created_at:创建时间。
- 业务要点
- 通过 claimed_at/used_at 区分领取与使用两个阶段。
- 与订单表通过 order_sn 关联,便于对账与统计。
classDiagram
class CouponLog {
+int id
+int user_id
+int coupon_id
+datetime claimed_at
+datetime used_at
+string order_sn
+string ip
+tinyint status
+datetime created_at
}
订单-优惠券关联表(dou_order_coupon)设计
- 关键字段
- order_id:订单ID。
- coupon_id:券模板ID。
- coupon_log_id:券实例ID(来自 dou_coupon_log)。
- amount:本次使用的优惠金额。
- type:券类型(money/percent)。
- created_at:创建时间。
- 业务要点
- 将订单与券的使用明细落库,支撑结算、退款、对账。
- 通过 idx_order 索引加速按订单查询。
classDiagram
class OrderCoupon {
+int id
+int order_id
+int coupon_id
+int coupon_log_id
+decimal amount
+string type
+datetime created_at
}
优惠券状态流转与资格判定
- 状态流转
- 未领取:不存在领取记录。
- 已领取:存在领取记录且未使用。
- 已使用:存在使用记录(used_at 非空)。
- 已过期:当前时间超过券有效期(end_at)。
- 资格判定
- 基于 dou_coupon 的 scope_type/scope_value/is_first_order_only/condition 等字段,结合购物车/订单金额判定是否可用。
- 百分比券受 max_discount 限制。
flowchart TD
Start(["开始"]) --> CheckClaim{"是否存在领取记录?"}
CheckClaim --> |否| NotGot["状态: 未领取"]
CheckClaim --> |是| CheckUsed{"是否存在使用记录?"}
CheckUsed --> |是| Used["状态: 已使用"]
CheckUsed --> |否| CheckExpire{"是否已过期?"}
CheckExpire --> |是| Expired["状态: 已过期"]
CheckExpire --> |否| Got["状态: 已领取"]
Used --> End(["结束"])
Expired --> End
Got --> End
NotGot --> End
折扣计算流程
- 输入:券ID、订单金额、用户ID。
- 步骤:
- 检查用户是否已领取该券。
- 校验券是否在有效期内且启用。
- 校验是否满足使用条件(condition、首单限制、适用范围等)。
- 根据 type 计算折扣:
- percent:按百分比计算,并受 max_discount 限制。
- money:直接减免固定金额。
- 输出:折后金额与优惠明细。
flowchart TD
S(["进入折扣计算"]) --> L1["检查是否已领取"]
L1 --> |否| R1["返回无优惠"]
L1 --> |是| L2["校验有效期与状态"]
L2 --> |不通过| R1
L2 --> |通过| L3["校验使用条件"]
L3 --> |不通过| R1
L3 --> |通过| T{"类型"}
T --> |percent| P["按比例计算并受上限限制"]
T --> |money| M["直接减免固定金额"]
P --> O["返回折后金额与明细"]
M --> O
依赖关系分析
- 表间关系
- dou_coupon 与 dou_coupon_log:一对多(一个券模板可被多次领取/使用)。
- dou_coupon_log 与 dou_order_coupon:一对多(一次使用产生一条订单关联明细)。
- dou_order_coupon 与 dou_coupon:多对一(多个订单可使用同一券模板)。
- 服务层依赖
- 服务层通过查询 dou_coupon 获取券配置,结合 dou_coupon_log 判断领取/使用状态,最终在 dou_order_coupon 中落库使用明细。
erDiagram
DOU_COUPON ||--o{ DOU_COUPON_LOG : "被领取/使用"
DOU_COUPON_LOG ||--o{ DOU_ORDER_COUPON : "被订单使用"
DOU_ORDER_COUPON }o--|| DOU_COUPON : "引用券模板"
性能与索引建议
- 现有索引
- dou_order_coupon 已包含 idx_order(order_id),利于按订单查询使用明细。
- 建议补充索引
- dou_coupon_log:
- (user_id, coupon_id):快速判断用户是否已领取某券。
- (coupon_id, claimed_at)、(coupon_id, used_at):提升按券统计领取/使用效率。
- dou_coupon:
- (status, start_at, end_at):加速“当前有效券”的筛选。
- (coupon_sn):若需按券号检索,建议加唯一索引。
- dou_coupon_log:
- 查询优化
- 列表页优先使用覆盖索引(如 sort、id)减少回表。
- 统计类报表考虑物化视图或定时汇总表,避免实时聚合大表。
故障排查指南
- 常见问题定位
- 券不可用:检查 status、start_at/end_at、condition、is_first_order_only、scope_type/scope_value。
- 重复领取:通过 (user_id, coupon_id) 去重校验。
- 折扣异常:核对 type、face_value、max_discount 与订单金额是否满足条件。
- 日志与审计
- 关注 dou_coupon_log 的 claimed_at/used_at/order_sn/ip/status,结合订单号回溯问题。
- 服务层断点
- 使用 CouponService.status/ifExpires/discount 等方法定位状态与计算逻辑。
结论
本设计文档基于仓库中的 SQL 与模型/服务代码,梳理了优惠券主表、领取/使用记录表与订单关联表的字段设计与业务语义,明确了类型、面额、条件、有效期、状态流转与限制策略的数据模型,并给出关系图与性能优化建议。运营人员可据此配置券规则,开发者可依据服务层逻辑与表结构进行扩展与维护。
附录:字段字典与枚举
- 优惠券类型(type)
- money:固定金额减免。
- percent:百分比减免。
- 优惠券状态(status)
- 0:禁用;1:启用(以实际业务为准)。
- 记录状态(coupon_log.status)
- 未使用/已使用/已过期等,具体值由语言包与显示层映射。
- 适用范围(scope_type/scope_value)
- 用于限定商品/分类等范围,具体取值依业务扩展。