Merge remote-tracking branch 'origin/wms_dev' into wms_dev

This commit is contained in:
zhou-hongcheng
2026-02-04 10:41:51 +08:00
6 changed files with 583 additions and 268 deletions
@@ -1,17 +1,31 @@
package com.mhd.wms.application.service.inventoryAdjustmentRecord;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.mhd.common.core.utils.StringUtils;
import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.common.security.utils.SecurityUtils;
import com.mhd.system.api.SystemServiceFeign;
import com.mhd.system.api.domain.BatchDetailFeignPO;
import com.mhd.system.api.domain.cache.AssociationWarehouseCacheDO;
import com.mhd.system.api.domain.cache.SystemServiceCacheUtil;
import com.mhd.system.api.model.LoginUser;
import com.mhd.wms.domain.inventoryAdjustmentRecord.repository.po.InventoryAdjustmentRecordPO;
import com.mhd.wms.domain.inventoryAdjustmentRecord.repository.todo.InventoryAdjustmentRecordDO;
import com.mhd.wms.domain.inventoryAdjustmentRecord.service.InventoryAdjustmentRecordDomainService;
import com.mhd.wms.domain.materialInventory.repository.mapper.MaterialInventoryMapper;
import com.mhd.wms.domain.materialInventory.repository.po.MaterialInventoryPO;
import com.mhd.wms.domain.materialMoreDetail.repository.po.MaterialMoreDetailPO;
import com.mhd.wms.domain.statementStatistics.po.ImmediateInventoryPO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
/**
* 库存调整记录ApplicationService
@@ -24,6 +38,10 @@ import java.util.List;
public class InventoryAdjustmentRecordApplicationService {
@Autowired
private InventoryAdjustmentRecordDomainService inventoryAdjustmentRecordDomainService;
@Autowired
private MaterialInventoryMapper materialInventoryMapper;
@Autowired
private SystemServiceFeign systemServiceFeign;
/**
@@ -40,7 +58,262 @@ public class InventoryAdjustmentRecordApplicationService {
AssociationWarehouseCacheDO associationWarehouseCacheDO = SystemServiceCacheUtil.getAssociationWarehouseCache(loginUser.getUserid());
inventoryAdjustmentRecordDO.setWarehouseId(associationWarehouseCacheDO.getWarehouseId());
}
return inventoryAdjustmentRecordDomainService.queryList(inventoryAdjustmentRecordDO);
List<InventoryAdjustmentRecordPO> inventoryAdjustmentRecordPOS = inventoryAdjustmentRecordDomainService.queryList(inventoryAdjustmentRecordDO);
// 性能优化:批量获取批次属性,避免N+1查询问题
// 1. 收集所有唯一的materialBaseInfoId
Set<Long> materialBaseInfoIdSet = inventoryAdjustmentRecordPOS.stream()
.map(InventoryAdjustmentRecordPO::getMaterialBaseInfoId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
// 2. 批量查询批次属性(使用Map缓存,避免重复查询相同的materialBaseInfoId
Map<Long, List<BatchDetailFeignPO>> batchDetailMap = new HashMap<>();
for (Long materialBaseInfoId : materialBaseInfoIdSet) {
try {
AjaxResult ajaxResult = systemServiceFeign.getBatchDetailListByMaterialBaseInfoId(materialBaseInfoId);
if (ajaxResult != null && "200".equals(String.valueOf(ajaxResult.get("code")))) {
List<BatchDetailFeignPO> batchDetailFeignPOList = JSON.parseArray(
JSONObject.toJSONString(ajaxResult.get("data")), BatchDetailFeignPO.class);
if (!CollectionUtils.isEmpty(batchDetailFeignPOList)) {
// 过滤isDisplay=1的属性
List<BatchDetailFeignPO> filteredList = batchDetailFeignPOList.stream()
.filter(batchDetail -> batchDetail.getIsDisplay() != null && batchDetail.getIsDisplay() == 1)
.collect(Collectors.toList());
batchDetailMap.put(materialBaseInfoId, filteredList);
}
}
} catch (Exception e) {
log.warn("获取物料批次属性失败,物料基础信息ID:{},错误:{}", materialBaseInfoId, e.getMessage());
}
}
// 3. 为每个物料明细设置更多属性(从库存表中获取值)
setMaterialMoreDetailListFromInventory(inventoryAdjustmentRecordPOS, batchDetailMap);
return inventoryAdjustmentRecordPOS;
}
/**
* 为物料库存设置更多属性(从库存表中获取值)
* @param materialInventoryPOList 物料库存列表
* @param batchDetailMap 批次属性Map
*/
private void setMaterialMoreDetailListFromInventory(List<InventoryAdjustmentRecordPO> materialInventoryPOList,
Map<Long, List<BatchDetailFeignPO>> batchDetailMap) {
if (CollectionUtils.isEmpty(materialInventoryPOList)) {
return;
}
materialInventoryPOList.forEach(materialInventoryPO -> {
Long materialBaseInfoId = materialInventoryPO.getMaterialBaseInfoId();
Long materialInventoryId = materialInventoryPO.getMaterialInventoryId();
// 创建新的materialMoreDetailList,只包含isDisplay=1的属性
List<MaterialMoreDetailPO> materialMoreDetailList = new ArrayList<>();
// 从库存表获取数据(包含批次属性字段)
MaterialInventoryPO inventoryPO = null;
if (materialInventoryId != null) {
inventoryPO = materialInventoryMapper.selectByIdWithBatchAttributes(materialInventoryId);
}
if (materialBaseInfoId != null && batchDetailMap.containsKey(materialBaseInfoId)) {
List<BatchDetailFeignPO> batchDetailFeignPOList = batchDetailMap.get(materialBaseInfoId);
// 用于跟踪已添加到列表中的batchDetailId
Set<Long> addedBatchDetailIds = new HashSet<>();
for (BatchDetailFeignPO batchDetailFeignPO : batchDetailFeignPOList) {
MaterialMoreDetailPO materialMoreDetailPO = new MaterialMoreDetailPO();
materialMoreDetailPO.setBatchId(batchDetailFeignPO.getBatchId());
materialMoreDetailPO.setBatchDetailId(batchDetailFeignPO.getBatchDetailId());
materialMoreDetailPO.setBatchLabels(batchDetailFeignPO.getBatchLabels());
materialMoreDetailPO.setInputControl(batchDetailFeignPO.getInputControl());
materialMoreDetailPO.setAttributeFormat(batchDetailFeignPO.getAttributeFormat());
materialMoreDetailPO.setAttributeOption(batchDetailFeignPO.getAttributeOption());
materialMoreDetailPO.setRemark(batchDetailFeignPO.getRemark());
// 确保添加到列表中(使用batchDetailId来避免重复)
Long batchDetailId = batchDetailFeignPO.getBatchDetailId();
if (batchDetailId != null && !addedBatchDetailIds.contains(batchDetailId)) {
materialMoreDetailList.add(materialMoreDetailPO);
addedBatchDetailIds.add(batchDetailId);
}
// 根据fieldName或batchLabels从库存表中获取对应的字段值
if (inventoryPO != null) {
String fieldValue = null;
String usedFieldName = null;
// 优先使用fieldName(如果存在)
if (StringUtils.isNotBlank(batchDetailFeignPO.getFieldName())) {
usedFieldName = batchDetailFeignPO.getFieldName();
fieldValue = getFieldValueByFieldName(inventoryPO, usedFieldName);
log.info("批次属性 batchDetailId={}, fieldName={}, 从库存表获取到的值={}",
batchDetailFeignPO.getBatchDetailId(), usedFieldName, fieldValue);
}
// 如果fieldName为空,尝试根据batchLabels映射到字段名
else if (StringUtils.isNotBlank(batchDetailFeignPO.getBatchLabels())) {
String fieldNameByLabel = getFieldNameByBatchLabel(batchDetailFeignPO.getBatchLabels());
if (StringUtils.isNotBlank(fieldNameByLabel)) {
usedFieldName = fieldNameByLabel;
fieldValue = getFieldValueByFieldName(inventoryPO, usedFieldName);
log.info("批次属性 batchDetailId={}, batchLabels={}, 映射字段名={}, 从库存表获取到的值={}",
batchDetailFeignPO.getBatchDetailId(), batchDetailFeignPO.getBatchLabels(),
usedFieldName, fieldValue);
}
}
// 只有当获取到值时才更新attributeValue
if (fieldValue != null) {
materialMoreDetailPO.setAttributeValue(fieldValue);
log.info("设置更多属性:batchDetailId={}, batchLabels={}, attributeValue={}",
materialMoreDetailPO.getBatchDetailId(), materialMoreDetailPO.getBatchLabels(),
materialMoreDetailPO.getAttributeValue());
}
}
}
}
materialInventoryPO.setMaterialMoreDetailList(materialMoreDetailList);
log.info("物料库存 materialInventoryId={}, materialBaseInfoId={}, materialMoreDetailList大小={}",
materialInventoryPO.getMaterialInventoryId(), materialInventoryPO.getMaterialBaseInfoId(),
materialMoreDetailList != null ? materialMoreDetailList.size() : 0);
});
}
/**
* 根据字段名从对象中获取字段值(使用反射)
* @param obj 对象
* @param fieldName 字段名
* @return 字段值(转换为字符串)
*/
private String getFieldValueByFieldName(Object obj, String fieldName) {
if (obj == null || StringUtils.isBlank(fieldName)) {
return null;
}
try {
// 兼容:如果传的是下划线命名(数据库列名风格),先转成驼峰字段名再取
String normalizedFieldName = fieldName;
if (normalizedFieldName.contains("_")) {
normalizedFieldName = snakeToCamel(normalizedFieldName);
}
// 获取对象的Class
Class<?> clazz = obj.getClass();
// 尝试获取字段(包括父类字段)
Field field = null;
Class<?> currentClass = clazz;
while (currentClass != null && field == null) {
try {
field = currentClass.getDeclaredField(normalizedFieldName);
} catch (NoSuchFieldException e) {
currentClass = currentClass.getSuperclass();
}
}
if (field == null) {
log.warn("字段不存在:{}(normalized{}),对象类型:{}", fieldName, normalizedFieldName, clazz.getName());
return null;
}
// 设置可访问
field.setAccessible(true);
// 获取字段值
Object value = field.get(obj);
// 转换为字符串
if (value == null) {
log.info("字段 {} 的值为 null,对象类型:{}", normalizedFieldName, clazz.getName());
return null;
}
String result;
// 处理日期类型字段
if (value instanceof Date) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
result = sdf.format((Date) value);
} else {
result = value.toString();
}
log.info("通过反射获取字段值成功,字段名:{}(原始:{}),值:{},对象类型:{}",
normalizedFieldName, fieldName, result, clazz.getName());
return result;
} catch (Exception e) {
log.warn("通过反射获取字段值失败,字段名:{},对象类型:{},错误:{}", fieldName, obj.getClass().getName(), e.getMessage());
return null;
}
}
private String snakeToCamel(String snake) {
if (StringUtils.isBlank(snake)) {
return null;
}
String s = snake.trim().toLowerCase();
StringBuilder sb = new StringBuilder();
boolean upperNext = false;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '_') {
upperNext = true;
continue;
}
if (upperNext) {
sb.append(Character.toUpperCase(c));
upperNext = false;
} else {
sb.append(c);
}
}
return sb.toString();
}
/**
* 根据批次标签(batchLabels)映射到字段名
* @param batchLabel 批次标签
* @return 字段名,如果找不到映射则返回null
*/
private String getFieldNameByBatchLabel(String batchLabel) {
if (StringUtils.isBlank(batchLabel)) {
return null;
}
// 批次标签到字段名的映射关系
Map<String, String> labelToFieldNameMap = new HashMap<>();
labelToFieldNameMap.put("Invoice No.", "invoiceNo");
labelToFieldNameMap.put("Invoice No", "invoiceNo");
labelToFieldNameMap.put("发票号", "invoiceNo");
labelToFieldNameMap.put("Batch Ref NO's", "batchRefNo");
labelToFieldNameMap.put("Batch Ref NO", "batchRefNo");
labelToFieldNameMap.put("批次参考号", "batchRefNo");
labelToFieldNameMap.put("Sheet Ref NO's", "sheetRefNo");
labelToFieldNameMap.put("Sheet Ref NO", "sheetRefNo");
labelToFieldNameMap.put("单据参考号", "sheetRefNo");
labelToFieldNameMap.put("箱号/卡板号", "boxPalletNo");
labelToFieldNameMap.put("箱号", "boxPalletNo");
labelToFieldNameMap.put("卡板号", "boxPalletNo");
labelToFieldNameMap.put("生产日期", "productionDate");
labelToFieldNameMap.put("过期日期", "expiryDate");
labelToFieldNameMap.put("存货日期", "inventoryDate");
labelToFieldNameMap.put("扩展字段1", "extAttr1");
labelToFieldNameMap.put("扩展字段2", "extAttr2");
labelToFieldNameMap.put("扩展字段3", "extAttr3");
labelToFieldNameMap.put("扩展字段4", "extAttr4");
// 精确匹配
String fieldName = labelToFieldNameMap.get(batchLabel.trim());
if (StringUtils.isNotBlank(fieldName)) {
return fieldName;
}
// 模糊匹配(包含关系)
for (Map.Entry<String, String> entry : labelToFieldNameMap.entrySet()) {
if (batchLabel.contains(entry.getKey()) || entry.getKey().contains(batchLabel)) {
return entry.getValue();
}
}
return null;
}
@@ -99,4 +372,4 @@ public class InventoryAdjustmentRecordApplicationService {
public Boolean inventoryFrozenForAll(InventoryAdjustmentRecordDO inventoryAdjustmentRecordDO) {
return inventoryAdjustmentRecordDomainService.inventoryFrozenForAll(inventoryAdjustmentRecordDO);
}
}
}
@@ -11,7 +11,6 @@ import com.mhd.system.api.domain.cache.AssociationWarehouseCacheDO;
import com.mhd.system.api.domain.cache.SystemServiceCacheUtil;
import com.mhd.system.api.model.LoginUser;
import com.mhd.wms.domain.inventoryStandingDetail.service.InventoryStandingDetailDomainService;
import com.mhd.wms.domain.investigetionManageDetail.repository.po.InvestigetionManageDetailPO;
import com.mhd.wms.domain.materialInventory.repository.mapper.MaterialInventoryMapper;
import com.mhd.wms.domain.materialInventory.repository.po.MaterialInventoryPO;
import com.mhd.wms.domain.materialInventory.service.MaterialInventoryDomainService;
@@ -1080,8 +1080,10 @@ public class StockInOrderApplicationService {
// 货主信息:优先使用表头,如果表头为空则使用明细行
String shipperName = StringUtils.isNotBlank(headerInfo.getShipperName()) ? headerInfo.getShipperName() : h.getShipperName();
String shipperCode = StringUtils.isNotBlank(headerInfo.getShipperCode()) ? headerInfo.getShipperCode() : h.getShipperCode();
// 货主ID先设置为null,后续在shipperParam方法中根据名称或编号查找
order.setShipperId(null);
// 提前获取货主ID,用于查询物料基础信息时过滤
Long shipperId = getShipperIdByNameOrCode(shipperName, shipperCode);
// 货主ID先设置为获取到的值,后续在shipperParam方法中会再次确认
order.setShipperId(shipperId);
if (StringUtils.isNotBlank(shipperName)) {
order.setShipperName(shipperName);
}
@@ -1168,6 +1170,7 @@ public class StockInOrderApplicationService {
r.getWarehouseQuantity(), r.getInboundQuantity());
// 根据明细表中的字段查询物料基础信息(优先:料号 > 商品SKU码 > 商品名称)
// 注意:查询时必须加上货主ID条件,确保查询到的是该货主绑定的物料
Long materialBaseInfoId = null;
LoginUser currentLoginUser = SecurityUtils.getLoginUser();
Long topOrganizationId = currentLoginUser != null && currentLoginUser.getUserPo() != null
@@ -1180,14 +1183,20 @@ public class StockInOrderApplicationService {
if (topOrganizationId != null) {
queryDO.setTopOrganizationId(topOrganizationId);
}
log.info("尝试通过料号查询物料基础信息,料号: [{}], topOrganizationId: {}", r.getMaterialCode(), topOrganizationId);
// 加上货主ID条件,确保查询到的是该货主绑定的物料
if (shipperId != null) {
queryDO.setShipperId(shipperId);
}
log.info("尝试通过料号查询物料基础信息,料号: [{}], topOrganizationId: {}, shipperId: {}",
r.getMaterialCode(), topOrganizationId, shipperId);
List<MaterialBaseInfoPO> materialList = materialBaseInfoService.queryList(queryDO);
log.info("料号查询结果,查询到 {} 条记录", materialList != null ? materialList.size() : 0);
if (materialList != null && !materialList.isEmpty()) {
materialBaseInfoId = materialList.get(0).getMaterialBaseInfoId();
log.info("通过料号查询到物料基础信息,料号: {}, 物料ID: {}", r.getMaterialCode(), materialBaseInfoId);
log.info("通过料号查询到物料基础信息,料号: {}, 物料ID: {}, 货主ID: {}",
r.getMaterialCode(), materialBaseInfoId, shipperId);
} else {
log.warn("通过料号未查询到物料基础信息,料号: [{}]", r.getMaterialCode());
log.warn("通过料号未查询到物料基础信息,料号: [{}], 货主ID: [{}]", r.getMaterialCode(), shipperId);
}
} else {
log.warn("料号为空,跳过料号查询");
@@ -1200,14 +1209,20 @@ public class StockInOrderApplicationService {
if (topOrganizationId != null) {
queryDO.setTopOrganizationId(topOrganizationId);
}
log.info("尝试通过商品SKU码查询物料基础信息,SKU码: [{}], topOrganizationId: {}", r.getSkuCode(), topOrganizationId);
// 加上货主ID条件,确保查询到的是该货主绑定的物料
if (shipperId != null) {
queryDO.setShipperId(shipperId);
}
log.info("尝试通过商品SKU码查询物料基础信息,SKU码: [{}], topOrganizationId: {}, shipperId: {}",
r.getSkuCode(), topOrganizationId, shipperId);
List<MaterialBaseInfoPO> materialList = materialBaseInfoService.queryList(queryDO);
log.info("SKU码查询结果,查询到 {} 条记录", materialList != null ? materialList.size() : 0);
if (materialList != null && !materialList.isEmpty()) {
materialBaseInfoId = materialList.get(0).getMaterialBaseInfoId();
log.info("通过商品SKU码查询到物料基础信息,SKU码: {}, 物料ID: {}", r.getSkuCode(), materialBaseInfoId);
log.info("通过商品SKU码查询到物料基础信息,SKU码: {}, 物料ID: {}, 货主ID: {}",
r.getSkuCode(), materialBaseInfoId, shipperId);
} else {
log.warn("通过SKU码未查询到物料基础信息,SKU码: [{}]", r.getSkuCode());
log.warn("通过SKU码未查询到物料基础信息,SKU码: [{}], 货主ID: [{}]", r.getSkuCode(), shipperId);
}
} else if (materialBaseInfoId == null) {
log.warn("SKU码为空,跳过SKU码查询");
@@ -1220,14 +1235,20 @@ public class StockInOrderApplicationService {
if (topOrganizationId != null) {
queryDO.setTopOrganizationId(topOrganizationId);
}
log.info("尝试通过商品名称查询物料基础信息,商品名称: [{}], topOrganizationId: {}", r.getMaterialName(), topOrganizationId);
// 加上货主ID条件,确保查询到的是该货主绑定的物料
if (shipperId != null) {
queryDO.setShipperId(shipperId);
}
log.info("尝试通过商品名称查询物料基础信息,商品名称: [{}], topOrganizationId: {}, shipperId: {}",
r.getMaterialName(), topOrganizationId, shipperId);
List<MaterialBaseInfoPO> materialList = materialBaseInfoService.queryList(queryDO);
log.info("商品名称查询结果,查询到 {} 条记录", materialList != null ? materialList.size() : 0);
if (materialList != null && !materialList.isEmpty()) {
materialBaseInfoId = materialList.get(0).getMaterialBaseInfoId();
log.info("通过商品名称查询到物料基础信息,商品名称: {}, 物料ID: {}", r.getMaterialName(), materialBaseInfoId);
log.info("通过商品名称查询到物料基础信息,商品名称: {}, 物料ID: {}, 货主ID: {}",
r.getMaterialName(), materialBaseInfoId, shipperId);
} else {
log.warn("通过商品名称未查询到物料基础信息,商品名称: [{}]", r.getMaterialName());
log.warn("通过商品名称未查询到物料基础信息,商品名称: [{}], 货主ID: [{}]", r.getMaterialName(), shipperId);
}
} else if (materialBaseInfoId == null) {
log.warn("商品名称为空,跳过商品名称查询");
@@ -1486,231 +1507,166 @@ public class StockInOrderApplicationService {
}
/**
* @description 封装货主信息(货主信息就是客户
* @description 根据货主名称或编号获取货主ID(用于导入时提前获取货主ID
* @param shipperName 货主名称
* @param shipperCode 货主编号
* @return 货主ID,如果找不到则返回null
*/
private Long getShipperIdByNameOrCode(String shipperName, String shipperCode) {
if (StringUtils.isBlank(shipperName) && StringUtils.isBlank(shipperCode)) {
return null;
}
Long shipperId = null;
// 优先尝试:如果名称是纯数字,可能是误传的ID,直接按ID查询
if (StringUtils.isNotEmpty(shipperName) && shipperName.matches("\\d+")) {
try {
Long possibleId = Long.valueOf(shipperName);
AjaxResult ajaxResult = userServiceFeign.getInfo(possibleId);
if ("200".equals(String.valueOf(ajaxResult.get("code"))) && ajaxResult.get("data") != null) {
UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
if (userPo != null) {
shipperId = userPo.getUserId();
log.info("根据货主名称(实际为ID)找到货主ID:{}", shipperId);
return shipperId;
}
}
} catch (Exception e) {
log.debug("尝试将货主名称作为ID查询失败,货主名称:{},错误:{}", shipperName, e.getMessage());
}
}
// 如果仍未找到,尝试根据名称查询
if (shipperId == null && StringUtils.isNotEmpty(shipperName) && !shipperName.matches("\\d+")) {
try {
AjaxResult ajaxResult = userServiceFeign.getInfoByName(shipperName);
String code = String.valueOf(ajaxResult.get("code"));
if ("200".equals(code) && ajaxResult.get("data") != null) {
UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
if (userPo != null) {
shipperId = userPo.getUserId();
log.info("根据货主名称找到货主ID,货主名称:{},货主ID:{}", shipperName, shipperId);
return shipperId;
}
}
} catch (Exception e) {
log.debug("根据货主名称查询失败,货主名称:{},错误:{}", shipperName, e.getMessage());
}
}
// 如果仍未找到,尝试从货主列表中根据编号或名称查找
if (shipperId == null && (StringUtils.isNotEmpty(shipperName) || StringUtils.isNotEmpty(shipperCode))) {
try {
AjaxResult shipperListResult = userServiceFeign.userShipperListAll();
if ("200".equals(String.valueOf(shipperListResult.get("code"))) && shipperListResult.get("data") != null) {
Object data = shipperListResult.get("data");
List<Map<String, Object>> shipperList = null;
if (data instanceof List) {
@SuppressWarnings("unchecked")
List<Object> rawList = (List<Object>) data;
shipperList = new ArrayList<>();
for (Object item : rawList) {
if (item instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> mapItem = (Map<String, Object>) item;
shipperList.add(mapItem);
} else {
Map<String, Object> mapItem = JSON.parseObject(JSONObject.toJSONString(item), Map.class);
shipperList.add(mapItem);
}
}
} else {
String jsonStr = JSONObject.toJSONString(data);
shipperList = JSON.parseObject(jsonStr, new com.alibaba.fastjson.TypeReference<List<Map<String, Object>>>(){});
}
if (shipperList != null && !shipperList.isEmpty()) {
String normalizedShipperName = shipperName != null ? shipperName.trim() : "";
String normalizedShipperCode = shipperCode != null ? shipperCode.trim() : "";
for (Map<String, Object> shipper : shipperList) {
Object userId = shipper.get("userId");
Object userName = shipper.get("userName");
Object userCode = shipper.get("userCode");
Object userMemberCode = shipper.get("userMemberCode");
if (userName == null) {
userName = shipper.get("name");
}
if (userName == null) {
userName = shipper.get("shipperName");
}
boolean matched = false;
// 优先根据编号匹配
if (StringUtils.isNotEmpty(normalizedShipperCode)) {
String normalizedUserCode = userCode != null ? String.valueOf(userCode).trim() : "";
String normalizedUserMemberCode = userMemberCode != null ? String.valueOf(userMemberCode).trim() : "";
if (normalizedShipperCode.equals(normalizedUserCode) ||
normalizedShipperCode.equals(normalizedUserMemberCode)) {
matched = true;
}
}
// 如果编号不匹配,再根据名称匹配
if (!matched && StringUtils.isNotEmpty(normalizedShipperName) && userName != null) {
String normalizedUserName = String.valueOf(userName).trim();
if (normalizedShipperName.equals(normalizedUserName) ||
normalizedUserName.contains(normalizedShipperName)) {
matched = true;
}
}
if (matched && userId != null) {
shipperId = Long.valueOf(String.valueOf(userId));
log.info("从货主列表中找到货主ID,货主名称:{},货主编号:{},货主ID:{}",
shipperName, shipperCode, shipperId);
return shipperId;
}
}
}
}
} catch (Exception e) {
log.debug("从货主列表中查找货主ID失败,货主名称:{},货主编号:{},错误:{}",
shipperName, shipperCode, e.getMessage());
}
}
if (shipperId == null) {
log.warn("未找到货主ID,货主名称:{},货主编号:{}", shipperName, shipperCode);
}
return shipperId;
}
/**
* @description 封装货主信息(改为与出库单相同的简洁逻辑,使用入库单的字段shipperName
* @author ZhouGY
* @date 2024/5/9 20:43
* @param stockInOrderDO
*/
private void shipperParam(StockInOrderDO stockInOrderDO){
Long shipperId = stockInOrderDO.getShipperId();
String shipperName = stockInOrderDO.getShipperName();
String shipperCode = stockInOrderDO.getShipperCode();
// 如果货主ID为空,尝试根据货主名称或编号查找
if (shipperId == null) {
// 优先尝试:如果名称是纯数字,可能是误传的ID,直接按ID查询
if (StringUtils.isNotEmpty(shipperName) && shipperName.matches("\\d+")) {
try {
Long possibleId = Long.valueOf(shipperName);
AjaxResult ajaxResult = userServiceFeign.getInfo(possibleId);
if ("200".equals(String.valueOf(ajaxResult.get("code"))) && ajaxResult.get("data") != null) {
UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
if (userPo != null) {
shipperId = userPo.getUserId();
log.info("根据货主名称(实际为ID)找到货主ID:{}", shipperId);
}
}
} catch (Exception e) {
log.warn("尝试将货主名称作为ID查询失败,货主名称:{},错误:{}", shipperName, e.getMessage());
}
if (StringUtils.isEmpty(shipperName)) return;
if (!shipperName.matches("\\d+")) {
// 按名称查询
AjaxResult ajaxResult = userServiceFeign.getInfoByName(shipperName);
if(!"200".equals(String.valueOf(ajaxResult.get("code")))){
throw new ServiceException("获取货主信息失败");
}
// 如果仍未找到,尝试根据名称查询(使用 getInfoByName 接口,更高效)
// 注意:如果接口返回404,说明接口可能未实现,继续尝试从列表中查找
if (shipperId == null && StringUtils.isNotEmpty(shipperName) && !shipperName.matches("\\d+")) {
try {
AjaxResult ajaxResult = userServiceFeign.getInfoByName(shipperName);
String code = String.valueOf(ajaxResult.get("code"));
if ("200".equals(code) && ajaxResult.get("data") != null) {
UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
if (userPo != null) {
shipperId = userPo.getUserId();
log.info("根据货主名称找到货主ID,货主名称:{},货主ID:{}", shipperName, shipperId);
}
} else {
// 接口返回非200(可能是404),记录日志但继续尝试其他方式
log.debug("getInfoByName接口返回非200,货主名称:{},返回码:{},将继续尝试从列表中查找", shipperName, code);
}
} catch (Exception e) {
// 接口调用异常(包括404),记录日志但继续尝试其他方式
log.debug("根据货主名称查询失败(可能是接口未实现),货主名称:{},错误:{},将继续尝试从列表中查找", shipperName, e.getMessage());
}
UserPo userPo = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
stockInOrderDO.setShipperId(userPo.getUserId());
stockInOrderDO.setShipperCode(userPo.getUserMemberCode());
stockInOrderDO.setShipperName(userPo.getUserName());
} else {
// 按ID查询
AjaxResult ajaxResult = userServiceFeign.getInfo(Long.valueOf(shipperName));
if(!"200".equals(String.valueOf(ajaxResult.get("code")))){
throw new ServiceException("获取货主信息失败");
}
// 如果仍未找到,尝试从货主列表中根据编号或名称查找(兜底方案)
if (shipperId == null && (StringUtils.isNotEmpty(shipperName) || StringUtils.isNotEmpty(shipperCode))) {
try {
log.debug("开始从货主列表中查找,货主名称:{},货主编号:{}", shipperName, shipperCode);
AjaxResult shipperListResult = userServiceFeign.userShipperListAll();
if ("200".equals(String.valueOf(shipperListResult.get("code"))) && shipperListResult.get("data") != null) {
Object data = shipperListResult.get("data");
List<Map<String, Object>> shipperList = null;
// 尝试解析为列表
if (data instanceof List) {
@SuppressWarnings("unchecked")
List<Object> rawList = (List<Object>) data;
shipperList = new ArrayList<>();
for (Object item : rawList) {
if (item instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> mapItem = (Map<String, Object>) item;
shipperList.add(mapItem);
} else {
// 如果不是Map,尝试转换为Map
Map<String, Object> mapItem = JSON.parseObject(JSONObject.toJSONString(item), Map.class);
shipperList.add(mapItem);
}
}
} else {
// 如果不是列表,尝试转换为列表
String jsonStr = JSONObject.toJSONString(data);
shipperList = JSON.parseObject(jsonStr, new com.alibaba.fastjson.TypeReference<List<Map<String, Object>>>(){});
}
if (shipperList != null && !shipperList.isEmpty()) {
log.debug("货主列表大小:{},开始匹配查找,查找货主名称:{},货主编号:{}",
shipperList.size(), shipperName, shipperCode);
// 输出前3个货主的详细信息,用于调试
if (log.isDebugEnabled() && shipperList.size() > 0) {
int debugCount = Math.min(3, shipperList.size());
for (int i = 0; i < debugCount; i++) {
Map<String, Object> debugShipper = shipperList.get(i);
log.debug("货主列表示例[{}]:所有字段={}", i, debugShipper.keySet());
log.debug("货主列表示例[{}]userId={}, userName={}, userCode={}, userMemberCode={}, name={}, shipperName={}",
i,
debugShipper.get("userId"),
debugShipper.get("userName"),
debugShipper.get("userCode"),
debugShipper.get("userMemberCode"),
debugShipper.get("name"),
debugShipper.get("shipperName"));
}
}
// 标准化输入的货主名称和编号(去除空格,用于匹配)
String normalizedShipperName = shipperName != null ? shipperName.trim() : "";
String normalizedShipperCode = shipperCode != null ? shipperCode.trim() : "";
for (Map<String, Object> shipper : shipperList) {
Object userId = shipper.get("userId");
Object userName = shipper.get("userName");
Object userCode = shipper.get("userCode");
Object userMemberCode = shipper.get("userMemberCode");
// 尝试多个可能的字段名(按优先级顺序)
if (userName == null) {
userName = shipper.get("name");
}
if (userName == null) {
userName = shipper.get("shipperName");
}
if (userName == null) {
userName = shipper.get("userName");
}
// 尝试其他可能的字段名
if (userName == null) {
userName = shipper.get("customerName");
}
if (userName == null) {
userName = shipper.get("companyName");
}
boolean matched = false;
// 优先根据编号匹配(更准确)
if (StringUtils.isNotEmpty(normalizedShipperCode)) {
String normalizedUserCode = userCode != null ? String.valueOf(userCode).trim() : "";
String normalizedUserMemberCode = userMemberCode != null ? String.valueOf(userMemberCode).trim() : "";
if (normalizedShipperCode.equals(normalizedUserCode) ||
normalizedShipperCode.equals(normalizedUserMemberCode)) {
matched = true;
log.debug("通过编号匹配成功,货主编号:{},货主ID:{}", normalizedShipperCode, userId);
}
}
// 如果编号不匹配,再根据名称匹配(支持去除空格后匹配)
if (!matched && StringUtils.isNotEmpty(normalizedShipperName) && userName != null) {
String normalizedUserName = String.valueOf(userName).trim();
// 精确匹配(优先)
if (normalizedShipperName.equals(normalizedUserName)) {
matched = true;
log.debug("通过名称精确匹配成功,货主名称:{},货主ID:{}", normalizedShipperName, userId);
}
// 如果精确匹配失败,尝试包含匹配(列表中的名称包含导入的名称,例如列表中是"珠海百思科鞋材有限公司",导入的是"百思科"
// 注意:这里不使用反向包含匹配(导入的名称包含列表中的名称),因为这样会误匹配(例如导入"珠海百思科鞋材有限公司"会匹配到"百思科"
if (!matched && normalizedUserName.contains(normalizedShipperName)) {
matched = true;
log.debug("通过名称包含匹配成功,货主名称:{},列表中的名称:{},货主ID:{}",
normalizedShipperName, normalizedUserName, userId);
}
// 不再使用反向包含匹配,避免误匹配
// 例如:导入"珠海百思科鞋材有限公司"不应该匹配到列表中的"百思科"
}
if (matched && userId != null) {
shipperId = Long.valueOf(String.valueOf(userId));
log.info("从货主列表中找到货主ID,货主名称:{},货主编号:{},货主ID:{}",
shipperName, shipperCode, shipperId);
break;
}
}
if (shipperId == null) {
// 输出所有货主名称,帮助排查
List<String> allShipperNames = new ArrayList<>();
for (Map<String, Object> shipper : shipperList) {
Object name = shipper.get("userName");
if (name == null) {
name = shipper.get("name");
}
if (name == null) {
name = shipper.get("shipperName");
}
if (name != null) {
allShipperNames.add(String.valueOf(name));
}
}
log.warn("从货主列表中未找到匹配的货主,货主名称:{},货主编号:{},列表大小:{},所有货主名称:{}",
shipperName, shipperCode, shipperList.size(), allShipperNames);
}
} else {
log.warn("货主列表为空或解析失败");
}
} else {
log.warn("获取货主列表失败,返回码:{}", shipperListResult.get("code"));
}
} catch (Exception e) {
log.error("从货主列表中查找货主ID失败,货主名称:{},货主编号:{},错误:{}", shipperName, shipperCode, e.getMessage(), e);
}
}
// 如果仍然找不到货主ID,抛出异常
if (shipperId == null) {
String errorMsg = "货主ID不能为空(货主信息就是客户)";
if (StringUtils.isNotEmpty(shipperName)) {
errorMsg += "。已提供货主名称:" + shipperName + ",但未找到对应的货主ID,请确保货主名称正确或直接提供货主ID";
} else if (StringUtils.isNotEmpty(shipperCode)) {
errorMsg += "。已提供货主编号:" + shipperCode + ",但未找到对应的货主ID,请确保货主编号正确或直接提供货主ID";
} else {
errorMsg += "。请提供货主ID、货主名称或货主编号";
}
throw new ServiceException(errorMsg);
}
stockInOrderDO.setShipperId(shipperId);
}
// 根据货主ID获取详细信息
AjaxResult ajaxResult = userServiceFeign.getInfo(shipperId);
if(!"200".equals(String.valueOf(ajaxResult.get("code")))){
String errorMsg = ajaxResult.get("msg") != null ? String.valueOf(ajaxResult.get("msg")) : "未知错误";
throw new ServiceException("获取货主信息失败(货主ID: " + shipperId + "),错误信息: " + errorMsg);
}
UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
if (userPo == null) {
throw new ServiceException("获取货主信息失败:返回数据为空(货主ID: " + shipperId + "");
}
stockInOrderDO.setShipperCode(userPo.getUserMemberCode());
// 如果原始shipperName不为空,保留原始值(导入时读取的客户名称应该保留)
// 只有在原始shipperName为空时,才使用查询到的userName
if (StringUtils.isBlank(stockInOrderDO.getShipperName())) {
UserPo userPo = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
stockInOrderDO.setShipperId(userPo.getUserId());
stockInOrderDO.setShipperCode(userPo.getUserMemberCode());
stockInOrderDO.setShipperName(userPo.getUserName());
}
}
@@ -1,12 +1,17 @@
package com.mhd.wms.domain.inventoryAdjustmentRecord.repository.po;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.mhd.common.core.annotation.Excel;
import com.mhd.common.core.web.domain.BaseVOEntity;
import com.mhd.wms.domain.materialMoreDetail.repository.po.MaterialMoreDetailPO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
@@ -147,6 +152,58 @@ public class InventoryAdjustmentRecordPO extends BaseVOEntity {
@Excel(name = "调整后冻结数量")
private BigDecimal freezeAfterQuantity;
@ApiModelProperty("Batch Ref NO's")
@Excel(name = "Batch Ref NO's")
private String batchRefNo;
@ApiModelProperty("Sheet Ref NO's")
@Excel(name = "Sheet Ref NO's")
private String sheetRefNo;
@ApiModelProperty("箱号/卡板号")
@Excel(name = "箱号/卡板号")
private String boxPalletNo;
@ApiModelProperty("扩展字段1")
@Excel(name = "扩展字段1")
private String extAttr1;
@ApiModelProperty("扩展字段2")
@Excel(name = "扩展字段2")
private String extAttr2;
@ApiModelProperty("生产日期")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "生产日期", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date productionDate;
@ApiModelProperty("过期日期")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "过期日期", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date expiryDate;
@ApiModelProperty("存货日期")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "存货日期", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date inventoryDate;
@ApiModelProperty("ExtAttr3")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "ExtAttr3", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date extAttr3;
@ApiModelProperty("ExtAttr4")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "ExtAttr4", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date extAttr4;
@ApiModelProperty("物料更多属性列表(批次属性)")
private List<MaterialMoreDetailPO> materialMoreDetailList;
}
}
@@ -74,6 +74,16 @@ public interface IOutMaterialDetailService extends IService<OutMaterialDetail>
*/
public StockOutOrderPO batchCancelAssignUpdate(String outOrderNumber, List<OutMaterialDetailDO> outMaterialDetailDOList);
/**
* @description 手动取消分配批量修改物流明细(弹窗方式,类似batchAssignUpdate
* @author ZhouGY
* @date 2024/5/22 9:27
* @param outOrderNumber
* @param outMaterialDetailDOList
* @return StockOutOrderPO
*/
public StockOutOrderPO batchManualCancelAssignUpdate(String outOrderNumber, List<OutMaterialDetailDO> outMaterialDetailDOList);
/**
* @description 拣货批量修改物流明细
* @author ZhouGY