Procházet zdrojové kódy

APP增加商城订单提交授信支付逻辑

FengChaoYu před 2 týdny
rodič
revize
5b14ce0fc6

+ 13 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/bean/user/UserCompanyCreditBean.java

@@ -0,0 +1,13 @@
+package com.gree.mall.miniapp.bean.user;
+
+import com.gree.mall.miniapp.plus.entity.UserCompanyCredit;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class UserCompanyCreditBean extends UserCompanyCredit {
+
+
+}

+ 10 - 1
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/commonmapper/MaterialMapper.java → mall-miniapp-service/src/main/java/com/gree/mall/miniapp/commonmapper/LockQueryMapper.java

@@ -2,11 +2,12 @@ package com.gree.mall.miniapp.commonmapper;
 
 import com.gree.mall.miniapp.bean.goods.GoodsMaterialStockDTO;
 import com.gree.mall.miniapp.plus.entity.GoodsMaterialStorage;
+import com.gree.mall.miniapp.plus.entity.UserCompanyCredit;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
-public interface MaterialMapper {
+public interface LockQueryMapper {
     /**
      * 带锁查询物料库存
      * @param dto
@@ -15,4 +16,12 @@ public interface MaterialMapper {
      */
     List<GoodsMaterialStorage> queryExistGoodsMaterialStockList(@Param("dto") GoodsMaterialStockDTO dto,
                                                                 @Param("stockList") List<GoodsMaterialStockDTO> stockList);
+
+    /**
+     * 带锁查询用户授信记录
+     * @param companyWechatId
+     * @param userId
+     * @return
+     */
+    UserCompanyCredit queryExistUserCompanyCredit(@Param("companyWechatId") String companyWechatId, @Param("userId") String userId);
 }

+ 2 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/constant/Constant.java

@@ -48,6 +48,8 @@ public class Constant {
         //订单号每日流水
         public final static String ORDER_NUM = "zfire:overseas:orderNo:";
 
+        public final static String LOCK_CREDIT_ORDER = "zfire:overseas:lock:credit:order";
+        public final static String LOCK_USER_COMPANY_CREDIT = "zfire:overseas:lock:user:company:credit:";
 
         // 接口令牌
         public final static String INF_TOKEN = "zfire:overseas:token:inf";

+ 3 - 3
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/logic/goods/GoodsMaterialStockLogic.java

@@ -2,7 +2,7 @@ package com.gree.mall.miniapp.logic.goods;
 
 import cn.hutool.core.collection.CollectionUtil;
 import com.gree.mall.miniapp.bean.goods.GoodsMaterialStockDTO;
-import com.gree.mall.miniapp.commonmapper.MaterialMapper;
+import com.gree.mall.miniapp.commonmapper.LockQueryMapper;
 import com.gree.mall.miniapp.constant.Constant;
 import com.gree.mall.miniapp.enums.material.DirectFlagEnum;
 import com.gree.mall.miniapp.exception.RemoteServiceException;
@@ -38,7 +38,7 @@ public class GoodsMaterialStockLogic {
     private final RedisLockRegistry redisLockRegistry;
     private final GoodsMaterialStorageService goodsMaterialStorageService;
     private final GoodsMaterialStockAccService goodsMaterialStockAccService;
-    private final MaterialMapper materialMapper;
+    private final LockQueryMapper lockQueryMapper;
     private final GoodsMaterialAccService goodsMaterialAccService;
 
     /**
@@ -84,7 +84,7 @@ public class GoodsMaterialStockLogic {
 
     private void saveGoodsMaterialStock(GoodsMaterialStockDTO dto, List<GoodsMaterialStockDTO> stockList) {
         // 查询存在的仓库物料库存
-        List<GoodsMaterialStorage> existStockList = materialMapper.queryExistGoodsMaterialStockList(dto, stockList);
+        List<GoodsMaterialStorage> existStockList = lockQueryMapper.queryExistGoodsMaterialStockList(dto, stockList);
         // 全部仓库物料库存
         Map<String, GoodsMaterialStorage> existStockMap = this.createNotExistStock(stockList, existStockList);
         // 计算仓库物料库存

+ 6 - 2
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/logic/order/OrderLogic.java

@@ -33,6 +33,7 @@ import com.gree.mall.miniapp.logic.goods.GoodsMaterialStockLogic;
 import com.gree.mall.miniapp.logic.promotion.PromotionFullPieceLogic;
 import com.gree.mall.miniapp.logic.promotion.PromotionGroupLogic;
 import com.gree.mall.miniapp.logic.user.PayLogic;
+import com.gree.mall.miniapp.logic.user.UserCompanyCreditLogic;
 import com.gree.mall.miniapp.logic.user.UserLogic;
 import com.gree.mall.miniapp.plus.entity.*;
 import com.gree.mall.miniapp.plus.service.*;
@@ -155,6 +156,8 @@ public class OrderLogic {
     OrderPickTimeConfigService orderPickTimeConfigService;
     @Resource
     GoodsMaterialStockLogic goodsMaterialStockLogic;
+    @Resource
+    UserCompanyCreditLogic userCompanyCreditLogic;
 
     /**
      * 立即购买
@@ -354,6 +357,7 @@ public class OrderLogic {
         // 如果是到店支付,订单改为待确认
         if (orderBuyBean.getPayTypeId().equals(PayTypeEnum.CREDIT.getKey())) {
             orderInfo.setOrderStatus(OrderStatusEnum.DJH.toString());
+            orderInfo.setIsCreditOrder(true);
         } else if (orderBuyBean.getPayTypeId().equals(PayTypeEnum.STORE.getKey())) {
             orderInfo.setOrderStatus(OrderStatusEnum.DQR.toString());
         }
@@ -413,8 +417,8 @@ public class OrderLogic {
             // TODO 在线支付逻辑
 
         } else if (StringUtils.equals(orderBuyBean.getPayTypeId(), PayTypeEnum.CREDIT.getKey())) {
-            // TODO 授信支付逻辑
-
+            // 授信支付逻辑
+            userCompanyCreditLogic.createCreditRecord(orderInfo, user);
             payDetail.setIsPay(false);
         } else {
             payDetail.setIsPay(false);

+ 90 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/logic/user/UserCompanyCreditLogic.java

@@ -0,0 +1,90 @@
+package com.gree.mall.miniapp.logic.user;
+
+import cn.hutool.core.date.DateUtil;
+import com.gree.mall.miniapp.commonmapper.LockQueryMapper;
+import com.gree.mall.miniapp.constant.Constant;
+import com.gree.mall.miniapp.exception.RemoteServiceException;
+import com.gree.mall.miniapp.helper.ResponseHelper;
+import com.gree.mall.miniapp.plus.entity.OrderInfo;
+import com.gree.mall.miniapp.plus.entity.User;
+import com.gree.mall.miniapp.plus.entity.UserCompanyCredit;
+import com.gree.mall.miniapp.plus.service.UserCompanyCreditService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.integration.redis.util.RedisLockRegistry;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.support.TransactionSynchronization;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class UserCompanyCreditLogic {
+
+    private final RedisLockRegistry redisLockRegistry;
+    private final UserCompanyCreditService userCompanyCreditService;
+    private final LockQueryMapper lockQueryMapper;
+
+    public void createCreditRecord(OrderInfo orderInfo, User user) throws Exception {
+        if(!TransactionSynchronizationManager.isSynchronizationActive()) {
+            throw new RemoteServiceException("请先开启事务");
+        }
+        Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.LOCK_CREDIT_ORDER + user.getUserId());
+        if(!obtain.tryLock(10, TimeUnit.SECONDS)){
+            throw new RemoteServiceException("订单创建过于频繁, 请稍后再试");
+        }
+        // 处理授信
+        try{
+            final BigDecimal payAmount = orderInfo.getPayAmount();
+            final UserCompanyCredit userCompanyCredit = lockQueryMapper.queryExistUserCompanyCredit(orderInfo.getCompanyWechatId(), orderInfo.getUserId());
+            if (Objects.isNull(userCompanyCredit)) {
+                throw new RemoteServiceException("用户在该商户下无授信关系");
+            }
+
+            if (!userCompanyCredit.getIsCreditEnabled()) {
+                throw new RemoteServiceException("用户在该商户下的授信未启用");
+            }
+
+            if (userCompanyCredit.getAvailableCredit().compareTo(payAmount) < 0) {
+                throw new RemoteServiceException("商户授信额度不足");
+            }
+
+            userCompanyCreditService.lambdaUpdate()
+                    .set(UserCompanyCredit::getAvailableCredit, userCompanyCredit.getAvailableCredit().subtract(payAmount))
+                    .set(UserCompanyCredit::getUpdateTime, DateUtil.date())
+                    .eq(UserCompanyCredit::getId, userCompanyCredit.getId())
+                    .update();
+
+        } finally {
+            this.txCallUnlock(obtain);
+        }
+    }
+
+    private void txCallUnlock(Lock obtain) {
+        //事务提交完成后才释放锁,此方法禁止执行mysql相关操作,否则将导致重大问题。
+        if (TransactionSynchronizationManager.isActualTransactionActive()) {
+            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
+                @Override
+                public void afterCompletion(int status) {
+
+                    if(TransactionSynchronization.STATUS_COMMITTED == status){
+                        log.info("=========【授信支付】======事务提交==============");
+                    }else if(TransactionSynchronization.STATUS_ROLLED_BACK == status){
+                        log.info("========【授信支付】=========事务回滚============");
+                    }
+
+                    obtain.unlock();
+                }
+            });
+        } else {
+            log.info("【授信支付】====没有事务===释放锁");
+            obtain.unlock();
+        }
+    }
+}

+ 12 - 1
mall-miniapp-service/src/main/resources/mapper/MaterialMapper.xml → mall-miniapp-service/src/main/resources/mapper/LockQueryMapper.xml

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.gree.mall.miniapp.commonmapper.MaterialMapper">
+<mapper namespace="com.gree.mall.miniapp.commonmapper.LockQueryMapper">
     <select id="queryExistGoodsMaterialStockList"
             resultType="com.gree.mall.miniapp.plus.entity.GoodsMaterialStorage">
         SELECT
@@ -19,4 +19,15 @@
         </foreach>
         FOR UPDATE
     </select>
+    <select id="queryExistUserCompanyCredit" resultType="com.gree.mall.miniapp.plus.entity.UserCompanyCredit">
+        SELECT
+            *
+        FROM
+            user_company_credit
+        WHERE
+            company_wechat_id = #{companyWechatId}
+            AND
+            user_id = #{userId}
+        FOR UPDATE
+    </select>
 </mapper>