Skip to content

优惠券模块设计文档

1. 数据库表设计

1.1 优惠券表 (t_coupon)

sql
-- 优惠券表
CREATE TABLE `t_coupon` (
  `coupon_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '优惠券ID',
  `coupon_name` varchar(100) NOT NULL COMMENT '优惠券名称',
  `coupon_code` varchar(50) NOT NULL COMMENT '优惠码',
  `discount_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '优惠方式:1-百分比,2-固定金额',
  `discount_value` decimal(10,2) NOT NULL COMMENT '优惠值:百分比时为0-100,固定金额时为具体金额',
  `proxy_type` varchar(50) NOT NULL COMMENT '对应使用代理类型:逗号分隔,如"1,2,3"表示支持动态住宅、静态住宅、静态数据中心',
  `valid_start_time` datetime NOT NULL COMMENT '有效期开始时间',
  `valid_end_time` datetime NOT NULL COMMENT '有效期结束时间',
  `sort` int(11) NOT NULL DEFAULT '0' COMMENT '排序数字:数字越大越靠前,用于推荐排序',
  `disabled_flag` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否禁用:0-启用,1-禁用',
  `deleted_flag` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除:0-未删除,1-已删除',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
  PRIMARY KEY (`coupon_id`),
  UNIQUE KEY `uk_coupon_code` (`coupon_code`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='优惠券表';

1.2 字段说明

列名列描述列类型能否为null默认值取值业务补充
coupon_id优惠券IDint(11)主键AUTO_INCREMENT-系统自动生成,唯一标识
coupon_name优惠券名称varchar(100)普通列-字符串用户可见的优惠券名称
coupon_code优惠码varchar(50)普通列-字符串用户输入的优惠码,需唯一
discount_type优惠方式tinyint(4)普通列11-百分比,2-固定金额决定优惠计算方式
discount_value优惠值decimal(10,2)普通列-百分比:0-100,固定金额:具体金额根据discount_type确定含义
proxy_type代理类型varchar(50)普通列-逗号分隔的字符串,如"1,2,3"限制优惠券可使用的代理类型
valid_start_time有效期开始时间datetime普通列-日期时间优惠券生效时间
valid_end_time有效期结束时间datetime普通列-日期时间优惠券失效时间
sort排序数字int(11)普通列0整数数字越大排序越靠前
disabled_flag是否禁用tinyint(1)普通列00-启用,1-禁用控制优惠券是否可用
deleted_flag是否删除tinyint(1)普通列00-未删除,1-已删除软删除标记
create_time创建时间datetime普通列CURRENT_TIMESTAMP日期时间记录创建时间
update_time修改时间datetime普通列CURRENT_TIMESTAMP日期时间记录最后修改时间

1.3 枚举定义

新增优惠方式枚举 (DiscountTypeEnum)

java
PERCENTAGE(1, "百分比")
FIXED_AMOUNT(2, "固定金额")

代理类型枚举 (ProxyTypeEnum)

java
RESIDENTIAL(1, "动态住宅")
STATIC_RESIDENTIAL(2, "静态住宅")
STATIC_DATACENTER(3, "静态数据中心")
ROTATING_ISP(4, "轮转ISP")
MOBILE(5, "移动IP")

2. 接口规范

2.1 获取最推荐优惠券

接口信息

  • 接口路径: POST /coupon/getRecommended
  • 接口描述: 根据代理类型,返回sort最大的,在有效期内的,启用的未删除的优惠码

请求参数

json
{
  "proxyType": 1,
}

参数说明:

参数名类型必填说明
proxyTypeInteger代理类型:1-动态住宅,2-静态住宅,3-静态数据中心,4-轮转ISP,5-移动IP

响应参数

json
{
  "code": 0,
  "msg": "success",
  "data": {
    "couponId": 1,
    "couponName": "新用户专享优惠",
    "couponCode": "NEWUSER2024",
    "discountType": 1,
    "discountTypeDesc": "百分比",
    "discountValue": 20.00,
    "validStartTime": "2024-01-01 00:00:00",
    "validEndTime": "2024-12-31 23:59:59",
    "sort": 100,
    "createTime": "2024-01-01 10:00:00"
  }
}

响应字段说明:

字段名类型说明
codeInteger响应码,0表示成功
msgString响应消息
dataObject优惠券信息
data.couponIdInteger优惠券ID
data.couponNameString优惠券名称
data.couponCodeString优惠码
data.discountTypeInteger优惠方式(1-百分比,2-固定金额)
data.discountTypeDescString优惠方式描述
data.discountValueBigDecimal优惠值
data.validStartTimeString有效期开始时间
data.validEndTimeString有效期结束时间
data.sortInteger排序值
data.createTimeString创建时间

2.2 校验优惠券使用规则

接口信息

  • 接口路径: POST /coupon/validate
  • 接口描述: 根据优惠码和代理类型校验是否符合使用规则

请求参数

json
{
  "couponCode": "NEWUSER2024",
  "proxyType": 1,
}

参数说明:

参数名类型必填说明
couponCodeString优惠码
proxyTypeInteger代理类型:1-动态住宅,2-静态住宅,3-静态数据中心,4-轮转ISP,5-移动IP

响应参数

成功响应:

json
{
  "code": 0,
  "msg": "success",
  "data": {
    "isValid": true,
    "errorMessage": null,
    "couponInfo": {
      "couponId": 1,
      "couponName": "新用户专享优惠",
      "couponCode": "NEWUSER2024",
      "discountType": 1,
      "discountTypeDesc": "百分比",
      "discountValue": 20.00,
      "validStartTime": "2024-01-01 00:00:00",
      "validEndTime": "2024-12-31 23:59:59"
    },
    "discountedAmount": 80.00,
    "discountAmount": 20.00
  }
}

失败响应:

json
{
  "code": 0,
  "msg": "success",
  "data": {
    "isValid": false,
    "errorMessage": "优惠券已过期",
    "couponInfo": null,
    "discountedAmount": null,
    "discountAmount": null
  }
}

响应字段说明:

字段名类型说明
codeInteger响应码,0表示成功
msgString响应消息
dataObject校验结果
data.isValidBoolean是否有效
data.errorMessageString错误信息(当isValid为false时返回)
data.couponInfoObject优惠券信息(当isValid为true时返回)
data.discountedAmountBigDecimal优惠后金额(当isValid为true时返回)
data.discountAmountBigDecimal优惠金额(当isValid为true时返回)

3. 错误码定义

错误码编码值说明
COUPON_VALID0折扣码有效
COUPON_INVALID32101折扣码无效
NO_COUPON_AVAILABLE32100暂无优惠码

4. 业务规则

4.1 优惠券查询规则

  1. 根据代理类型匹配(使用FIND_IN_SET函数)
  2. 优惠券必须在有效期内
  3. 优惠券必须启用(disabled_flag = 0)
  4. 优惠券未删除(deleted_flag = 0)
  5. 按sort字段降序排列,sort相同时按创建时间降序排列
  6. 返回sort最大的优惠券

4.2 优惠券校验规则

  1. 优惠券必须存在
  2. 优惠券必须在有效期内
  3. 优惠券必须启用
  4. 优惠券未删除
  5. 代理类型必须匹配
  6. 计算优惠后金额和优惠金额

4.3 优惠券使用逻辑

4.3.1 优惠计算基础

  • 优惠计算基于产品原始金额,不包含手续费、税费等其他费用
  • orderAmount参数:传入的订单金额必须是产品原始金额
  • 优惠金额计算:基于产品原始金额进行折扣计算

4.3.2 优惠金额计算规则

  • 百分比优惠: 优惠金额 = 产品原始金额 × (优惠值 / 100)
  • 固定金额优惠: 优惠金额 = 优惠值
  • 优惠后金额: 产品原始金额 - 优惠金额(最低为0)

4.3.3 最终订单金额计算

最终订单金额 = 优惠后金额 + 手续费 + 税费 + 其他费用

4.3.4 使用示例

产品原始金额:100.00
手续费:5.00
税费:3.00
优惠券:20%折扣

计算过程:
1. 优惠金额 = 100.00 × 20% = 20.00
2. 优惠后金额 = 100.00 - 20.00 = 80.00
3. 最终订单金额 = 80.00 + 5.00 + 3.00 = 88.00

4.4 注意事项

  1. 优惠券只对产品原始金额生效,不影响手续费、税费等其他费用
  2. 优惠金额不能超过产品原始金额
  3. 优惠后金额最低为0,不会出现负数
  4. 最终订单金额需要在前端或订单模块中重新计算

5. 下单接口集成

5.1 接口字段扩展

下单接口需要新增 couponCode 字段,用于接收用户输入的优惠券代码。

新增字段说明

字段名类型必填说明
couponCodeString优惠券代码,用户可选择性输入

5.2 合规性校验要求

前端校验

  1. 格式校验:优惠券代码不能为空字符串,长度不超过50个字符
  2. 实时校验:用户输入优惠券代码后,调用 /coupon/validate 接口进行实时校验
  3. 错误提示:校验失败时显示具体错误信息,如"优惠券已过期"、"优惠券不适用于当前代理类型"等
  4. 金额计算:根据校验结果实时计算并显示优惠后金额

后端校验

  1. 必填校验:如果传入 couponCode,则不能为空
  2. 格式校验:优惠券代码长度不超过50个字符,只允许字母、数字、连字符
  3. 业务校验:调用优惠券校验逻辑,验证优惠券的有效性、适用性、有效期等
  4. 金额计算:基于校验通过的优惠券,重新计算订单金额
  5. 数据一致性:确保优惠券使用后,相关使用记录和状态更新的一致性

5.3 校验流程

用户输入优惠券代码 → 前端格式校验 → 调用校验接口 → 后端业务校验 → 返回校验结果 → 前端显示结果

5.4 注意事项

  1. 优惠券代码为可选字段,用户可以不输入
  2. 前端和后端都需要进行校验,确保数据安全性和用户体验
  3. 校验失败时,订单仍可正常提交,但不享受优惠
  4. 优惠券使用后需要更新相关状态,防止重复使用

Released under the MIT License.