# Web端商户优惠券核销接口文档 ## 概述 本接口用于核销订单前的效验,支持代金券和团购券两种类型的验证。 --- ## 接口信息 ### 核销订单前效验 - **接口名称**:核销订单前效验 - **接口路径**:`GET /couponManage/verifyOrder` - **请求方式**:GET - **接口描述**:在核销订单前进行效验,验证券是否可用 --- ## 请求参数 | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | orderCode | String | 是 | 劵code(券码) | --- ## 请求示例 ```http GET /couponManage/verifyOrder?orderCode=ABC123456789 ``` --- ## 响应参数 ### 成功响应(效验通过) ```json { "code": 200, "success": true, "data": "效验通过", "msg": "效验通过" } ``` ### 失败响应示例 #### 1. 券不是待使用状态 ```json { "code": 500, "success": false, "data": null, "msg": "该劵不是待使用状态" } ``` #### 2. 券不在有效期内 ```json { "code": 500, "success": false, "data": null, "msg": "该劵不在有效期内" } ``` #### 3. 券在不可用日期内 ```json { "code": 500, "success": false, "data": null, "msg": "该劵在不可用日期内" } ``` #### 4. 超过今日核销次数 ```json { "code": 500, "success": false, "data": null, "msg": "该订单已经超过今日单次核销数量" } ``` --- ## 业务逻辑 ### 验证流程图 ``` 开始验证 ↓ 根据券码查询订单券中间表 ↓ 检查券状态(status=1 待使用) ↓ 查询用户订单 ↓ 判断券类型 ├─ couponType=1 → 代金券验证流程 └─ couponType=2 → 团购券验证流程 ``` --- ### 代金券验证流程 ``` 代金券验证开始 ↓ 1. 验证有效期 ├─ 类型1:指定天数(支付时间+天数) └─ 类型2:指定时间段(开始-结束日期) ↓ 2. 验证不可用日期 ├─ 类型2:限制星期 + 节日 └─ 类型3:自定义日期范围 ↓ 3. 验证使用时间段 ├─ 正常时间段(如 9:00-18:00) └─ 跨天时间段(如 22:00-3:00) ↓ 4. 验证单次核销数量 └─ 检查今日已核销次数是否超限 ↓ 验证通过 ``` --- ### 团购券验证流程 ``` 团购券验证开始 ↓ 1. 验证有效期 ├─ 类型0:指定天数(支付时间+天数) └─ 类型1:指定时间段(开始-结束日期) ↓ 2. 验证不可用日期 ├─ 类型1:限制星期 + 节日 └─ 类型2:自定义日期范围 ↓ 验证通过 ``` --- ## 详细验证规则 ### 1. 有效期验证 #### 代金券有效期 | ExpirationType | 说明 | 验证逻辑 | |----------------|------|----------| | 1 | 指定天数 | `支付时间 + 天数 > 当前时间` | | 2 | 指定时间段 | `开始时间 ≤ 当前时间 ≤ 结束时间` | **代金券有效期字段**: - `expirationType`:有效期类型("1"-指定天数,"2"-指定时间段) - `expirationDate`:有效天数(当类型为1时) - `validityPeriod`:有效时间段(当类型为2时,格式:时间戳1,时间戳2) #### 团购券有效期 | EffectiveDateType | 说明 | 验证逻辑 | |-------------------|------|----------| | 0 | 指定天数 | `支付时间 + 天数 > 当前时间` | | 1 | 指定时间段 | `开始日期 ≤ 当前日期 ≤ 结束日期` | **团购券有效期字段**: - `effectiveDateType`:有效期类型(0-指定天数,1-指定时间段) - `effectiveDateValue`:有效期值 - 类型0:天数(如 "30") - 类型1:日期段(如 "2025-01-01,2025-12-31") --- ### 2. 不可用日期验证 #### 代金券不可用日期 | UnusedType | 说明 | 格式 | 示例 | |------------|------|------|------| | 2 | 限制星期+节日 | `星期;节日ID` | `星期一,星期二;1,2,3` | | 3 | 自定义日期范围 | `开始,结束;开始,结束` | `2025-01-01,2025-01-03;2025-02-01,2025-02-05` | **代金券字段**: - `unusedType`:不可用类型("2"-限制星期+节日,"3"-自定义日期) - `unavaiLableDate`:不可用日期值 #### 团购券不可用日期 | DisableDateType | 说明 | 格式 | 示例 | |-----------------|------|------|------| | 1 | 限制星期+节日 | `星期;节日ID` | `星期一,星期二;1,2,3` | | 2 | 自定义日期范围 | `开始,结束;开始,结束` | `2025-01-01,2025-01-03;2025-02-01,2025-02-05` | **团购券字段**: - `disableDateType`:不可用类型(1-限制星期+节日,2-自定义日期) - `disableDateValue`:不可用日期值 --- ### 3. 使用时间段验证(仅代金券) 验证当前时间是否在允许使用的时间段内。 | 字段 | 说明 | 格式 | |------|------|------| | buyUseStartTime | 开始时间 | 小时数(0-24) | | buyUseEndTime | 结束时间 | 小时数(0-24) | **验证规则**: ``` 正常时间段(如 9-18): 9 ≤ 当前小时 ≤ 18 跨天时间段(如 22-3): 当前小时 ≥ 22 OR 当前小时 ≤ 3 ``` **示例**: - `9,18`:9点到18点可用 - `22,3`:22点到次日3点可用 - `0,24`:全天可用 --- ### 4. 单次核销数量验证(仅代金券) 验证同一订单今日是否已超过核销次数限制。 | 字段 | 说明 | |------|------| | singleCanUse | 单次可核销次数 | **验证逻辑**: ```sql SELECT COUNT(*) FROM order_coupon_middle WHERE order_id = ? AND used_time BETWEEN '今日00:00:00' AND '今日23:59:59' AND status = 2 IF count >= singleCanUse THEN 返回"该订单已经超过今日单次核销数量" ``` **特殊值**: - `"0"`:无限制 - `"1"`:每天只能核销1次 - `"N"`:每天最多核销N次 --- ## 数据库表 ### 涉及的表 1. **order_coupon_middle**(订单券中间表) - `coupon_code`:券码 - `status`:状态(1-待使用,2-已使用) - `order_id`:订单ID - `coupon_id`:券ID - `used_time`:使用时间 2. **life_user_order**(用户订单表) - `id`:订单ID - `coupon_type`:券类型(1-代金券,2-团购) - `pay_time`:支付时间 3. **life_coupon**(代金券表) - `id`:券ID - `expiration_type`:有效期类型 - `expiration_date`:有效天数 - `validity_period`:有效时间段 - `unused_type`:不可用类型 - `unavai_lable_date`:不可用日期 - `buy_use_start_time`:开始使用时间 - `buy_use_end_time`:结束使用时间 - `single_can_use`:单次可核销次数 4. **life_group_buy_main**(团购主表) - `id`:团购ID - `effective_date_type`:有效期类型 - `effective_date_value`:有效期值 - `disable_date_type`:不可用类型 - `disable_date_value`:不可用日期值 5. **essential_holiday_comparison**(节日对照表) - `id`:节日ID - `start_time`:开始时间 - `end_time`:结束时间 --- ## 错误码说明 | 错误信息 | 说明 | 处理建议 | |----------|------|----------| | 该劵不是待使用状态 | 券已被使用/过期/取消 | 检查券状态 | | 该劵不在有效期内 | 券已过期或未到使用时间 | 检查有效期配置 | | 该劵在不可用日期内 | 当前日期在不可用范围内 | 更换使用日期 | | 该订单已经超过今日单次核销数量 | 今日核销次数达到上限 | 明日再试 | | 订单不存在 | 订单ID无效 | 检查订单数据 | | 代金券不存在 | 券ID无效 | 检查券数据 | | 团购券不存在 | 团购ID无效 | 检查团购数据 | | 有效期配置异常 | 配置数据格式错误 | 检查配置 | | 使用时间配置异常 | 时间格式错误 | 检查配置 | --- ## 技术实现 ### Controller 层 ```java @ApiOperation("核销订单前效验") @GetMapping("/verifyOrder") public R verifyOrder(@RequestParam("orderCode") String orderCode) { log.info("CouponManageController.verifyOrder?orderCode={}", orderCode); try { return couponManageService.verifyOrder(orderCode); } catch (Exception e) { log.error("CouponManageController.verifyOrder ERROR: {}", e.getMessage(), e); return R.fail("效验失败:" + e.getMessage()); } } ``` ### Service 层架构 ``` verifyOrder (主入口) ↓ ├─ verifyCoupon (代金券验证) │ ├─ validateCouponValidity (有效期验证) │ ├─ validateCouponUnavailableDate (不可用日期验证) │ ├─ validateCouponUseTime (使用时间验证) │ └─ validateCouponSingleUse (单次核销验证) │ └─ verifyGroupBuy (团购券验证) ├─ validateGroupBuyValidity (有效期验证) └─ validateGroupBuyUnavailableDate (不可用日期验证) ``` **优势**: - ✅ 模块化设计,每个验证逻辑独立 - ✅ 易于扩展和维护 - ✅ 完整的日志记录 - ✅ 详细的异常处理 --- ## 测试用例 ### 测试场景 #### 1. 正常场景 | 场景 | 券码 | 预期结果 | |------|------|----------| | 有效的代金券 | COUPON001 | 效验通过 | | 有效的团购券 | GROUP001 | 效验通过 | #### 2. 异常场景 | 场景 | 预期结果 | |------|----------| | 券码不存在 | 该劵不是待使用状态 | | 券已使用 | 该劵不是待使用状态 | | 券已过期 | 该劵不在有效期内 | | 当前星期不可用 | 该劵在不可用日期内 | | 当前时间不可用 | 该劵不在有效期内 | | 超过核销次数 | 该订单已经超过今日单次核销数量 | --- ## 注意事项 1. **时间相关** - 所有时间比较都基于服务器当前时间 - 跨天时间段需要特殊处理(如22点-3点) - 日期格式统一使用 `yyyy-MM-dd` 2. **数据格式** - 多个值使用逗号分隔(如 `星期一,星期二`) - 范围值使用分号分隔(如 `星期;节日ID`) - 日期范围使用逗号分隔(如 `2025-01-01,2025-01-03`) 3. **空值处理** - 配置为空或"0"时,表示无限制 - 需要对所有字段进行空值检查 4. **性能优化** - 数据库查询使用索引(券码、订单ID等) - 复杂验证逻辑可考虑缓存节日信息 5. **安全性** - 验证失败统一返回错误信息,不暴露内部逻辑 - 记录详细日志用于问题排查 --- ## 迁移说明 ### 原接口(app端) - **路径**:`/alienStore/coupon/orderVerify` - **Controller**:`LifeCouponController` - **Service**:`LifeCouponService.orderVerify()` ### 新接口(web端) - **路径**:`/couponManage/verifyOrder` - **Controller**:`CouponManageController` - **Service**:`CouponManageService.verifyOrder()` ### 改进点 1. ✅ **代码结构优化** - 将验证逻辑拆分为多个独立方法 - 每个验证步骤职责单一 2. ✅ **错误处理增强** - 添加更详细的异常信息 - 完整的日志记录 3. ✅ **代码可读性** - 使用清晰的方法命名 - 添加详细的注释 4. ✅ **业务逻辑复用** - 完全复用原有业务逻辑 - 保持与app端一致的验证规则 --- ## 更新日志 ### 2025-11-13 **新增功能**: - ✅ 创建 `CouponManageController`(优惠券管理控制器) - ✅ 创建 `CouponManageService` 接口 - ✅ 创建 `CouponManageServiceImpl` 实现类 - ✅ 实现 `verifyOrder` 核销前效验接口 - ✅ 支持代金券和团购券两种类型验证 - ✅ 完整的验证逻辑: - 有效期验证 - 不可用日期验证 - 使用时间段验证 - 单次核销数量验证 - ✅ 完整的日志记录和异常处理 - ✅ Linter检查:无错误 **涉及文件**: - `CouponManageController.java` - 新增 - `CouponManageService.java` - 新增 - `CouponManageServiceImpl.java` - 新增 - `API_COUPON_VERIFY.md` - 新增(本文档) **开发人员**:ssk --- ## 常见问题 ### Q1:券码格式有什么要求? **A**:券码由系统生成,通常是字母+数字组合,无固定格式要求。 ### Q2:一张券可以被核销多次吗? **A**:取决于代金券的 `singleCanUse` 配置: - `"0"`:无限制 - `"1"`:每天只能核销1次 - `"N"`:每天最多核销N次 ### Q3:跨天时间段如何处理? **A**:例如22点-3点表示22:00-次日03:00,验证逻辑为: ``` 当前小时 >= 22 OR 当前小时 <= 3 → 可用 ``` ### Q4:节日ID从哪里获取? **A**:节日ID来自 `essential_holiday_comparison` 表,由系统管理员配置。 ### Q5:如何测试这个接口? **A**: 1. 准备测试数据(创建订单券) 2. 使用 Swagger UI 测试:`http://localhost:port/doc.html` 3. 或使用 Postman/curl 发送GET请求 --- **文档版本**:v1.0 **最后更新**:2025-11-13 **维护人员**:ssk