|
@@ -2,7 +2,9 @@ package com.etotem.cfc.service;
|
|
|
|
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.etotem.cfc.entity.Coupon;
|
|
import com.etotem.cfc.entity.Coupon;
|
|
|
|
|
+import com.etotem.cfc.entity.CouponGrantLog;
|
|
|
import com.etotem.cfc.entity.UserCoupon;
|
|
import com.etotem.cfc.entity.UserCoupon;
|
|
|
|
|
+import com.etotem.cfc.mapper.CouponGrantLogMapper;
|
|
|
import com.etotem.cfc.mapper.CouponMapper;
|
|
import com.etotem.cfc.mapper.CouponMapper;
|
|
|
import com.etotem.cfc.mapper.UserCouponMapper;
|
|
import com.etotem.cfc.mapper.UserCouponMapper;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
@@ -22,6 +24,9 @@ public class CouponService {
|
|
|
@Resource
|
|
@Resource
|
|
|
private UserCouponMapper userCouponMapper;
|
|
private UserCouponMapper userCouponMapper;
|
|
|
|
|
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private CouponGrantLogMapper couponGrantLogMapper;
|
|
|
|
|
+
|
|
|
public List<Coupon> listAvailable(Long userId) {
|
|
public List<Coupon> listAvailable(Long userId) {
|
|
|
List<UserCoupon> userCoupons = userCouponMapper.selectList(
|
|
List<UserCoupon> userCoupons = userCouponMapper.selectList(
|
|
|
new LambdaQueryWrapper<UserCoupon>()
|
|
new LambdaQueryWrapper<UserCoupon>()
|
|
@@ -97,9 +102,16 @@ public class CouponService {
|
|
|
if (!"ALL".equals(coupon.getApplicableTo()) && !coupon.getApplicableTo().equals(orderType)) {
|
|
if (!"ALL".equals(coupon.getApplicableTo()) && !coupon.getApplicableTo().equals(orderType)) {
|
|
|
return null;
|
|
return null;
|
|
|
}
|
|
}
|
|
|
- if (coupon.getMinSpend() != null && orderAmount < coupon.getMinSpend()) {
|
|
|
|
|
|
|
+ // 无门槛券(CASH)忽略起用门槛;满减/折扣券校验
|
|
|
|
|
+ if (!"CASH".equals(coupon.getType()) && coupon.getMinSpend() != null && orderAmount < coupon.getMinSpend()) {
|
|
|
return null;
|
|
return null;
|
|
|
}
|
|
}
|
|
|
|
|
+ // 返回抵扣金额(调用方以 originalAmount - discount 计算最终价)
|
|
|
|
|
+ if ("DISCOUNT".equals(coupon.getType())) {
|
|
|
|
|
+ int rate = coupon.getDiscountRate() != null ? coupon.getDiscountRate() : 9000;
|
|
|
|
|
+ int discount = orderAmount * (10000 - rate) / 10000;
|
|
|
|
|
+ return Math.max(discount, 0);
|
|
|
|
|
+ }
|
|
|
return Math.min(coupon.getValue(), orderAmount);
|
|
return Math.min(coupon.getValue(), orderAmount);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -138,4 +150,99 @@ public class CouponService {
|
|
|
uc.setReceivedAt(new Date());
|
|
uc.setReceivedAt(new Date());
|
|
|
userCouponMapper.insert(uc);
|
|
userCouponMapper.insert(uc);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 发放优惠券并落流水(幂等)。
|
|
|
|
|
+ * period 非空时先查流水:已存在则跳过(PERIODIC 防重用);唯一键冲突由事务回滚保证一致性。
|
|
|
|
|
+ */
|
|
|
|
|
+ @Transactional
|
|
|
|
|
+ public boolean grant(Long userId, Long couponId, String grantType, String period, String source) {
|
|
|
|
|
+ Coupon coupon = couponMapper.selectById(couponId);
|
|
|
|
|
+ if (coupon == null) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (period != null) {
|
|
|
|
|
+ Long exists = couponGrantLogMapper.selectCount(
|
|
|
|
|
+ new LambdaQueryWrapper<CouponGrantLog>()
|
|
|
|
|
+ .eq(CouponGrantLog::getUserId, userId)
|
|
|
|
|
+ .eq(CouponGrantLog::getCouponId, couponId)
|
|
|
|
|
+ .eq(CouponGrantLog::getGrantType, grantType)
|
|
|
|
|
+ .eq(CouponGrantLog::getPeriod, period));
|
|
|
|
|
+ if (exists != null && exists > 0) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ int quantity = coupon.getGrantQuantity() != null && coupon.getGrantQuantity() > 0
|
|
|
|
|
+ ? coupon.getGrantQuantity() : 1;
|
|
|
|
|
+ for (int i = 0; i < quantity; i++) {
|
|
|
|
|
+ issueToUser(couponId, userId);
|
|
|
|
|
+ }
|
|
|
|
|
+ CouponGrantLog log = new CouponGrantLog();
|
|
|
|
|
+ log.setUserId(userId);
|
|
|
|
|
+ log.setCouponId(couponId);
|
|
|
|
|
+ log.setGrantType(grantType);
|
|
|
|
|
+ log.setPeriod(period);
|
|
|
|
|
+ log.setQuantity(quantity);
|
|
|
|
|
+ log.setSource(source);
|
|
|
|
|
+ couponGrantLogMapper.insert(log);
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** JOIN: 开通/续费指定等级会员时发放 */
|
|
|
|
|
+ @Transactional
|
|
|
|
|
+ public void grantJoinCoupons(Long userId, String levelCode, String source) {
|
|
|
|
|
+ List<Coupon> coupons = couponMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<Coupon>()
|
|
|
|
|
+ .eq(Coupon::getGrantType, "JOIN")
|
|
|
|
|
+ .eq(Coupon::getGrantLevelCode, levelCode));
|
|
|
|
|
+ for (Coupon c : coupons) {
|
|
|
|
|
+ grant(userId, c.getId(), "JOIN", null, source);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** POPULATION: 新增家庭成员时发放(目标账户由调用方决定) */
|
|
|
|
|
+ @Transactional
|
|
|
|
|
+ public void grantPopulationCoupons(Long userId, Long memberId) {
|
|
|
|
|
+ List<Coupon> coupons = couponMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<Coupon>()
|
|
|
|
|
+ .eq(Coupon::getGrantType, "POPULATION"));
|
|
|
|
|
+ for (Coupon c : coupons) {
|
|
|
|
|
+ grant(userId, c.getId(), "POPULATION", null, "member:" + memberId);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** PERIODIC: 返回所有周期性补发券模板 */
|
|
|
|
|
+ public List<Coupon> listPeriodicTemplates() {
|
|
|
|
|
+ return couponMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<Coupon>().eq(Coupon::getGrantType, "PERIODIC"));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** 积分兑换中心:所有可兑换券(points_price>0 且在有效期内) */
|
|
|
|
|
+ public List<Coupon> listExchangeable() {
|
|
|
|
|
+ Date now = new Date();
|
|
|
|
|
+ return couponMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<Coupon>()
|
|
|
|
|
+ .gt(Coupon::getPointsPrice, 0)
|
|
|
|
|
+ .le(Coupon::getValidFrom, now)
|
|
|
|
|
+ .ge(Coupon::getValidUntil, now)
|
|
|
|
|
+ .orderByAsc(Coupon::getPointsPrice));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** 商品详情:绑定该商品的兑换券 */
|
|
|
|
|
+ public List<Coupon> listByProduct(Long productId) {
|
|
|
|
|
+ Date now = new Date();
|
|
|
|
|
+ return couponMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<Coupon>()
|
|
|
|
|
+ .eq(Coupon::getProductId, productId)
|
|
|
|
|
+ .gt(Coupon::getPointsPrice, 0)
|
|
|
|
|
+ .le(Coupon::getValidFrom, now)
|
|
|
|
|
+ .ge(Coupon::getValidUntil, now)
|
|
|
|
|
+ .orderByAsc(Coupon::getPointsPrice));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** JOIN 权益展示:所有加入赠券模板 */
|
|
|
|
|
+ public List<Coupon> listJoinRules() {
|
|
|
|
|
+ return couponMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<Coupon>().eq(Coupon::getGrantType, "JOIN"));
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|