package com.ruoyi.production.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.production.bean.dto.ProductionOrderPickDto;
import com.ruoyi.production.bean.vo.ProductionOrderPickVo;
import com.ruoyi.production.mapper.ProductionOperationTaskMapper;
import com.ruoyi.production.mapper.ProductionOrderMapper;
import com.ruoyi.production.mapper.ProductionOrderPickMapper;
import com.ruoyi.production.mapper.ProductionOrderPickRecordMapper;
import com.ruoyi.production.pojo.ProductionOrder;
import com.ruoyi.production.pojo.ProductionOrderPick;
import com.ruoyi.production.pojo.ProductionOrderPickRecord;
import com.ruoyi.production.service.ProductionOrderPickService;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.mapper.StockInventoryMapper;
import com.ruoyi.stock.pojo.StockInventory;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
*
* 璁㈠崟棰嗘枡绾胯竟浠?鏈嶅姟瀹炵幇绫?
*
*
* @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
* @since 2026-04-21 03:55:52
*/
@Service
@RequiredArgsConstructor
public class ProductionOrderPickServiceImpl extends ServiceImpl implements ProductionOrderPickService {
private final ProductionOrderMapper productionOrderMapper;
private final ProductionOperationTaskMapper productionOperationTaskMapper;
private final ProductionOrderPickRecordMapper productionOrderPickRecordMapper;
private final StockInventoryMapper stockInventoryMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean savePick(ProductionOrderPickDto dto) {
List pickItems = resolvePickItems(dto);
for (int i = 0; i < pickItems.size(); i++) {
int rowNo = i + 1;
ProductionOrderPickDto resolvedDto = mergeDto(dto, pickItems.get(i));
validatePickParam(resolvedDto, rowNo);
List batchNoList = resolveBatchNoList(resolvedDto);
String inventoryBatchNo = pickInventoryBatchNo(batchNoList);
String storedBatchNo = formatBatchNoStorage(batchNoList);
subtractInventory(resolvedDto.getProductModelId(), inventoryBatchNo, resolvedDto.getPickQuantity(), rowNo);
ProductionOrderPick orderPick = new ProductionOrderPick();
orderPick.setProductionOrderId(resolvedDto.getProductionOrderId());
orderPick.setProductModelId(resolvedDto.getProductModelId());
orderPick.setBatchNo(storedBatchNo);
orderPick.setQuantity(resolvedDto.getPickQuantity());
orderPick.setRemark(resolvedDto.getRemark());
orderPick.setOperationName(resolvedDto.getOperationName());
orderPick.setTechnologyOperationId(resolvedDto.getTechnologyOperationId());
orderPick.setDemandedQuantity(resolvedDto.getDemandedQuantity());
orderPick.setBom(resolvedDto.getBom());
baseMapper.insert(orderPick);
insertPickRecord(orderPick.getId(),
resolvedDto.getProductionOrderId(),
resolvedDto.getProductionOperationTaskId(),
resolvedDto.getProductModelId(),
inventoryBatchNo,
resolvedDto.getPickQuantity(),
BigDecimal.ZERO,
resolvedDto.getPickQuantity(),
resolvedDto.getPickType(),
resolvedDto.getRemark());
}
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updatePick(ProductionOrderPickDto dto) {
if (dto == null) {
throw new ServiceException("变更参数不能为空");
}
Long productionOrderId = resolveProductionOrderId(dto);
if (productionOrderId == null) {
throw new ServiceException("生产订单ID不能为空");
}
ProductionOrder productionOrder = productionOrderMapper.selectById(productionOrderId);
if (productionOrder == null) {
throw new ServiceException("生产订单不存在");
}
List existingPickList = baseMapper.selectList(
Wrappers.lambdaQuery()
.eq(ProductionOrderPick::getProductionOrderId, productionOrderId));
Map existingPickMap = existingPickList.stream()
.filter(item -> item.getId() != null)
.collect(Collectors.toMap(ProductionOrderPick::getId, Function.identity(), (a, b) -> a));
processDeletePickIds(dto, existingPickMap, productionOrderId);
List pickItems = resolveUpdateItems(dto);
Set keepPickIdSet = new HashSet<>();
for (int i = 0; i < pickItems.size(); i++) {
int rowNo = i + 1;
ProductionOrderPickDto resolvedDto = mergeDto(dto, pickItems.get(i));
if (isEmptyUpdateItem(resolvedDto)) {
continue;
}
if (resolvedDto.getProductionOrderId() == null) {
resolvedDto.setProductionOrderId(productionOrderId);
}
validatePickParam(resolvedDto, rowNo);
if (resolvedDto.getId() == null) {
addNewPickInUpdate(resolvedDto, rowNo);
continue;
}
keepPickIdSet.add(resolvedDto.getId());
updateExistingPick(resolvedDto, rowNo, existingPickMap);
}
processMissingPickItems(dto, existingPickMap, productionOrderId, keepPickIdSet);
return true;
}
@Override
public List listPickedDetail(Long productionOrderId) {
if (productionOrderId == null) {
return Collections.emptyList();
}
List detailList = baseMapper.listPickedDetailByOrderId(productionOrderId);
fillBatchNoList(detailList);
fillSelectableBatchNoList(detailList);
return detailList;
}
private void processDeletePickIds(ProductionOrderPickDto rootDto,
Map existingPickMap,
Long productionOrderId) {
if (rootDto.getDeletePickIds() == null || rootDto.getDeletePickIds().isEmpty()) {
return;
}
Set deleteIdSet = new LinkedHashSet<>(rootDto.getDeletePickIds());
for (Long deleteId : deleteIdSet) {
if (deleteId == null) {
continue;
}
ProductionOrderPick existingPick = existingPickMap.get(deleteId);
if (existingPick == null || !Objects.equals(existingPick.getProductionOrderId(), productionOrderId)) {
throw new ServiceException("要删除的领料记录不存在或不属于当前订单,ID=" + deleteId);
}
String oldBatchNo = resolveInventoryBatchNoFromStored(existingPick.getBatchNo());
BigDecimal oldQuantity = defaultDecimal(existingPick.getQuantity());
addInventory(existingPick.getProductModelId(), oldBatchNo, oldQuantity);
int affected = baseMapper.deleteById(deleteId);
if (affected <= 0) {
throw new ServiceException("删除领料失败,ID=" + deleteId);
}
insertPickRecord(existingPick.getId(),
existingPick.getProductionOrderId(),
rootDto.getProductionOperationTaskId(),
existingPick.getProductModelId(),
oldBatchNo,
oldQuantity,
oldQuantity,
BigDecimal.ZERO,
rootDto.getPickType(),
rootDto.getRemark());
existingPickMap.remove(deleteId);
}
}
private void processMissingPickItems(ProductionOrderPickDto rootDto,
Map existingPickMap,
Long productionOrderId,
Set keepPickIdSet) {
if (rootDto.getPickList() == null) {
return;
}
List missingPickList = existingPickMap.values().stream()
.filter(Objects::nonNull)
.filter(item -> item.getId() != null)
.filter(item -> Objects.equals(item.getProductionOrderId(), productionOrderId))
.filter(item -> !keepPickIdSet.contains(item.getId()))
.collect(Collectors.toList());
for (ProductionOrderPick missingPick : missingPickList) {
String oldBatchNo = resolveInventoryBatchNoFromStored(missingPick.getBatchNo());
BigDecimal oldQuantity = defaultDecimal(missingPick.getQuantity());
addInventory(missingPick.getProductModelId(), oldBatchNo, oldQuantity);
int affected = baseMapper.deleteById(missingPick.getId());
if (affected <= 0) {
throw new ServiceException("删除领料失败,ID=" + missingPick.getId());
}
insertPickRecord(missingPick.getId(),
missingPick.getProductionOrderId(),
rootDto.getProductionOperationTaskId(),
missingPick.getProductModelId(),
oldBatchNo,
oldQuantity,
oldQuantity,
BigDecimal.ZERO,
rootDto.getPickType(),
rootDto.getRemark());
existingPickMap.remove(missingPick.getId());
}
}
private void addNewPickInUpdate(ProductionOrderPickDto dto, int rowNo) {
List batchNoList = resolveBatchNoList(dto);
String inventoryBatchNo = pickInventoryBatchNo(batchNoList);
String storedBatchNo = formatBatchNoStorage(batchNoList);
subtractInventory(dto.getProductModelId(), inventoryBatchNo, dto.getPickQuantity(), rowNo);
ProductionOrderPick orderPick = new ProductionOrderPick();
orderPick.setProductionOrderId(dto.getProductionOrderId());
orderPick.setProductModelId(dto.getProductModelId());
orderPick.setBatchNo(storedBatchNo);
orderPick.setQuantity(dto.getPickQuantity());
orderPick.setRemark(dto.getRemark());
orderPick.setOperationName(dto.getOperationName());
orderPick.setTechnologyOperationId(dto.getTechnologyOperationId());
orderPick.setDemandedQuantity(dto.getDemandedQuantity());
orderPick.setBom(dto.getBom());
baseMapper.insert(orderPick);
insertPickRecord(orderPick.getId(),
dto.getProductionOrderId(),
dto.getProductionOperationTaskId(),
dto.getProductModelId(),
inventoryBatchNo,
dto.getPickQuantity(),
BigDecimal.ZERO,
dto.getPickQuantity(),
dto.getPickType(),
dto.getRemark());
}
private void updateExistingPick(ProductionOrderPickDto dto,
int rowNo,
Map existingPickMap) {
ProductionOrderPick oldPick = existingPickMap.get(dto.getId());
if (oldPick == null || !Objects.equals(oldPick.getProductionOrderId(), dto.getProductionOrderId())) {
throw new ServiceException("第" + rowNo + "条领料记录不存在或不属于当前订单");
}
Long oldProductModelId = oldPick.getProductModelId();
String oldBatchNo = resolveInventoryBatchNoFromStored(oldPick.getBatchNo());
BigDecimal oldQuantity = defaultDecimal(oldPick.getQuantity());
Long newProductModelId = dto.getProductModelId();
List newBatchNoList = resolveBatchNoList(dto);
String newBatchNo = pickInventoryBatchNo(newBatchNoList);
String newStoredBatchNo = formatBatchNoStorage(newBatchNoList);
BigDecimal newQuantity = dto.getPickQuantity();
boolean sameStockKey = Objects.equals(oldProductModelId, newProductModelId)
&& Objects.equals(oldBatchNo, newBatchNo);
if (sameStockKey) {
BigDecimal delta = newQuantity.subtract(oldQuantity);
if (delta.compareTo(BigDecimal.ZERO) > 0) {
subtractInventory(newProductModelId, newBatchNo, delta, rowNo);
} else if (delta.compareTo(BigDecimal.ZERO) < 0) {
addInventory(oldProductModelId, oldBatchNo, delta.abs());
}
} else {
addInventory(oldProductModelId, oldBatchNo, oldQuantity);
subtractInventory(newProductModelId, newBatchNo, newQuantity, rowNo);
}
oldPick.setProductModelId(newProductModelId);
oldPick.setBatchNo(newStoredBatchNo);
oldPick.setQuantity(newQuantity);
oldPick.setRemark(dto.getRemark());
oldPick.setOperationName(dto.getOperationName());
oldPick.setTechnologyOperationId(dto.getTechnologyOperationId());
if (dto.getDemandedQuantity() != null) {
oldPick.setDemandedQuantity(dto.getDemandedQuantity());
}
if (dto.getBom() != null) {
oldPick.setBom(dto.getBom());
}
int affected = baseMapper.updateById(oldPick);
if (affected <= 0) {
throw new ServiceException("第" + rowNo + "条领料更新失败");
}
BigDecimal recordQuantity = sameStockKey ? oldQuantity.subtract(newQuantity).abs() : newQuantity;
if (recordQuantity.compareTo(BigDecimal.ZERO) > 0 || oldQuantity.compareTo(newQuantity) != 0 || !sameStockKey) {
insertPickRecord(oldPick.getId(),
dto.getProductionOrderId(),
dto.getProductionOperationTaskId(),
newProductModelId,
newBatchNo,
recordQuantity,
oldQuantity,
newQuantity,
dto.getPickType(),
dto.getRemark());
}
}
private void insertPickRecord(Long pickId,
Long productionOrderId,
Long productionOperationTaskId,
Long productModelId,
String batchNo,
BigDecimal pickQuantity,
BigDecimal beforeQuantity,
BigDecimal afterQuantity,
Byte pickType,
String remark) {
ProductionOrderPickRecord pickRecord = new ProductionOrderPickRecord();
pickRecord.setPickId(pickId);
pickRecord.setProductionOrderId(productionOrderId);
pickRecord.setProductionOperationTaskId(productionOperationTaskId);
pickRecord.setProductModelId(productModelId);
pickRecord.setBatchNo(batchNo);
pickRecord.setPickQuantity(defaultDecimal(pickQuantity));
pickRecord.setBeforeQuantity(defaultDecimal(beforeQuantity));
pickRecord.setAfterQuantity(defaultDecimal(afterQuantity));
pickRecord.setPickType(pickType == null ? (byte) 1 : pickType);
pickRecord.setRemark(remark);
productionOrderPickRecordMapper.insert(pickRecord);
}
private void subtractInventory(Long productModelId, String batchNo, BigDecimal quantity, int rowNo) {
StockInventory stockInventory = stockInventoryMapper.selectOne(buildStockWrapper(productModelId, batchNo));
if (stockInventory == null) {
throw new ServiceException("第" + rowNo + "条领料对应库存不存在");
}
BigDecimal availableQuantity = defaultDecimal(stockInventory.getQualitity())
.subtract(defaultDecimal(stockInventory.getLockedQuantity()));
if (quantity.compareTo(availableQuantity) > 0) {
throw new ServiceException("第" + rowNo + "条领料可用库存不足");
}
StockInventoryDto stockInventoryDto = new StockInventoryDto();
stockInventoryDto.setProductModelId(productModelId);
stockInventoryDto.setBatchNo(batchNo);
stockInventoryDto.setQualitity(quantity);
int affected = stockInventoryMapper.updateSubtractStockInventory(stockInventoryDto);
if (affected <= 0) {
throw new ServiceException("第" + rowNo + "条领料扣减库存失败");
}
}
private void addInventory(Long productModelId, String batchNo, BigDecimal quantity) {
BigDecimal addQuantity = defaultDecimal(quantity);
if (addQuantity.compareTo(BigDecimal.ZERO) <= 0) {
return;
}
StockInventory stockInventory = stockInventoryMapper.selectOne(buildStockWrapper(productModelId, batchNo));
if (stockInventory == null) {
StockInventory newStockInventory = new StockInventory();
newStockInventory.setProductModelId(productModelId);
newStockInventory.setBatchNo(batchNo);
newStockInventory.setQualitity(addQuantity);
newStockInventory.setLockedQuantity(BigDecimal.ZERO);
newStockInventory.setVersion(1);
stockInventoryMapper.insert(newStockInventory);
return;
}
StockInventoryDto stockInventoryDto = new StockInventoryDto();
stockInventoryDto.setProductModelId(productModelId);
stockInventoryDto.setBatchNo(batchNo);
stockInventoryDto.setQualitity(addQuantity);
int affected = stockInventoryMapper.updateAddStockInventory(stockInventoryDto);
if (affected <= 0) {
throw new ServiceException("库存回退失败,产品规格ID=" + productModelId);
}
}
private List resolvePickItems(ProductionOrderPickDto dto) {
if (dto == null) {
throw new ServiceException("领料参数不能为空");
}
if (dto.getPickList() != null && !dto.getPickList().isEmpty()) {
return dto.getPickList();
}
return Collections.singletonList(dto);
}
private List resolveUpdateItems(ProductionOrderPickDto dto) {
if (dto.getPickList() != null) {
return dto.getPickList();
}
if (isEmptyUpdateItem(dto)) {
return Collections.emptyList();
}
return Collections.singletonList(dto);
}
private boolean isEmptyUpdateItem(ProductionOrderPickDto dto) {
return dto.getId() == null
&& dto.getProductModelId() == null
&& dto.getPickQuantity() == null
&& StringUtils.isEmpty(dto.getBatchNo())
&& (dto.getBatchNoList() == null || dto.getBatchNoList().isEmpty())
&& dto.getPickType() == null
&& dto.getProductionOperationTaskId() == null
&& dto.getTechnologyOperationId() == null
&& StringUtils.isEmpty(dto.getOperationName())
&& dto.getDemandedQuantity() == null
&& dto.getBom() == null
&& StringUtils.isEmpty(dto.getRemark());
}
private Long resolveProductionOrderId(ProductionOrderPickDto dto) {
if (dto.getProductionOrderId() != null) {
return dto.getProductionOrderId();
}
if (dto.getPickList() == null || dto.getPickList().isEmpty()) {
return null;
}
return dto.getPickList().stream()
.filter(Objects::nonNull)
.map(ProductionOrderPickDto::getProductionOrderId)
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}
private ProductionOrderPickDto mergeDto(ProductionOrderPickDto rootDto, ProductionOrderPickDto itemDto) {
ProductionOrderPickDto merged = new ProductionOrderPickDto();
if (itemDto != null) {
merged.setId(itemDto.getId());
merged.setProductionOrderId(itemDto.getProductionOrderId());
merged.setProductionOperationTaskId(itemDto.getProductionOperationTaskId());
merged.setProductModelId(itemDto.getProductModelId());
merged.setBatchNo(itemDto.getBatchNo());
merged.setBatchNoList(itemDto.getBatchNoList());
merged.setPickQuantity(itemDto.getPickQuantity());
merged.setPickType(itemDto.getPickType());
merged.setRemark(itemDto.getRemark());
merged.setTechnologyOperationId(itemDto.getTechnologyOperationId());
merged.setOperationName(itemDto.getOperationName());
merged.setDemandedQuantity(itemDto.getDemandedQuantity());
merged.setBom(itemDto.getBom());
}
if (merged.getId() == null) {
merged.setId(rootDto.getId());
}
if (merged.getProductionOrderId() == null) {
merged.setProductionOrderId(rootDto.getProductionOrderId());
}
if (merged.getProductionOperationTaskId() == null) {
merged.setProductionOperationTaskId(rootDto.getProductionOperationTaskId());
}
if (merged.getProductModelId() == null) {
merged.setProductModelId(rootDto.getProductModelId());
}
if (merged.getBatchNo() == null) {
merged.setBatchNo(rootDto.getBatchNo());
}
if (merged.getBatchNoList() == null || merged.getBatchNoList().isEmpty()) {
merged.setBatchNoList(rootDto.getBatchNoList());
}
if (merged.getPickQuantity() == null) {
merged.setPickQuantity(rootDto.getPickQuantity());
}
if (merged.getPickType() == null) {
merged.setPickType(rootDto.getPickType());
}
if (merged.getRemark() == null) {
merged.setRemark(rootDto.getRemark());
}
if (merged.getTechnologyOperationId() == null) {
merged.setTechnologyOperationId(rootDto.getTechnologyOperationId());
}
if (merged.getOperationName() == null) {
merged.setOperationName(rootDto.getOperationName());
}
if (merged.getDemandedQuantity() == null) {
merged.setDemandedQuantity(rootDto.getDemandedQuantity());
}
if (merged.getBom() == null) {
merged.setBom(rootDto.getBom());
}
return merged;
}
private void validatePickParam(ProductionOrderPickDto dto, int rowNo) {
if (dto.getProductionOrderId() == null) {
throw new ServiceException("第" + rowNo + "条生产订单ID不能为空");
}
if (dto.getProductModelId() == null) {
throw new ServiceException("第" + rowNo + "条产品规格ID不能为空");
}
if (dto.getPickQuantity() == null || dto.getPickQuantity().compareTo(BigDecimal.ZERO) <= 0) {
throw new ServiceException("第" + rowNo + "条领料数量必须大于0");
}
if (dto.getPickType() != null && dto.getPickType() != 1 && dto.getPickType() != 2) {
throw new ServiceException("第" + rowNo + "条领料类型只能是1或2");
}
}
private String normalizeBatchNo(String batchNo) {
if (StringUtils.isEmpty(batchNo)) {
return null;
}
String trimBatchNo = batchNo.trim();
return trimBatchNo.isEmpty() ? null : trimBatchNo;
}
private List resolveBatchNoList(ProductionOrderPickDto dto) {
List normalizedBatchNoList = normalizeBatchNoList(dto.getBatchNoList());
if (!normalizedBatchNoList.isEmpty()) {
return normalizedBatchNoList;
}
return parseBatchNoValue(dto.getBatchNo());
}
private String pickInventoryBatchNo(List batchNoList) {
if (batchNoList == null || batchNoList.isEmpty()) {
return null;
}
return batchNoList.get(0);
}
private String resolveInventoryBatchNoFromStored(String storedBatchNo) {
return pickInventoryBatchNo(parseBatchNoValue(storedBatchNo));
}
private String formatBatchNoStorage(List batchNoList) {
if (batchNoList == null || batchNoList.isEmpty()) {
return null;
}
if (batchNoList.size() == 1) {
return batchNoList.get(0);
}
return String.join(",", batchNoList);
}
private List normalizeBatchNoList(List batchNoList) {
if (batchNoList == null || batchNoList.isEmpty()) {
return Collections.emptyList();
}
LinkedHashSet normalizedSet = new LinkedHashSet<>();
for (String batchNo : batchNoList) {
String normalizedBatchNo = normalizeBatchNo(batchNo);
if (!StringUtils.isEmpty(normalizedBatchNo)) {
normalizedSet.add(normalizedBatchNo);
}
}
return new ArrayList<>(normalizedSet);
}
private void fillBatchNoList(List detailList) {
if (detailList == null || detailList.isEmpty()) {
return;
}
Map> batchNoGroupMap = new HashMap<>();
for (ProductionOrderPickVo detail : detailList) {
String key = buildBatchNoGroupKey(detail);
LinkedHashSet batchSet = batchNoGroupMap.computeIfAbsent(key, k -> new LinkedHashSet<>());
batchSet.addAll(parseBatchNoValue(detail.getBatchNo()));
if (detail.getBatchNoList() != null && !detail.getBatchNoList().isEmpty()) {
batchSet.addAll(normalizeBatchNoList(detail.getBatchNoList()));
}
}
for (ProductionOrderPickVo detail : detailList) {
String key = buildBatchNoGroupKey(detail);
LinkedHashSet batchSet = batchNoGroupMap.get(key);
detail.setBatchNoList(batchSet == null ? Collections.emptyList() : new ArrayList<>(batchSet));
}
}
private void fillSelectableBatchNoList(List detailList) {
if (detailList == null || detailList.isEmpty()) {
return;
}
Set productModelIdSet = detailList.stream()
.map(ProductionOrderPickVo::getProductModelId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
if (productModelIdSet.isEmpty()) {
return;
}
List stockBatchList = stockInventoryMapper.listSelectableBatchNoByProductModelIds(
new ArrayList<>(productModelIdSet));
Map> stockBatchMap = new HashMap<>();
for (StockInventory stockInventory : stockBatchList) {
if (stockInventory == null || stockInventory.getProductModelId() == null) {
continue;
}
String normalizedBatchNo = normalizeBatchNo(stockInventory.getBatchNo());
if (StringUtils.isEmpty(normalizedBatchNo)) {
continue;
}
stockBatchMap.computeIfAbsent(stockInventory.getProductModelId(), k -> new LinkedHashSet<>())
.add(normalizedBatchNo);
}
for (ProductionOrderPickVo detail : detailList) {
LinkedHashSet mergedBatchSet = new LinkedHashSet<>();
mergedBatchSet.addAll(normalizeBatchNoList(detail.getBatchNoList()));
LinkedHashSet selectableBatchSet = stockBatchMap.get(detail.getProductModelId());
if (selectableBatchSet != null) {
mergedBatchSet.addAll(selectableBatchSet);
}
detail.setBatchNoList(new ArrayList<>(mergedBatchSet));
}
}
private String buildBatchNoGroupKey(ProductionOrderPickVo detail) {
return String.valueOf(detail.getProductionOrderId()) + "|"
+ String.valueOf(detail.getProductModelId()) + "|"
+ String.valueOf(detail.getTechnologyOperationId()) + "|"
+ String.valueOf(detail.getOperationName());
}
private List parseBatchNoValue(String rawBatchNoValue) {
String normalizedValue = normalizeBatchNo(rawBatchNoValue);
if (StringUtils.isEmpty(normalizedValue)) {
return Collections.emptyList();
}
if (normalizedValue.startsWith("[") && normalizedValue.endsWith("]")) {
String value = normalizedValue.substring(1, normalizedValue.length() - 1);
if (StringUtils.isEmpty(value)) {
return Collections.emptyList();
}
List parsed = Arrays.stream(value.split(","))
.map(item -> item == null ? null : item.trim().replace("\"", "").replace("'", ""))
.collect(Collectors.toList());
return normalizeBatchNoList(parsed);
}
if (normalizedValue.contains(",")) {
List parsed = Arrays.stream(normalizedValue.split(","))
.map(item -> item == null ? null : item.trim())
.collect(Collectors.toList());
return normalizeBatchNoList(parsed);
}
return Collections.singletonList(normalizedValue);
}
private LambdaQueryWrapper buildStockWrapper(Long productModelId, String batchNo) {
LambdaQueryWrapper wrapper = Wrappers.lambdaQuery()
.eq(StockInventory::getProductModelId, productModelId);
if (StringUtils.isEmpty(batchNo)) {
wrapper.isNull(StockInventory::getBatchNo);
} else {
wrapper.eq(StockInventory::getBatchNo, batchNo);
}
return wrapper;
}
private BigDecimal defaultDecimal(BigDecimal value) {
return value == null ? BigDecimal.ZERO : value;
}
}