优惠券模块设计文档
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 | 优惠券ID | int(11) | 主键 | 否 | AUTO_INCREMENT | - | 系统自动生成,唯一标识 |
| coupon_name | 优惠券名称 | varchar(100) | 普通列 | 否 | - | 字符串 | 用户可见的优惠券名称 |
| coupon_code | 优惠码 | varchar(50) | 普通列 | 否 | - | 字符串 | 用户输入的优惠码,需唯一 |
| discount_type | 优惠方式 | tinyint(4) | 普通列 | 否 | 1 | 1-百分比,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) | 普通列 | 否 | 0 | 0-启用,1-禁用 | 控制优惠券是否可用 |
| deleted_flag | 是否删除 | tinyint(1) | 普通列 | 否 | 0 | 0-未删除,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,
}参数说明:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| proxyType | Integer | 是 | 代理类型: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"
}
}响应字段说明:
| 字段名 | 类型 | 说明 |
|---|---|---|
| code | Integer | 响应码,0表示成功 |
| msg | String | 响应消息 |
| data | Object | 优惠券信息 |
| data.couponId | Integer | 优惠券ID |
| data.couponName | String | 优惠券名称 |
| data.couponCode | String | 优惠码 |
| data.discountType | Integer | 优惠方式(1-百分比,2-固定金额) |
| data.discountTypeDesc | String | 优惠方式描述 |
| data.discountValue | BigDecimal | 优惠值 |
| data.validStartTime | String | 有效期开始时间 |
| data.validEndTime | String | 有效期结束时间 |
| data.sort | Integer | 排序值 |
| data.createTime | String | 创建时间 |
2.2 校验优惠券使用规则
接口信息
- 接口路径:
POST /coupon/validate - 接口描述: 根据优惠码和代理类型校验是否符合使用规则
请求参数
json
{
"couponCode": "NEWUSER2024",
"proxyType": 1,
}参数说明:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| couponCode | String | 是 | 优惠码 |
| proxyType | Integer | 是 | 代理类型: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
}
}响应字段说明:
| 字段名 | 类型 | 说明 |
|---|---|---|
| code | Integer | 响应码,0表示成功 |
| msg | String | 响应消息 |
| data | Object | 校验结果 |
| data.isValid | Boolean | 是否有效 |
| data.errorMessage | String | 错误信息(当isValid为false时返回) |
| data.couponInfo | Object | 优惠券信息(当isValid为true时返回) |
| data.discountedAmount | BigDecimal | 优惠后金额(当isValid为true时返回) |
| data.discountAmount | BigDecimal | 优惠金额(当isValid为true时返回) |
3. 错误码定义
| 错误码 | 编码值 | 说明 |
|---|---|---|
| COUPON_VALID | 0 | 折扣码有效 |
| COUPON_INVALID | 32101 | 折扣码无效 |
| NO_COUPON_AVAILABLE | 32100 | 暂无优惠码 |
4. 业务规则
4.1 优惠券查询规则
- 根据代理类型匹配(使用FIND_IN_SET函数)
- 优惠券必须在有效期内
- 优惠券必须启用(disabled_flag = 0)
- 优惠券未删除(deleted_flag = 0)
- 按sort字段降序排列,sort相同时按创建时间降序排列
- 返回sort最大的优惠券
4.2 优惠券校验规则
- 优惠券必须存在
- 优惠券必须在有效期内
- 优惠券必须启用
- 优惠券未删除
- 代理类型必须匹配
- 计算优惠后金额和优惠金额
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.004.4 注意事项
- 优惠券只对产品原始金额生效,不影响手续费、税费等其他费用
- 优惠金额不能超过产品原始金额
- 优惠后金额最低为0,不会出现负数
- 最终订单金额需要在前端或订单模块中重新计算
5. 下单接口集成
5.1 接口字段扩展
下单接口需要新增 couponCode 字段,用于接收用户输入的优惠券代码。
新增字段说明
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| couponCode | String | 否 | 优惠券代码,用户可选择性输入 |
5.2 合规性校验要求
前端校验
- 格式校验:优惠券代码不能为空字符串,长度不超过50个字符
- 实时校验:用户输入优惠券代码后,调用
/coupon/validate接口进行实时校验 - 错误提示:校验失败时显示具体错误信息,如"优惠券已过期"、"优惠券不适用于当前代理类型"等
- 金额计算:根据校验结果实时计算并显示优惠后金额
后端校验
- 必填校验:如果传入
couponCode,则不能为空 - 格式校验:优惠券代码长度不超过50个字符,只允许字母、数字、连字符
- 业务校验:调用优惠券校验逻辑,验证优惠券的有效性、适用性、有效期等
- 金额计算:基于校验通过的优惠券,重新计算订单金额
- 数据一致性:确保优惠券使用后,相关使用记录和状态更新的一致性
5.3 校验流程
用户输入优惠券代码 → 前端格式校验 → 调用校验接口 → 后端业务校验 → 返回校验结果 → 前端显示结果5.4 注意事项
- 优惠券代码为可选字段,用户可以不输入
- 前端和后端都需要进行校验,确保数据安全性和用户体验
- 校验失败时,订单仍可正常提交,但不享受优惠
- 优惠券使用后需要更新相关状态,防止重复使用
