Merge remote-tracking branch 'origin/dev_WMS20260401' into dev_WMS20260401
This commit is contained in:
+192
-72
@@ -275,7 +275,8 @@ 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);
|
||||||
fillBarCodeFromMaterialBarCodeRecursively(receiptMaterialDetailPOList, materialBarCodeMap);
|
fillBarCodeFromMaterialBarCodeRecursively(receiptMaterialDetailPOList, materialBarCodeMap);
|
||||||
@@ -842,6 +843,23 @@ public class StockReceiptOrderApplicationService {
|
|||||||
* @param materialBaseInfoMap 物料基础信息Map(key: materialBaseInfoId, value: MaterialBaseInfoPO)
|
* @param materialBaseInfoMap 物料基础信息Map(key: materialBaseInfoId, value: MaterialBaseInfoPO)
|
||||||
* @param packDetailMap 包装规格明细Map(key: materialBaseInfoId, value: PackDetailFeignPO,单位代码为EA)
|
* @param packDetailMap 包装规格明细Map(key: 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(真实子项)时才转换,避免将两条平铺明细错误转为父子导致第一条被覆盖
|
||||||
|
|||||||
+3
@@ -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;
|
||||||
|
|
||||||
|
|||||||
+67
-8
@@ -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);
|
||||||
|
|||||||
+4
-1
@@ -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;
|
||||||
}
|
}
|
||||||
+37
-3
@@ -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-否)、materialBaseInfoId、materialDetailId
|
||||||
|
*/
|
||||||
|
@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 同源)。抄码物料请在对应明细上传 copyBatch、palletNumber、copyQuantity、copyDetails;
|
||||||
|
* 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:嵌套 children、receiptGrossWeight/receiptNetWeight/receiptVolume/receiptArea 等会丢失或类型不对,导致累计未落库
|
// 勿用 Hutool JSON 往返转 DO:嵌套 children、receiptGrossWeight/receiptNetWeight/receiptVolume/receiptArea 等会丢失或类型不对,导致累计未落库
|
||||||
|
|||||||
Reference in New Issue
Block a user