PDA收货详情查询修改

This commit is contained in:
秦鸿展
2026-03-27 17:32:33 +08:00
parent c6e3cb22f6
commit 97e41ffe1c
3 changed files with 211 additions and 15 deletions
@@ -285,6 +285,8 @@ public class StockReceiptOrderApplicationService {
flattenMaterialDetailList(receiptMaterialDetailPOList);
// PC 端子项计划数量不展示:递归清空所有子项的 quantity
clearChildQuantityRecursively(receiptMaterialDetailPOList);
// 计算待收货数量 = 计划数量 - 已收货数量
fillPendingReceiptQuantityRecursively(receiptMaterialDetailPOList);
stockReceiptOrderPO.setMaterialDetailList(receiptMaterialDetailPOList);
log.info("返回收货单信息,receiptOrderId={}, materialDetailList大小={}, totalNetWeight={}, totalGrossWeight={}, totalVolume={}, totalArea={}",
stockReceiptOrderPO.getReceiptOrderId(),
@@ -451,6 +453,89 @@ public class StockReceiptOrderApplicationService {
}
}
}
/**
* 递归计算并填充待收货数量:待收货数量 = 计划数量 - 已收货数量
*/
private void fillPendingReceiptQuantityRecursively(List<ReceiptMaterialDetailPO> receiptMaterialDetailPOList) {
if (CollectionUtils.isEmpty(receiptMaterialDetailPOList)) {
return;
}
for (ReceiptMaterialDetailPO detail : receiptMaterialDetailPOList) {
BigDecimal quantity = detail.getQuantity() != null ? detail.getQuantity() : BigDecimal.ZERO;
BigDecimal alreadyReceiptQuantity = detail.getAlreadyReceiptQuantity() != null ? detail.getAlreadyReceiptQuantity() : BigDecimal.ZERO;
BigDecimal pending = quantity.subtract(alreadyReceiptQuantity);
detail.setPendingReceiptQuantity(pending.compareTo(BigDecimal.ZERO) > 0 ? pending : BigDecimal.ZERO);
List<ReceiptMaterialDetailPO> children = detail.getChildren();
if (!CollectionUtils.isEmpty(children)) {
fillPendingReceiptQuantityRecursively(children);
}
}
}
/**
* PDA详情展示:按“计划-已收”计算待收字段
*/
private void fillPendingDisplayFieldsRecursively(List<ReceiptMaterialDetailPO> receiptMaterialDetailPOList) {
if (CollectionUtils.isEmpty(receiptMaterialDetailPOList)) {
return;
}
for (ReceiptMaterialDetailPO detail : receiptMaterialDetailPOList) {
BigDecimal quantity = detail.getQuantity() != null ? detail.getQuantity() : BigDecimal.ZERO;
BigDecimal alreadyReceiptQuantity = detail.getAlreadyReceiptQuantity() != null ? detail.getAlreadyReceiptQuantity() : BigDecimal.ZERO;
BigDecimal pendingQuantity = quantity.subtract(alreadyReceiptQuantity);
if (pendingQuantity.compareTo(BigDecimal.ZERO) < 0) {
pendingQuantity = BigDecimal.ZERO;
}
detail.setPendingReceiptQuantity(pendingQuantity);
// 按需求:收货数量展示为待收数量
detail.setReceiptQuantity(pendingQuantity);
// 计划值 - 已收值;已收值按数量比例折算
detail.setTotalGrossWeight(calcPendingMetric(detail.getTotalGrossWeight(), quantity, alreadyReceiptQuantity));
detail.setTotalNetWeight(calcPendingMetric(detail.getTotalNetWeight(), quantity, alreadyReceiptQuantity));
detail.setTotalVolume(calcPendingMetric(detail.getTotalVolume(), quantity, alreadyReceiptQuantity));
detail.setTotalArea(calcPendingMetric(detail.getTotalArea(), quantity, alreadyReceiptQuantity));
List<ReceiptMaterialDetailPO> children = detail.getChildren();
if (!CollectionUtils.isEmpty(children)) {
fillPendingDisplayFieldsRecursively(children);
}
}
}
/**
* 详情展示:仅回填待收毛重/净重/体积/面积,避免影响数量字段口径
*/
private void fillPendingMetricsOnlyRecursively(List<ReceiptMaterialDetailPO> receiptMaterialDetailPOList) {
if (CollectionUtils.isEmpty(receiptMaterialDetailPOList)) {
return;
}
for (ReceiptMaterialDetailPO detail : receiptMaterialDetailPOList) {
BigDecimal quantity = detail.getQuantity() != null ? detail.getQuantity() : BigDecimal.ZERO;
BigDecimal alreadyReceiptQuantity = detail.getAlreadyReceiptQuantity() != null ? detail.getAlreadyReceiptQuantity() : BigDecimal.ZERO;
detail.setTotalGrossWeight(calcPendingMetric(detail.getTotalGrossWeight(), quantity, alreadyReceiptQuantity));
detail.setTotalNetWeight(calcPendingMetric(detail.getTotalNetWeight(), quantity, alreadyReceiptQuantity));
detail.setTotalVolume(calcPendingMetric(detail.getTotalVolume(), quantity, alreadyReceiptQuantity));
detail.setTotalArea(calcPendingMetric(detail.getTotalArea(), quantity, alreadyReceiptQuantity));
if (!CollectionUtils.isEmpty(detail.getChildren())) {
fillPendingMetricsOnlyRecursively(detail.getChildren());
}
}
}
private BigDecimal calcPendingMetric(BigDecimal planMetric, BigDecimal quantity, BigDecimal alreadyReceiptQuantity) {
if (planMetric == null) {
return null;
}
if (quantity == null || quantity.compareTo(BigDecimal.ZERO) <= 0) {
return planMetric;
}
BigDecimal alreadyRatio = (alreadyReceiptQuantity == null ? BigDecimal.ZERO : alreadyReceiptQuantity)
.divide(quantity, 8, java.math.RoundingMode.HALF_UP);
BigDecimal pendingMetric = planMetric.subtract(planMetric.multiply(alreadyRatio));
return pendingMetric.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : pendingMetric;
}
/**
* 递归为物料明细设置更多属性
@@ -933,11 +1018,22 @@ public class StockReceiptOrderApplicationService {
* 获取收货单详细信息(PDA 端)
* 在 Domain 层结果基础上,补充包装规格填充,与 PC 端 getInfo 一致
*/
public StockReceiptOrderPO getInfoByApp(Long receiptOrderId)
public StockReceiptOrderPO getInfoByApp(Long receiptOrderId, Integer receiptStatus)
{
StockReceiptOrderPO stockReceiptOrderPO = stockReceiptOrderDomainService.getInfoByApp(receiptOrderId);
if (stockReceiptOrderPO == null) {
return null;
}
List<ReceiptMaterialDetailPO> materialDetailList = stockReceiptOrderPO.getMaterialDetailList();
if (!CollectionUtils.isEmpty(materialDetailList)) {
// PDA 详情按明细收货状态过滤:1=待收货/收货中(明细状态1、2),3=已收货(明细状态3)
if (receiptStatus != null) {
materialDetailList = filterMaterialDetailsByReceiptStatus(materialDetailList, receiptStatus);
stockReceiptOrderPO.setMaterialDetailList(materialDetailList);
}
if (CollectionUtils.isEmpty(materialDetailList)) {
return stockReceiptOrderPO;
}
Set<Long> materialBaseInfoIdSet = new HashSet<>();
collectMaterialBaseInfoIdsRecursively(materialDetailList, materialBaseInfoIdSet);
Map<Long, MaterialBaseInfoPO> materialBaseInfoMap = new HashMap<>();
@@ -981,10 +1077,53 @@ public class StockReceiptOrderApplicationService {
// PDA 端与 PC 端一致:主行收货数量取第一条子项,已收货数量汇总所有子项
flattenMaterialDetailList(materialDetailList);
clearChildQuantityRecursively(materialDetailList);
// 收货详情:总毛重/净重/体积/面积按“计划-已收”展示
fillPendingMetricsOnlyRecursively(materialDetailList);
// 仅在 PDA 详情筛选“待收/收货中”时,按待收口径回填展示字段
if (receiptStatus != null && receiptStatus == 1) {
// 按“计划-已收”回填待收展示字段(数量/毛净重/体积/面积)
fillPendingDisplayFieldsRecursively(materialDetailList);
} else {
// 其他场景保持原始详情口径,仅补充待收数量字段
fillPendingReceiptQuantityRecursively(materialDetailList);
}
}
return stockReceiptOrderPO;
}
private List<ReceiptMaterialDetailPO> filterMaterialDetailsByReceiptStatus(List<ReceiptMaterialDetailPO> source, Integer receiptStatus) {
if (CollectionUtils.isEmpty(source) || receiptStatus == null) {
return source;
}
List<ReceiptMaterialDetailPO> result = new ArrayList<>();
for (ReceiptMaterialDetailPO item : source) {
if (item == null) {
continue;
}
// 先递归过滤子项
List<ReceiptMaterialDetailPO> filteredChildren = filterMaterialDetailsByReceiptStatus(item.getChildren(), receiptStatus);
item.setChildren(filteredChildren == null ? new ArrayList<>() : filteredChildren);
// 父项命中或存在命中的子项都保留,保证树结构可展示
if (matchReceiptStatus(item.getReceiptStatus(), receiptStatus) || !CollectionUtils.isEmpty(item.getChildren())) {
result.add(item);
}
}
return result;
}
private boolean matchReceiptStatus(Integer detailStatus, Integer receiptStatus) {
if (detailStatus == null || receiptStatus == null) {
return false;
}
if (receiptStatus == 1) {
return detailStatus == 1 || detailStatus == 2;
}
if (receiptStatus == 3) {
return detailStatus == 3;
}
return true;
}
/**
* 递归收集明细树中所有物料基础信息ID
*/
@@ -1078,6 +1217,8 @@ public class StockReceiptOrderApplicationService {
*/
public Boolean receivingGoodsByApp(StockReceiptOrderDO stockReceiptOrderDO){
List<ReceiptMaterialDetailDO> list = stockReceiptOrderDO.getMaterialDetailList();
// 超计划提示:实际收货数量 > 待收数量(计划-已收) 时,先提示确认
checkOverPlanReceiptForApp(stockReceiptOrderDO);
// 记录 PDA 传入时第一项是否已有 children
boolean firstItemHadChildrenBefore = !CollectionUtils.isEmpty(list)
&& !CollectionUtils.isEmpty(list.get(0).getChildren());
@@ -1097,6 +1238,60 @@ public class StockReceiptOrderApplicationService {
return stockReceiptOrderDomainService.receivingGoods(assembleStockReceiptOrderDO);
}
private void checkOverPlanReceiptForApp(StockReceiptOrderDO stockReceiptOrderDO) {
if (stockReceiptOrderDO == null || CollectionUtils.isEmpty(stockReceiptOrderDO.getMaterialDetailList())) {
return;
}
StockReceiptOrderPO dbOrder = stockReceiptOrderDomainService.getInfo(stockReceiptOrderDO.getReceiptOrderId());
if (dbOrder == null) {
return;
}
ReceiptMaterialDetailDO queryDO = new ReceiptMaterialDetailDO();
queryDO.setReceiptOrderNumber(dbOrder.getReceiptOrderNumber());
List<ReceiptMaterialDetailPO> dbList = receiptMaterialDetailDomainService.queryList(queryDO);
Map<Long, ReceiptMaterialDetailPO> dbById = dbList.stream()
.filter(x -> x.getMaterialDetailId() != null)
.collect(Collectors.toMap(ReceiptMaterialDetailPO::getMaterialDetailId, Function.identity(), (a, b) -> a));
Map<Long, ReceiptMaterialDetailPO> dbByUniqueId = dbList.stream()
.filter(x -> x.getUniqueId() != null)
.collect(Collectors.toMap(ReceiptMaterialDetailPO::getUniqueId, Function.identity(), (a, b) -> a));
for (ReceiptMaterialDetailDO item : stockReceiptOrderDO.getMaterialDetailList()) {
validateOverPlanNode(item, dbById, dbByUniqueId);
}
}
private void validateOverPlanNode(ReceiptMaterialDetailDO item,
Map<Long, ReceiptMaterialDetailPO> dbById,
Map<Long, ReceiptMaterialDetailPO> dbByUniqueId) {
if (item == null) {
return;
}
ReceiptMaterialDetailPO db = null;
if (item.getMaterialDetailId() != null) {
db = dbById.get(item.getMaterialDetailId());
}
if (db == null && item.getUniqueId() != null) {
db = dbByUniqueId.get(item.getUniqueId());
}
if (db != null) {
BigDecimal plan = db.getQuantity() != null ? db.getQuantity() : BigDecimal.ZERO;
BigDecimal already = db.getAlreadyReceiptQuantity() != null ? db.getAlreadyReceiptQuantity() : BigDecimal.ZERO;
BigDecimal pending = plan.subtract(already);
if (pending.compareTo(BigDecimal.ZERO) < 0) {
pending = BigDecimal.ZERO;
}
BigDecimal current = item.getReceiptQuantity() != null ? item.getReceiptQuantity() : BigDecimal.ZERO;
if (current.compareTo(pending) > 0) {
throw new ServiceException("当前物料实收数量大于计划收货数量,是否确认收货");
}
}
if (!CollectionUtils.isEmpty(item.getChildren())) {
for (ReceiptMaterialDetailDO child : item.getChildren()) {
validateOverPlanNode(child, dbById, dbByUniqueId);
}
}
}
/**
* 收货时:将 children 中第一条的值赋给主项,并删除第一条。
* PDA 收两条时只生成 2 条(主项 + 第二条子项),主项展示第一条子项的数据。
@@ -1382,7 +1577,8 @@ public class StockReceiptOrderApplicationService {
//设置物料状态及容器信息
setMaterialMoreDetailInfo(receiptMaterialDetailDO);
}
// 主项本次收货增量 = 新子项数量 + 已存在子项的本次收货增量PDA 传子项累计值时:child.receiptQuantity - childDb.alreadyReceiptQuantity
// 主项本次收货增量 = 新子项数量 + 已存在子项的本次收货增量
// 统一口径:PDA 上传的 receiptQuantity 视为“本次收货量”,不再按累计值覆盖
BigDecimal newChildrenTotalQuantity = BigDecimal.ZERO;
BigDecimal existingChildrenIncrement = BigDecimal.ZERO;
List<ReceiptMaterialDetailDO> receiptMaterialDetailDOChildList = receiptMaterialDetailDO.getChildren();
@@ -1396,14 +1592,11 @@ public class StockReceiptOrderApplicationService {
BigDecimal childDbAlready = receiptMaterialDetailPOChildDb != null && receiptMaterialDetailPOChildDb.getAlreadyReceiptQuantity() != null
? receiptMaterialDetailPOChildDb.getAlreadyReceiptQuantity() : BigDecimal.ZERO;
if (receiptMaterialDetailPOChildDb == null) {
// 新子项:累加其收货
// 新子项:累加其本次收货量
newChildrenTotalQuantity = newChildrenTotalQuantity.add(childQty);
} else {
// 已存在子项:累加本次增量(PDA 传累计值,增量 = 本次值 - DB 已收值)
BigDecimal delta = childQty.subtract(childDbAlready);
if (delta.compareTo(BigDecimal.ZERO) > 0) {
existingChildrenIncrement = existingChildrenIncrement.add(delta);
}
// 已存在子项:累加其本次收货量
existingChildrenIncrement = existingChildrenIncrement.add(childQty);
}
BigDecimal childReceiptQty = receiptMaterialDetailDOChild.getReceiptQuantity() != null ? receiptMaterialDetailDOChild.getReceiptQuantity() : BigDecimal.ZERO;
ReceiptMaterialDetailDO returnReceiptMaterialDetailDOChild = new ReceiptMaterialDetailDO();
@@ -1411,10 +1604,8 @@ public class StockReceiptOrderApplicationService {
// 子项已存在:用 DB 数据 + PDA 收货数据组装,保证不同明细独立收货不被丢失
BeanUtils.copyProperties(receiptMaterialDetailPOChildDb, returnReceiptMaterialDetailDOChild);
BeanUtils.copyProperties(receiptMaterialDetailDOChild, returnReceiptMaterialDetailDOChild, IgnoreNullUtil.getNullPropertyNames(receiptMaterialDetailDOChild));
// PDA 传子项累计值时,更新子项已收数量(取较大值,确保第二次及以后收货时子项已收数正确)
if (childQty.compareTo(childDbAlready) > 0) {
returnReceiptMaterialDetailDOChild.setAlreadyReceiptQuantity(childQty);
}
// 子项统一按“本次收货量”累加
returnReceiptMaterialDetailDOChild.setAlreadyReceiptQuantity(childDbAlready.add(childQty));
returnReceiptMaterialDetailDOChild.setAllowModify(2);
returnReceiptMaterialDetailDOChild.setLevel(2);
returnReceiptMaterialDetailDOChild.setParentUniqueId(receiptMaterialDetailPO.getUniqueId());
@@ -80,6 +80,10 @@ public class ReceiptMaterialDetailPO extends BaseVOEntity {
@Excel(name = "已收货数量")
private BigDecimal alreadyReceiptQuantity;
@ApiModelProperty("待收货数量")
@Excel(name = "待收货数量")
private BigDecimal pendingReceiptQuantity;
@ApiModelProperty("收货数量")
@Excel(name = "收货数量")
private BigDecimal receiptQuantity;
@@ -49,10 +49,11 @@ public class StockReceiptOrderAppApi extends BaseController {
/**
* 获取收货单详细信息
*/
@ApiOperation("获取收货单")
@ApiOperation("获取收货单详细信息")
@GetMapping(value = "/getInfoByApp")
public AjaxResult getInfoByApp(Long receiptOrderId) {
return AjaxResult.success(stockReceiptOrderApplicationService.getInfoByApp(receiptOrderId));
public AjaxResult getInfoByApp(@RequestParam Long receiptOrderId,
@RequestParam(required = false) Integer receiptStatus) {
return AjaxResult.success(stockReceiptOrderApplicationService.getInfoByApp(receiptOrderId, receiptStatus));
}
/**