Merge remote-tracking branch 'origin/dev_WMS20260401' into dev_WMS20260401

This commit is contained in:
zhou-hongcheng
2026-04-16 16:38:42 +08:00
5 changed files with 303 additions and 84 deletions
@@ -275,6 +275,7 @@ public class StockReceiptOrderApplicationService {
// 4.3 为每个明细行填充物料单位信息(如果单位信息为空) // 4.3 为每个明细行填充物料单位信息(如果单位信息为空)
fillMaterialDetailUnitInfoRecursively(receiptMaterialDetailPOList, materialBaseInfoMap, packDetailMap); fillMaterialDetailUnitInfoRecursively(receiptMaterialDetailPOList, materialBaseInfoMap, packDetailMap);
fillReceiptOrderHasCopyCodeFromMaterialBase(stockReceiptOrderPO, materialBaseInfoMap);
// 4.4 为每个明细行填充物料条码(为空时取物料维护的条码信息第一行的 barCode) // 4.4 为每个明细行填充物料条码(为空时取物料维护的条码信息第一行的 barCode)
Map<Long, String> materialBarCodeMap = buildMaterialBarCodeMap(materialBaseInfoIdSet); Map<Long, String> materialBarCodeMap = buildMaterialBarCodeMap(materialBaseInfoIdSet);
@@ -842,6 +843,23 @@ public class StockReceiptOrderApplicationService {
* @param materialBaseInfoMap 物料基础信息Mapkey: materialBaseInfoId, value: MaterialBaseInfoPO * @param materialBaseInfoMap 物料基础信息Mapkey: materialBaseInfoId, value: MaterialBaseInfoPO
* @param packDetailMap 包装规格明细Mapkey: materialBaseInfoId, value: PackDetailFeignPO,单位代码为EA * @param packDetailMap 包装规格明细Mapkey: materialBaseInfoId, value: PackDetailFeignPO,单位代码为EA
*/ */
/**
* 收货单头:根据本单涉及的物料主数据汇总「整单是否含抄码物料」(与明细行 copyCode 同源)
*/
private void fillReceiptOrderHasCopyCodeFromMaterialBase(StockReceiptOrderPO order, Map<Long, MaterialBaseInfoPO> materialBaseInfoMap) {
if (order == null) {
return;
}
if (materialBaseInfoMap == null || materialBaseInfoMap.isEmpty()) {
order.setHasCopyCodeMaterial(2);
return;
}
boolean anyCopy = materialBaseInfoMap.values().stream()
.filter(Objects::nonNull)
.anyMatch(m -> m.getCopyCode() != null && m.getCopyCode() == 1);
order.setHasCopyCodeMaterial(anyCopy ? 1 : 2);
}
private void fillMaterialDetailUnitInfoRecursively(List<ReceiptMaterialDetailPO> receiptMaterialDetailPOList, private void fillMaterialDetailUnitInfoRecursively(List<ReceiptMaterialDetailPO> receiptMaterialDetailPOList,
Map<Long, MaterialBaseInfoPO> materialBaseInfoMap, Map<Long, MaterialBaseInfoPO> materialBaseInfoMap,
Map<Long, PackDetailFeignPO> packDetailMap) { Map<Long, PackDetailFeignPO> packDetailMap) {
@@ -865,6 +883,9 @@ public class StockReceiptOrderApplicationService {
if (StringUtils.isBlank(receiptMaterialDetailPO.getPackName()) && StringUtils.isNotBlank(materialBaseInfoPO.getPackName())) { if (StringUtils.isBlank(receiptMaterialDetailPO.getPackName()) && StringUtils.isNotBlank(materialBaseInfoPO.getPackName())) {
receiptMaterialDetailPO.setPackName(materialBaseInfoPO.getPackName()); receiptMaterialDetailPO.setPackName(materialBaseInfoPO.getPackName());
} }
if (materialBaseInfoPO.getCopyCode() != null) {
receiptMaterialDetailPO.setCopyCode(materialBaseInfoPO.getCopyCode());
}
} }
// 只有当单位信息为空时才填充 // 只有当单位信息为空时才填充
if (StringUtils.isBlank(receiptMaterialDetailPO.getUnitCode()) if (StringUtils.isBlank(receiptMaterialDetailPO.getUnitCode())
@@ -1167,84 +1188,160 @@ public class StockReceiptOrderApplicationService {
return null; return null;
} }
List<ReceiptMaterialDetailPO> materialDetailList = stockReceiptOrderPO.getMaterialDetailList(); List<ReceiptMaterialDetailPO> materialDetailList = stockReceiptOrderPO.getMaterialDetailList();
if (!CollectionUtils.isEmpty(materialDetailList)) { if (CollectionUtils.isEmpty(materialDetailList)) {
// PDA 详情筛选:receiptStatus=1 仅 1 待收货、2 收货中;receiptStatus=3 为 3 已收货、4 少收、5 超收(不含 1、2) stockReceiptOrderPO.setHasCopyCodeMaterial(2);
if (receiptStatus != null) { return stockReceiptOrderPO;
materialDetailList = filterMaterialDetailsByReceiptStatus(materialDetailList, receiptStatus); }
stockReceiptOrderPO.setMaterialDetailList(materialDetailList); // PDA 详情筛选:receiptStatus=1 仅 1 待收货、2 收货中;receiptStatus=3 为 3 已收货、4 少收、5 超收(不含 1、2)
} if (receiptStatus != null) {
if (CollectionUtils.isEmpty(materialDetailList)) { materialDetailList = filterMaterialDetailsByReceiptStatus(materialDetailList, receiptStatus);
return stockReceiptOrderPO; stockReceiptOrderPO.setMaterialDetailList(materialDetailList);
} }
Set<Long> materialBaseInfoIdSet = new HashSet<>(); if (CollectionUtils.isEmpty(materialDetailList)) {
collectMaterialBaseInfoIdsRecursively(materialDetailList, materialBaseInfoIdSet); stockReceiptOrderPO.setHasCopyCodeMaterial(2);
Map<Long, MaterialBaseInfoPO> materialBaseInfoMap = new HashMap<>(); return stockReceiptOrderPO;
for (Long materialBaseInfoId : materialBaseInfoIdSet) { }
try { Set<Long> materialBaseInfoIdSet = new HashSet<>();
MaterialBaseInfoPO materialBaseInfoPO = materialBaseInfoService.getInfo(materialBaseInfoId); collectMaterialBaseInfoIdsRecursively(materialDetailList, materialBaseInfoIdSet);
if (materialBaseInfoPO != null) { Map<Long, MaterialBaseInfoPO> materialBaseInfoMap = new HashMap<>();
materialBaseInfoMap.put(materialBaseInfoId, materialBaseInfoPO); for (Long materialBaseInfoId : materialBaseInfoIdSet) {
} try {
} catch (Exception e) { MaterialBaseInfoPO materialBaseInfoPO = materialBaseInfoService.getInfo(materialBaseInfoId);
log.warn("获取物料基础信息失败,物料基础信息ID:{},错误:{}", materialBaseInfoId, e.getMessage()); if (materialBaseInfoPO != null) {
materialBaseInfoMap.put(materialBaseInfoId, materialBaseInfoPO);
} }
} } catch (Exception e) {
Map<Long, PackDetailFeignPO> packDetailMap = new HashMap<>(); log.warn("获取物料基础信息失败,物料基础信息ID:{},错误:{}", materialBaseInfoId, e.getMessage());
for (Long materialBaseInfoId : materialBaseInfoIdSet) {
MaterialBaseInfoPO materialBaseInfoPO = materialBaseInfoMap.get(materialBaseInfoId);
if (materialBaseInfoPO != null && materialBaseInfoPO.getPackId() != null) {
try {
AjaxResult packDetailResult = systemServiceFeign.getInfoByPackIdAndUnitCode(materialBaseInfoPO.getPackId(), "EA");
if (packDetailResult != null && "200".equals(String.valueOf(packDetailResult.get("code")))
&& packDetailResult.get("data") != null) {
PackDetailFeignPO packDetailFeignPO = JSON.parseObject(
JSONObject.toJSONString(packDetailResult.get("data")),
PackDetailFeignPO.class);
if (packDetailFeignPO != null) {
packDetailMap.put(materialBaseInfoId, packDetailFeignPO);
}
}
} catch (Exception e) {
log.warn("获取包装规格EA单位信息失败,物料基础信息ID:{},包装ID:{},错误:{}",
materialBaseInfoId, materialBaseInfoPO.getPackId(), e.getMessage());
}
}
}
fillMaterialDetailUnitInfoRecursively(materialDetailList, materialBaseInfoMap, packDetailMap);
// 物料条码为空时取物料维护的条码信息第一行的 barCode
Map<Long, String> materialBarCodeMap = buildMaterialBarCodeMap(materialBaseInfoIdSet);
fillBarCodeFromMaterialBarCodeRecursively(materialDetailList, materialBarCodeMap);
// 第一次收货:主项无子项时,收货数量默认等于计划数量
fillFirstReceiptQuantityDefault(materialDetailList);
// PDA 端与 PC 端一致:主行收货数量取第一条子项,已收货数量汇总所有子项
flattenMaterialDetailList(materialDetailList);
// 须先算待收指标再清空子项 quantity;已收尾明细(3/4/5)不按「计划−待收」计算,见 isPdaReceiptDetailFullyReceived
if (receiptStatus != null && receiptStatus == 1) {
fillPendingDisplayFieldsRecursively(materialDetailList);
} else {
fillPendingMetricsOnlyRecursively(materialDetailList);
fillPendingReceiptQuantityRecursively(materialDetailList);
syncReceiptQuantityCumulativeDisplayRecursively(materialDetailList);
}
// pending* = plan* already_receipt_*(主行 already* 已为全部已收汇总)
fillPlanAndPendingMetricsRecursively(materialDetailList);
// 未完成行:total* 与 pending* 同值,即「计划总的 − 全部已收」
overwriteTotalWithPendingForPdaDisplayRecursively(materialDetailList);
clearChildQuantityRecursively(materialDetailList);
// 仅在未按 tab 筛明细时纠正整单头状态;筛成「待收/已收」子集时不能据子集推断整单是否已收完
if (receiptStatus == null) {
refreshPdaReceiptOrderHeaderStatusFromDerivedPlanLines(stockReceiptOrderPO, materialDetailList);
} }
} }
Map<Long, PackDetailFeignPO> packDetailMap = new HashMap<>();
for (Long materialBaseInfoId : materialBaseInfoIdSet) {
MaterialBaseInfoPO materialBaseInfoPO = materialBaseInfoMap.get(materialBaseInfoId);
if (materialBaseInfoPO != null && materialBaseInfoPO.getPackId() != null) {
try {
AjaxResult packDetailResult = systemServiceFeign.getInfoByPackIdAndUnitCode(materialBaseInfoPO.getPackId(), "EA");
if (packDetailResult != null && "200".equals(String.valueOf(packDetailResult.get("code")))
&& packDetailResult.get("data") != null) {
PackDetailFeignPO packDetailFeignPO = JSON.parseObject(
JSONObject.toJSONString(packDetailResult.get("data")),
PackDetailFeignPO.class);
if (packDetailFeignPO != null) {
packDetailMap.put(materialBaseInfoId, packDetailFeignPO);
}
}
} catch (Exception e) {
log.warn("获取包装规格EA单位信息失败,物料基础信息ID:{},包装ID:{},错误:{}",
materialBaseInfoId, materialBaseInfoPO.getPackId(), e.getMessage());
}
}
}
fillMaterialDetailUnitInfoRecursively(materialDetailList, materialBaseInfoMap, packDetailMap);
fillReceiptOrderHasCopyCodeFromMaterialBase(stockReceiptOrderPO, materialBaseInfoMap);
// 物料条码为空时取物料维护的条码信息第一行的 barCode
Map<Long, String> materialBarCodeMap = buildMaterialBarCodeMap(materialBaseInfoIdSet);
fillBarCodeFromMaterialBarCodeRecursively(materialDetailList, materialBarCodeMap);
// 第一次收货:主项无子项时,收货数量默认等于计划数量
fillFirstReceiptQuantityDefault(materialDetailList);
// PDA 端与 PC 端一致:主行收货数量取第一条子项,已收货数量汇总所有子项
flattenMaterialDetailList(materialDetailList);
// 须先算待收指标再清空子项 quantity;已收尾明细(3/4/5)不按「计划−待收」计算,见 isPdaReceiptDetailFullyReceived
if (receiptStatus != null && receiptStatus == 1) {
fillPendingDisplayFieldsRecursively(materialDetailList);
} else {
fillPendingMetricsOnlyRecursively(materialDetailList);
fillPendingReceiptQuantityRecursively(materialDetailList);
syncReceiptQuantityCumulativeDisplayRecursively(materialDetailList);
}
// pending* = plan* already_receipt_*(主行 already* 已为全部已收汇总)
fillPlanAndPendingMetricsRecursively(materialDetailList);
// 未完成行:total* 与 pending* 同值,即「计划总的 − 全部已收」
overwriteTotalWithPendingForPdaDisplayRecursively(materialDetailList);
clearChildQuantityRecursively(materialDetailList);
// 仅在未按 tab 筛明细时纠正整单头状态;筛成「待收/已收」子集时不能据子集推断整单是否已收完
if (receiptStatus == null) {
refreshPdaReceiptOrderHeaderStatusFromDerivedPlanLines(stockReceiptOrderPO, materialDetailList);
}
return stockReceiptOrderPO; return stockReceiptOrderPO;
} }
/**
* PDA:与 PC 端收货明细上的「抄码方式」同源——物料主数据 {@link MaterialBaseInfoPO#getCopyCode()}1-是 2-否)。
* 在列表页未调用 {@link #getInfoByApp(Long, Integer)} 时,可仅凭收货单 ID + 明细 materialDetailId 拉取该标识用于跳转抄码页或普通收货页。
*/
public Map<String, Object> getCopyCodeForPdaReceiptLine(Long receiptOrderId, Long materialDetailId) {
StockReceiptOrderPO order = stockReceiptOrderDomainService.getInfo(receiptOrderId);
if (order == null) {
throw new ServiceException("收货单不存在");
}
ReceiptMaterialDetailPO line = receiptMaterialDetailDomainService.getInfo(materialDetailId);
if (line == null) {
throw new ServiceException("收货明细不存在");
}
if (!Objects.equals(order.getReceiptOrderNumber(), line.getReceiptOrderNumber())) {
throw new ServiceException("收货明细不属于该收货单");
}
Long materialBaseInfoId = line.getMaterialBaseInfoId();
Map<String, Object> ret = new HashMap<>(4);
ret.put("materialDetailId", materialDetailId);
ret.put("materialBaseInfoId", materialBaseInfoId);
if (materialBaseInfoId == null) {
ret.put("copyCode", null);
return ret;
}
MaterialBaseInfoPO m = materialBaseInfoService.getInfo(materialBaseInfoId);
ret.put("copyCode", m != null ? m.getCopyCode() : null);
return ret;
}
/**
* PDA:仅已知物料基础信息 ID 时查询是否抄码(与 PC 物料主数据一致)。列表若带出 materialBaseInfoId 可直接用,无需收货明细 ID。
*/
public Map<String, Object> getCopyCodeByMaterialBaseInfoId(Long materialBaseInfoId) {
if (materialBaseInfoId == null) {
throw new ServiceException("物料基础信息ID不能为空");
}
MaterialBaseInfoPO m = materialBaseInfoService.getInfo(materialBaseInfoId);
Map<String, Object> ret = new HashMap<>(4);
ret.put("materialBaseInfoId", materialBaseInfoId);
ret.put("copyCode", m != null ? m.getCopyCode() : null);
return ret;
}
/** /**
* PDA:点击卡片后查询当前计划行下全部分批收货子行(level=2,库表真实数据,不含 getInfoByApp 的 parent_copy)。 * PDA:点击卡片后查询当前计划行下全部分批收货子行(level=2,库表真实数据,不含 getInfoByApp 的 parent_copy)。
*/ */
public List<ReceiptMaterialDetailPO> listLevel2ChildrenByParentForApp(Long receiptOrderId, Long parentMaterialDetailId) { public List<ReceiptMaterialDetailPO> listLevel2ChildrenByParentForApp(Long receiptOrderId, Long parentMaterialDetailId) {
List<ReceiptMaterialDetailPO> receiptMaterialDetailPOS = stockReceiptOrderDomainService.listLevel2ChildrenByParentForApp(receiptOrderId, parentMaterialDetailId); List<ReceiptMaterialDetailPO> list = stockReceiptOrderDomainService.listLevel2ChildrenByParentForApp(receiptOrderId, parentMaterialDetailId);
return stockReceiptOrderDomainService.listLevel2ChildrenByParentForApp(receiptOrderId, parentMaterialDetailId); if (CollectionUtils.isEmpty(list)) {
return list;
}
Set<Long> materialBaseInfoIdSet = new HashSet<>();
for (ReceiptMaterialDetailPO line : list) {
if (line != null && line.getMaterialBaseInfoId() != null) {
materialBaseInfoIdSet.add(line.getMaterialBaseInfoId());
}
}
Map<Long, MaterialBaseInfoPO> materialBaseInfoMap = new HashMap<>();
for (Long id : materialBaseInfoIdSet) {
try {
MaterialBaseInfoPO po = materialBaseInfoService.getInfo(id);
if (po != null) {
materialBaseInfoMap.put(id, po);
}
} catch (Exception e) {
log.warn("获取物料基础信息失败,物料基础信息ID:{},错误:{}", id, e.getMessage());
}
}
for (ReceiptMaterialDetailPO line : list) {
if (line == null || line.getMaterialBaseInfoId() == null) {
continue;
}
MaterialBaseInfoPO mb = materialBaseInfoMap.get(line.getMaterialBaseInfoId());
if (mb != null && mb.getCopyCode() != null) {
line.setCopyCode(mb.getCopyCode());
}
}
return list;
} }
/** /**
@@ -1985,9 +2082,12 @@ public class StockReceiptOrderApplicationService {
continue; continue;
} }
ReceiptMaterialDetailDO firstChild = children.get(0); ReceiptMaterialDetailDO firstChild = children.get(0);
// 将第一条子项的值赋给主项(含批次属性、收货数量等 // 主行已携带本次收货/抄码数据时,不再被 children[0] 覆盖(避免 copyDetails/copyQuantity 被清空
BeanUtils.copyProperties(firstChild, parent, "children", "parentUniqueId", "uniqueId", "materialDetailId", if (!hasPdaSubmittedReceiptOrCopyData(parent)) {
"organizationIdList", "permissionMenuId", "receiptOrderNumberList", "compoundOrQuery"); // 将第一条子项的值赋给主项(含批次属性、收货数量等)
BeanUtils.copyProperties(firstChild, parent, "children", "parentUniqueId", "uniqueId", "materialDetailId",
"organizationIdList", "permissionMenuId", "receiptOrderNumberList", "compoundOrQuery");
}
// 删除 children 中的第一条 // 删除 children 中的第一条
List<ReceiptMaterialDetailDO> newChildren = new ArrayList<>(); List<ReceiptMaterialDetailDO> newChildren = new ArrayList<>();
for (int i = 1; i < children.size(); i++) { for (int i = 1; i < children.size(); i++) {
@@ -1997,6 +2097,26 @@ public class StockReceiptOrderApplicationService {
} }
} }
private static boolean hasPdaSubmittedReceiptOrCopyData(ReceiptMaterialDetailDO line) {
if (line == null) {
return false;
}
BigDecimal qty = line.getReceiptQuantity() != null ? line.getReceiptQuantity() : BigDecimal.ZERO;
BigDecimal gross = line.getReceiptGrossWeight() != null ? line.getReceiptGrossWeight() : BigDecimal.ZERO;
BigDecimal net = line.getReceiptNetWeight() != null ? line.getReceiptNetWeight() : BigDecimal.ZERO;
BigDecimal volume = line.getReceiptVolume() != null ? line.getReceiptVolume() : BigDecimal.ZERO;
BigDecimal area = line.getReceiptArea() != null ? line.getReceiptArea() : BigDecimal.ZERO;
return qty.compareTo(BigDecimal.ZERO) > 0
|| gross.compareTo(BigDecimal.ZERO) > 0
|| net.compareTo(BigDecimal.ZERO) > 0
|| volume.compareTo(BigDecimal.ZERO) > 0
|| area.compareTo(BigDecimal.ZERO) > 0
|| StringUtils.isNotBlank(line.getCopyQuantity())
|| StringUtils.isNotBlank(line.getCopyDetails())
|| StringUtils.isNotBlank(line.getCopyBatch())
|| StringUtils.isNotBlank(line.getPalletNumber());
}
/** /**
* PDA 收货回传时,将 materialDetailList 的第一项作为主项(level 1),其余项作为其子项(level 2) * PDA 收货回传时,将 materialDetailList 的第一项作为主项(level 1),其余项作为其子项(level 2)
* 仅当数据库中第二项为 level 2(真实子项)时才转换,避免将两条平铺明细错误转为父子导致第一条被覆盖 * 仅当数据库中第二项为 level 2(真实子项)时才转换,避免将两条平铺明细错误转为父子导致第一条被覆盖
@@ -139,6 +139,9 @@ public class StockReceiptOrderPO extends StockInOrderBasePO {
@ApiModelProperty("物料明细") @ApiModelProperty("物料明细")
private List<ReceiptMaterialDetailPO> materialDetailList; private List<ReceiptMaterialDetailPO> materialDetailList;
@ApiModelProperty("整单是否含抄码物料:1-是(至少一行物料主数据 copyCode=1) 2-否;与明细行 copyCode 同源,来自物料主数据")
private Integer hasCopyCodeMaterial;
@ApiModelProperty("收货作业单号") @ApiModelProperty("收货作业单号")
private String receiptTaskNumber; private String receiptTaskNumber;
@@ -1123,33 +1123,92 @@ public class StockShelfOrderDomainService {
} }
} }
/**
* 上架完成库存入账后写入抄码对照表数据来自上架明细 {@link ShelfMaterialDetail#getCopyDetails()}
* 与收货明细/PDA 提交的 JSON 一致key 为序号字符串value 为单件净重千克支持小数如 1.343
*/
private void copyCodeProductComparison(MaterialBaseInfo materialBaseInfo, ShelfMaterialDetail shelfMaterialDetail, MaterialInventoryParamDO materialInventoryId) { private void copyCodeProductComparison(MaterialBaseInfo materialBaseInfo, ShelfMaterialDetail shelfMaterialDetail, MaterialInventoryParamDO materialInventoryId) {
JSONObject jsonObject = JSONObject.parseObject(shelfMaterialDetail.getCopyDetails()); if (materialBaseInfo == null || shelfMaterialDetail == null || materialInventoryId == null) {
ArrayList<CopyCodeReference> copyCodeReferences = new ArrayList<>(); return;
}
if (StringUtils.isBlank(shelfMaterialDetail.getCopyDetails())) {
return;
}
JSONObject jsonObject;
try {
jsonObject = JSONObject.parseObject(shelfMaterialDetail.getCopyDetails().trim());
} catch (Exception e) {
log.warn("抄码 copyDetails 非合法 JSON,跳过写入对照表,materialDetailId={}raw={}",
shelfMaterialDetail.getMaterialDetailId(), shelfMaterialDetail.getCopyDetails(), e);
return;
}
if (jsonObject == null || jsonObject.size() == 0) {
return;
}
List<CopyCodeReference> copyCodeReferences = new ArrayList<>();
for (String key : jsonObject.keySet()) { for (String key : jsonObject.keySet()) {
if (StringUtils.isBlank(key)) {
continue;
}
BigDecimal lineNetKg = parseCopyDetailNetWeightKg(jsonObject.get(key));
if (lineNetKg == null) {
continue;
}
int serial;
try {
serial = Integer.parseInt(key.trim());
} catch (NumberFormatException e) {
log.warn("抄码 copyDetails 序号非数字,已跳过 key={}", key);
continue;
}
CopyCodeReference copyCodeReference = new CopyCodeReference(); CopyCodeReference copyCodeReference = new CopyCodeReference();
BeanUtils.copyProperties(materialBaseInfo, copyCodeReference); BeanUtils.copyProperties(materialBaseInfo, copyCodeReference);
BeanUtils.copyProperties(shelfMaterialDetail, copyCodeReference, IgnoreNullUtil.getNullPropertyNames(shelfMaterialDetail)); BeanUtils.copyProperties(shelfMaterialDetail, copyCodeReference, IgnoreNullUtil.getNullPropertyNames(shelfMaterialDetail));
copyCodeReference.setBoxPalletNo(shelfMaterialDetail.getPalletNumber()); copyCodeReference.setBoxPalletNo(shelfMaterialDetail.getPalletNumber());
copyCodeReference.setBatchNumber(shelfMaterialDetail.getCopyBatch()); copyCodeReference.setBatchNumber(shelfMaterialDetail.getCopyBatch());
copyCodeReference.setSerialNumber(Integer.parseInt(key)); copyCodeReference.setSerialNumber(serial);
Integer value = jsonObject.getInteger(key); copyCodeReference.setNetWeight(lineNetKg);
copyCodeReference.setNetWeight(new BigDecimal(value)); copyCodeReference.setGrossWeight(shelfMaterialDetail.getTotalGrossWeight());
copyCodeReference.setMaterialStatusName("可用"); copyCodeReference.setMaterialStatusName("可用");
copyCodeReference.setMaterialStatusCode("1"); copyCodeReference.setMaterialStatusCode("1");
copyCodeReference.setMaterialDetailId(shelfMaterialDetail.getMaterialDetailId()); copyCodeReference.setMaterialDetailId(shelfMaterialDetail.getMaterialDetailId());
copyCodeReference.setMaterialInventoryId(materialInventoryId.getMaterialInventoryId()); copyCodeReference.setMaterialInventoryId(materialInventoryId.getMaterialInventoryId());
copyCodeReference.setInOrderNumber(materialInventoryId.getInOrderNumber()); copyCodeReference.setInOrderNumber(materialInventoryId.getInOrderNumber());
copyCodeReference.setInventoryQuantity(new BigDecimal(1)); copyCodeReference.setInventoryQuantity(BigDecimal.ONE);
copyCodeReference.setNetWeight(shelfMaterialDetail.getTotalNetWeight());
copyCodeReference.setGrossWeight(shelfMaterialDetail.getTotalGrossWeight());
copyCodeReference.setShipperName(materialBaseInfo.getShipperName()); copyCodeReference.setShipperName(materialBaseInfo.getShipperName());
copyCodeReference.setShipperId(materialBaseInfo.getShipperId()); copyCodeReference.setShipperId(materialBaseInfo.getShipperId());
copyCodeReferences.add(copyCodeReference); copyCodeReferences.add(copyCodeReference);
} }
if (CollectionUtils.isEmpty(copyCodeReferences)) {
return;
}
copyCodeReferenceService.saveBatch(copyCodeReferences); copyCodeReferenceService.saveBatch(copyCodeReferences);
} }
/**
* 解析 copyDetails JSON 中单件净重千克支持整数与小数
*/
private static BigDecimal parseCopyDetailNetWeightKg(Object raw) {
if (raw == null) {
return null;
}
try {
if (raw instanceof BigDecimal) {
return (BigDecimal) raw;
}
if (raw instanceof Number) {
return BigDecimal.valueOf(((Number) raw).doubleValue());
}
String s = raw.toString().trim();
if (StringUtils.isBlank(s)) {
return null;
}
return new BigDecimal(s);
} catch (Exception e) {
return null;
}
}
private MaterialInventory getParam(ShelfMaterialDetail shelfMaterialDetail, List<String> fieldNames,Long shipperId,String inOrderNumber){ private MaterialInventory getParam(ShelfMaterialDetail shelfMaterialDetail, List<String> fieldNames,Long shipperId,String inOrderNumber){
MaterialInventory param = new MaterialInventory(); MaterialInventory param = new MaterialInventory();
param.setShipperId(shipperId); param.setShipperId(shipperId);
@@ -53,6 +53,9 @@ public class ReceiptMaterialDetailDTO extends BaseVOEntity {
@Excel(name = "物料基础信息id") @Excel(name = "物料基础信息id")
private Long materialBaseInfoId; private Long materialBaseInfoId;
@ApiModelProperty("是否抄码(物料主数据): 1-是 2-否,与 PC 明细一致")
private Integer copyCode;
@ApiModelProperty("物料编码") @ApiModelProperty("物料编码")
@Excel(name = "物料编码") @Excel(name = "物料编码")
private String materialCode; private String materialCode;
@@ -297,7 +300,7 @@ public class ReceiptMaterialDetailDTO extends BaseVOEntity {
@Excel(name = "抄码数量") @Excel(name = "抄码数量")
private String copyQuantity; private String copyQuantity;
@ApiModelProperty("抄码数量克重详情") @ApiModelProperty("抄码数量克重详情JSON 字符串,key 为序号(1,2,3…)value 为单件净重KG(支持小数)。例:{\"1\":1.343,\"2\":1.343};上架完成后写入 copy_code_reference")
@Excel(name = "抄码数量克重详情") @Excel(name = "抄码数量克重详情")
private String copyDetails; private String copyDetails;
} }
@@ -18,9 +18,17 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 收货单Api * 收货单 PDA Api
* <p>
* 抄码收货方式与 PC {@code StockReceiptOrderApi#getInfo} 一致均来自物料主数据是否抄码({@code copyCode}1- 2-)
* 在明细上由服务端填充 {@link com.mhd.wms.application.service.stockReceiptOrder.StockReceiptOrderApplicationService#getInfoByApp} /
* {@link com.mhd.wms.application.service.stockReceiptOrder.StockReceiptOrderApplicationService#getInfo} 中的单位/包装填充逻辑
* 提交收货仍使用 {@link #receivingGoods}抄码实绩字段托盘号抄码批次抄码数量克重明细等随明细 JSON PC 相同
* 若列表页未拉详情可在点击收货前调用 {@link #getCopyCodeForReceiptLine} {@link #getCopyCodeByMaterialBaseInfoId} 仅取抄码标识
* </p>
* *
* @author gen * @author gen
* @date 2024-05-21 * @date 2024-05-21
@@ -63,6 +71,31 @@ public class StockReceiptOrderAppApi extends BaseController {
return AjaxResult.success(stockReceiptOrderApplicationService.getInfoByApp(receiptOrderId, receiptStatus)); return AjaxResult.success(stockReceiptOrderApplicationService.getInfoByApp(receiptOrderId, receiptStatus));
} }
/**
* PDA按收货单行查询是否抄码 PC 物料主数据 copyCode 一致列表未拉 {@link #getInfoByApp} 点击收货前调用本接口即可分流抄码页/普通收货页
*
* @return data copyCode(1- 2-)materialBaseInfoIdmaterialDetailId
*/
@ApiOperation("按收货明细行查询是否抄码(与PC同源,供跳转抄码收货页)")
@GetMapping("/getCopyCodeForReceiptLine")
public AjaxResult getCopyCodeForReceiptLine(
@ApiParam(value = "收货单ID", required = true) @RequestParam Long receiptOrderId,
@ApiParam(value = "收货明细 material_detail_id", required = true) @RequestParam Long materialDetailId) {
Map<String, Object> data = stockReceiptOrderApplicationService.getCopyCodeForPdaReceiptLine(receiptOrderId, materialDetailId);
return AjaxResult.success(data);
}
/**
* PDA仅已知物料基础信息 ID 时查询是否抄码 PC 一致列表若已带 materialBaseInfoId 可直调无需整单详情
*/
@ApiOperation("按物料基础信息ID查询是否抄码")
@GetMapping("/getCopyCodeByMaterialBaseInfoId")
public AjaxResult getCopyCodeByMaterialBaseInfoId(
@ApiParam(value = "物料基础信息ID", required = true) @RequestParam Long materialBaseInfoId) {
Map<String, Object> data = stockReceiptOrderApplicationService.getCopyCodeByMaterialBaseInfoId(materialBaseInfoId);
return AjaxResult.success(data);
}
/** /**
* PDA查询某计划行卡片下所有 level=2 分批收货子行含首笔仅落主行时的主行快照附带序列号 * PDA查询某计划行卡片下所有 level=2 分批收货子行含首笔仅落主行时的主行快照附带序列号
*/ */
@@ -78,9 +111,10 @@ public class StockReceiptOrderAppApi extends BaseController {
} }
/** /**
* 收货 * 收货 PC 同源抄码物料请在对应明细上传 copyBatchpalletNumbercopyQuantitycopyDetails
* copyDetails JSON序号 单件净重(KG) {"1":1.343,"2":1.343}抄码对照表在上架完成入账后写入非本接口直接写
*/ */
@ApiOperation("收货") @ApiOperation("收货(抄码明细字段见 materialDetailList.copyDetails 等,与 PC 一致)")
@PostMapping("/receivingGoods") @PostMapping("/receivingGoods")
public AjaxResult receivingGoods(@RequestBody StockReceiptOrderDTO stockReceiptOrderDTO) { public AjaxResult receivingGoods(@RequestBody StockReceiptOrderDTO stockReceiptOrderDTO) {
// 勿用 Hutool JSON 往返转 DO嵌套 childrenreceiptGrossWeight/receiptNetWeight/receiptVolume/receiptArea 等会丢失或类型不对导致累计未落库 // 勿用 Hutool JSON 往返转 DO嵌套 childrenreceiptGrossWeight/receiptNetWeight/receiptVolume/receiptArea 等会丢失或类型不对导致累计未落库