diff --git a/src/main/java/com/ycwl/basic/pricing/dto/resp/SceneCouponAvailableResp.java b/src/main/java/com/ycwl/basic/pricing/dto/resp/SceneCouponAvailableResp.java index ac35fee1..f504b665 100644 --- a/src/main/java/com/ycwl/basic/pricing/dto/resp/SceneCouponAvailableResp.java +++ b/src/main/java/com/ycwl/basic/pricing/dto/resp/SceneCouponAvailableResp.java @@ -3,7 +3,7 @@ package com.ycwl.basic.pricing.dto.resp; import lombok.Data; import java.math.BigDecimal; -import java.time.LocalDateTime; +import java.util.Date; /** * 场景下可领取优惠券响应 @@ -44,12 +44,12 @@ public class SceneCouponAvailableResp { /** * 有效期起始 */ - private LocalDateTime validFrom; + private Date validFrom; /** * 有效期结束 */ - private LocalDateTime validUntil; + private Date validUntil; /** * 用户可领取数量限制(每人最多可领,null或0表示无限制) diff --git a/src/main/java/com/ycwl/basic/pricing/dto/resp/SceneCouponConfigResp.java b/src/main/java/com/ycwl/basic/pricing/dto/resp/SceneCouponConfigResp.java index 2b32f833..df924645 100644 --- a/src/main/java/com/ycwl/basic/pricing/dto/resp/SceneCouponConfigResp.java +++ b/src/main/java/com/ycwl/basic/pricing/dto/resp/SceneCouponConfigResp.java @@ -3,7 +3,6 @@ package com.ycwl.basic.pricing.dto.resp; import lombok.Data; import java.math.BigDecimal; -import java.time.LocalDateTime; import java.util.Date; /** @@ -55,10 +54,10 @@ public class SceneCouponConfigResp { /** * 优惠券有效期起始 */ - private LocalDateTime couponValidFrom; + private Date couponValidFrom; /** * 优惠券有效期结束 */ - private LocalDateTime couponValidUntil; + private Date couponValidUntil; } diff --git a/src/main/java/com/ycwl/basic/pricing/entity/PriceCouponConfig.java b/src/main/java/com/ycwl/basic/pricing/entity/PriceCouponConfig.java index 09a58060..fd85c025 100644 --- a/src/main/java/com/ycwl/basic/pricing/entity/PriceCouponConfig.java +++ b/src/main/java/com/ycwl/basic/pricing/entity/PriceCouponConfig.java @@ -8,7 +8,6 @@ import com.ycwl.basic.pricing.enums.CouponType; import lombok.Data; import java.math.BigDecimal; -import java.time.LocalDateTime; import java.util.Date; /** @@ -80,12 +79,12 @@ public class PriceCouponConfig { /** * 生效时间 */ - private LocalDateTime validFrom; - + private Date validFrom; + /** * 失效时间 */ - private LocalDateTime validUntil; + private Date validUntil; /** * 是否启用 diff --git a/src/main/java/com/ycwl/basic/pricing/mapper/PriceCouponConfigMapper.java b/src/main/java/com/ycwl/basic/pricing/mapper/PriceCouponConfigMapper.java index c7e8710c..7e491dc6 100644 --- a/src/main/java/com/ycwl/basic/pricing/mapper/PriceCouponConfigMapper.java +++ b/src/main/java/com/ycwl/basic/pricing/mapper/PriceCouponConfigMapper.java @@ -40,12 +40,19 @@ public interface PriceCouponConfigMapper extends BaseMapper { int incrementUsedQuantity(Long couponId); /** - * 原子性增加已领取数量(仅对有限库存的优惠券生效) + * 原子性增加已领取数量(仅对有限库存的优惠券生效,带库存检查) */ @Update("UPDATE price_coupon_config SET claimed_quantity = COALESCE(claimed_quantity, 0) + 1, " + "update_time = NOW() WHERE id = #{couponId} AND total_quantity IS NOT NULL AND total_quantity > 0 " + "AND COALESCE(claimed_quantity, 0) < total_quantity") int incrementClaimedQuantityIfAvailable(@Param("couponId") Long couponId); + + /** + * 无条件增加已领取数量(用于无限量优惠券的领取统计) + */ + @Update("UPDATE price_coupon_config SET claimed_quantity = COALESCE(claimed_quantity, 0) + 1, " + + "update_time = NOW() WHERE id = #{couponId}") + int incrementClaimedQuantity(@Param("couponId") Long couponId); /** * 插入优惠券配置 diff --git a/src/main/java/com/ycwl/basic/pricing/service/impl/CouponServiceImpl.java b/src/main/java/com/ycwl/basic/pricing/service/impl/CouponServiceImpl.java index 7c3644a8..fe35367e 100644 --- a/src/main/java/com/ycwl/basic/pricing/service/impl/CouponServiceImpl.java +++ b/src/main/java/com/ycwl/basic/pricing/service/impl/CouponServiceImpl.java @@ -23,7 +23,6 @@ import org.springframework.transaction.interceptor.TransactionAspectSupport; import java.math.BigDecimal; import java.math.RoundingMode; -import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -316,11 +315,11 @@ public class CouponServiceImpl implements ICouponService { } // 4. 检查优惠券有效期 - LocalDateTime now = LocalDateTime.now(); - if (coupon.getValidFrom() != null && now.isBefore(coupon.getValidFrom())) { + Date now = new Date(); + if (coupon.getValidFrom() != null && now.before(coupon.getValidFrom())) { return CouponClaimResult.failure(CouponClaimResult.ERROR_COUPON_EXPIRED, "优惠券尚未生效"); } - if (coupon.getValidUntil() != null && now.isAfter(coupon.getValidUntil())) { + if (coupon.getValidUntil() != null && now.after(coupon.getValidUntil())) { return CouponClaimResult.failure(CouponClaimResult.ERROR_COUPON_EXPIRED, "优惠券已过期"); } @@ -366,17 +365,20 @@ public class CouponServiceImpl implements ICouponService { } // 9. 更新优惠券已领取数量(区分于已使用数量) - // 仅在有总量限制时才更新claimedQuantity(totalQuantity为正整数) if (coupon.getTotalQuantity() != null && coupon.getTotalQuantity() > 0) { + // 有总量限制:使用带库存检查的原子更新 int affected = couponConfigMapper.incrementClaimedQuantityIfAvailable(coupon.getId()); if (affected == 0) { throw new CouponInvalidException( CouponClaimResult.ERROR_COUPON_OUT_OF_STOCK, "优惠券已被领取完,请稍后重试"); } - int updatedClaimedQuantity = (coupon.getClaimedQuantity() == null ? 0 : coupon.getClaimedQuantity()) + 1; - coupon.setClaimedQuantity(updatedClaimedQuantity); + } else { + // 无总量限制:无条件增加已领取数量(用于统计) + couponConfigMapper.incrementClaimedQuantity(coupon.getId()); } + int updatedClaimedQuantity = (coupon.getClaimedQuantity() == null ? 0 : coupon.getClaimedQuantity()) + 1; + coupon.setClaimedQuantity(updatedClaimedQuantity); log.info("优惠券领取成功: userId={}, couponId={}, claimRecordId={}", request.getUserId(), request.getCouponId(), claimRecord.getId()); diff --git a/src/main/java/com/ycwl/basic/pricing/service/impl/SceneCouponServiceImpl.java b/src/main/java/com/ycwl/basic/pricing/service/impl/SceneCouponServiceImpl.java index e304b205..28e2811a 100644 --- a/src/main/java/com/ycwl/basic/pricing/service/impl/SceneCouponServiceImpl.java +++ b/src/main/java/com/ycwl/basic/pricing/service/impl/SceneCouponServiceImpl.java @@ -24,7 +24,6 @@ import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -301,11 +300,11 @@ public class SceneCouponServiceImpl implements ISceneCouponService { } // 2. 检查有效期 - LocalDateTime now = LocalDateTime.now(); - if (coupon.getValidFrom() != null && now.isBefore(coupon.getValidFrom())) { + Date now = new Date(); + if (coupon.getValidFrom() != null && now.before(coupon.getValidFrom())) { return "优惠券尚未生效"; } - if (coupon.getValidUntil() != null && now.isAfter(coupon.getValidUntil())) { + if (coupon.getValidUntil() != null && now.after(coupon.getValidUntil())) { return "优惠券已过期"; }