feat(market):新增优惠卷核销的功能
This commit is contained in:
parent
a355354d5f
commit
75ab9620f4
@ -1,8 +1,12 @@
|
|||||||
package com.jzo2o.api.market;
|
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.AvailableCouponsResDTO;
|
||||||
|
import com.jzo2o.api.market.dto.response.CouponUseResDTO;
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
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 org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@ -19,4 +23,10 @@ public interface CouponApi {
|
|||||||
*/
|
*/
|
||||||
@GetMapping("/getAvailable")
|
@GetMapping("/getAvailable")
|
||||||
List<AvailableCouponsResDTO> getAvailableCoupon(@RequestParam BigDecimal totalAmount);
|
List<AvailableCouponsResDTO> getAvailableCoupon(@RequestParam BigDecimal totalAmount);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户核销优惠卷返回优惠金额
|
||||||
|
*/
|
||||||
|
@PostMapping("/use")
|
||||||
|
CouponUseResDTO useCoupon(@RequestBody CouponUseReqDTO couponUseReqDTO);
|
||||||
}
|
}
|
||||||
@ -2,11 +2,13 @@ package com.jzo2o.api.market.dto.request;
|
|||||||
|
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@Builder
|
||||||
@ApiModel("优惠券使用模型")
|
@ApiModel("优惠券使用模型")
|
||||||
public class CouponUseReqDTO {
|
public class CouponUseReqDTO {
|
||||||
@ApiModelProperty("优惠券id")
|
@ApiModelProperty("优惠券id")
|
||||||
@ -15,4 +17,4 @@ public class CouponUseReqDTO {
|
|||||||
private Long ordersId;
|
private Long ordersId;
|
||||||
@ApiModelProperty("总金额")
|
@ApiModelProperty("总金额")
|
||||||
private BigDecimal totalAmount;
|
private BigDecimal totalAmount;
|
||||||
}
|
}
|
||||||
@ -2,13 +2,17 @@ package com.jzo2o.api.market.dto.response;
|
|||||||
|
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@ApiModel("优惠券使用返回信息模型")
|
@ApiModel("优惠券使用返回信息模型")
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
public class CouponUseResDTO {
|
public class CouponUseResDTO {
|
||||||
@ApiModelProperty("优惠金额")
|
@ApiModelProperty("优惠金额")
|
||||||
private BigDecimal discountAmount;
|
private BigDecimal discountAmount;
|
||||||
}
|
}
|
||||||
@ -1,15 +1,15 @@
|
|||||||
package com.jzo2o.market.controller.inner;
|
package com.jzo2o.market.controller.inner;
|
||||||
|
|
||||||
import com.jzo2o.api.market.CouponApi;
|
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.AvailableCouponsResDTO;
|
||||||
|
import com.jzo2o.api.market.dto.response.CouponUseResDTO;
|
||||||
import com.jzo2o.market.service.ICouponService;
|
import com.jzo2o.market.service.ICouponService;
|
||||||
|
import com.jzo2o.market.service.ICouponWriteOffService;
|
||||||
import io.swagger.annotations.ApiImplicitParam;
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@ -25,6 +25,8 @@ import java.util.List;
|
|||||||
public class CouponController implements CouponApi {
|
public class CouponController implements CouponApi {
|
||||||
@Resource
|
@Resource
|
||||||
private ICouponService couponService;
|
private ICouponService couponService;
|
||||||
|
@Resource
|
||||||
|
private ICouponWriteOffService couponWriteOffService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据订单金额获取当前用户可用优惠卷
|
* 根据订单金额获取当前用户可用优惠卷
|
||||||
@ -36,4 +38,11 @@ public class CouponController implements CouponApi {
|
|||||||
public List<AvailableCouponsResDTO> getAvailableCoupon(@RequestParam BigDecimal totalAmount) {
|
public List<AvailableCouponsResDTO> getAvailableCoupon(@RequestParam BigDecimal totalAmount) {
|
||||||
return couponService.getAvailableCoupon(totalAmount);
|
return couponService.getAvailableCoupon(totalAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@PostMapping("/use")
|
||||||
|
@ApiOperation("使用优惠卷并返回优惠金额")
|
||||||
|
public CouponUseResDTO useCoupon(@RequestBody CouponUseReqDTO couponUseReqDTO) {
|
||||||
|
return couponWriteOffService.use(couponUseReqDTO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,18 +1,17 @@
|
|||||||
package com.jzo2o.market.model.domain;
|
package com.jzo2o.market.model.domain;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* 优惠券核销表
|
* 优惠券核销表
|
||||||
* </p>
|
* </p>
|
||||||
*
|
|
||||||
* @author itcast
|
* @author itcast
|
||||||
* @since 2023-09-22
|
* @since 2023-09-22
|
||||||
*/
|
*/
|
||||||
@ -26,7 +25,7 @@ public class CouponWriteOff implements Serializable {
|
|||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@TableId(value = "id", type = IdType.NONE)
|
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,6 +62,4 @@ public class CouponWriteOff implements Serializable {
|
|||||||
* 核销人姓名
|
* 核销人姓名
|
||||||
*/
|
*/
|
||||||
private String writeOffManName;
|
private String writeOffManName;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
|
||||||
@ -44,4 +44,11 @@ public interface ICouponService extends IService<Coupon> {
|
|||||||
* 根据订单金额获取当前用户可用优惠卷
|
* 根据订单金额获取当前用户可用优惠卷
|
||||||
*/
|
*/
|
||||||
List<AvailableCouponsResDTO> getAvailableCoupon(BigDecimal totalAmount);
|
List<AvailableCouponsResDTO> getAvailableCoupon(BigDecimal totalAmount);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算优惠卷的优惠价格
|
||||||
|
* @param coupon 优惠卷信息
|
||||||
|
* @param totalAmount 订单总金额
|
||||||
|
*/
|
||||||
|
BigDecimal calcDiscountAmount(Coupon coupon, BigDecimal totalAmount);
|
||||||
}
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
package com.jzo2o.market.service;
|
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.jzo2o.market.model.domain.CouponWriteOff;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
@ -7,11 +9,12 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
|||||||
* <p>
|
* <p>
|
||||||
* 优惠券核销表 服务类
|
* 优惠券核销表 服务类
|
||||||
* </p>
|
* </p>
|
||||||
*
|
|
||||||
* @author itcast
|
* @author itcast
|
||||||
* @since 2023-09-22
|
* @since 2023-09-22
|
||||||
*/
|
*/
|
||||||
public interface ICouponWriteOffService extends IService<CouponWriteOff> {
|
public interface ICouponWriteOffService extends IService<CouponWriteOff> {
|
||||||
|
/**
|
||||||
|
* 核销指定的优惠卷并返回优惠金额
|
||||||
}
|
*/
|
||||||
|
CouponUseResDTO use(CouponUseReqDTO couponUseReqDTO);
|
||||||
|
}
|
||||||
@ -179,7 +179,8 @@ public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> impleme
|
|||||||
* @param coupon 优惠卷信息
|
* @param coupon 优惠卷信息
|
||||||
* @param totalAmount 订单总金额
|
* @param totalAmount 订单总金额
|
||||||
*/
|
*/
|
||||||
private BigDecimal calcDiscountAmount(Coupon coupon, BigDecimal totalAmount) {
|
@Override
|
||||||
|
public BigDecimal calcDiscountAmount(Coupon coupon, BigDecimal totalAmount) {
|
||||||
CouponTypeEnum type = coupon.getType();
|
CouponTypeEnum type = coupon.getType();
|
||||||
BigDecimal discountAmount = BigDecimal.ZERO;
|
BigDecimal discountAmount = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
|||||||
@ -1,20 +1,77 @@
|
|||||||
package com.jzo2o.market.service.impl;
|
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.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.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* 优惠券核销表 服务实现类
|
* 优惠券核销表 服务实现类
|
||||||
* </p>
|
* </p>
|
||||||
*
|
|
||||||
* @author itcast
|
* @author itcast
|
||||||
* @since 2023-09-22
|
* @since 2023-09-22
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class CouponWriteOffServiceImpl extends ServiceImpl<CouponWriteOffMapper, CouponWriteOff> implements ICouponWriteOffService {
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,7 +3,9 @@ package com.jzo2o.orders.manager.service.client;
|
|||||||
import com.alibaba.csp.sentinel.annotation.SentinelResource;
|
import com.alibaba.csp.sentinel.annotation.SentinelResource;
|
||||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||||
import com.jzo2o.api.market.CouponApi;
|
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.AvailableCouponsResDTO;
|
||||||
|
import com.jzo2o.api.market.dto.response.CouponUseResDTO;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ -37,4 +39,20 @@ public class MarketClient {
|
|||||||
log.warn("优惠卷接口异常(触发熔断降级), 总金额: {}", totalAmount, blockException);
|
log.warn("优惠卷接口异常(触发熔断降级), 总金额: {}", totalAmount, blockException);
|
||||||
return null;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -3,7 +3,9 @@ package com.jzo2o.orders.manager.service.impl;
|
|||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.jzo2o.api.customer.dto.response.AddressBookResDTO;
|
import com.jzo2o.api.customer.dto.response.AddressBookResDTO;
|
||||||
import com.jzo2o.api.foundations.dto.response.ServeAggregationResDTO;
|
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.AvailableCouponsResDTO;
|
||||||
|
import com.jzo2o.api.market.dto.response.CouponUseResDTO;
|
||||||
import com.jzo2o.api.trade.NativePayApi;
|
import com.jzo2o.api.trade.NativePayApi;
|
||||||
import com.jzo2o.api.trade.TradingApi;
|
import com.jzo2o.api.trade.TradingApi;
|
||||||
import com.jzo2o.api.trade.dto.request.NativePayReqDTO;
|
import com.jzo2o.api.trade.dto.request.NativePayReqDTO;
|
||||||
@ -98,10 +100,22 @@ public class OrdersCreateServiceImpl extends ServiceImpl<OrdersMapper, Orders> i
|
|||||||
}
|
}
|
||||||
// 获取订单id
|
// 获取订单id
|
||||||
Long orderId = generateOrderId();
|
Long orderId = generateOrderId();
|
||||||
// TODO 获取优惠卷相关信息
|
// 计算总金额
|
||||||
BigDecimal discountAmount = BigDecimal.ZERO;
|
|
||||||
// 计算价格
|
|
||||||
BigDecimal totalAmount = serve.getPrice().multiply(BigDecimal.valueOf(placeOrderReqDTO.getPurNum()));
|
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);
|
BigDecimal realPayAmount = totalAmount.subtract(discountAmount);
|
||||||
|
|
||||||
// 组装订单信息插入数据库完成下单
|
// 组装订单信息插入数据库完成下单
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user