feat(market):新增优惠卷核销的功能

This commit is contained in:
JIAN 2024-10-01 13:40:28 +08:00
parent a355354d5f
commit 75ab9620f4
11 changed files with 149 additions and 27 deletions

View File

@ -1,8 +1,12 @@
package com.jzo2o.api.market;
import com.jzo2o.api.market.dto.request.CouponUseReqDTO;
import com.jzo2o.api.market.dto.response.AvailableCouponsResDTO;
import com.jzo2o.api.market.dto.response.CouponUseResDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.math.BigDecimal;
@ -19,4 +23,10 @@ public interface CouponApi {
*/
@GetMapping("/getAvailable")
List<AvailableCouponsResDTO> getAvailableCoupon(@RequestParam BigDecimal totalAmount);
/**
* 用户核销优惠卷返回优惠金额
*/
@PostMapping("/use")
CouponUseResDTO useCoupon(@RequestBody CouponUseReqDTO couponUseReqDTO);
}

View File

@ -2,11 +2,13 @@ package com.jzo2o.api.market.dto.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;
import java.math.BigDecimal;
@Data
@Builder
@ApiModel("优惠券使用模型")
public class CouponUseReqDTO {
@ApiModelProperty("优惠券id")

View File

@ -2,12 +2,16 @@ package com.jzo2o.api.market.dto.response;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
@Data
@ApiModel("优惠券使用返回信息模型")
@NoArgsConstructor
@AllArgsConstructor
public class CouponUseResDTO {
@ApiModelProperty("优惠金额")
private BigDecimal discountAmount;

View File

@ -1,15 +1,15 @@
package com.jzo2o.market.controller.inner;
import com.jzo2o.api.market.CouponApi;
import com.jzo2o.api.market.dto.request.CouponUseReqDTO;
import com.jzo2o.api.market.dto.response.AvailableCouponsResDTO;
import com.jzo2o.api.market.dto.response.CouponUseResDTO;
import com.jzo2o.market.service.ICouponService;
import com.jzo2o.market.service.ICouponWriteOffService;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.math.BigDecimal;
@ -25,6 +25,8 @@ import java.util.List;
public class CouponController implements CouponApi {
@Resource
private ICouponService couponService;
@Resource
private ICouponWriteOffService couponWriteOffService;
/**
* 根据订单金额获取当前用户可用优惠卷
@ -36,4 +38,11 @@ public class CouponController implements CouponApi {
public List<AvailableCouponsResDTO> getAvailableCoupon(@RequestParam BigDecimal totalAmount) {
return couponService.getAvailableCoupon(totalAmount);
}
@Override
@PostMapping("/use")
@ApiOperation("使用优惠卷并返回优惠金额")
public CouponUseResDTO useCoupon(@RequestBody CouponUseReqDTO couponUseReqDTO) {
return couponWriteOffService.use(couponUseReqDTO);
}
}

View File

@ -1,18 +1,17 @@
package com.jzo2o.market.model.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import lombok.*;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 优惠券核销表
* </p>
*
* @author itcast
* @since 2023-09-22
*/
@ -26,7 +25,7 @@ public class CouponWriteOff implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.NONE)
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/**
@ -63,6 +62,4 @@ public class CouponWriteOff implements Serializable {
* 核销人姓名
*/
private String writeOffManName;
}

View File

@ -44,4 +44,11 @@ public interface ICouponService extends IService<Coupon> {
* 根据订单金额获取当前用户可用优惠卷
*/
List<AvailableCouponsResDTO> getAvailableCoupon(BigDecimal totalAmount);
/**
* 计算优惠卷的优惠价格
* @param coupon 优惠卷信息
* @param totalAmount 订单总金额
*/
BigDecimal calcDiscountAmount(Coupon coupon, BigDecimal totalAmount);
}

View File

@ -1,5 +1,7 @@
package com.jzo2o.market.service;
import com.jzo2o.api.market.dto.request.CouponUseReqDTO;
import com.jzo2o.api.market.dto.response.CouponUseResDTO;
import com.jzo2o.market.model.domain.CouponWriteOff;
import com.baomidou.mybatisplus.extension.service.IService;
@ -7,11 +9,12 @@ import com.baomidou.mybatisplus.extension.service.IService;
* <p>
* 优惠券核销表 服务类
* </p>
*
* @author itcast
* @since 2023-09-22
*/
public interface ICouponWriteOffService extends IService<CouponWriteOff> {
/**
* 核销指定的优惠卷并返回优惠金额
*/
CouponUseResDTO use(CouponUseReqDTO couponUseReqDTO);
}

View File

@ -179,7 +179,8 @@ public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> impleme
* @param coupon 优惠卷信息
* @param totalAmount 订单总金额
*/
private BigDecimal calcDiscountAmount(Coupon coupon, BigDecimal totalAmount) {
@Override
public BigDecimal calcDiscountAmount(Coupon coupon, BigDecimal totalAmount) {
CouponTypeEnum type = coupon.getType();
BigDecimal discountAmount = BigDecimal.ZERO;

View File

@ -1,20 +1,77 @@
package com.jzo2o.market.service.impl;
import com.jzo2o.market.model.domain.CouponWriteOff;
import com.jzo2o.market.mapper.CouponWriteOffMapper;
import com.jzo2o.market.service.ICouponWriteOffService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.market.dto.request.CouponUseReqDTO;
import com.jzo2o.api.market.dto.response.CouponUseResDTO;
import com.jzo2o.common.expcetions.BadRequestException;
import com.jzo2o.common.expcetions.DBException;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.market.enums.CouponStatusEnum;
import com.jzo2o.market.mapper.CouponWriteOffMapper;
import com.jzo2o.market.model.domain.Coupon;
import com.jzo2o.market.model.domain.CouponWriteOff;
import com.jzo2o.market.service.ICouponService;
import com.jzo2o.market.service.ICouponWriteOffService;
import com.jzo2o.mvc.utils.UserContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* <p>
* 优惠券核销表 服务实现类
* </p>
*
* @author itcast
* @since 2023-09-22
*/
@Service
public class CouponWriteOffServiceImpl extends ServiceImpl<CouponWriteOffMapper, CouponWriteOff> implements ICouponWriteOffService {
@Resource
private ICouponService couponService;
@Override
@Transactional
public CouponUseResDTO use(CouponUseReqDTO couponUseReqDTO) {
Long couponId = couponUseReqDTO.getId();
BigDecimal totalAmount = couponUseReqDTO.getTotalAmount();
Long userId = UserContext.currentUserId();
LocalDateTime nowTime = LocalDateTime.now();
Coupon coupon = couponService.getById(couponId);
if (ObjectUtils.isEmpty(coupon) || ObjectUtils.notEqual(coupon.getUserId(), userId)) {
throw new BadRequestException("优惠卷不存在");
} else if (coupon.getStatus() != CouponStatusEnum.NO_USE
|| coupon.getValidityTime().isBefore(nowTime)) {
throw new BadRequestException("优惠卷已使用/已失效");
} else if (coupon.getAmountCondition().compareTo(totalAmount) > 0) {
throw new BadRequestException("订单金额未达到满减金额");
}
Long ordersId = couponUseReqDTO.getOrdersId();
if (!couponService.lambdaUpdate()
.eq(Coupon::getId, couponId)
.set(Coupon::getUseTime, nowTime)
.set(Coupon::getStatus, CouponStatusEnum.USED)
.set(Coupon::getOrdersId, ordersId)
.update()) {
throw new DBException("更新优惠卷表失败");
}
if (!this.save(CouponWriteOff.builder()
.couponId(couponId)
.userId(userId)
.ordersId(ordersId)
.activityId(coupon.getActivityId())
.writeOffTime(nowTime)
.writeOffManName(coupon.getUserName())
.writeOffManPhone(coupon.getUserPhone())
.build())) {
throw new DBException("更新核销表失败");
}
return new CouponUseResDTO(couponService.calcDiscountAmount(coupon, totalAmount));
}
}

View File

@ -3,7 +3,9 @@ package com.jzo2o.orders.manager.service.client;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.jzo2o.api.market.CouponApi;
import com.jzo2o.api.market.dto.request.CouponUseReqDTO;
import com.jzo2o.api.market.dto.response.AvailableCouponsResDTO;
import com.jzo2o.api.market.dto.response.CouponUseResDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@ -37,4 +39,20 @@ public class MarketClient {
log.warn("优惠卷接口异常(触发熔断降级), 总金额: {}", totalAmount, blockException);
return null;
}
@SentinelResource(value = "useCoupon",
fallback = "useCouponFallback", blockHandler = "useCouponBlockHandler")
public CouponUseResDTO useCoupon(CouponUseReqDTO couponUseReqDTO) {
return couponApi.useCoupon(couponUseReqDTO);
}
public CouponUseResDTO useCouponFallback(CouponUseReqDTO couponUseReqDTO, Throwable throwable) {
log.warn("优惠卷接口异常(未触发熔断), 相关信息: {}", couponUseReqDTO, throwable);
return null;
}
public CouponUseResDTO useCouponBlockHandler(CouponUseReqDTO couponUseReqDTO, BlockException blockException) {
log.warn("优惠卷接口异常(触发熔断降级), 相关信息: {}", couponUseReqDTO, blockException);
return null;
}
}

View File

@ -3,7 +3,9 @@ package com.jzo2o.orders.manager.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.customer.dto.response.AddressBookResDTO;
import com.jzo2o.api.foundations.dto.response.ServeAggregationResDTO;
import com.jzo2o.api.market.dto.request.CouponUseReqDTO;
import com.jzo2o.api.market.dto.response.AvailableCouponsResDTO;
import com.jzo2o.api.market.dto.response.CouponUseResDTO;
import com.jzo2o.api.trade.NativePayApi;
import com.jzo2o.api.trade.TradingApi;
import com.jzo2o.api.trade.dto.request.NativePayReqDTO;
@ -98,10 +100,22 @@ public class OrdersCreateServiceImpl extends ServiceImpl<OrdersMapper, Orders> i
}
// 获取订单id
Long orderId = generateOrderId();
// TODO 获取优惠卷相关信息
BigDecimal discountAmount = BigDecimal.ZERO;
// 计算价格
// 计算总金额
BigDecimal totalAmount = serve.getPrice().multiply(BigDecimal.valueOf(placeOrderReqDTO.getPurNum()));
// 计算优惠卷相关金额
BigDecimal discountAmount = BigDecimal.ZERO;
Long couponId = placeOrderReqDTO.getCouponId();
if (ObjectUtils.isNotEmpty(couponId)) {
CouponUseResDTO couponUseResDTO = Optional
.ofNullable(marketClient.useCoupon(CouponUseReqDTO.builder()
.ordersId(orderId)
.id(couponId)
.totalAmount(totalAmount)
.build()))
.orElseThrow(() -> new ForbiddenOperationException("优惠卷核销失败下单失败"));
discountAmount = couponUseResDTO.getDiscountAmount();
}
// 计算实际金额
BigDecimal realPayAmount = totalAmount.subtract(discountAmount);
// 组装订单信息插入数据库完成下单