From 050a6301777a6753c800f1999670f8d30f1589f9 Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期一, 27 四月 2026 17:55:51 +0800
Subject: [PATCH] feat:1.根据bom结构领料 2.额外领取库存产品
---
src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java | 641 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 639 insertions(+), 2 deletions(-)
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java
index b4e3826..8f2f728 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java
@@ -1,20 +1,657 @@
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;
/**
* <p>
- * 璁㈠崟棰嗘枡绾胯竟浠� 鏈嶅姟瀹炵幇绫�
+ * 鐠併垹宕熸0鍡樻灐缁捐儻绔熸禒?閺堝秴濮熺�圭偟骞囩猾?
* </p>
*
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @author 閼侯垰顕辨潪顖欐閿涘牊鐫欓懟蹇ョ礆閺堝妾洪崗顒�寰�
* @since 2026-04-21 03:55:52
*/
@Service
+@RequiredArgsConstructor
public class ProductionOrderPickServiceImpl extends ServiceImpl<ProductionOrderPickMapper, ProductionOrderPick> 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<ProductionOrderPickDto> 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<String> 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<ProductionOrderPick> existingPickList = baseMapper.selectList(
+ Wrappers.<ProductionOrderPick>lambdaQuery()
+ .eq(ProductionOrderPick::getProductionOrderId, productionOrderId));
+ Map<Long, ProductionOrderPick> existingPickMap = existingPickList.stream()
+ .filter(item -> item.getId() != null)
+ .collect(Collectors.toMap(ProductionOrderPick::getId, Function.identity(), (a, b) -> a));
+
+ processDeletePickIds(dto, existingPickMap, productionOrderId);
+
+ List<ProductionOrderPickDto> pickItems = resolveUpdateItems(dto);
+ Set<Long> 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<ProductionOrderPickVo> listPickedDetail(Long productionOrderId) {
+ if (productionOrderId == null) {
+ return Collections.emptyList();
+ }
+ List<ProductionOrderPickVo> detailList = baseMapper.listPickedDetailByOrderId(productionOrderId);
+ fillBatchNoList(detailList);
+ fillSelectableBatchNoList(detailList);
+ return detailList;
+ }
+
+ private void processDeletePickIds(ProductionOrderPickDto rootDto,
+ Map<Long, ProductionOrderPick> existingPickMap,
+ Long productionOrderId) {
+ if (rootDto.getDeletePickIds() == null || rootDto.getDeletePickIds().isEmpty()) {
+ return;
+ }
+ Set<Long> 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("鍒犻櫎棰嗘枡澶辫触锛孖D=" + 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<Long, ProductionOrderPick> existingPickMap,
+ Long productionOrderId,
+ Set<Long> keepPickIdSet) {
+ if (rootDto.getPickList() == null) {
+ return;
+ }
+ List<ProductionOrderPick> 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("鍒犻櫎棰嗘枡澶辫触锛孖D=" + 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<String> 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<Long, ProductionOrderPick> 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<String> 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("搴撳瓨鍥為��澶辫触锛屼骇鍝佽鏍糏D=" + productModelId);
+ }
+ }
+
+ private List<ProductionOrderPickDto> 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<ProductionOrderPickDto> 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 + "鏉$敓浜ц鍗旾D涓嶈兘涓虹┖");
+ }
+ if (dto.getProductModelId() == null) {
+ throw new ServiceException("绗�" + rowNo + "鏉′骇鍝佽鏍糏D涓嶈兘涓虹┖");
+ }
+ 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<String> resolveBatchNoList(ProductionOrderPickDto dto) {
+ List<String> normalizedBatchNoList = normalizeBatchNoList(dto.getBatchNoList());
+ if (!normalizedBatchNoList.isEmpty()) {
+ return normalizedBatchNoList;
+ }
+ return parseBatchNoValue(dto.getBatchNo());
+ }
+
+ private String pickInventoryBatchNo(List<String> 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<String> batchNoList) {
+ if (batchNoList == null || batchNoList.isEmpty()) {
+ return null;
+ }
+ if (batchNoList.size() == 1) {
+ return batchNoList.get(0);
+ }
+ return String.join(",", batchNoList);
+ }
+
+ private List<String> normalizeBatchNoList(List<String> batchNoList) {
+ if (batchNoList == null || batchNoList.isEmpty()) {
+ return Collections.emptyList();
+ }
+ LinkedHashSet<String> 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<ProductionOrderPickVo> detailList) {
+ if (detailList == null || detailList.isEmpty()) {
+ return;
+ }
+ Map<String, LinkedHashSet<String>> batchNoGroupMap = new HashMap<>();
+ for (ProductionOrderPickVo detail : detailList) {
+ String key = buildBatchNoGroupKey(detail);
+ LinkedHashSet<String> 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<String> batchSet = batchNoGroupMap.get(key);
+ detail.setBatchNoList(batchSet == null ? Collections.emptyList() : new ArrayList<>(batchSet));
+ }
+ }
+
+ private void fillSelectableBatchNoList(List<ProductionOrderPickVo> detailList) {
+ if (detailList == null || detailList.isEmpty()) {
+ return;
+ }
+ Set<Long> productModelIdSet = detailList.stream()
+ .map(ProductionOrderPickVo::getProductModelId)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toSet());
+ if (productModelIdSet.isEmpty()) {
+ return;
+ }
+ List<StockInventory> stockBatchList = stockInventoryMapper.listSelectableBatchNoByProductModelIds(
+ new ArrayList<>(productModelIdSet));
+ Map<Long, LinkedHashSet<String>> 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<String> mergedBatchSet = new LinkedHashSet<>();
+ mergedBatchSet.addAll(normalizeBatchNoList(detail.getBatchNoList()));
+ LinkedHashSet<String> 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<String> 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<String> parsed = Arrays.stream(value.split(","))
+ .map(item -> item == null ? null : item.trim().replace("\"", "").replace("'", ""))
+ .collect(Collectors.toList());
+ return normalizeBatchNoList(parsed);
+ }
+ if (normalizedValue.contains(",")) {
+ List<String> parsed = Arrays.stream(normalizedValue.split(","))
+ .map(item -> item == null ? null : item.trim())
+ .collect(Collectors.toList());
+ return normalizeBatchNoList(parsed);
+ }
+ return Collections.singletonList(normalizedValue);
+ }
+
+ private LambdaQueryWrapper<StockInventory> buildStockWrapper(Long productModelId, String batchNo) {
+ LambdaQueryWrapper<StockInventory> wrapper = Wrappers.<StockInventory>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;
+ }
}
+
--
Gitblit v1.9.3