01-优惠券核销管理接口.md 18 KB

Web端商户优惠券核销接口文档

模块概述

本模块提供优惠券的核销功能,包括核销前效验和核销订单两个接口,支持代金券和团购券的核销处理。


接口列表

  1. 核销订单前效验 - 验证券是否可用
  2. 核销订单 - 实际执行核销操作

接口一:核销订单前效验

接口信息

  • 接口名称:核销订单前效验
  • 接口路径:GET /couponManage/verifyOrder
  • 请求方式:GET
  • 接口描述:在核销订单前进行效验,验证券是否满足核销条件(有效期、不可用日期、使用时间段等)

请求参数

参数名 类型 必填 说明
orderCode String 劵code(券码)

请求示例

GET /couponManage/verifyOrder?orderCode=ABC123456789

响应参数

成功响应(效验通过)

{
    "code": 200,
    "success": true,
    "data": "效验通过",
    "msg": "效验通过"
}

失败响应示例

{
    "code": 500,
    "success": false,
    "data": null,
    "msg": "该劵不在有效期内"
}

业务规则

详见核销前效验规则章节。


接口二:核销订单

接口信息

  • 接口名称:核销订单
  • 接口路径:GET /couponManage/verifyCoupon
  • 请求方式:GET
  • 接口描述:执行券的核销操作,更新券状态、计算收入、更新店铺余额

请求参数

参数名 类型 必填 说明
storeId String 门店ID
quanCode String 券码

请求示例

GET /couponManage/verifyCoupon?storeId=102&quanCode=ABC123456789

响应参数

成功响应(核销成功)

{
    "code": 200,
    "success": true,
    "data": {
        "code": "true",
        "message": "核销成功"
    }
}

失败响应示例

1. 重复核销
{
    "code": 200,
    "success": true,
    "data": {
        "code": "false",
        "message": "请勿重复核销"
    }
}
2. 券不存在或状态不正确
{
    "code": 200,
    "success": true,
    "data": {
        "code": "false",
        "message": "核销失败"
    }
}
3. 订单不存在
{
    "code": 200,
    "success": true,
    "data": {
        "code": "false",
        "message": "订单不存在"
    }
}
4. 门店不存在
{
    "code": 200,
    "success": true,
    "data": {
        "code": "false",
        "message": "门店不存在"
    }
}

核销业务流程

完整核销流程图

┌─────────────────────────────────────────────┐
│  客户端调用核销接口                           │
│  /couponManage/verifyCoupon                  │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  1. Redis分布式锁                             │
│  检查 coupon:use:{quanCode} 是否存在          │
│  存在 → 返回"请勿重复核销"                    │
│  不存在 → 设置锁并继续                        │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  2. 查询订单券中间表                          │
│  - 根据券码查询                               │
│  - 状态必须为:待使用(1) 或 退款失败(8)       │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  3. 更新订单券状态                            │
│  - status → 已使用(2)                        │
│  - usedTime → 当前时间                       │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  4. 查询用户订单信息                          │
│  - 根据 orderId 查询                         │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  5. 检查平台优惠券                            │
│  - 查询 quanId                               │
│  - 如果 type=3,标记为平台券                  │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  6-7. 查询订单下所有券                        │
│  - 检查是否全部已核销                        │
│  - 筛选未完成的券                            │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  8. 订单完成判断                              │
│  如果所有券都已核销 或 无未完成券             │
│  → 更新订单状态为已完成(3)                   │
│  → 设置完成时间                              │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  9. 查询门店信息                              │
│  - 获取抽成比例 commissionRate               │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  10. 计算抽成和收入                           │
│  抽成 = 券价 × 100 × 抽成比例                │
│  收入 = 券价 × 100 - 抽成                    │
│  (如有平台券,需加上平均优惠价格)             │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  11. 插入收入明细记录                         │
│  - storeId, userOrderId                      │
│  - incomeType, businessId                    │
│  - commission, money                         │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  12. 更新店铺账户余额                         │
│  - store_user.money += 收入金额              │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  13. 返回核销成功                             │
│  { code: "true", message: "核销成功" }       │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  14. 释放分布式锁 (finally)                   │
│  删除 coupon:use:{quanCode}                  │
└─────────────────────────────────────────────┘

核销前效验规则

效验内容

核销前效验(verifyOrder)会根据券类型进行不同的验证:

代金券验证(couponType=1)

  1. 有效期验证

    • 指定天数:支付时间 + 天数 > 当前时间
    • 指定时间段:开始时间 ≤ 当前时间 ≤ 结束时间
  2. 不可用日期验证

    • 限制星期:检查当前是否为不可用星期
    • 限制节日:检查当前是否在节日范围
    • 自定义日期:检查当前是否在自定义不可用日期
  3. 使用时间段验证

    • 检查当前小时是否在允许使用的时间段内
    • 支持跨天时间段(如22点-3点)
  4. 单次核销数量验证

    • 检查今日已核销次数是否达到上限

团购券验证(couponType=2)

  1. 有效期验证

    • 指定天数:支付时间 + 天数 > 当前时间
    • 指定时间段:开始日期 ≤ 当前日期 ≤ 结束日期
  2. 不可用日期验证

    • 限制星期:检查当前是否为不可用星期
    • 限制节日:检查当前是否在节日范围
    • 自定义日期:检查当前是否在自定义不可用日期

金额计算规则

基础计算公式

1. 抽成金额计算

抽成比例(小数) = storeInfo.commissionRate ÷ 100
抽成金额(分) = 券价(元) × 100 × 抽成比例

示例:

券价 = 100元
抽成比例 = 4%
抽成金额 = 100 × 100 × 0.04 = 400分(4元)

2. 实际收入计算

普通订单(无平台优惠券)
实际收入(分) = 券价(元) × 100 - 抽成金额(分)

示例:

券价 = 100元
抽成 = 400分
实际收入 = 100 × 100 - 400 = 9600分(96元)
使用平台优惠券的订单
实际收入(分) = (券价(元) + 平均优惠券价格(元)) × 100 - 抽成金额(分)

示例:

券价 = 100元
平台优惠 = 10元
抽成 = 400分
实际收入 = (100 + 10) × 100 - 400 = 10600分(106元)

金额单位说明

存储单位 显示单位 转换关系
分(数据库) 元(前端) 1元 = 100分

注意:

  • 所有金额计算使用 BigDecimal,精度为2位小数
  • 金额存储到数据库时转换为整数(分)
  • 显示给用户时转换为元(除以100)

并发控制

Redis分布式锁机制

锁的生命周期

┌─────────────────────────────────────────────┐
│  1. 检查锁                                    │
│  getString("coupon:use:{quanCode}")          │
│  如果返回值不为空 → 锁已存在 → 拒绝核销      │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  2. 设置锁                                    │
│  setListRight("coupon:use:{quanCode}",       │
│               quanCode)                      │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  3. 执行核销业务逻辑                          │
│  (数据库操作、金额计算等)                   │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  4. 释放锁 (finally块)                       │
│  delete("coupon:use:{quanCode}")             │
│  确保无论成功失败都会释放                    │
└─────────────────────────────────────────────┘

锁的作用

  • 防止重复核销:同一券码在处理过程中不允许再次核销
  • 并发安全:多个核销请求同时到达时,只有一个能获取锁
  • 自动释放:finally块确保锁一定会被释放

数据库操作

涉及的表

1. order_coupon_middle(订单券中间表)

查询操作:

SELECT * FROM order_coupon_middle
WHERE coupon_code = ?
  AND status IN (1, 8)  -- 待使用或退款失败

更新操作:

UPDATE order_coupon_middle
SET status = 2,           -- 已使用
    used_time = NOW()
WHERE id = ?

2. life_user_order(用户订单表)

查询操作:

SELECT * FROM life_user_order
WHERE id = ?

更新操作(订单完成时):

UPDATE life_user_order
SET status = 3,              -- 已完成
    finish_time = NOW(),
    created_time = NOW()
WHERE id = ?

3. life_discount_coupon(优惠券表)

查询操作(检查平台券):

SELECT * FROM life_discount_coupon
WHERE id = ?
  AND type = 3  -- 平台券

4. store_info(门店信息表)

查询操作:

SELECT * FROM store_info
WHERE id = ?

5. store_income_details_record(收入明细表)

插入操作:

INSERT INTO store_income_details_record
(store_id, user_order_id, income_type, business_id, commission, money)
VALUES (?, ?, ?, ?, ?, ?)

6. store_user(门店用户表)

更新操作:

UPDATE store_user
SET money = money + ?
WHERE store_id = ?
  AND delete_flag = 0

订单状态说明

order_coupon_middle 状态

Status 枚举常量 说明
1 WAIT_USE 待使用
2 USED 已使用(核销完成)
3 REFUND 已退款
8 REFUND_FAILED 退款失败

life_user_order 状态

Status 枚举常量 说明
1 WAIT_PAY 待支付
2 WAIT_USE 待使用
3 COMPLETE 已完成
4 REFUND 已退款
5 CANCEL 已取消
6 EXPIRE 已过期

收入明细记录

StoreIncomeDetailsRecord 字段说明

字段名 类型 说明 示例
storeId Integer 门店ID 102
userOrderId Integer 订单券ID 12345
incomeType Integer 收入类型(券类型) 1-代金券, 2-团购
businessId Integer 业务ID(券ID) 67890
commission Integer 抽成金额(分) 400
money Integer 实际收入(分) 9600

事务管理

事务范围

核销订单接口使用 @Transactional 注解,确保以下操作的原子性:

  1. 更新订单券状态
  2. 更新用户订单状态(如需要)
  3. 插入收入明细记录
  4. 更新店铺账户余额

回滚机制

@Transactional(rollbackFor = Exception.class)
public Map<String, String> verifyCoupon(String storeId, String quanCode) {
    // 任何异常都会触发回滚
}

异常处理

异常场景

场景 返回code 返回message 处理方式
重复核销 "false" "请勿重复核销" 检测到锁存在
券不存在 "false" "核销失败" 查询结果为空
订单不存在 "false" "订单不存在" 订单查询失败
门店不存在 "false" "门店不存在" 门店查询失败
系统异常 "false" "核销失败:{异常信息}" 捕获Exception

迁移说明

原接口(app端)

  • 路径:/alienStore/coupon/newVerify
  • Controller:LifeCouponController
  • Service:LifeCouponService.newCouponVerify()

新接口(web端)

  • 路径:/couponManage/verifyCoupon
  • Controller:CouponManageController
  • Service:CouponManageService.verifyCoupon()

差异说明

项目 app端 web端 说明
好友券发放 ✅ 支持 ⚠️ 暂不支持 需通过Feign调用实现
其他逻辑 完全一致

更新日志

2025-11-14

新增接口:

  • GET /couponManage/verifyOrder - 核销订单前效验
  • GET /couponManage/verifyCoupon - 核销订单

核心功能:

  • ✅ Redis分布式锁防止重复核销
  • ✅ 券状态更新(待使用→已使用)
  • ✅ 订单状态更新(所有券核销完成→订单完成)
  • ✅ 平台优惠券识别和处理
  • ✅ 抽成计算(从门店信息获取比例)
  • ✅ 收入记录插入
  • ✅ 店铺余额更新
  • ✅ 完整的事务管理
  • ✅ 详细的日志记录
  • ✅ 异常处理和回滚机制

涉及文件:

  • CouponManageController.java - 更新
  • CouponManageService.java - 更新
  • CouponManageServiceImpl.java - 更新(新增200行)

文档版本:v1.0
最后更新:2025-11-14
维护人员:ssk