|  | @@ -10,8 +10,10 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  package com.yami.shop.api.listener;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +import cn.hutool.core.bean.BeanUtil;
 | 
	
		
			
				|  |  |  import cn.hutool.core.lang.Snowflake;
 | 
	
		
			
				|  |  |  import cn.hutool.core.util.StrUtil;
 | 
	
		
			
				|  |  | +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 | 
	
		
			
				|  |  |  import com.yami.shop.bean.app.dto.ShopCartItemDiscountDto;
 | 
	
		
			
				|  |  |  import com.yami.shop.bean.app.dto.ShopCartItemDto;
 | 
	
		
			
				|  |  |  import com.yami.shop.bean.app.dto.ShopCartOrderDto;
 | 
	
	
		
			
				|  | @@ -22,7 +24,6 @@ import com.yami.shop.bean.event.SubmitOrderEvent;
 | 
	
		
			
				|  |  |  import com.yami.shop.bean.model.*;
 | 
	
		
			
				|  |  |  import com.yami.shop.bean.order.SubmitOrderOrder;
 | 
	
		
			
				|  |  |  import com.yami.shop.common.exception.GlobalException;
 | 
	
		
			
				|  |  | -import com.yami.shop.common.exception.YamiShopBindException;
 | 
	
		
			
				|  |  |  import com.yami.shop.common.util.Arith;
 | 
	
		
			
				|  |  |  import com.yami.shop.dao.*;
 | 
	
		
			
				|  |  |  import com.yami.shop.security.api.util.SecurityUtils;
 | 
	
	
		
			
				|  | @@ -36,7 +37,10 @@ import org.springframework.context.event.EventListener;
 | 
	
		
			
				|  |  |  import org.springframework.core.annotation.Order;
 | 
	
		
			
				|  |  |  import org.springframework.stereotype.Component;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +import java.math.BigDecimal;
 | 
	
		
			
				|  |  | +import java.time.LocalDateTime;
 | 
	
		
			
				|  |  |  import java.util.*;
 | 
	
		
			
				|  |  | +import java.util.stream.Collectors;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /**
 | 
	
		
			
				|  |  |   * 确认订单信息时的默认操作
 | 
	
	
		
			
				|  | @@ -58,6 +62,7 @@ public class SubmitOrderListener {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      private final Snowflake snowflake;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    private final PointsRecordMapper pointsRecordMapper;
 | 
	
		
			
				|  |  |      private final OrderItemMapper orderItemMapper;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      private final SkuMapper skuMapper;
 | 
	
	
		
			
				|  | @@ -98,20 +103,57 @@ public class SubmitOrderListener {
 | 
	
		
			
				|  |  |          userAddrOrder.setUserId(userId);
 | 
	
		
			
				|  |  |          userAddrOrder.setCreateTime(now);
 | 
	
		
			
				|  |  |          userAddrOrderService.save(userAddrOrder);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +        //所有当前用户可用的积分记录
 | 
	
		
			
				|  |  | +        List<PointsRecord> pointsRecords = pointsRecordMapper.selectList(new LambdaQueryWrapper<PointsRecord>()
 | 
	
		
			
				|  |  | +                        .eq(PointsRecord::getUserId, userId)
 | 
	
		
			
				|  |  | +                        .eq(PointsRecord::getChannelId, mergerOrder.getPlatform())
 | 
	
		
			
				|  |  | +                        .in(PointsRecord::getPointsType, Arrays.asList(1, 3))
 | 
	
		
			
				|  |  | +                        .in(PointsRecord::getPointsAudit, Arrays.asList(1, 2)).and(wrapper -> wrapper
 | 
	
		
			
				|  |  | +                                .gt(PointsRecord::getExpiryDate, LocalDateTime.now())
 | 
	
		
			
				|  |  | +                                .or()
 | 
	
		
			
				|  |  | +                                .isNull(PointsRecord::getExpiryDate)
 | 
	
		
			
				|  |  | +                        )).stream()
 | 
	
		
			
				|  |  | +                .sorted(Comparator
 | 
	
		
			
				|  |  | +                        .comparing(PointsRecord::getExpiryDate,
 | 
	
		
			
				|  |  | +                                Comparator.nullsLast(Comparator.naturalOrder()))
 | 
	
		
			
				|  |  | +                        .thenComparing(PointsRecord::getId))
 | 
	
		
			
				|  |  | +                .collect(Collectors.toList());
 | 
	
		
			
				|  |  | +        ;
 | 
	
		
			
				|  |  | +        // 将记录添加到队列中
 | 
	
		
			
				|  |  | +        ArrayDeque<PointsRecord> expiryQueue = new ArrayDeque<>(pointsRecords);
 | 
	
		
			
				|  |  |          // 订单地址id
 | 
	
		
			
				|  |  |          Long addrOrderId = userAddrOrder.getAddrOrderId();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          if (CollectionUtils.isNotEmpty(shopCartOrders)) {
 | 
	
		
			
				|  |  |              // 每个店铺生成一个订单
 | 
	
		
			
				|  |  |              for (ShopCartOrderDto shopCartOrderDto : shopCartOrders) {
 | 
	
		
			
				|  |  | -                Double sumPlatformAmount = 0.0;
 | 
	
		
			
				|  |  | +                //兑换人民币是分,必须要实时统计计算
 | 
	
		
			
				|  |  | +                Integer point = pointsRecordMapper.statisticsPoint(userId, mergerOrder.getPlatform());
 | 
	
		
			
				|  |  |                  // 使用雪花算法生成的订单号
 | 
	
		
			
				|  |  |                  String orderNumber = String.valueOf(snowflake.nextId());
 | 
	
		
			
				|  |  |                  shopCartOrderDto.setOrderNumber(orderNumber);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  Long shopId = shopCartOrderDto.getShopId();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +                // 订单信息
 | 
	
		
			
				|  |  | +                com.yami.shop.bean.model.Order order = new com.yami.shop.bean.model.Order();
 | 
	
		
			
				|  |  | +                Double actualTotal = shopCartOrderDto.getActualTotal();
 | 
	
		
			
				|  |  | +                //企业用户才进这个判断,并且该用户的积分必须大于0
 | 
	
		
			
				|  |  | +                if (1 == mergerOrder.getPlatform() && null != point && point > 0) {
 | 
	
		
			
				|  |  | +                    // 计算商品金额和积分
 | 
	
		
			
				|  |  | +                    Double mul = Arith.mul(actualTotal, 100);
 | 
	
		
			
				|  |  | +                    Double vp = Double.valueOf(point);
 | 
	
		
			
				|  |  | +                    if (vp >= mul) {
 | 
	
		
			
				|  |  | +                        //积分完全足够支付
 | 
	
		
			
				|  |  | +                        actualTotal = 0.0;//剩下需要付的钱
 | 
	
		
			
				|  |  | +                        order.setOffsetPoints(Long.valueOf(String.valueOf(mul)));
 | 
	
		
			
				|  |  | +                    } else {
 | 
	
		
			
				|  |  | +                        //积分不够抵扣
 | 
	
		
			
				|  |  | +                        double sub = Arith.sub(mul, vp);
 | 
	
		
			
				|  |  | +                        //剩下需要付的钱
 | 
	
		
			
				|  |  | +                        actualTotal = sub / 100;
 | 
	
		
			
				|  |  | +                        order.setOffsetPoints(Long.valueOf(String.valueOf(sub)));
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  |                  // 订单商品名称
 | 
	
		
			
				|  |  |                  StringBuilder orderProdName = new StringBuilder(100);
 | 
	
		
			
				|  |  |                  List<OrderItem> orderItems = new ArrayList<>();
 | 
	
	
		
			
				|  | @@ -138,9 +180,19 @@ public class SubmitOrderListener {
 | 
	
		
			
				|  |  |                          orderItem.setBasketDate(shopCartItem.getBasketDate());
 | 
	
		
			
				|  |  |                          //平台的补贴优惠金额
 | 
	
		
			
				|  |  |                          orderItem.setPlatformShareReduce(shopCartItem.getPlatformShareReduce());
 | 
	
		
			
				|  |  | +                        Double actualItem = shopCartItem.getActualTotal();
 | 
	
		
			
				|  |  | +                        //后台充值的积分
 | 
	
		
			
				|  |  | +                        if (1 == mergerOrder.getPlatform() && null != point && point > 0) {
 | 
	
		
			
				|  |  | +                            //把钱换算成积分
 | 
	
		
			
				|  |  | +                            actualItem = this.doGetOrderItemPoints(Arith.mul(actualItem, 100), expiryQueue, orderNumber);
 | 
	
		
			
				|  |  | +                            //把积分换算成钱
 | 
	
		
			
				|  |  | +                            if (actualItem > 0) {
 | 
	
		
			
				|  |  | +                                actualItem = Arith.div(actualItem, 100);
 | 
	
		
			
				|  |  | +                            }
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  |                          // 实际订单项支付金额
 | 
	
		
			
				|  |  | -                        //TODO wangjian 根据platform来计算是否优先扣减积分抵扣
 | 
	
		
			
				|  |  | -                        orderItem.setActualTotal(shopCartItem.getActualTotal());
 | 
	
		
			
				|  |  | +                        // 根据platform来计算是否优先扣减积分抵扣
 | 
	
		
			
				|  |  | +                        orderItem.setActualTotal(actualItem);
 | 
	
		
			
				|  |  |                          // 分摊优惠金额
 | 
	
		
			
				|  |  |                          orderItem.setShareReduce(shopCartItem.getShareReduce());
 | 
	
		
			
				|  |  |                          orderProdName.append(orderItem.getProdName()).append(",");
 | 
	
	
		
			
				|  | @@ -162,8 +214,6 @@ public class SubmitOrderListener {
 | 
	
		
			
				|  |  |                      orderProdName.deleteCharAt(orderProdName.length() - 1);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                // 订单信息
 | 
	
		
			
				|  |  | -                com.yami.shop.bean.model.Order order = new com.yami.shop.bean.model.Order();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  order.setShopId(shopId);
 | 
	
		
			
				|  |  |                  order.setOrderNumber(orderNumber);
 | 
	
	
		
			
				|  | @@ -174,8 +224,7 @@ public class SubmitOrderListener {
 | 
	
		
			
				|  |  |                  // 商品总额
 | 
	
		
			
				|  |  |                  order.setTotal(shopCartOrderDto.getTotal());
 | 
	
		
			
				|  |  |                  // 实际总额
 | 
	
		
			
				|  |  | -                //TODO wangjian 根据platform来计算是否优先扣减积分抵扣
 | 
	
		
			
				|  |  | -                order.setActualTotal(shopCartOrderDto.getActualTotal());
 | 
	
		
			
				|  |  | +                order.setActualTotal(actualTotal);
 | 
	
		
			
				|  |  |                  order.setStatus(OrderStatus.UNPAY.value());
 | 
	
		
			
				|  |  |                  order.setChannelId(Long.valueOf(mergerOrder.getPlatform()));
 | 
	
		
			
				|  |  |                  order.setUpdateTime(now);
 | 
	
	
		
			
				|  | @@ -217,7 +266,7 @@ public class SubmitOrderListener {
 | 
	
		
			
				|  |  |              basketMapper.deleteShopCartItemsByBasketIds(userId, basketIds);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -//TODO wangjia 修改本地库存
 | 
	
		
			
				|  |  | +//        现在不用维护库存
 | 
	
		
			
				|  |  |  //        // 更新sku库存
 | 
	
		
			
				|  |  |  //        skuStocksMap.forEach((key, sku) -> {
 | 
	
		
			
				|  |  |  //
 | 
	
	
		
			
				|  | @@ -228,7 +277,7 @@ public class SubmitOrderListener {
 | 
	
		
			
				|  |  |  //            }
 | 
	
		
			
				|  |  |  //        });
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  | -////         更新商品库存
 | 
	
		
			
				|  |  | +//        //更新商品库存
 | 
	
		
			
				|  |  |  //        prodStocksMap.forEach((prodId, prod) -> {
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  |  //            if (productMapper.updateStocks(prod) == 0) {
 | 
	
	
		
			
				|  | @@ -331,4 +380,36 @@ public class SubmitOrderListener {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    private Double doGetOrderItemPoints(Double actualTotal, ArrayDeque<PointsRecord> expiryQueue, String orderNumber) {
 | 
	
		
			
				|  |  | +        PointsRecord pointsRecord = expiryQueue.poll();
 | 
	
		
			
				|  |  | +        //判定可用金额
 | 
	
		
			
				|  |  | +        BigDecimal points = pointsRecord.getPoints();
 | 
	
		
			
				|  |  | +        BigDecimal variablePoints = pointsRecord.getVariablePoints();
 | 
	
		
			
				|  |  | +        //充值记录中可用的记录
 | 
	
		
			
				|  |  | +        Double available = points.subtract(variablePoints).doubleValue();
 | 
	
		
			
				|  |  | +        actualTotal = Arith.sub(actualTotal, available);
 | 
	
		
			
				|  |  | +        pointsRecord.setVariablePoints(BigDecimal.valueOf(available));
 | 
	
		
			
				|  |  | +        if (available > actualTotal) {
 | 
	
		
			
				|  |  | +            //钱已经抵扣完,但是当条积分还有剩余,所以不要重新把剩余的放入队列
 | 
	
		
			
				|  |  | +            //更改pointsRecord的变动的值,并修改数据库
 | 
	
		
			
				|  |  | +            expiryQueue.addFirst(pointsRecord);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        int update = pointsRecordMapper.updateById(pointsRecord);
 | 
	
		
			
				|  |  | +        if (update > 0) {
 | 
	
		
			
				|  |  | +            PointsRecord pr = new PointsRecord();
 | 
	
		
			
				|  |  | +            BeanUtil.copyProperties(pointsRecord, pr);
 | 
	
		
			
				|  |  | +            pr.setId(null);
 | 
	
		
			
				|  |  | +            pr.setOrderNumber(orderNumber);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        // TODO 插入数据库
 | 
	
		
			
				|  |  | +        if (actualTotal > available) {
 | 
	
		
			
				|  |  | +            //把当前积分已完全够扣,但是还有钱
 | 
	
		
			
				|  |  | +            actualTotal = this.doGetOrderItemPoints(actualTotal, expiryQueue, orderNumber);
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            //恰好积分等于钱
 | 
	
		
			
				|  |  | +//            actualTotal = Arith.sub(actualTotal, available);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        return actualTotal;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  }
 |