update 优惠券接口

This commit is contained in:
Guoqs
2026-03-05 08:58:24 +08:00
parent c231c322f8
commit 675dfd4b95
3 changed files with 25 additions and 18 deletions

View File

@@ -118,7 +118,14 @@
---
## 关键设计决策
## 前端页面
| # | 子任务 | 状态 | 文件 |
|---|--------|------|------|
| F1 | API 文件 | ✅ 完成 | `jsowell-charge-ui/src/api/coupon/template.js` / `record.js` |
| F2 | 券模板管理页 | ✅ 完成 | `jsowell-charge-ui/src/views/coupon/template/index.vue` |
| F3 | 兑换记录页 | ✅ 完成 | `jsowell-charge-ui/src/views/coupon/record/index.vue` |
| F4 | 路由注册 | ✅ 完成 | `jsowell-charge-ui/src/router/index.js` |
1. **兑换幂等**`member_coupon.exchange_request_id` 唯一索引,捕获 `DuplicateKeyException` 返回已有结果
2. **库存扣减**`UPDATE ... SET stock_remain=stock_remain-1 WHERE id=? AND (stock_remain>0 OR stock_remain=-1)`

View File

@@ -74,7 +74,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
public void edit(CouponTemplate template, Long loginMerchantId, boolean isPlatformAdmin) {
CouponTemplate existing = couponTemplateMapper.selectById(template.getId());
if (existing == null) {
throw new BusinessException("券模板不存在");
throw new BusinessException("ERROR", "券模板不存在");
}
checkOwnership(existing, loginMerchantId, isPlatformAdmin);
@@ -83,7 +83,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
if (hasExchanged) {
if (template.getType() != null || template.getPointsCost() != null
|| template.getValidityType() != null || template.getValidDays() != null) {
throw new BusinessException("该券已有用户兑换,不可修改券类型、积分价格、有效期规则等核心字段");
throw new BusinessException("ERROR", "该券已有用户兑换,不可修改券类型、积分价格、有效期规则等核心字段");
}
}
@@ -102,7 +102,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
public void changeStatus(Long id, Integer status, Long loginMerchantId, boolean isPlatformAdmin) {
CouponTemplate existing = couponTemplateMapper.selectById(id);
if (existing == null) {
throw new BusinessException("券模板不存在");
throw new BusinessException("ERROR", "券模板不存在");
}
checkOwnership(existing, loginMerchantId, isPlatformAdmin);
@@ -124,7 +124,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
}
// 运营商管理员不能选全平台
if (!isPlatformAdmin && scopeType == 1) {
throw new BusinessException("运营商管理员不能创建全平台范围的券");
throw new BusinessException("ERROR", "运营商管理员不能创建全平台范围的券");
}
// 运营商管理员选指定站点时,校验站点归属
if (!isPlatformAdmin && scopeType == 3 && !CollectionUtils.isEmpty(template.getScopeList())) {
@@ -142,7 +142,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
private void checkOwnership(CouponTemplate template, Long loginMerchantId, boolean isPlatformAdmin) {
if (!isPlatformAdmin) {
if (!loginMerchantId.equals(template.getCreatorMerchantId())) {
throw new BusinessException("无权操作该券模板");
throw new BusinessException("ERROR", "无权操作该券模板");
}
}
}

View File

@@ -81,24 +81,24 @@ public class MemberCouponServiceImpl implements MemberCouponService {
public MemberCoupon exchange(String memberId, Long templateId, String requestId) {
CouponTemplate template = couponTemplateMapper.selectById(templateId);
if (template == null || template.getStatus() != 1) {
throw new BusinessException("券模板不存在或已下架");
throw new BusinessException("ERROR", "券模板不存在或已下架");
}
Date now = new Date();
// 1. 兑换时间段校验
if (template.getExchangeStartTime() != null && now.before(template.getExchangeStartTime())) {
throw new BusinessException("兑换活动尚未开始");
throw new BusinessException("ERROR", "兑换活动尚未开始");
}
if (template.getExchangeEndTime() != null && now.after(template.getExchangeEndTime())) {
throw new BusinessException("兑换活动已结束");
throw new BusinessException("ERROR", "兑换活动已结束");
}
// 2. 单用户累计限额
if (template.getTotalLimit() != null && template.getTotalLimit() > 0) {
int total = memberCouponMapper.countByMemberAndTemplate(memberId, templateId);
if (total >= template.getTotalLimit()) {
throw new BusinessException("您已达到兑换上限");
throw new BusinessException("ERROR", "您已达到兑换上限");
}
}
@@ -107,7 +107,7 @@ public class MemberCouponServiceImpl implements MemberCouponService {
Date[] monthRange = getMonthRange(now);
int monthly = memberCouponMapper.countMonthByMemberAndTemplate(memberId, templateId, monthRange[0], monthRange[1]);
if (monthly >= template.getMonthlyLimit()) {
throw new BusinessException("本月兑换已达上限");
throw new BusinessException("ERROR", "本月兑换已达上限");
}
}
@@ -116,7 +116,7 @@ public class MemberCouponServiceImpl implements MemberCouponService {
Date[] dayRange = getDayRange(now);
int daily = memberCouponMapper.countTodayByMemberAndTemplate(memberId, templateId, dayRange[0], dayRange[1]);
if (daily >= template.getDailyLimit()) {
throw new BusinessException("今日兑换已达上限");
throw new BusinessException("ERROR", "今日兑换已达上限");
}
}
@@ -124,7 +124,7 @@ public class MemberCouponServiceImpl implements MemberCouponService {
if (template.getStockRemain() != null && template.getStockRemain() != -1) {
int updated = couponTemplateMapper.deductStock(templateId);
if (updated <= 0) {
throw new BusinessException("库存不足,兑换失败");
throw new BusinessException("ERROR", "库存不足,兑换失败");
}
}
@@ -158,7 +158,7 @@ public class MemberCouponServiceImpl implements MemberCouponService {
.filter(c -> requestId.equals(c.getExchangeRequestId()))
.map(MemberCoupon::getCouponNo)
.findFirst()
.orElseThrow(() -> new BusinessException("兑换异常,请重试")));
.orElseThrow(() -> new BusinessException("ERROR", "兑换异常,请重试")));
}
return coupon;
}
@@ -172,7 +172,7 @@ public class MemberCouponServiceImpl implements MemberCouponService {
public MemberCoupon detail(String memberId, String couponNo) {
MemberCoupon coupon = memberCouponMapper.selectByCouponNo(couponNo);
if (coupon == null || !memberId.equals(coupon.getMemberId())) {
throw new BusinessException("券不存在");
throw new BusinessException("ERROR", "券不存在");
}
return coupon;
}
@@ -191,14 +191,14 @@ public class MemberCouponServiceImpl implements MemberCouponService {
if (existing.getResult() == 1) {
return; // 已成功核销,幂等返回
}
throw new BusinessException("该核销请求已失败,请重新发起");
throw new BusinessException("ERROR", "该核销请求已失败,请重新发起");
}
}
MemberCoupon coupon = memberCouponMapper.selectByCouponNo(couponNo);
if (coupon == null) {
writeVerifyLog(couponNo, requestId, storeId, operatorId, 2, "券不存在");
throw new BusinessException("券不存在");
throw new BusinessException("ERROR", "券不存在");
}
// 校验 scope核销门店是否在券可用范围内
@@ -206,7 +206,7 @@ public class MemberCouponServiceImpl implements MemberCouponService {
if (template != null && template.getScopeType() != null && template.getScopeType() > 1) {
if (!isScopeMatch(template, storeId)) {
writeVerifyLog(couponNo, requestId, storeId, operatorId, 2, "核销门店不在券可用范围内");
throw new BusinessException("核销门店不在券可用范围内");
throw new BusinessException("ERROR", "核销门店不在券可用范围内");
}
}