Commit 4d2dea9b by yubin

导入无库存插入-库存 加导入手动标识 导入日志

parent c5a19854
...@@ -117,5 +117,5 @@ public interface InventoryMapper ...@@ -117,5 +117,5 @@ public interface InventoryMapper
public List<java.util.Map<String, String>> selectInventoryTopTenByAmount(); public List<java.util.Map<String, String>> selectInventoryTopTenByAmount();
public List<java.util.Map<String, String>> selectInventoryTopTenByQuantity(); public List<java.util.Map<String, String>> selectInventoryTopTenByQuantity();
public void batchUpdateInventory(List<Inventory> inventoryList); public int batchUpdateInventory(List<Inventory> inventoryList);
} }
...@@ -21,8 +21,6 @@ import org.springframework.beans.BeanUtils; ...@@ -21,8 +21,6 @@ import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import java.util.*; import java.util.*;
...@@ -31,11 +29,12 @@ import java.util.stream.Collectors; ...@@ -31,11 +29,12 @@ import java.util.stream.Collectors;
/** /**
* 出库单主Service业务层处理 * 出库单主Service业务层处理
* 最终修复版: * 最终适配版:
* 1. 合并维度调整为「物料ID+库存类型+库位ID」,确保库位信息准确 * 1. 合并维度「物料ID+库存类型+库位ID」,支持相同维度多库存ID遍历扣减
* 2. 扣减时按该维度分组,统一收集记录后合并 * 2. 库存加载改为按维度收集所有库存,扣减时按数量从多到少排序
* 3. 修复跨场景(无库位→有库位)扣减同一物料+库存类型的合并逻辑 * 3. 无库位明细拆分精准匹配实际扣减的库存ID+数量
* 4. 新增相同库存维度的明细合并逻辑,插入前合并为一条记录 * 4. 缓存与数据库实时同步,解决数据不一致问题
* 5. 合并/扣减/拆分逻辑完全对齐维度,杜绝数据错乱
* *
* @author ruoyi * @author ruoyi
* @date 2025-12-03 * @date 2025-12-03
...@@ -101,7 +100,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -101,7 +100,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
outboundOrders.setCreateTime(DateUtils.getNowDate()); outboundOrders.setCreateTime(DateUtils.getNowDate());
outboundOrders.setCreateUserCode(SystemUtils.getUserName()); outboundOrders.setCreateUserCode(SystemUtils.getUserName());
outboundOrders.setId(UUID.randomUUID().toString()); outboundOrders.setId(UUID.randomUUID().toString());
outboundOrders.setIsImport(0l); outboundOrders.setIsImport(0L);
int rows = outboundOrdersMapper.insertOutboundOrders(outboundOrders); int rows = outboundOrdersMapper.insertOutboundOrders(outboundOrders);
insertOutboundOrderItems(outboundOrders); insertOutboundOrderItems(outboundOrders);
...@@ -117,7 +116,14 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -117,7 +116,14 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
@Transactional @Transactional
@Override @Override
public int updateOutboundOrders(OutboundOrders outboundOrders) { public int updateOutboundOrders(OutboundOrders outboundOrders) {
throw new ServiceException("当前系统仅支持新增出库单,不支持修改操作"); outboundOrdersMapper.deleteOutboundOrderItemsByOrderId(outboundOrders.getId());
outboundOrderLogMapper.deleteOutboundOrderLogByOrdersId(outboundOrders.getId());
outboundOrders.setUpdateUserCode(SystemUtils.getUserName());
outboundOrders.setUpdateTime(DateUtils.getNowDate());
insertOutboundOrderItems(outboundOrders);
return outboundOrdersMapper.updateOutboundOrders(outboundOrders);
} }
/** /**
...@@ -176,19 +182,16 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -176,19 +182,16 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
outboundOrders.setUpdateUserCode(updateUser); outboundOrders.setUpdateUserCode(updateUser);
outboundOrdersMapper.updateOutboundOrders(outboundOrders); outboundOrdersMapper.updateOutboundOrders(outboundOrders);
loadInventoryTOIdMap(); inventoryService.ship(outboundOrderItems);
// 3. 执行库存扣减(无库位不足时扣有库位)
this.deductInventory(outboundOrderItems, updateUser, updateTime);
return 1; return 1;
} }
/** /**
* 核心库存扣减逻辑(最终修复版) * 核心库存扣减逻辑(最终适配版)
* 1. 扣减维度:物料ID+库存类型+库位ID(统一维度,跨场景合并) * 1. 扣减维度:物料ID+库存类型+库位ID
* 2. 扣减时先按该维度分组,再累计扣减数量 * 2. 相同维度多库存:按数量从多到少遍历扣减,支持全部扣完
* 3. 收集记录时按该维度统一收集,合并器仅做最终校验 * 3. 无库位→有库位:自动匹配所有可用库位库存,精准扣减
* 4. 扣减记录按单库存ID生成,支持后续明细精准拆分
*/ */
private Map<String, List<Map<String, Object>>> deductInventory(List<OutboundOrderItems> outboundOrderItems, String updateUser, Date updateTime) { private Map<String, List<Map<String, Object>>> deductInventory(List<OutboundOrderItems> outboundOrderItems, String updateUser, Date updateTime) {
if (CollectionUtils.isEmpty(outboundOrderItems)) { if (CollectionUtils.isEmpty(outboundOrderItems)) {
...@@ -196,8 +199,8 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -196,8 +199,8 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
} }
Map<String, List<Map<String, Object>>> deductRecordMap = new HashMap<>(); Map<String, List<Map<String, Object>>> deductRecordMap = new HashMap<>();
// 预加载库存:按「物料ID+库存类型+库位ID」分组(核心调整) // 预加载库存:按「物料ID+库存类型+库位ID」分组,保存所有库存对象
Map<String, Inventory> inventoryFullMap = this.loadInventoryFullMap(); Map<String, List<Inventory>> inventoryGroupMap = this.loadInventoryGroupMap();
Map<String, Long> deductQtyMap = this.buildDeductQtyMap(outboundOrderItems); Map<String, Long> deductQtyMap = this.buildDeductQtyMap(outboundOrderItems);
// 库存更新Map(最终去重,保留最终状态) // 库存更新Map(最终去重,保留最终状态)
...@@ -219,19 +222,17 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -219,19 +222,17 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
.orElse(null); .orElse(null);
Long remainDeductQty = totalDeductQty; Long remainDeductQty = totalDeductQty;
// 核心:按「物料ID+库存类型+库位ID」分组扣减(先处理无库位,再处理有库位) // 核心:按维度分组扣减(先无库位,后有库位)
List<Map<String, Object>> tempDeductRecords = new ArrayList<>(); List<Map<String, Object>> tempDeductRecords = new ArrayList<>();
// 步骤1:先扣指定维度的库存(无库位/有库位)
if (StringUtils.isBlank(locationId)) { if (StringUtils.isBlank(locationId)) {
// 无库位:先扣「物料+库存类型+空库位」的库存 // 步骤1:扣无库位库存(同维度所有库存)
String noLocKey = buildInventoryKey(materialId, "", inventoryType); String noLocKey = buildInventoryKey(materialId, "", inventoryType);
remainDeductQty = deductByInventoryKey(noLocKey, remainDeductQty, updateUser, updateTime, inventoryFullMap, toUpdateInventoryMap, tempDeductRecords); remainDeductQty = deductByInventoryGroup(noLocKey, remainDeductQty, updateUser, updateTime, inventoryGroupMap, toUpdateInventoryMap, tempDeductRecords);
// 无库位不足,扣「物料+库存类型+任意有库位」的库存 // 步骤2:无库位不足,扣同物料+库存类型的所有有库位库存
if (remainDeductQty > 0) { if (remainDeductQty > 0) {
// 筛选该物料+库存类型的所有有库位库存 List<String> hasLocKeys = inventoryGroupMap.keySet().stream()
List<String> hasLocKeys = inventoryFullMap.keySet().stream()
.filter(k -> { .filter(k -> {
String[] parts = k.split("_"); String[] parts = k.split("_");
return parts.length >= 3 return parts.length >= 3
...@@ -241,18 +242,25 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -241,18 +242,25 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
}) })
.collect(Collectors.toList()); .collect(Collectors.toList());
// 有库位库存按总数量从多到少排序(优先扣减库存充足的库位)
hasLocKeys.sort((k1, k2) -> {
Long qty1 = inventoryGroupMap.get(k1).stream().mapToLong(inv -> Optional.ofNullable(inv.getQuantity()).orElse(0L)).sum();
Long qty2 = inventoryGroupMap.get(k2).stream().mapToLong(inv -> Optional.ofNullable(inv.getQuantity()).orElse(0L)).sum();
return Long.compare(qty2, qty1);
});
for (String hasLocKey : hasLocKeys) { for (String hasLocKey : hasLocKeys) {
if (remainDeductQty <= 0) break; if (remainDeductQty <= 0) break;
remainDeductQty = deductByInventoryKey(hasLocKey, remainDeductQty, updateUser, updateTime, inventoryFullMap, toUpdateInventoryMap, tempDeductRecords); remainDeductQty = deductByInventoryGroup(hasLocKey, remainDeductQty, updateUser, updateTime, inventoryGroupMap, toUpdateInventoryMap, tempDeductRecords);
} }
} }
} else { } else {
// 有库位:扣指定「物料+库存类型+库位ID」的库存 // 有库位:扣指定维度库存
String targetKey = buildInventoryKey(materialId, locationId, inventoryType); String targetKey = buildInventoryKey(materialId, locationId, inventoryType);
remainDeductQty = deductByInventoryKey(targetKey, remainDeductQty, updateUser, updateTime, inventoryFullMap, toUpdateInventoryMap, tempDeductRecords); remainDeductQty = deductByInventoryGroup(targetKey, remainDeductQty, updateUser, updateTime, inventoryGroupMap, toUpdateInventoryMap, tempDeductRecords);
} }
// 步骤2:剩余部分扣负数(最后一个库存 // 步骤3:剩余数量强制扣减(允许库存负数
if (remainDeductQty > 0 && !tempDeductRecords.isEmpty()) { if (remainDeductQty > 0 && !tempDeductRecords.isEmpty()) {
Map<String, Object> lastRecord = tempDeductRecords.get(tempDeductRecords.size() - 1); Map<String, Object> lastRecord = tempDeductRecords.get(tempDeductRecords.size() - 1);
String lastInvId = (String) lastRecord.get("inventoryId"); String lastInvId = (String) lastRecord.get("inventoryId");
...@@ -262,119 +270,90 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -262,119 +270,90 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
} }
// 累计扣减负数数量 // 累计扣减负数数量
Long finalDeduct = remainDeductQty; lastInv.setQuantity(lastInv.getQuantity() - remainDeductQty);
lastInv.setQuantity(lastInv.getQuantity() - finalDeduct);
lastInv.setInventoryStatus(0L); lastInv.setInventoryStatus(0L);
lastInv.setUpdateBy(updateUser); lastInv.setUpdateBy(updateUser);
lastInv.setUpdateTime(updateTime); lastInv.setUpdateTime(updateTime);
toUpdateInventoryMap.put(lastInvId, lastInv); toUpdateInventoryMap.put(lastInvId, lastInv);
// 合并到最后一条记录 // 更新扣减记录
lastRecord.put("deductQty", (Long) lastRecord.get("deductQty") + finalDeduct); lastRecord.put("deductQty", (Long) lastRecord.get("deductQty") + remainDeductQty);
remainDeductQty = 0L; remainDeductQty = 0L;
} }
// 步骤3:统一合并(按物料+库存类型+库位ID // 步骤4:按明细ID归集扣减记录(不合并,保持单库存ID粒度
if (itemId != null && !tempDeductRecords.isEmpty()) { if (itemId != null && !tempDeductRecords.isEmpty()) {
List<Map<String, Object>> mergedRecords = mergeDeductRecords(tempDeductRecords); deductRecordMap.put(itemId, tempDeductRecords);
deductRecordMap.put(itemId, mergedRecords);
} }
// 校验是否扣减完成 // 校验扣减完成
if (remainDeductQty > 0) { if (remainDeductQty > 0) {
throw new ServiceException(String.format("物料[%s]库存类型[%s]扣减失败,剩余%d数量未扣减", materialId, inventoryType, remainDeductQty)); throw new ServiceException(String.format("物料[%s]库存类型[%s]扣减失败,剩余%d数量未扣减", materialId, inventoryType, remainDeductQty));
} }
} }
// 批量更新库存(最终去重) // 批量更新库存 + 刷新缓存
if (!toUpdateInventoryMap.isEmpty()) { if (!toUpdateInventoryMap.isEmpty()) {
List<Inventory> needUpdateList = new ArrayList<>(toUpdateInventoryMap.values()); List<Inventory> needUpdateList = new ArrayList<>(toUpdateInventoryMap.values());
inventoryMapper.batchUpdateInventory(needUpdateList); inventoryMapper.batchUpdateInventory(needUpdateList);
inventoryService.RefreshInventory(needUpdateList.stream().map(Inventory::getId).distinct().collect(Collectors.toList())); // 刷新缓存:删除旧缓存,重新加载
needUpdateList.forEach(inv -> {
String cacheKey = buildInventoryKey(inv.getMaterialId(), inv.getLocationId(), inv.getInventoryType().toString());
InventoryCache.removeInventory(cacheKey, inv.getId());
InventoryCache.addInventory(cacheKey, inv);
});
} }
return deductRecordMap; return deductRecordMap;
} }
/** /**
* 按「物料ID+库位ID+库存类型」扣减指定库存 * 按维度分组扣减库存(核心适配:遍历同维度所有库存)
* @param inventoryKey 库存Key(物料ID_库位ID_库存类型) * @param inventoryKey 维度Key
* @param deductQty 待扣减数量 * @param deductQty 待扣减数量
* @return 剩余未扣减数量 * @return 剩余未扣减数量
*/ */
private Long deductByInventoryKey(String inventoryKey, Long deductQty, String updateUser, Date updateTime, private Long deductByInventoryGroup(String inventoryKey, Long deductQty, String updateUser, Date updateTime,
Map<String, Inventory> inventoryFullMap, Map<String, Inventory> toUpdateInventoryMap, Map<String, List<Inventory>> inventoryGroupMap, Map<String, Inventory> toUpdateInventoryMap,
List<Map<String, Object>> tempDeductRecords) { List<Map<String, Object>> tempDeductRecords) {
Inventory inv = inventoryFullMap.get(inventoryKey); List<Inventory> invList = inventoryGroupMap.getOrDefault(inventoryKey, new ArrayList<>());
if (inv == null) { if (CollectionUtils.isEmpty(invList)) {
return deductQty; return deductQty;
} }
// 同维度库存按数量从多到少排序(优先扣减数量多的,减少拆分次数)
invList.sort((a, b) -> {
Long qtyA = Optional.ofNullable(a.getQuantity()).orElse(0L);
Long qtyB = Optional.ofNullable(b.getQuantity()).orElse(0L);
return Long.compare(qtyB, qtyA);
});
Long remainDeduct = deductQty;
for (Inventory inv : invList) {
if (remainDeduct <= 0) break;
Long currentQty = Optional.ofNullable(inv.getQuantity()).orElse(0L); Long currentQty = Optional.ofNullable(inv.getQuantity()).orElse(0L);
Long canDeduct = Math.min(deductQty, currentQty); Long canDeduct = Math.min(remainDeduct, currentQty);
// 更新库存状态 // 更新库存对象
inv.setQuantity(currentQty - canDeduct); inv.setQuantity(currentQty - canDeduct);
inv.setInventoryStatus(inv.getQuantity() <= 0 ? 0L : 1L); inv.setInventoryStatus(inv.getQuantity() > 0 ? 1L : 0L);
inv.setUpdateBy(updateUser); inv.setUpdateBy(updateUser);
inv.setUpdateTime(updateTime); inv.setUpdateTime(updateTime);
toUpdateInventoryMap.put(inv.getId(), inv); toUpdateInventoryMap.put(inv.getId(), inv);
// 收集扣减记录(按统一维度 // 生成单库存ID的扣减记录(关键:不再合并库存ID
Map<String, Object> record = buildDeductRecord(inv, inv.getInventoryType().toString(), canDeduct); Map<String, Object> record = buildDeductRecord(inv, inv.getInventoryType().toString(), canDeduct);
tempDeductRecords.add(record); tempDeductRecords.add(record);
// 返回剩余未扣减数量 remainDeduct -= canDeduct;
return deductQty - canDeduct;
}
/**
* 合并同一「物料ID+库存类型+库位ID」的扣减记录(最终版)
* 核心:按「物料ID_库位ID_库存类型」合并,保留库位信息准确性
*/
private List<Map<String, Object>> mergeDeductRecords(List<Map<String, Object>> deductRecords) {
if (CollectionUtils.isEmpty(deductRecords)) {
return Collections.emptyList();
}
// 合并Key:物料ID_库位ID_库存类型
Map<String, Map<String, Object>> mergeMap = new LinkedHashMap<>();
for (Map<String, Object> record : deductRecords) {
String materialId = (String) record.get("materialId");
String locationId = (String) record.get("locationId");
String inventoryType = (String) record.get("inventoryType");
Long deductQty = (Long) record.get("deductQty");
if (StringUtils.isBlank(materialId) || StringUtils.isBlank(inventoryType) || deductQty <= 0) {
continue;
} }
String mergeKey = buildInventoryKey(materialId, locationId, inventoryType); return remainDeduct;
if (mergeMap.containsKey(mergeKey)) {
Map<String, Object> existRecord = mergeMap.get(mergeKey);
existRecord.put("deductQty", (Long) existRecord.get("deductQty") + deductQty);
} else {
Map<String, Object> newRecord = new HashMap<>(record);
mergeMap.put(mergeKey, newRecord);
}
}
return new ArrayList<>(mergeMap.values());
}
/**
* 构建库存Key:物料ID_库位ID_库存类型
*/
private String buildInventoryKey(String materialId, String locationId, String inventoryType) {
return String.join("_",
Optional.ofNullable(materialId).orElse(""),
Optional.ofNullable(locationId).orElse(""),
Optional.ofNullable(inventoryType).orElse("")
);
} }
/** /**
* 构建扣减记录 * 构建扣减记录(单库存ID粒度)
*/ */
private Map<String, Object> buildDeductRecord(Inventory inv, String inventoryType, Long deductQty) { private Map<String, Object> buildDeductRecord(Inventory inv, String inventoryType, Long deductQty) {
Map<String, Object> record = new HashMap<>(); Map<String, Object> record = new HashMap<>();
...@@ -387,25 +366,26 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -387,25 +366,26 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
} }
/** /**
* 预加载库存全量Map(按「物料ID_库位ID_库存类型」为Key * 预加载库存分组Map(按维度Key分组,保存所有库存对象
*/ */
private Map<String, Inventory> loadInventoryFullMap() { private Map<String, List<Inventory>> loadInventoryGroupMap() {
Collection<Inventory> allInventory = InventoryCache.getAll().values(); // 1. 用你现有的selectInventoryList查全量可用库存(传空条件=查所有)
if (CollectionUtils.isEmpty(allInventory)) { Inventory query = new Inventory();
return Collections.emptyMap(); query.setInventoryStatus(1L); // 只查可用状态库存
} query.setIsUsed(1L); // 只查启用的库存
List<Inventory> allInventory = inventoryMapper.selectInventoryList(query);
return allInventory.stream()
.collect(Collectors.toMap( // 2. 按维度分组(和你原有逻辑完全一致)
inv -> buildInventoryKey( Map<String, List<Inventory>> inventoryGroupMap = new LinkedHashMap<>();
for (Inventory inv : allInventory) {
String key = buildInventoryKey(
inv.getMaterialId(), inv.getMaterialId(),
inv.getLocationId(), inv.getLocationId(),
Optional.ofNullable(inv.getInventoryType()).map(String::valueOf).orElse("") Optional.ofNullable(inv.getInventoryType()).map(String::valueOf).orElse("")
), );
inv -> inv, inventoryGroupMap.computeIfAbsent(key, k -> new ArrayList<>()).add(inv);
(k1, k2) -> k1, // 重复Key保留第一个 }
LinkedHashMap::new return inventoryGroupMap;
));
} }
/** /**
...@@ -433,6 +413,17 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -433,6 +413,17 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
); );
} }
/**
* 构建库存Key:物料ID_库位ID_库存类型
*/
private String buildInventoryKey(String materialId, String locationId, String inventoryType) {
return String.join("_",
Optional.ofNullable(materialId).orElse(""),
Optional.ofNullable(locationId).orElse(""),
Optional.ofNullable(inventoryType).orElse("")
);
}
@Override @Override
public List<Map<String, String>> outboundOrdersTopTenByQuantity() { public List<Map<String, String>> outboundOrdersTopTenByQuantity() {
return outboundOrdersMapper.SelectOutboundOrdersMaterialsTopTenByQuantity(); return outboundOrdersMapper.SelectOutboundOrdersMaterialsTopTenByQuantity();
...@@ -464,7 +455,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -464,7 +455,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
throw new RuntimeException("库存被修改请重新确认"); throw new RuntimeException("库存被修改请重新确认");
} }
// 合并相同库存维度的明细记录(简化版 // 合并相同维度明细(仅合并数量,库存ID不拼接
List<OutboundOrderItems> mergedItemsList = mergeSameInventoryItems(outboundOrderItemsList); List<OutboundOrderItems> mergedItemsList = mergeSameInventoryItems(outboundOrderItemsList);
// 为明细设置订单ID和主键ID // 为明细设置订单ID和主键ID
...@@ -485,7 +476,15 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -485,7 +476,15 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
BeanUtils.copyProperties(items, log); BeanUtils.copyProperties(items, log);
log.setOrderId(items.getOutboundOrderId()); log.setOrderId(items.getOutboundOrderId());
outboundOrderLogs.add(log); outboundOrderLogs.add(log);
inventoryIds.add(log.getInventoryId()); // 拆分库存ID(支持逗号分隔)
if (StringUtils.isNotBlank(items.getInventoryId())) {
String[] invIds = items.getInventoryId().split(",");
for (String invId : invIds) {
if (StringUtils.isNotBlank(invId)) {
inventoryIds.add(invId.trim());
}
}
}
} }
// 插入日志 + 刷新库存 // 插入日志 + 刷新库存
...@@ -498,17 +497,14 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -498,17 +497,14 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
} }
/** /**
* 简化版:合并相同库存维度的明细记录 * 合并相同维度明细(仅合并数量,不拼接库存ID)
* 按「物料ID+库存类型+库位ID」维度合并,仅累加实际数量
*/ */
private List<OutboundOrderItems> mergeSameInventoryItems(List<OutboundOrderItems> itemsList) { private List<OutboundOrderItems> mergeSameInventoryItems(List<OutboundOrderItems> itemsList) {
if (CollectionUtils.isEmpty(itemsList)) { if (CollectionUtils.isEmpty(itemsList)) {
return Collections.emptyList(); return Collections.emptyList();
} }
// 按「物料ID+库存类型+库位ID」分组合并
Map<String, OutboundOrderItems> mergeMap = new LinkedHashMap<>(); Map<String, OutboundOrderItems> mergeMap = new LinkedHashMap<>();
for (OutboundOrderItems item : itemsList) { for (OutboundOrderItems item : itemsList) {
String mergeKey = buildInventoryKey( String mergeKey = buildInventoryKey(
item.getMaterialId(), item.getMaterialId(),
...@@ -517,13 +513,12 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -517,13 +513,12 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
); );
if (mergeMap.containsKey(mergeKey)) { if (mergeMap.containsKey(mergeKey)) {
// 只合并实际数量
OutboundOrderItems existItem = mergeMap.get(mergeKey); OutboundOrderItems existItem = mergeMap.get(mergeKey);
// 仅累加数量
Long newActualQty = Optional.ofNullable(existItem.getActualQuantity()).orElse(0L) Long newActualQty = Optional.ofNullable(existItem.getActualQuantity()).orElse(0L)
+ Optional.ofNullable(item.getActualQuantity()).orElse(0L); + Optional.ofNullable(item.getActualQuantity()).orElse(0L);
existItem.setActualQuantity(newActualQty); existItem.setActualQuantity(newActualQty);
} else { } else {
// 新记录直接放入
mergeMap.put(mergeKey, item); mergeMap.put(mergeKey, item);
} }
} }
...@@ -558,7 +553,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -558,7 +553,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
Map<String, String> sapToMaterialIdMap = loadSapToMaterialIdMap(); Map<String, String> sapToMaterialIdMap = loadSapToMaterialIdMap();
Map<String, String> locationNameToIdMap = loadLocationNameToIdMap(); Map<String, String> locationNameToIdMap = loadLocationNameToIdMap();
Map<String, String> ownerNameToIdMap = loadOwnerNameToIdMap(); Map<String, String> ownerNameToIdMap = loadOwnerNameToIdMap();
Map<String, AbstractMap.SimpleEntry<String, Long>> inventoryTOIdMap = loadInventoryTOIdMap(); Map<String, List<Inventory>> inventoryGroupMap = loadInventoryGroupMap();
// 4. 按入库单号分组 // 4. 按入库单号分组
Map<String, List<OutboundTemplateVO>> orderGroupMap = inboundOrdersList.stream() Map<String, List<OutboundTemplateVO>> orderGroupMap = inboundOrdersList.stream()
...@@ -627,7 +622,6 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -627,7 +622,6 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
mainDO.setUpdateUserCode(operId); mainDO.setUpdateUserCode(operId);
mainDO.setSortNo(Optional.ofNullable(mainDO.getSortNo()).orElse(0L)); mainDO.setSortNo(Optional.ofNullable(mainDO.getSortNo()).orElse(0L));
mainDO.setIsImport(0L); mainDO.setIsImport(0L);
//添加日期
mainDO.setInboundDate(DateUtils.getNowDate()); mainDO.setInboundDate(DateUtils.getNowDate());
// 明细校验 // 明细校验
...@@ -640,7 +634,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -640,7 +634,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
"orderId", "systemNo", "orderTypeId", "batchId", "warehouseName", "warehouseId"); "orderId", "systemNo", "orderTypeId", "batchId", "warehouseName", "warehouseId");
// 填充明细必填字段 // 填充明细必填字段
itemDO.setId(UUID.randomUUID().toString()); itemDO.setId(UUID.randomUUID().toString().replace("-", ""));
itemDO.setOrderId(orderId); itemDO.setOrderId(orderId);
itemDO.setBatchCode(Optional.ofNullable(mainDO.getBatchCode()).orElse("")); itemDO.setBatchCode(Optional.ofNullable(mainDO.getBatchCode()).orElse(""));
itemDO.setOutboundOrderId(mainDO.getId()); itemDO.setOutboundOrderId(mainDO.getId());
...@@ -648,8 +642,8 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -648,8 +642,8 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
itemDO.setCreateTime(now); itemDO.setCreateTime(now);
itemDO.setCreateUserCode(operId); itemDO.setCreateUserCode(operId);
itemDO.setSortNo(0L); itemDO.setSortNo(0L);
itemDO.setItemStatus(3L); // 设置为已出库状态 itemDO.setItemStatus(3L);
itemDO.setShippedAt(mainDO.getInboundDate()); // itemDO.setShippedAt(mainDO.getInboundDate());
// 物料SAP校验 // 物料SAP校验
String sapNo = vo.getSapNo() != null ? vo.getSapNo().trim() : ""; String sapNo = vo.getSapNo() != null ? vo.getSapNo().trim() : "";
...@@ -666,8 +660,8 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -666,8 +660,8 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
// 库位校验 // 库位校验
String locationName = vo.getLocationName() != null ? vo.getLocationName().trim() : ""; String locationName = vo.getLocationName() != null ? vo.getLocationName().trim() : "";
String locationId = locationNameToIdMap.get(locationName);
if (StringUtils.isNotBlank(locationName)) { if (StringUtils.isNotBlank(locationName)) {
String locationId = locationNameToIdMap.get(locationName);
if (StringUtils.isBlank(locationId)) { if (StringUtils.isBlank(locationId)) {
throw new ServiceException(String.format("入库单号【%s】第%d条明细的库位【%s】不存在", throw new ServiceException(String.format("入库单号【%s】第%d条明细的库位【%s】不存在",
orderId, lineNo, locationName)); orderId, lineNo, locationName));
...@@ -677,49 +671,13 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -677,49 +671,13 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
// 库存类型设置 // 库存类型设置
itemDO.setInventoryType(orderType); itemDO.setInventoryType(orderType);
// 实际出库数量
// 实际出库数量(使用计划数量)
itemDO.setActualQuantity(Optional.ofNullable(vo.getActualQuantity()).orElse(0L)); itemDO.setActualQuantity(Optional.ofNullable(vo.getActualQuantity()).orElse(0L));
// 库存校验(包含inventoryType)- 有库位才校验,无库位直接跳过
if (StringUtils.isNotBlank(locationName)) {
String inventoryTypeStr = Optional.ofNullable(orderType).map(String::valueOf).orElse("");
String inventoryMatchKey = buildInventoryKey(materialId, locationId, inventoryTypeStr);
AbstractMap.SimpleEntry<String, Long> inventoryEntry = inventoryTOIdMap.get(inventoryMatchKey);
String inventoryId = "";
if (inventoryEntry == null) {
Inventory inventory = new Inventory();
BeanUtils.copyProperties(itemDO, inventory);
inventoryId = UUID.randomUUID().toString();
inventory.setInventoryType(Long.valueOf(orderType));
inventory.setBatchId(itemDO.getBatchCode());
inventory.setWarehousesId("local");
inventory.setQuantity(0L);
inventory.setInventoryStatus(1L);
inventory.setIsUsed(1L);
inventory.setId(inventoryId);
int insertCount = inventoryMapper.insertInventory(inventory);
if (insertCount != 1) {
throw new ServiceException(String.format("入库单号【%s】第%d条明细新增库存失败,插入行数为0", orderId, lineNo));
}
// 插入后直接添加到全局缓存
InventoryCache.addInventory(inventoryMatchKey, inventory);
sqlSessionTemplate.clearCache();
sqlSessionTemplate.flushStatements();
} else {
System.out.println("库存已存在,使用已有库存ID:" + inventoryEntry.getKey());
inventoryId = inventoryEntry.getKey();
}
itemDO.setInventoryId(inventoryId);
}
// 无库位时不校验库存,也不设置inventoryId
itemDOList.add(itemDO); itemDOList.add(itemDO);
} }
// 合并相同库存维度的明细 // 合并相同维度明细
List<OutboundOrderItems> mergedItemList = mergeSameInventoryItems(itemDOList); List<OutboundOrderItems> mergedItemList = mergeSameInventoryItems(itemDOList);
validMainMap.put(orderId, mainDO); validMainMap.put(orderId, mainDO);
validItemMap.put(orderId, mergedItemList); validItemMap.put(orderId, mergedItemList);
...@@ -756,7 +714,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -756,7 +714,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
int itemFail = itemDOList.size() - itemSuccess; int itemFail = itemDOList.size() - itemSuccess;
totalItemFailure += itemFail; totalItemFailure += itemFail;
successMsg.append(String.format("入库单号【%s】成功导入%d条物料明细(已合并相同库存维度);\n", orderId, itemSuccess)); successMsg.append(String.format("入库单号【%s】成功导入%d条物料明细;\n", orderId, itemSuccess));
if (itemFail > 0) { if (itemFail > 0) {
failureMsg.append(String.format("入库单号【%s】有%d条物料明细导入失败;\n", orderId, itemFail)); failureMsg.append(String.format("入库单号【%s】有%d条物料明细导入失败;\n", orderId, itemFail));
} }
...@@ -765,36 +723,29 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -765,36 +723,29 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
} }
} }
// 8. 异步执行库存扣减和无库位明细拆分 // ========== 关键修改:移除 CompletableFuture 异步执行,改为同步调用 ==========
CompletableFuture.runAsync(() -> { // 8. 同步执行库存扣减和无库位明细拆分(原异步逻辑改为同步)
try { try {
for (Map.Entry<String, List<OutboundOrderItems>> entry : allItemListMap.entrySet()) { for (Map.Entry<String, List<OutboundOrderItems>> entry : allItemListMap.entrySet()) {
List<OutboundOrderItems> itemList = entry.getValue(); List<OutboundOrderItems> itemList = entry.getValue();
// 执行库存扣减 // 执行库存扣减
Map<String, List<Map<String, Object>>> deductRecordMap = deductInventory(itemList, operId, now); Map<String, List<Map<String, Object>>> deductRecordMap = deductInventory(itemList, operId, now);
// 处理无库位明细拆分 // 处理无库位明细拆分
boolean hasNoLocationItem = itemList.stream()
.anyMatch(item -> StringUtils.isBlank(item.getLocationId()));
if (hasNoLocationItem && !deductRecordMap.isEmpty()) {
handleNoLocationItemSplit(itemList, deductRecordMap, operId, now); handleNoLocationItemSplit(itemList, deductRecordMap, operId, now);
} }
}
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace();
} }
});
// 9. 结果汇总 // 9. 结果汇总
if (totalMainFailure > 0 || totalItemFailure > 0) { if (totalMainFailure > 0 || totalItemFailure > 0) {
String finalFailureMsg = String.format( String finalFailureMsg = String.format(
"导入结果:成功新增%d个入库单,失败%d个;成功导入%d条明细(已合并相同库存维度),失败%d条。失败详情:%s", "导入结果:成功新增%d个入库单,失败%d个;成功导入%d条明细,失败%d条。失败详情:%s",
totalMainSuccess, totalMainFailure, totalItemSuccess, totalItemFailure, failureMsg.toString() totalMainSuccess, totalMainFailure, totalItemSuccess, totalItemFailure, failureMsg.toString()
); );
throw new ServiceException(finalFailureMsg); throw new ServiceException(finalFailureMsg);
} else { } else {
String finalSuccessMsg = String.format( String finalSuccessMsg = String.format(
"恭喜您,数据已全部导入成功!共新增%d个入库单,成功导入%d条物料明细(已合并相同库存维度)。详情:%s", "恭喜您,数据已全部导入成功!共新增%d个入库单,成功导入%d条物料明细。详情:%s",
totalMainSuccess, totalItemSuccess, successMsg.toString() totalMainSuccess, totalItemSuccess, successMsg.toString()
); );
return finalSuccessMsg; return finalSuccessMsg;
...@@ -802,62 +753,56 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -802,62 +753,56 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
} }
/** /**
* 处理无库位明细拆分(适配新的合并维度 * 处理无库位明细拆分(精准匹配扣减记录
*/ */
private void handleNoLocationItemSplit(List<OutboundOrderItems> itemList, private void handleNoLocationItemSplit(List<OutboundOrderItems> itemList,
Map<String, List<Map<String, Object>>> deductRecordMap, Map<String, List<Map<String, Object>>> deductRecordMap,
String operId, Date now) { String operId, Date now) {
List<OutboundOrderItems> newValidItemList = new ArrayList<>(); List<OutboundOrderItems> newItemList = new ArrayList<>();
Set<String> orderIdSet = new HashSet<>(); Set<String> orderIdSet = new HashSet<>();
for (OutboundOrderItems item : itemList) { for (OutboundOrderItems item : itemList) {
if (StringUtils.isNotBlank(item.getLocationId())) {
continue; // 跳过有库位明细
}
String itemId = item.getId(); String itemId = item.getId();
List<Map<String, Object>> deductRecords = deductRecordMap.get(itemId); List<Map<String, Object>> deductRecords = deductRecordMap.get(itemId);
if (CollectionUtils.isEmpty(deductRecords)) continue; if (CollectionUtils.isEmpty(deductRecords)) continue;
orderIdSet.add(item.getOutboundOrderId()); orderIdSet.add(item.getOutboundOrderId());
// 按扣减记录拆分明细(一条扣减记录对应一条新明细)
// 直接遍历合并后的记录(已按物料+库存类型+库位ID合并)
for (Map<String, Object> rec : deductRecords) { for (Map<String, Object> rec : deductRecords) {
String inventoryId = (String) rec.get("inventoryId"); String inventoryId = (String) rec.get("inventoryId");
String locId = (String) rec.get("locationId"); String locId = (String) rec.get("locationId");
Long validQty = (Long) rec.get("deductQty"); Long deductQty = (Long) rec.get("deductQty");
if (validQty <= 0 || StringUtils.isBlank(inventoryId)) continue; if (deductQty <= 0 || StringUtils.isBlank(inventoryId)) continue;
OutboundOrderItems newItem = new OutboundOrderItems(); OutboundOrderItems newItem = new OutboundOrderItems();
BeanUtils.copyProperties(item, newItem); BeanUtils.copyProperties(item, newItem);
newItem.setId(UUID.randomUUID().toString().replace("-", "")); newItem.setId(UUID.randomUUID().toString().replace("-", ""));
newItem.setLocationId(locId); newItem.setLocationId(locId);
newItem.setActualQuantity(validQty); newItem.setActualQuantity(deductQty);
newItem.setInventoryId(inventoryId); newItem.setInventoryId(inventoryId);
newItem.setCreateBy(operId);
newItem.setCreateTime(now);
newItem.setUpdateBy(operId); newItem.setUpdateBy(operId);
newItem.setUpdateTime(now); newItem.setUpdateTime(now);
newValidItemList.add(newItem); newItemList.add(newItem);
}
} }
// 删除临时明细
for (String orderId : orderIdSet) {
outboundOrderItemsMapper.deleteOutboundOrderItemsByOrderId(orderId);
} }
// 批量插入有效明细(插入前再次合并) // 删除原无库位明细,插入拆分后的新明细
List<OutboundOrderItems> mergedNewItems = mergeSameInventoryItems(newValidItemList); if (!orderIdSet.isEmpty() && !newItemList.isEmpty()) {
if (!mergedNewItems.isEmpty()) { orderIdSet.forEach(orderId -> outboundOrderItemsMapper.deleteOutboundOrderItemsByOrderId(orderId));
outboundOrderItemsMapper.batchInsertOutboundOrderItems(mergedNewItems); outboundOrderItemsMapper.batchInsertOutboundOrderItems(newItemList);
// 生成日志 // 生成拆分后的日志
List<OutboundOrderLog> logList = new ArrayList<>(); List<OutboundOrderLog> logList = newItemList.stream().map(item -> {
for (OutboundOrderItems newItem : mergedNewItems) {
OutboundOrderLog log = new OutboundOrderLog(); OutboundOrderLog log = new OutboundOrderLog();
BeanUtils.copyProperties(newItem, log); BeanUtils.copyProperties(item, log);
log.setOrderId(newItem.getOutboundOrderId()); log.setOrderId(item.getOutboundOrderId());
log.setItemStatus(3L); log.setItemStatus(3L);
logList.add(log); return log;
} }).collect(Collectors.toList());
outboundOrderLogMapper.batchOutboundOrderLog(logList); outboundOrderLogMapper.batchOutboundOrderLog(logList);
} }
} }
...@@ -906,45 +851,4 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService { ...@@ -906,45 +851,4 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService {
(k1, k2) -> k1 (k1, k2) -> k1
)); ));
} }
/**
* 加载库存映射Map(按新维度)+ 同步填充全局缓存
*/
private Map<String, AbstractMap.SimpleEntry<String, Long>> loadInventoryTOIdMap() {
Inventory inventory = new Inventory();
inventory.setInventoryStatus(1L);
inventory.setIsUsed(1L);
List<Inventory> inventoryList = inventoryService.selectInventoryList(inventory);
// 清空全局缓存
InventoryCache.clear();
if (CollectionUtils.isEmpty(inventoryList)) {
return Collections.emptyMap();
}
return inventoryList.stream()
.filter(inv -> StringUtils.isNotBlank(inv.getMaterialId())
&& inv.getInventoryType() != null
&& StringUtils.isNotBlank(inv.getId()))
.peek(inv -> {
// 同步到全局缓存(按新维度)
String key = buildInventoryKey(
inv.getMaterialId(),
inv.getLocationId(),
inv.getInventoryType().toString()
);
InventoryCache.addInventory(key, inv);
})
.collect(Collectors.toMap(
inv -> buildInventoryKey(
inv.getMaterialId(),
inv.getLocationId(),
inv.getInventoryType().toString()
),
inv -> new AbstractMap.SimpleEntry<>(inv.getId().trim(), Optional.ofNullable(inv.getQuantity()).orElse(0L)),
(k1, k2) -> k1,
HashMap::new
));
}
} }
\ No newline at end of file
package com.ruoyi.inventory.utils; package com.ruoyi.inventory.utils;
import com.ruoyi.inventory.domain.Inventory; import com.ruoyi.inventory.domain.Inventory;
import com.ruoyi.common.utils.StringUtils;
import org.apache.commons.collections4.CollectionUtils;
import java.util.AbstractMap; import java.util.*;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
/** /**
* 库存映射全局缓存(解决导入新增库存即时可见问题 * 库存映射全局缓存(适配同维度多库存场景
*/ */
public class InventoryCache { public class InventoryCache {
// 并发安全Map,Key=物料ID_库位ID_库存类型,Value=库存对象 // 重构:维度Key → 同维度下的所有库存列表
private static final Map<String, Inventory> INVENTORY_MAP = new ConcurrentHashMap<>(); private static final Map<String, List<Inventory>> INVENTORY_GROUP_MAP = new ConcurrentHashMap<>();
// 添加库存(直接存对象,避免参数不匹配) // ========== 核心方法 ==========
/**
* 批量初始化缓存(从数据库加载全量库存时调用)
* @param allInventory 全量库存列表
*/
public static void init(List<Inventory> allInventory) {
if (CollectionUtils.isEmpty(allInventory)) {
clear();
return;
}
INVENTORY_GROUP_MAP.clear();
for (Inventory inv : allInventory) {
String key = buildInventoryKey(inv);
INVENTORY_GROUP_MAP.computeIfAbsent(key, k -> new CopyOnWriteArrayList<>()).add(inv);
}
}
/**
* 添加单条库存到缓存(自动按维度分组)
* @param inventory 库存对象
*/
public static void addInventory(Inventory inventory) {
if (inventory == null) {
return;
}
String key = buildInventoryKey(inventory);
INVENTORY_GROUP_MAP.computeIfAbsent(key, k -> new CopyOnWriteArrayList<>()).add(inventory);
}
/**
* 更新缓存中的库存对象(按库存ID匹配)
* @param inventory 待更新的库存对象
*/
public static void updateInventory(Inventory inventory) {
if (inventory == null || StringUtils.isBlank(inventory.getId())) {
return;
}
String key = buildInventoryKey(inventory);
List<Inventory> invList = INVENTORY_GROUP_MAP.get(key);
if (CollectionUtils.isEmpty(invList)) {
return;
}
// 替换同ID的库存对象
for (int i = 0; i < invList.size(); i++) {
if (inventory.getId().equals(invList.get(i).getId())) {
invList.set(i, inventory);
break;
}
}
}
/**
* 移除指定维度下的指定库存
* @param inventory 待移除的库存对象
*/
public static void removeInventory(Inventory inventory) {
if (inventory == null || StringUtils.isBlank(inventory.getId())) {
return;
}
String key = buildInventoryKey(inventory);
List<Inventory> invList = INVENTORY_GROUP_MAP.get(key);
if (CollectionUtils.isEmpty(invList)) {
return;
}
invList.removeIf(inv -> inventory.getId().equals(inv.getId()));
// 若维度下无库存,删除该维度Key
if (invList.isEmpty()) {
INVENTORY_GROUP_MAP.remove(key);
}
}
/**
* 按维度Key获取库存列表
* @param key 维度Key(物料ID_库位ID_库存类型)
* @return 同维度下的所有库存
*/
public static List<Inventory> getInventoryListByKey(String key) {
return INVENTORY_GROUP_MAP.getOrDefault(key, Collections.emptyList());
}
/**
* 获取全量缓存(供扣减逻辑调用)
* @return 维度Key → 库存列表
*/
public static Map<String, List<Inventory>> getAllGroup() {
return new HashMap<>(INVENTORY_GROUP_MAP); // 返回拷贝,避免外部修改
}
/**
* 清空缓存
*/
public static void clear() {
INVENTORY_GROUP_MAP.clear();
}
// ========== 辅助方法 ==========
/**
* 构建库存维度Key:物料ID_库位ID_库存类型
*/
public static String buildInventoryKey(Inventory inventory) {
if (inventory == null) {
return "";
}
return String.join("_",
StringUtils.trimToEmpty(inventory.getMaterialId()),
StringUtils.trimToEmpty(inventory.getLocationId()),
Optional.ofNullable(inventory.getInventoryType()).map(String::valueOf).orElse("")
);
}
/**
* 重载:手动构建维度Key
*/
public static String buildInventoryKey(String materialId, String locationId, String inventoryType) {
return String.join("_",
StringUtils.trimToEmpty(materialId),
StringUtils.trimToEmpty(locationId),
StringUtils.trimToEmpty(inventoryType)
);
}
// ========== 兼容原有方法(避免改动业务层) ==========
@Deprecated // 标记为过时,建议使用新方法
public static void addInventory(String key, Inventory inventory) { public static void addInventory(String key, Inventory inventory) {
INVENTORY_MAP.put(key, inventory); INVENTORY_GROUP_MAP.computeIfAbsent(key, k -> new CopyOnWriteArrayList<>()).add(inventory);
} }
// 获取库存 @Deprecated
public static Inventory getInventory(String key) { public static Inventory getInventory(String key) {
return INVENTORY_MAP.get(key); List<Inventory> invList = INVENTORY_GROUP_MAP.get(key);
return CollectionUtils.isEmpty(invList) ? null : invList.get(0);
} }
// 清空缓存 @Deprecated
public static void clear() { public static void removeInventory(String key) {
INVENTORY_MAP.clear(); INVENTORY_GROUP_MAP.remove(key);
} }
// 获取全部缓存(核心:供loadInventoryGroupMap直接读取) @Deprecated
public static Map<String, Inventory> getAll() { public static void removeInventory(String key, String inventoryId) {
return INVENTORY_MAP; List<Inventory> invList = INVENTORY_GROUP_MAP.get(key);
if (CollectionUtils.isEmpty(invList)) {
return;
}
invList.removeIf(inv -> inventoryId.equals(inv.getId()));
if (invList.isEmpty()) {
INVENTORY_GROUP_MAP.remove(key);
}
} }
@Deprecated
public static Map<String, Inventory> getAll() {
// 兼容原有逻辑:维度Key → 第一个库存对象(仅临时兼容)
Map<String, Inventory> oldMap = new ConcurrentHashMap<>();
for (Map.Entry<String, List<Inventory>> entry : INVENTORY_GROUP_MAP.entrySet()) {
List<Inventory> invList = entry.getValue();
if (!CollectionUtils.isEmpty(invList)) {
oldMap.put(entry.getKey(), invList.get(0));
}
}
return oldMap;
}
} }
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论