From dfb360e1230c22967c84cdefec7ae4182a6e8c55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=A6=E9=B8=BF=E5=B1=95?= <18031053041@163.com> Date: Fri, 17 Apr 2026 18:06:16 +0800 Subject: [PATCH] =?UTF-8?q?PDA=E6=8A=84=E7=A0=81=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StockReceiptOrderApplicationService.java | 21 +- .../CopyCodeReferenceDomainService.java | 183 +++++++++++++++++ .../entity/PickingMaterialDetail.java | 8 + .../po/PickingMaterialDetailPO.java | 8 + .../todo/PickingMaterialDetailDO.java | 3 + .../service/PickingOrderDomainService.java | 5 +- .../repository/po/TaskMaterialPO.java | 5 + .../StockOutTaskOrderDomainService.java | 185 +++++++++++++++++- .../TaskPickingMaterialDetailImpl.java | 43 ++++ .../po/TaskPickingMaterialDetailPO.java | 9 + .../todo/TaskPickingMaterialDetailDO.java | 6 + .../PickingMaterialDetailMapper.xml | 7 + 12 files changed, 477 insertions(+), 6 deletions(-) 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 336b55d5b..6e926cd24 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 @@ -2269,6 +2269,21 @@ public class StockReceiptOrderApplicationService { line.setTotalArea(null); line.setLevel(1); line.setParentUniqueId(null); + // 本次抄码/托盘等已落到子行;若不清理主行,assemble 会用请求覆盖库中主行,导致第二笔冲掉第一笔抄码展示(与 batch_number 特例同因) + clearPdaParentCopyCodeFieldsAfterSyntheticChildSplit(line); + } + + /** + * PDA 分批拆子行后,主行仅保留计划行与首笔/累计已收;抄码实绩只在子行,主行抄码字段勿带入第二次请求的覆盖值。 + */ + private static void clearPdaParentCopyCodeFieldsAfterSyntheticChildSplit(ReceiptMaterialDetailDO line) { + if (line == null) { + return; + } + line.setPalletNumber(null); + line.setCopyBatch(null); + line.setCopyQuantity(null); + line.setCopyDetails(null); } /** @@ -3147,10 +3162,14 @@ public class StockReceiptOrderApplicationService { ReceiptMaterialDetailDO returnReceiptMaterialDetailDO = new ReceiptMaterialDetailDO(); BeanUtils.copyProperties(receiptMaterialDetailPO, returnReceiptMaterialDetailDO); BeanUtils.copyProperties(receiptMaterialDetailDO, returnReceiptMaterialDetailDO, IgnoreNullUtil.getNullPropertyNames(receiptMaterialDetailDO)); - // 主行本次收货件数为 0、仅子行有收货时:不从请求覆盖主行批次号(避免 PDA 把子行新批次回写到主行,冲掉首笔批次) + // 主行本次收货件数为 0、仅子行有收货时:不从请求覆盖主行批次号/抄码托盘等(避免 PDA 把子行新批次或第二笔抄码回写到主行,冲掉首笔) if (mainItemActualQuantity.compareTo(BigDecimal.ZERO) == 0 && !CollectionUtils.isEmpty(returnReceiptMaterialDetailDOChildList)) { returnReceiptMaterialDetailDO.setBatchNumber(receiptMaterialDetailPO.getBatchNumber()); + returnReceiptMaterialDetailDO.setPalletNumber(receiptMaterialDetailPO.getPalletNumber()); + returnReceiptMaterialDetailDO.setCopyBatch(receiptMaterialDetailPO.getCopyBatch()); + returnReceiptMaterialDetailDO.setCopyQuantity(receiptMaterialDetailPO.getCopyQuantity()); + returnReceiptMaterialDetailDO.setCopyDetails(receiptMaterialDetailPO.getCopyDetails()); } returnReceiptMaterialDetailDO.setTotalNetWeight(receiptMaterialDetailDO.getTotalNetWeight()); returnReceiptMaterialDetailDO.setTotalGrossWeight(receiptMaterialDetailDO.getTotalGrossWeight()); diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/copyCodeReference/service/CopyCodeReferenceDomainService.java b/mhd_wms/src/main/java/com/mhd/wms/domain/copyCodeReference/service/CopyCodeReferenceDomainService.java index 29859ed83..2acd53e09 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/copyCodeReference/service/CopyCodeReferenceDomainService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/copyCodeReference/service/CopyCodeReferenceDomainService.java @@ -1,15 +1,30 @@ package com.mhd.wms.domain.copyCodeReference.service; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.mhd.common.core.utils.bean.BeanUtils; +import com.mhd.wms.domain.copyCodeReference.entity.CopyCodeReference; import com.mhd.wms.domain.copyCodeReference.repository.facade.ICopyCodeReferenceService; import com.mhd.wms.domain.copyCodeReference.repository.po.CopyCodeReferencePO; import com.mhd.wms.domain.copyCodeReference.repository.todo.CopyCodeReferenceDO; +import com.mhd.wms.domain.pickingMaterialDetail.repository.po.PickingMaterialDetailPO; import com.mhd.wms.interfaces.dto.copyCodeReference.CopyCodeReferenceDTO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; @Service public class CopyCodeReferenceDomainService { @@ -24,4 +39,172 @@ public class CopyCodeReferenceDomainService { public List queryWeightList(CopyCodeReferenceDTO dto) { return copyCodeReferenceService.queryWeightList(dto); } + + /** + * 解析逗号分隔的抄码对照 id(顺序与字符串一致) + */ + public List parseCommaSeparatedLongIds(String csv) { + return parseCommaSeparatedLongIdsStatic(csv); + } + + private static List parseCommaSeparatedLongIdsStatic(String csv) { + if (!StringUtils.hasText(csv)) { + return Collections.emptyList(); + } + List out = new ArrayList<>(); + for (String part : csv.split(",")) { + String t = part.trim(); + if (t.isEmpty()) { + continue; + } + try { + out.add(Long.parseLong(t)); + } catch (NumberFormatException ignored) { + // skip invalid token + } + } + return out; + } + + /** + * 合并两段逗号分隔的抄码对照 id(去重,保留先出现的顺序)。仅 incoming 为空时返回 existing。 + */ + public static String mergeCommaSeparatedUniqueIds(String existing, String incoming) { + if (!StringUtils.hasText(incoming)) { + return StringUtils.hasText(existing) ? existing : null; + } + LinkedHashSet order = new LinkedHashSet<>(); + order.addAll(parseCommaSeparatedLongIdsStatic(existing)); + order.addAll(parseCommaSeparatedLongIdsStatic(incoming)); + if (order.isEmpty()) { + return null; + } + return order.stream().map(String::valueOf).collect(Collectors.joining(",")); + } + + /** + * 抄码拣货(按顺序):假定按 {@code copyCodeReferenceIds} 顺序依次拣完前 {@code pickingQuantity} 件。 + * 若现场不按顺序拣货,请改用 {@link #remainingCopyReferenceIdsExcludingPicked} + + * {@link #resolveRemainingCopyReferenceIdsForPicking},并在明细上持久化「已拣抄码 id 集合」。 + * + * @return 待拣抄码 id 子列表(去掉前 {@code pickedCount} 个) + */ + public static List remainingCopyReferenceIdsAfterPicked(List orderedIds, BigDecimal pickingQuantity) { + if (orderedIds == null || orderedIds.isEmpty()) { + return Collections.emptyList(); + } + int picked = 0; + if (pickingQuantity != null) { + picked = pickingQuantity.setScale(0, RoundingMode.DOWN).intValue(); + } + if (picked < 0) { + picked = 0; + } + if (picked >= orderedIds.size()) { + return Collections.emptyList(); + } + return new ArrayList<>(orderedIds.subList(picked, orderedIds.size())); + } + + /** + * 抄码拣货(乱序):已拣集合由库表/接口显式给出,与拣货顺序无关。 + * {@code orderedAll} 仅用于输出待拣 id 的先后展示顺序(通常与全量 copy_code_reference_ids 一致)。 + * + * @param pickedIdsCsv 已拣抄码对照 id,逗号分隔(可随扫描追加) + * @return 仍待拣的 id 列表(在 {@code orderedAll} 中且不在已拣集合内) + */ + public static List remainingCopyReferenceIdsExcludingPicked(List orderedAll, String pickedIdsCsv) { + if (orderedAll == null || orderedAll.isEmpty()) { + return Collections.emptyList(); + } + if (!StringUtils.hasText(pickedIdsCsv)) { + return new ArrayList<>(orderedAll); + } + Set picked = new HashSet<>(); + for (String part : pickedIdsCsv.split(",")) { + String t = part.trim(); + if (t.isEmpty()) { + continue; + } + try { + picked.add(Long.parseLong(t)); + } catch (NumberFormatException ignored) { + // skip + } + } + List out = new ArrayList<>(); + for (Long id : orderedAll) { + if (id != null && !picked.contains(id)) { + out.add(id); + } + } + return out; + } + + /** + * 计算待拣抄码 id:若 {@code pickedCopyCodeReferenceIds} 有值则按集合差(乱序); + * 否则退回 {@link #remainingCopyReferenceIdsAfterPicked}(顺序假设)。 + */ + public static List resolveRemainingCopyReferenceIdsForPicking( + List orderedIds, BigDecimal pickingQuantity, String pickedCopyCodeReferenceIds) { + if (orderedIds == null || orderedIds.isEmpty()) { + return Collections.emptyList(); + } + if (StringUtils.hasText(pickedCopyCodeReferenceIds)) { + return remainingCopyReferenceIdsExcludingPicked(orderedIds, pickedCopyCodeReferenceIds); + } + return remainingCopyReferenceIdsAfterPicked(orderedIds, pickingQuantity); + } + + /** + * 按 id 批量查询抄码对照,转为 PO(含 netWeight、batchNumber、boxPalletNo、serialNumber 等) + */ + public Map mapPoByIds(List distinctIds) { + if (CollectionUtils.isEmpty(distinctIds)) { + return Collections.emptyMap(); + } + List list = copyCodeReferenceService.list( + new LambdaQueryWrapper() + .in(CopyCodeReference::getId, distinctIds)); + Map map = new HashMap<>(list.size()); + for (CopyCodeReference c : list) { + CopyCodeReferencePO po = new CopyCodeReferencePO(); + BeanUtils.copyProperties(c, po); + map.put(c.getId(), po); + } + return map; + } + + /** + * 拣货单明细:根据行上 copyCodeReferenceIds 批量回填 weightList(与出库明细 weightList 结构一致) + */ + public void fillWeightListOnPickingMaterialDetails(List lines) { + if (CollectionUtils.isEmpty(lines)) { + return; + } + List all = new ArrayList<>(); + for (PickingMaterialDetailPO p : lines) { + all.addAll(parseCommaSeparatedLongIds(p.getCopyCodeReferenceIds())); + } + if (all.isEmpty()) { + return; + } + Map refMap = mapPoByIds(all.stream().distinct().collect(Collectors.toList())); + for (PickingMaterialDetailPO p : lines) { + List ordered = parseCommaSeparatedLongIds(p.getCopyCodeReferenceIds()); + if (ordered.isEmpty()) { + continue; + } + List remaining = resolveRemainingCopyReferenceIdsForPicking( + ordered, p.getPickingQuantity(), p.getPickedCopyCodeReferenceIds()); + List weightList = new ArrayList<>(); + for (Long id : remaining) { + CopyCodeReferencePO po = refMap.get(id); + if (po != null) { + weightList.add(po); + } + } + p.setWeightList(weightList); + } + } } diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/pickingMaterialDetail/entity/PickingMaterialDetail.java b/mhd_wms/src/main/java/com/mhd/wms/domain/pickingMaterialDetail/entity/PickingMaterialDetail.java index 19c8724f1..0e1f8eb87 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/pickingMaterialDetail/entity/PickingMaterialDetail.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/pickingMaterialDetail/entity/PickingMaterialDetail.java @@ -283,4 +283,12 @@ public class PickingMaterialDetail extends BaseVOEntity { @ApiModelProperty("抄码id数组 逗号分隔") @Excel(name = "抄码id数组") private String copyCodeReferenceIds; + + /** + * 已拣抄码对照 id(逗号分隔,与 {@link #copyCodeReferenceIds} 同源 id);乱序拣货时每次扫描追加,用于计算待拣集合。 + * 为空时接口仍按 {@code picking_quantity} 与全量 id 顺序假定「先拣前 N 件」。 + */ + @ApiModelProperty("已拣抄码对照id(逗号分隔,乱序拣货用)") + @Excel(name = "已拣抄码对照id") + private String pickedCopyCodeReferenceIds; } \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/pickingMaterialDetail/repository/po/PickingMaterialDetailPO.java b/mhd_wms/src/main/java/com/mhd/wms/domain/pickingMaterialDetail/repository/po/PickingMaterialDetailPO.java index 3e054306c..2eb7ff4d5 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/pickingMaterialDetail/repository/po/PickingMaterialDetailPO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/pickingMaterialDetail/repository/po/PickingMaterialDetailPO.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.mhd.common.core.annotation.Excel; import com.mhd.common.core.web.domain.BaseVOEntity; +import com.mhd.wms.domain.copyCodeReference.repository.po.CopyCodeReferencePO; import com.mhd.wms.domain.materialMoreDetail.repository.po.MaterialMoreDetailPO; import com.mhd.wms.domain.outMaterialDetailSerialNumber.repository.todo.OutMaterialDetailSerialNumberDO; import io.swagger.annotations.ApiModel; @@ -313,4 +314,11 @@ public class PickingMaterialDetailPO extends BaseVOEntity { @Excel(name = "抄码id数组") private String copyCodeReferenceIds; + @ApiModelProperty("已拣抄码对照id(逗号分隔,乱序拣货用;有值时待拣=全量 id 去掉已拣集合)") + private String pickedCopyCodeReferenceIds; + + @ApiModelProperty("待拣抄码克重明细(顺序/乱序规则见 CopyCodeReferenceDomainService#resolveRemainingCopyReferenceIdsForPicking)") + @TableField(exist = false) + private List weightList; + } \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/pickingMaterialDetail/repository/todo/PickingMaterialDetailDO.java b/mhd_wms/src/main/java/com/mhd/wms/domain/pickingMaterialDetail/repository/todo/PickingMaterialDetailDO.java index 1c28c3d46..3a2bda4e7 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/pickingMaterialDetail/repository/todo/PickingMaterialDetailDO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/pickingMaterialDetail/repository/todo/PickingMaterialDetailDO.java @@ -295,4 +295,7 @@ public class PickingMaterialDetailDO extends BaseVOEntity { @ApiModelProperty("抄码id数组 逗号分隔") @Excel(name = "抄码id数组") private String copyCodeReferenceIds; + + @ApiModelProperty("已拣抄码对照id(逗号分隔,合并写入)") + private String pickedCopyCodeReferenceIds; } \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/pickingOrder/service/PickingOrderDomainService.java b/mhd_wms/src/main/java/com/mhd/wms/domain/pickingOrder/service/PickingOrderDomainService.java index 8b7d8b13d..1935e4742 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/pickingOrder/service/PickingOrderDomainService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/pickingOrder/service/PickingOrderDomainService.java @@ -31,6 +31,7 @@ import com.mhd.wms.domain.mobilizeManageDetail.repository.facade.IMobilizeManage import com.mhd.wms.domain.mobilizeManageDetail.repository.po.MobilizeManageDetailPO; import com.mhd.wms.domain.mobilizeManageDetail.repository.todo.MobilizeManageDetailDO; import com.mhd.wms.domain.outMaterialDetail.entity.OutMaterialDetail; +import com.mhd.wms.domain.copyCodeReference.service.CopyCodeReferenceDomainService; import com.mhd.wms.domain.outMaterialDetail.repository.mapper.OutMaterialDetailMapper; import com.mhd.wms.domain.outOrderAbnormal.repository.facade.IOutOrderAbnormalService; import com.mhd.wms.domain.outOrderAbnormal.repository.todo.OutOrderAbnormalBaseDO; @@ -118,7 +119,8 @@ public class PickingOrderDomainService { private OutMaterialDetailMapper outMaterialDetailMapper; @Resource private MaterialBaseInfoMapper materialBaseInfoMapper; - + @Autowired + private CopyCodeReferenceDomainService copyCodeReferenceDomainService; /** @@ -239,6 +241,7 @@ public class PickingOrderDomainService { pickingMaterialDetailPO.setCopyCode(materialBaseInfo.getCopyCode()); } } + copyCodeReferenceDomainService.fillWeightListOnPickingMaterialDetails(pickingMaterialDetailPOList); pickingOrderPO.setMaterialDetailList(pickingMaterialDetailPOList); return pickingOrderPO; } diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutTaskOrder/repository/po/TaskMaterialPO.java b/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutTaskOrder/repository/po/TaskMaterialPO.java index a159142cd..e375f635c 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutTaskOrder/repository/po/TaskMaterialPO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutTaskOrder/repository/po/TaskMaterialPO.java @@ -1,5 +1,6 @@ package com.mhd.wms.domain.stockOutTaskOrder.repository.po; +import com.baomidou.mybatisplus.annotation.TableField; import com.fasterxml.jackson.annotation.JsonProperty; import com.mhd.common.core.annotation.Excel; import com.mhd.common.core.web.domain.BaseVOEntity; @@ -66,6 +67,10 @@ public class TaskMaterialPO extends BaseVOEntity { @Excel(name = "拣货状态: 1-待拣货 2-拣货中 3-已拣货", readConverterExp = "少=拣") private Integer pickingStatus; + @ApiModelProperty("是否抄码: 1-是 2-否(由分组内首条明细带出,查询时回填)") + @TableField(exist = false) + private Integer copyCode; + @ApiModelProperty("拣货作业物料详情") private List taskPickingMaterialDetailList; diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutTaskOrder/service/StockOutTaskOrderDomainService.java b/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutTaskOrder/service/StockOutTaskOrderDomainService.java index 58e5d743c..7af7482b3 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutTaskOrder/service/StockOutTaskOrderDomainService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutTaskOrder/service/StockOutTaskOrderDomainService.java @@ -12,6 +12,10 @@ import com.mhd.common.core.utils.bean.BeanUtils; import com.mhd.common.security.utils.SecurityUtils; import com.mhd.system.api.model.LoginUser; import com.mhd.wms.domain.inMaterialDetail.repository.todo.InMaterialDetailDO; +import com.mhd.wms.domain.copyCodeReference.repository.po.CopyCodeReferencePO; +import com.mhd.wms.domain.copyCodeReference.service.CopyCodeReferenceDomainService; +import com.mhd.wms.domain.materialBaseInfo.entity.MaterialBaseInfo; +import com.mhd.wms.domain.materialBaseInfo.repository.facade.IMaterialBaseInfoService; import com.mhd.wms.domain.materialInventory.entity.MaterialInventory; import com.mhd.wms.domain.materialInventory.repository.facade.IMaterialInventoryService; import com.mhd.wms.domain.materialInventory.repository.todo.MaterialInventoryDO; @@ -59,8 +63,10 @@ import javax.annotation.Resource; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; /** @@ -97,6 +103,10 @@ public class StockOutTaskOrderDomainService { private IOutOrderAbnormalService outOrderAbnormalService; @Autowired private IMaterialInventoryService materialInventoryService; + @Autowired + private IMaterialBaseInfoService materialBaseInfoService; + @Autowired + private CopyCodeReferenceDomainService copyCodeReferenceDomainService; @Resource private OutMaterialDetailMapper outMaterialDetailMapper; @@ -215,6 +225,8 @@ public class StockOutTaskOrderDomainService { taskPickingMaterialDetailDO.setTaskNumber(stockOutTaskOrderPO.getTaskNumber()); List taskPickingMaterialDetailPOList = taskPickingMaterialDetailService.queryList(taskPickingMaterialDetailDO); enrichTaskDetailPlanAndWork(stockOutTaskOrderPO, taskPickingMaterialDetailPOList); + fillTaskPickingDetailCopyCode(taskPickingMaterialDetailPOList); + fillTaskPickingDetailWeightList(stockOutTaskOrderPO, taskPickingMaterialDetailPOList); Map> taskPickingMaterialDetailPOMap = taskPickingMaterialDetailPOList.stream().collect(Collectors.groupingBy(TaskPickingMaterialDetailPO::getMaterialBaseInfoId)); int totalPickingMaterialQuantity = 0;//拣货单按物料分组 统计已拣货进度 for (Map.Entry> map : taskPickingMaterialDetailPOMap.entrySet()){ @@ -266,6 +278,8 @@ public class StockOutTaskOrderDomainService { // .collect(Collectors.groupingBy(OutMaterialDetailSerialNumberPO::getMaterialDetailUniqueId)); List taskPickingMaterialDetailPOList = taskPickingMaterialDetailService.queryList(taskPickingMaterialDetailDO); enrichTaskDetailPlanAndWork(stockOutTaskOrderPO, taskPickingMaterialDetailPOList); + fillTaskPickingDetailCopyCode(taskPickingMaterialDetailPOList); + fillTaskPickingDetailWeightList(stockOutTaskOrderPO, taskPickingMaterialDetailPOList); Map> taskPickingMaterialDetailPOMap = taskPickingMaterialDetailPOList.stream().collect(Collectors.groupingBy(TaskPickingMaterialDetailPO::getStorageLocationId)); int totalPickingMaterialQuantity = 0;//拣货单按库位分组 统计已拣货进度(含已完成的库位) int totalStorageCount = taskPickingMaterialDetailPOMap.size(); @@ -326,6 +340,8 @@ public class StockOutTaskOrderDomainService { taskPickingMaterialDetailDO.setTaskNumber(stockOutTaskOrderPO.getTaskNumber()); List taskPickingMaterialDetailPOList = taskPickingMaterialDetailService.queryList(taskPickingMaterialDetailDO); enrichTaskDetailPlanAndWork(stockOutTaskOrderPO, taskPickingMaterialDetailPOList); + fillTaskPickingDetailCopyCode(taskPickingMaterialDetailPOList); + fillTaskPickingDetailWeightList(stockOutTaskOrderPO, taskPickingMaterialDetailPOList); Map> taskPickingMaterialDetailPOMap = taskPickingMaterialDetailPOList.stream().collect(Collectors.groupingBy(TaskPickingMaterialDetailPO::getMaterialBaseInfoId)); int totalPickingMaterialQuantity = 0;//拣货单按物料分组 统计已拣货进度 List taskMaterialPOList = new ArrayList<>(); @@ -422,6 +438,45 @@ public class StockOutTaskOrderDomainService { } } + /** + * 解析作业行对应的出库明细:picking_unique_id 多为拣货单明细 unique_id,需经 picking_material_detail.out_unique_id 再查 out_material_detail。 + */ + private OutMaterialDetail resolveOutMaterialDetailForPickingLine(StockOutTaskOrderPO header, TaskPickingMaterialDetailPO line) { + if (header == null || line == null || line.getPickingUniqueId() == null) { + return null; + } + String outOrderNumber = header.getOrderNumber(); + if (!StringUtils.hasText(outOrderNumber)) { + return null; + } + OutMaterialDetail direct = outMaterialDetailMapper.selectOne(new LambdaQueryWrapper() + .eq(OutMaterialDetail::getOutOrderNumber, outOrderNumber) + .eq(OutMaterialDetail::getUniqueId, line.getPickingUniqueId()) + .eq(OutMaterialDetail::getDelFlag, 1)); + if (direct != null) { + return direct; + } + if (!StringUtils.hasText(header.getPickingOrderNumber())) { + return null; + } + List pmdList = pickingMaterialDetailService.list( + new LambdaQueryWrapper() + .eq(PickingMaterialDetail::getPickingOrderNumber, header.getPickingOrderNumber()) + .eq(PickingMaterialDetail::getUniqueId, line.getPickingUniqueId()) + .eq(PickingMaterialDetail::getDelFlag, 1)); + if (CollectionUtils.isEmpty(pmdList)) { + return null; + } + Long outUid = pmdList.get(0).getOutUniqueId(); + if (outUid == null) { + return null; + } + return outMaterialDetailMapper.selectOne(new LambdaQueryWrapper() + .eq(OutMaterialDetail::getOutOrderNumber, outOrderNumber) + .eq(OutMaterialDetail::getUniqueId, outUid) + .eq(OutMaterialDetail::getDelFlag, 1)); + } + /** * 作业单详情:按任务类型写入明细上的计划/作业展示数量(关联出库明细) */ @@ -439,10 +494,7 @@ public class StockOutTaskOrderDomainService { if (line.getPickingUniqueId() == null) { continue; } - OutMaterialDetail omd = outMaterialDetailMapper.selectOne(new LambdaQueryWrapper() - .eq(OutMaterialDetail::getOutOrderNumber, outOrderNumber) - .eq(OutMaterialDetail::getUniqueId, line.getPickingUniqueId()) - .eq(OutMaterialDetail::getDelFlag, 1)); + OutMaterialDetail omd = resolveOutMaterialDetailForPickingLine(header, line); if (omd == null) { continue; } @@ -460,6 +512,131 @@ public class StockOutTaskOrderDomainService { } } + /** + * 拣货作业明细:按物料主数据回填是否抄码(查询回显) + */ + private void fillTaskPickingDetailCopyCode(List lines) { + if (CollectionUtils.isEmpty(lines)) { + return; + } + List ids = lines.stream() + .map(TaskPickingMaterialDetailPO::getMaterialBaseInfoId) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + if (CollectionUtil.isEmpty(ids)) { + return; + } + List baseList = materialBaseInfoService.list( + new LambdaQueryWrapper() + .select(MaterialBaseInfo::getMaterialBaseInfoId, MaterialBaseInfo::getCopyCode) + .in(MaterialBaseInfo::getMaterialBaseInfoId, ids)); + if (CollectionUtils.isEmpty(baseList)) { + return; + } + Map copyByMaterialId = new HashMap<>(baseList.size()); + for (MaterialBaseInfo m : baseList) { + if (m.getMaterialBaseInfoId() != null) { + copyByMaterialId.put(m.getMaterialBaseInfoId(), m.getCopyCode()); + } + } + for (TaskPickingMaterialDetailPO line : lines) { + if (line.getMaterialBaseInfoId() != null) { + line.setCopyCode(copyByMaterialId.get(line.getMaterialBaseInfoId())); + } + } + } + + /** + * 拣货作业明细:按抄码 id 列表批量查 copy_code_reference,回填 weightList(与出库明细一致,含净重、批次号、托盘号等)。 + *

说明:作业明细上的 picking_unique_id 对应 {@link PickingMaterialDetail#uniqueId},抄码 id 落在拣货单明细表; + * 仅当该值恰好等于出库明细 unique_id 时才能从 out_material_detail 命中,故优先查 picking_material_detail。

+ *

抄码待拣:优先用拣货明细 {@code picked_copy_code_reference_ids}(乱序);否则按 {@code picking_quantity} 与 id 顺序假定先拣前 N 件。

+ */ + private void fillTaskPickingDetailWeightList(StockOutTaskOrderPO header, List lines) { + if (header == null || CollectionUtils.isEmpty(lines)) { + return; + } + List pickingUniqueIds = lines.stream() + .map(TaskPickingMaterialDetailPO::getPickingUniqueId) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + if (CollectionUtil.isEmpty(pickingUniqueIds)) { + return; + } + Map uniqueToCsv = new HashMap<>(); + Map uniqueToPickedCsv = new HashMap<>(); + // 1)拣货单明细:picking_unique_id = picking_material_detail.unique_id,COPY_CODE_REFERENCE_IDS 落在此 + if (StringUtils.hasText(header.getPickingOrderNumber())) { + List pmdList = pickingMaterialDetailService.list( + new LambdaQueryWrapper() + .eq(PickingMaterialDetail::getPickingOrderNumber, header.getPickingOrderNumber()) + .in(PickingMaterialDetail::getUniqueId, pickingUniqueIds) + .eq(PickingMaterialDetail::getDelFlag, 1)); + if (!CollectionUtils.isEmpty(pmdList)) { + for (PickingMaterialDetail pmd : pmdList) { + if (pmd.getUniqueId() != null && StringUtils.hasText(pmd.getCopyCodeReferenceIds())) { + uniqueToCsv.put(pmd.getUniqueId(), pmd.getCopyCodeReferenceIds()); + } + if (pmd.getUniqueId() != null && StringUtils.hasText(pmd.getPickedCopyCodeReferenceIds())) { + uniqueToPickedCsv.put(pmd.getUniqueId(), pmd.getPickedCopyCodeReferenceIds()); + } + } + } + } + // 2)出库明细:兼容 picking_unique_id 即 out_material_detail.unique_id 的历史数据 + if (StringUtils.hasText(header.getOrderNumber())) { + List omdList = outMaterialDetailMapper.selectList( + new LambdaQueryWrapper() + .eq(OutMaterialDetail::getOutOrderNumber, header.getOrderNumber()) + .in(OutMaterialDetail::getUniqueId, pickingUniqueIds) + .eq(OutMaterialDetail::getDelFlag, 1)); + if (!CollectionUtils.isEmpty(omdList)) { + for (OutMaterialDetail omd : omdList) { + if (omd.getUniqueId() != null && StringUtils.hasText(omd.getCopyCodeReferenceIds())) { + uniqueToCsv.putIfAbsent(omd.getUniqueId(), omd.getCopyCodeReferenceIds()); + } + } + } + } + if (uniqueToCsv.isEmpty()) { + return; + } + List allRefIds = new ArrayList<>(); + for (TaskPickingMaterialDetailPO line : lines) { + String csv = uniqueToCsv.get(line.getPickingUniqueId()); + if (StringUtils.hasText(csv)) { + allRefIds.addAll(copyCodeReferenceDomainService.parseCommaSeparatedLongIds(csv)); + } + } + if (allRefIds.isEmpty()) { + return; + } + Map refMap = copyCodeReferenceDomainService.mapPoByIds(allRefIds.stream().distinct().collect(Collectors.toList())); + for (TaskPickingMaterialDetailPO line : lines) { + String csv = uniqueToCsv.get(line.getPickingUniqueId()); + if (!StringUtils.hasText(csv)) { + continue; + } + List ordered = copyCodeReferenceDomainService.parseCommaSeparatedLongIds(csv); + if (ordered.isEmpty()) { + continue; + } + String pickedCsv = uniqueToPickedCsv.get(line.getPickingUniqueId()); + List remaining = CopyCodeReferenceDomainService.resolveRemainingCopyReferenceIdsForPicking( + ordered, line.getPickingQuantity(), pickedCsv); + List weightList = new ArrayList<>(); + for (Long id : remaining) { + CopyCodeReferencePO po = refMap.get(id); + if (po != null) { + weightList.add(po); + } + } + line.setWeightList(weightList); + } + } + private static BigDecimal detailPlanForDisplay(TaskPickingMaterialDetailPO d) { if (d == null) { return BigDecimal.ZERO; diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/taskPickingMaterialDetail/repository/persistence/TaskPickingMaterialDetailImpl.java b/mhd_wms/src/main/java/com/mhd/wms/domain/taskPickingMaterialDetail/repository/persistence/TaskPickingMaterialDetailImpl.java index 45b6415ea..d86e5ec05 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/taskPickingMaterialDetail/repository/persistence/TaskPickingMaterialDetailImpl.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/taskPickingMaterialDetail/repository/persistence/TaskPickingMaterialDetailImpl.java @@ -1,6 +1,7 @@ package com.mhd.wms.domain.taskPickingMaterialDetail.repository.persistence; import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.mhd.common.core.exception.ServiceException; @@ -10,6 +11,8 @@ import com.mhd.system.api.model.LoginUser; import com.mhd.wms.domain.outMaterialDetailSerialNumber.entity.OutMaterialDetailSerialNumber; import com.mhd.wms.domain.outMaterialDetailSerialNumber.repository.facade.IOutMaterialDetailSerialNumberService; import com.mhd.wms.domain.outMaterialDetailSerialNumber.repository.todo.OutMaterialDetailSerialNumberDO; +import com.mhd.wms.domain.copyCodeReference.service.CopyCodeReferenceDomainService; +import com.mhd.wms.domain.pickingMaterialDetail.entity.PickingMaterialDetail; import com.mhd.wms.domain.pickingMaterialDetail.repository.facade.IPickingMaterialDetailService; import com.mhd.wms.domain.pickingMaterialDetail.repository.todo.PickingMaterialDetailDO; import com.mhd.wms.domain.pickingMaterialDetail.repository.todo.PickingMaterialDetailDOByUpdate; @@ -25,12 +28,16 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; @@ -126,6 +133,28 @@ public class TaskPickingMaterialDetailImpl extends ServiceImpl taskPickingMaterialDetailMap = taskPickingMaterialDetailDbList.stream().collect(Collectors.toMap(TaskPickingMaterialDetail::getMaterialDetailId, Function.identity())); + Set pickingUniqueIdsInRequest = new HashSet<>(); + for (TaskPickingMaterialDetailDO row : taskPickingMaterialDetailDOList) { + if (ObjectUtil.isNull(row.getActualQuantity()) || row.getActualQuantity().compareTo(BigDecimal.ZERO) == 0) { + continue; + } + TaskPickingMaterialDetail taskDb = taskPickingMaterialDetailMap.get(row.getMaterialDetailId()); + if (taskDb != null && taskDb.getPickingUniqueId() != null) { + pickingUniqueIdsInRequest.add(taskDb.getPickingUniqueId()); + } + } + Map pmdByPickingUniqueId = new HashMap<>(); + if (!pickingUniqueIdsInRequest.isEmpty()) { + List pmdRows = pickingMaterialDetailService.list( + new LambdaQueryWrapper() + .in(PickingMaterialDetail::getUniqueId, pickingUniqueIdsInRequest) + .eq(PickingMaterialDetail::getDelFlag, 1)); + if (!CollectionUtils.isEmpty(pmdRows)) { + pmdByPickingUniqueId = pmdRows.stream() + .collect(Collectors.toMap(PickingMaterialDetail::getUniqueId, Function.identity(), (a, b) -> a)); + } + } + Map pickedCsvByPickingUnique = new HashMap<>(); // 批量新增或修改序列号 List outMaterialDetailSerialNumberList = new ArrayList<>(); BigDecimal totalPickingQuantity = BigDecimal.ZERO; @@ -162,11 +191,22 @@ public class TaskPickingMaterialDetailImpl extends ServiceImpl pickingUniqueId.equals(p.getUniqueId())).findFirst().orElse(null); if (existing != null) { existing.setPickingQuantity((existing.getPickingQuantity() != null ? existing.getPickingQuantity() : BigDecimal.ZERO).add(qty)); + if (StringUtils.hasText(mergedPickedCsv)) { + existing.setPickedCopyCodeReferenceIds(mergedPickedCsv); + } // 净重、毛重、体积、面积:拣货填写值直接覆盖,不累加 if (taskPickingMaterialDetailDO.getTotalNetWeight() != null) { existing.setTotalNetWeight(taskPickingMaterialDetailDO.getTotalNetWeight()); @@ -184,6 +224,9 @@ public class TaskPickingMaterialDetailImpl extends ServiceImpl weightList; + } diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/taskPickingMaterialDetail/repository/todo/TaskPickingMaterialDetailDO.java b/mhd_wms/src/main/java/com/mhd/wms/domain/taskPickingMaterialDetail/repository/todo/TaskPickingMaterialDetailDO.java index 20092288b..4befcec23 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/taskPickingMaterialDetail/repository/todo/TaskPickingMaterialDetailDO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/taskPickingMaterialDetail/repository/todo/TaskPickingMaterialDetailDO.java @@ -223,4 +223,10 @@ public class TaskPickingMaterialDetailDO extends BaseVOEntity { @ApiModelProperty("总面积(SQM)") @Excel(name = "总面积(SQM)") private BigDecimal totalArea; + + /** + * 本次确认拣货对应的抄码对照 id(逗号分隔,可与多行合并);乱序拣货时与 {@code actualQuantity} 同步上报,服务端合并写入拣货单明细 {@code picked_copy_code_reference_ids}。 + */ + @ApiModelProperty("本次已拣抄码对照id(逗号分隔,乱序拣货用)") + private String pickedCopyCodeReferenceIds; } diff --git a/mhd_wms/src/main/resources/mapper/pickingMaterialDetail/PickingMaterialDetailMapper.xml b/mhd_wms/src/main/resources/mapper/pickingMaterialDetail/PickingMaterialDetailMapper.xml index 16d7fb84e..486fd03a4 100644 --- a/mhd_wms/src/main/resources/mapper/pickingMaterialDetail/PickingMaterialDetailMapper.xml +++ b/mhd_wms/src/main/resources/mapper/pickingMaterialDetail/PickingMaterialDetailMapper.xml @@ -63,6 +63,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + @@ -79,6 +80,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" a.create_time, a.create_by, a.create_by_name, a.update_time, a.update_by, a.update_by_name, a.del_flag, a.total_area, a.total_gross_weight, a.total_net_weight, a.total_volume, a.out_unique_id, a.COPY_CODE_REFERENCE_IDS, + a.picked_copy_code_reference_ids, omd.in_order_number, omd.lot_no as lot_number @@ -265,6 +267,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" WHEN #{item.uniqueId} THEN COALESCE(#{item.totalArea}, total_area) + + + WHEN #{item.uniqueId} THEN COALESCE(#{item.pickedCopyCodeReferenceIds}, picked_copy_code_reference_ids) + + update_by = #{updateBy}, update_by_name = #{updateByName}, update_time = #{updateTime}