feat(wms):上架管理PC上传页默认填充指定上架库位(维他奶仓→2层冷凍A區A01),仅回显不落库
This commit is contained in:
@@ -237,6 +237,12 @@ public interface SystemServiceFeign {
|
|||||||
@GetMapping("/warehouseApi/getInfo/{warehouseId}")
|
@GetMapping("/warehouseApi/getInfo/{warehouseId}")
|
||||||
public AjaxResult getWarehouseInfoByWarehouseId(@PathVariable("warehouseId") Long warehouseId);
|
public AjaxResult getWarehouseInfoByWarehouseId(@PathVariable("warehouseId") Long warehouseId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据warehouseId获取仓库及下库区及库位树(与前端 warehouseApi/getWarehouseChildren 一致,用于PC上架页默认库位回显)
|
||||||
|
*/
|
||||||
|
@GetMapping("/warehouseApi/getWarehouseChildren")
|
||||||
|
public AjaxResult getWarehouseChildren(@RequestParam("warehouseId") Long warehouseId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据storageSectionId获取对应库区信息
|
* 根据storageSectionId获取对应库区信息
|
||||||
*/
|
*/
|
||||||
|
|||||||
+30
@@ -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<WarehouseLinkageFeignPO> children;
|
||||||
|
}
|
||||||
+6
@@ -20,6 +20,7 @@ import org.springframework.cloud.openfeign.FallbackFactory;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -184,6 +185,11 @@ public class RemoteSystemFeignFallbackFactory implements FallbackFactory<SystemS
|
|||||||
return AjaxResult.error("根据仓库ID获取仓库信息失败");
|
return AjaxResult.error("根据仓库ID获取仓库信息失败");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AjaxResult getWarehouseChildren(@RequestParam("warehouseId") Long warehouseId) {
|
||||||
|
return AjaxResult.error("根据仓库ID获取仓库及下库区及库位树失败");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AjaxResult getStorageSectionInfoByStorageSectionId(@PathVariable("storageSectionId") Long storageSectionId) {
|
public AjaxResult getStorageSectionInfoByStorageSectionId(@PathVariable("storageSectionId") Long storageSectionId) {
|
||||||
return AjaxResult.error("根据库区ID获取库区信息失败");
|
return AjaxResult.error("根据库区ID获取库区信息失败");
|
||||||
|
|||||||
+112
@@ -133,6 +133,14 @@ public class StockShelfOrderApplicationService {
|
|||||||
private static final String API_NAME = "save_qnBill_i";
|
private static final String API_NAME = "save_qnBill_i";
|
||||||
private static final String VERIFY = "ESLuxAmB6VXCgbqP1eFzxTPVRagkQ62BUkfhElrgQ6XmE/g2reHVflY/SiCSU7JD";
|
private static final String VERIFY = "ESLuxAmB6VXCgbqP1eFzxTPVRagkQ62BUkfhElrgQ6XmE/g2reHVflY/SiCSU7JD";
|
||||||
|
|
||||||
|
/** 仅这些仓库的上架单在PC上传页默认填充上架库位(按仓库名匹配;需放开其他仓库时在此追加)。
|
||||||
|
* 生产环境:维他奶仓(warehouseId=14);测试环境为 青洲仓(warehouseId=13),需测试时切换 */
|
||||||
|
private static final Set<String> 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* 仍按明细树递归汇总;明细行净重/毛重/体积/面积<strong>不</strong>做「计划−已上架」覆盖,保持 shelf_material_detail 库表值
|
// PC 端(addParentCopyWhenNoChildren==false):单头 total* 仍按明细树递归汇总;明细行净重/毛重/体积/面积<strong>不</strong>做「计划−已上架」覆盖,保持 shelf_material_detail 库表值
|
||||||
if (!addParentCopyWhenNoChildren) {
|
if (!addParentCopyWhenNoChildren) {
|
||||||
|
// PC上传页:指定仓库(维他奶仓)的待上架明细默认填充指定库位,供前端回显(PDA不填充,实际落库仍以上架提交时选择的库位为准)
|
||||||
|
fillDefaultStorageLocation(stockShelfOrderPO, shelfMaterialDetailPOList);
|
||||||
BigDecimal totalNetWeight = BigDecimal.ZERO;
|
BigDecimal totalNetWeight = BigDecimal.ZERO;
|
||||||
BigDecimal totalGrossWeight = BigDecimal.ZERO;
|
BigDecimal totalGrossWeight = BigDecimal.ZERO;
|
||||||
BigDecimal totalVolume = 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<ShelfMaterialDetailPO> 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<WarehouseLinkageFeignPO> 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<ShelfMaterialDetailPO> 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<ShelfMaterialDetailPO> 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)映射到字段名
|
* 根据批次标签(batchLabels)映射到字段名
|
||||||
* @param batchLabel 批次标签
|
* @param batchLabel 批次标签
|
||||||
|
|||||||
Reference in New Issue
Block a user