chenxiaofei пре 1 месец
родитељ
комит
99a320bfb6

+ 39 - 0
sckw-common/sckw-common-core/src/main/java/com/sckw/core/model/enums/LogisticsTransportBizTypeEnum.java

@@ -0,0 +1,39 @@
+package com.sckw.core.model.enums;
+
+import lombok.Getter;
+
+/**
+ * 物流合同业务类型(新增页「合同类型」)
+ */
+@Getter
+public enum LogisticsTransportBizTypeEnum {
+
+    /** 贸易运输:沿用原系统逻辑 */
+    TRADE_TRANSPORT(1, "贸易运输"),
+    /** 原矿转运:不录入运价,使用允许误差做装卸货量比对 */
+    RAW_ORE_TRANSFER(2, "原矿转运");
+
+    private final int code;
+    private final String label;
+
+    LogisticsTransportBizTypeEnum(int code, String label) {
+        this.code = code;
+        this.label = label;
+    }
+
+    public static String getLabelByCode(Integer code) {
+        if (code == null) {
+            return null;
+        }
+        for (LogisticsTransportBizTypeEnum e : values()) {
+            if (e.code == code) {
+                return e.label;
+            }
+        }
+        return null;
+    }
+
+    public static boolean isRawOreTransfer(Integer code) {
+        return code != null && code == RAW_ORE_TRANSFER.code;
+    }
+}

+ 12 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/entity/KwcContractLogistics.java

@@ -147,4 +147,16 @@ public class KwcContractLogistics implements Serializable {
     @TableField("common_price")
     @TableField("common_price")
     private BigDecimal commonPrice;
     private BigDecimal commonPrice;
 
 
+    /**
+     * 业务合同类型(1贸易运输 2原矿转运)
+     */
+    @TableField("transport_biz_type")
+    private Integer transportBizType;
+
+    /**
+     * 允许误差(千分比数值,如 5 表示 5‰)
+     */
+    @TableField("allowed_error")
+    private BigDecimal allowedError;
+
 }
 }

+ 13 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/vo/req/LogisticListReq.java

@@ -151,6 +151,19 @@ public class LogisticListReq implements Serializable {
         @JsonFormat(pattern="yyyy-MM-dd", timezone = "GMT+8")
         @JsonFormat(pattern="yyyy-MM-dd", timezone = "GMT+8")
         @Schema(description = "生效时间")
         @Schema(description = "生效时间")
         private Date startTime;
         private Date startTime;
+
+        /**
+         * 业务合同类型(1贸易运输 2原矿转运),未传时后端按贸易运输处理
+         */
+        @Schema(description = "业务合同类型 1-贸易运输 2-原矿转运", allowableValues = {"1", "2"})
+        private Integer transportBizType;
+
+        /**
+         * 允许误差(千分比数值,如 5 表示 5‰);原矿转运时必填
+         */
+        @Schema(description = "允许误差(千分比),原矿转运必填")
+        private BigDecimal allowedError;
+
         /**
         /**
          * 通用价格
          * 通用价格
          */
          */

+ 5 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/vo/req/QueryLogisticListReq.java

@@ -43,6 +43,11 @@ public class QueryLogisticListReq extends PageReq implements Serializable {
      * 状态
      * 状态
      */
      */
     private String status;
     private String status;
+    /**
+     * 合同类型:1托运合同 2承运合同(相对当前查看企业)
+     */
+    @Schema(description = "合同类型:1托运合同 2承运合同")
+    private Integer contractType;
     /**
     /**
      * 企业id
      * 企业id
      */
      */

+ 17 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/vo/res/QueryLogisticDetailResp.java

@@ -159,6 +159,23 @@ public class QueryLogisticDetailResp implements Serializable {
         @Schema(description = "通用价格")
         @Schema(description = "通用价格")
         private BigDecimal commonPrice;
         private BigDecimal commonPrice;
 
 
+        /**
+         * 业务合同类型 1贸易运输 2原矿转运
+         */
+        @Schema(description = "业务合同类型 1-贸易运输 2-原矿转运")
+        private Integer transportBizType;
+        /**
+         * 业务合同类型描述
+         */
+        @Schema(description = "业务合同类型描述")
+        private String transportBizTypeDesc;
+
+        /**
+         * 允许误差(千分比数值,如 5 表示 5‰)
+         */
+        @Schema(description = "允许误差(千分比)")
+        private BigDecimal allowedError;
+
         /**
         /**
          * 合同状态
          * 合同状态
          */
          */

+ 10 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/vo/res/QueryLogisticListResp.java

@@ -54,6 +54,16 @@ public class QueryLogisticListResp implements Serializable {
      */
      */
     @Schema(description = "承运单位名称")
     @Schema(description = "承运单位名称")
     private String carriageUnitName;
     private String carriageUnitName;
+    /**
+     * 合同类型:1托运合同 2承运合同(相对当前查看企业)
+     */
+    @Schema(description = "合同类型:1托运合同 2承运合同")
+    private Integer contractType;
+    /**
+     * 合同类型描述
+     */
+    @Schema(description = "合同类型描述")
+    private String contractTypeDesc;
     /**
     /**
      * 合同编号
      * 合同编号
      */
      */

+ 102 - 12
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/service/operateService/KwcContractLogisticsService.java

@@ -10,14 +10,13 @@ import com.github.pagehelper.PageInfo;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.google.common.collect.Sets;
-import com.sckw.contract.api.model.dto.req.TradeEntListQueryFeignDto;
-import com.sckw.contract.api.model.dto.res.TradeEntInfoResVo;
-import com.sckw.contract.api.model.dto.req.TradeEntListQueryFeignDto;
 import com.sckw.contract.dao.KwcContractLogisticsMapper;
 import com.sckw.contract.dao.KwcContractLogisticsMapper;
 import com.sckw.contract.model.dto.req.QueryListReqDto;
 import com.sckw.contract.model.dto.req.QueryListReqDto;
+import com.sckw.contract.model.dto.req.TradeEntListQueryFeignDto;
 import com.sckw.contract.model.dto.res.QueryListResDto;
 import com.sckw.contract.model.dto.res.QueryListResDto;
-import com.sckw.contract.api.model.dto.res.TradeEntInfoResVo;
+import com.sckw.contract.model.dto.res.TradeEntInfoResVo;
 import com.sckw.contract.model.entity.*;
 import com.sckw.contract.model.entity.*;
+import com.sckw.contract.model.enums.LogisticsTransportBizTypeEnum;
 import com.sckw.contract.model.report.LogisticsListExport;
 import com.sckw.contract.model.report.LogisticsListExport;
 import com.sckw.contract.model.vo.req.*;
 import com.sckw.contract.model.vo.req.*;
 import com.sckw.contract.model.vo.res.*;
 import com.sckw.contract.model.vo.res.*;
@@ -1114,6 +1113,10 @@ public class KwcContractLogisticsService {
         if (CollectionUtils.isEmpty(contractIdList) && CollectionUtils.isNotEmpty(entIdList)){
         if (CollectionUtils.isEmpty(contractIdList) && CollectionUtils.isNotEmpty(entIdList)){
             return PageDataResult.empty(req.getPageNum(),req.getPageSize());
             return PageDataResult.empty(req.getPageNum(),req.getPageSize());
         }
         }
+        applyContractTypeFilterToIds(req, entId, contractIdList);
+        if (CollectionUtils.isEmpty(contractIdList)) {
+            return PageDataResult.empty(req.getPageNum(), req.getPageSize());
+        }
         DataPermissionDTO perm = fetchDataPermissionForCurrentUser();
         DataPermissionDTO perm = fetchDataPermissionForCurrentUser();
         contractIdList = applyDataPermissionToLogisticsContractIds(contractIdList, perm);
         contractIdList = applyDataPermissionToLogisticsContractIds(contractIdList, perm);
         if (CollectionUtils.isEmpty(contractIdList)) {
         if (CollectionUtils.isEmpty(contractIdList)) {
@@ -1181,19 +1184,39 @@ public class KwcContractLogisticsService {
         List<QueryLogisticListResp> resp = records.stream()
         List<QueryLogisticListResp> resp = records.stream()
                 .map(r -> getQueryLogisticListResp(r, finalContractUniTypeAndUnitMap,
                 .map(r -> getQueryLogisticListResp(r, finalContractUniTypeAndUnitMap,
                         finalContractIdAndGoodsMap, finalLongUserCacheResDtoMap, finalLogTradeOrderIdAndWaybillMap,
                         finalContractIdAndGoodsMap, finalLongUserCacheResDtoMap, finalLogTradeOrderIdAndWaybillMap,
-                        contractIdAndLogisticsOrderMap))
+                        contractIdAndLogisticsOrderMap, entId))
                 .collect(Collectors.toList());
                 .collect(Collectors.toList());
 
 
         return PageDataResult.of(page, resp);
         return PageDataResult.of(page, resp);
     }
     }
 
 
+    /**
+     * 合同类型筛选:1 托运合同 2 承运合同(相对当前查看企业 entId 在合同中的角色)
+     */
+    private void applyContractTypeFilterToIds(QueryLogisticListReq req, Long entId, Set<Long> contractIdList) {
+        if (req == null || entId == null || CollectionUtils.isEmpty(contractIdList)) {
+            return;
+        }
+        Integer ct = req.getContractType();
+        if (ct == null || (ct != 1 && ct != 2)) {
+            return;
+        }
+        int unitType = ct == 1 ? CooperateTypeEnum.CONSIGN.getCode() : CooperateTypeEnum.CARRIAGE.getCode();
+        List<KwcContractLogisticsUnit> typeUnits = kwcContractLogisticsUnitRepository.queryByEntIdAndEntType(entId, unitType);
+        Set<Long> allowed = typeUnits.stream()
+                .map(KwcContractLogisticsUnit::getContractId)
+                .collect(Collectors.toSet());
+        contractIdList.retainAll(allowed);
+    }
+
     @NotNull
     @NotNull
     private static QueryLogisticListResp getQueryLogisticListResp(KwcContractLogistics r,
     private static QueryLogisticListResp getQueryLogisticListResp(KwcContractLogistics r,
                                                                   Map<String, KwcContractLogisticsUnit> finalContractUniTypeAndUnitMap,
                                                                   Map<String, KwcContractLogisticsUnit> finalContractUniTypeAndUnitMap,
                                                                   Map<Long, List<KwcContractLogisticsGoods>> finalContractIdAndGoodsMap,
                                                                   Map<Long, List<KwcContractLogisticsGoods>> finalContractIdAndGoodsMap,
                                                                   Map<Long, UserCacheResDto> finalLongUserCacheResDtoMap,
                                                                   Map<Long, UserCacheResDto> finalLongUserCacheResDtoMap,
                                                                   Map<Long, RWaybillSubOrderVo> logTradeOrderIdAndWaybillMap,
                                                                   Map<Long, RWaybillSubOrderVo> logTradeOrderIdAndWaybillMap,
-                                                                  Map<Long, WayContaractbillOrderVo> contractIdAndLogisticsOrderMap) {
+                                                                  Map<Long, WayContaractbillOrderVo> contractIdAndLogisticsOrderMap,
+                                                                  Long viewerEntId) {
         QueryLogisticListResp queryLogisticListResp = new QueryLogisticListResp();
         QueryLogisticListResp queryLogisticListResp = new QueryLogisticListResp();
         queryLogisticListResp.setId(r.getId());
         queryLogisticListResp.setId(r.getId());
         queryLogisticListResp.setContractStatus(r.getStatus());
         queryLogisticListResp.setContractStatus(r.getStatus());
@@ -1209,7 +1232,15 @@ public class KwcContractLogisticsService {
             queryLogisticListResp.setCarriageUnit(String.valueOf(carriageUnit.getEntId()));
             queryLogisticListResp.setCarriageUnit(String.valueOf(carriageUnit.getEntId()));
             queryLogisticListResp.setCarriageUnitName(carriageUnit.getFirmName());
             queryLogisticListResp.setCarriageUnitName(carriageUnit.getFirmName());
         }
         }
-
+        if (Objects.nonNull(viewerEntId)) {
+            if (Objects.nonNull(logisticsUnit) && Objects.equals(viewerEntId, logisticsUnit.getEntId())) {
+                queryLogisticListResp.setContractType(1);
+                queryLogisticListResp.setContractTypeDesc("托运合同");
+            } else if (Objects.nonNull(carriageUnit) && Objects.equals(viewerEntId, carriageUnit.getEntId())) {
+                queryLogisticListResp.setContractType(2);
+                queryLogisticListResp.setContractTypeDesc("承运合同");
+            }
+        }
 
 
         queryLogisticListResp.setContractCode(r.getContractNo());
         queryLogisticListResp.setContractCode(r.getContractNo());
         queryLogisticListResp.setContractName(r.getName());
         queryLogisticListResp.setContractName(r.getName());
@@ -1323,6 +1354,9 @@ public class KwcContractLogisticsService {
         if(Objects.equals(baseInfo.getSettlement(),1)){
         if(Objects.equals(baseInfo.getSettlement(),1)){
             throw new BusinessException("暂不支持普通结算模式");
             throw new BusinessException("暂不支持普通结算模式");
         }
         }
+        int transportBizType = resolveTransportBizType(baseInfo);
+        baseInfo.setTransportBizType(transportBizType);
+        validateLogisticsContractBiz(req, transportBizType);
         if (Objects.nonNull(req.getId())){
         if (Objects.nonNull(req.getId())){
             saveContractLogistics.setId(req.getId());
             saveContractLogistics.setId(req.getId());
         }else {
         }else {
@@ -1370,7 +1404,14 @@ public class KwcContractLogisticsService {
 
 
         saveContractLogistics.setUpdateBy(LoginUserHolder.getUserId());
         saveContractLogistics.setUpdateBy(LoginUserHolder.getUserId());
         saveContractLogistics.setUpdateTime(date);
         saveContractLogistics.setUpdateTime(date);
-        saveContractLogistics.setCommonPrice(baseInfo.getCommonPrice());
+        saveContractLogistics.setTransportBizType(transportBizType);
+        if (LogisticsTransportBizTypeEnum.isRawOreTransfer(transportBizType)) {
+            saveContractLogistics.setCommonPrice(null);
+            saveContractLogistics.setAllowedError(baseInfo.getAllowedError().setScale(4, RoundingMode.HALF_UP));
+        } else {
+            saveContractLogistics.setCommonPrice(baseInfo.getCommonPrice());
+            saveContractLogistics.setAllowedError(null);
+        }
         saveContractLogistics.setSigningUrl(req.getContractFile());
         saveContractLogistics.setSigningUrl(req.getContractFile());
         kwcContractLogisticsRepository.saveOrUpdateLogistics(saveContractLogistics);
         kwcContractLogisticsRepository.saveOrUpdateLogistics(saveContractLogistics);
 
 
@@ -1389,6 +1430,44 @@ public class KwcContractLogisticsService {
         return Boolean.TRUE;
         return Boolean.TRUE;
     }
     }
 
 
+    private static int resolveTransportBizType(LogisticListReq.TradeBaseInfo baseInfo) {
+        Integer t = baseInfo.getTransportBizType();
+        if (t == null) {
+            return LogisticsTransportBizTypeEnum.TRADE_TRANSPORT.getCode();
+        }
+        if (!Objects.equals(t, LogisticsTransportBizTypeEnum.TRADE_TRANSPORT.getCode())
+                && !Objects.equals(t, LogisticsTransportBizTypeEnum.RAW_ORE_TRANSFER.getCode())) {
+            throw new BusinessException("合同类型无效,请选择贸易运输或原矿转运");
+        }
+        return t;
+    }
+
+    private void validateLogisticsContractBiz(LogisticListReq req, int transportBizType) {
+        LogisticListReq.TradeBaseInfo baseInfo = req.getBaseInfo();
+        if (LogisticsTransportBizTypeEnum.isRawOreTransfer(transportBizType)) {
+            if (baseInfo.getAllowedError() == null) {
+                throw new BusinessException("原矿转运合同须填写允许误差");
+            }
+            if (baseInfo.getAllowedError().compareTo(BigDecimal.ZERO) <= 0) {
+                throw new BusinessException("允许误差须大于0");
+            }
+            if (baseInfo.getAllowedError().compareTo(new BigDecimal("1000")) > 0) {
+                throw new BusinessException("允许误差不能超过1000‰");
+            }
+            if (baseInfo.getCommonPrice() != null && baseInfo.getCommonPrice().compareTo(BigDecimal.ZERO) > 0) {
+                throw new BusinessException("原矿转运合同不可录入通用运价");
+            }
+            List<LogisticListReq.TradeGoodsInfo> goodsInfos = req.getGoodsInfo();
+            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(goodsInfos)) {
+                for (LogisticListReq.TradeGoodsInfo g : goodsInfos) {
+                    if (g.getPrice() != null && g.getPrice().compareTo(BigDecimal.ZERO) > 0) {
+                        throw new BusinessException("原矿转运合同不可录入运输单价");
+                    }
+                }
+            }
+        }
+    }
+
     private void checkAutoDispatchingContractEntType(LogisticListReq.TradeBaseInfo baseInfo,Map<Long, EntCacheResDto> entCacheResDtoMap) {
     private void checkAutoDispatchingContractEntType(LogisticListReq.TradeBaseInfo baseInfo,Map<Long, EntCacheResDto> entCacheResDtoMap) {
         if(DispatchingTypeEnum.AUTO.getValue().equals(baseInfo.getDispatchWay())){
         if(DispatchingTypeEnum.AUTO.getValue().equals(baseInfo.getDispatchWay())){
             EntCacheResDto entCacheResDto = entCacheResDtoMap.get(baseInfo.getProvideEntId());
             EntCacheResDto entCacheResDto = entCacheResDtoMap.get(baseInfo.getProvideEntId());
@@ -1456,10 +1535,12 @@ public class KwcContractLogisticsService {
         logisticsGoods.setSkuId(0L);
         logisticsGoods.setSkuId(0L);
         logisticsGoods.setAmount(x.getAmount());
         logisticsGoods.setAmount(x.getAmount());
         logisticsGoods.setUnit(x.getUnit());
         logisticsGoods.setUnit(x.getUnit());
-        if (Objects.isNull(x.getPrice())) {
+        if (LogisticsTransportBizTypeEnum.isRawOreTransfer(baseInfo.getTransportBizType())) {
+            logisticsGoods.setPrice(null);
+        } else if (Objects.isNull(x.getPrice())) {
             logisticsGoods.setPrice(Objects.nonNull(baseInfo.getCommonPrice())? baseInfo.getCommonPrice().setScale(2,
             logisticsGoods.setPrice(Objects.nonNull(baseInfo.getCommonPrice())? baseInfo.getCommonPrice().setScale(2,
                     RoundingMode.HALF_UP) : null);
                     RoundingMode.HALF_UP) : null);
-        }else {
+        } else {
             logisticsGoods.setPrice(x.getPrice());
             logisticsGoods.setPrice(x.getPrice());
         }
         }
         logisticsGoods.setPriceUnit(x.getAmountUnit());
         logisticsGoods.setPriceUnit(x.getAmountUnit());
@@ -1599,7 +1680,16 @@ public class KwcContractLogisticsService {
 
 
         tradeBaseInfo.setStartTime(logistics.getStartTime());
         tradeBaseInfo.setStartTime(logistics.getStartTime());
 
 
-        tradeBaseInfo.setCommonPrice(logistics.getCommonPrice().compareTo(new BigDecimal("0.00"))==0 ? null: logistics.getCommonPrice());
+        Integer transportBizType = logistics.getTransportBizType();
+        if (transportBizType == null) {
+            transportBizType = LogisticsTransportBizTypeEnum.TRADE_TRANSPORT.getCode();
+        }
+        tradeBaseInfo.setTransportBizType(transportBizType);
+        tradeBaseInfo.setTransportBizTypeDesc(LogisticsTransportBizTypeEnum.getLabelByCode(transportBizType));
+        tradeBaseInfo.setAllowedError(logistics.getAllowedError());
+
+        BigDecimal commonPrice = logistics.getCommonPrice();
+        tradeBaseInfo.setCommonPrice(commonPrice != null && commonPrice.compareTo(BigDecimal.ZERO) == 0 ? null : commonPrice);
         tradeBaseInfo.setContractStatus(String.valueOf(logistics.getStatus()));
         tradeBaseInfo.setContractStatus(String.valueOf(logistics.getStatus()));
         tradeBaseInfo.setContractStatusDesc(ContractStatusEnum.getNameByCode(logistics.getStatus()));
         tradeBaseInfo.setContractStatusDesc(ContractStatusEnum.getNameByCode(logistics.getStatus()));
 
 
@@ -1667,7 +1757,6 @@ public class KwcContractLogisticsService {
             payableAddDto.setCarriageEntId(collect.get(CooperateTypeEnum.CARRIAGE.getCode()).getEntId());
             payableAddDto.setCarriageEntId(collect.get(CooperateTypeEnum.CARRIAGE.getCode()).getEntId());
             payableAddDto.setTradeAmount(BigDecimal.ZERO);
             payableAddDto.setTradeAmount(BigDecimal.ZERO);
             payableAddDto.setRemark("运费清单初始化");
             payableAddDto.setRemark("运费清单初始化");
-            log.info("托运放:{}与承运方:{}签订物流合同,运费清单初始化",payableAddDto.getConsignEntId(),payableAddDto.getCarriageEntId());
             BaseResult<Object> payable = paymentFeignService.initPayable(payableAddDto);
             BaseResult<Object> payable = paymentFeignService.initPayable(payableAddDto);
             if (payable.getCode() == HttpStatus.SUCCESS_CODE){
             if (payable.getCode() == HttpStatus.SUCCESS_CODE){
                 log.info("创建运费清单成功");
                 log.info("创建运费清单成功");
@@ -1718,6 +1807,7 @@ public class KwcContractLogisticsService {
                         .filter(contractId ->contractIds.contains(contractId)).collect(Collectors.toSet());
                         .filter(contractId ->contractIds.contains(contractId)).collect(Collectors.toSet());
             }
             }
         }
         }
+        applyContractTypeFilterToIds(req, entId, contractIdList);
         if (org.apache.commons.collections4.CollectionUtils.isEmpty(contractIdList) && org.apache.commons.collections4.CollectionUtils.isNotEmpty(entIdList)){
         if (org.apache.commons.collections4.CollectionUtils.isEmpty(contractIdList) && org.apache.commons.collections4.CollectionUtils.isNotEmpty(entIdList)){
             Map<Integer, List<KwcContractLogistics>> statusAndLogOrdersMap = new HashMap<>();
             Map<Integer, List<KwcContractLogistics>> statusAndLogOrdersMap = new HashMap<>();
             List<ContractStatusCountResp.ContractStatusCount> statusCounts = statusEnums.stream()
             List<ContractStatusCountResp.ContractStatusCount> statusCounts = statusEnums.stream()

+ 3 - 0
sql/2026/04/2026_04_16_logistics_transport_biz.sql

@@ -0,0 +1,3 @@
+ALTER TABLE `sckw_ng_contract`.`kwc_contract_logistics`
+    ADD COLUMN `transport_biz_type` tinyint NOT NULL DEFAULT 1 COMMENT '业务合同类型 1贸易运输 2原矿转运' AFTER `common_price`,
+    ADD COLUMN `allowed_error` decimal(12, 4) NULL COMMENT '允许误差(千分比数值,如5表示5‰),原矿转运时必填' AFTER `transport_biz_type`;