Просмотр исходного кода

Merge remote-tracking branch 'origin/master'

lixiaolong 1 месяц назад
Родитель
Сommit
861de946fc

+ 2 - 2
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/controller/UnifyOrderManager.java

@@ -283,8 +283,8 @@ public class UnifyOrderManager {
                 .getCompanyCode(), quoteVo.getOrder()
                 .getApiType(), sysQuoteConfigService, sysQuoteRedisService, platformClient, baseController);
 
-        // 生成主订单及子订单  返回子订单id
-        String ordersNo = insOrdersService.generateOrders(quoteVo, companyName, systemCode, quoteVo.getOrder().getProductId());
+        // 生成主订单及子订单  返回子订单id(带分布式锁,同车同险种并发时串行)
+        String ordersNo = insOrdersService.generateOrdersWithLock(quoteVo, companyName, systemCode, quoteVo.getOrder().getProductId());
 
         // 添加车辆没有的参数: 车辆明细、
         QuoteInfoParameterFilling.setParameterSettings(quoteVo, esmInsCompanyHttpResult.getData().getCompanyCode());

+ 11 - 0
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/service/InsOrdersService.java

@@ -63,6 +63,17 @@ public interface InsOrdersService extends IService<InsOrders> {
      */
     String generateOrders(QuoteVo quoteVo, String companyName, String systemCode,String productId);
 
+    /**
+     * 生成订单(带分布式锁):同车+同险种并发时串行,保证只有一个主订单,其余为子订单
+     *
+     * @param quoteVo     报价信息
+     * @param companyName 保险公司名称
+     * @param systemCode 租户代码
+     * @param productId  产品ID
+     * @return 子订单号
+     */
+    String generateOrdersWithLock(QuoteVo quoteVo, String companyName, String systemCode, String productId);
+
 
     /**
      * 获取主订单信息 用于判断是否存在主订单

+ 58 - 9
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/service/impl/InsOrdersServiceImpl.java

@@ -62,6 +62,8 @@ import jakarta.servlet.http.HttpServletRequest;
 import lombok.RequiredArgsConstructor;
 import lombok.Setter;
 import org.apache.http.util.TextUtils;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -81,6 +83,7 @@ import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 @RequiredArgsConstructor
@@ -136,6 +139,8 @@ public class InsOrdersServiceImpl extends ServiceImpl<InsOrdersMapper, InsOrders
 
     private final OrderStateListener orderStateListener;
 
+    private final RedissonClient redissonClient;
+
     @Autowired
     private InsOrdersQrcodeMapper insOrdersQrcodeMapper;
 
@@ -718,7 +723,7 @@ public class InsOrdersServiceImpl extends ServiceImpl<InsOrdersMapper, InsOrders
                 List<InsOrdersPolicy> list = insOrdersPolicyService.list(wrapper);
                 if(list != null && !list.isEmpty()){
                     // 修改订单时,排除原订单的问题
-                    if(!list.get(0).getOrderNo().equals(insOrdersExternalPolicy.getOrderNo())){
+                    if(!list.get(0).getOrderNo().equals(ordersEnd.getInsOrders().getId())){
                         return HttpResult.error("该交强险保单号信息已存在!");
                     }
                 }
@@ -728,7 +733,7 @@ public class InsOrdersServiceImpl extends ServiceImpl<InsOrdersMapper, InsOrders
                 wrapper.eq(InsOrdersPolicy::getSyPolicyNo, insOrdersExternalPolicy.getSyPolicy());
                 List<InsOrdersPolicy> list = insOrdersPolicyService.list(wrapper);
                 if(list != null && !list.isEmpty()){
-                    if(!list.get(0).getOrderNo().equals(insOrdersExternalPolicy.getOrderNo())){
+                    if(!list.get(0).getOrderNo().equals(ordersEnd.getInsOrders().getId())){
                         return HttpResult.error("该商业保单号信息已存在!");
                     }
                 }
@@ -1759,6 +1764,44 @@ public class InsOrdersServiceImpl extends ServiceImpl<InsOrdersMapper, InsOrders
 
     }
 
+    /**
+     * 生成订单(带分布式锁):同车+同险种并发时串行,保证只有一个主订单,其余为子订单
+     * 锁粒度:车牌+车架+险种(不含保司,因为同车同险种只允许一个主订单)
+     * 锁释放在事务提交后(外层方法非事务,内层 generateOrders 事务返回时已提交)
+     *
+     * @param quoteVo     报价参数
+     * @param companyName 保司名称
+     * @param systemCode  系统编码
+     * @param productId   产品ID
+     * @return 子订单号
+     */
+    @Override
+    public String generateOrdersWithLock(QuoteVo quoteVo, String companyName, String systemCode, String productId) {
+        String licenseNo = quoteVo.getCarInfoVo().getLicenseNo();
+        String vinNo = quoteVo.getCarInfoVo().getVinNo();
+        // 锁 key:车+险种(同车同险种串行)
+        String lockKey = "order:generate:" + licenseNo + ":" + vinNo + ":" + productId;
+        RLock lock = redissonClient.getLock(lockKey);
+
+        try {
+            // 等锁 3 秒,持锁 30 秒(覆盖事务提交)
+            boolean locked = lock.tryLock(10, 30, TimeUnit.SECONDS);
+            if (!locked) {
+                log.warn("生成订单获取锁失败,lockKey=[{}]", lockKey);
+                throw new SystemException("订单生成中,请稍后重试");
+            }
+            // 调用事务方法,return 后事务已提交,再释放锁
+            return this.generateOrders(quoteVo, companyName, systemCode, productId);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new SystemException("生成订单被中断");
+        } finally {
+            if (lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
+        }
+    }
+
     /**
      * 生成一个主订单和多个子订单
      *
@@ -2250,9 +2293,13 @@ public class InsOrdersServiceImpl extends ServiceImpl<InsOrdersMapper, InsOrders
         BigDecimal jqAddThrow = nvl(request.getJqAddThrow());
         BigDecimal syAddThrow = nvl(request.getSyAddThrow());
         BigDecimal jyAddThrow = nvl(request.getJyAddThrow());
-        BigDecimal jqExport = this.calExportByIsRecordByLeader(request.isIsrecordByLeader(), nvl(request.getJqExport()));
-        BigDecimal syExport = this.calExportByIsRecordByLeader(request.isIsrecordByLeader(), nvl(request.getSyExport()));
-        BigDecimal jyExport = this.calExportByIsRecordByLeader(request.isIsrecordByLeader(), nvl(request.getJyExport()));
+        // 代课录单扣减1
+
+        BigDecimal jqExport = nvl(request.getJqExport());
+        BigDecimal syExport = nvl(request.getSyExport());
+        BigDecimal jyExport = nvl(request.getJyExport());
+
+
 
         BigDecimal jqEKP = nvl(request.getJqKeepPointRatio());
         BigDecimal syEKP = nvl(request.getSyKeepPointRatio());
@@ -2339,13 +2386,15 @@ public class InsOrdersServiceImpl extends ServiceImpl<InsOrdersMapper, InsOrders
         feeOrders.setSyKeepPointRatio(div100(nvl(feeOrders.getSyKeepPointRatio())));
         feeOrders.setJyKeepPointRatio(div100(nvl(feeOrders.getJyKeepPointRatio())));
 
-        // 出口比例 = 入口比例 +加投比例 - 分销比例 -留点比例
+        // 出口比例 = 入口比例 +加投比例 - 分销比例 -留点比例-代课录单比例
         BigDecimal firstDist = nvl(feeOrders.getFirstDistributionRatio());
         BigDecimal secondDist = nvl(feeOrders.getSecondDistributionRatio());
         BigDecimal thirdDist = nvl(feeOrders.getThirdDistributionRatio());
-        feeOrders.setJqExportRatio(jqInlet.compareTo(BigDecimal.ZERO) > 0 ? div100(jqInlet).add(div100(request.getJqAddThrow())).subtract(div100(firstDist)).subtract(div100(secondDist)).subtract(div100(thirdDist)).subtract(div100(jqEKP)) : BigDecimal.ZERO);
-        feeOrders.setSyExportRatio(syInlet.compareTo(BigDecimal.ZERO) > 0 ? div100(syInlet).add(div100(request.getSyAddThrow())).subtract(div100(firstDist)).subtract(div100(secondDist)).subtract(div100(thirdDist)).subtract(div100(syEKP)) : BigDecimal.ZERO);
-        feeOrders.setJyExportRatio(jyInlet.compareTo(BigDecimal.ZERO) > 0 ? div100(jyInlet).add(div100(request.getJyAddThrow())).subtract(div100(firstDist)).subtract(div100(secondDist)).subtract(div100(thirdDist)).subtract(div100(jyEKP)) : BigDecimal.ZERO);
+        // 代课录单比例
+        BigDecimal IsrecordByLeader = request.isIsrecordByLeader() ? new BigDecimal("0.01") :BigDecimal.ZERO;
+        feeOrders.setJqExportRatio(jqInlet.compareTo(BigDecimal.ZERO) > 0 ? div100(jqInlet).add(div100(request.getJqAddThrow())).subtract(div100(firstDist)).subtract(div100(secondDist)).subtract(div100(thirdDist)).subtract(div100(jqEKP)).subtract(IsrecordByLeader) : BigDecimal.ZERO);
+        feeOrders.setSyExportRatio(syInlet.compareTo(BigDecimal.ZERO) > 0 ? div100(syInlet).add(div100(request.getSyAddThrow())).subtract(div100(firstDist)).subtract(div100(secondDist)).subtract(div100(thirdDist)).subtract(div100(syEKP)).subtract(IsrecordByLeader) : BigDecimal.ZERO);
+        feeOrders.setJyExportRatio(jyInlet.compareTo(BigDecimal.ZERO) > 0 ? div100(jyInlet).add(div100(request.getJyAddThrow())).subtract(div100(firstDist)).subtract(div100(secondDist)).subtract(div100(thirdDist)).subtract(div100(jyEKP)).subtract(IsrecordByLeader) : BigDecimal.ZERO);
 
         feeOrders.setJqExportKeepPointRatio(div100(request.getJqExportKeepPointRatio()!=null? request.getJqExportKeepPointRatio() : new BigDecimal(0)));
         feeOrders.setSyExportKeepPointRatio(div100(request.getSyExportKeepPointRatio()!=null? request.getSyExportKeepPointRatio() : new BigDecimal(0)));