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

Merge branch 'dev_jzg_lipf_v20260518'

lipf 4 месяцев назад
Родитель
Сommit
49aa08595e
27 измененных файлов с 486 добавлено и 159 удалено
  1. 8 0
      commons/src/main/java/com/jzg/commons/entity/finance/po/InsPlyIncome.java
  2. 4 0
      commons/src/main/java/com/jzg/commons/entity/finance/po/InsPlyIncomeInvoiceLink.java
  3. 3 0
      commons/src/main/java/com/jzg/commons/entity/orders/po/InsFeeAudit.java
  4. 5 0
      commons/src/main/java/com/jzg/commons/entity/orders/vo/FeeAuditVo.java
  5. 4 0
      commons/src/main/java/com/jzg/commons/entity/scheme/po/PtlSchemeInfo.java
  6. 3 0
      commons/src/main/java/com/jzg/commons/entity/scheme/po/PtlSchemeRulesAttrLink.java
  7. 1 1
      commons/src/main/java/com/jzg/commons/util/BuildDescUtils.java
  8. 10 0
      tenant/insurance/quotation-guoren/src/main/java/com/jzg/quotation/guoren/crawler/component/GuoRenCrawlerRequestComponent.java
  9. 16 9
      tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/controller/InsFeeAuditController.java
  10. 6 3
      tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/service/InsFeeAuditService.java
  11. 17 6
      tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/service/impl/InsFeeAuditServiceImpl.java
  12. 5 2
      tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/state/listener/AuditStateListener.java
  13. 2 1
      tenant/insurance/quotation-summary/src/main/resources/mapper/InsFeeAuditMapper.xml
  14. 6 0
      tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/component/ZhongAnCrawlerCacheComponent.java
  15. 1 1
      tenant/organization/src/main/java/com/jzg/organization/controller/PtlAgreementCostController.java
  16. 7 4
      tenant/organization/src/main/java/com/jzg/organization/controller/ReceivableController.java
  17. 13 2
      tenant/organization/src/main/java/com/jzg/organization/mapper/ReceivableMapper.java
  18. 7 1
      tenant/organization/src/main/java/com/jzg/organization/service/PtlAgreementCostService.java
  19. 29 0
      tenant/organization/src/main/java/com/jzg/organization/service/PtlAreaLicenseService.java
  20. 10 1
      tenant/organization/src/main/java/com/jzg/organization/service/ReceivableService.java
  21. 12 3
      tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlAgreementCostServiceImpl.java
  22. 42 47
      tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlAgreementDispatchServiceImpl.java
  23. 76 0
      tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlAreaLicenseServiceImpl.java
  24. 2 2
      tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlSchemeServiceImpl.java
  25. 138 42
      tenant/organization/src/main/java/com/jzg/organization/service/impl/ReceivableServiceImpl.java
  26. 7 11
      tenant/organization/src/main/resources/mapper/PtlSchemeMapper.xml
  27. 52 23
      tenant/organization/src/main/resources/mapper/ReceivableMapper.xml

+ 8 - 0
commons/src/main/java/com/jzg/commons/entity/finance/po/InsPlyIncome.java

@@ -278,4 +278,12 @@ public class InsPlyIncome extends BaseModel {
     @Schema(description = "订单费用表")
     private InsFeeOrders insFeeOrders;
 
+    @TableField(exist = false)
+    @Schema(description = "是否已经开票")
+    private String invoiceStatusName;
+
+    @TableField(exist = false)
+    @Schema(description = "订单关联的发票信息")
+    private String invoiceId;
+
 }

+ 4 - 0
commons/src/main/java/com/jzg/commons/entity/finance/po/InsPlyIncomeInvoiceLink.java

@@ -17,4 +17,8 @@ public class InsPlyIncomeInvoiceLink{
     @Schema(description = "应收表ID")
     private String incomeId;
 
+    // 开票类型 1:手续费 2:跟单费 3:驾意手续费 4::驾意跟单费
+    @Schema(description = "开票类型")
+    private String invoiceType;
+
 }

+ 3 - 0
commons/src/main/java/com/jzg/commons/entity/orders/po/InsFeeAudit.java

@@ -44,6 +44,9 @@ public class InsFeeAudit extends BaseModel {
     @Schema(description = "是否是疑问订单 0.否 1.是")
     private Integer isProblem;
 
+    @Schema(description = "设为疑问单的原因")
+    private String problemReason;
+
     @Schema(description = "驳回原因")
     private String refuse;
 

+ 5 - 0
commons/src/main/java/com/jzg/commons/entity/orders/vo/FeeAuditVo.java

@@ -129,4 +129,9 @@ public class FeeAuditVo extends BaseModel {
     @Schema(description = "权益金额")
     private BigDecimal equityAmount;
 
+    @Schema(description = "是否是疑问单")
+    private int problem;
+
+    @Schema(description = "设置为疑问单的原因")
+    private String problemReason;
 }

+ 4 - 0
commons/src/main/java/com/jzg/commons/entity/scheme/po/PtlSchemeInfo.java

@@ -6,9 +6,13 @@ import com.jzg.commons.core.base.BaseModel;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
+import java.io.Serial;
+
 @Data
 public class PtlSchemeInfo extends BaseModel {
 
+    @Serial
+    private static final long serialVersionUID = 6506525156379399705L;
     @TableId(value = "id")
     private String id;
 

+ 3 - 0
commons/src/main/java/com/jzg/commons/entity/scheme/po/PtlSchemeRulesAttrLink.java

@@ -7,12 +7,15 @@ import com.jzg.commons.core.base.BaseModel;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
+import java.io.Serial;
 import java.util.ArrayList;
 import java.util.List;
 
 @Data
 public class PtlSchemeRulesAttrLink extends BaseModel {
 
+    @Serial
+    private static final long serialVersionUID = 3487191741779052143L;
     @TableId(value = "id")
     private String id;
 

+ 1 - 1
commons/src/main/java/com/jzg/commons/util/BuildDescUtils.java

@@ -36,7 +36,7 @@ public class BuildDescUtils {
                     desc.append(ptlAgreementUndwrtRulesAttr.getAttrName()).append("包含");
                     for (int k=0 ; k<link.getMinArray().length; k++){
                         PtlAgreementUndwrtRulesDictLabal ptlAgreementUndwrtRulesDictLabal = ptlAgreementUndwrtRulesAttr.getDictLabal().stream().filter(x -> Arrays.asList(link.getMinArray()).contains(x.getCode())).findFirst().orElse(null);
-                        desc.append(ptlAgreementUndwrtRulesDictLabal.getName()).append(",");
+                        desc.append(null != ptlAgreementUndwrtRulesDictLabal ? ptlAgreementUndwrtRulesDictLabal.getName() : "").append(",");
                     }
 
                 }else {

+ 10 - 0
tenant/insurance/quotation-guoren/src/main/java/com/jzg/quotation/guoren/crawler/component/GuoRenCrawlerRequestComponent.java

@@ -10,6 +10,7 @@ import com.jzg.commons.entity.quote.vo.QuoteVo;
 import com.jzg.commons.entity.quote.vo.image.InsuranceImageVo;
 import com.jzg.commons.exception.SystemException;
 import com.jzg.commons.exception.TokenExpireException;
+import com.jzg.commons.util.AssertionUtils;
 import com.jzg.commons.util.MinioUtils;
 import com.jzg.commons.util.StringUtils;
 import com.jzg.quotation.commons.client.PlatformClient;
@@ -41,6 +42,8 @@ import org.springframework.util.CollectionUtils;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.util.List;
 import java.util.Optional;
 
@@ -118,6 +121,12 @@ public class GuoRenCrawlerRequestComponent {
      */
     public <Response> Response request(RequestUrl requestUrl, Object body, Class<Response> responseClass, HttpHeaders httpHeaders) {
         String url = guoRenCrawlerProperties.getBaseUrl() + requestUrl.getUri();
+        // 校验是否为合法 URL
+        try {
+            new URL(url);
+        } catch (MalformedURLException e) {
+            return null;
+        }
         ResponseEntity<Response> responseResponseEntity = requestComponent.objectPost(url, body, responseClass, httpHeaders);
         return responseResponseEntity.getBody();
     }
@@ -132,6 +141,7 @@ public class GuoRenCrawlerRequestComponent {
     public IdentifyCodeDataResponse identifyCode(String username) {
         GuoRenCrawlerIdentifyCodeRequest identifyCodeRequest = new GuoRenCrawlerIdentifyCodeRequest(username);
         IdentifyCodeDataResponse request = request(RequestUrl.IDENTIFY_CODE, identifyCodeRequest, IdentifyCodeDataResponse.class, new HttpHeaders());
+        AssertionUtils.isEmpty(request, "验证码请求失败,未获取到验证码编号");
         if (request.getResultCode() != 0) {
             throw new SystemException(request.getResultMsg());
         }

+ 16 - 9
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/controller/InsFeeAuditController.java

@@ -20,6 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
+import java.util.Objects;
 
 @Tag(name="订单审核接口")
 @RestController
@@ -79,12 +80,12 @@ public class InsFeeAuditController {
     }
 
     /**
-     * 领取审核订单
+     * 领取待审核订单
      * @return
      */
     @PostMapping("/auditReceive")
     @Operation(summary = "领取审核订单")
-    public HttpResult auditReceive(@RequestParam("orderNo") String orderNo){
+    public HttpResult<String> auditReceive(@RequestParam("orderNo") String orderNo){
         insFeeAuditService.auditReceive(orderNo);
         return HttpResult.ok("领取订单完成");
     }
@@ -125,18 +126,24 @@ public class InsFeeAuditController {
             log.info("审核订单发生异常:param=[{}], e", JSONUtil.toJsonStr(param), e);
             return HttpResult.ok(e.getMessage());
         }
-
-        return HttpResult.ok("订单审核成功");
+        if("1".equals(Objects.toString(param.getAuditStatus(),"") )){
+            return HttpResult.ok("订单审核成功");
+        }else if("2".equals(Objects.toString(param.getAuditStatus(),""))){
+            return HttpResult.ok("订单审核驳回成功");
+        }else{
+            return HttpResult.ok("订单审核状态不支持。"+param.getAuditStatus());
+        }
     }
 
     /**
      * 设置为疑问订单
-     * @return
+     *
+     * @return HttpResult<String> 设为疑问单的处理结果
      */
     @PostMapping("/updateToQuestionOrder")
     @Operation(summary = "设置为疑问订单")
-    public HttpResult updateToQuestionOrder(@RequestParam("orderNo") String orderNo){
-        insFeeAuditService.updateToQuestionOrder(orderNo,"1");
+    public HttpResult<String> updateToQuestionOrder(@RequestParam("orderNo") String orderNo,@RequestParam(value = "problemReason",required = false) String problemReason){
+        insFeeAuditService.updateToQuestionOrder(orderNo,"1", problemReason);
         return HttpResult.ok("已设为疑问订单,可前往疑问订单列表查看");
     }
 
@@ -146,8 +153,8 @@ public class InsFeeAuditController {
      */
     @PostMapping("/updateToUnQuestionOrder")
     @Operation(summary = "设置为疑问订单")
-    public HttpResult updateToUnQuestionOrder(@RequestParam("orderNo") String orderNo){
-        insFeeAuditService.updateToQuestionOrder(orderNo,"0");
+    public HttpResult<String> updateToUnQuestionOrder(@RequestParam("orderNo") String orderNo){
+        insFeeAuditService.updateToQuestionOrder(orderNo,"0", "");
         return HttpResult.ok("已取消疑问订单,可前往待审核订单列表查看");
     }
 

+ 6 - 3
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/service/InsFeeAuditService.java

@@ -43,7 +43,8 @@ public interface InsFeeAuditService extends IService<InsFeeAudit> {
 
     /**
      * 领取审核订单
-     * @param orderNo
+     *
+     * @param orderNo 订单编号
      */
     void auditReceive(String orderNo);
 
@@ -75,9 +76,11 @@ public interface InsFeeAuditService extends IService<InsFeeAudit> {
 
     /**
      * 设置为疑问订单
-     * @param orderNo
+     *
+     * @param orderNo 订单编号
+     * @param problemReason 设置为疑问单的原因
      */
-    void updateToQuestionOrder(String orderNo,String status);
+    void updateToQuestionOrder(String orderNo, String status, String problemReason);
 
     /**
      * 订单审核费用详情

+ 17 - 6
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/service/impl/InsFeeAuditServiceImpl.java

@@ -230,8 +230,14 @@ public class InsFeeAuditServiceImpl extends ServiceImpl<InsFeeAuditMapper, InsFe
         return detailVo;
     }
 
+    /**
+     * 领取审核订单
+     *
+     * @param orderNo 订单编号
+     */
     @Override
     public void auditReceive(String orderNo) {
+        log.info("领取待审核订单。 orderNo=[{}]",orderNo);
         AssertionUtils.isFail(this.isLock(orderNo),"订单已被领取");
         InsFeeAudit audit = this.getById(orderNo);
         if(audit.getAuditStatus() > 0){
@@ -296,8 +302,11 @@ public class InsFeeAuditServiceImpl extends ServiceImpl<InsFeeAuditMapper, InsFe
 
     @Override
     public Boolean isLock(String orderNo) {
-        RBucket<Object> bucket = redissonClient.getBucket(ORDER_LOCK_PREFIX + orderNo);
-        return bucket.isExists();
+        String key = ORDER_LOCK_PREFIX + orderNo;
+        RBucket<Object> bucket = redissonClient.getBucket(key);
+        boolean exists = bucket.isExists();
+        log.info("订单锁定状态:[{}]-[{}]",key,exists);
+        return exists;
     }
 
     @Override
@@ -555,8 +564,10 @@ public class InsFeeAuditServiceImpl extends ServiceImpl<InsFeeAuditMapper, InsFe
             HttpResult result2 = orgClient.addUserAccountIncomeLog(builderIncomeLog);
             AssertionUtils.isFail(result2.getCode() != 200,"账户记录添加失败,审核失败");
         }else{
+            log.info("订单审核驳回:param=[{}]", JSONUtil.toJsonStr(param));
             StateResult stateFailResult = auditStateListener.statusChange(AuditState.AuditStateEnum.FAIL_AUDIT,audit.getAuditStatus()+"");
-            audit.setAuditStatus(stateFailResult.getCurrentState());
+            log.error("订单审核驳回:stateFailResult=[{}]", JSONUtil.toJsonStr(stateFailResult));
+            audit.setAuditStatus(param.getAuditStatus());
         }
         audit.setRefuse(param.getRefuse());
         audit.setIsProblem(0);
@@ -571,7 +582,6 @@ public class InsFeeAuditServiceImpl extends ServiceImpl<InsFeeAuditMapper, InsFe
         }catch (Exception e){
             log.error("保存合伙人佣金计算异常:{}",e.getMessage(), e);
         }
-
     }
 
     /**
@@ -649,7 +659,8 @@ public class InsFeeAuditServiceImpl extends ServiceImpl<InsFeeAuditMapper, InsFe
     }
 
     @Override
-    public void updateToQuestionOrder(String orderNo,String status) {
+    public void updateToQuestionOrder(String orderNo, String status, String problemReason) {
+        log.info("更新订单的疑问状态。 orderNo=[{}],status=[{}], problemReason=[{}]",orderNo,status,problemReason);
         InsFeeAudit audit = this.getById(orderNo);
         if(audit.getAuditStatus() > 0){
             AssertionUtils.isFail(true, "订单已审核刷新订单详情页!");
@@ -662,7 +673,7 @@ public class InsFeeAuditServiceImpl extends ServiceImpl<InsFeeAuditMapper, InsFe
         if (!userName.equals(audit.getReceiveUser())) {
             AssertionUtils.isFail(true, "订单已被"+audit.getReceiveUser()+"领取返回待审核订单列表!");
         }
-
+        audit.setProblemReason(Objects.toString(problemReason,""));
         audit.setIsProblem(Integer.parseInt(status));
         this.updateById(audit);
     }

+ 5 - 2
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/state/listener/AuditStateListener.java

@@ -1,10 +1,11 @@
 package com.jzg.quotation.summary.state.listener;
 
-import com.jzg.commons.constants.dict.InsOrderStatusEnum;
 import com.jzg.commons.core.base.StateResult;
 import com.jzg.commons.util.AssertionUtils;
 import com.jzg.quotation.summary.state.AuditState;
 import jakarta.annotation.Resource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.messaging.Message;
 import org.springframework.messaging.support.MessageBuilder;
 import org.springframework.statemachine.StateMachine;
@@ -19,6 +20,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
 @Component
 public class AuditStateListener {
 
+    private static final Logger log = LoggerFactory.getLogger(AuditStateListener.class);
+
     @Resource
     private StateMachine<AuditState.AuditStateEnum, AuditState.AuditStateEvent> costStateMachine;
 
@@ -47,7 +50,7 @@ public class AuditStateListener {
                 result.set(true);
             }
         } catch (Exception e) {
-
+            log.error("sendEvent发生异常",e);
         } finally {
             costStateMachine.stopReactively();
             return result.get();

+ 2 - 1
tenant/insurance/quotation-summary/src/main/resources/mapper/InsFeeAuditMapper.xml

@@ -57,7 +57,8 @@
                ioc.jq_premium as jqPremium, ioc.sy_premium as syPremium, ioc.jy_premium as jyPremium,
                ioc.sum_premium as sumPremium,sd.name as deptName,ifa.create_time as createTime,
                ifa.create_by as createBy,io.pay_time as payTime, ifa.audit_time as auditTime,
-               ifa.audit_user as auditUser, ifa.refuse
+               ifa.audit_user as auditUser, ifa.refuse,
+               ifa.is_problem, ifa.problem_reason
         FROM ins_fee_audit ifa
         LEFT JOIN ins_orders as io on ifa.order_no = io.id
         LEFT JOIN ins_orders_car_info as ioci on io.id = ioci.order_no

+ 6 - 0
tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/component/ZhongAnCrawlerCacheComponent.java

@@ -2,6 +2,7 @@ package com.jzg.quotation.zhongan.crawler.component;
 
 import com.alibaba.fastjson2.JSON;
 import com.alibaba.fastjson2.JSONObject;
+import com.jzg.commons.util.AssertionUtils;
 import com.jzg.quotation.zhongan.crawler.client.LoginResult;
 import com.jzg.quotation.zhongan.crawler.entity.request.ZhongAnCrawlerQueryInitInfoRequest;
 import com.jzg.quotation.zhongan.crawler.entity.response.ZhongAnCrawlerPaymentResponse;
@@ -145,26 +146,31 @@ public class ZhongAnCrawlerCacheComponent {
             // 发送第一个请求,不跟随重定向
             HttpGet get1 = buildGet(uri1);
             CloseableHttpResponse resp1 = HTTP_CLIENT.execute(get1, context);
+            AssertionUtils.isEmpty(resp1, "第一次请求失败,请联系管理员");
             String location1 = resp1.getFirstHeader("Location").getValue();
             resp1.close();
             // 发送第二个请求
             HttpGet get2 = buildGet(new URI(location1));
             CloseableHttpResponse resp2 = HTTP_CLIENT.execute(get2, context);
+            AssertionUtils.isEmpty(resp2, "第二次请求失败,请联系管理员");
             String location2 = getLocationHeader(resp2);
             resp2.close();
             // 发送第三个请求
             HttpGet get3 = buildGet(new URI(location2));
             CloseableHttpResponse resp3 = HTTP_CLIENT.execute(get3, context);
+            AssertionUtils.isEmpty(resp3, "第三次请求失败,请联系管理员");
             String location3 = resp3.getFirstHeader("Location").getValue();
             resp3.close();
             // 发送第四个请求
             HttpGet get4 = buildGet(new URI(location3));
             CloseableHttpResponse resp4 = HTTP_CLIENT.execute(get4, context);
+            AssertionUtils.isEmpty(resp4, "第四次请求失败,请联系管理员");
             String location4 = resp4.getFirstHeader("Location").getValue();
             resp4.close();
             // 第五次请求,拿cookie
             HttpGet get5 = buildGet(new URI(location4));
             CloseableHttpResponse resp5 = HTTP_CLIENT.execute(get5, context);
+            AssertionUtils.isEmpty(resp5, "第五次请求失败,请联系管理员");
             String location5 = resp5.getFirstHeader("Location").getValue();
             // 提取 zaLoginCookieKey
             String cookieKey = null;

+ 1 - 1
tenant/organization/src/main/java/com/jzg/organization/controller/PtlAgreementCostController.java

@@ -45,7 +45,7 @@ public class PtlAgreementCostController {
     @OperatorTrajectory(moduleName = "报价配置/费用管理/修改费用",OperationDict = OperationTypeEnum.EDITED_AGREEMENT, type = "U", mapperClass = PtlAgreementCostMapper.class,entityClass = PtlAgreementCostEnd.class)
     @Operation(summary = "协议费用管理修改")
     @PostMapping("update")
-    public HttpResult update(@RequestBody @Valid PtlAgreementCostEnd costEndList){
+    public HttpResult<String> update(@RequestBody @Valid PtlAgreementCostEnd costEndList){
         return ptlAgreementCostService.update(costEndList);
     }
 

+ 7 - 4
tenant/organization/src/main/java/com/jzg/organization/controller/ReceivableController.java

@@ -168,11 +168,14 @@ public class ReceivableController {
 
     @PostMapping("invoicingCheck")
     @Operation(summary = "开票检测")
-    public HttpResult invoicingCheck(@RequestBody InvoicingVo invoicingVo) {
+    public HttpResult<String> invoicingCheck(@RequestBody InvoicingVo invoicingVo) {
         boolean result = receivableService.invoicingCheck(invoicingVo);
-        // 查询订单的应收跟单金额
-
-        return result ? HttpResult.ok("无占用") : HttpResult.error("有订单占用");
+        if(result){
+            return HttpResult.ok("无占用");
+        }else{
+            List<String> invoiceIds = receivableService.queryIncomeBindInvoice(invoicingVo);
+            return HttpResult.error("订单已开票。发票序号是"+ invoiceIds.toString());
+        }
     }
 
     @PostMapping("getReceivableCompany")

+ 13 - 2
tenant/organization/src/main/java/com/jzg/organization/mapper/ReceivableMapper.java

@@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.jzg.commons.entity.finance.dto.*;
 import com.jzg.commons.entity.finance.po.InsPlyIncome;
+import com.jzg.commons.entity.finance.po.InsPlyIncomeInvoice;
+import com.jzg.commons.entity.finance.po.InsPlyIncomeInvoiceLink;
 import com.jzg.commons.entity.finance.po.InsPlyIncomeInvoiceSettlement;
 import com.jzg.commons.entity.finance.vo.InvoiceRecordQueryVo;
 import com.jzg.commons.entity.finance.vo.InvoiceRecordResult;
@@ -16,6 +18,7 @@ import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
+import java.util.Map;
 
 @Mapper
 public interface ReceivableMapper extends BaseMapper<InsPlyIncome> {
@@ -149,6 +152,14 @@ public interface ReceivableMapper extends BaseMapper<InsPlyIncome> {
     List<InvoiceAmountDto> getSuperviseAmount();
     Integer invoicingCheck(@Param("invoicingVo") InvoicingVo invoicingVo);
 
+    /**
+     * 查询订单绑定发票信息
+     *
+     * @author lipf
+     * @date 2026/5/21 11:57
+     */
+    List<InsPlyIncomeInvoiceLink> queryIncomeBindInvoice(@Param("invoicingVo") InvoicingVo invoicingVo);
+
     /**
      * 对接人结算报表
      * @param page
@@ -158,9 +169,9 @@ public interface ReceivableMapper extends BaseMapper<InsPlyIncome> {
     Page<ReceiverSettlementReportDto> getReceiverSettlementReport(Page page,@Param("settlementReportQueryVo") SettlementReportQueryVo settlementReportQueryVo);
 
     /**
-     * 获取应收的总金额
+     * 获取应收交强的总金额
      */
-    String getJqSumReceivable(@Param("orderNos") List<String> orderNos);
+    Map<String, Object> getJqSumReceivable(@Param("orderNos") List<String> orderNos);
 
     /**
      * 获取开票记录

+ 7 - 1
tenant/organization/src/main/java/com/jzg/organization/service/PtlAgreementCostService.java

@@ -21,7 +21,13 @@ public interface PtlAgreementCostService extends IService<PtlAgreementCost> {
     HttpResult save(PtlAgreemenCostAdd ptlAgreemenCostAdd);
 
 
-    HttpResult update(PtlAgreementCostEnd costEndList);
+    /**
+     * 协议费用管理修改
+     *
+     * @author lipf
+     * @date 2026/5/22 11:26
+     */
+    HttpResult<String> update(PtlAgreementCostEnd costEndList);
 
 
     HttpResult queryById(@NotNull(message = "id不能为空") Long id);

+ 29 - 0
tenant/organization/src/main/java/com/jzg/organization/service/PtlAreaLicenseService.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.jzg.commons.entity.po.PtlAreaLicense;
 
 import java.util.List;
+import java.util.Map;
 
 public interface PtlAreaLicenseService extends IService<PtlAreaLicense> {
 
@@ -15,4 +16,32 @@ public interface PtlAreaLicenseService extends IService<PtlAreaLicense> {
      */
     List<PtlAreaLicense> getByParentNumber(String parentNumber);
 
+    /**
+     * 查看车牌号和所有地区的对应关系
+     *
+     * @return List<PtlAreaLicense> 所有车牌号和地区的对应关系
+     * @author lipf
+     * @date 2026/5/21 9:40
+     */
+    List<PtlAreaLicense> queryAllAreaLicense();
+
+    /**
+     * 查看车牌号和所有地区的对应关系
+     *
+     * @return Map<String,PtlAreaLicense> key是areaNumber, value是地区和车牌前缀的对应关系
+     * @author lipf
+     * @date 2026/5/21 9:45
+     */
+    Map<String,PtlAreaLicense> queryAllAreaLicenseMap();
+
+    /**
+     * 将地区编码转换为对应的车牌号
+     *
+     * @param areaNumbers 地区编码,支持多个拼接,例如1401,1402,1403
+     * @return String 地区车牌号,例如晋A,晋B,晋C
+     * @author lipf
+     * @date 2026/5/21 9:53
+     */
+    String convertAreaNumber2License(Map<String,PtlAreaLicense> areaLicenseMap , String areaNumbers);
+
 }

+ 10 - 1
tenant/organization/src/main/java/com/jzg/organization/service/ReceivableService.java

@@ -294,4 +294,13 @@ public interface ReceivableService extends IService<InsPlyIncome> {
     HttpResult<List<InsPlyIncome>> queryIncomeDatas(IncomeDataVO incomeDataVO);
 
     Boolean deleteInvoiceById(String id);
-}
+
+    /**
+     * 查询订单绑定的发票信息
+     *
+     * @return List<InsPlyIncomeInvoice> 订单绑定的发票信息
+     * @author lipf
+     * @date 2026/5/21 11:59
+     */
+    List<String> queryIncomeBindInvoice(InvoicingVo invoicingVo);
+    }

+ 12 - 3
tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlAgreementCostServiceImpl.java

@@ -128,9 +128,16 @@ public class PtlAgreementCostServiceImpl extends ServiceImpl<PtlAgreementCostMap
         return HttpResult.ok(ReturnInformation.SUCCESS_MESSAGE);
     }
 
+    /**
+     * 协议费用管理修改
+     *
+     * @author lipf
+     * @date 2026/5/22 11:26
+     */
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public HttpResult update(PtlAgreementCostEnd ptlAgreementCostEnd) {
+    public HttpResult<String> update(PtlAgreementCostEnd ptlAgreementCostEnd) {
+        log.info("协议费用修改。ptlAgreementCostEnd=[{}]", JSONUtil.toJsonStr(ptlAgreementCostEnd));
         if (ListUtils.hasDuplicates(ptlAgreementCostEnd.getRuleConditions())){
             return HttpResult.error("已存在相同且有效的费用规则,请检查");
         }
@@ -145,6 +152,8 @@ public class PtlAgreementCostServiceImpl extends ServiceImpl<PtlAgreementCostMap
             }
         }
         PtlAgreementCost ptlAgreementCost = BeanUtil.copyProperties(ptlAgreementCostEnd, PtlAgreementCost.class);
+        // modify by lipf, 2026年5月22日11:28:34 设置为待审核状态
+        ptlAgreementCost.setApproved(0);
         ptlAgreementCost.setCostRules(buildDescString(ptlAgreementCostEnd.getRuleConditions()));
         if (baseMapper.updateById(ptlAgreementCost) <= 0) {
             throw new RuntimeException(ReturnInformation.UPDATE_FAILED);
@@ -347,10 +356,10 @@ public class PtlAgreementCostServiceImpl extends ServiceImpl<PtlAgreementCostMap
         log.info("查询协议费用信息:costParam=[{}]", JSONUtil.toJsonStr(costParam));
         Page<CostManagementVo> costManagementVoPage = baseMapper.pageList(costParam.getPage(), costParam);
         costManagementVoPage.getRecords().forEach(item->{
-            if(item.getCostRules() != null && !item.getCostRules().equals("")){
+            if(item.getCostRules() != null && !item.getCostRules().isEmpty()){
                 item.setCostRules(item.getCostRules().substring(0,item.getCostRules().length()-1));
             }
-            if(item.getRuleDescription() != null && !item.getRuleDescription().equals("")){
+            if(item.getRuleDescription() != null && !item.getRuleDescription().isEmpty()){
                 item.setRuleDescription(item.getRuleDescription().substring(0,item.getRuleDescription().length()-1));
             }
             // 刷新有效状态

+ 42 - 47
tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlAgreementDispatchServiceImpl.java

@@ -12,10 +12,8 @@ import com.jzg.commons.entity.agreement.dispatch.dto.PtlAgreementDispatchRulesAt
 import com.jzg.commons.entity.agreement.dispatch.vo.PtlAgreementDispatchQuery;
 import com.jzg.commons.entity.agreement.dispatch.vo.PtlAgreementDispatchVo;
 import com.jzg.commons.entity.agreement.po.PtlAgreementAttribution;
-import com.jzg.commons.entity.po.PtlAgreement;
-import com.jzg.commons.entity.po.PtlAgreementUndwrtRulesAttr;
-import com.jzg.commons.entity.po.PtlAgreementUndwrtRulesDictLabal;
-import com.jzg.commons.entity.po.SysDict;
+import com.jzg.commons.entity.po.*;
+import com.jzg.commons.util.StringUtils;
 import com.jzg.commons.util.idgen.IdGenerate;
 import com.jzg.organization.client.EsmInsCompanyClient;
 import com.jzg.organization.mapper.PtlAgreementDispatchActionMapper;
@@ -29,10 +27,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -48,27 +43,22 @@ public class PtlAgreementDispatchServiceImpl extends ServiceImpl<PtlAgreementDis
 
     @Autowired
     PtlAgreementDispatchRulesAttrLinkMapper rulesAttrLinkMapper;
-
-    @Autowired
-    PtlAgreementDispatchActionMapper actionMapper;
-
     @Autowired
     PtlAgreementUndwrtRulesAttrService ptlAgreementUndwrtRulesAttrService;
-
     @Autowired
     PtlAgreementUndwrtRulesDictLabalService ptlAgreementUndwrtRulesDictLabalService;
-
+    @Autowired
+    private PtlAreaLicenseService ptlAreaLicenseService;
     @Autowired
     SysDictService sysDictService;
-
     @Autowired
     PtlAgreementService ptlAgreementService;
-
     @Autowired
     EsmInsCompanyClient esmInsCompanyClient;
-
     @Autowired
     PtlAgreementDispatchAfterActionMapper afterActionMapper;
+    @Autowired
+    PtlAgreementDispatchActionMapper actionMapper;
     @Override
     @Transactional
     public String addAgreementDispatch(PtlAgreementDispatchVo.DispatchVo ptlAgreementDispatchVo) {
@@ -134,10 +124,14 @@ public class PtlAgreementDispatchServiceImpl extends ServiceImpl<PtlAgreementDis
             // 查询保司所有的规则属性 然后进行分组
             List<PtlAgreementDispatchRulesAttrLink> ptlAgreementDispatchRulesAttrLinks = rulesAttrLinkMapper.selectList(new LambdaQueryWrapper<PtlAgreementDispatchRulesAttrLink>()
                     .in(PtlAgreementDispatchRulesAttrLink::getDispatchId, dispatchIds));
-
+            ptlAgreementDispatchRulesAttrLinks = ptlAgreementDispatchRulesAttrLinks.stream().peek(action->{
+                String min = action.getMin();
+                if(StringUtils.isNotEmpty(min)){
+                    action.setMinArray(Arrays.asList(min.split(",")));
+                }
+            }).toList();
             // 获取所有保司的动作
             List<PtlAgreementDispatchAction> ptlAgreementDispatchActions = actionMapper.getActions(dispatchIds);
-
             // 获取保司的报价失败之后的动作
             List<PtlAgreementDispatchAfterAction> ptlAgreementDispatchAfterActions = afterActionMapper.getAfterActions(ptlAgreementDispatchQuery.getCompanyId());
             int index = 1;
@@ -145,6 +139,15 @@ public class PtlAgreementDispatchServiceImpl extends ServiceImpl<PtlAgreementDis
             List<PtlAgreementUndwrtRulesDictLabal> ptlAgreementUndwrtRulesDictLabals = baseMapper.queryAllDictLabal();
             Map<String, String> dictLabalId2Name = ptlAgreementUndwrtRulesDictLabals.stream()
                     .collect(Collectors.toMap(PtlAgreementUndwrtRulesDictLabal::getIdStr, PtlAgreementUndwrtRulesDictLabal::getName));
+            Map<String, PtlAreaLicense> areaLicenseMap = ptlAreaLicenseService.queryAllAreaLicenseMap();
+
+            Map<String,String> operatorMap = new HashMap<>();
+            operatorMap.put("1","包含");
+            operatorMap.put("2","小于");
+            operatorMap.put("3","小于等于");
+            operatorMap.put("4","大于");
+            operatorMap.put("5","大于等于");
+            operatorMap.put("","未知");
             for(PtlAgreementDispatch dispatch : ptlAgreementDispatches){
                 if(dispatch.getDispatchName().isEmpty()){
                     dispatch.setDispatchName("规则" + index);
@@ -153,41 +156,33 @@ public class PtlAgreementDispatchServiceImpl extends ServiceImpl<PtlAgreementDis
                 List<PtlAgreementDispatchRulesAttrLink> attrLinks = ptlAgreementDispatchRulesAttrLinks.stream().filter(x -> x.getDispatchId().equals(dispatch.getId())).collect(Collectors.toList());
                 List<PtlAgreementDispatchAction> actions = ptlAgreementDispatchActions.stream().filter(x -> x.getDispatchId().equals(dispatch.getId())).collect(Collectors.toList());
                 for(PtlAgreementDispatchRulesAttrLink attrlink : attrLinks){
-                    if (attrlink.getOperator() != null) {
-                        if (attrlink.getOperator().equals("1")) {
-                            attrlink.setOperatorDesc("包含");
-                        }
-                        if (attrlink.getOperator().equals("2")) {
-                            attrlink.setOperatorDesc("小于");
-                        }
-                        if (attrlink.getOperator().equals("3")) {
-                            attrlink.setOperatorDesc("小于等于");
-                        }
-                        if (attrlink.getOperator().equals("4")) {
-                            attrlink.setOperatorDesc("大于");
-                        }
-                        if (attrlink.getOperator().equals("5")) {
-                            attrlink.setOperatorDesc("大于等于");
-                        }
+                    log.info("attrlink=[{}]", JSONUtil.toJsonStr(attrlink));
+                    attrlink.setOperatorDesc(operatorMap.get(Objects.toString(attrlink.getOperator(),"")));
+                    if("LicenseNo".equals(attrlink.getAttrCode())){
+                        String minName = ptlAreaLicenseService.convertAreaNumber2License(areaLicenseMap, attrlink.getMin());
+                        attrlink.setMinName(minName);
                     }else{
-                        attrlink.setOperatorDesc("未知");
+                        String minName = dictLabalId2Name.getOrDefault(attrlink.getMin(),attrlink.getMin());
+                        String maxName = dictLabalId2Name.getOrDefault(attrlink.getMax(),attrlink.getMax());
+                        attrlink.setMinName(minName);
+                        attrlink.setMaxName(maxName);
                     }
-                    String minName = dictLabalId2Name.getOrDefault(attrlink.getMin(),attrlink.getMin());
-                    String maxName = dictLabalId2Name.getOrDefault(attrlink.getMax(),attrlink.getMax());
-                    attrlink.setMinName(minName);
-                    attrlink.setMaxName(maxName);
                     PtlAgreementUndwrtRulesAttr undwrtRuleAttrByAttrCode = ptlAgreementUndwrtRulesAttrService.getUndwrtRuleAttrByAttrCode(attrlink.getAttrCode());
-                    if(undwrtRuleAttrByAttrCode != null && undwrtRuleAttrByAttrCode.getDictId() != null){
+                    if(undwrtRuleAttrByAttrCode != null){
                         attrlink.setAttrCodeName(undwrtRuleAttrByAttrCode.getAttrName());
-                        List<PtlAgreementUndwrtRulesDictLabal> dictLabelsByTypeCode = ptlAgreementUndwrtRulesDictLabalService.getDictLabelsByTypeCode(undwrtRuleAttrByAttrCode.getDictId());
-                        PtlAgreementUndwrtRulesDictLabal ptlAgreementUndwrtRulesDictLabal = dictLabelsByTypeCode.stream().filter(x -> x.getCode().equals(attrlink.getMin())).findFirst().orElse(null);
-                        if(ptlAgreementUndwrtRulesDictLabal != null){
-                            if(attrlink.getAttrDesc() == null){
-                                attrlink.setAttrDesc(new ArrayList<>());
+                        if(undwrtRuleAttrByAttrCode.getDictId() != null){
+                            attrlink.setAttrCodeName(undwrtRuleAttrByAttrCode.getAttrName());
+                            List<PtlAgreementUndwrtRulesDictLabal> dictLabelsByTypeCode = ptlAgreementUndwrtRulesDictLabalService.getDictLabelsByTypeCode(undwrtRuleAttrByAttrCode.getDictId());
+                            PtlAgreementUndwrtRulesDictLabal ptlAgreementUndwrtRulesDictLabal = dictLabelsByTypeCode.stream().filter(x -> x.getCode().equals(attrlink.getMin())).findFirst().orElse(null);
+                            if(ptlAgreementUndwrtRulesDictLabal != null){
+                                if(attrlink.getAttrDesc() == null){
+                                    attrlink.setAttrDesc(new ArrayList<>());
+                                }
+                                attrlink.getAttrDesc().add(ptlAgreementUndwrtRulesDictLabal.getName());
                             }
-                            attrlink.getAttrDesc().add(ptlAgreementUndwrtRulesDictLabal.getName());
                         }
                     }
+                    log.info("attrlink数据填充完成:attrlink=[{}]",JSONUtil.toJsonStr(attrlink));
                 }
 
                 for(PtlAgreementDispatchAction action : actions){

+ 76 - 0
tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlAreaLicenseServiceImpl.java

@@ -1,18 +1,26 @@
 package com.jzg.organization.service.impl;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.jzg.commons.entity.po.PtlAreaLicense;
 import com.jzg.commons.util.StringUtils;
 import com.jzg.organization.mapper.PtlAreaLicenseMapper;
 import com.jzg.organization.service.PtlAreaLicenseService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
+import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 @Service
 public class PtlAreaLicenseServiceImpl extends ServiceImpl<PtlAreaLicenseMapper, PtlAreaLicense>
         implements PtlAreaLicenseService {
 
+    private static final Logger log = LoggerFactory.getLogger(PtlAreaLicenseServiceImpl.class);
 
     @Override
     public List<PtlAreaLicense> getByParentNumber(String parentNumber) {
@@ -21,4 +29,72 @@ public class PtlAreaLicenseServiceImpl extends ServiceImpl<PtlAreaLicenseMapper,
         }
         return lambdaQuery().eq(PtlAreaLicense::getParentNumber, parentNumber).list();
     }
+
+    /**
+     * 查看车牌号和所有地区的对应关系
+     *
+     * @return List<PtlAreaLicense> 所有车牌号和地区的对应关系
+     * @author lipf
+     * @date 2026/5/21 9:40
+     */
+    @Override
+    public List<PtlAreaLicense> queryAllAreaLicense() {
+        log.info("查询所有车牌前缀和地区的对应关系: ");
+        List<PtlAreaLicense> ptlAreaLicenses = baseMapper.selectList(null);
+        log.info("查询所有车牌前缀和地区的对应关系。 查询出[{}]条记录", CollUtil.size(ptlAreaLicenses));
+        return ptlAreaLicenses;
+    }
+
+    /**
+     * 查看车牌号和所有地区的对应关系
+     *
+     * @return Map<String,PtlAreaLicense> key是areaNumber, value是地区和车牌前缀的对应关系
+     * @author lipf
+     * @date 2026/5/21 9:45
+     */
+    @Override
+    public Map<String, PtlAreaLicense> queryAllAreaLicenseMap() {
+        List<PtlAreaLicense> ptlAreaLicenses = this.queryAllAreaLicense();
+        if(CollUtil.isEmpty(ptlAreaLicenses)){
+            return Map.of();
+        }
+        return ptlAreaLicenses.stream()
+                .filter(action-> StrUtil.isNotEmpty(action.getAreaNumber()))
+                .collect(Collectors.toMap(PtlAreaLicense::getAreaNumber,
+                        action->action,
+                        (oldItem, newItem)->newItem));
+
+    }
+
+    /**
+     * 将地区编码转换为对应的车牌号
+     *
+     * @param areaLicenseMap 地区编码和车牌对应集
+     * @param areaNumbers    地区编码,支持多个拼接,例如1401,1402,1403
+     * @return String 地区车牌号,例如晋A,晋B,晋C
+     * @author lipf
+     * @date 2026/5/21 9:53
+     */
+    @Override
+    public String convertAreaNumber2License(Map<String, PtlAreaLicense> areaLicenseMap, String areaNumbers) {
+        if(StrUtil.isEmpty(areaNumbers)){
+            return StrUtil.EMPTY;
+        }
+        if(CollUtil.isEmpty(areaLicenseMap)){
+            return areaNumbers;
+        }
+        String[] split = areaNumbers.split(",");
+        List<String> licenses =  new ArrayList<>();
+        for (String s : split) {
+            PtlAreaLicense ptlAreaLicense = areaLicenseMap.getOrDefault(s, null);
+            if(ptlAreaLicense != null){
+                licenses.add(ptlAreaLicense.getLicense());
+            }else{
+                licenses.add(s);
+            }
+        }
+        String collect = String.join(",", licenses);
+        log.info("地区编码[{}]转换后的车牌编码是[{}]",areaNumbers,collect);
+        return collect;
+    }
 }

+ 2 - 2
tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlSchemeServiceImpl.java

@@ -127,7 +127,7 @@ public class PtlSchemeServiceImpl extends ServiceImpl<PtlSchemeMapper, PtlScheme
         //商业险信息
         List<PtlSchemeInsurance> ptlSchemeInsuranceList = ptlSchemeSaveVo.getPtlSchemeInsuranceList();
         //清空商业险信息
-        cleanInsurance(ptlSchemeInfoList);
+        this.cleanInsurance(ptlSchemeInfoList);
         ptlSchemeInsuranceMapper.insertOrUpdate(ptlSchemeInsuranceList);
 
         //驾意险信息
@@ -165,7 +165,7 @@ public class PtlSchemeServiceImpl extends ServiceImpl<PtlSchemeMapper, PtlScheme
      * @param ptlSchemeInfoList
      */
     private void cleanInsurance(List<PtlSchemeInfo> ptlSchemeInfoList) {
-        List<String> ids = ptlSchemeInfoList.stream().map(info -> info.getId()).collect(Collectors.toList());
+        List<String> ids = ptlSchemeInfoList.stream().map(PtlSchemeInfo::getId).collect(Collectors.toList());
         ptlSchemeInsuranceMapper.delete(new LambdaQueryWrapper<PtlSchemeInsurance>()
                 .in(PtlSchemeInsurance::getSchemeInfoId, ids));
     }

+ 138 - 42
tenant/organization/src/main/java/com/jzg/organization/service/impl/ReceivableServiceImpl.java

@@ -397,6 +397,15 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
      */
     List<InsPlyIncome> fillOtherInfo(List<InsPlyIncome> records){
         if(CollUtil.isNotEmpty(records)){
+            List<String> incomeIds = records.stream().map(InsPlyIncome::getId).toList();
+            InvoicingVo invoicingVo = new InvoicingVo();
+            invoicingVo.setIncomeIds(incomeIds);
+            List<InsPlyIncomeInvoiceLink> links = baseMapper.queryIncomeBindInvoice(invoicingVo);
+            Map<String, String> income2InvoceIdMap = links.stream()
+                    .filter(action -> StrUtil.isNotEmpty(action.getIncomeId()))
+                    .collect(Collectors.toMap(InsPlyIncomeInvoiceLink::getIncomeId, InsPlyIncomeInvoiceLink::getInvoiceId, (oleItem, newItem) -> oleItem));
+
+
             Map<String, String> typeAttrMaps = sysUserJzgInfoSalesmanService.queryYwyTypeAttrMap();
             records.forEach(insPlyIncome -> {
                 if("0".equals(insPlyIncome.getSettlementStatus())){
@@ -413,6 +422,10 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
                 // 费用信息
                 List<InsFeeOrders> insFeeOrderByOrderNo = insFeeOrdersClient.getInsFeeOrderByOrderNo(insPlyIncome.getOrderNo());
                 insPlyIncome.setInsFeeOrders(CollUtil.getFirst(insFeeOrderByOrderNo));
+
+                String invoiceId = income2InvoceIdMap.get(insPlyIncome.getId());
+                insPlyIncome.setInvoiceStatusName(StrUtil.isEmpty(invoiceId)? "未开票":"已开票");
+                insPlyIncome.setInvoiceId(invoiceId);
             });
         }
         return records;
@@ -423,65 +436,147 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
         return baseMapper.getReceivableList(receivableQueryVo);
     }
 
+
+    /**
+     * 查询订单绑定的发票信息
+     *
+     * @param invoicingVo
+     * @return List<String> 订单绑定的发票号
+     * @author lipf
+     * @date 2026/5/21 11:59
+     */
+    @Override
+    public List<String> queryIncomeBindInvoice(InvoicingVo invoicingVo) {
+        log.info("查询订单绑定的发票信息:invoicingVo=[{}]", JSONUtil.toJsonStr(invoicingVo));
+        List<InsPlyIncomeInvoiceLink> links = baseMapper.queryIncomeBindInvoice(invoicingVo);
+        List<String> invoiceIds = links.stream().map(InsPlyIncomeInvoiceLink::getInvoiceId).distinct().toList();
+        log.info("查询订单绑定的发票信息:invoicingVo=[{}].invoiceIds=[{}]", JSONUtil.toJsonStr(invoicingVo), JSONUtil.toJsonStr(invoiceIds));
+        return invoiceIds;
+    }
+
+    /**
+     * 开票重复校验
+     * 功能:DB+Redis双重校验,防止并发重复开票
+     *
+     * @param invoicingVo 开票参数
+     * @return true=允许开票,false=禁止开票
+     */
     @Override
     public boolean invoicingCheck(InvoicingVo invoicingVo) {
+        // 1. 基础参数校验
+        if (invoicingVo == null || CollUtil.isEmpty(invoicingVo.getIncomeIds()) || StrUtil.isBlank(invoicingVo.getInvoiceType())) {
+            log.error("开票校验参数不能为空");
+            return false;
+        }
+
+        // 2. 数据库校验:是否已存在开票记录
         Integer count = baseMapper.invoicingCheck(invoicingVo);
-        RKeys keys = redissonClient.getKeys();
-        Iterable<String> allKeys = null;
-        String redisKey = null;
-        if (invoicingVo.getInvoiceType().equals("1")) {
-            redisKey = CAR_INVOICING_COMMISSION_LOCK;
-        } else if (invoicingVo.getInvoiceType().equals("2")) {
-            redisKey = CAR_INVOICING_OTHER_LOCK;
-        } else if (invoicingVo.getInvoiceType().equals("3")) {
-            redisKey = JY_INVOICING_COMMISSION_LOCK;
-        } else if (invoicingVo.getInvoiceType().equals("4")) {
-            redisKey = JY_INVOICING_OTHER_LOCK;
+        if (count > 0) {
+            log.info("数据库已存在开票记录,直接禁止");
+            return false;
         }
-        allKeys = keys.getKeysByPattern(redisKey + "*");
-        //提取所有redis的key  然后遍历是否存在重复的id
-        for (String key : allKeys) {
-            // 过滤掉自己的redis key
-            if (!key.equals(key + baseController.getUserName())) {
-                RBucket<Object> bucket = redissonClient.getBucket(key);
-                String incomeIds = bucket.get().toString();
-                incomeIds = incomeIds.substring(1, incomeIds.length() - 1);
-                List<String> incomeIdList = Arrays.stream(incomeIds.split(",")).collect(Collectors.toList());
-                boolean hasDuplicate = invoicingVo.getIncomeIds().stream().anyMatch(incomeIdList::contains);
-                if (hasDuplicate) {
-                    return false;
-                }
+
+        // 3. 根据开票类型获取Redis锁前缀
+        String redisKeyPrefix = switch (invoicingVo.getInvoiceType()) {
+            case "1" -> CAR_INVOICING_COMMISSION_LOCK;
+            case "2" -> CAR_INVOICING_OTHER_LOCK;
+            case "3" -> JY_INVOICING_COMMISSION_LOCK;
+            case "4" -> JY_INVOICING_OTHER_LOCK;
+            default -> throw new SystemException("不支持的开票类型");
+        };
+
+        // 4. 当前用户的Redis Key
+        String currentUserName = baseController.getUserName();
+        String currentRedisKey = redisKeyPrefix + currentUserName;
+
+        // 5. Redis校验:同类型下,是否有其他用户占用了相同incomeId
+        // 把锁key存入同一个set,避免使用keys命令
+        RKeys keys = redissonClient.getKeys();
+        Iterable<String> allLockKeys = keys.getKeysByPattern(redisKeyPrefix + "*");
+
+        for (String lockKey : allLockKeys) {
+            // 正确过滤自己的key
+            if (currentRedisKey.equals(lockKey)) {
+                continue;
+            }
+
+            // 安全获取缓存值
+            RBucket<Object> bucket = redissonClient.getBucket(lockKey);
+            Object cacheObj = bucket.get();
+            if (cacheObj == null) {
+                continue;
             }
-        }
 
-        if (count == 0) {
-            // 设置缓存
-            RBucket<Object> bucket = redissonClient.getBucket(redisKey + baseController.getUserName());
-            bucket.set(invoicingVo.getIncomeIds(), 10, TimeUnit.MINUTES);
+            // 解析缓存中的incomeId集合
+            List<String> cacheIncomeIds = this.parseIncomeIdsFromRedis(cacheObj.toString());
+            // 校验重复
+            boolean duplicate = invoicingVo.getIncomeIds().stream().anyMatch(cacheIncomeIds::contains);
+            if (duplicate) {
+                log.info("Redis校验重复,lockKey:{}", lockKey);
+                return false;
+            }
         }
 
-        return count == 0;
+        // 6. 校验通过,存入Redis锁(10分钟自动过期)
+        RBucket<Object> bucket = redissonClient.getBucket(currentRedisKey);
+        bucket.set(invoicingVo.getIncomeIds(), 10, TimeUnit.MINUTES);
+        log.info("开票校验通过,Redis加锁成功,key:{}", currentRedisKey);
+
+        return true;
+    }
+
+    /**
+     * 从Redis字符串解析收入ID集合(安全解析,防止异常)
+     */
+    private List<String> parseIncomeIdsFromRedis(String incomeIdsStr) {
+        try {
+            if (StrUtil.isBlank(incomeIdsStr) || !incomeIdsStr.startsWith("[") || !incomeIdsStr.endsWith("]")) {
+                return Collections.emptyList();
+            }
+            String content = incomeIdsStr.substring(1, incomeIdsStr.length() - 1).trim();
+            if (StrUtil.isBlank(content)) {
+                return Collections.emptyList();
+            }
+            return Arrays.stream(content.split(","))
+                    .map(String::trim)
+                    .collect(Collectors.toList());
+        } catch (Exception e) {
+            log.error("解析Redis收入ID异常", e);
+            return Collections.emptyList();
+        }
     }
 
     @Override
     public BigDecimal getReceivableAmount(InvoicingVo invoicingVo) {
         String invoiceType = invoicingVo.getInvoiceType();
+        List<String> orderNos = invoicingVo.getOrderNos();
+        orderNos = orderNos.stream()
+                .filter(s -> s != null && !s.trim().isEmpty())
+                .map(String::trim)
+                .distinct() // 可选,去重
+                .collect(Collectors.toList());
+        // 修改后(返回总手续费 = 交强险+商业险+驾意险 手续费之和)
+        Map<String, Object> map = baseMapper.getJqSumReceivable(orderNos);
+        BigDecimal jqCommissionPremium = (BigDecimal) Optional.ofNullable(map.get("jqCommissionPremium")).orElse(BigDecimal.ZERO);
+        BigDecimal syCommissionPremium = (BigDecimal) Optional.ofNullable(map.get("syCommissionPremium")).orElse(BigDecimal.ZERO);
+        BigDecimal jyCommissionPremium = (BigDecimal) Optional.ofNullable(map.get("jyCommissionPremium")).orElse(BigDecimal.ZERO);
+        BigDecimal jqFollowPremium = (BigDecimal) Optional.ofNullable(map.get("jqFollowPremium")).orElse(BigDecimal.ZERO);
+        BigDecimal syFollowPremium = (BigDecimal) Optional.ofNullable(map.get("syFollowPremium")).orElse(BigDecimal.ZERO);
+        BigDecimal jyFollowPremium = (BigDecimal) Optional.ofNullable(map.get("jyFollowPremium")).orElse(BigDecimal.ZERO);
+
         // 私有手续费 应收金额
+        // 交强的总手续费(jq_commission_premium) + 商业的总手续费(sy_commission_premium)
         if (invoiceType.equals("1")) {
-            List<String> orderNos = invoicingVo.getOrderNos();
-            orderNos = orderNos.stream()
-                    .filter(s -> s != null && !s.trim().isEmpty())
-                    .map(String::trim)
-                    .distinct() // 可选,去重
-                    .collect(Collectors.toList());
-            String jqSumReceivable = baseMapper.getJqSumReceivable(orderNos);
-            return new BigDecimal(jqSumReceivable);
+            return jqCommissionPremium.add(syCommissionPremium);
         } else if (invoiceType.equals("2")) {
-
+            // 交强的总跟单费(jq_follow_premium) + 商业的总跟单费(sy_follow_premium)
+            return jqFollowPremium.add(syFollowPremium);
         } else if (invoiceType.equals("3")) {
-
+            // 驾意险的总手续费(jy_commission_premium)
+            return jyCommissionPremium;
         } else if (invoiceType.equals("4")) {
-
+            // 驾意险的总跟单费(jy_follow_premium)
+            return jyFollowPremium;
         }
         return null;
     }
@@ -522,11 +617,12 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
                 link.setId(IdGenerate.nextId());
                 link.setInvoiceId(invoice.getId());
                 link.setIncomeId(incomeId);
+                link.setInvoiceType(invoicingVo.getInvoiceType());
                 invoicingLinkList.add(link);
             });
             insPlyIncomeInvoiceLinkMapper.insert(invoicingLinkList);
             result.setInvoiceId(invoice.getId());
-            result.setSumPrice(invoicingVo.getReceivablePremium().toString());
+            result.setSumPrice(null != invoicingVo.getReceivablePremium() ? invoicingVo.getReceivablePremium().toString() : null);
             return result;
         } catch (Exception e) {
             log.info("开票异常.invoicingVo=[{}]",JSONUtil.toJsonStr(invoicingVo), e);

+ 7 - 11
tenant/organization/src/main/resources/mapper/PtlSchemeMapper.xml

@@ -164,16 +164,12 @@
             psidi.selected_status
         FROM
             ptl_scheme ps
-                INNER JOIN ptl_scheme_info psi ON ps.id = psi.scheme_id
-                INNER JOIN ptl_scheme_insurance_driving_intention psidi ON psidi.scheme_info_id = psi.id
-                INNER JOIN jyx_config jc ON psidi.driving_intention_id = jc.id
-                INNER JOIN jyx_config jc1 on jc.parent_id = jc1.id
-        WHERE
-            ps.company_id = #{companyId}
-        AND
-            ps.product_id = #{productId}
+                left JOIN ptl_scheme_info psi ON ps.id = psi.scheme_id
+                left JOIN ptl_scheme_insurance_driving_intention psidi ON psidi.scheme_info_id = psi.id
+                left JOIN jyx_config jc ON psidi.driving_intention_id = jc.id
+                left JOIN jyx_config jc1 on jc.parent_id = jc1.id
+        WHERE  ps.company_id = #{companyId}
+        AND ps.product_id = #{productId}
+        and psidi.id is not null
     </select>
-
-
-
 </mapper>

+ 52 - 23
tenant/organization/src/main/resources/mapper/ReceivableMapper.xml

@@ -266,6 +266,7 @@
                 #{id}
             </foreach>
         </if>
+        ORDER BY ipi.create_time DESC
     </select>
     <select id="getReceivablePage" resultType="com.jzg.commons.entity.finance.po.InsPlyIncome">
         <include refid="query"/>
@@ -356,6 +357,7 @@
         <if test="receivableQueryVo.syStartDate != null and receivableQueryVo.syStartDate != ''">
             AND ior2.start_date between #{receivableQueryVo.syStartDate} and  #{receivableQueryVo.syStartDate}
         </if>
+        ORDER BY ipi.create_time DESC
     </select>
 
 
@@ -426,6 +428,7 @@
         <if test="receivableQueryVo.agreementType != null and receivableQueryVo.agreementType != ''">
             AND ipi.agreement_type = #{receivableQueryVo.agreementType}
         </if>
+        ORDER BY ipi.create_time DESC
     </select>
 
     <select id="getSuperviseJyExcelDtos" resultType="com.jzg.commons.entity.finance.dto.ExportSuperviseJyExcelDto">
@@ -495,6 +498,7 @@
         <if test="receivableQueryVo.agreementType != null and receivableQueryVo.agreementType != ''">
             AND ipi.agreement_type = #{receivableQueryVo.agreementType}
         </if>
+        ORDER BY ipi.create_time DESC
     </select>
 
     <select id="superviseSettlementExcelDtos" resultType="com.jzg.commons.entity.finance.dto.ExportSuperviseSettlementExcelDto">
@@ -503,13 +507,13 @@
         ipiis.invoice_id as invoiceId,
         io.company_id,
         io.company_name,
-        ipii.invoice_type as invoiceType,
-        ipii.invoice_party as invoiceParty,
-        ipii.tax_point as taxPoint,
-        ipiis.actual_received_amount as actualReceivedAmount,
-        ipiis.receive_payment_date as receivePaymentDate,
-        ipiis.create_by as createBy,
-        ipiis.create_time as createTime
+        ipii.invoice_type,
+        ipii.invoice_party,
+        ipii.tax_point,
+        ipiis.actual_received_amount,
+        ipiis.receive_payment_date,
+        ipiis.create_by ,
+        ipiis.create_time
         FROM
         ins_ply_income_invoice_settlement ipiis
         LEFT JOIN ins_ply_income_invoice ipii ON ipii.id = ipiis.invoice_id
@@ -564,6 +568,7 @@
         <if test="settlementQueryVo.settlementId != null and settlementQueryVo.settlementId != ''">
             AND ipiis.id = #{settlementQueryVo.settlementId}
         </if>
+        order by ipiis.create_time desc
     </select>
 
 <!--    <select id="getSuperviseSettlementExcelDtos" resultType="com.jzg.commons.entity.finance.dto.ExportSuperviseSettlementExcelDto">-->
@@ -725,6 +730,7 @@
         <if test="settlementQueryVo.agreementType != null and settlementQueryVo.agreementType != ''">
             AND ipi.agreement_type = #{settlementQueryVo.agreementType}
         </if>
+        ORDER BY ipi.create_time DESC
     </select>
 
     <select id="getOtherExcelDtos" resultType="com.jzg.commons.entity.finance.dto.ExportOtherExcelDto">
@@ -784,6 +790,7 @@
         <if test="receivableQueryVo.signingTimeStart != null and receivableQueryVo.signingTimeStart != ''">
             and ipi.signing_time between #{receivableQueryVo.signingTimeStart} and #{receivableQueryVo.signingTimeEnd}
         </if>
+        ORDER BY ipi.create_time DESC
     </select>
 
     <select id="getOtherJyExcelDtos" resultType="com.jzg.commons.entity.finance.dto.ExportOtherJyExcelDto">
@@ -838,6 +845,7 @@
         <if test="receivableQueryVo.signingTimeStart != null and receivableQueryVo.signingTimeStart != ''">
             and ipi.signing_time between #{receivableQueryVo.signingTimeStart} and #{receivableQueryVo.signingTimeEnd}
         </if>
+        ORDER BY ipi.create_time DESC
     </select>
 
     <select id="getOtherSettlementExcelDtos" resultType="com.jzg.commons.entity.finance.dto.ExportOtherSettlementExcelDto">
@@ -1020,25 +1028,46 @@
             eic.id
     </select>
 
-    <select id="invoicingCheck" resultType="Integer">
-        SELECT
-            count(id) as count
-        FROM
-            ins_ply_income_invoice_link
+    <select id="invoicingCheck" resultType="java.lang.Integer">
+        SELECT count(id) AS count
+        FROM ins_ply_income_invoice_link
+        <where>
+            <if test="invoicingVo.incomeIds != null and invoicingVo.incomeIds.size > 0">
+                AND income_id IN
+                <foreach collection="invoicingVo.incomeIds"
+                         item="id" open="(" separator="," close=")">
+                    #{id}
+                </foreach>
+            </if>
+            <if test="invoicingVo.invoiceType != null and invoicingVo.invoiceType != ''">
+                AND invoice_type = #{invoicingVo.invoiceType}
+            </if>
+        </where>
+    </select>
+
+    <!-- 查询订单绑定的发票信息 lipf 2026年5月21日11:56:19 -->
+    <select id="queryIncomeBindInvoice" resultType="com.jzg.commons.entity.finance.po.InsPlyIncomeInvoiceLink">
+        SELECT  *  FROM
+        ins_ply_income_invoice_link
         where
-            income_id IN
-            <foreach collection="invoicingVo.incomeIds" item="id" open="(" separator="," close=")">
-                #{id}
-            </foreach>
+        income_id IN
+        <foreach collection="invoicingVo.incomeIds" item="id" open="(" separator="," close=")">
+            #{id}
+        </foreach>
     </select>
 
-    <select id="getJqSumReceivable" resultType="String">
+    <select id="getJqSumReceivable" resultType="java.util.Map">
         SELECT
-            sum( jq_commission_premium ) AS receivable_premium
+            sum( jq_commission_premium ) AS jqCommissionPremium,
+            sum( sy_commission_premium ) AS syCommissionPremium,
+            sum( jy_commission_premium ) AS jyCommissionPremium,
+            sum( jq_follow_premium ) AS jqFollowPremium,
+            sum( sy_follow_premium ) AS syFollowPremium,
+            sum( jy_follow_premium ) AS jyFollowPremium
         FROM
-            ins_fee_orders
+        ins_fee_orders
         WHERE
-            order_no IN
+        order_no IN
         <foreach collection="orderNos" item="id" open="(" separator="," close=")">
             #{id}
         </foreach>
@@ -1098,6 +1127,7 @@
             ipii.invoice_type,
             ipii.company_id,
             ipii.invoice_party
+        ORDER BY ipii.create_time DESC
     </select>
 
     <!-- 基础结果集映射 -->
@@ -1293,7 +1323,7 @@
         SELECT
             eic.id AS companyId,
             eic.name AS companyName,
-            COALESCE(SUM(ifo.jq_commission_premium + ifo.sy_commission_premium + ifo.jy_commission_premium), 0) AS superviseAmount
+        SUM(COALESCE(ifo.jq_commission_premium, 0) + COALESCE(ifo.sy_commission_premium, 0) + COALESCE(ifo.jy_commission_premium, 0)) AS superviseAmount
         FROM
             esm_ins_company eic
                 LEFT JOIN
@@ -1302,8 +1332,7 @@
             ins_fee_orders ifo ON pa.id = ifo.agreement_id
         GROUP BY
             eic.id, eic.name
-        ORDER BY
-            eic.id;
+        ORDER BY  eic.name
     </select>
 
     <select id="getReceiverSettlementReport" resultType="com.jzg.commons.entity.finance.dto.ReceiverSettlementReportDto">