diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/service/ReservationStockInOrderApplicationService.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/service/ReservationStockInOrderApplicationService.java index c0bb0bcce..348f3b829 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/service/ReservationStockInOrderApplicationService.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/service/ReservationStockInOrderApplicationService.java @@ -181,17 +181,9 @@ public class ReservationStockInOrderApplicationService { * 新增入库单 */ public Boolean insert(ReservationStockInOrderDO stockInOrderDO) { -// 如果仓库ID为空,从当前登录用户的关联仓库中获取 + // 仓库为必填项,前端必须选择入库仓库 if (stockInOrderDO.getWarehouseId() == null) { - LoginUser loginUser = SecurityUtils.getLoginUser(); - if (loginUser == null) { - throw new ServiceException("登录已失效,请重新登录"); - } - AssociationWarehouseCacheDO associationWarehouseCacheDO = SystemServiceCacheUtil.getAssociationWarehouseCache(loginUser.getUserid()); - if (associationWarehouseCacheDO == null || associationWarehouseCacheDO.getWarehouseId() == null) { - throw new ServiceException("当前用户未配置关联仓库,请先配置仓库"); - } - stockInOrderDO.setWarehouseId(associationWarehouseCacheDO.getWarehouseId()); + throw new ServiceException("请选择入库仓库"); } //设置仓库 setWarehouseInfo(stockInOrderDO); diff --git a/mhd_wms/src/main/java/com/mhd/wms/application/service/statementStatistics/StatementStatisticsService.java b/mhd_wms/src/main/java/com/mhd/wms/application/service/statementStatistics/StatementStatisticsService.java index 367e97829..f358a9a11 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/application/service/statementStatistics/StatementStatisticsService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/application/service/statementStatistics/StatementStatisticsService.java @@ -25,6 +25,7 @@ import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import java.lang.reflect.Field; +import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.util.*; import java.util.stream.Collectors; @@ -127,6 +128,17 @@ public class StatementStatisticsService { } } List immediateInventoryPOS = materialInventoryDomainService.queryImmediateInventoryList(immediateInventoryDO); + + // 库存数量合计:与列表同筛选条件、不分页统计全部库存数量,回填到每行 + if (!CollectionUtils.isEmpty(immediateInventoryPOS)) { + BigDecimal totalInventoryQuantity = materialInventoryDomainService.sumImmediateInventoryQuantity(immediateInventoryDO); + if (totalInventoryQuantity == null) { + totalInventoryQuantity = BigDecimal.ZERO; + } + BigDecimal finalTotal = totalInventoryQuantity; + immediateInventoryPOS.forEach(po -> po.setTotalInventoryQuantity(finalTotal)); + } + // 性能优化:批量获取批次属性,避免N+1查询问题 // 1. 收集所有唯一的materialBaseInfoId Set materialBaseInfoIdSet = immediateInventoryPOS.stream() diff --git a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockReceiptOrder/StockReceiptOrderApplicationService.java b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockReceiptOrder/StockReceiptOrderApplicationService.java index 355dc57d2..4cbf4c4cc 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockReceiptOrder/StockReceiptOrderApplicationService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockReceiptOrder/StockReceiptOrderApplicationService.java @@ -2220,24 +2220,31 @@ public class StockReceiptOrderApplicationService { } /** - * PDA 抄码收货不采集毛重、体积、面积:在装配前将对应请求字段置 0,避免 getInfo 带回的累计展示值被当作本次增量。 + * PDA 抄码收货不采集毛重、体积、面积:在装配前将对应请求字段置 null, + * 利用 MyBatis-Plus NOT_NULL 策略跳过这些字段,避免覆盖已有累计数据。 + * @param lines 收货明细列表 */ private static void normalizePdaCopyReceiptGrossVolumeAreaToZero(List lines) { + // 没有明细时,直接返回 if (CollectionUtils.isEmpty(lines)) { return; } + // 有明细时,遍历 for (ReceiptMaterialDetailDO line : lines) { + // 跳过 line 为 null if (line == null) { continue; } + // 在装配之前将字段置为 null if (isPdaCopyReceiptLine(line)) { - line.setReceiptGrossWeight(BigDecimal.ZERO); - line.setTotalGrossWeight(BigDecimal.ZERO); - line.setReceiptVolume(BigDecimal.ZERO); - line.setTotalVolume(BigDecimal.ZERO); - line.setReceiptArea(BigDecimal.ZERO); - line.setTotalArea(BigDecimal.ZERO); + line.setReceiptGrossWeight(null); + line.setTotalGrossWeight(null); + line.setReceiptVolume(null); + line.setTotalVolume(null); + line.setReceiptArea(null); + line.setTotalArea(null); } + // 递归,确保每一个子行都会独立通过 isPdaCopyReceiptLine 判断是否需要清字段 normalizePdaCopyReceiptGrossVolumeAreaToZero(line.getChildren()); } } diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/repository/persistence/ReceiptMaterialDetailImpl.java b/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/repository/persistence/ReceiptMaterialDetailImpl.java index c9c533d42..5226eb019 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/repository/persistence/ReceiptMaterialDetailImpl.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/repository/persistence/ReceiptMaterialDetailImpl.java @@ -459,6 +459,7 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl uniqueIds = collectReceiptDetailUniqueIds(receiptMaterialDetailDOList); - if (!uniqueIds.isEmpty()) { - IMaterialMoreDetailService.remove(new QueryWrapper() - .eq("order_number", receiptOrderNumber) - .in("material_detail_unique_id", uniqueIds) - .eq("del_flag", 1)); - } - } - IMaterialMoreDetailService.saveBatch(materialMoreDetailList); - } +// if (!CollectionUtils.isEmpty(materialMoreDetailList)){ +// String receiptOrderNumber = stockReceiptOrderDO.getReceiptOrderNumber(); +// if (StringUtils.isBlank(receiptOrderNumber) && !CollectionUtils.isEmpty(receiptMaterialDetailDOList)) { +// receiptOrderNumber = receiptMaterialDetailDOList.get(0).getReceiptOrderNumber(); +// } +// if (StringUtils.isNotBlank(receiptOrderNumber)) { +// java.util.Set uniqueIds = collectReceiptDetailUniqueIds(receiptMaterialDetailDOList); +// if (!uniqueIds.isEmpty()) { +// IMaterialMoreDetailService.remove(new QueryWrapper() +// .eq("order_number", receiptOrderNumber) +// .in("material_detail_unique_id", uniqueIds) +// .eq("del_flag", 1)); +// } +// } +// IMaterialMoreDetailService.saveBatch(materialMoreDetailList); +// } //批量新增序列号 if (!CollectionUtils.isEmpty(materialDetailSerialNumberList)){ inMaterialDetailSerialNumberService.saveBatch(materialDetailSerialNumberList); @@ -513,6 +519,144 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl materialMoreDetailList, + StockReceiptOrderDO stockReceiptOrderDO, + List receiptMaterialDetailDOList) { + // 无批次属性则直接返回 + if (CollectionUtils.isEmpty(materialMoreDetailList)) { + return; + } + // 无收货单号无法做增量更新,退回全量插入 + String receiptOrderNumber = stockReceiptOrderDO.getReceiptOrderNumber(); + if (StringUtils.isBlank(receiptOrderNumber) && !CollectionUtils.isEmpty(receiptMaterialDetailDOList)) { + receiptOrderNumber = receiptMaterialDetailDOList.get(0).getReceiptOrderNumber(); + } + // 无收货单号无法做增量更新,退回全量插入 + if (StringUtils.isBlank(receiptOrderNumber)) { + IMaterialMoreDetailService.saveBatch(materialMoreDetailList); + return; + } + // 无明细唯一ID无法做增量更新,退回全量插入 + java.util.Set uniqueIds = collectReceiptDetailUniqueIds(receiptMaterialDetailDOList); + if (uniqueIds.isEmpty()) { + IMaterialMoreDetailService.saveBatch(materialMoreDetailList); + return; + } + // 查询已存在的批次属性记录 + List existingList = IMaterialMoreDetailService.list( + new QueryWrapper() + .eq("order_number", receiptOrderNumber) // 收货单号 + .in("material_detail_unique_id", uniqueIds) // 明细唯一ID + .eq("del_flag", 1)); // 删除标志 + // 按 materialDetailUniqueId + batchDetailId 构建索引 + Map existingMap = new HashMap<>(); + for (MaterialMoreDetail existing : existingList) { + String key = buildMaterialMoreDetailKey(existing.getMaterialDetailUniqueId(), existing.getBatchDetailId()); + existingMap.put(key, existing); + } + // 分离:需要更新的 以及 需要新增的;跳过空值(保留旧数据) + List toUpdate = new ArrayList<>(); + List toInsert = new ArrayList<>(); + for (MaterialMoreDetail incoming : materialMoreDetailList) { + // attributeValue 为空/空白时跳过,不覆盖已有数据 + if (StringUtils.isBlank(incoming.getAttributeValue())) { + continue; + } + // 按 materialDetailUniqueId + batchDetailId 构建索引 + String key = buildMaterialMoreDetailKey(incoming.getMaterialDetailUniqueId(), incoming.getBatchDetailId()); + // 已存在的批次属性记录 + MaterialMoreDetail existing = existingMap.get(key); + // 存在则更新 ,不存在则新增 + if (existing != null) { + // 设置主键走 update,保留已有记录的 id + incoming.setMaterialMoreDetailId(existing.getMaterialMoreDetailId()); + // 更新现有记录 + toUpdate.add(incoming); + } else { + // 插入新的记录 + toInsert.add(incoming); + } + } + // 判断需更新的记录是否存在,存在则更新 + if (!toUpdate.isEmpty()) { + IMaterialMoreDetailService.updateBatchById(toUpdate); + } + // 判断是否存在需新增的记录,存在则批量插入 + if (!toInsert.isEmpty()) { + IMaterialMoreDetailService.saveBatch(toInsert); + } + } + + /** + * 构建批次属性索引 + * @param materialDetailUniqueId 明细唯一ID + * @param batchDetailId 批次属性ID + * @return 批次属性索引 + */ + private static String buildMaterialMoreDetailKey(Long materialDetailUniqueId, Long batchDetailId) { + return (materialDetailUniqueId != null ? materialDetailUniqueId : "null") + "_" + + (batchDetailId != null ? batchDetailId : "null"); + } + + /** + * 将 total* 指标字段中值为 0 的置为 null。 + * MyBatis-Plus 默认 NOT_NULL 策略下,null 不参与 SET 子句,已有数据得以保留。 + * 注意:仅对「未填写」场景生效;用户确实需要填 0 的极端场景不受影响(因前端通常传 null 表示未填)。 + * @param receiptMaterialDetail 收货明细 + * 需保证 total* 字段已赋值。 + * 需保证 alreadyReceipt* 字段已赋值。 + * 静态方法修改 receiptMaterialDetail 参数 + **/ + private static void normalizeZeroMetricsToNull(ReceiptMaterialDetail receiptMaterialDetail) { + // entity 为 null 时直接返回 + if (receiptMaterialDetail == null) { + return; + } + // receiptMaterialDetail totalNetWeight 字段为 0 时置为 null + if (isZeroBigDecimal(receiptMaterialDetail.getTotalNetWeight())) { + receiptMaterialDetail.setTotalNetWeight(null); + } + // receiptMaterialDetail totalGrossWeight 字段为 0 时置为 null + if (isZeroBigDecimal(receiptMaterialDetail.getTotalGrossWeight())) { + receiptMaterialDetail.setTotalGrossWeight(null); + } + // receiptMaterialDetail totalVolume 字段为 0 时置为 null + if (isZeroBigDecimal(receiptMaterialDetail.getTotalVolume())) { + receiptMaterialDetail.setTotalVolume(null); + } + // receiptMaterialDetail totalArea 字段为 0 时置为 null + if (isZeroBigDecimal(receiptMaterialDetail.getTotalArea())) { + receiptMaterialDetail.setTotalArea(null); + } + // receiptMaterialDetail alreadyReceiptNetWeight 字段为 0 时置为 null + if (isZeroBigDecimal(receiptMaterialDetail.getAlreadyReceiptNetWeight())) { + receiptMaterialDetail.setAlreadyReceiptNetWeight(null); + } + // receiptMaterialDetail alreadyReceiptGrossWeight 字段为 0 时置为 null + if (isZeroBigDecimal(receiptMaterialDetail.getAlreadyReceiptGrossWeight())) { + receiptMaterialDetail.setAlreadyReceiptGrossWeight(null); + } + // receiptMaterialDetail alreadyReceiptVolume 字段为 0 时置为 null + if (isZeroBigDecimal(receiptMaterialDetail.getAlreadyReceiptVolume())) { + receiptMaterialDetail.setAlreadyReceiptVolume(null); + } + // receiptMaterialDetail alreadyReceiptArea 字段为 0 时置为 null + if (isZeroBigDecimal(receiptMaterialDetail.getAlreadyReceiptArea())) { + receiptMaterialDetail.setAlreadyReceiptArea(null); + } + } + + private static boolean isZeroBigDecimal(BigDecimal val) { + return val != null && val.compareTo(BigDecimal.ZERO) == 0; + } + private void setMore(ReceiptMaterialDetailDO receiptMaterialDetailDO) { List materialMoreDetailList = receiptMaterialDetailDO.getMaterialMoreDetailList(); if (!CollectionUtils.isEmpty(materialMoreDetailList)) {