ソースを参照

提交商品部分代码

chenxiaofei 1 週間 前
コミット
af47f00b8a

+ 10 - 0
sckw-modules-api/sckw-contract-api/src/main/java/com/sckw/contract/api/RemoteContractService.java

@@ -77,6 +77,16 @@ public interface RemoteContractService {
      */
     TradeContractGoodsDto queryTradeContractNew(Long entId, Long goodsId, LocalDateTime time);
 
+    /**
+     * 查询当前企业作为采购方或销售方时,指定商品最新有效贸易合同签约价。
+     *
+     * @param entId   当前企业ID
+     * @param goodsId 商品ID
+     * @param time    当前时间
+     * @return 最新有效贸易合同商品签约价
+     */
+    TradeContractGoodsDto queryTradeContractNewByEnt(Long entId, Long goodsId, LocalDateTime time);
+
     List<Long> queryNewSignGoods(Long entId, LocalDateTime time);
 
     /**

+ 112 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/dubbo/RemoteContractServiceImpl.java

@@ -49,6 +49,7 @@ import org.springframework.data.redis.core.RedisTemplate;
 
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
@@ -307,6 +308,117 @@ public class RemoteContractServiceImpl implements RemoteContractService {
         return kwcContractTradeMapper.queryNewSignPrice(entId, goodsId, time);
     }
 
+    /**
+     * 根据企业ID、商品ID和指定时间,查询该企业在当时有效的最新贸易合同中的商品价格。
+     * <p>
+     * 业务逻辑:
+     * 1. 参数校验:确保 entId, goodsId, time 不为空。
+     * 2. 查找关联合同:查询该企业(作为供应商或采购商)参与的所有未删除的贸易合同单元,获取合同ID列表。
+     * 3. 筛选商品关联:在上述合同ID列表中,查找包含指定商品ID且未删除的合同商品记录。
+     * 4. 构建映射:将合同商品记录以 contractId 为 key 建立映射,方便后续快速查找。
+     * 5. 确定有效合同:在筛选出的合同中,查找满足以下条件的唯一最新合同:
+     *    - 状态为已签约 (SIGNED)
+     *    - 未删除
+     *    - 指定时间在合同有效期内 (startTime <= time < endTime 或 endTime 为空)
+     *    - 按创建时间倒序排列,取第一条(即最近创建的符合条件的合同)
+     * 6. 返回结果:如果找到有效合同,返回对应的合同ID、商品ID和价格;否则返回 null。
+     *
+     * @param entId   企业ID
+     * @param goodsId 商品ID
+     * @param time    查询时间点
+     * @return 贸易合同商品信息DTO,包含合同ID、商品ID和价格;若无匹配数据则返回 null
+     */
+    @Override
+    public TradeContractGoodsDto queryTradeContractNewByEnt(Long entId, Long goodsId, LocalDateTime time) {
+        // 1. 参数校验
+        if (Objects.isNull(entId) || Objects.isNull(goodsId) || Objects.isNull(time)) {
+            log.warn("查询企业商品最新签约价参数异常,entId:{},goodsId:{},time:{}", entId, goodsId, time);
+            return null;
+        }
+
+        log.debug("开始查询企业[{}]商品[{}]在时间[{}]的最新签约价", entId, goodsId, time);
+
+        // 将 LocalDateTime 转换为 Date 用于数据库查询
+        Date queryTime = Date.from(time.atZone(ZoneId.systemDefault()).toInstant());
+
+        // 2. 查找该企业参与的所有有效贸易合同ID
+        // 条件:未删除、企业ID匹配、单位类型为供应商或采购商
+        List<Long> contractIdsByEnt = kwcContractTradeUnitMapper.selectList(new LambdaQueryWrapper<KwcContractTradeUnit>()
+                        .eq(KwcContractTradeUnit::getDelFlag, Global.NO)
+                        .eq(KwcContractTradeUnit::getEntId, entId)
+                        .in(KwcContractTradeUnit::getUnitType, List.of(CooperateTypeEnum.SUPPLIER.getCode(), CooperateTypeEnum.PURCHASER.getCode())))
+                .stream()
+                .map(KwcContractTradeUnit::getContractId)
+                .filter(Objects::nonNull)
+                .distinct()
+                .toList();
+
+        if (CollectionUtils.isEmpty(contractIdsByEnt)) {
+            log.debug("企业[{}]未找到任何关联的贸易合同单元", entId);
+            return null;
+        }
+        log.debug("企业[{}]关联的合同ID数量: {}", entId, contractIdsByEnt.size());
+
+        // 3. 在这些合同中查找包含指定商品的记录
+        List<KwcContractTradeGoods> contractGoods = kwcContractTradeGoodsMapper.selectList(new LambdaQueryWrapper<KwcContractTradeGoods>()
+                .eq(KwcContractTradeGoods::getDelFlag, Global.NO)
+                .eq(KwcContractTradeGoods::getGoodsId, goodsId)
+                .in(KwcContractTradeGoods::getContractId, contractIdsByEnt));
+
+        if (CollectionUtils.isEmpty(contractGoods)) {
+            log.debug("在企业[{}]的合同中找到商品[{}]的记录为空", entId, goodsId);
+            return null;
+        }
+
+        // 4. 构建合同ID到合同商品对象的映射,以便后续通过合同ID快速获取商品信息
+        Map<Long, KwcContractTradeGoods> contractGoodsMap = contractGoods.stream()
+                .filter(item -> Objects.nonNull(item.getContractId()))
+                .collect(Collectors.toMap(KwcContractTradeGoods::getContractId, item -> item, (oldValue, newValue) -> oldValue));
+
+        if (CollectionUtils.isEmpty(contractGoodsMap)) {
+            log.warn("构建合同商品映射失败,contractGoodsMap为空");
+            return null;
+        }
+
+        // 5. 查询在指定时间点有效的最新已签约合同
+        // 条件:
+        // - 未删除
+        // - 状态为已签约
+        // - 合同ID在之前筛选出的包含该商品的合同ID集合中
+        // - 合同开始时间 <= 查询时间
+        // - 合同结束时间 > 查询时间 或 结束时间为空(表示长期有效)
+        // - 按创建时间倒序,取最新的一条
+        KwcContractTrade contractTrade = kwcContractTradeMapper.selectOne(new LambdaQueryWrapper<KwcContractTrade>()
+                .eq(KwcContractTrade::getDelFlag, Global.NO)
+                .eq(KwcContractTrade::getStatus, ContractStatusEnum.SIGNED.getCode())
+                .in(KwcContractTrade::getId, contractGoodsMap.keySet())
+                .lt(KwcContractTrade::getStartTime, queryTime)
+                .and(wrapper -> wrapper.gt(KwcContractTrade::getEndTime, queryTime).or().isNull(KwcContractTrade::getEndTime))
+                .orderByDesc(KwcContractTrade::getCreateTime)
+                .last("limit 1"));
+
+        if (Objects.isNull(contractTrade)) {
+            log.debug("未找到企业[{}]商品[{}]在时间[{}]的有效已签约合同", entId, goodsId, time);
+            return null;
+        }
+        log.info("找到企业[{}]商品[{}]的有效合同ID: {}", entId, goodsId, contractTrade.getId());
+
+        // 6. 从映射中获取对应的商品信息并组装返回对象
+        KwcContractTradeGoods newestContractGoods = contractGoodsMap.get(contractTrade.getId());
+        if (Objects.isNull(newestContractGoods)) {
+            log.error("数据不一致:合同ID[{}]在contractGoodsMap中不存在", contractTrade.getId());
+            return null;
+        }
+
+        TradeContractGoodsDto tradeContractGoodsDto = new TradeContractGoodsDto();
+        tradeContractGoodsDto.setContractId(contractTrade.getId());
+        tradeContractGoodsDto.setGoodsId(goodsId);
+        tradeContractGoodsDto.setPrice(newestContractGoods.getPrice());
+
+        log.debug("查询成功,返回合同ID: {}, 价格: {}", tradeContractGoodsDto.getContractId(), tradeContractGoodsDto.getPrice());
+        return tradeContractGoodsDto;
+    }
+
     @Override
     public List<Long> queryNewSignGoods(Long entId, LocalDateTime time) {
         return kwcContractTradeMapper.queryNewSignGoods(entId, time);

+ 7 - 1
sckw-modules/sckw-fleet/pom.xml

@@ -113,6 +113,12 @@
             <version>4.5.0</version>
         </dependency>
 
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
 
     <build>
@@ -134,4 +140,4 @@
         </plugins>
     </build>
 
-</project>
+</project>

+ 6 - 0
sckw-modules/sckw-fleet/src/main/java/com/sckw/fleet/model/KwfTruck.java

@@ -196,6 +196,12 @@ public class KwfTruck extends BaseModel {
      */
     private Integer blacklist;
 
+    /**
+     * 最大运输距离,单位:公里
+     */
+    @TableField("max_transport_distance")
+    private BigDecimal maxTransportDistance;
+
 
 
 

+ 7 - 0
sckw-modules/sckw-fleet/src/main/java/com/sckw/fleet/model/reponse/TruckDetailResp.java

@@ -7,6 +7,7 @@ import lombok.Data;
 
 import java.io.Serial;
 import java.io.Serializable;
+import java.math.BigDecimal;
 import java.util.Date;
 
 /**
@@ -131,6 +132,12 @@ public class TruckDetailResp implements Serializable {
     @Schema(description = "发动机号")
     private String positionDevice;
 
+    /**
+     * 最大运输距离,单位:公里
+     */
+    @Schema(description = "最大运输距离,单位:公里")
+    private BigDecimal maxTransportDistance;
+
     /**
      * 车辆行驶证信息
      */

+ 7 - 0
sckw-modules/sckw-fleet/src/main/java/com/sckw/fleet/model/reponse/TruckResp.java

@@ -10,6 +10,7 @@ import lombok.experimental.Accessors;
 
 import java.io.Serial;
 import java.io.Serializable;
+import java.math.BigDecimal;
 import java.util.Date;
 
 /**
@@ -84,6 +85,12 @@ public class TruckResp implements Serializable {
     @Schema(description = "关联司机")
     private String driverName;
 
+    /**
+     * 最大运输距离,单位:公里
+     */
+    @Schema(description = "最大运输距离,单位:公里")
+    private BigDecimal maxTransportDistance;
+
     /**
      * 黑名单
      */

+ 7 - 0
sckw-modules/sckw-fleet/src/main/java/com/sckw/fleet/model/request/TruckSaveParam.java

@@ -8,6 +8,7 @@ import lombok.Data;
 
 import java.io.Serial;
 import java.io.Serializable;
+import java.math.BigDecimal;
 import java.util.Date;
 
 /**
@@ -101,6 +102,12 @@ public class TruckSaveParam implements Serializable {
     @Schema(description = "发动机号")
     private String positionDevice;
 
+    /**
+     * 最大运输距离,单位:公里
+     */
+    @Schema(description = "最大运输距离,单位:公里")
+    private BigDecimal maxTransportDistance;
+
     /**
      * 车辆行驶证信息
      */

+ 6 - 0
sckw-modules/sckw-fleet/src/main/java/com/sckw/fleet/service/KwfTruckService.java

@@ -2217,6 +2217,7 @@ public class KwfTruckService {
             truckResp.setBlacklist(truck.getBlacklist());
             truckResp.setRemark(truck.getRemark());
             truckResp.setAnnualInspectionTime(truck.getAnnualInspectionTime());
+            truckResp.setMaxTransportDistance(truck.getMaxTransportDistance());
             //查询车辆轴数
             TmsTruckAxleNum axleNum = getCarAxisInfo(truck.getCarAxis());
             truckResp.setCarAxis(truck.getCarAxis());
@@ -2267,6 +2268,7 @@ public class KwfTruckService {
         truckDetailResp.setAnnualInspectionTime(truck.getAnnualInspectionTime());
         truckDetailResp.setTransportValidityTime(truck.getTransportValidityTime());
         truckDetailResp.setPositionDevice(truck.getPositionDevice());
+        truckDetailResp.setMaxTransportDistance(truck.getMaxTransportDistance());
         truckDetailResp.setTruckLicense(truck.getTruckLicense());
         truckDetailResp.setTransportLicense(truck.getTransportLicense());
         truckDetailResp.setEnvironmentalList(truck.getEnvironmentalList());
@@ -2324,6 +2326,7 @@ public class KwfTruckService {
             truck.setAnnualInspectionTime(param.getAnnualInspectionTime());
             truck.setTransportValidityTime(param.getTransportValidityTime());
             truck.setPositionDevice(param.getPositionDevice());
+            truck.setMaxTransportDistance(param.getMaxTransportDistance());
             truck.setTruckLicense(param.getTruckLicense());
             truck.setTransportLicense(param.getTransportLicense());
             truck.setEnvironmentalList(param.getEnvironmentalList());
@@ -2355,6 +2358,7 @@ public class KwfTruckService {
             truck.setAnnualInspectionTime(param.getAnnualInspectionTime());
             truck.setTransportValidityTime(param.getTransportValidityTime());
             truck.setPositionDevice(param.getPositionDevice());
+            truck.setMaxTransportDistance(param.getMaxTransportDistance());
             truck.setTruckLicense(param.getTruckLicense());
             truck.setTransportLicense(param.getTransportLicense());
             truck.setEnvironmentalList(param.getEnvironmentalList());
@@ -2395,6 +2399,7 @@ public class KwfTruckService {
             truck.setAnnualInspectionTime(param.getAnnualInspectionTime());
             truck.setTransportValidityTime(param.getTransportValidityTime());
             truck.setPositionDevice(param.getPositionDevice());
+            truck.setMaxTransportDistance(param.getMaxTransportDistance());
             truck.setTruckLicense(param.getTruckLicense());
             truck.setTransportLicense(param.getTransportLicense());
             truck.setEnvironmentalList(param.getEnvironmentalList());
@@ -2426,6 +2431,7 @@ public class KwfTruckService {
             truck.setAnnualInspectionTime(param.getAnnualInspectionTime());
             truck.setTransportValidityTime(param.getTransportValidityTime());
             truck.setPositionDevice(param.getPositionDevice());
+            truck.setMaxTransportDistance(param.getMaxTransportDistance());
             truck.setTruckLicense(param.getTruckLicense());
             truck.setTransportLicense(param.getTransportLicense());
             truck.setEnvironmentalList(param.getEnvironmentalList());

+ 35 - 0
sckw-modules/sckw-fleet/src/test/java/com/sckw/fleet/model/TruckMaxTransportDistanceTest.java

@@ -0,0 +1,35 @@
+package com.sckw.fleet.model;
+
+import com.sckw.fleet.model.reponse.TruckDetailResp;
+import com.sckw.fleet.model.reponse.TruckResp;
+import com.sckw.fleet.model.request.TruckSaveParam;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.math.BigDecimal;
+
+/**
+ * 车辆最大运输距离接口字段单元测试。
+ */
+public class TruckMaxTransportDistanceTest {
+
+    /**
+     * 校验新增、详情、列表接口对象均支持最大运输距离字段读写。
+     */
+    @Test
+    public void shouldReadAndWriteMaxTransportDistance() {
+        BigDecimal maxTransportDistance = new BigDecimal("1200.50");
+
+        TruckSaveParam saveParam = new TruckSaveParam();
+        TruckDetailResp detailResp = new TruckDetailResp();
+        TruckResp truckResp = new TruckResp();
+
+        saveParam.setMaxTransportDistance(maxTransportDistance);
+        detailResp.setMaxTransportDistance(maxTransportDistance);
+        truckResp.setMaxTransportDistance(maxTransportDistance);
+
+        Assert.assertEquals(maxTransportDistance, saveParam.getMaxTransportDistance());
+        Assert.assertEquals(maxTransportDistance, detailResp.getMaxTransportDistance());
+        Assert.assertEquals(maxTransportDistance, truckResp.getMaxTransportDistance());
+    }
+}

+ 5 - 0
sckw-modules/sckw-product/pom.xml

@@ -118,6 +118,11 @@
             <artifactId>sckw-contract-api</artifactId>
             <version>${basic.version}</version>
         </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>

+ 3 - 0
sckw-modules/sckw-product/src/main/java/com/sckw/product/model/vo/res/BuildingMaterialsMarketList.java

@@ -91,4 +91,7 @@ public class BuildingMaterialsMarketList {
 
     @Schema(description = "是否签约")
     private boolean signFlag;
+
+    @Schema(description = "是否展示立即下单按钮")
+    private boolean showOrderButtonFlag;
 }

+ 6 - 1
sckw-modules/sckw-product/src/main/java/com/sckw/product/service/KwpGoodsService.java

@@ -1148,7 +1148,7 @@ public class KwpGoodsService {
             materials.setGoodsTypeLabel(CollectionUtils.isNotEmpty(productNameMap) ? productNameMap.get(e.getGoodsType()) : null).setUnitLabel(CollectionUtils.isNotEmpty(unitMap) ? unitMap.get(e.getUnit()) : null).setSpec(CollectionUtils.isNotEmpty(specMap) ? specMap.get(e.getSpec()) : null).setAddressName(Objects.isNull(address) ? null : address.getCityName()).setDetailAddress(Objects.isNull(address) ? null : address.getDetailAddress()).setPrice(CollectionUtils.isEmpty(priceRanges) ? null : priceRanges.get(0).getPrice()).setThumb(FileUtils.splice(e.getThumb())).setSupplyEnt(entMap.get(e.getSupplyEntId()));
             materials.setSignFlag(false);
             if (Objects.nonNull(entId)) {
-                TradeContractGoodsDto tradeContractResDto = remoteContractService.queryTradeContractNew(entId, e.getId(), LocalDateTime.now());
+                TradeContractGoodsDto tradeContractResDto = remoteContractService.queryTradeContractNewByEnt(entId, e.getId(), LocalDateTime.now());
                 if (Objects.nonNull(tradeContractResDto)) {
                     materials.setSignPrice(tradeContractResDto.getPrice());
                     materials.setSignFlag(true);
@@ -1561,12 +1561,17 @@ public class KwpGoodsService {
             List<KwpGoodsPriceRange> priceRanges = priceRangeMap.get(e.getId());
             materials.setGoodsTypeLabel(CollectionUtils.isNotEmpty(productNameMap) ? productNameMap.get(e.getGoodsType()) : null).setUnitLabel(CollectionUtils.isNotEmpty(unitMap) ? unitMap.get(e.getUnit()) : null).setSpec(CollectionUtils.isNotEmpty(goodsMap) ? goodsMap.get(e.getSpec()) : null).setAddressName(Objects.isNull(address) ? null : address.getCityName()).setDetailAddress(Objects.isNull(address) ? null : address.getDetailAddress()).setPrice(CollectionUtils.isEmpty(priceRanges) ? null : priceRanges.get(0).getPrice()).setThumb(FileUtils.splice(e.getThumb())).setSupplyEnt(entMap.get(e.getSupplyEntId()));
             materials.setSignFlag(false);
+            materials.setShowOrderButtonFlag(false);
             if (Objects.nonNull(entId)) {
                 TradeContractGoodsDto tradeContractResDto = remoteContractService.queryTradeContractNew(entId, e.getId(), LocalDateTime.now());
                 if (Objects.nonNull(tradeContractResDto)) {
                     materials.setSignPrice(tradeContractResDto.getPrice());
                     materials.setSignFlag(true);
                 }
+                TradeContractGoodsDto orderButtonContractDto = Objects.nonNull(tradeContractResDto)
+                        ? tradeContractResDto
+                        : remoteContractService.queryTradeContractNewByEnt(entId, e.getId(), LocalDateTime.now());
+                materials.setShowOrderButtonFlag(Objects.nonNull(orderButtonContractDto));
             }
             result.add(materials);
         });

+ 30 - 0
sckw-modules/sckw-product/src/test/java/com/sckw/product/model/vo/res/BuildingMaterialsMarketListTest.java

@@ -0,0 +1,30 @@
+package com.sckw.product.model.vo.res;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.math.BigDecimal;
+
+/**
+ * 建材市场商品列表响应单元测试。
+ */
+public class BuildingMaterialsMarketListTest {
+
+    /**
+     * 校验新增已签约展示标识默认不展示,且支持链式赋值。
+     */
+    @Test
+    public void showSignedFlagShouldDefaultFalseAndSupportSetter() {
+        BuildingMaterialsMarketList goods = new BuildingMaterialsMarketList();
+
+        Assert.assertFalse(goods.isShowOrderButtonFlag());
+
+        goods.setSignPrice(new BigDecimal("12.34"))
+                .setSignFlag(true)
+                .setShowOrderButtonFlag(true);
+
+        Assert.assertTrue(goods.isSignFlag());
+        Assert.assertTrue(goods.isShowOrderButtonFlag());
+        Assert.assertEquals(new BigDecimal("12.34"), goods.getSignPrice());
+    }
+}

+ 2 - 0
sql/2026/06/2026_06_07_fleet_truck_max_transport_distance.sql

@@ -0,0 +1,2 @@
+ALTER TABLE `kwf_truck`
+    ADD COLUMN `max_transport_distance` decimal(12, 2) NULL COMMENT '最大运输距离,单位:公里' AFTER `position_device`;