一、功能概述
优惠券管理是电商系统中重要的营销工具,叮咚买菜系统的优惠券管理功能应包含优惠券的创建、发放、使用、统计等全生命周期管理,支持多种类型的优惠券活动。
二、核心功能模块
1. 优惠券类型管理
- 满减券:满X元减Y元
- 折扣券:按比例折扣(如8折)
- 无门槛券:直接抵扣金额
- 运费券:免运费或减免运费
- 品类券:限定品类使用
- 新人专享券:仅限新用户
2. 优惠券创建与配置
```java
// 优惠券实体类示例
public class Coupon {
private Long id;
private String name; // 优惠券名称
private String type; // 类型:满减、折扣等
private BigDecimal amount; // 金额或折扣比例
private BigDecimal minOrder; // 最低使用门槛
private Date startTime; // 生效时间
private Date endTime; // 失效时间
private Integer total; // 发放总量
private Integer remaining; // 剩余数量
private String scope; // 使用范围:全平台/特定品类
private String userScope; // 用户范围:全部/新用户/指定用户
// getters & setters
}
```
3. 优惠券发放方式
- 主动领取:用户在APP/小程序领取
- 系统发放:自动发放给符合条件的用户
- 分享发放:用户分享后获得
- 订单完成后发放:下笔订单奖励
4. 优惠券使用流程
1. 用户选择商品加入购物车
2. 结算时系统自动匹配可用优惠券
3. 用户选择使用或放弃使用
4. 系统验证优惠券有效性
5. 计算最终支付金额
三、数据库设计
优惠券表(coupon)
```sql
CREATE TABLE coupon (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
type VARCHAR(20) NOT NULL COMMENT 满减/折扣/无门槛等,
amount DECIMAL(10,2) NOT NULL,
min_order_amount DECIMAL(10,2) DEFAULT 0,
start_time DATETIME NOT NULL,
end_time DATETIME NOT NULL,
total_count INT NOT NULL,
remaining_count INT NOT NULL,
scope VARCHAR(20) DEFAULT ALL COMMENT 使用范围,
user_scope VARCHAR(20) DEFAULT ALL COMMENT 用户范围,
create_time DATETIME NOT NULL,
update_time DATETIME NOT NULL
);
```
用户优惠券表(user_coupon)
```sql
CREATE TABLE user_coupon (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
coupon_id BIGINT NOT NULL,
status VARCHAR(20) NOT NULL COMMENT 未使用/已使用/已过期,
order_id BIGINT DEFAULT NULL COMMENT 关联订单ID,
get_time DATETIME NOT NULL,
use_time DATETIME DEFAULT NULL,
expire_time DATETIME NOT NULL,
FOREIGN KEY (coupon_id) REFERENCES coupon(id)
);
```
四、核心接口实现
1. 创建优惠券接口
```java
@PostMapping("/coupons")
public Result createCoupon(@RequestBody CouponCreateDTO dto) {
// 参数校验
if (dto.getTotalCount() <= 0) {
return Result.fail("发放数量必须大于0");
}
Coupon coupon = new Coupon();
// 设置优惠券属性...
couponService.save(coupon);
return Result.success("创建成功");
}
```
2. 用户领取优惠券接口
```java
@PostMapping("/coupons/{couponId}/receive")
public Result receiveCoupon(@PathVariable Long couponId,
@RequestHeader("userId") Long userId) {
// 检查优惠券是否存在
Coupon coupon = couponService.getById(couponId);
if (coupon == null) {
return Result.fail("优惠券不存在");
}
// 检查是否可领取
if (coupon.getRemainingCount() <= 0) {
return Result.fail("优惠券已领完");
}
// 检查用户是否已领取过(根据业务需求)
// 创建用户优惠券记录
UserCoupon userCoupon = new UserCoupon();
userCoupon.setUserId(userId);
userCoupon.setCouponId(couponId);
userCoupon.setStatus("UNUSED");
userCoupon.setExpireTime(coupon.getEndTime());
userCouponService.save(userCoupon);
// 更新优惠券剩余数量
coupon.setRemainingCount(coupon.getRemainingCount() - 1);
couponService.updateById(coupon);
return Result.success("领取成功");
}
```
3. 使用优惠券接口
```java
@PostMapping("/orders/{orderId}/use-coupon")
public Result useCoupon(@PathVariable Long orderId,
@RequestParam Long couponId,
@RequestHeader("userId") Long userId) {
// 验证订单和用户
Order order = orderService.getById(orderId);
if (!order.getUserId().equals(userId)) {
return Result.fail("无权操作此订单");
}
// 验证优惠券
UserCoupon userCoupon = userCouponService.getByUserIdAndCouponId(userId, couponId);
if (userCoupon == null || !"UNUSED".equals(userCoupon.getStatus())) {
return Result.fail("优惠券不可用");
}
// 验证有效期
if (new Date().after(userCoupon.getExpireTime())) {
return Result.fail("优惠券已过期");
}
// 计算优惠金额(根据优惠券类型)
BigDecimal discountAmount = calculateDiscount(userCoupon, order);
// 更新订单信息
order.setCouponId(couponId);
order.setDiscountAmount(discountAmount);
order.setActualAmount(order.getTotalAmount().subtract(discountAmount));
orderService.updateById(order);
// 更新优惠券状态
userCoupon.setStatus("USED");
userCoupon.setUseTime(new Date());
userCouponService.updateById(userCoupon);
return Result.success("使用成功");
}
```
五、关键业务逻辑
1. 优惠券有效性验证
```java
public boolean isValidCoupon(UserCoupon userCoupon, Order order) {
// 检查状态
if (!"UNUSED".equals(userCoupon.getStatus())) {
return false;
}
// 检查有效期
if (new Date().after(userCoupon.getExpireTime())) {
return false;
}
// 检查订单金额是否满足条件
Coupon coupon = couponService.getById(userCoupon.getCouponId());
if (order.getTotalAmount().compareTo(coupon.getMinOrderAmount()) < 0) {
return false;
}
// 检查商品范围(如果有)
if (StringUtils.isNotBlank(coupon.getScope())) {
// 验证订单商品是否在范围内
// ...
}
return true;
}
```
2. 优惠金额计算
```java
public BigDecimal calculateDiscount(UserCoupon userCoupon, Order order) {
Coupon coupon = couponService.getById(userCoupon.getCouponId());
switch (coupon.getType()) {
case "FIXED": // 满减券
return coupon.getAmount();
case "PERCENT": // 折扣券
return order.getTotalAmount().multiply(coupon.getDiscount())
.setScale(2, RoundingMode.DOWN);
case "NO_THRESHOLD": // 无门槛券
return Math.min(coupon.getAmount(), order.getTotalAmount());
default:
return BigDecimal.ZERO;
}
}
```
六、前端交互设计
1. 优惠券列表页
- 展示用户拥有的所有优惠券
- 按状态分类:未使用/已使用/已过期
- 支持按类型、有效期筛选
2. 优惠券领取页
- 展示可领取的优惠券列表
- 显示优惠券详情(面额、使用条件、有效期)
- "立即领取"按钮
3. 结算页优惠券选择
- 自动匹配可用优惠券
- 显示最优优惠券建议
- 用户可手动选择/更换优惠券
七、性能优化考虑
1. 缓存策略:
- 热门优惠券信息缓存
- 用户优惠券列表分页缓存
2. 数据库优化:
- 优惠券表按类型、状态分区
- 用户优惠券表按用户ID分区
3. 异步处理:
- 优惠券发放使用消息队列
- 优惠券使用统计异步计算
4. 限流措施:
- 优惠券领取接口限流
- 防止黄牛刷券
八、安全考虑
1. 防止优惠券篡改(使用签名机制)
2. 防止重复领取(唯一性校验)
3. 防止优惠券滥用(使用记录审计)
4. 敏感操作二次验证(如大额优惠券使用)
九、扩展功能
1. 优惠券分享:用户可分享优惠券给好友
2. 优惠券组合:支持多张优惠券叠加使用
3. 优惠券推荐:根据用户购买习惯推荐优惠券
4. 优惠券核销:线下场景优惠券核销功能
十、测试要点
1. 优惠券创建边界测试(金额、数量、时间)
2. 并发领取测试
3. 优惠券过期自动处理测试
4. 各种优惠券类型使用场景测试
5. 退款时优惠券返还逻辑测试
通过以上设计,叮咚买菜系统可以实现一个功能完善、性能优良的优惠券管理系统,有效提升用户活跃度和订单转化率。