|
|
@ -1,14 +1,42 @@ |
|
|
|
package cn.nla.order.service.impl; |
|
|
|
|
|
|
|
import cn.nla.common.constant.CacheKey; |
|
|
|
import cn.nla.common.enums.BizCodeEnum; |
|
|
|
import cn.nla.common.enums.CouponStateEnum; |
|
|
|
import cn.nla.common.exception.BizException; |
|
|
|
import cn.nla.common.interceptor.LoginInterceptor; |
|
|
|
import cn.nla.common.model.LoginUser; |
|
|
|
import cn.nla.common.util.CommonUtil; |
|
|
|
import cn.nla.common.util.JsonData; |
|
|
|
import cn.nla.order.feign.CouponFeignService; |
|
|
|
import cn.nla.order.feign.ProductFeignService; |
|
|
|
import cn.nla.order.feign.UserFeignService; |
|
|
|
import cn.nla.order.model.VO.CouponRecordVO; |
|
|
|
import cn.nla.order.model.VO.OrderItemVO; |
|
|
|
import cn.nla.order.model.VO.ProductOrderAddressVO; |
|
|
|
import cn.nla.order.model.entity.ProductOrderEntity; |
|
|
|
import cn.nla.order.mapper.ProductOrderMapper; |
|
|
|
import cn.nla.order.model.request.ConfirmOrderRequest; |
|
|
|
import cn.nla.order.model.request.LockCouponRecordRequest; |
|
|
|
import cn.nla.order.model.request.LockProductRequest; |
|
|
|
import cn.nla.order.model.request.OrderItemRequest; |
|
|
|
import cn.nla.order.service.ProductOrderService; |
|
|
|
import com.alibaba.fastjson.TypeReference; |
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
import org.apache.commons.lang3.StringUtils; |
|
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
|
import org.springframework.data.redis.core.StringRedisTemplate; |
|
|
|
import org.springframework.data.redis.core.script.DefaultRedisScript; |
|
|
|
import org.springframework.stereotype.Service; |
|
|
|
|
|
|
|
import javax.annotation.Resource; |
|
|
|
import java.math.BigDecimal; |
|
|
|
import java.util.ArrayList; |
|
|
|
import java.util.List; |
|
|
|
import java.util.stream.Collectors; |
|
|
|
|
|
|
|
/** |
|
|
|
* <p> |
|
|
|
* 订单表 服务实现类 |
|
|
@ -17,14 +45,117 @@ import org.springframework.stereotype.Service; |
|
|
|
* @author YJs |
|
|
|
* @since 2024-08-13 |
|
|
|
*/ |
|
|
|
@Slf4j |
|
|
|
@Service |
|
|
|
public class ProductOrderServiceImpl extends ServiceImpl<ProductOrderMapper, ProductOrderEntity> implements ProductOrderService { |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private StringRedisTemplate redisTemplate; |
|
|
|
|
|
|
|
@Resource |
|
|
|
private UserFeignService userFeignService; |
|
|
|
|
|
|
|
@Resource |
|
|
|
private CouponFeignService couponFeignService; |
|
|
|
|
|
|
|
@Resource |
|
|
|
private ProductFeignService productFeignService; |
|
|
|
|
|
|
|
@Override |
|
|
|
public JsonData confirmOrder(ConfirmOrderRequest request) { |
|
|
|
LoginUser loginUser = LoginInterceptor.threadLocal.get(); |
|
|
|
String orderToken = request.getToken(); |
|
|
|
if (StringUtils.isBlank(orderToken)) { |
|
|
|
throw new BizException(BizCodeEnum.ORDER_CONFIRM_TOKEN_NOT_EXIST); |
|
|
|
} |
|
|
|
//原子操作 校验令牌,删除令牌
|
|
|
|
// String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
|
|
|
|
// Long result = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class),
|
|
|
|
// List.of(String.format(CacheKey.SUBMIT_ORDER_TOKEN_KEY, loginUser.getId())), orderToken);
|
|
|
|
// if (result == 0L) {
|
|
|
|
// throw new BizException(BizCodeEnum.ORDER_CONFIRM_TOKEN_EQUAL_FAIL);
|
|
|
|
// }
|
|
|
|
String orderOutTradeNo = CommonUtil.getStringNumRandom(32); |
|
|
|
//获取收货地址详情
|
|
|
|
ProductOrderAddressVO addressVO = this.getUserAddress(request.getAddressId()); |
|
|
|
log.info("收货地址信息:{}", addressVO); |
|
|
|
|
|
|
|
//获取用户加入购物车的商品
|
|
|
|
List<Long> productIdList = request.getProductIdList(); |
|
|
|
JsonData cartItemDate = productFeignService.confirmOrderCartItem(productIdList); |
|
|
|
List<OrderItemVO> orderItemList = cartItemDate.getData(new TypeReference<>() { |
|
|
|
}); |
|
|
|
log.info("获取的商品:{}", orderItemList); |
|
|
|
if (orderItemList == null) { |
|
|
|
//购物车商品不存在
|
|
|
|
throw new BizException(BizCodeEnum.ORDER_CONFIRM_CART_ITEM_NOT_EXIST); |
|
|
|
} |
|
|
|
|
|
|
|
//验证价格,减去商品优惠券
|
|
|
|
this.checkPrice(orderItemList, request); |
|
|
|
//锁定优惠券
|
|
|
|
this.lockCouponRecords(request, orderOutTradeNo); |
|
|
|
//锁定库存
|
|
|
|
this.lockProductStocks(orderItemList, orderOutTradeNo); |
|
|
|
// //创建订单
|
|
|
|
// ProductOrderDO productOrderDO = this.saveProductOrder(request, loginUser, orderOutTradeNo, addressVO);
|
|
|
|
|
|
|
|
|
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 锁定优惠券 |
|
|
|
*/ |
|
|
|
private void lockCouponRecords(ConfirmOrderRequest orderRequest, String orderOutTradeNo) { |
|
|
|
List<Long> lockCouponRecordIds = new ArrayList<>(); |
|
|
|
if (orderRequest.getCouponRecordId() > 0) { |
|
|
|
lockCouponRecordIds.add(orderRequest.getCouponRecordId()); |
|
|
|
LockCouponRecordRequest lockCouponRecordRequest = new LockCouponRecordRequest(); |
|
|
|
lockCouponRecordRequest.setOrderOutTradeNo(orderOutTradeNo); |
|
|
|
lockCouponRecordRequest.setLockCouponRecordIds(lockCouponRecordIds); |
|
|
|
//发起锁定优惠券请求
|
|
|
|
JsonData jsonData = couponFeignService.lockCouponRecords(lockCouponRecordRequest); |
|
|
|
if (jsonData.getCode() != 0) { |
|
|
|
throw new BizException(BizCodeEnum.COUPON_RECORD_LOCK_FAIL); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 锁定商品库存 |
|
|
|
*/ |
|
|
|
private void lockProductStocks(List<OrderItemVO> orderItemList, String orderOutTradeNo) { |
|
|
|
List<OrderItemRequest> itemRequestList = orderItemList.stream().map(obj -> { |
|
|
|
OrderItemRequest request = new OrderItemRequest(); |
|
|
|
request.setBuyNum(obj.getBuyNum()); |
|
|
|
request.setProductId(obj.getProductId()); |
|
|
|
return request; |
|
|
|
}).collect(Collectors.toList()); |
|
|
|
LockProductRequest lockProductRequest = new LockProductRequest(); |
|
|
|
lockProductRequest.setOrderOutTradeNo(orderOutTradeNo); |
|
|
|
lockProductRequest.setOrderItemList(itemRequestList); |
|
|
|
JsonData jsonData = productFeignService.lockProducts(lockProductRequest); |
|
|
|
if (jsonData.getCode() != 0) { |
|
|
|
log.error("锁定商品库存失败:{}", lockProductRequest); |
|
|
|
throw new BizException(BizCodeEnum.ORDER_CONFIRM_LOCK_PRODUCT_FAIL); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 获取收货地址详情(后端通过id调用服务拿到地址) |
|
|
|
*/ |
|
|
|
private ProductOrderAddressVO getUserAddress(long addressId) { |
|
|
|
JsonData addressData = userFeignService.detail(addressId); |
|
|
|
if (addressData.getCode() != 0) { |
|
|
|
log.error("获取收获地址失败,msg:{}", addressData); |
|
|
|
throw new BizException(BizCodeEnum.ADDRESS_NO_EXITS); |
|
|
|
} |
|
|
|
return addressData.getData(new TypeReference<>() { |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
public String queryProductOrderState(String outTradeNo) { |
|
|
|
ProductOrderEntity productOrderDO = baseMapper.selectOne(new QueryWrapper<ProductOrderEntity>() |
|
|
@ -35,4 +166,80 @@ public class ProductOrderServiceImpl extends ServiceImpl<ProductOrderMapper, Pro |
|
|
|
return productOrderDO.getState(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* 验证价格 |
|
|
|
* 1)统计全部商品的价格 |
|
|
|
* 2) 获取优惠券(判断是否满足优惠券的条件),总价再减去优惠券的价格 就是 最终的价格 |
|
|
|
*/ |
|
|
|
private void checkPrice(List<OrderItemVO> orderItemList, ConfirmOrderRequest orderRequest) { |
|
|
|
//统计商品总价格
|
|
|
|
BigDecimal realPayAmount = new BigDecimal("0"); |
|
|
|
if (orderItemList != null) { |
|
|
|
for (OrderItemVO orderItemVO : orderItemList) { |
|
|
|
BigDecimal itemRealPayAmount = orderItemVO.getTotalAmount(); |
|
|
|
realPayAmount = realPayAmount.add(itemRealPayAmount); |
|
|
|
} |
|
|
|
} |
|
|
|
//获取优惠券,判断是否可以使用
|
|
|
|
CouponRecordVO couponRecordVO = getCartCouponRecord(orderRequest.getCouponRecordId()); |
|
|
|
//计算购物车价格,是否满足优惠券满减条件
|
|
|
|
if (couponRecordVO != null) { |
|
|
|
//计算是否满足满减
|
|
|
|
if (realPayAmount.compareTo(couponRecordVO.getConditionPrice()) < 0) { |
|
|
|
throw new BizException(BizCodeEnum.ORDER_CONFIRM_COUPON_FAIL); |
|
|
|
} |
|
|
|
if (couponRecordVO.getPrice().compareTo(realPayAmount) > 0) { |
|
|
|
realPayAmount = BigDecimal.ZERO; |
|
|
|
} else { |
|
|
|
realPayAmount = realPayAmount.subtract(couponRecordVO.getPrice()); |
|
|
|
} |
|
|
|
} |
|
|
|
if (realPayAmount.compareTo(orderRequest.getRealPayAmount()) != 0) { |
|
|
|
log.error("订单验价失败:{}", orderRequest); |
|
|
|
throw new BizException(BizCodeEnum.ORDER_CONFIRM_PRICE_FAIL); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* 获取优惠券 |
|
|
|
*/ |
|
|
|
private CouponRecordVO getCartCouponRecord(Long couponRecordId) { |
|
|
|
if (couponRecordId == null || couponRecordId < 0) { |
|
|
|
return null; |
|
|
|
} |
|
|
|
JsonData couponData = couponFeignService.findUserCouponRecordById(couponRecordId); |
|
|
|
if (couponData.getCode() != 0) { |
|
|
|
throw new BizException(BizCodeEnum.ORDER_CONFIRM_COUPON_FAIL); |
|
|
|
} |
|
|
|
if (couponData.getCode() == 0) { |
|
|
|
CouponRecordVO couponRecordVO = couponData.getData(new TypeReference<>() { |
|
|
|
}); |
|
|
|
if (!couponAvailable(couponRecordVO)) { |
|
|
|
log.error("优惠券使用失败"); |
|
|
|
throw new BizException(BizCodeEnum.COUPON_UNAVAILABLE); |
|
|
|
} |
|
|
|
return couponRecordVO; |
|
|
|
} |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* 判断优惠券是否可用 |
|
|
|
*/ |
|
|
|
private boolean couponAvailable(CouponRecordVO couponRecordVO) { |
|
|
|
if (couponRecordVO.getUseState().equalsIgnoreCase(CouponStateEnum.NEW.name())) { |
|
|
|
long currentTimestamp = CommonUtil.getCurrentTimestamp(); |
|
|
|
long end = couponRecordVO.getEndTime().getTime(); |
|
|
|
long start = couponRecordVO.getStartTime().getTime(); |
|
|
|
if (currentTimestamp >= start && currentTimestamp <= end) { |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|