From b6a7f6e41467f73f26fc7f209652e19ff26c3752 Mon Sep 17 00:00:00 2001
From: Cui Zhi Feng <cuizf@fengyuntec.com>
Date: 星期二, 03 九月 2024 20:18:32 +0800
Subject: [PATCH] Merge branch 'master' into master-v2

---
 src/main/java/com/mzl/flower/service/payment/OrderService.java |  267 +++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 229 insertions(+), 38 deletions(-)

diff --git a/src/main/java/com/mzl/flower/service/payment/OrderService.java b/src/main/java/com/mzl/flower/service/payment/OrderService.java
index 8841099..9660450 100644
--- a/src/main/java/com/mzl/flower/service/payment/OrderService.java
+++ b/src/main/java/com/mzl/flower/service/payment/OrderService.java
@@ -12,6 +12,7 @@
 import com.mzl.flower.config.security.SecurityUtils;
 import com.mzl.flower.constant.Constants;
 import com.mzl.flower.dto.PriceDTO;
+import com.mzl.flower.dto.request.menber.MemberGrowthRecordDTO;
 import com.mzl.flower.dto.request.payment.*;
 import com.mzl.flower.dto.response.flower.FlowerCartListDTO;
 import com.mzl.flower.dto.response.flower.FlowerCartListWrapDTO;
@@ -21,9 +22,11 @@
 import com.mzl.flower.dto.response.system.CodeValueDTO;
 import com.mzl.flower.dto.response.transport.TransportOrderDTO;
 import com.mzl.flower.dto.response.warehouse.WarehouseLocationDTO;
+import com.mzl.flower.entity.coupon.CouponRecordDO;
 import com.mzl.flower.entity.customer.Address;
 import com.mzl.flower.entity.customer.Customer;
 import com.mzl.flower.entity.flower.FlowerSupplierSaleNum;
+import com.mzl.flower.entity.menber.Member;
 import com.mzl.flower.entity.partner.Partner;
 import com.mzl.flower.entity.payment.*;
 import com.mzl.flower.entity.supplier.Station;
@@ -38,6 +41,9 @@
 import com.mzl.flower.mapper.warehouse.WarehouseLocationMapper;
 import com.mzl.flower.service.BaseService;
 import com.mzl.flower.service.flower.FlowerService;
+import com.mzl.flower.service.menber.MemberGrowthRecordService;
+import com.mzl.flower.service.point.CustomerPointService;
+import com.mzl.flower.service.point.PointGoodsService;
 import com.mzl.flower.service.system.CodeService;
 import com.mzl.flower.service.system.WeChatService;
 import com.mzl.flower.service.transport.TransportService;
@@ -48,6 +54,7 @@
 import me.chanjar.weixin.common.error.WxErrorException;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -131,47 +138,84 @@
     @Autowired
     private OrderItemCheckMapper orderItemCheckMapper;
 
+    @Autowired
+    private OrderPointGoodsMapper pointGoodsMapper;
+
+    @Autowired
+    @Lazy
+    private MemberGrowthRecordService memberGrowthRecordService;
+
+    @Autowired
+    private CustomerPointService customerPointService;
+
+    @Autowired
+    private PointGoodsService pointGoodsService;
+
+    @Autowired
+    private RedisLockService lockService;
+
     public void changeFlower2Cart(CartSaveDTO dto) {
         String userId = SecurityUtils.getUserId();
-        Cart c = cartMapper.selectOne(new QueryWrapper<Cart>()
-                .eq("create_by", userId).eq("flower_id", dto.getId()));
-        if (c == null) {
-            if (dto.getNum() <= 0) {
-                throw new ValidationException("数量不能小于等于0,请刷新页面重试");
-            }
-            c = new Cart();
-            c.setFlowerId(dto.getId());
-            c.setNum(dto.getNum());
-            c.create(userId);
+        String key = userId + "_" + dto.getId();
+        boolean lock = lockService.getObjectLock(RedisLockService.LOCK_KEY_CART_, key);
+        if(!lock){
+            return;
+        }
 
-            cartMapper.insert(c);
-        } else {
-            c.setNum(c.getNum() + dto.getNum());
-            c.update(userId);
-            if (c.getNum() <= 0) {
-                cartMapper.deleteById(c.getId());
+        try {
+            Cart c = cartMapper.selectOne(new QueryWrapper<Cart>()
+                    .eq("create_by", userId).eq("flower_id", dto.getId()));
+            if (c == null) {
+                if (dto.getNum() <= 0) {
+                    throw new ValidationException("数量不能小于等于0,请刷新页面重试");
+                }
+                c = new Cart();
+                c.setFlowerId(dto.getId());
+                c.setNum(dto.getNum());
+                c.create(userId);
+
+                cartMapper.insert(c);
             } else {
-                cartMapper.updateById(c);
+                c.setNum(c.getNum() + dto.getNum());
+                c.update(userId);
+                if (c.getNum() <= 0) {
+                    cartMapper.deleteById(c.getId());
+                } else {
+                    cartMapper.updateById(c);
+                }
             }
+        } finally {
+            lockService.releaseObjectLock(RedisLockService.LOCK_KEY_CART_, key);
         }
     }
 
     public void saveFlower2Cart(CartSaveDTO dto) {
         String userId = SecurityUtils.getUserId();
-        Cart c = cartMapper.selectOne(new QueryWrapper<Cart>()
-                .eq("create_by", userId).eq("flower_id", dto.getId()));
-        if (c == null) {
-            c = new Cart();
-            c.setFlowerId(dto.getId());
-            c.setNum(dto.getNum());
-            c.create(userId);
 
-            cartMapper.insert(c);
-        } else {
-            c.setNum(dto.getNum());
-            c.update(userId);
+        String key = userId + "_" + dto.getId();
+        boolean lock = lockService.getObjectLock(RedisLockService.LOCK_KEY_CART_, key);
+        if(!lock){
+            return;
+        }
 
-            cartMapper.updateById(c);
+        try {
+            Cart c = cartMapper.selectOne(new QueryWrapper<Cart>()
+                    .eq("create_by", userId).eq("flower_id", dto.getId()));
+            if (c == null) {
+                c = new Cart();
+                c.setFlowerId(dto.getId());
+                c.setNum(dto.getNum());
+                c.create(userId);
+
+                cartMapper.insert(c);
+            } else {
+                c.setNum(dto.getNum());
+                c.update(userId);
+
+                cartMapper.updateById(c);
+            }
+        } finally {
+            lockService.releaseObjectLock(RedisLockService.LOCK_KEY_CART_, key);
         }
     }
 
@@ -211,13 +255,18 @@
         if (ls != null && ls.size() > 0) {
             Customer customer = getCurrentCustomer();
             Long partnerId = customer.getPartnerId();
+            Long levelId = customer.getLevelId();
+            Member member = getMember(levelId);
 
             Map<Long, FlowerCartListWrapDTO> map = new HashMap<>();
             for (FlowerCartListDTO c : ls) {
                 BigDecimal price = getFinalPrice(partnerId, c.getCategory()
                         , c.getId(), c.getPrice(), c.getLevel());
                 c.setPrice(price);
+                c.setPriceMember(calculateMemberPrice(price, member));
+
                 c.setTotal(price.multiply(new BigDecimal(c.getNum())));
+                c.setTotalMember(c.getPriceMember().multiply(new BigDecimal(c.getNum())));
 
                 if (c.getSales() != null && c.getRealSales() != null) {
                     c.setSales(c.getSales() + c.getRealSales());
@@ -265,10 +314,20 @@
         List<FlowerCartListDTO> ls = flowerMapper.selectFlowerOrderList(ids);
         Customer customer = getCurrentCustomer();
         Long partnerId = customer.getPartnerId();
+        Long levelId = customer.getLevelId();
+        Member member = getMember(levelId);
+        if (member != null) {
+            result.setMemberId(levelId);
+            result.setMemberName(member.getName());
+            result.setMemberDiscountType(member.getDiscountType());
+            result.setMemberDiscountRatio(member.getDiscountRatio());
+            result.setMemberDiscountAmount(member.getDiscountAmount());
+        }
 
         double totalWeight = 0D;
         int num = 0;
         BigDecimal totalAmount = new BigDecimal(0);
+        BigDecimal totalMemberAmount = new BigDecimal(0);
         for (FlowerCartListDTO c : ls) {
             if (!Constants.FLOWER_STATUS.UP.name().equals(c.getStatus())) {
                 throw new ValidationException("商品" + c.getName() + "已下架,请重新提交");
@@ -288,7 +347,10 @@
                     , c.getId(), c.getPrice(), c.getLevel());
             BigDecimal price = priceDTO.getPrice();
             c.setPrice(price);
+            c.setPriceMember(calculateMemberPrice(price, member));
+
             c.setTotal(price.multiply(new BigDecimal(c.getNum())));
+            c.setTotalMember(c.getPriceMember().multiply(new BigDecimal(c.getNum())));//使用会员价计算总价
 
             if (priceMap != null) {
                 priceMap.put(c.getId(), priceDTO);
@@ -296,6 +358,7 @@
 
             totalWeight += c.getWeight() * c.getNum();
             totalAmount = totalAmount.add(c.getTotal());
+            totalMemberAmount = totalMemberAmount.add(c.getTotalMember());
             num += c.getNum();
         }
 
@@ -306,6 +369,7 @@
         result.setFlowers(ls);
         result.setPacking(packing);
         result.setTotalAmount(totalAmount);
+        result.setTotalMemberAmount(totalMemberAmount);
         result.setTotalWeight(totalWeight);
 
         return result;
@@ -339,7 +403,8 @@
         }
 
         Address address = addressMapper.selectById(dto.getAddressId());
-        List<TransportOrderDTO> tLs = transportService.getPreOrderTransportList(address, p.getTotalWeight(), dto.getTransportId());
+        List<TransportOrderDTO> tLs = transportService.getPreOrderTransportList(address
+                , p.getTotalWeight(), dto.getTransportId());
         BigDecimal transportFee = new BigDecimal(0);
         String deliveryName = "";
         if (tLs != null && tLs.size() > 0) {
@@ -351,18 +416,38 @@
         String userId = SecurityUtils.getUserId();
         Order order = new Order();
         order.setId(UUIDGenerator.getUUID());
+
+        final List<Long> goodsRecordIdList = dto.getGoodsRecordIdList();
+        usePointGoods(order.getId(), goodsRecordIdList);//使用积分商品兑换券
+
         order.create(userId);
         order.setRemarks(dto.getRemarks());
         order.setSpecialNeeds(dto.getSpecialNeeds());
         order.setStatusBackend(Constants.ORDER_STATUS_BACKEND.PENDING.name());
         order.setStatus(Constants.ORDER_STATUS.PENDING.name());
 
-        order.setFlowerAmount(p.getTotalAmount());
+        //设置下单时的会员信息
+        order.setMemberId(p.getMemberId());
+        order.setMemberName(p.getMemberName());
+        order.setMemberDiscountType(p.getMemberDiscountType());
+        order.setMemberDiscountRatio(p.getMemberDiscountRatio());
+        order.setMemberCouponAmount(p.getMemberDiscountAmount());
+
+        order.setFlowerAmount(p.getTotalMemberAmount());//使用会员价总价
         order.setPackingFee(p.getPacking());
         order.setTransportFee(transportFee);
         order.setDeliveryName(deliveryName);
 
-        BigDecimal totalAmount = order.getFlowerAmount().add(p.getPacking()).add(transportFee);
+        BigDecimal totalAmount = order.getFlowerAmount().add(p.getPacking()).add(transportFee);//使用优惠券之前的总价
+        CouponRecordDO coupon = useCouponRecord(order.getId(), totalAmount, dto.getCouponRecordId());
+        if(coupon != null){
+            order.setMemberCouponId(coupon.getId());
+            order.setMemberCouponCode(coupon.getCouponCode());
+            order.setMemberCouponName(coupon.getCouponName());
+            order.setMemberCouponAmount(coupon.getCouponDiscountValue());
+
+            totalAmount = totalAmount.subtract(order.getMemberCouponAmount());//满足条件需要减去优惠券金额
+        }
         order.setTotalAmount(totalAmount);
 
         order.setCustomer(address.getName());
@@ -383,6 +468,8 @@
         //商品列表处理
         List<FlowerCartListDTO> flowers = p.getFlowers();
         Map<Long, List<ParamItemDTO>> paramMap = new HashMap<>();
+        final BigDecimal flowerAmount = order.getFlowerAmount();//订单商品总价
+        final BigDecimal memberCouponAmount = order.getMemberCouponAmount();//使用优惠券面值
         for (FlowerCartListDTO f : flowers) {
             OrderItem t = new OrderItem();
             t.setId(UUIDGenerator.getUUID());
@@ -408,8 +495,13 @@
             t.setMarkupOne(pp.getFirstFee());
             t.setMarkupTwo(pp.getSecondFee());
             t.setMarkupPartner(pp.getPartnerFee());
-            t.setPrice(pp.getPrice());
-            t.setTotal(f.getTotal());
+            t.setPrice(f.getPriceMember());//使用会员单价
+            t.setTotal(f.getTotalMember());//使用会员总价
+
+            t.setOriginalPrice(pp.getPrice());//非会员售价
+            BigDecimal couponAmount = calculateCoupon(memberCouponAmount, t.getTotal(), flowerAmount, t.getNum());
+            t.setCouponAmount(couponAmount);//每扎平摊的优惠券面值
+            t.setRealPrice(t.getPrice().subtract(couponAmount));//退款时使用的真实成交价
 
             t.create(userId);
             orderItemMapper.insert(t);
@@ -421,9 +513,57 @@
         order.setPayOpenid(openId);
         orderMapper.insert(order);
 
+        //处理积分商品兑换券
+        if(goodsRecordIdList != null && goodsRecordIdList.size() > 0){
+            for(Long goodsRecordId : goodsRecordIdList){
+                OrderPointGoods g = new OrderPointGoods();
+                g.setId(UUIDGenerator.getUUID());
+                g.setOrderId(order.getId());
+                g.setGoodsRecordId(goodsRecordId);
+                g.create(userId);
+                pointGoodsMapper.insert(g);
+            }
+        }
+
         Map map = paymentV3Service.wxPrepay(order);
         map.put("_testV2OrderId", order.getId());
         return map;
+    }
+
+    private void usePointGoods(String orderId, List<Long> goodsRecordIdList){
+        //使用积分商品兑换券
+        if(goodsRecordIdList != null && goodsRecordIdList.size() > 0){
+            for(Long grId : goodsRecordIdList){
+                pointGoodsService.useExchangeGoods(grId, orderId);
+            }
+        }
+    }
+
+    /**
+     * 计算订单中每种商品每扎平摊的优惠券面值,保留2位小数
+     *
+     * @param couponAmount
+     * @param itemTotalAmount
+     * @param totalAmount
+     * @param num
+     * @return
+     */
+    private BigDecimal calculateCoupon(BigDecimal couponAmount, BigDecimal itemTotalAmount
+            , BigDecimal totalAmount, Integer num){
+        if(couponAmount == null){
+            return new BigDecimal(0);
+        }
+        BigDecimal radio = itemTotalAmount.divide(totalAmount, 2, RoundingMode.HALF_UP);//计算该商品总价在订单中的占比
+        BigDecimal subCoupon = couponAmount.multiply(radio);//占有的优惠券面值
+        return subCoupon.divide(BigDecimal.valueOf(num), 2, RoundingMode.HALF_UP);
+    }
+
+    private CouponRecordDO useCouponRecord(String orderId, BigDecimal amount, String couponRecordId){
+        if(StringUtils.isNotEmpty(couponRecordId)){
+            //TODO 优惠券使用和验证,如果不符合使用条件需要抛出异常。需调用优惠券使用方法
+        }
+
+        return null;
     }
 
     private String getOrderNo() {
@@ -767,6 +907,9 @@
         boolean couldCheckRefund = StringUtils.isEmpty(transferId) && count == 0 && cc == 0;
         dto.setCouldCheckRefund(couldCheckRefund);
 
+        List<OrderPointGoodsListDTO> pointGoodsList = orderMapper.getPointGoodsList(id);
+        dto.setPointGoodsList(pointGoodsList);
+
         return dto;
     }
 
@@ -805,12 +948,12 @@
         return result;
     }
 
-    public void autoReceive() {
+    public List<Order> autoReceive() {
         int days = -5; //5天前的订单自动收货
         LocalDateTime endTime = LocalDateTime.now().plusDays(days);
         List<Order> ls = orderMapper.getOrderForAutoReceive(endTime);
         if (ls == null || ls.size() == 0) {
-            return;
+            return ls;
         }
 
         for (Order o : ls) {
@@ -819,8 +962,44 @@
             o.setReceiveTime(LocalDateTime.now());
             o.update("sys");
             orderMapper.updateById(o);
-
         }
+
+        return ls;
+    }
+
+    public void processAfterReceive(Order o){
+        String status = o.getStatus();
+        if(!Constants.ORDER_STATUS.EVALUATE.name().equals(status)){
+            log.warn("订单未确认收货,无法处理积分和成长值");
+            return;
+        }
+
+        BigDecimal totalAmount = o.getTotalAmount();
+        List<OrderItemCheck> checkList = orderItemCheckMapper.selectList(new QueryWrapper<OrderItemCheck>()
+                .eq("order_id", o.getId())
+                .eq("audit_status", Constants.CHECK_AUDIT_STATUS.AGREED.name())
+        );
+
+        if(checkList != null && checkList.size() > 0){
+            for(OrderItemCheck c : checkList){
+                if(Constants.CHECK_TYPE.replace.name().equals(c.getType())){
+                    continue;
+                }
+                totalAmount = totalAmount.subtract(getAmount(c.getDeductAmount()));
+            }
+        }
+
+        //成长值计算
+        MemberGrowthRecordDTO mDto = new MemberGrowthRecordDTO();
+        mDto.setTotalAmount(totalAmount);
+        mDto.setUserId(o.getCreateBy());
+        mDto.setSource(Constants.GROWTH_SOURCE.consume.name());
+        mDto.setType(Constants.GROWTH_TYPE.add.name());
+        mDto.setRemarks("订单: " + o.getOrderNo());
+        memberGrowthRecordService.saveMemberGrowthRecord(mDto);
+
+        //积分计算
+        customerPointService.consumptionPoint(totalAmount, o.getOrderNo(), o.getCreateBy());
     }
 
     public JSONObject sendWxDeliveryGood(Order o) {
@@ -862,7 +1041,7 @@
         }
     }
 
-    public void confirmOrderReceive(String id) {
+    public Order confirmOrderReceive(String id) {
         Order o = orderMapper.selectById(id);
         String userId = SecurityUtils.getUserId();
         if (!userId.equals(o.getCreateBy())) {
@@ -881,6 +1060,8 @@
         o.setReceiveTime(LocalDateTime.now());
         o.update(userId);
         orderMapper.updateById(o);
+
+        return o;
     }
 
     public Integer getMyOrderStatusCount(String status) {
@@ -1194,4 +1375,14 @@
         order.update(SecurityUtils.getUserId());
         orderMapper.updateById(order);
     }
+
+    /**
+     * 获取用户最后收货时间
+     * @param userId
+     * @return
+     */
+    public LocalDateTime getUserLastOrderTime(String userId){
+        Order o = orderMapper.getUserLastOrder(userId);
+        return o.getReceiveTime();
+    }
 }

--
Gitblit v1.9.3