IT频道
标题:美团买菜优惠券系统:设计、实现与监控全流程解析
来源:     阅读:15
网站管理员
发布于 2025-11-06 08:30
查看主页
  
   一、功能概述
  
  美团买菜系统的优惠券通用功能需要支持多种类型的优惠券(满减券、折扣券、无门槛券等),能够在不同业务场景(买菜、配送、会员服务等)下通用,并实现精准的发放、使用和结算。
  
   二、系统架构设计
  
   1. 核心模块划分
  - 优惠券模板管理:定义优惠券规则和属性
  - 优惠券发放系统:控制优惠券的生成和分发
  - 优惠券使用系统:处理优惠券的核销和抵扣
  - 优惠券结算系统:与订单系统对接完成金额计算
  - 优惠券统计系统:数据分析和效果追踪
  
   2. 数据库设计
  ```sql
  -- 优惠券模板表
  CREATE TABLE coupon_template (
   id BIGINT PRIMARY KEY AUTO_INCREMENT,
   name VARCHAR(100) NOT NULL COMMENT 优惠券名称,
   type TINYINT NOT NULL COMMENT 类型(1:满减,2:折扣,3:无门槛),
   discount_type TINYINT COMMENT 折扣类型(1:百分比,2:固定金额),
   value DECIMAL(10,2) NOT NULL COMMENT 优惠值,
   min_order_amount DECIMAL(10,2) DEFAULT NULL COMMENT 最低订单金额,
   start_time DATETIME NOT NULL COMMENT 生效时间,
   end_time DATETIME NOT NULL COMMENT 过期时间,
   total_count INT DEFAULT NULL COMMENT 总发放量,
   remain_count INT DEFAULT NULL COMMENT 剩余量,
   scope TINYINT NOT NULL COMMENT 使用范围(1:全品类,2:指定品类,3:指定商品),
   status TINYINT DEFAULT 1 COMMENT 状态(1:有效,0:无效),
   create_time DATETIME NOT NULL,
   update_time DATETIME NOT NULL
  );
  
  -- 用户优惠券表
  CREATE TABLE user_coupon (
   id BIGINT PRIMARY KEY AUTO_INCREMENT,
   user_id BIGINT NOT NULL COMMENT 用户ID,
   template_id BIGINT NOT NULL COMMENT 模板ID,
   coupon_code VARCHAR(32) NOT NULL COMMENT 优惠券码,
   status TINYINT NOT NULL COMMENT 状态(1:未使用,2:已使用,3:已过期),
   order_id BIGINT DEFAULT NULL COMMENT 关联订单ID,
   get_time DATETIME NOT NULL COMMENT 获取时间,
   use_time DATETIME DEFAULT NULL COMMENT 使用时间,
   expire_time DATETIME NOT NULL COMMENT 过期时间,
   UNIQUE KEY uk_coupon_code (coupon_code)
  );
  ```
  
   三、核心功能实现
  
   1. 优惠券模板管理
  ```java
  public class CouponTemplate {
   private Long id;
   private String name;
   private Integer type; // 1-满减, 2-折扣, 3-无门槛
   private BigDecimal value;
   private BigDecimal minOrderAmount;
   private Date startTime;
   private Date endTime;
   private Integer totalCount;
   private Integer remainCount;
   private Integer scope; // 1-全品类, 2-指定品类, 3-指定商品
   // getters and setters
  }
  
  // 创建优惠券模板服务
  public CouponTemplate createCouponTemplate(CouponTemplateDTO dto) {
   // 参数校验
   validateTemplate(dto);
  
   CouponTemplate template = new CouponTemplate();
   // 转换DTO到Entity
   BeanUtils.copyProperties(dto, template);
  
   // 设置默认值
   template.setStatus(1); // 有效
   template.setCreateTime(new Date());
   template.setUpdateTime(new Date());
  
   // 保存到数据库
   couponTemplateMapper.insert(template);
  
   return template;
  }
  ```
  
   2. 优惠券发放系统
  ```java
  public interface CouponDistributionService {
   /
   * 发放优惠券给用户
   * @param userId 用户ID
   * @param templateId 模板ID
   * @param count 发放数量
   * @return 发放结果
   */
   DistributionResult distributeCoupon(Long userId, Long templateId, Integer count);
  }
  
  @Service
  public class CouponDistributionServiceImpl implements CouponDistributionService {
  
   @Autowired
   private CouponTemplateMapper couponTemplateMapper;
  
   @Autowired
   private UserCouponMapper userCouponMapper;
  
   @Override
   @Transactional
   public DistributionResult distributeCoupon(Long userId, Long templateId, Integer count) {
   // 1. 查询模板信息
   CouponTemplate template = couponTemplateMapper.selectById(templateId);
   if (template == null || template.getStatus() != 1) {
   return DistributionResult.fail("优惠券模板不存在或已失效");
   }
  
   // 2. 检查发放数量
   if (template.getRemainCount() < count) {
   return DistributionResult.fail("优惠券库存不足");
   }
  
   // 3. 生成用户优惠券
   List coupons = new ArrayList<>();
   for (int i = 0; i < count; i++) {
   UserCoupon coupon = new UserCoupon();
   coupon.setUserId(userId);
   coupon.setTemplateId(templateId);
   coupon.setCouponCode(generateCouponCode());
   coupon.setStatus(1); // 未使用
   coupon.setGetTime(new Date());
   coupon.setExpireTime(template.getEndTime());
   coupons.add(coupon);
   }
  
   // 4. 批量插入
   userCouponMapper.batchInsert(coupons);
  
   // 5. 更新模板剩余数量
   couponTemplateMapper.decreaseRemainCount(templateId, count);
  
   return DistributionResult.success();
   }
  
   private String generateCouponCode() {
   // 生成唯一优惠券码
   return UUID.randomUUID().toString().replace("-", "").substring(0, 16).toUpperCase();
   }
  }
  ```
  
   3. 优惠券使用系统
  ```java
  public interface CouponUsageService {
   /
   * 使用优惠券
   * @param userId 用户ID
   * @param couponCode 优惠券码
   * @param orderAmount 订单金额
   * @return 优惠信息
   */
   CouponUsageResult useCoupon(Long userId, String couponCode, BigDecimal orderAmount);
  }
  
  @Service
  public class CouponUsageServiceImpl implements CouponUsageService {
  
   @Autowired
   private UserCouponMapper userCouponMapper;
  
   @Autowired
   private CouponTemplateMapper couponTemplateMapper;
  
   @Override
   @Transactional
   public CouponUsageResult useCoupon(Long userId, String couponCode, BigDecimal orderAmount) {
   // 1. 查询用户优惠券
   UserCoupon userCoupon = userCouponMapper.selectByCodeAndUserId(couponCode, userId);
   if (userCoupon == null || userCoupon.getStatus() != 1) {
   return CouponUsageResult.fail("优惠券不存在或不可用");
   }
  
   // 2. 查询模板信息
   CouponTemplate template = couponTemplateMapper.selectById(userCoupon.getTemplateId());
   if (template == null || template.getStatus() != 1) {
   return CouponUsageResult.fail("优惠券模板已失效");
   }
  
   // 3. 检查有效期
   if (new Date().after(template.getEndTime())) {
   return CouponUsageResult.fail("优惠券已过期");
   }
  
   // 4. 检查使用范围
   if (!checkCouponScope(template, orderItems)) { // 假设有orderItems参数
   return CouponUsageResult.fail("优惠券不适用于当前商品");
   }
  
   // 5. 检查最低订单金额
   if (template.getMinOrderAmount() != null
   && orderAmount.compareTo(template.getMinOrderAmount()) < 0) {
   return CouponUsageResult.fail("订单金额不满足使用条件");
   }
  
   // 6. 计算优惠金额
   BigDecimal discountAmount = calculateDiscount(template, orderAmount);
  
   // 7. 更新优惠券状态
   userCoupon.setStatus(2); // 已使用
   userCoupon.setUseTime(new Date());
   userCouponMapper.updateById(userCoupon);
  
   return CouponUsageResult.success(discountAmount, template.getType());
   }
  
   private BigDecimal calculateDiscount(CouponTemplate template, BigDecimal orderAmount) {
   switch (template.getType()) {
   case 1: // 满减券
   return template.getValue();
   case 2: // 折扣券
   if (template.getDiscountType() == 1) { // 百分比
   return orderAmount.multiply(template.getValue()).divide(new BigDecimal(100), 2, RoundingMode.DOWN);
   } else { // 固定金额折扣
   return template.getValue();
   }
   case 3: // 无门槛券
   return template.getValue();
   default:
   return BigDecimal.ZERO;
   }
   }
  }
  ```
  
   4. 优惠券结算系统集成
  ```java
  @Service
  public class OrderSettlementService {
  
   @Autowired
   private CouponUsageService couponUsageService;
  
   public OrderSettlementResult settle(Long userId, List items, String couponCode) {
   // 计算商品总价
   BigDecimal totalAmount = calculateTotalAmount(items);
  
   // 使用优惠券
   CouponUsageResult couponResult = null;
   if (StringUtils.isNotBlank(couponCode)) {
   couponResult = couponUsageService.useCoupon(userId, couponCode, totalAmount);
   if (!couponResult.isSuccess()) {
   return OrderSettlementResult.fail(couponResult.getMessage());
   }
   }
  
   // 计算最终金额
   BigDecimal finalAmount = totalAmount;
   if (couponResult != null) {
   finalAmount = totalAmount.subtract(couponResult.getDiscountAmount());
   if (finalAmount.compareTo(BigDecimal.ZERO) < 0) {
   finalAmount = BigDecimal.ZERO;
   }
   }
  
   // 返回结算结果
   return OrderSettlementResult.success(finalAmount,
   couponResult != null ? couponResult.getDiscountAmount() : BigDecimal.ZERO);
   }
  }
  ```
  
   四、关键业务规则实现
  
   1. 优惠券使用范围检查
  ```java
  private boolean checkCouponScope(CouponTemplate template, List items) {
   if (template.getScope() == 1) { // 全品类
   return true;
   }
  
   // 获取优惠券适用的品类或商品ID列表
   List applicableIds = getApplicableIds(template.getId());
  
   for (OrderItem item : items) {
   if (template.getScope() == 2) { // 指定品类
   if (!applicableIds.contains(item.getCategoryId())) {
   return false;
   }
   } else if (template.getScope() == 3) { // 指定商品
   if (!applicableIds.contains(item.getProductId())) {
   return false;
   }
   }
   }
  
   return true;
  }
  ```
  
   2. 优惠券叠加使用限制
  ```java
  public class CouponCombinationValidator {
  
   public ValidationResult validateCombination(List coupons, BigDecimal orderAmount) {
   // 1. 检查优惠券类型是否允许叠加
   Set types = coupons.stream().map(UserCoupon::getTemplateType).collect(Collectors.toSet());
   if (types.size() > 1 && !isCombinationAllowed(types)) {
   return ValidationResult.fail("不支持此类优惠券叠加使用");
   }
  
   // 2. 检查每张优惠券的使用条件
   for (UserCoupon coupon : coupons) {
   CouponTemplate template = getTemplateById(coupon.getTemplateId());
   if (orderAmount.compareTo(template.getMinOrderAmount()) < 0) {
   return ValidationResult.fail("订单金额不满足优惠券使用条件");
   }
   }
  
   return ValidationResult.success();
   }
  
   private boolean isCombinationAllowed(Set types) {
   // 实现业务规则:哪些类型的优惠券可以叠加使用
   // 例如:满减券和折扣券不能叠加,但多张满减券可以叠加
   // 这里需要根据实际业务需求实现
   return true;
   }
  }
  ```
  
   五、系统优化与扩展
  
   1. 性能优化
  - 使用Redis缓存热门优惠券模板信息
  - 对用户优惠券列表实现分页查询
  - 异步处理优惠券发放和统计
  
   2. 扩展功能
  - 优惠券分享功能
  - 优惠券转赠功能
  - 优惠券过期前提醒
  - 优惠券使用数据分析
  
   3. 分布式锁实现
  ```java
  @Service
  public class DistributedCouponService {
  
   @Autowired
   private RedisTemplate redisTemplate;
  
   private static final String LOCK_PREFIX = "coupon:lock:";
  
   public boolean tryAcquireLock(String couponCode, Long userId) {
   String lockKey = LOCK_PREFIX + couponCode;
   String lockValue = userId + ":" + System.currentTimeMillis();
  
   try {
   // 尝试获取锁,设置过期时间为10秒
   Boolean acquired = redisTemplate.opsForValue().setIfAbsent(
   lockKey, lockValue, 10, TimeUnit.SECONDS);
   return Boolean.TRUE.equals(acquired);
   } catch (Exception e) {
   return false;
   }
   }
  
   public void releaseLock(String couponCode, String lockValue) {
   String lockKey = LOCK_PREFIX + couponCode;
   String currentValue = redisTemplate.opsForValue().get(lockKey);
  
   if (lockValue.equals(currentValue)) {
   redisTemplate.delete(lockKey);
   }
   }
  }
  ```
  
   六、测试用例设计
  
   1. 单元测试
  ```java
  @RunWith(SpringRunner.class)
  @SpringBootTest
  public class CouponServiceTest {
  
   @Autowired
   private CouponDistributionService distributionService;
  
   @Test
   public void testDistributeCoupon_Success() {
   // 准备测试数据
   Long userId = 1L;
   Long templateId = 100L;
  
   // 执行测试
   DistributionResult result = distributionService.distributeCoupon(userId, templateId, 1);
  
   // 验证结果
   assertTrue(result.isSuccess());
   // 其他断言...
   }
  
   @Test
   public void testUseCoupon_InvalidCoupon() {
   // 准备测试数据
   Long userId = 1L;
   String invalidCode = "INVALID_CODE";
  
   // 执行测试
   CouponUsageResult result = couponUsageService.useCoupon(userId, invalidCode, new BigDecimal("100"));
  
   // 验证结果
   assertFalse(result.isSuccess());
   assertEquals("优惠券不存在或不可用", result.getMessage());
   }
  }
  ```
  
   2. 集成测试
  ```java
  @RunWith(SpringRunner.class)
  @SpringBootTest
  @AutoConfigureMockMvc
  public class CouponIntegrationTest {
  
   @Autowired
   private MockMvc mockMvc;
  
   @Test
   public void testCouponLifecycle() throws Exception {
   // 1. 创建优惠券模板
   String templateJson = "{name:测试满减券,type:1,value:10,minOrderAmount:50,"
   + "startTime:2023-01-01,endTime:2023-12-31,totalCount:1000}";
  
   mockMvc.perform(post("/api/coupon/template")
   .contentType(MediaType.APPLICATION_JSON)
   .content(templateJson))
   .andExpect(status().isCreated());
  
   // 2. 用户领取优惠券
   mockMvc.perform(post("/api/coupon/distribute")
   .param("userId", "1")
   .param("templateId", "1")
   .param("count", "1"))
   .andExpect(status().isOk());
  
   // 3. 用户使用优惠券
   mockMvc.perform(post("/api/coupon/use")
   .param("userId", "1")
   .param("couponCode", "GENERATED_CODE")
   .param("orderAmount", "60"))
   .andExpect(status().isOk())
   .andExpect(jsonPath("$.success", is(true)))
   .andExpect(jsonPath("$.discountAmount", is(10.0)));
   }
  }
  ```
  
   七、部署与监控
  
   1. 监控指标
  - 优惠券发放成功率
  - 优惠券使用率
  - 优惠券核销失败率
  - 优惠券系统响应时间
  
   2. 告警规则
  - 优惠券发放失败率 > 1%
  - 优惠券使用率异常下降
  - 系统响应时间 > 500ms
  
   3. 日志收集
  ```log4j
   优惠券使用日志
  log4j.logger.coupon.usage=INFO, couponUsage
  log4j.appender.couponUsage=org.apache.log4j.DailyRollingFileAppender
  log4j.appender.couponUsage.File=/var/log/meituan/coupon_usage.log
  log4j.appender.couponUsage.DatePattern=.yyyy-MM-dd
  log4j.appender.couponUsage.layout=org.apache.log4j.PatternLayout
  log4j.appender.couponUsage.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %m%n
  ```
  
  以上是美团买菜系统优惠券通用功能的详细实现方案,涵盖了从数据库设计到业务逻辑实现,再到测试和监控的全流程。实际开发中需要根据具体业务需求进行调整和优化。
免责声明:本文为用户发表,不代表网站立场,仅供参考,不构成引导等用途。 IT频道
购买生鲜系统联系18310199838
广告
相关推荐
蔬东坡系统:助力生鲜企业降本增效,构建差异化竞争力
悦厚生鲜系统:数字化赋能,降本增效提服务
菜东家生鲜配送系统:数字化闭环管理,降本增效提满意
短途配送系统:功能模块、技术实现、成本逻辑及实施方案
观麦生鲜系统:全流程数字化,助力企业降本增效与规模扩张