| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- package com.ylx.massage.service.impl;
- import cn.hutool.core.collection.CollUtil;
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.ylx.common.exception.ServiceException;
- import com.ylx.massage.domain.Coupon;
- import com.ylx.massage.domain.CouponReceive;
- import com.ylx.massage.mapper.CouponMapper;
- import com.ylx.massage.service.CouponReceiveService;
- import com.ylx.massage.service.CouponService;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import javax.annotation.Resource;
- import java.math.BigDecimal;
- import java.math.RoundingMode;
- import java.time.LocalDate;
- import java.time.LocalDateTime;
- import java.util.List;
- import java.util.Map;
- /**
- * 优惠券的规则信息(Coupon)表服务实现类
- *
- * @author makejava
- * @since 2024-05-13 16:32:59
- */
- @Slf4j
- @Service("couponService")
- public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> implements CouponService {
- @Resource
- private CouponReceiveService couponReceiveService;
- @Override
- public BigDecimal calculateDiscountAmount(String couponId, String openId, BigDecimal orderAmount) {
- // 1. 查询优惠券领取详情
- Map<String, Object> detail = couponReceiveService.selectCouponDetailForCalc(couponId, openId);
- if (CollUtil.isEmpty(detail)) {
- throw new ServiceException("未查询到该用户的优惠券信息");
- }
- // 3. 校验优惠券状态(必须是 0:待使用)
- Integer couponStatus = (Integer) detail.get("coupon_status");
- if (couponStatus == null || couponStatus != 0) {
- throw new ServiceException("优惠券状态异常,不可使用");
- }
- // 4. 校验有效期
- LocalDate validStart = ((java.sql.Date) detail.get("valid_start_time")).toLocalDate();
- LocalDate expiration = ((java.sql.Date) detail.get("expiration_time")).toLocalDate();
- LocalDate today = LocalDate.now();
- if (today.isBefore(validStart) || today.isAfter(expiration)) {
- throw new ServiceException("优惠券不在有效期内");
- }
- // 5. 提取优惠规则字段
- Integer discountType = (Integer) detail.get("discount_type");
- BigDecimal discountValue = (BigDecimal) detail.get("discount_value");
- BigDecimal rebValue = (BigDecimal) detail.get("reb_value");
- BigDecimal thresholdAmount = (BigDecimal) detail.get("threshold_amount");
- // 6. 根据类型计算抵扣金额
- BigDecimal discountAmount = BigDecimal.ZERO;
- switch (discountType) {
- case 1: // 无门槛
- discountAmount = discountValue;
- break;
- case 2: // 折扣 (reb_value 例如 0.8 代表8折)
- // 抵扣金额 = 订单金额 * (1 - 折扣值)
- discountAmount = orderAmount.multiply(BigDecimal.ONE.subtract(rebValue));
- break;
- case 3: // 满减
- if (orderAmount.compareTo(thresholdAmount) < 0) {
- throw new ServiceException("订单金额未达到满减门槛");
- }
- discountAmount = discountValue;
- break;
- default:
- throw new ServiceException("未知的优惠券类型: " + discountType);
- }
- // 7. 兜底逻辑:抵扣金额不能大于订单实际金额
- if (discountAmount.compareTo(orderAmount) > 0) {
- discountAmount = orderAmount;
- }
- // 8. 保留两位小数,四舍五入
- return discountAmount.setScale(2, RoundingMode.HALF_UP);
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void useCoupon(String couponId, String openId, Long orderId, Integer orderType) {
- // 1. 乐观锁核销用户领取记录
- int updatedRows = couponReceiveService.useCouponOptimisticLock(couponId, openId, orderId, orderType, LocalDateTime.now());
- if (updatedRows == 0) {
- throw new ServiceException("优惠券核销失败:状态异常或已被使用");
- }
- // 2. 规则表使用数量 +1
- int ruleUpdatedRows = couponReceiveService.incrementUsedNum(couponId);
- if (ruleUpdatedRows == 0) {
- throw new ServiceException("优惠券规则状态异常,核销中止");
- }
- log.info("优惠券核销成功: couponId={}, openId={}, orderId={}", couponId, openId, orderId);
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void returnCoupon(String couponId, String openId, Long orderId) {
- // 1. 将已使用的券退回到待使用状态
- int rows = couponReceiveService.returnCouponOptimisticLock(couponId, openId, orderId);
- if (rows == 0) {
- log.warn("退还优惠券失败,可能券已过期或不属于该订单: couponId={}, orderId={}", couponId, orderId);
- return;
- }
- // 2. 规则表使用数量 -1
- this.couponReceiveService.decrementUsedNum(couponId);
- log.info("优惠券退还成功: couponId={}, orderId={}", couponId, orderId);
- }
- }
|