mirror of
https://codeup.aliyun.com/67c68d4e484ca2f0a13ac3c1/ydc/jsowell-charger-web.git
synced 2026-06-14 20:30:04 +08:00
update 优惠券接口
This commit is contained in:
@@ -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` 返回已有结果
|
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)`
|
2. **库存扣减**:`UPDATE ... SET stock_remain=stock_remain-1 WHERE id=? AND (stock_remain>0 OR stock_remain=-1)`
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
|
|||||||
public void edit(CouponTemplate template, Long loginMerchantId, boolean isPlatformAdmin) {
|
public void edit(CouponTemplate template, Long loginMerchantId, boolean isPlatformAdmin) {
|
||||||
CouponTemplate existing = couponTemplateMapper.selectById(template.getId());
|
CouponTemplate existing = couponTemplateMapper.selectById(template.getId());
|
||||||
if (existing == null) {
|
if (existing == null) {
|
||||||
throw new BusinessException("券模板不存在");
|
throw new BusinessException("ERROR", "券模板不存在");
|
||||||
}
|
}
|
||||||
checkOwnership(existing, loginMerchantId, isPlatformAdmin);
|
checkOwnership(existing, loginMerchantId, isPlatformAdmin);
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
|
|||||||
if (hasExchanged) {
|
if (hasExchanged) {
|
||||||
if (template.getType() != null || template.getPointsCost() != null
|
if (template.getType() != null || template.getPointsCost() != null
|
||||||
|| template.getValidityType() != null || template.getValidDays() != 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) {
|
public void changeStatus(Long id, Integer status, Long loginMerchantId, boolean isPlatformAdmin) {
|
||||||
CouponTemplate existing = couponTemplateMapper.selectById(id);
|
CouponTemplate existing = couponTemplateMapper.selectById(id);
|
||||||
if (existing == null) {
|
if (existing == null) {
|
||||||
throw new BusinessException("券模板不存在");
|
throw new BusinessException("ERROR", "券模板不存在");
|
||||||
}
|
}
|
||||||
checkOwnership(existing, loginMerchantId, isPlatformAdmin);
|
checkOwnership(existing, loginMerchantId, isPlatformAdmin);
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
|
|||||||
}
|
}
|
||||||
// 运营商管理员不能选全平台
|
// 运营商管理员不能选全平台
|
||||||
if (!isPlatformAdmin && scopeType == 1) {
|
if (!isPlatformAdmin && scopeType == 1) {
|
||||||
throw new BusinessException("运营商管理员不能创建全平台范围的券");
|
throw new BusinessException("ERROR", "运营商管理员不能创建全平台范围的券");
|
||||||
}
|
}
|
||||||
// 运营商管理员选指定站点时,校验站点归属
|
// 运营商管理员选指定站点时,校验站点归属
|
||||||
if (!isPlatformAdmin && scopeType == 3 && !CollectionUtils.isEmpty(template.getScopeList())) {
|
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) {
|
private void checkOwnership(CouponTemplate template, Long loginMerchantId, boolean isPlatformAdmin) {
|
||||||
if (!isPlatformAdmin) {
|
if (!isPlatformAdmin) {
|
||||||
if (!loginMerchantId.equals(template.getCreatorMerchantId())) {
|
if (!loginMerchantId.equals(template.getCreatorMerchantId())) {
|
||||||
throw new BusinessException("无权操作该券模板");
|
throw new BusinessException("ERROR", "无权操作该券模板");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,24 +81,24 @@ public class MemberCouponServiceImpl implements MemberCouponService {
|
|||||||
public MemberCoupon exchange(String memberId, Long templateId, String requestId) {
|
public MemberCoupon exchange(String memberId, Long templateId, String requestId) {
|
||||||
CouponTemplate template = couponTemplateMapper.selectById(templateId);
|
CouponTemplate template = couponTemplateMapper.selectById(templateId);
|
||||||
if (template == null || template.getStatus() != 1) {
|
if (template == null || template.getStatus() != 1) {
|
||||||
throw new BusinessException("券模板不存在或已下架");
|
throw new BusinessException("ERROR", "券模板不存在或已下架");
|
||||||
}
|
}
|
||||||
|
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
|
|
||||||
// 1. 兑换时间段校验
|
// 1. 兑换时间段校验
|
||||||
if (template.getExchangeStartTime() != null && now.before(template.getExchangeStartTime())) {
|
if (template.getExchangeStartTime() != null && now.before(template.getExchangeStartTime())) {
|
||||||
throw new BusinessException("兑换活动尚未开始");
|
throw new BusinessException("ERROR", "兑换活动尚未开始");
|
||||||
}
|
}
|
||||||
if (template.getExchangeEndTime() != null && now.after(template.getExchangeEndTime())) {
|
if (template.getExchangeEndTime() != null && now.after(template.getExchangeEndTime())) {
|
||||||
throw new BusinessException("兑换活动已结束");
|
throw new BusinessException("ERROR", "兑换活动已结束");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 单用户累计限额
|
// 2. 单用户累计限额
|
||||||
if (template.getTotalLimit() != null && template.getTotalLimit() > 0) {
|
if (template.getTotalLimit() != null && template.getTotalLimit() > 0) {
|
||||||
int total = memberCouponMapper.countByMemberAndTemplate(memberId, templateId);
|
int total = memberCouponMapper.countByMemberAndTemplate(memberId, templateId);
|
||||||
if (total >= template.getTotalLimit()) {
|
if (total >= template.getTotalLimit()) {
|
||||||
throw new BusinessException("您已达到兑换上限");
|
throw new BusinessException("ERROR", "您已达到兑换上限");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ public class MemberCouponServiceImpl implements MemberCouponService {
|
|||||||
Date[] monthRange = getMonthRange(now);
|
Date[] monthRange = getMonthRange(now);
|
||||||
int monthly = memberCouponMapper.countMonthByMemberAndTemplate(memberId, templateId, monthRange[0], monthRange[1]);
|
int monthly = memberCouponMapper.countMonthByMemberAndTemplate(memberId, templateId, monthRange[0], monthRange[1]);
|
||||||
if (monthly >= template.getMonthlyLimit()) {
|
if (monthly >= template.getMonthlyLimit()) {
|
||||||
throw new BusinessException("本月兑换已达上限");
|
throw new BusinessException("ERROR", "本月兑换已达上限");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ public class MemberCouponServiceImpl implements MemberCouponService {
|
|||||||
Date[] dayRange = getDayRange(now);
|
Date[] dayRange = getDayRange(now);
|
||||||
int daily = memberCouponMapper.countTodayByMemberAndTemplate(memberId, templateId, dayRange[0], dayRange[1]);
|
int daily = memberCouponMapper.countTodayByMemberAndTemplate(memberId, templateId, dayRange[0], dayRange[1]);
|
||||||
if (daily >= template.getDailyLimit()) {
|
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) {
|
if (template.getStockRemain() != null && template.getStockRemain() != -1) {
|
||||||
int updated = couponTemplateMapper.deductStock(templateId);
|
int updated = couponTemplateMapper.deductStock(templateId);
|
||||||
if (updated <= 0) {
|
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()))
|
.filter(c -> requestId.equals(c.getExchangeRequestId()))
|
||||||
.map(MemberCoupon::getCouponNo)
|
.map(MemberCoupon::getCouponNo)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow(() -> new BusinessException("兑换异常,请重试")));
|
.orElseThrow(() -> new BusinessException("ERROR", "兑换异常,请重试")));
|
||||||
}
|
}
|
||||||
return coupon;
|
return coupon;
|
||||||
}
|
}
|
||||||
@@ -172,7 +172,7 @@ public class MemberCouponServiceImpl implements MemberCouponService {
|
|||||||
public MemberCoupon detail(String memberId, String couponNo) {
|
public MemberCoupon detail(String memberId, String couponNo) {
|
||||||
MemberCoupon coupon = memberCouponMapper.selectByCouponNo(couponNo);
|
MemberCoupon coupon = memberCouponMapper.selectByCouponNo(couponNo);
|
||||||
if (coupon == null || !memberId.equals(coupon.getMemberId())) {
|
if (coupon == null || !memberId.equals(coupon.getMemberId())) {
|
||||||
throw new BusinessException("券不存在");
|
throw new BusinessException("ERROR", "券不存在");
|
||||||
}
|
}
|
||||||
return coupon;
|
return coupon;
|
||||||
}
|
}
|
||||||
@@ -191,14 +191,14 @@ public class MemberCouponServiceImpl implements MemberCouponService {
|
|||||||
if (existing.getResult() == 1) {
|
if (existing.getResult() == 1) {
|
||||||
return; // 已成功核销,幂等返回
|
return; // 已成功核销,幂等返回
|
||||||
}
|
}
|
||||||
throw new BusinessException("该核销请求已失败,请重新发起");
|
throw new BusinessException("ERROR", "该核销请求已失败,请重新发起");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MemberCoupon coupon = memberCouponMapper.selectByCouponNo(couponNo);
|
MemberCoupon coupon = memberCouponMapper.selectByCouponNo(couponNo);
|
||||||
if (coupon == null) {
|
if (coupon == null) {
|
||||||
writeVerifyLog(couponNo, requestId, storeId, operatorId, 2, "券不存在");
|
writeVerifyLog(couponNo, requestId, storeId, operatorId, 2, "券不存在");
|
||||||
throw new BusinessException("券不存在");
|
throw new BusinessException("ERROR", "券不存在");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 校验 scope:核销门店是否在券可用范围内
|
// 校验 scope:核销门店是否在券可用范围内
|
||||||
@@ -206,7 +206,7 @@ public class MemberCouponServiceImpl implements MemberCouponService {
|
|||||||
if (template != null && template.getScopeType() != null && template.getScopeType() > 1) {
|
if (template != null && template.getScopeType() != null && template.getScopeType() > 1) {
|
||||||
if (!isScopeMatch(template, storeId)) {
|
if (!isScopeMatch(template, storeId)) {
|
||||||
writeVerifyLog(couponNo, requestId, storeId, operatorId, 2, "核销门店不在券可用范围内");
|
writeVerifyLog(couponNo, requestId, storeId, operatorId, 2, "核销门店不在券可用范围内");
|
||||||
throw new BusinessException("核销门店不在券可用范围内");
|
throw new BusinessException("ERROR", "核销门店不在券可用范围内");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user