PDA抄码修改

This commit is contained in:
秦鸿展
2026-04-17 18:06:16 +08:00
parent 5d78a94f29
commit dfb360e123
12 changed files with 477 additions and 6 deletions
@@ -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());
@@ -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<CopyCodeReferencePO> queryWeightList(CopyCodeReferenceDTO dto) {
return copyCodeReferenceService.queryWeightList(dto);
}
/**
* 解析逗号分隔的抄码对照 id顺序与字符串一致
*/
public List<Long> parseCommaSeparatedLongIds(String csv) {
return parseCommaSeparatedLongIdsStatic(csv);
}
private static List<Long> parseCommaSeparatedLongIdsStatic(String csv) {
if (!StringUtils.hasText(csv)) {
return Collections.emptyList();
}
List<Long> 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<Long> 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(","));
}
/**
* 抄码拣货<strong>按顺序</strong>假定按 {@code copyCodeReferenceIds} 顺序依次拣完前 {@code pickingQuantity}
* 若现场<strong>不按顺序</strong>拣货请改用 {@link #remainingCopyReferenceIdsExcludingPicked} +
* {@link #resolveRemainingCopyReferenceIdsForPicking}并在明细上持久化已拣抄码 id 集合
*
* @return 待拣抄码 id 子列表去掉前 {@code pickedCount}
*/
public static List<Long> remainingCopyReferenceIdsAfterPicked(List<Long> 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()));
}
/**
* 抄码拣货<strong>乱序</strong>已拣集合由库表/接口显式给出与拣货顺序无关
* {@code orderedAll} 仅用于输出待拣 id 的先后展示顺序通常与全量 copy_code_reference_ids 一致
*
* @param pickedIdsCsv 已拣抄码对照 id逗号分隔可随扫描追加
* @return 仍待拣的 id 列表 {@code orderedAll} 中且不在已拣集合内
*/
public static List<Long> remainingCopyReferenceIdsExcludingPicked(List<Long> orderedAll, String pickedIdsCsv) {
if (orderedAll == null || orderedAll.isEmpty()) {
return Collections.emptyList();
}
if (!StringUtils.hasText(pickedIdsCsv)) {
return new ArrayList<>(orderedAll);
}
Set<Long> 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<Long> out = new ArrayList<>();
for (Long id : orderedAll) {
if (id != null && !picked.contains(id)) {
out.add(id);
}
}
return out;
}
/**
* 计算待拣抄码 id {@code pickedCopyCodeReferenceIds} 有值则按<strong>集合差</strong>乱序
* 否则退回 {@link #remainingCopyReferenceIdsAfterPicked}顺序假设
*/
public static List<Long> resolveRemainingCopyReferenceIdsForPicking(
List<Long> 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 netWeightbatchNumberboxPalletNoserialNumber
*/
public Map<Long, CopyCodeReferencePO> mapPoByIds(List<Long> distinctIds) {
if (CollectionUtils.isEmpty(distinctIds)) {
return Collections.emptyMap();
}
List<CopyCodeReference> list = copyCodeReferenceService.list(
new LambdaQueryWrapper<CopyCodeReference>()
.in(CopyCodeReference::getId, distinctIds));
Map<Long, CopyCodeReferencePO> 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<PickingMaterialDetailPO> lines) {
if (CollectionUtils.isEmpty(lines)) {
return;
}
List<Long> all = new ArrayList<>();
for (PickingMaterialDetailPO p : lines) {
all.addAll(parseCommaSeparatedLongIds(p.getCopyCodeReferenceIds()));
}
if (all.isEmpty()) {
return;
}
Map<Long, CopyCodeReferencePO> refMap = mapPoByIds(all.stream().distinct().collect(Collectors.toList()));
for (PickingMaterialDetailPO p : lines) {
List<Long> ordered = parseCommaSeparatedLongIds(p.getCopyCodeReferenceIds());
if (ordered.isEmpty()) {
continue;
}
List<Long> remaining = resolveRemainingCopyReferenceIdsForPicking(
ordered, p.getPickingQuantity(), p.getPickedCopyCodeReferenceIds());
List<CopyCodeReferencePO> weightList = new ArrayList<>();
for (Long id : remaining) {
CopyCodeReferencePO po = refMap.get(id);
if (po != null) {
weightList.add(po);
}
}
p.setWeightList(weightList);
}
}
}
@@ -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;
}
@@ -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<CopyCodeReferencePO> weightList;
}
@@ -295,4 +295,7 @@ public class PickingMaterialDetailDO extends BaseVOEntity {
@ApiModelProperty("抄码id数组 逗号分隔")
@Excel(name = "抄码id数组")
private String copyCodeReferenceIds;
@ApiModelProperty("已拣抄码对照id(逗号分隔,合并写入)")
private String pickedCopyCodeReferenceIds;
}
@@ -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;
}
@@ -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<TaskPickingMaterialDetailPO> taskPickingMaterialDetailList;
@@ -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<TaskPickingMaterialDetailPO> taskPickingMaterialDetailPOList = taskPickingMaterialDetailService.queryList(taskPickingMaterialDetailDO);
enrichTaskDetailPlanAndWork(stockOutTaskOrderPO, taskPickingMaterialDetailPOList);
fillTaskPickingDetailCopyCode(taskPickingMaterialDetailPOList);
fillTaskPickingDetailWeightList(stockOutTaskOrderPO, taskPickingMaterialDetailPOList);
Map<Long, List<TaskPickingMaterialDetailPO>> taskPickingMaterialDetailPOMap = taskPickingMaterialDetailPOList.stream().collect(Collectors.groupingBy(TaskPickingMaterialDetailPO::getMaterialBaseInfoId));
int totalPickingMaterialQuantity = 0;//拣货单按物料分组 统计已拣货进度
for (Map.Entry<Long, List<TaskPickingMaterialDetailPO>> map : taskPickingMaterialDetailPOMap.entrySet()){
@@ -266,6 +278,8 @@ public class StockOutTaskOrderDomainService {
// .collect(Collectors.groupingBy(OutMaterialDetailSerialNumberPO::getMaterialDetailUniqueId));
List<TaskPickingMaterialDetailPO> taskPickingMaterialDetailPOList = taskPickingMaterialDetailService.queryList(taskPickingMaterialDetailDO);
enrichTaskDetailPlanAndWork(stockOutTaskOrderPO, taskPickingMaterialDetailPOList);
fillTaskPickingDetailCopyCode(taskPickingMaterialDetailPOList);
fillTaskPickingDetailWeightList(stockOutTaskOrderPO, taskPickingMaterialDetailPOList);
Map<Long, List<TaskPickingMaterialDetailPO>> 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<TaskPickingMaterialDetailPO> taskPickingMaterialDetailPOList = taskPickingMaterialDetailService.queryList(taskPickingMaterialDetailDO);
enrichTaskDetailPlanAndWork(stockOutTaskOrderPO, taskPickingMaterialDetailPOList);
fillTaskPickingDetailCopyCode(taskPickingMaterialDetailPOList);
fillTaskPickingDetailWeightList(stockOutTaskOrderPO, taskPickingMaterialDetailPOList);
Map<Long, List<TaskPickingMaterialDetailPO>> taskPickingMaterialDetailPOMap = taskPickingMaterialDetailPOList.stream().collect(Collectors.groupingBy(TaskPickingMaterialDetailPO::getMaterialBaseInfoId));
int totalPickingMaterialQuantity = 0;//拣货单按物料分组 统计已拣货进度
List<TaskMaterialPO> 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<OutMaterialDetail>()
.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<PickingMaterialDetail> pmdList = pickingMaterialDetailService.list(
new LambdaQueryWrapper<PickingMaterialDetail>()
.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<OutMaterialDetail>()
.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<OutMaterialDetail>()
.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<TaskPickingMaterialDetailPO> lines) {
if (CollectionUtils.isEmpty(lines)) {
return;
}
List<Long> ids = lines.stream()
.map(TaskPickingMaterialDetailPO::getMaterialBaseInfoId)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
if (CollectionUtil.isEmpty(ids)) {
return;
}
List<MaterialBaseInfo> baseList = materialBaseInfoService.list(
new LambdaQueryWrapper<MaterialBaseInfo>()
.select(MaterialBaseInfo::getMaterialBaseInfoId, MaterialBaseInfo::getCopyCode)
.in(MaterialBaseInfo::getMaterialBaseInfoId, ids));
if (CollectionUtils.isEmpty(baseList)) {
return;
}
Map<Long, Integer> 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与出库明细一致含净重批次号托盘号等
* <p>说明作业明细上的 picking_unique_id 对应 {@link PickingMaterialDetail#uniqueId}抄码 id 落在拣货单明细表
* 仅当该值恰好等于出库明细 unique_id 时才能从 out_material_detail 命中故优先查 picking_material_detail</p>
* <p>抄码待拣优先用拣货明细 {@code picked_copy_code_reference_ids}乱序否则按 {@code picking_quantity} id 顺序假定先拣前 N </p>
*/
private void fillTaskPickingDetailWeightList(StockOutTaskOrderPO header, List<TaskPickingMaterialDetailPO> lines) {
if (header == null || CollectionUtils.isEmpty(lines)) {
return;
}
List<Long> pickingUniqueIds = lines.stream()
.map(TaskPickingMaterialDetailPO::getPickingUniqueId)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
if (CollectionUtil.isEmpty(pickingUniqueIds)) {
return;
}
Map<Long, String> uniqueToCsv = new HashMap<>();
Map<Long, String> uniqueToPickedCsv = new HashMap<>();
// 1拣货单明细picking_unique_id = picking_material_detail.unique_idCOPY_CODE_REFERENCE_IDS 落在此
if (StringUtils.hasText(header.getPickingOrderNumber())) {
List<PickingMaterialDetail> pmdList = pickingMaterialDetailService.list(
new LambdaQueryWrapper<PickingMaterialDetail>()
.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<OutMaterialDetail> omdList = outMaterialDetailMapper.selectList(
new LambdaQueryWrapper<OutMaterialDetail>()
.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<Long> 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<Long, CopyCodeReferencePO> 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<Long> ordered = copyCodeReferenceDomainService.parseCommaSeparatedLongIds(csv);
if (ordered.isEmpty()) {
continue;
}
String pickedCsv = uniqueToPickedCsv.get(line.getPickingUniqueId());
List<Long> remaining = CopyCodeReferenceDomainService.resolveRemainingCopyReferenceIdsForPicking(
ordered, line.getPickingQuantity(), pickedCsv);
List<CopyCodeReferencePO> 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;
@@ -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<TaskPickingMateri
.eq(TaskPickingMaterialDetail::getTaskNumber, stockOutTaskOrderDO.getTaskNumber())
.eq(TaskPickingMaterialDetail::getDelFlag, 1));
Map<Long, TaskPickingMaterialDetail> taskPickingMaterialDetailMap = taskPickingMaterialDetailDbList.stream().collect(Collectors.toMap(TaskPickingMaterialDetail::getMaterialDetailId, Function.identity()));
Set<Long> 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<Long, PickingMaterialDetail> pmdByPickingUniqueId = new HashMap<>();
if (!pickingUniqueIdsInRequest.isEmpty()) {
List<PickingMaterialDetail> pmdRows = pickingMaterialDetailService.list(
new LambdaQueryWrapper<PickingMaterialDetail>()
.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<Long, String> pickedCsvByPickingUnique = new HashMap<>();
// 批量新增或修改序列号
List<OutMaterialDetailSerialNumber> outMaterialDetailSerialNumberList = new ArrayList<>();
BigDecimal totalPickingQuantity = BigDecimal.ZERO;
@@ -162,11 +191,22 @@ public class TaskPickingMaterialDetailImpl extends ServiceImpl<TaskPickingMateri
}
Long pickingUniqueId = taskPickingMaterialDetailDb.getPickingUniqueId();
BigDecimal qty = taskPickingMaterialDetailDO.getActualQuantity() != null ? taskPickingMaterialDetailDO.getActualQuantity() : BigDecimal.ZERO;
String basePickedCsv = pickedCsvByPickingUnique.get(pickingUniqueId);
if (basePickedCsv == null) {
PickingMaterialDetail pmdRow = pmdByPickingUniqueId.get(pickingUniqueId);
basePickedCsv = pmdRow != null ? pmdRow.getPickedCopyCodeReferenceIds() : null;
}
String mergedPickedCsv = CopyCodeReferenceDomainService.mergeCommaSeparatedUniqueIds(
basePickedCsv, taskPickingMaterialDetailDO.getPickedCopyCodeReferenceIds());
pickedCsvByPickingUnique.put(pickingUniqueId, mergedPickedCsv);
// pickingUniqueId 聚合同一拣货明细可能对应多条任务明细
PickingMaterialDetailDO existing = pickingMaterialDetailList.stream()
.filter(p -> 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<TaskPickingMateri
PickingMaterialDetailDO pickingMaterialDetailDO = new PickingMaterialDetailDO();
pickingMaterialDetailDO.setUniqueId(pickingUniqueId);
pickingMaterialDetailDO.setPickingQuantity(qty);
if (StringUtils.hasText(mergedPickedCsv)) {
pickingMaterialDetailDO.setPickedCopyCodeReferenceIds(mergedPickedCsv);
}
pickingMaterialDetailDO.setTotalNetWeight(taskPickingMaterialDetailDO.getTotalNetWeight());
pickingMaterialDetailDO.setTotalGrossWeight(taskPickingMaterialDetailDO.getTotalGrossWeight());
pickingMaterialDetailDO.setTotalVolume(taskPickingMaterialDetailDO.getTotalVolume());
@@ -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.po.OutMaterialDetailSerialNumberPO;
import io.swagger.annotations.ApiModel;
@@ -235,4 +236,12 @@ public class TaskPickingMaterialDetailPO extends BaseVOEntity {
@TableField(exist = false)
private BigDecimal workQuantity;
@ApiModelProperty("是否抄码: 1-是 2-否(与物料主数据一致,查询时回填)")
@TableField(exist = false)
private Integer copyCode;
@ApiModelProperty("待拣抄码克重明细(来自 copy_code_reference;顺序与库存抄码 id 列表一致,已按 pickingQuantity 去掉已拣件,仅余待扫)")
@TableField(exist = false)
private List<CopyCodeReferencePO> weightList;
}
@@ -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;
}
@@ -63,6 +63,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="totalVolume" column="total_volume" />
<result property="outUniqueId" column="out_unique_id" />
<result property="copyCodeReferenceIds" column="COPY_CODE_REFERENCE_IDS" />
<result property="pickedCopyCodeReferenceIds" column="picked_copy_code_reference_ids" />
</resultMap>
@@ -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
</sql>
@@ -265,6 +267,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
WHEN #{item.uniqueId} THEN COALESCE(#{item.totalArea}, total_area)
</foreach>
</trim>
<trim prefix="picked_copy_code_reference_ids = CASE unique_id" suffix="END,">
<foreach collection="pickingMaterialDetailList" item="item" index="index">
WHEN #{item.uniqueId} THEN COALESCE(#{item.pickedCopyCodeReferenceIds}, picked_copy_code_reference_ids)
</foreach>
</trim>
update_by = #{updateBy},
update_by_name = #{updateByName},
update_time = #{updateTime}