From ab7219e6004002326e18d4eefccf103a445298fb Mon Sep 17 00:00:00 2001 From: rcx <3084692334@qq.com> Date: Sat, 22 Aug 2026 14:06:56 +0800 Subject: [PATCH] =?UTF-8?q?feat(wms):=E4=B8=8A=E6=9E=B6=E7=AE=A1=E7=90=86P?= =?UTF-8?q?C=E4=B8=8A=E4=BC=A0=E9=A1=B5=E9=BB=98=E8=AE=A4=E5=A1=AB?= =?UTF-8?q?=E5=85=85=E6=8C=87=E5=AE=9A=E4=B8=8A=E6=9E=B6=E5=BA=93=E4=BD=8D?= =?UTF-8?q?=EF=BC=88=E7=BB=B4=E4=BB=96=E5=A5=B6=E4=BB=93=E2=86=922?= =?UTF-8?q?=E5=B1=82=E5=86=B7=E5=87=8DA=E5=8D=80A01=EF=BC=89=EF=BC=8C?= =?UTF-8?q?=E4=BB=85=E5=9B=9E=E6=98=BE=E4=B8=8D=E8=90=BD=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mhd/system/api/SystemServiceFeign.java | 6 + .../api/domain/WarehouseLinkageFeignPO.java | 30 +++++ .../RemoteSystemFeignFallbackFactory.java | 6 + .../StockShelfOrderApplicationService.java | 112 ++++++++++++++++++ 4 files changed, 154 insertions(+) create mode 100644 mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/domain/WarehouseLinkageFeignPO.java diff --git a/mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/SystemServiceFeign.java b/mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/SystemServiceFeign.java index 4ce362167..f9abbe1f6 100644 --- a/mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/SystemServiceFeign.java +++ b/mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/SystemServiceFeign.java @@ -237,6 +237,12 @@ public interface SystemServiceFeign { @GetMapping("/warehouseApi/getInfo/{warehouseId}") public AjaxResult getWarehouseInfoByWarehouseId(@PathVariable("warehouseId") Long warehouseId); + /** + * 根据warehouseId获取仓库及下库区及库位树(与前端 warehouseApi/getWarehouseChildren 一致,用于PC上架页默认库位回显) + */ + @GetMapping("/warehouseApi/getWarehouseChildren") + public AjaxResult getWarehouseChildren(@RequestParam("warehouseId") Long warehouseId); + /** * 根据storageSectionId获取对应库区信息 */ diff --git a/mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/domain/WarehouseLinkageFeignPO.java b/mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/domain/WarehouseLinkageFeignPO.java new file mode 100644 index 000000000..ea5a37d59 --- /dev/null +++ b/mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/domain/WarehouseLinkageFeignPO.java @@ -0,0 +1,30 @@ +package com.mhd.system.api.domain; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 仓库联动树节点(Feign侧) + * 镜像system端WarehouseLinkagePO/StorageSectionLinkagePO/StorageLocationLinkagePO三级结构:仓库→库区→库位 + * + * @author rcx + * @date 2026-08-22 + */ +@Data +public class WarehouseLinkageFeignPO implements Serializable { + private static final long serialVersionUID = 1L; + + /** 仓库id / 库区id(storageSectionId) / 库位id(storageLocationId) */ + private Long id; + + /** warehouseCode / storageCode / storageLocationCode */ + private String code; + + /** warehouseName / storageName / storageLocationName */ + private String name; + + /** 下级节点:仓库下为库区列表,库区下为库位列表,库位无children */ + private List children; +} diff --git a/mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/factory/RemoteSystemFeignFallbackFactory.java b/mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/factory/RemoteSystemFeignFallbackFactory.java index ead5581ff..a4b0bfe44 100644 --- a/mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/factory/RemoteSystemFeignFallbackFactory.java +++ b/mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/factory/RemoteSystemFeignFallbackFactory.java @@ -20,6 +20,7 @@ import org.springframework.cloud.openfeign.FallbackFactory; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; import java.util.List; @@ -184,6 +185,11 @@ public class RemoteSystemFeignFallbackFactory implements FallbackFactory DEFAULT_STORAGE_LOCATION_WAREHOUSE_NAMES = new HashSet<>(Collections.singletonList("维他奶仓")); + /** 默认上架库位:指定库区名→库位名(精确匹配,须与基础资料名称完全一致,注意含繁体字)。 + * 生产环境:維他奶2层冷凍A區 → 2层冷凍A區A01;测试环境为 4楼A区 → 4A-01-01,需测试时切换 */ + private static final String DEFAULT_SHELF_STORAGE_NAME = "維他奶2层冷凍A區"; + private static final String DEFAULT_SHELF_STORAGE_LOCATION_NAME = "2层冷凍A區A01"; + /** * 分页查询上架单列表 @@ -357,6 +365,8 @@ public class StockShelfOrderApplicationService { // PC 端(addParentCopyWhenNoChildren==false):单头 total* 仍按明细树递归汇总;明细行净重/毛重/体积/面积做「计划−已上架」覆盖,保持 shelf_material_detail 库表值 if (!addParentCopyWhenNoChildren) { + // PC上传页:指定仓库(维他奶仓)的待上架明细默认填充指定库位,供前端回显(PDA不填充,实际落库仍以上架提交时选择的库位为准) + fillDefaultStorageLocation(stockShelfOrderPO, shelfMaterialDetailPOList); BigDecimal totalNetWeight = BigDecimal.ZERO; BigDecimal totalGrossWeight = BigDecimal.ZERO; BigDecimal totalVolume = BigDecimal.ZERO; @@ -2447,6 +2457,108 @@ public class StockShelfOrderApplicationService { } } + /** + * PC上传页:为尚未指定上架库位的明细行默认填充指定仓库的指定库位 + * (按名称精确匹配 DEFAULT_SHELF_STORAGE_NAME 库区下的 DEFAULT_SHELF_STORAGE_LOCATION_NAME 库位,非取排序第一个)。 + * 仅回显默认值不落库:实际落库仍以上架提交时选择的库位为准(setStorageLocationInfo 会重新校验补全); + * 已上架行的库表库位不覆盖,兼容二次上架。Feign失败或未匹配到目标库位时仅告警降级,不影响页面打开。 + */ + private void fillDefaultStorageLocation(StockShelfOrderPO stockShelfOrderPO, List shelfMaterialDetailPOList) { + if (stockShelfOrderPO == null || CollectionUtils.isEmpty(shelfMaterialDetailPOList)) { + return; + } + // 已完成上架的单据不再填充,避免展示从未实际使用的库位 + if (stockShelfOrderPO.getStatus() != null && stockShelfOrderPO.getStatus() > 2) { + return; + } + // 仅指定仓库生效(按名称匹配,warehouseId跨环境不稳定) + if (stockShelfOrderPO.getWarehouseId() == null + || !DEFAULT_STORAGE_LOCATION_WAREHOUSE_NAMES.contains(stockShelfOrderPO.getWarehouseName())) { + return; + } + // 明细树中存在未填库位的行才发起查询 + if (!hasEmptyStorageLocationRecursively(shelfMaterialDetailPOList)) { + return; + } + try { + AjaxResult warehouseChildrenResult = systemServiceFeign.getWarehouseChildren(stockShelfOrderPO.getWarehouseId()); + if (warehouseChildrenResult == null || !"200".equals(String.valueOf(warehouseChildrenResult.get("code"))) + || warehouseChildrenResult.get("data") == null) { + log.warn("获取仓库库位树失败,跳过默认上架库位填充,warehouseId={}", stockShelfOrderPO.getWarehouseId()); + return; + } + List warehouseLinkageList = JSON.parseArray( + JSONObject.toJSONString(warehouseChildrenResult.get("data")), WarehouseLinkageFeignPO.class); + if (CollectionUtils.isEmpty(warehouseLinkageList)) { + return; + } + WarehouseLinkageFeignPO warehouse = warehouseLinkageList.get(0); + if (CollectionUtils.isEmpty(warehouse.getChildren())) { + return; + } + // 精确匹配指定的默认库区/库位(非取排序第一个) + WarehouseLinkageFeignPO section = warehouse.getChildren().stream() + .filter(sectionNode -> DEFAULT_SHELF_STORAGE_NAME.equals(sectionNode.getName())) + .findFirst().orElse(null); + if (section == null || CollectionUtils.isEmpty(section.getChildren())) { + log.warn("未找到默认上架库区:{},warehouseId={},跳过默认库位填充", + DEFAULT_SHELF_STORAGE_NAME, stockShelfOrderPO.getWarehouseId()); + return; + } + WarehouseLinkageFeignPO location = section.getChildren().stream() + .filter(locationNode -> DEFAULT_SHELF_STORAGE_LOCATION_NAME.equals(locationNode.getName())) + .findFirst().orElse(null); + if (location == null) { + log.warn("未找到默认上架库位:{}(库区:{}),warehouseId={},跳过默认库位填充", + DEFAULT_SHELF_STORAGE_LOCATION_NAME, DEFAULT_SHELF_STORAGE_NAME, stockShelfOrderPO.getWarehouseId()); + return; + } + fillStorageLocationRecursively(shelfMaterialDetailPOList, warehouse, section, location); + log.info("已为上架单填充默认上架库位,shelfOrderId={},shelfOrderNumber={},库位:{}-{}-{}(库位ID:{})", + stockShelfOrderPO.getShelfOrderId(), stockShelfOrderPO.getShelfOrderNumber(), + warehouse.getName(), section.getName(), location.getName(), location.getId()); + } catch (Exception e) { + log.warn("填充默认上架库位失败,warehouseId={},错误:{}", stockShelfOrderPO.getWarehouseId(), e.getMessage()); + } + } + + /** 明细树(含子行)中是否存在未指定库位(storageLocationId为空或0)的行 */ + private boolean hasEmptyStorageLocationRecursively(List shelfMaterialDetailPOList) { + for (ShelfMaterialDetailPO detail : shelfMaterialDetailPOList) { + if (detail.getStorageLocationId() == null || detail.getStorageLocationId() == 0) { + return true; + } + if (!CollectionUtils.isEmpty(detail.getChildren()) + && hasEmptyStorageLocationRecursively(detail.getChildren())) { + return true; + } + } + return false; + } + + /** 递归为未指定库位(storageLocationId为空或0)的明细行填充仓库/库区/库位信息,已有值不覆盖 */ + private void fillStorageLocationRecursively(List shelfMaterialDetailPOList, + WarehouseLinkageFeignPO warehouse, + WarehouseLinkageFeignPO section, + WarehouseLinkageFeignPO location) { + for (ShelfMaterialDetailPO detail : shelfMaterialDetailPOList) { + if (detail.getStorageLocationId() == null || detail.getStorageLocationId() == 0) { + detail.setWarehouseId(warehouse.getId()); + detail.setWarehouseCode(warehouse.getCode()); + detail.setWarehouseName(warehouse.getName()); + detail.setStorageSectionId(section.getId()); + detail.setStorageCode(section.getCode()); + detail.setStorageName(section.getName()); + detail.setStorageLocationId(location.getId()); + detail.setStorageLocationCode(location.getCode()); + detail.setStorageLocationName(location.getName()); + } + if (!CollectionUtils.isEmpty(detail.getChildren())) { + fillStorageLocationRecursively(detail.getChildren(), warehouse, section, location); + } + } + } + /** * 根据批次标签(batchLabels)映射到字段名 * @param batchLabel 批次标签