diff --git a/mhd_wms/sql/pdaSql.sql b/mhd_wms/sql/pdaSql.sql new file mode 100644 index 000000000..eb48a6bb8 --- /dev/null +++ b/mhd_wms/sql/pdaSql.sql @@ -0,0 +1,19 @@ +-- ALREADY_RECEIPT_GROSS_WEIGHT +ALTER TABLE "RECEIPT_MATERIAL_DETAIL" + ADD "ALREADY_RECEIPT_GROSS_WEIGHT" DECIMAL(20, 8) NULL; +COMMENT ON COLUMN "RECEIPT_MATERIAL_DETAIL"."ALREADY_RECEIPT_GROSS_WEIGHT" IS '累计已收货毛重(KG),称重实绩'; + +-- ALREADY_RECEIPT_NET_WEIGHT +ALTER TABLE RECEIPT_MATERIAL_DETAIL + ADD ALREADY_RECEIPT_NET_WEIGHT DECIMAL(20, 8) NULL; +COMMENT ON COLUMN RECEIPT_MATERIAL_DETAIL.ALREADY_RECEIPT_NET_WEIGHT IS '累计已收货净重(KG)'; + +-- ALREADY_RECEIPT_VOLUME +ALTER TABLE RECEIPT_MATERIAL_DETAIL + ADD ALREADY_RECEIPT_VOLUME DECIMAL(20, 8) NULL; +COMMENT ON COLUMN RECEIPT_MATERIAL_DETAIL.ALREADY_RECEIPT_VOLUME IS '累计已收货体积(CBM)'; + +-- ALREADY_RECEIPT_AREA +ALTER TABLE RECEIPT_MATERIAL_DETAIL + ADD ALREADY_RECEIPT_AREA DECIMAL(20, 8) NULL; +COMMENT ON COLUMN RECEIPT_MATERIAL_DETAIL.ALREADY_RECEIPT_AREA IS '累计已收货面积(SQM)'; \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockReceiptOrder/StockReceiptOrderApplicationService.java b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockReceiptOrder/StockReceiptOrderApplicationService.java index 690a7d3c6..1cc9ccce4 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockReceiptOrder/StockReceiptOrderApplicationService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockReceiptOrder/StockReceiptOrderApplicationService.java @@ -287,6 +287,7 @@ public class StockReceiptOrderApplicationService { clearChildQuantityRecursively(receiptMaterialDetailPOList); // 计算待收货数量 = 计划数量 - 已收货数量 fillPendingReceiptQuantityRecursively(receiptMaterialDetailPOList); + fillPlanAndPendingMetricsRecursively(receiptMaterialDetailPOList); stockReceiptOrderPO.setMaterialDetailList(receiptMaterialDetailPOList); log.info("返回收货单信息,receiptOrderId={}, materialDetailList大小={}, totalNetWeight={}, totalGrossWeight={}, totalVolume={}, totalArea={}", stockReceiptOrderPO.getReceiptOrderId(), @@ -429,6 +430,7 @@ public class StockReceiptOrderApplicationService { child.setQuantity(null); } parent.setAlreadyReceiptQuantity(alreadyReceiptQuantitySum); + // 累计已称毛重不按子行汇总到主行:多批/多子行各自一条计划毛重,汇总会大于主行计划,导致 计划−已称=0 且界面显示 0E-8;待收毛重按本行 already_receipt_gross_weight 与 total_gross_weight 计算即可 if (maxReceiptStatus != null) { parent.setReceiptStatus(maxReceiptStatus); } @@ -462,10 +464,12 @@ public class StockReceiptOrderApplicationService { 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); + if (!isPdaReceiptDetailFullyReceived(detail)) { + 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 children = detail.getChildren(); if (!CollectionUtils.isEmpty(children)) { fillPendingReceiptQuantityRecursively(children); @@ -474,13 +478,45 @@ public class StockReceiptOrderApplicationService { } /** - * PDA详情展示:按“计划-已收”计算待收字段 + * PDA 详情:收货数量展示为「累计已收货」= 库表 already_receipt_quantity。 + * 库表 receipt_quantity 仅为本次收货量,多次提交会覆盖;与「已有 + 本次」口径一致时应使用累计字段。 + * 仅在 getInfoByApp 非「待收/收货中」筛选分支中调用,避免影响 PC 端 getInfo。 + */ + private void syncReceiptQuantityCumulativeDisplayRecursively(List receiptMaterialDetailPOList) { + if (CollectionUtils.isEmpty(receiptMaterialDetailPOList)) { + return; + } + for (ReceiptMaterialDetailPO detail : receiptMaterialDetailPOList) { + BigDecimal already = detail.getAlreadyReceiptQuantity() != null ? detail.getAlreadyReceiptQuantity() : BigDecimal.ZERO; + BigDecimal plan = detail.getQuantity() != null ? detail.getQuantity() : BigDecimal.ZERO; + BigDecimal display = already; + if (plan.compareTo(BigDecimal.ZERO) > 0 && display.compareTo(plan) > 0) { + display = plan; + } + detail.setReceiptQuantity(display); + List children = detail.getChildren(); + if (!CollectionUtils.isEmpty(children)) { + syncReceiptQuantityCumulativeDisplayRecursively(children); + } + } + } + + /** + * PDA详情展示:按“计划-已收”计算待收字段(已收货明细行不算待收、不改 total*) */ private void fillPendingDisplayFieldsRecursively(List receiptMaterialDetailPOList) { if (CollectionUtils.isEmpty(receiptMaterialDetailPOList)) { return; } for (ReceiptMaterialDetailPO detail : receiptMaterialDetailPOList) { + if (isPdaReceiptDetailFullyReceived(detail)) { + applyCumulativeReceiptQuantityDisplayOnly(detail); + List doneChildren = detail.getChildren(); + if (!CollectionUtils.isEmpty(doneChildren)) { + fillPendingDisplayFieldsRecursively(doneChildren); + } + continue; + } BigDecimal quantity = detail.getQuantity() != null ? detail.getQuantity() : BigDecimal.ZERO; BigDecimal alreadyReceiptQuantity = detail.getAlreadyReceiptQuantity() != null ? detail.getAlreadyReceiptQuantity() : BigDecimal.ZERO; BigDecimal pendingQuantity = quantity.subtract(alreadyReceiptQuantity); @@ -488,14 +524,16 @@ public class StockReceiptOrderApplicationService { pendingQuantity = BigDecimal.ZERO; } detail.setPendingReceiptQuantity(pendingQuantity); - // 按需求:收货数量展示为待收数量 - detail.setReceiptQuantity(pendingQuantity); + // 收货数量展示为累计已收货(已有 + 各次本次),与库表 receipt_quantity(仅本次)区分 + BigDecimal already = alreadyReceiptQuantity; + BigDecimal displayQty = already; + if (quantity.compareTo(BigDecimal.ZERO) > 0 && displayQty.compareTo(quantity) > 0) { + displayQty = quantity; + } + detail.setReceiptQuantity(displayQty); - // 计划值 - 已收值;已收值按数量比例折算 - 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)); + // 毛重/净重/体积/面积:未完成=待收(计划−累计);已收完=展示累计实绩(无则退回计划) + applyDisplayWeightVolumeAndAreaForDetail(detail); List children = detail.getChildren(); if (!CollectionUtils.isEmpty(children)) { @@ -505,36 +543,100 @@ public class StockReceiptOrderApplicationService { } /** - * 详情展示:仅回填待收毛重/净重/体积/面积,避免影响数量字段口径 + * 详情展示:仅回填待收毛重/净重/体积/面积,避免影响数量字段口径(已收货行保持库表 total*) */ private void fillPendingMetricsOnlyRecursively(List 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 (!isPdaReceiptDetailFullyReceived(detail)) { + applyDisplayWeightVolumeAndAreaForDetail(detail); + } if (!CollectionUtils.isEmpty(detail.getChildren())) { fillPendingMetricsOnlyRecursively(detail.getChildren()); } } } - private BigDecimal calcPendingMetric(BigDecimal planMetric, BigDecimal quantity, BigDecimal alreadyReceiptQuantity) { - if (planMetric == null) { + /** + * 详情中 total*:累计称重/体积/面积实绩(同 already_receipt_*)。 + * 计划/待收见 plan*、pending*(fillPlanAndPendingMetricsRecursively)。 + */ + private void applyDisplayWeightVolumeAndAreaForDetail(ReceiptMaterialDetailPO detail) { + BigDecimal planGross = detail.getPlanGrossWeight() != null + ? detail.getPlanGrossWeight() : detail.getTotalGrossWeight(); + BigDecimal planNet = detail.getPlanNetWeight() != null + ? detail.getPlanNetWeight() : detail.getTotalNetWeight(); + BigDecimal planVol = detail.getPlanVolume() != null + ? detail.getPlanVolume() : detail.getTotalVolume(); + BigDecimal planArea = detail.getPlanArea() != null + ? detail.getPlanArea() : detail.getTotalArea(); + detail.setTotalGrossWeight(displayCompleteMetric(detail.getAlreadyReceiptGrossWeight(), planGross)); + detail.setTotalNetWeight(displayCompleteMetric(detail.getAlreadyReceiptNetWeight(), planNet)); + detail.setTotalVolume(displayCompleteMetric(detail.getAlreadyReceiptVolume(), planVol)); + detail.setTotalArea(displayCompleteMetric(detail.getAlreadyReceiptArea(), planArea)); + } + + /** + * 计划/待收:plan* 来自入库单联表(与首次创建时 total 同源);pending* = plan − 累计已收,仅接口计算不落库。 + */ + private void fillPlanAndPendingMetricsRecursively(List list) { + if (CollectionUtils.isEmpty(list)) { + return; + } + for (ReceiptMaterialDetailPO d : list) { + if (d == null) { + continue; + } + if (!isPdaReceiptDetailFullyReceived(d)) { + d.setPendingNetWeight(calcPendingMetric(d.getPlanNetWeight(), d.getAlreadyReceiptNetWeight())); + d.setPendingGrossWeight(calcPendingMetric(d.getPlanGrossWeight(), d.getAlreadyReceiptGrossWeight())); + d.setPendingVolume(calcPendingMetric(d.getPlanVolume(), d.getAlreadyReceiptVolume())); + d.setPendingArea(calcPendingMetric(d.getPlanArea(), d.getAlreadyReceiptArea())); + } + fillPlanAndPendingMetricsRecursively(d.getChildren()); + } + } + + /** 待收 = max(0, 计划 − 累计已收货) */ + private static BigDecimal calcPendingMetric(BigDecimal plan, BigDecimal alreadyReceipt) { + if (plan == null) { return null; } - if (quantity == null || quantity.compareTo(BigDecimal.ZERO) <= 0) { - return planMetric; + BigDecimal already = alreadyReceipt != null ? alreadyReceipt : BigDecimal.ZERO; + BigDecimal pending = plan.subtract(already); + if (pending.compareTo(BigDecimal.ZERO) <= 0) { + return BigDecimal.ZERO; } - 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; + return normalizeDecimalForApi(pending); + } + + /** 已收完展示:优先累计实绩;未维护累计时退回计划值 */ + private static BigDecimal displayCompleteMetric(BigDecimal accumulated, BigDecimal planFallback) { + if (accumulated != null) { + return normalizeDecimalForApi(accumulated); + } + if (planFallback == null) { + return null; + } + return normalizeDecimalForApi(planFallback); + } + + /** + * 统一待收数值的标度,避免 JSON 出现 0E-8 / 1.1E+3: + * stripTrailingZeros 后 scale 可能为负,BigDecimal.toString 会变成科学计数法,序列化到前端同效。 + * 使用 toPlainString 再构造,保证输出为普通十进制形式。 + */ + private static BigDecimal normalizeDecimalForApi(BigDecimal v) { + if (v == null) { + return null; + } + if (v.compareTo(BigDecimal.ZERO) == 0) { + return BigDecimal.ZERO; + } + BigDecimal stripped = v.stripTrailingZeros(); + return new BigDecimal(stripped.toPlainString()); } /** @@ -1026,7 +1128,7 @@ public class StockReceiptOrderApplicationService { } List materialDetailList = stockReceiptOrderPO.getMaterialDetailList(); if (!CollectionUtils.isEmpty(materialDetailList)) { - // PDA 详情按明细收货状态过滤:1=待收货/收货中(明细状态1、2),3=已收货(明细状态3) + // PDA 详情筛选:receiptStatus=1 仅 1 待收货、2 收货中;receiptStatus=3 为 3 已收货、4 少收、5 超收(不含 1、2) if (receiptStatus != null) { materialDetailList = filterMaterialDetailsByReceiptStatus(materialDetailList, receiptStatus); stockReceiptOrderPO.setMaterialDetailList(materialDetailList); @@ -1076,21 +1178,70 @@ public class StockReceiptOrderApplicationService { fillFirstReceiptQuantityDefault(materialDetailList); // PDA 端与 PC 端一致:主行收货数量取第一条子项,已收货数量汇总所有子项 flattenMaterialDetailList(materialDetailList); - clearChildQuantityRecursively(materialDetailList); - // 收货详情:总毛重/净重/体积/面积按“计划-已收”展示 - fillPendingMetricsOnlyRecursively(materialDetailList); - // 仅在 PDA 详情筛选“待收/收货中”时,按待收口径回填展示字段 + // 须先算待收指标再清空子项 quantity;已收尾明细(3/4/5)不按「计划−待收」计算,见 isPdaReceiptDetailFullyReceived if (receiptStatus != null && receiptStatus == 1) { - // 按“计划-已收”回填待收展示字段(数量/毛净重/体积/面积) fillPendingDisplayFieldsRecursively(materialDetailList); } else { - // 其他场景保持原始详情口径,仅补充待收数量字段 + fillPendingMetricsOnlyRecursively(materialDetailList); fillPendingReceiptQuantityRecursively(materialDetailList); + syncReceiptQuantityCumulativeDisplayRecursively(materialDetailList); } + fillPlanAndPendingMetricsRecursively(materialDetailList); + // PDA 绑定 total* 展示「待收」= plan − 已收;已收货行不覆盖 + overwriteTotalWithPendingForPdaDisplayRecursively(materialDetailList); + clearChildQuantityRecursively(materialDetailList); } return stockReceiptOrderPO; } + /** + * PDA 界面「总净重/总毛重/体积/面积」绑定 total*:有计划时展示待收(pending*);无计划联表时保留原 total*(累计实绩)。 + */ + private void overwriteTotalWithPendingForPdaDisplayRecursively(List list) { + if (CollectionUtils.isEmpty(list)) { + return; + } + for (ReceiptMaterialDetailPO d : list) { + if (d == null) { + continue; + } + if (!isPdaReceiptDetailFullyReceived(d)) { + if (d.getPlanNetWeight() != null) { + d.setTotalNetWeight(d.getPendingNetWeight() != null ? d.getPendingNetWeight() : BigDecimal.ZERO); + } + if (d.getPlanGrossWeight() != null) { + d.setTotalGrossWeight(d.getPendingGrossWeight() != null ? d.getPendingGrossWeight() : BigDecimal.ZERO); + } + if (d.getPlanVolume() != null) { + d.setTotalVolume(d.getPendingVolume() != null ? d.getPendingVolume() : BigDecimal.ZERO); + } + if (d.getPlanArea() != null) { + d.setTotalArea(d.getPendingArea() != null ? d.getPendingArea() : BigDecimal.ZERO); + } + } + overwriteTotalWithPendingForPdaDisplayRecursively(d.getChildren()); + } + } + + /** 明细已收尾(3/4/5),不参与「计划−待收」口径;与已收货 tab 一致 */ + private static boolean isPdaReceiptDetailFullyReceived(ReceiptMaterialDetailPO d) { + return d != null && isPdaTerminalReceiptDetailStatus(d.getReceiptStatus()); + } + + /** 与 syncReceiptQuantityCumulativeDisplayRecursively 单节点口径一致:收货数量展示为累计实绩(封顶计划) */ + private static void applyCumulativeReceiptQuantityDisplayOnly(ReceiptMaterialDetailPO detail) { + if (detail == null) { + return; + } + BigDecimal already = detail.getAlreadyReceiptQuantity() != null ? detail.getAlreadyReceiptQuantity() : BigDecimal.ZERO; + BigDecimal plan = detail.getQuantity() != null ? detail.getQuantity() : BigDecimal.ZERO; + BigDecimal display = already; + if (plan.compareTo(BigDecimal.ZERO) > 0 && display.compareTo(plan) > 0) { + display = plan; + } + detail.setReceiptQuantity(display); + } + private List filterMaterialDetailsByReceiptStatus(List source, Integer receiptStatus) { if (CollectionUtils.isEmpty(source) || receiptStatus == null) { return source; @@ -1111,6 +1262,9 @@ public class StockReceiptOrderApplicationService { return result; } + /** + * @param receiptStatus 请求筛选:1=待收货 tab(仅明细 1、2);3=已收货 tab(仅 3 已收货、4 少收、5 超收) + */ private boolean matchReceiptStatus(Integer detailStatus, Integer receiptStatus) { if (detailStatus == null || receiptStatus == null) { return false; @@ -1119,11 +1273,16 @@ public class StockReceiptOrderApplicationService { return detailStatus == 1 || detailStatus == 2; } if (receiptStatus == 3) { - return detailStatus == 3; + return isPdaTerminalReceiptDetailStatus(detailStatus); } return true; } + /** 明细节点属于「已收货」tab:3 已收货、4 少收、5 超收(与待收货 1、2 互斥) */ + private static boolean isPdaTerminalReceiptDetailStatus(Integer detailStatus) { + return detailStatus != null && (detailStatus == 3 || detailStatus == 4 || detailStatus == 5); + } + /** * 递归收集明细树中所有物料基础信息ID */ @@ -1503,6 +1662,30 @@ public class StockReceiptOrderApplicationService { stockReceiptOrderDO.setOperatorsName(userPo.getUserName()); } + /** + * 本次收货的毛/净重、体积、面积增量:优先 receipt*;否则 total*。 + * total* 与 PC 回显对齐后可能为「累计实绩」:若 total > 本单收货前累计则增量=差;相等则 0;小于累计则视为「本次增量」原值。 + */ + private static BigDecimal pickThisReceiptMetricIncrement(BigDecimal receiptField, BigDecimal totalField, + BigDecimal dbAlreadyBeforeThisReceipt) { + if (receiptField != null) { + return receiptField; + } + if (totalField == null) { + return BigDecimal.ZERO; + } + if (dbAlreadyBeforeThisReceipt == null) { + return totalField; + } + if (totalField.compareTo(dbAlreadyBeforeThisReceipt) == 0) { + return BigDecimal.ZERO; + } + if (totalField.compareTo(dbAlreadyBeforeThisReceipt) > 0) { + return totalField.subtract(dbAlreadyBeforeThisReceipt); + } + return totalField; + } + /** * @description 收货装配参数 * @author ZhouGY @@ -1581,6 +1764,14 @@ public class StockReceiptOrderApplicationService { // 统一口径:PDA 上传的 receiptQuantity 视为“本次收货量”,不再按累计值覆盖 BigDecimal newChildrenTotalQuantity = BigDecimal.ZERO; BigDecimal existingChildrenIncrement = BigDecimal.ZERO; + BigDecimal newChildrenGrossTotal = BigDecimal.ZERO; + BigDecimal existingChildrenGrossIncrement = BigDecimal.ZERO; + BigDecimal newChildrenNetTotal = BigDecimal.ZERO; + BigDecimal existingChildrenNetIncrement = BigDecimal.ZERO; + BigDecimal newChildrenVolTotal = BigDecimal.ZERO; + BigDecimal existingChildrenVolIncrement = BigDecimal.ZERO; + BigDecimal newChildrenAreaTotal = BigDecimal.ZERO; + BigDecimal existingChildrenAreaIncrement = BigDecimal.ZERO; List receiptMaterialDetailDOChildList = receiptMaterialDetailDO.getChildren(); if (!CollectionUtils.isEmpty(receiptMaterialDetailDOChildList)){ for (ReceiptMaterialDetailDO receiptMaterialDetailDOChild : receiptMaterialDetailDOChildList){ @@ -1588,15 +1779,35 @@ public class StockReceiptOrderApplicationService { if (receiptMaterialDetailPOChildDb == null && receiptMaterialDetailDOChild.getUniqueId() != null) { receiptMaterialDetailPOChildDb = receiptMaterialDetailDbMapByUniqueId.get(receiptMaterialDetailDOChild.getUniqueId()); } - BigDecimal childQty = receiptMaterialDetailDOChild.getReceiptQuantity() != null ? receiptMaterialDetailDOChild.getReceiptQuantity() : BigDecimal.ZERO; BigDecimal childDbAlready = receiptMaterialDetailPOChildDb != null && receiptMaterialDetailPOChildDb.getAlreadyReceiptQuantity() != null ? receiptMaterialDetailPOChildDb.getAlreadyReceiptQuantity() : BigDecimal.ZERO; + BigDecimal childDbAlreadyGross = receiptMaterialDetailPOChildDb != null && receiptMaterialDetailPOChildDb.getAlreadyReceiptGrossWeight() != null + ? receiptMaterialDetailPOChildDb.getAlreadyReceiptGrossWeight() : BigDecimal.ZERO; + BigDecimal childDbAlreadyNet = receiptMaterialDetailPOChildDb != null && receiptMaterialDetailPOChildDb.getAlreadyReceiptNetWeight() != null + ? receiptMaterialDetailPOChildDb.getAlreadyReceiptNetWeight() : BigDecimal.ZERO; + BigDecimal childDbAlreadyVol = receiptMaterialDetailPOChildDb != null && receiptMaterialDetailPOChildDb.getAlreadyReceiptVolume() != null + ? receiptMaterialDetailPOChildDb.getAlreadyReceiptVolume() : BigDecimal.ZERO; + BigDecimal childDbAlreadyArea = receiptMaterialDetailPOChildDb != null && receiptMaterialDetailPOChildDb.getAlreadyReceiptArea() != null + ? receiptMaterialDetailPOChildDb.getAlreadyReceiptArea() : BigDecimal.ZERO; + BigDecimal childQty = receiptMaterialDetailDOChild.getReceiptQuantity() != null ? receiptMaterialDetailDOChild.getReceiptQuantity() : BigDecimal.ZERO; + BigDecimal childGross = pickThisReceiptMetricIncrement(receiptMaterialDetailDOChild.getReceiptGrossWeight(), receiptMaterialDetailDOChild.getTotalGrossWeight(), childDbAlreadyGross); + BigDecimal childNet = pickThisReceiptMetricIncrement(receiptMaterialDetailDOChild.getReceiptNetWeight(), receiptMaterialDetailDOChild.getTotalNetWeight(), childDbAlreadyNet); + BigDecimal childVol = pickThisReceiptMetricIncrement(receiptMaterialDetailDOChild.getReceiptVolume(), receiptMaterialDetailDOChild.getTotalVolume(), childDbAlreadyVol); + BigDecimal childArea = pickThisReceiptMetricIncrement(receiptMaterialDetailDOChild.getReceiptArea(), receiptMaterialDetailDOChild.getTotalArea(), childDbAlreadyArea); if (receiptMaterialDetailPOChildDb == null) { // 新子项:累加其本次收货量 newChildrenTotalQuantity = newChildrenTotalQuantity.add(childQty); + newChildrenGrossTotal = newChildrenGrossTotal.add(childGross); + newChildrenNetTotal = newChildrenNetTotal.add(childNet); + newChildrenVolTotal = newChildrenVolTotal.add(childVol); + newChildrenAreaTotal = newChildrenAreaTotal.add(childArea); } else { // 已存在子项:累加其本次收货量 existingChildrenIncrement = existingChildrenIncrement.add(childQty); + existingChildrenGrossIncrement = existingChildrenGrossIncrement.add(childGross); + existingChildrenNetIncrement = existingChildrenNetIncrement.add(childNet); + existingChildrenVolIncrement = existingChildrenVolIncrement.add(childVol); + existingChildrenAreaIncrement = existingChildrenAreaIncrement.add(childArea); } BigDecimal childReceiptQty = receiptMaterialDetailDOChild.getReceiptQuantity() != null ? receiptMaterialDetailDOChild.getReceiptQuantity() : BigDecimal.ZERO; ReceiptMaterialDetailDO returnReceiptMaterialDetailDOChild = new ReceiptMaterialDetailDO(); @@ -1606,6 +1817,10 @@ public class StockReceiptOrderApplicationService { BeanUtils.copyProperties(receiptMaterialDetailDOChild, returnReceiptMaterialDetailDOChild, IgnoreNullUtil.getNullPropertyNames(receiptMaterialDetailDOChild)); // 子项统一按“本次收货量”累加 returnReceiptMaterialDetailDOChild.setAlreadyReceiptQuantity(childDbAlready.add(childQty)); + returnReceiptMaterialDetailDOChild.setAlreadyReceiptGrossWeight(childDbAlreadyGross.add(childGross)); + returnReceiptMaterialDetailDOChild.setAlreadyReceiptNetWeight(childDbAlreadyNet.add(childNet)); + returnReceiptMaterialDetailDOChild.setAlreadyReceiptVolume(childDbAlreadyVol.add(childVol)); + returnReceiptMaterialDetailDOChild.setAlreadyReceiptArea(childDbAlreadyArea.add(childArea)); returnReceiptMaterialDetailDOChild.setAllowModify(2); returnReceiptMaterialDetailDOChild.setLevel(2); returnReceiptMaterialDetailDOChild.setParentUniqueId(receiptMaterialDetailPO.getUniqueId()); @@ -1623,7 +1838,16 @@ public class StockReceiptOrderApplicationService { returnReceiptMaterialDetailDOChild.setLevel(2); returnReceiptMaterialDetailDOChild.setParentUniqueId(receiptMaterialDetailPO.getUniqueId()); setMaterialMoreDetailInfo(returnReceiptMaterialDetailDOChild); + returnReceiptMaterialDetailDOChild.setAlreadyReceiptGrossWeight(childGross); + returnReceiptMaterialDetailDOChild.setAlreadyReceiptNetWeight(childNet); + returnReceiptMaterialDetailDOChild.setAlreadyReceiptVolume(childVol); + returnReceiptMaterialDetailDOChild.setAlreadyReceiptArea(childArea); } + // PC 端读 total*:与累计实绩一致(与 already_receipt_* 同步) + returnReceiptMaterialDetailDOChild.setTotalNetWeight(returnReceiptMaterialDetailDOChild.getAlreadyReceiptNetWeight()); + returnReceiptMaterialDetailDOChild.setTotalGrossWeight(returnReceiptMaterialDetailDOChild.getAlreadyReceiptGrossWeight()); + returnReceiptMaterialDetailDOChild.setTotalVolume(returnReceiptMaterialDetailDOChild.getAlreadyReceiptVolume()); + returnReceiptMaterialDetailDOChild.setTotalArea(returnReceiptMaterialDetailDOChild.getAlreadyReceiptArea()); //是否开启了序列号管理 if (receiptMaterialDetailPO.getSerialNumberManage() == 1){ if (CollectionUtils.isEmpty(receiptMaterialDetailDOChild.getMaterialDetailSerialNumberList())){ @@ -1642,8 +1866,45 @@ public class StockReceiptOrderApplicationService { mainItemActualQuantity = CollectionUtils.isEmpty(receiptMaterialDetailDOChildList) ? receiptQuantity : receiptQuantity.add(childrenTotalIncrement); + BigDecimal dbParentBeforeGross = receiptMaterialDetailPO.getAlreadyReceiptGrossWeight() != null ? receiptMaterialDetailPO.getAlreadyReceiptGrossWeight() : BigDecimal.ZERO; + BigDecimal dbParentBeforeNet = receiptMaterialDetailPO.getAlreadyReceiptNetWeight() != null ? receiptMaterialDetailPO.getAlreadyReceiptNetWeight() : BigDecimal.ZERO; + BigDecimal dbParentBeforeVol = receiptMaterialDetailPO.getAlreadyReceiptVolume() != null ? receiptMaterialDetailPO.getAlreadyReceiptVolume() : BigDecimal.ZERO; + BigDecimal dbParentBeforeArea = receiptMaterialDetailPO.getAlreadyReceiptArea() != null ? receiptMaterialDetailPO.getAlreadyReceiptArea() : BigDecimal.ZERO; + BigDecimal parentReceiptGross = pickThisReceiptMetricIncrement(receiptMaterialDetailDO.getReceiptGrossWeight(), receiptMaterialDetailDO.getTotalGrossWeight(), dbParentBeforeGross); + BigDecimal parentReceiptNet = pickThisReceiptMetricIncrement(receiptMaterialDetailDO.getReceiptNetWeight(), receiptMaterialDetailDO.getTotalNetWeight(), dbParentBeforeNet); + BigDecimal parentReceiptVol = pickThisReceiptMetricIncrement(receiptMaterialDetailDO.getReceiptVolume(), receiptMaterialDetailDO.getTotalVolume(), dbParentBeforeVol); + BigDecimal parentReceiptArea = pickThisReceiptMetricIncrement(receiptMaterialDetailDO.getReceiptArea(), receiptMaterialDetailDO.getTotalArea(), dbParentBeforeArea); + BigDecimal childrenGrossIncrement = newChildrenGrossTotal.add(existingChildrenGrossIncrement); + BigDecimal childrenNetIncrement = newChildrenNetTotal.add(existingChildrenNetIncrement); + BigDecimal childrenVolIncrement = newChildrenVolTotal.add(existingChildrenVolIncrement); + BigDecimal childrenAreaIncrement = newChildrenAreaTotal.add(existingChildrenAreaIncrement); + BigDecimal mainGrossIncrement = CollectionUtils.isEmpty(receiptMaterialDetailDOChildList) + ? parentReceiptGross + : parentReceiptGross.add(childrenGrossIncrement); + BigDecimal mainNetIncrement = CollectionUtils.isEmpty(receiptMaterialDetailDOChildList) + ? parentReceiptNet + : parentReceiptNet.add(childrenNetIncrement); + BigDecimal mainVolIncrement = CollectionUtils.isEmpty(receiptMaterialDetailDOChildList) + ? parentReceiptVol + : parentReceiptVol.add(childrenVolIncrement); + BigDecimal mainAreaIncrement = CollectionUtils.isEmpty(receiptMaterialDetailDOChildList) + ? parentReceiptArea + : parentReceiptArea.add(childrenAreaIncrement); //主项已收货数量 = 原有 + 主项本次收货增量 receiptMaterialDetailDO.setAlreadyReceiptQuantity(receiptMaterialDetailPO.getAlreadyReceiptQuantity().add(mainItemActualQuantity)); + BigDecimal dbParentAlreadyGross = receiptMaterialDetailPO.getAlreadyReceiptGrossWeight() != null ? receiptMaterialDetailPO.getAlreadyReceiptGrossWeight() : BigDecimal.ZERO; + receiptMaterialDetailDO.setAlreadyReceiptGrossWeight(dbParentAlreadyGross.add(mainGrossIncrement)); + BigDecimal dbParentAlreadyNet = receiptMaterialDetailPO.getAlreadyReceiptNetWeight() != null ? receiptMaterialDetailPO.getAlreadyReceiptNetWeight() : BigDecimal.ZERO; + receiptMaterialDetailDO.setAlreadyReceiptNetWeight(dbParentAlreadyNet.add(mainNetIncrement)); + BigDecimal dbParentAlreadyVol = receiptMaterialDetailPO.getAlreadyReceiptVolume() != null ? receiptMaterialDetailPO.getAlreadyReceiptVolume() : BigDecimal.ZERO; + receiptMaterialDetailDO.setAlreadyReceiptVolume(dbParentAlreadyVol.add(mainVolIncrement)); + BigDecimal dbParentAlreadyArea = receiptMaterialDetailPO.getAlreadyReceiptArea() != null ? receiptMaterialDetailPO.getAlreadyReceiptArea() : BigDecimal.ZERO; + receiptMaterialDetailDO.setAlreadyReceiptArea(dbParentAlreadyArea.add(mainAreaIncrement)); + // PC 端读 total*:与累计称重/体积/面积实绩一致(不改 PC 即可回显) + receiptMaterialDetailDO.setTotalNetWeight(receiptMaterialDetailDO.getAlreadyReceiptNetWeight()); + receiptMaterialDetailDO.setTotalGrossWeight(receiptMaterialDetailDO.getAlreadyReceiptGrossWeight()); + receiptMaterialDetailDO.setTotalVolume(receiptMaterialDetailDO.getAlreadyReceiptVolume()); + receiptMaterialDetailDO.setTotalArea(receiptMaterialDetailDO.getAlreadyReceiptArea()); //记录本次收货单收货总数(主项+子项合计,用于收货单级统计) orderLevelQuantity = mainItemActualQuantity; totalActualQuantity = totalActualQuantity.add(orderLevelQuantity); @@ -1656,11 +1917,19 @@ public class StockReceiptOrderApplicationService { } else { // 收货为 0 的明细:保持已收货数量和状态不变,仍加入列表以保持明细完整 receiptMaterialDetailDO.setAlreadyReceiptQuantity(receiptMaterialDetailPO.getAlreadyReceiptQuantity()); + receiptMaterialDetailDO.setAlreadyReceiptGrossWeight(receiptMaterialDetailPO.getAlreadyReceiptGrossWeight()); + receiptMaterialDetailDO.setAlreadyReceiptNetWeight(receiptMaterialDetailPO.getAlreadyReceiptNetWeight()); + receiptMaterialDetailDO.setAlreadyReceiptVolume(receiptMaterialDetailPO.getAlreadyReceiptVolume()); + receiptMaterialDetailDO.setAlreadyReceiptArea(receiptMaterialDetailPO.getAlreadyReceiptArea()); receiptMaterialDetailDO.setReceiptStatus(receiptMaterialDetailPO.getReceiptStatus() != null ? receiptMaterialDetailPO.getReceiptStatus() : 1); } ReceiptMaterialDetailDO returnReceiptMaterialDetailDO = new ReceiptMaterialDetailDO(); BeanUtils.copyProperties(receiptMaterialDetailPO, returnReceiptMaterialDetailDO); BeanUtils.copyProperties(receiptMaterialDetailDO, returnReceiptMaterialDetailDO, IgnoreNullUtil.getNullPropertyNames(receiptMaterialDetailDO)); + returnReceiptMaterialDetailDO.setTotalNetWeight(receiptMaterialDetailDO.getTotalNetWeight()); + returnReceiptMaterialDetailDO.setTotalGrossWeight(receiptMaterialDetailDO.getTotalGrossWeight()); + returnReceiptMaterialDetailDO.setTotalVolume(receiptMaterialDetailDO.getTotalVolume()); + returnReceiptMaterialDetailDO.setTotalArea(receiptMaterialDetailDO.getTotalArea()); if (receiptMaterialDetailPO.getReceiptStatus() == 1){ //一级列表 首次收货 //是否开启了序列号管理 diff --git a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockShelfOrder/StockShelfOrderApplicationService.java b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockShelfOrder/StockShelfOrderApplicationService.java index 470b71f21..a8e42c4c3 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockShelfOrder/StockShelfOrderApplicationService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockShelfOrder/StockShelfOrderApplicationService.java @@ -20,6 +20,9 @@ import com.mhd.system.api.domain.cache.AssociationWarehouseCacheDO; import com.mhd.system.api.domain.cache.SystemServiceCacheUtil; import com.mhd.system.api.model.LoginUser; import com.mhd.wms.domain.inventoryAdjustmentRecord.entity.InventoryAdjustmentRecord; +import com.mhd.wms.domain.receiptMaterialDetail.repository.po.ReceiptMaterialDetailPO; +import com.mhd.wms.domain.receiptMaterialDetail.repository.todo.ReceiptMaterialDetailDO; +import com.mhd.wms.domain.receiptMaterialDetail.service.ReceiptMaterialDetailDomainService; import com.mhd.wms.domain.materialBarCode.repository.facade.IMaterialBarCodeService; import com.mhd.wms.domain.materialBarCode.repository.po.MaterialBarCodePO; import com.mhd.wms.domain.materialBaseInfo.entity.MaterialBaseInfo; @@ -36,6 +39,9 @@ import com.mhd.wms.domain.materialInventory.repository.mapper.MaterialInventoryM import com.mhd.wms.domain.materialInventory.repository.po.MaterialInventoryPO; import com.mhd.system.api.domain.BatchDetailFeignPO; import com.mhd.wms.domain.materialMoreDetail.repository.po.MaterialMoreDetailPO; +import com.mhd.wms.domain.inMaterialDetail.repository.po.InMaterialDetailPO; +import com.mhd.wms.domain.inMaterialDetail.repository.todo.InMaterialDetailDO; +import com.mhd.wms.domain.inMaterialDetail.service.InMaterialDetailDomainService; import com.mhd.wms.domain.shelfMaterialDetail.repository.po.ShelfMaterialDetailPO; import com.mhd.wms.domain.shelfMaterialDetail.repository.todo.ShelfMaterialDetailDO; import com.mhd.wms.domain.shelfMaterialDetail.service.ShelfMaterialDetailDomainService; @@ -75,6 +81,10 @@ public class StockShelfOrderApplicationService { @Autowired private ShelfMaterialDetailDomainService shelfMaterialDetailDomainService; @Autowired + private InMaterialDetailDomainService inMaterialDetailDomainService; + @Autowired + private ReceiptMaterialDetailDomainService receiptMaterialDetailDomainService; + @Autowired private UserServiceFeign userServiceFeign; @Autowired private SystemServiceFeign systemServiceFeign; @@ -320,6 +330,374 @@ public class StockShelfOrderApplicationService { return stockShelfOrderPO; } + /** + * PDA 获取上架单详情:可按明细 shelvesStatus 做 tab 筛选(PC 不走该接口) + * + * @param shelfStatus 1=待上架(仅1/2),3=已上架(3/4/5),null 返回全部明细 + */ + public StockShelfOrderPO getInfo(Long shelfOrderId, boolean addParentCopyWhenNoChildren, Integer shelfStatus) { + StockShelfOrderPO stockShelfOrderPO = getInfo(shelfOrderId, addParentCopyWhenNoChildren); + if (stockShelfOrderPO == null) { + return stockShelfOrderPO; + } + // 只在 PDA 场景下生效(addParentCopyWhenNoChildren==true) + if (!addParentCopyWhenNoChildren) { + return stockShelfOrderPO; + } + List materialDetailList = stockShelfOrderPO.getMaterialDetailList(); + if (CollectionUtils.isEmpty(materialDetailList)) { + return stockShelfOrderPO; + } + if (shelfStatus != null) { + materialDetailList = filterShelfMaterialDetailsByShelfStatus(materialDetailList, shelfStatus); + } + // 已上架完成(3/4/5):主项无子项时注入的 parent_copy 与主项为同一明细,子行可能仍带「本次提交」的 shelves_quantity=0, + // 导致「上架数量」误显示为 0;与主项对齐累计已上架数量后再做展示计算 + alignParentCopyShelfQuantityWithParentForTerminal(materialDetailList); + // PDA 待上架数量 = 计划数量 - 已上架数量,仅接口计算(不落库) + fillPendingShelvesQuantityRecursively(materialDetailList); + // PDA 展示:shelvesQuantity 显示为累计已上架数量(与 receipt 口径一致);已上架完成行不再用本次提交量 + syncShelvesQuantityCumulativeDisplayRecursively(materialDetailList); + // PDA 展示:净重/毛重/体积/面积 + // - 待上架/上架中:展示 pending = 计划 - 已上架 + // - 已上架(3/4/5):展示累计已上架(不计算 pending) + Map planWeightMetrics = loadReceiptPlanWeightMetrics(stockShelfOrderPO.getReceiptOrderNumber()); + overwriteTotalWithPendingForPdaWeightDisplayRecursively(materialDetailList, planWeightMetrics); + syncMaterialMoreDetailWeightValuesRecursively(materialDetailList); + stockShelfOrderPO.setMaterialDetailList(materialDetailList); + return stockShelfOrderPO; + } + + private List filterShelfMaterialDetailsByShelfStatus(List source, Integer shelfStatus) { + if (CollectionUtils.isEmpty(source) || shelfStatus == null) { + return source; + } + List result = new ArrayList<>(); + for (ShelfMaterialDetailPO item : source) { + if (item == null) { + continue; + } + List filteredChildren = filterShelfMaterialDetailsByShelfStatus(item.getChildren(), shelfStatus); + item.setChildren(filteredChildren == null ? new ArrayList<>() : filteredChildren); + if (matchShelfDetailStatusFilter(item.getShelvesStatus(), shelfStatus) || !CollectionUtils.isEmpty(item.getChildren())) { + result.add(item); + } + } + return result; + } + + private boolean matchShelfDetailStatusFilter(Integer detailShelvesStatus, Integer requestShelfStatus) { + if (detailShelvesStatus == null || requestShelfStatus == null) { + return false; + } + if (requestShelfStatus == 1) { + return detailShelvesStatus == 1 || detailShelvesStatus == 2; + } + if (requestShelfStatus == 3) { + return detailShelvesStatus == 3 || detailShelvesStatus == 4 || detailShelvesStatus == 5; + } + return true; + } + + /** + * PDA 待上架数量递归计算:待上架数量 = max(0, 计划数量 - 已上架数量) + */ + private void fillPendingShelvesQuantityRecursively(List list) { + if (CollectionUtils.isEmpty(list)) { + return; + } + for (ShelfMaterialDetailPO d : list) { + if (d == null) { + continue; + } + BigDecimal plan = d.getQuantity() != null ? d.getQuantity() : BigDecimal.ZERO; + BigDecimal already = d.getAlreadyShelvesQuantity() != null ? d.getAlreadyShelvesQuantity() : BigDecimal.ZERO; + BigDecimal pending = plan.subtract(already); + if (pending.compareTo(BigDecimal.ZERO) <= 0) { + pending = BigDecimal.ZERO; + } + d.setPendingShelvesQuantity(pending); + fillPendingShelvesQuantityRecursively(d.getChildren()); + } + } + + /** + * PDA:已上架完成时,将 parent_copy 子行的累计已上架数量与主项对齐(仅接口展示,不落库)。 + * 否则详情页从 children 读数时「上架数量」仍为 0。 + */ + private void alignParentCopyShelfQuantityWithParentForTerminal(List list) { + if (CollectionUtils.isEmpty(list)) { + return; + } + for (ShelfMaterialDetailPO parent : list) { + if (parent == null) { + continue; + } + List children = parent.getChildren(); + if (!CollectionUtils.isEmpty(children)) { + ShelfMaterialDetailPO first = children.get(0); + if (first != null + && isShelfParentCopyPo(parent, first) + && isShelfTerminalShelvesStatus(parent.getShelvesStatus())) { + BigDecimal pAlready = parent.getAlreadyShelvesQuantity() != null + ? parent.getAlreadyShelvesQuantity() + : BigDecimal.ZERO; + first.setAlreadyShelvesQuantity(pAlready); + first.setShelvesStatus(parent.getShelvesStatus()); + } + alignParentCopyShelfQuantityWithParentForTerminal(children); + } + } + } + + /** + * 判断子项是否为 getInfo 时注入的 parent_copy(与主项同 materialDetailId 或 uniqueId) + */ + private static boolean isShelfParentCopyPo(ShelfMaterialDetailPO parent, ShelfMaterialDetailPO child) { + if (parent == null || child == null) { + return false; + } + Long parentId = parent.getMaterialDetailId(); + Long childId = child.getMaterialDetailId(); + Long parentUid = parent.getUniqueId(); + Long childUid = child.getUniqueId(); + if (parentId != null && parentId.equals(childId)) { + return true; + } + if (parentUid != null && parentUid.equals(childUid)) { + return true; + } + if (childId != null && parentId != null && !childId.equals(parentId)) { + return false; + } + if (childUid != null && parentUid != null && !childUid.equals(parentUid)) { + return false; + } + return childId == null && childUid == null; + } + + /** + * PDA 展示把 shelvesQuantity 改为累计已上架数量(alreadyShelvesQuantity) + * - 不落库:仅影响接口返回 + * - 让前端“上架数量”展示字段与累计字段一致 + * - 已上架完成(3/4/5):不再使用 DB 中「本次提交」的 shelves_quantity 语义,统一为已上架数量 + */ + private void syncShelvesQuantityCumulativeDisplayRecursively(List list) { + if (CollectionUtils.isEmpty(list)) { + return; + } + for (ShelfMaterialDetailPO d : list) { + if (d == null) { + continue; + } + BigDecimal already = d.getAlreadyShelvesQuantity() != null ? d.getAlreadyShelvesQuantity() : BigDecimal.ZERO; + d.setShelvesQuantity(already); + syncShelvesQuantityCumulativeDisplayRecursively(d.getChildren()); + } + } + + private static boolean isShelfTerminalShelvesStatus(Integer shelvesStatus) { + return shelvesStatus != null && (shelvesStatus == 3 || shelvesStatus == 4 || shelvesStatus == 5); + } + + private static class WeightMetrics { + private BigDecimal netWeight; + private BigDecimal grossWeight; + private BigDecimal volume; + private BigDecimal area; + + private WeightMetrics(BigDecimal netWeight, BigDecimal grossWeight, BigDecimal volume, BigDecimal area) { + this.netWeight = netWeight; + this.grossWeight = grossWeight; + this.volume = volume; + this.area = area; + } + } + + /** + * 从收货单明细加载 PDA“计划净重/毛重/体积/面积”(用于 plan - already) + * key: + * - receipt_material_detail.unique_id + * - receipt_material_detail.in_unique_id(兼容部分场景只传 inUniqueId) + */ + private Map loadReceiptPlanWeightMetrics(String receiptOrderNumber) { + Map result = new HashMap<>(); + if (StringUtils.isBlank(receiptOrderNumber)) { + return result; + } + ReceiptMaterialDetailDO query = new ReceiptMaterialDetailDO(); + query.setReceiptOrderNumber(receiptOrderNumber); + List list = receiptMaterialDetailDomainService.queryList(query); + if (CollectionUtils.isEmpty(list)) { + return result; + } + for (ReceiptMaterialDetailPO p : list) { + if (p == null || p.getUniqueId() == null) { + continue; + } + WeightMetrics metrics = new WeightMetrics( + p.getTotalNetWeight(), + p.getTotalGrossWeight(), + p.getTotalVolume(), + p.getTotalArea() + ); + // key1:收货明细 unique_id + result.put(p.getUniqueId(), metrics); + // key2:兼容:有些上架明细可能只带 inUniqueId + if (p.getInUniqueId() != null) { + result.put(p.getInUniqueId(), metrics); + } + } + return result; + } + + private void overwriteTotalWithPendingForPdaWeightDisplayRecursively( + List list, + Map planWeightMetrics + ) { + if (CollectionUtils.isEmpty(list)) { + return; + } + for (ShelfMaterialDetailPO d : list) { + if (d == null) { + continue; + } + // 已上架:不覆盖,展示累计已上架实绩(与 DB 同口径) + if (isShelfTerminalShelvesStatus(d.getShelvesStatus())) { + // 参考收货:已完成行不参与「计划−待收」,total* 直接展示累计 already + if (d.getAlreadyShelvesNetWeight() != null) { + d.setTotalNetWeight(d.getAlreadyShelvesNetWeight()); + } + if (d.getAlreadyShelvesGrossWeight() != null) { + d.setTotalGrossWeight(d.getAlreadyShelvesGrossWeight()); + } + if (d.getAlreadyShelvesVolume() != null) { + d.setTotalVolume(d.getAlreadyShelvesVolume()); + } + if (d.getAlreadyShelvesArea() != null) { + d.setTotalArea(d.getAlreadyShelvesArea()); + } + overwriteTotalWithPendingForPdaWeightDisplayRecursively(d.getChildren(), planWeightMetrics); + continue; + } + + Long planKey = d.getReceiptUniqueId() != null ? d.getReceiptUniqueId() : d.getInUniqueId(); + WeightMetrics plan = planWeightMetrics != null && planKey != null ? planWeightMetrics.get(planKey) : null; + BigDecimal planNet = plan != null ? plan.netWeight : null; + BigDecimal planGross = plan != null ? plan.grossWeight : null; + BigDecimal planVol = plan != null ? plan.volume : null; + BigDecimal planArea = plan != null ? plan.area : null; + + BigDecimal alreadyNet = d.getAlreadyShelvesNetWeight() != null ? d.getAlreadyShelvesNetWeight() : BigDecimal.ZERO; + BigDecimal alreadyGross = d.getAlreadyShelvesGrossWeight() != null ? d.getAlreadyShelvesGrossWeight() : BigDecimal.ZERO; + BigDecimal alreadyVol = d.getAlreadyShelvesVolume() != null ? d.getAlreadyShelvesVolume() : BigDecimal.ZERO; + BigDecimal alreadyArea = d.getAlreadyShelvesArea() != null ? d.getAlreadyShelvesArea() : BigDecimal.ZERO; + + // 参考收货:只对「有计划值」的字段覆盖 total*,否则保留原 total* + if (planNet == null && planGross == null && planVol == null && planArea == null) { + overwriteTotalWithPendingForPdaWeightDisplayRecursively(d.getChildren(), planWeightMetrics); + continue; + } + + // 兜底:待上架(1/2) 且已上架数量为 0 时, + // DB 里的 total_* 可能被初始化为“计划值”,此时不应把它当作 already。 + // 按“数量为准”把 already 权重当 0,使 pending 展示为计划值。 + BigDecimal alreadyShelvesQty = d.getAlreadyShelvesQuantity() != null ? d.getAlreadyShelvesQuantity() : BigDecimal.ZERO; + boolean hasAlreadyQty = alreadyShelvesQty.compareTo(BigDecimal.ZERO) > 0; + if (!hasAlreadyQty) { + alreadyNet = BigDecimal.ZERO; + alreadyGross = BigDecimal.ZERO; + alreadyVol = BigDecimal.ZERO; + alreadyArea = BigDecimal.ZERO; + } + + if (planNet != null) { + d.setTotalNetWeight(calcPendingMetric(planNet, alreadyNet)); + } + if (planGross != null) { + d.setTotalGrossWeight(calcPendingMetric(planGross, alreadyGross)); + } + if (planVol != null) { + d.setTotalVolume(calcPendingMetric(planVol, alreadyVol)); + } + if (planArea != null) { + d.setTotalArea(calcPendingMetric(planArea, alreadyArea)); + } + + overwriteTotalWithPendingForPdaWeightDisplayRecursively(d.getChildren(), planWeightMetrics); + } + } + + private static BigDecimal calcPendingMetric(BigDecimal plan, BigDecimal already) { + if (plan == null) { + return null; + } + BigDecimal pending = plan.subtract(already != null ? already : BigDecimal.ZERO); + if (pending.compareTo(BigDecimal.ZERO) <= 0) { + return BigDecimal.ZERO; + } + return normalizeDecimalForApi(pending); + } + + private static BigDecimal normalizeDecimalForApi(BigDecimal v) { + if (v == null) { + return null; + } + if (v.compareTo(BigDecimal.ZERO) == 0) { + return BigDecimal.ZERO; + } + BigDecimal stripped = v.stripTrailingZeros(); + return new BigDecimal(stripped.toPlainString()); + } + + private void syncMaterialMoreDetailWeightValuesRecursively(List list) { + if (CollectionUtils.isEmpty(list)) { + return; + } + for (ShelfMaterialDetailPO d : list) { + if (d == null) { + continue; + } + if (!CollectionUtils.isEmpty(d.getMaterialMoreDetailList())) { + String netStr = d.getTotalNetWeight() != null ? d.getTotalNetWeight().toPlainString() : null; + String grossStr = d.getTotalGrossWeight() != null ? d.getTotalGrossWeight().toPlainString() : null; + String volStr = d.getTotalVolume() != null ? d.getTotalVolume().toPlainString() : null; + String areaStr = d.getTotalArea() != null ? d.getTotalArea().toPlainString() : null; + for (MaterialMoreDetailPO m : d.getMaterialMoreDetailList()) { + if (m == null || StringUtils.isBlank(m.getBatchLabels())) { + continue; + } + String labels = m.getBatchLabels().trim(); + switch (labels) { + case "总净重": + case "净重(KG)": + case "净重": + m.setAttributeValue(netStr); + break; + case "总毛重": + case "毛重(KG)": + case "毛重": + m.setAttributeValue(grossStr); + break; + case "总体积": + case "体积(CBM)": + case "体积": + m.setAttributeValue(volStr); + break; + case "总面积": + case "面积(SQM)": + case "面积": + m.setAttributeValue(areaStr); + break; + default: + break; + } + } + } + syncMaterialMoreDetailWeightValuesRecursively(d.getChildren()); + } + } + /** * 获取上架单详细信息 */ @@ -363,6 +741,8 @@ public class StockShelfOrderApplicationService { * @return Boolean */ public Boolean upShelfByApp(StockShelfOrderDO stockReceiptOrderDO){ + // 标记 PDA:权重/数量都按“累计”语义处理(与收货保持一致) + stockReceiptOrderDO.setFromApp(Boolean.TRUE); List shelfMaterialDetailDOList = stockReceiptOrderDO.getMaterialDetailList(); boolean firstItemHadChildrenBefore = !CollectionUtils.isEmpty(shelfMaterialDetailDOList) && !CollectionUtils.isEmpty(shelfMaterialDetailDOList.get(0).getChildren()); @@ -599,6 +979,11 @@ public class StockShelfOrderApplicationService { if (stockShelfOrderPO.getStatus() > 2) { throw new ServiceException("上架单已完成上架"); } + // PDA:totalNetWeight/totalGrossWeight/totalVolume/totalArea 按“增量”回传,需要累加到 DB 的 total*(不超过计划) + boolean fromApp = Boolean.TRUE.equals(stockShelfOrderDO.getFromApp()); + Map planWeightMetrics = fromApp + ? loadReceiptPlanWeightMetrics(stockShelfOrderPO.getReceiptOrderNumber()) + : new HashMap<>(); StockShelfOrderDO returnStockShelfOrderDO = new StockShelfOrderDO(); BeanUtils.copyProperties(stockShelfOrderDO, returnStockShelfOrderDO); returnStockShelfOrderDO.setShelfOrderId(stockShelfOrderPO.getShelfOrderId()); @@ -649,6 +1034,11 @@ public class StockShelfOrderApplicationService { continue; } BigDecimal actualQuantity = BigDecimal.ZERO;//当前作业上架数 + // PDA 权重/体积/面积:记录“本次增量” + BigDecimal netIncrement = BigDecimal.ZERO; + BigDecimal grossIncrement = BigDecimal.ZERO; + BigDecimal volIncrement = BigDecimal.ZERO; + BigDecimal areaIncrement = BigDecimal.ZERO; //判断收否上架 第一次收货创建 更多属性 序列号 if (shelfMaterialDetailPO.getShelvesQuantity().compareTo(BigDecimal.ZERO) == 0){ //设置上架信息 @@ -663,7 +1053,23 @@ public class StockShelfOrderApplicationService { //判断是否存在子项 List returnShelfMaterialDetailDOChildList = new ArrayList<>(); List shelfMaterialDetailDOChildList = shelfMaterialDetailDO.getChildren(); - if (!CollectionUtils.isEmpty(shelfMaterialDetailDOChildList)){ + // 叶子节点在第二次上架时,DB 里的 shelves_quantity 可能不为 0, + // 旧逻辑只依赖 children 来计算 actualQuantity,导致 actualQuantity=0, + // 从而 alreadyShelvesQuantity 不累计(覆盖问题的根因)。 + // 当没有子项时,actualQuantity 应直接等于本次上架数量 shelvesQuantity。 + if (CollectionUtils.isEmpty(shelfMaterialDetailDOChildList)) { + actualQuantity = shelvesQuantity; + if (fromApp) { + // 若本次未上架数量(shelvesQuantity=0),则不允许用 PDA 提交的重量更新累计值 + // 否则会出现:数量仍为 0,但 total_* 已经被累加到计划值 => pending 全 0 + if (shelvesQuantity.compareTo(BigDecimal.ZERO) > 0) { + netIncrement = shelfMaterialDetailDO.getTotalNetWeight() != null ? shelfMaterialDetailDO.getTotalNetWeight() : BigDecimal.ZERO; + grossIncrement = shelfMaterialDetailDO.getTotalGrossWeight() != null ? shelfMaterialDetailDO.getTotalGrossWeight() : BigDecimal.ZERO; + volIncrement = shelfMaterialDetailDO.getTotalVolume() != null ? shelfMaterialDetailDO.getTotalVolume() : BigDecimal.ZERO; + areaIncrement = shelfMaterialDetailDO.getTotalArea() != null ? shelfMaterialDetailDO.getTotalArea() : BigDecimal.ZERO; + } + } + } else { for (ShelfMaterialDetailDO shelfMaterialDetailDOChild : shelfMaterialDetailDOChildList){ ShelfMaterialDetailPO shelfMaterialDetailPOChildDb = shelfMaterialDetailDbMap.get(shelfMaterialDetailDOChild.getMaterialDetailId()); if (shelfMaterialDetailPOChildDb == null && shelfMaterialDetailDOChild.getUniqueId() != null) { @@ -673,12 +1079,100 @@ public class StockShelfOrderApplicationService { } } BigDecimal childShelvesQty = shelfMaterialDetailDOChild.getShelvesQuantity() != null ? shelfMaterialDetailDOChild.getShelvesQuantity() : BigDecimal.ZERO; + if (fromApp) { + // 子项未上架数量时,不累加重量增量 + BigDecimal childNetInc = childShelvesQty.compareTo(BigDecimal.ZERO) > 0 + ? (shelfMaterialDetailDOChild.getTotalNetWeight() != null ? shelfMaterialDetailDOChild.getTotalNetWeight() : BigDecimal.ZERO) + : BigDecimal.ZERO; + BigDecimal childGrossInc = childShelvesQty.compareTo(BigDecimal.ZERO) > 0 + ? (shelfMaterialDetailDOChild.getTotalGrossWeight() != null ? shelfMaterialDetailDOChild.getTotalGrossWeight() : BigDecimal.ZERO) + : BigDecimal.ZERO; + BigDecimal childVolInc = childShelvesQty.compareTo(BigDecimal.ZERO) > 0 + ? (shelfMaterialDetailDOChild.getTotalVolume() != null ? shelfMaterialDetailDOChild.getTotalVolume() : BigDecimal.ZERO) + : BigDecimal.ZERO; + BigDecimal childAreaInc = childShelvesQty.compareTo(BigDecimal.ZERO) > 0 + ? (shelfMaterialDetailDOChild.getTotalArea() != null ? shelfMaterialDetailDOChild.getTotalArea() : BigDecimal.ZERO) + : BigDecimal.ZERO; + // 汇总父项“本次增量” + netIncrement = netIncrement.add(childNetInc); + grossIncrement = grossIncrement.add(childGrossInc); + volIncrement = volIncrement.add(childVolInc); + areaIncrement = areaIncrement.add(childAreaInc); + } if (shelfMaterialDetailPOChildDb != null){ // 子项已存在:累加上架数量,并加入返回列表供 batchShelfUpdate 更新(与收货一致,避免重复提交/漏更新) actualQuantity = actualQuantity.add(childShelvesQty); ShelfMaterialDetailDO returnShelfMaterialDetailDOChild = new ShelfMaterialDetailDO(); BeanUtils.copyProperties(shelfMaterialDetailPOChildDb, returnShelfMaterialDetailDOChild); BeanUtils.copyProperties(shelfMaterialDetailDOChild, returnShelfMaterialDetailDOChild, IgnoreNullUtil.getNullPropertyNames(shelfMaterialDetailDOChild)); + if (fromApp) { + // 子项已存在:total* 回传的是“本次增量”,需要累加到已有 already(并不超过计划) + // oldAlready:优先用 DB 的累计值 total_*。 + // 但如果 DB 历史脏数据导致 already_shelves_quantity=0 时 total_* 也被初始化成“计划值”, + // 那么这些 total_* 不应再当作 already 基数参与累加(否则会被 min(plan, ...) 直接卡死为 plan)。 + BigDecimal childOldAlreadyQty = shelfMaterialDetailPOChildDb.getAlreadyShelvesQuantity() != null + ? shelfMaterialDetailPOChildDb.getAlreadyShelvesQuantity() + : BigDecimal.ZERO; + boolean childHasAlreadyQty = childOldAlreadyQty.compareTo(BigDecimal.ZERO) > 0; + + BigDecimal childOldAlreadyNet = childHasAlreadyQty && shelfMaterialDetailPOChildDb.getTotalNetWeight() != null + ? shelfMaterialDetailPOChildDb.getTotalNetWeight() + : BigDecimal.ZERO; + BigDecimal childOldAlreadyGross = childHasAlreadyQty && shelfMaterialDetailPOChildDb.getTotalGrossWeight() != null + ? shelfMaterialDetailPOChildDb.getTotalGrossWeight() + : BigDecimal.ZERO; + BigDecimal childOldAlreadyVol = childHasAlreadyQty && shelfMaterialDetailPOChildDb.getTotalVolume() != null + ? shelfMaterialDetailPOChildDb.getTotalVolume() + : BigDecimal.ZERO; + BigDecimal childOldAlreadyArea = childHasAlreadyQty && shelfMaterialDetailPOChildDb.getTotalArea() != null + ? shelfMaterialDetailPOChildDb.getTotalArea() + : BigDecimal.ZERO; + + WeightMetrics childPlan = shelfMaterialDetailPOChildDb.getInUniqueId() != null + ? planWeightMetrics.get(shelfMaterialDetailPOChildDb.getReceiptUniqueId() != null + ? shelfMaterialDetailPOChildDb.getReceiptUniqueId() + : shelfMaterialDetailPOChildDb.getInUniqueId()) + : null; + + // 子项未上架数量时,不累加重量增量(保持 DB already 不变) + BigDecimal childNetInc = childShelvesQty.compareTo(BigDecimal.ZERO) > 0 + ? (shelfMaterialDetailDOChild.getTotalNetWeight() != null ? shelfMaterialDetailDOChild.getTotalNetWeight() : BigDecimal.ZERO) + : BigDecimal.ZERO; + BigDecimal childGrossInc = childShelvesQty.compareTo(BigDecimal.ZERO) > 0 + ? (shelfMaterialDetailDOChild.getTotalGrossWeight() != null ? shelfMaterialDetailDOChild.getTotalGrossWeight() : BigDecimal.ZERO) + : BigDecimal.ZERO; + BigDecimal childVolInc = childShelvesQty.compareTo(BigDecimal.ZERO) > 0 + ? (shelfMaterialDetailDOChild.getTotalVolume() != null ? shelfMaterialDetailDOChild.getTotalVolume() : BigDecimal.ZERO) + : BigDecimal.ZERO; + BigDecimal childAreaInc = childShelvesQty.compareTo(BigDecimal.ZERO) > 0 + ? (shelfMaterialDetailDOChild.getTotalArea() != null ? shelfMaterialDetailDOChild.getTotalArea() : BigDecimal.ZERO) + : BigDecimal.ZERO; + + BigDecimal childNewAlreadyNet = childOldAlreadyNet.add(childNetInc); + BigDecimal childNewAlreadyGross = childOldAlreadyGross.add(childGrossInc); + BigDecimal childNewAlreadyVol = childOldAlreadyVol.add(childVolInc); + BigDecimal childNewAlreadyArea = childOldAlreadyArea.add(childAreaInc); + + if (childPlan != null) { + if (childPlan.netWeight != null && childNewAlreadyNet.compareTo(childPlan.netWeight) > 0) { + childNewAlreadyNet = childPlan.netWeight; + } + if (childPlan.grossWeight != null && childNewAlreadyGross.compareTo(childPlan.grossWeight) > 0) { + childNewAlreadyGross = childPlan.grossWeight; + } + if (childPlan.volume != null && childNewAlreadyVol.compareTo(childPlan.volume) > 0) { + childNewAlreadyVol = childPlan.volume; + } + if (childPlan.area != null && childNewAlreadyArea.compareTo(childPlan.area) > 0) { + childNewAlreadyArea = childPlan.area; + } + } + + returnShelfMaterialDetailDOChild.setTotalNetWeight(childNewAlreadyNet); + returnShelfMaterialDetailDOChild.setTotalGrossWeight(childNewAlreadyGross); + returnShelfMaterialDetailDOChild.setTotalVolume(childNewAlreadyVol); + returnShelfMaterialDetailDOChild.setTotalArea(childNewAlreadyArea); + } setStorageLocationInfo(returnShelfMaterialDetailDOChild); returnShelfMaterialDetailDOChild.setAllowModify(2); returnShelfMaterialDetailDOChild.setLevel(2); @@ -691,6 +1185,47 @@ public class StockShelfOrderApplicationService { BeanUtils.copyProperties(shelfMaterialDetailPO, returnShelfMaterialDetailDOChild, "materialDetailId","createBy","createByName","createTime", "updateBy","updateByName","updateTime"); BeanUtils.copyProperties(shelfMaterialDetailDOChild, returnShelfMaterialDetailDOChild, IgnoreNullUtil.getNullPropertyNames(shelfMaterialDetailDOChild)); + if (fromApp) { + // 子项不存在:new already = 0 + 本次增量(并不超过计划) + WeightMetrics childPlan = shelfMaterialDetailDOChild.getInUniqueId() != null + ? planWeightMetrics.get(shelfMaterialDetailDOChild.getReceiptUniqueId() != null + ? shelfMaterialDetailDOChild.getReceiptUniqueId() + : shelfMaterialDetailDOChild.getInUniqueId()) + : null; + + // 子项未上架数量时,不允许用 PDA 提交的 total_* 更新累计重量 + BigDecimal childNewAlreadyNet = childShelvesQty.compareTo(BigDecimal.ZERO) > 0 + ? (shelfMaterialDetailDOChild.getTotalNetWeight() != null ? shelfMaterialDetailDOChild.getTotalNetWeight() : BigDecimal.ZERO) + : BigDecimal.ZERO; + BigDecimal childNewAlreadyGross = childShelvesQty.compareTo(BigDecimal.ZERO) > 0 + ? (shelfMaterialDetailDOChild.getTotalGrossWeight() != null ? shelfMaterialDetailDOChild.getTotalGrossWeight() : BigDecimal.ZERO) + : BigDecimal.ZERO; + BigDecimal childNewAlreadyVol = childShelvesQty.compareTo(BigDecimal.ZERO) > 0 + ? (shelfMaterialDetailDOChild.getTotalVolume() != null ? shelfMaterialDetailDOChild.getTotalVolume() : BigDecimal.ZERO) + : BigDecimal.ZERO; + BigDecimal childNewAlreadyArea = childShelvesQty.compareTo(BigDecimal.ZERO) > 0 + ? (shelfMaterialDetailDOChild.getTotalArea() != null ? shelfMaterialDetailDOChild.getTotalArea() : BigDecimal.ZERO) + : BigDecimal.ZERO; + + if (childPlan != null) { + if (childPlan.netWeight != null && childNewAlreadyNet.compareTo(childPlan.netWeight) > 0) { + childNewAlreadyNet = childPlan.netWeight; + } + if (childPlan.grossWeight != null && childNewAlreadyGross.compareTo(childPlan.grossWeight) > 0) { + childNewAlreadyGross = childPlan.grossWeight; + } + if (childPlan.volume != null && childNewAlreadyVol.compareTo(childPlan.volume) > 0) { + childNewAlreadyVol = childPlan.volume; + } + if (childPlan.area != null && childNewAlreadyArea.compareTo(childPlan.area) > 0) { + childNewAlreadyArea = childPlan.area; + } + } + returnShelfMaterialDetailDOChild.setTotalNetWeight(childNewAlreadyNet); + returnShelfMaterialDetailDOChild.setTotalGrossWeight(childNewAlreadyGross); + returnShelfMaterialDetailDOChild.setTotalVolume(childNewAlreadyVol); + returnShelfMaterialDetailDOChild.setTotalArea(childNewAlreadyArea); + } setStorageLocationInfo(shelfMaterialDetailDOChild); returnShelfMaterialDetailDOChild.setAllowModify(2); returnShelfMaterialDetailDOChild.setMaterialDetailSerialNumberList(shelfMaterialDetailDOChild.getMaterialDetailSerialNumberList()); @@ -710,6 +1245,58 @@ public class StockShelfOrderApplicationService { } //现在已上架数量=之前已上架数量+现在作业数量 shelfMaterialDetailDO.setAlreadyShelvesQuantity(shelfMaterialDetailPO.getAlreadyShelvesQuantity().add(actualQuantity)); + if (fromApp) { + // 父项:total* 回传的是“本次增量”,需要累加到已有 already(并不超过计划) + // oldAlready:优先用 DB 的累计值 total_*。 + // 但如果 DB 历史脏数据导致 already_shelves_quantity=0 时 total_* 也被初始化成“计划值”, + // 那么这些 total_* 不应再当作 already 基数参与累加(否则会被 min(plan, ...) 直接卡死为 plan)。 + BigDecimal oldAlreadyQty = shelfMaterialDetailPO.getAlreadyShelvesQuantity() != null + ? shelfMaterialDetailPO.getAlreadyShelvesQuantity() + : BigDecimal.ZERO; + boolean hasAlreadyQty = oldAlreadyQty.compareTo(BigDecimal.ZERO) > 0; + + BigDecimal oldAlreadyNet = hasAlreadyQty && shelfMaterialDetailPO.getTotalNetWeight() != null + ? shelfMaterialDetailPO.getTotalNetWeight() + : BigDecimal.ZERO; + BigDecimal oldAlreadyGross = hasAlreadyQty && shelfMaterialDetailPO.getTotalGrossWeight() != null + ? shelfMaterialDetailPO.getTotalGrossWeight() + : BigDecimal.ZERO; + BigDecimal oldAlreadyVol = hasAlreadyQty && shelfMaterialDetailPO.getTotalVolume() != null + ? shelfMaterialDetailPO.getTotalVolume() + : BigDecimal.ZERO; + BigDecimal oldAlreadyArea = hasAlreadyQty && shelfMaterialDetailPO.getTotalArea() != null + ? shelfMaterialDetailPO.getTotalArea() + : BigDecimal.ZERO; + + BigDecimal newAlreadyNet = oldAlreadyNet.add(netIncrement); + BigDecimal newAlreadyGross = oldAlreadyGross.add(grossIncrement); + BigDecimal newAlreadyVol = oldAlreadyVol.add(volIncrement); + BigDecimal newAlreadyArea = oldAlreadyArea.add(areaIncrement); + + WeightMetrics plan = shelfMaterialDetailPO.getInUniqueId() != null + ? planWeightMetrics.get(shelfMaterialDetailPO.getReceiptUniqueId() != null + ? shelfMaterialDetailPO.getReceiptUniqueId() + : shelfMaterialDetailPO.getInUniqueId()) + : null; + if (plan != null) { + if (plan.netWeight != null && newAlreadyNet.compareTo(plan.netWeight) > 0) { + newAlreadyNet = plan.netWeight; + } + if (plan.grossWeight != null && newAlreadyGross.compareTo(plan.grossWeight) > 0) { + newAlreadyGross = plan.grossWeight; + } + if (plan.volume != null && newAlreadyVol.compareTo(plan.volume) > 0) { + newAlreadyVol = plan.volume; + } + if (plan.area != null && newAlreadyArea.compareTo(plan.area) > 0) { + newAlreadyArea = plan.area; + } + } + shelfMaterialDetailDO.setTotalNetWeight(newAlreadyNet); + shelfMaterialDetailDO.setTotalGrossWeight(newAlreadyGross); + shelfMaterialDetailDO.setTotalVolume(newAlreadyVol); + shelfMaterialDetailDO.setTotalArea(newAlreadyArea); + } //记录本次上架单上架总数 totalActualQuantity = totalActualQuantity.add(actualQuantity); //判断上架数量是否大于计划数量 diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/inventoryAdjustmentRecord/entity/InventoryAdjustmentRecord.java b/mhd_wms/src/main/java/com/mhd/wms/domain/inventoryAdjustmentRecord/entity/InventoryAdjustmentRecord.java index 4a5c18caf..7f2fa8c8e 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/inventoryAdjustmentRecord/entity/InventoryAdjustmentRecord.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/inventoryAdjustmentRecord/entity/InventoryAdjustmentRecord.java @@ -188,4 +188,12 @@ public class InventoryAdjustmentRecord extends BaseVOEntity { @Excel(name = "调整后面积") private BigDecimal adjustedArea; + @ApiModelProperty("入库单号") + @Excel(name = "入库单号") + private String inOrderNumber; + + @ApiModelProperty("LOT编号") + @Excel(name = "LOT编号") + private String lotNumber; + } \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/inventoryAdjustmentRecord/repository/po/InventoryAdjustmentRecordPO.java b/mhd_wms/src/main/java/com/mhd/wms/domain/inventoryAdjustmentRecord/repository/po/InventoryAdjustmentRecordPO.java index 7d2ee9697..da2a626a4 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/inventoryAdjustmentRecord/repository/po/InventoryAdjustmentRecordPO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/inventoryAdjustmentRecord/repository/po/InventoryAdjustmentRecordPO.java @@ -244,4 +244,12 @@ public class InventoryAdjustmentRecordPO extends BaseVOEntity { @ApiModelProperty("调整后面积") @Excel(name = "调整后面积") private BigDecimal adjustedArea; + + @ApiModelProperty("入库单号") + @Excel(name = "入库单号") + private String inOrderNumber; + + @ApiModelProperty("LOT编号") + @Excel(name = "LOT编号") + private String LotNumber; } \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/entity/MaterialInventory.java b/mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/entity/MaterialInventory.java index ccaae3094..74315ea9e 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/entity/MaterialInventory.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/entity/MaterialInventory.java @@ -227,4 +227,13 @@ public class MaterialInventory extends BaseVOEntity { @ApiModelProperty("条码") @Excel(name = "条码") private String barCode; + + @ApiModelProperty("入库单号") + @Excel(name = "入库单号") + private String inOrderNumber; + + @ApiModelProperty("LOT编号") + @Excel(name = "LOT编号") + private String lotNumber; + } \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/repository/persistence/MaterialInventoryImpl.java b/mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/repository/persistence/MaterialInventoryImpl.java index 792cbe8cf..8ef49d33a 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/repository/persistence/MaterialInventoryImpl.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/repository/persistence/MaterialInventoryImpl.java @@ -269,7 +269,9 @@ public class MaterialInventoryImpl extends ServiceImpl shelfMaterialDetailList = new ArrayList<>(); // 批量新增序列号 @@ -326,11 +327,21 @@ public class ShelfMaterialDetailImpl extends ServiceImpl shiftMoveMaterialQuantityList; diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/shiftMaterialDetail/repository/persistence/ShiftMaterialDetailImpl.java b/mhd_wms/src/main/java/com/mhd/wms/domain/shiftMaterialDetail/repository/persistence/ShiftMaterialDetailImpl.java index 5337fde55..b1b4b7273 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/shiftMaterialDetail/repository/persistence/ShiftMaterialDetailImpl.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/shiftMaterialDetail/repository/persistence/ShiftMaterialDetailImpl.java @@ -729,6 +729,8 @@ public class ShiftMaterialDetailImpl extends ServiceImpl children; diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/shiftMaterialDetail/repository/todo/ShiftMaterialDetailDO.java b/mhd_wms/src/main/java/com/mhd/wms/domain/shiftMaterialDetail/repository/todo/ShiftMaterialDetailDO.java index ac9748f99..f726ab51b 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/shiftMaterialDetail/repository/todo/ShiftMaterialDetailDO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/shiftMaterialDetail/repository/todo/ShiftMaterialDetailDO.java @@ -273,6 +273,14 @@ public class ShiftMaterialDetailDO extends BaseVOEntity { @ApiModelProperty("总面积(SQM),PDA 表单区修改后回传") private BigDecimal totalArea; + @ApiModelProperty("入库单号") + @Excel(name = "入库单号") + private String inOrderNumber; + + @ApiModelProperty("LOT编号") + @Excel(name = "LOT编号") + private String lotNumber; + @ApiModelProperty("移位详情") @TableField(exist = false) private List children; diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/statementStatistics/po/ImmediateInventoryPO.java b/mhd_wms/src/main/java/com/mhd/wms/domain/statementStatistics/po/ImmediateInventoryPO.java index 308904562..a3885172a 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/statementStatistics/po/ImmediateInventoryPO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/statementStatistics/po/ImmediateInventoryPO.java @@ -127,4 +127,11 @@ public class ImmediateInventoryPO { @ApiModelProperty("批次号") private String batchNumber; + @ApiModelProperty("入库单号") + @Excel(name = "入库单号") + private String inOrderNumber; + + @ApiModelProperty("LOT编号") + @Excel(name = "LOT编号") + private String lotNumber; } \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/stockInOrder/service/StockInOrderDomainService.java b/mhd_wms/src/main/java/com/mhd/wms/domain/stockInOrder/service/StockInOrderDomainService.java index f1d320bb4..a815bea3b 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/stockInOrder/service/StockInOrderDomainService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/stockInOrder/service/StockInOrderDomainService.java @@ -259,7 +259,7 @@ public class StockInOrderDomainService { } } - // 填充入库单明细的收货数量、上架数量,以及更新毛重、净重、面积、体积 + // 填充入库单明细的收货数量、上架数量;入库单明细 total* 保持计划值不因收货覆盖(原按收货汇总 total* 已注释保留) for (InMaterialDetailPO inMaterialDetail : inMaterialDetailPOList) { Long materialDetailId = inMaterialDetail.getMaterialDetailId(); if (materialDetailId != null) { @@ -273,18 +273,18 @@ public class StockInOrderDomainService { // 更新毛重、净重、面积、体积(根据收货时所填的明细行数据更新到入库单明细中) // 将收货单明细中填写的数据汇总后更新到入库单明细 - if (receiptDetail.getTotalGrossWeight() != null) { - inMaterialDetail.setTotalGrossWeight(receiptDetail.getTotalGrossWeight()); - } - if (receiptDetail.getTotalNetWeight() != null) { - inMaterialDetail.setTotalNetWeight(receiptDetail.getTotalNetWeight()); - } - if (receiptDetail.getTotalArea() != null) { - inMaterialDetail.setTotalArea(receiptDetail.getTotalArea()); - } - if (receiptDetail.getTotalVolume() != null) { - inMaterialDetail.setTotalVolume(receiptDetail.getTotalVolume()); - } +// if (receiptDetail.getTotalGrossWeight() != null) { +// inMaterialDetail.setTotalGrossWeight(receiptDetail.getTotalGrossWeight()); +// } +// if (receiptDetail.getTotalNetWeight() != null) { +// inMaterialDetail.setTotalNetWeight(receiptDetail.getTotalNetWeight()); +// } +// if (receiptDetail.getTotalArea() != null) { +// inMaterialDetail.setTotalArea(receiptDetail.getTotalArea()); +// } +// if (receiptDetail.getTotalVolume() != null) { +// inMaterialDetail.setTotalVolume(receiptDetail.getTotalVolume()); +// } } // 填充上架数量(入库单对应的上架单实际上架数量) @@ -301,7 +301,7 @@ public class StockInOrderDomainService { } /** - * 递归处理收货单明细,汇总毛重、净重、面积、体积 + * 递归处理收货单明细,汇总收货数量;毛重/净重/面积/体积汇总已注释(入库单明细 total* 不因收货覆盖) * @param receiptDetail 收货单明细 * @param receiptDetailMap 收货单明细汇总Map */ @@ -323,23 +323,23 @@ public class StockInOrderDomainService { BigDecimal newReceiptQuantity = receiptDetail.getReceiptQuantity() != null ? receiptDetail.getReceiptQuantity() : BigDecimal.ZERO; existing.setReceiptQuantity(receiptQuantity.add(newReceiptQuantity)); - // 汇总毛重、净重、面积、体积(根据收货时填写的数据) + // 汇总毛重、净重、面积、体积(根据收货时填写的数据)— 入库单明细 total* 不因收货覆盖,已注释保留 // 累加所有收货单明细的毛重、净重、面积、体积 - BigDecimal existingGrossWeight = existing.getTotalGrossWeight() != null ? existing.getTotalGrossWeight() : BigDecimal.ZERO; - BigDecimal newGrossWeight = receiptDetail.getTotalGrossWeight() != null ? receiptDetail.getTotalGrossWeight() : BigDecimal.ZERO; - existing.setTotalGrossWeight(existingGrossWeight.add(newGrossWeight)); - - BigDecimal existingNetWeight = existing.getTotalNetWeight() != null ? existing.getTotalNetWeight() : BigDecimal.ZERO; - BigDecimal newNetWeight = receiptDetail.getTotalNetWeight() != null ? receiptDetail.getTotalNetWeight() : BigDecimal.ZERO; - existing.setTotalNetWeight(existingNetWeight.add(newNetWeight)); - - BigDecimal existingArea = existing.getTotalArea() != null ? existing.getTotalArea() : BigDecimal.ZERO; - BigDecimal newArea = receiptDetail.getTotalArea() != null ? receiptDetail.getTotalArea() : BigDecimal.ZERO; - existing.setTotalArea(existingArea.add(newArea)); - - BigDecimal existingVolume = existing.getTotalVolume() != null ? existing.getTotalVolume() : BigDecimal.ZERO; - BigDecimal newVolume = receiptDetail.getTotalVolume() != null ? receiptDetail.getTotalVolume() : BigDecimal.ZERO; - existing.setTotalVolume(existingVolume.add(newVolume)); +// BigDecimal existingGrossWeight = existing.getTotalGrossWeight() != null ? existing.getTotalGrossWeight() : BigDecimal.ZERO; +// BigDecimal newGrossWeight = receiptDetail.getTotalGrossWeight() != null ? receiptDetail.getTotalGrossWeight() : BigDecimal.ZERO; +// existing.setTotalGrossWeight(existingGrossWeight.add(newGrossWeight)); +// +// BigDecimal existingNetWeight = existing.getTotalNetWeight() != null ? existing.getTotalNetWeight() : BigDecimal.ZERO; +// BigDecimal newNetWeight = receiptDetail.getTotalNetWeight() != null ? receiptDetail.getTotalNetWeight() : BigDecimal.ZERO; +// existing.setTotalNetWeight(existingNetWeight.add(newNetWeight)); +// +// BigDecimal existingArea = existing.getTotalArea() != null ? existing.getTotalArea() : BigDecimal.ZERO; +// BigDecimal newArea = receiptDetail.getTotalArea() != null ? receiptDetail.getTotalArea() : BigDecimal.ZERO; +// existing.setTotalArea(existingArea.add(newArea)); +// +// BigDecimal existingVolume = existing.getTotalVolume() != null ? existing.getTotalVolume() : BigDecimal.ZERO; +// BigDecimal newVolume = receiptDetail.getTotalVolume() != null ? receiptDetail.getTotalVolume() : BigDecimal.ZERO; +// existing.setTotalVolume(existingVolume.add(newVolume)); } // 递归处理子明细 diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/stockReceiptOrder/service/StockReceiptOrderDomainService.java b/mhd_wms/src/main/java/com/mhd/wms/domain/stockReceiptOrder/service/StockReceiptOrderDomainService.java index 24df63599..e66c27f13 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/stockReceiptOrder/service/StockReceiptOrderDomainService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/stockReceiptOrder/service/StockReceiptOrderDomainService.java @@ -404,7 +404,7 @@ public class StockReceiptOrderDomainService { genInventoryStandingReport(stockReceiptOrderPO, stockReceiptOrderDO); //修改物料明细信息 receiptMaterialDetailService.batchReceiptUpdate(stockReceiptOrderDO); - //同步更新入库单明细的收货数量、总毛重、总净重、总面积、总体积 + // 同步更新入库单明细的收货数量(入库单 totalNetWeight/totalGrossWeight/totalVolume/totalArea 不因收货改库,见 sync 内注释) syncUpdateInMaterialDetailFromReceipt(stockReceiptOrderDO, stockReceiptOrderPO); //生成 收货作业单 genStockReceiptTaskOrderByReceivingGoods(stockReceiptOrderPO,stockReceiptOrderDO); @@ -419,8 +419,8 @@ public class StockReceiptOrderDomainService { } /** - * 同步更新入库单明细的收货数量、总毛重、总净重、总面积、总体积 - * 根据收货单明细中填写的数据,按materialDetailId分组汇总后更新到入库单明细 + * 同步更新入库单明细的收货数量(总毛重/总净重/总面积/总体积不再写入入库单明细,逻辑已注释保留) + * 根据收货单明细中填写的数据,按 materialDetailId 分组汇总后更新到入库单明细 * @param stockReceiptOrderDO 收货单DO * @param stockReceiptOrderPO 收货单PO(可选,如果为null则从DO中获取) */ @@ -511,29 +511,26 @@ public class StockReceiptOrderDomainService { hasUpdate = true; } - // 更新总毛重 - if (summary.containsKey("totalGrossWeight") && summary.get("totalGrossWeight") != null) { - updateWrapper.set("total_gross_weight", summary.get("totalGrossWeight")); - hasUpdate = true; - } - - // 更新总净重 - if (summary.containsKey("totalNetWeight") && summary.get("totalNetWeight") != null) { - updateWrapper.set("total_net_weight", summary.get("totalNetWeight")); - hasUpdate = true; - } - - // 更新总面积 - if (summary.containsKey("totalArea") && summary.get("totalArea") != null) { - updateWrapper.set("total_area", summary.get("totalArea")); - hasUpdate = true; - } - - // 更新总体积 - if (summary.containsKey("totalVolume") && summary.get("totalVolume") != null) { - updateWrapper.set("total_volume", summary.get("totalVolume")); - hasUpdate = true; - } + // 更新总毛重/总净重/总面积/总体积:入库单明细保持计划值,收货实绩仅在收货单侧,此处不再改库(原逻辑保留如下) +// if (summary.containsKey("totalGrossWeight") && summary.get("totalGrossWeight") != null) { +// updateWrapper.set("total_gross_weight", summary.get("totalGrossWeight")); +// hasUpdate = true; +// } +// +// if (summary.containsKey("totalNetWeight") && summary.get("totalNetWeight") != null) { +// updateWrapper.set("total_net_weight", summary.get("totalNetWeight")); +// hasUpdate = true; +// } +// +// if (summary.containsKey("totalArea") && summary.get("totalArea") != null) { +// updateWrapper.set("total_area", summary.get("totalArea")); +// hasUpdate = true; +// } +// +// if (summary.containsKey("totalVolume") && summary.get("totalVolume") != null) { +// updateWrapper.set("total_volume", summary.get("totalVolume")); +// hasUpdate = true; +// } if (hasUpdate) { updateWrapper.set("update_by", loginUser.getUserid()); @@ -541,13 +538,9 @@ public class StockReceiptOrderDomainService { updateWrapper.set("update_time", updateTime); boolean updateResult = iInMaterialDetailService.update(updateWrapper); if (updateResult) { - log.info("成功更新入库单明细,uniqueId: {}, 收货数量: {}, 总毛重: {}, 总净重: {}, 总面积: {}, 总体积: {}", + log.info("成功更新入库单明细,uniqueId: {}, 收货数量: {}(入库单 total* 不再随收货同步)", uniqueId, - summary.get("receiptQuantity"), - summary.get("totalGrossWeight"), - summary.get("totalNetWeight"), - summary.get("totalArea"), - summary.get("totalVolume")); + summary.get("receiptQuantity")); } else { log.warn("更新入库单明细失败,uniqueId: {}, inOrderNumber: {}", uniqueId, inOrderNumber); } @@ -562,7 +555,7 @@ public class StockReceiptOrderDomainService { } /** - * 递归处理收货单明细,汇总收货数量、总毛重、总净重、总面积、总体积 + * 递归处理收货单明细,汇总收货数量(总毛重/净重/面积/体积的汇总已注释,不再写入入库单) * @param receiptDetail 收货单明细PO * @param uniqueIdSummaryMap 汇总Map,key为入库单明细的unique_id(即收货单明细的in_unique_id),value为字段汇总Map */ @@ -576,30 +569,36 @@ public class StockReceiptOrderDomainService { Long uniqueId = receiptDetail.getInUniqueId(); Map summary = uniqueIdSummaryMap.computeIfAbsent(uniqueId, k -> new HashMap<>()); - // 汇总收货数量 + // 汇总收货数量:必须按「累计已收货」汇总。receipt_quantity 字段存的是本次收货量,多次收货会覆盖为最后一次; + // 同步入库单明细应使用 already_receipt_quantity,否则会误把最后一次的本次量写入 in_material_detail。 BigDecimal receiptQuantity = summary.getOrDefault("receiptQuantity", BigDecimal.ZERO); - BigDecimal newReceiptQuantity = receiptDetail.getReceiptQuantity() != null ? receiptDetail.getReceiptQuantity() : BigDecimal.ZERO; - summary.put("receiptQuantity", receiptQuantity.add(newReceiptQuantity)); + BigDecimal alreadyReceipt = receiptDetail.getAlreadyReceiptQuantity() != null ? receiptDetail.getAlreadyReceiptQuantity() : BigDecimal.ZERO; + summary.put("receiptQuantity", receiptQuantity.add(alreadyReceipt)); - // 汇总总毛重 - BigDecimal totalGrossWeight = summary.getOrDefault("totalGrossWeight", BigDecimal.ZERO); - BigDecimal newGrossWeight = receiptDetail.getTotalGrossWeight() != null ? receiptDetail.getTotalGrossWeight() : BigDecimal.ZERO; - summary.put("totalGrossWeight", totalGrossWeight.add(newGrossWeight)); - - // 汇总总净重 - BigDecimal totalNetWeight = summary.getOrDefault("totalNetWeight", BigDecimal.ZERO); - BigDecimal newNetWeight = receiptDetail.getTotalNetWeight() != null ? receiptDetail.getTotalNetWeight() : BigDecimal.ZERO; - summary.put("totalNetWeight", totalNetWeight.add(newNetWeight)); - - // 汇总总面积 - BigDecimal totalArea = summary.getOrDefault("totalArea", BigDecimal.ZERO); - BigDecimal newArea = receiptDetail.getTotalArea() != null ? receiptDetail.getTotalArea() : BigDecimal.ZERO; - summary.put("totalArea", totalArea.add(newArea)); - - // 汇总总体积 - BigDecimal totalVolume = summary.getOrDefault("totalVolume", BigDecimal.ZERO); - BigDecimal newVolume = receiptDetail.getTotalVolume() != null ? receiptDetail.getTotalVolume() : BigDecimal.ZERO; - summary.put("totalVolume", totalVolume.add(newVolume)); + // 汇总总毛重/净重/面积/体积:曾用于同步写入入库单明细,现已不再改入库单 total*,汇总逻辑注释保留 +// BigDecimal totalGrossWeight = summary.getOrDefault("totalGrossWeight", BigDecimal.ZERO); +// BigDecimal newGrossWeight = receiptDetail.getAlreadyReceiptGrossWeight() != null +// ? receiptDetail.getAlreadyReceiptGrossWeight() +// : (receiptDetail.getTotalGrossWeight() != null ? receiptDetail.getTotalGrossWeight() : BigDecimal.ZERO); +// summary.put("totalGrossWeight", totalGrossWeight.add(newGrossWeight)); +// +// BigDecimal totalNetWeight = summary.getOrDefault("totalNetWeight", BigDecimal.ZERO); +// BigDecimal newNetWeight = receiptDetail.getAlreadyReceiptNetWeight() != null +// ? receiptDetail.getAlreadyReceiptNetWeight() +// : (receiptDetail.getTotalNetWeight() != null ? receiptDetail.getTotalNetWeight() : BigDecimal.ZERO); +// summary.put("totalNetWeight", totalNetWeight.add(newNetWeight)); +// +// BigDecimal totalArea = summary.getOrDefault("totalArea", BigDecimal.ZERO); +// BigDecimal newArea = receiptDetail.getAlreadyReceiptArea() != null +// ? receiptDetail.getAlreadyReceiptArea() +// : (receiptDetail.getTotalArea() != null ? receiptDetail.getTotalArea() : BigDecimal.ZERO); +// summary.put("totalArea", totalArea.add(newArea)); +// +// BigDecimal totalVolume = summary.getOrDefault("totalVolume", BigDecimal.ZERO); +// BigDecimal newVolume = receiptDetail.getAlreadyReceiptVolume() != null +// ? receiptDetail.getAlreadyReceiptVolume() +// : (receiptDetail.getTotalVolume() != null ? receiptDetail.getTotalVolume() : BigDecimal.ZERO); +// summary.put("totalVolume", totalVolume.add(newVolume)); // 递归处理子明细 if (!CollectionUtils.isEmpty(receiptDetail.getChildren())) { @@ -712,6 +711,8 @@ public class StockReceiptOrderDomainService { if (abnormal == 1){ genInOrderAbnormal(stockReceiptOrderPO); } + // 完成收货:同步更新本单全部明细收货状态(与整单收货 entireReceipt 一致,否则 PDA/列表仍显示收货中) + updateReceiptMaterialDetailReceiptStatusWhenOrderCompleted(stockReceiptOrderPO, loginUser, userRealName); return stockReceiptOrderService.update(null, new UpdateWrapper().lambda() .set(StockReceiptOrder::getStatus, 3) .set(StockReceiptOrder::getAbnormal, abnormal) @@ -721,6 +722,45 @@ public class StockReceiptOrderDomainService { .eq(StockReceiptOrder::getReceiptOrderId, receiptOrderId)); } + /** + * 收货单完成时:按累计已收与计划数量比较,更新明细 receipt_status(3 正常收完 / 4 少收 / 5 超收) + */ + private void updateReceiptMaterialDetailReceiptStatusWhenOrderCompleted(StockReceiptOrderPO stockReceiptOrderPO, + LoginUser loginUser, String userRealName) { + if (stockReceiptOrderPO == null || StringUtils.isBlank(stockReceiptOrderPO.getReceiptOrderNumber())) { + return; + } + Date updateTime = new Date(); + List details = receiptMaterialDetailService.list( + new QueryWrapper().lambda() + .eq(ReceiptMaterialDetail::getReceiptOrderNumber, stockReceiptOrderPO.getReceiptOrderNumber()) + .eq(ReceiptMaterialDetail::getDelFlag, 1)); + if (CollectionUtils.isEmpty(details)) { + return; + } + for (ReceiptMaterialDetail d : details) { + d.setReceiptStatus(resolveReceiptDetailStatusOnOrderComplete(d.getAlreadyReceiptQuantity(), d.getQuantity())); + d.setUpdateBy(loginUser.getUserid()); + d.setUpdateByName(userRealName); + d.setUpdateTime(updateTime); + } + receiptMaterialDetailService.updateBatchById(details); + } + + /** 3=已收足 4=少收 5=超收 */ + private static Integer resolveReceiptDetailStatusOnOrderComplete(BigDecimal alreadyReceiptQuantity, BigDecimal quantity) { + BigDecimal already = alreadyReceiptQuantity != null ? alreadyReceiptQuantity : BigDecimal.ZERO; + BigDecimal plan = quantity != null ? quantity : BigDecimal.ZERO; + int cmp = already.compareTo(plan); + if (cmp > 0) { + return 5; + } + if (cmp < 0) { + return 4; + } + return 3; + } + /** * @param receiptOrderId * @return Boolean diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/stockShelfOrder/service/StockShelfOrderDomainService.java b/mhd_wms/src/main/java/com/mhd/wms/domain/stockShelfOrder/service/StockShelfOrderDomainService.java index 026122a87..af1fcd521 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/stockShelfOrder/service/StockShelfOrderDomainService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/stockShelfOrder/service/StockShelfOrderDomainService.java @@ -649,12 +649,14 @@ public class StockShelfOrderDomainService { .collect(Collectors.toList()); } Long shipperId = stockReceiptOrderDO.getShipperId(); - MaterialInventory param = getParam(shelfMaterialDetail, fieldNames, shipperId); + MaterialInventory param = getParam(shelfMaterialDetail, fieldNames, shipperId,stockReceiptOrderDO.getInOrderNumber()); List materialInventoryPOS = materialInventoryMapper.selectListByWhere(param); MaterialBaseInfo materialBaseInfo = materialBaseInfoMapper.selectById(materialBaseInfoId); LoginUser loginUser = SecurityUtils.getLoginUser(); if (materialInventoryPOS.size() == 0) { MaterialInventory materialInventory = new MaterialInventory(); + materialInventory.setInOrderNumber(stockReceiptOrderDO.getInOrderNumber()); + materialInventory.setLotNumber(shelfMaterialDetail.getLotNumber()); //仓库信息 materialInventory.setWarehouseId(stockReceiptOrderDO.getWarehouseId()); materialInventory.setWarehouseCode(stockReceiptOrderDO.getWarehouseCode()); @@ -733,6 +735,8 @@ public class StockShelfOrderDomainService { //库存调整记录 InventoryAdjustmentRecord inventoryAdjustmentRecord = new InventoryAdjustmentRecord(); + inventoryAdjustmentRecord.setInOrderNumber(stockReceiptOrderDO.getInOrderNumber()); + inventoryAdjustmentRecord.setLotNumber(shelfMaterialDetail.getLotNumber()); inventoryAdjustmentRecord.setAdjustAction("入库"); inventoryAdjustmentRecord.setRelateNo(stockReceiptOrderDO.getInOrderNumber()); inventoryAdjustmentRecord.setAdjustAfterStatusCode(materialInventory.getMaterialStatusCode() == null ? "" : materialInventory.getMaterialStatusCode()); @@ -802,6 +806,9 @@ public class StockShelfOrderDomainService { inventoryAdjustmentRecordMapper.insert(inventoryAdjustmentRecord); } else if (materialInventoryPOS.size() == 1) { MaterialInventory materialInventory = new MaterialInventory(); + materialInventory.setInOrderNumber(stockReceiptOrderDO.getInOrderNumber()); + materialInventory.setLotNumber(shelfMaterialDetail.getLotNumber()); + BigDecimal shelvesQuantity = shelfMaterialDetail.getShelvesQuantity(); shelvesQuantity = shelvesQuantity != null ? shelvesQuantity : BigDecimal.ZERO; MaterialInventoryPO materialInventoryPO = materialInventoryPOS.get(0); @@ -869,6 +876,8 @@ public class StockShelfOrderDomainService { InventoryAdjustmentRecord inventoryAdjustmentRecord = new InventoryAdjustmentRecord(); + inventoryAdjustmentRecord.setInOrderNumber(stockReceiptOrderDO.getInOrderNumber()); + inventoryAdjustmentRecord.setLotNumber(shelfMaterialDetail.getLotNumber()); inventoryAdjustmentRecord.setAdjustAction("入库"); inventoryAdjustmentRecord.setRelateNo(stockReceiptOrderDO.getInOrderNumber()); inventoryAdjustmentRecord.setAdjustAfterStatusCode(materialInventory.getMaterialStatusCode() == null ? "" : materialInventory.getMaterialStatusCode()); @@ -923,7 +932,7 @@ public class StockShelfOrderDomainService { } } - private MaterialInventory getParam(ShelfMaterialDetail shelfMaterialDetail, List fieldNames,Long shipperId){ + private MaterialInventory getParam(ShelfMaterialDetail shelfMaterialDetail, List fieldNames,Long shipperId,String inOrderNumber){ MaterialInventory param = new MaterialInventory(); param.setShipperId(shipperId); param.setWarehouseId(shelfMaterialDetail.getWarehouseId()); @@ -932,6 +941,8 @@ public class StockShelfOrderDomainService { param.setStorageLocationId(shelfMaterialDetail.getStorageLocationId()); param.setOrganizationId(shelfMaterialDetail.getOrganizationId()); param.setBatchNumber(shelfMaterialDetail.getBatchNumber()); + param.setLotNumber(shelfMaterialDetail.getLotNumber()); + param.setInOrderNumber(inOrderNumber); if (fieldNames.size() > 0) { for (String fieldName : fieldNames) { switch (fieldName) { diff --git a/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/receiptMaterialDetail/ReceiptMaterialDetailDTO.java b/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/receiptMaterialDetail/ReceiptMaterialDetailDTO.java index 883f03844..9c3f3c771 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/receiptMaterialDetail/ReceiptMaterialDetailDTO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/receiptMaterialDetail/ReceiptMaterialDetailDTO.java @@ -73,6 +73,30 @@ public class ReceiptMaterialDetailDTO extends BaseVOEntity { @Excel(name = "已收货数量") private BigDecimal alreadyReceiptQuantity; + @ApiModelProperty("累计已收货毛重(KG),称重实绩") + private BigDecimal alreadyReceiptGrossWeight; + + @ApiModelProperty("累计已收货净重(KG)") + private BigDecimal alreadyReceiptNetWeight; + + @ApiModelProperty("本次称重毛重(KG),仅提交请求使用,不落库") + private BigDecimal receiptGrossWeight; + + @ApiModelProperty("本次净重(KG),仅提交请求使用,不落库") + private BigDecimal receiptNetWeight; + + @ApiModelProperty("累计已收货体积(CBM)") + private BigDecimal alreadyReceiptVolume; + + @ApiModelProperty("累计已收货面积(SQM)") + private BigDecimal alreadyReceiptArea; + + @ApiModelProperty("本次体积(CBM),仅提交请求使用,不落库") + private BigDecimal receiptVolume; + + @ApiModelProperty("本次面积(SQM),仅提交请求使用,不落库") + private BigDecimal receiptArea; + @ApiModelProperty("收货数量") @Excel(name = "收货数量") private BigDecimal receiptQuantity; diff --git a/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApp/stockReceiptOrder/StockReceiptOrderAppApi.java b/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApp/stockReceiptOrder/StockReceiptOrderAppApi.java index c416da82d..f4fde3d96 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApp/stockReceiptOrder/StockReceiptOrderAppApi.java +++ b/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApp/stockReceiptOrder/StockReceiptOrderAppApi.java @@ -1,6 +1,6 @@ package com.mhd.wms.interfaces.facadeApp.stockReceiptOrder; -import cn.hutool.json.JSONUtil; +import com.fasterxml.jackson.databind.ObjectMapper; import com.mhd.common.core.web.controller.BaseController; import com.mhd.common.core.web.domain.AjaxResult; import com.mhd.common.core.web.page.TableDataInfoApi; @@ -11,6 +11,7 @@ import com.mhd.wms.domain.stockReceiptOrder.repository.todo.StockReceiptOrderDO; import com.mhd.wms.interfaces.assember.stockReceiptOrder.StockReceiptOrderAssembler; import com.mhd.wms.interfaces.dto.stockReceiptOrder.StockReceiptOrderDTO; import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @@ -32,6 +33,9 @@ public class StockReceiptOrderAppApi extends BaseController { @Resource private StockReceiptOrderAssembler stockReceiptOrderAssembler; + @Autowired + private ObjectMapper objectMapper; + /** * 分页查询收货单列表 */ @@ -51,8 +55,10 @@ public class StockReceiptOrderAppApi extends BaseController { */ @ApiOperation("获取收货单详细信息") @GetMapping(value = "/getInfoByApp") - public AjaxResult getInfoByApp(@RequestParam Long receiptOrderId, - @RequestParam(required = false) Integer receiptStatus) { + public AjaxResult getInfoByApp( + @ApiParam(value = "收货单ID", required = true) @RequestParam Long receiptOrderId, + @ApiParam(value = "明细筛选:1=待收货(仅状态1待收货、2收货中);3=已收货(仅3已收货、4少收、5超收)") + @RequestParam(required = false) Integer receiptStatus) { return AjaxResult.success(stockReceiptOrderApplicationService.getInfoByApp(receiptOrderId, receiptStatus)); } @@ -62,7 +68,8 @@ public class StockReceiptOrderAppApi extends BaseController { @ApiOperation("收货") @PostMapping("/receivingGoods") public AjaxResult receivingGoods(@RequestBody StockReceiptOrderDTO stockReceiptOrderDTO) { - StockReceiptOrderDO stockReceiptOrderDO = JSONUtil.toBean(JSONUtil.toJsonStr(stockReceiptOrderDTO), StockReceiptOrderDO.class); + // 勿用 Hutool JSON 往返转 DO:嵌套 children、receiptGrossWeight/receiptNetWeight/receiptVolume/receiptArea 等会丢失或类型不对,导致累计未落库 + StockReceiptOrderDO stockReceiptOrderDO = objectMapper.convertValue(stockReceiptOrderDTO, StockReceiptOrderDO.class); return toAjax(stockReceiptOrderApplicationService.receivingGoodsByApp(stockReceiptOrderDO)); } @@ -87,7 +94,7 @@ public class StockReceiptOrderAppApi extends BaseController { @ApiOperation("无单收货") @PostMapping("/noOrderReceipt") public AjaxResult noOrderReceipt(@RequestBody StockReceiptOrderDTO stockReceiptOrderDTO) { - StockReceiptOrderDO stockReceiptOrderDO = JSONUtil.toBean(JSONUtil.toJsonStr(stockReceiptOrderDTO), StockReceiptOrderDO.class); + StockReceiptOrderDO stockReceiptOrderDO = objectMapper.convertValue(stockReceiptOrderDTO, StockReceiptOrderDO.class); return toAjax(stockReceiptOrderApplicationService.noOrderReceipt(stockReceiptOrderDO)); } diff --git a/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApp/stockShelfOrder/StockShelfOrderAppApi.java b/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApp/stockShelfOrder/StockShelfOrderAppApi.java index 4f82c804c..37e94a3a9 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApp/stockShelfOrder/StockShelfOrderAppApi.java +++ b/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApp/stockShelfOrder/StockShelfOrderAppApi.java @@ -51,9 +51,11 @@ public class StockShelfOrderAppApi extends BaseController { */ @ApiOperation("获取上架单") @GetMapping(value = "/getInfo") - public AjaxResult getInfo(Long shelfOrderId) + public AjaxResult getInfo(Long shelfOrderId, + @RequestParam(required = false) Integer shelfStatus) { - return AjaxResult.success(stockShelfOrderApplicationService.getInfo(shelfOrderId, true)); + // 仅 PDA 支持根据明细 shelvesStatus 做筛选:1 待上架(仅1/2),3 已上架(3/4/5) + return AjaxResult.success(stockShelfOrderApplicationService.getInfo(shelfOrderId, true, shelfStatus)); } diff --git a/mhd_wms/src/main/resources/mapper/inMaterialDetail/InMaterialDetailMapper.xml b/mhd_wms/src/main/resources/mapper/inMaterialDetail/InMaterialDetailMapper.xml index bf31d0b9a..6eabf50d2 100644 --- a/mhd_wms/src/main/resources/mapper/inMaterialDetail/InMaterialDetailMapper.xml +++ b/mhd_wms/src/main/resources/mapper/inMaterialDetail/InMaterialDetailMapper.xml @@ -9,6 +9,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + diff --git a/mhd_wms/src/main/resources/mapper/inventoryAdjustmentRecord/InventoryAdjustmentRecordMapper.xml b/mhd_wms/src/main/resources/mapper/inventoryAdjustmentRecord/InventoryAdjustmentRecordMapper.xml index 0917626e5..f6058d1d8 100644 --- a/mhd_wms/src/main/resources/mapper/inventoryAdjustmentRecord/InventoryAdjustmentRecordMapper.xml +++ b/mhd_wms/src/main/resources/mapper/inventoryAdjustmentRecord/InventoryAdjustmentRecordMapper.xml @@ -56,6 +56,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + @@ -77,7 +79,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" a.adjusted_area, b.ext_attr_1, b.ext_attr_2, b.ext_attr_3, b.ext_attr_4, b.production_date, b.expiry_date, b.inventory_date, - b.batch_ref_no, b.sheet_ref_no, b.box_pallet_no,a.ADJUST_ACTION,a.RELATE_NO + b.batch_ref_no, b.sheet_ref_no, b.box_pallet_no,a.ADJUST_ACTION,a.RELATE_NO, + a.in_order_number,a.lot_number from inventory_adjustment_record a left join material_inventory b on a.material_inventory_id = b.material_inventory_id where a.del_flag = 1 diff --git a/mhd_wms/src/main/resources/mapper/materialInventory/MaterialInventoryMapper.xml b/mhd_wms/src/main/resources/mapper/materialInventory/MaterialInventoryMapper.xml index db8246c98..124b47725 100644 --- a/mhd_wms/src/main/resources/mapper/materialInventory/MaterialInventoryMapper.xml +++ b/mhd_wms/src/main/resources/mapper/materialInventory/MaterialInventoryMapper.xml @@ -62,6 +62,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + @@ -83,7 +85,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" a.ext_attr_1, a.ext_attr_2, a.ext_attr_3, a.ext_attr_4, a.production_date, a.expiry_date, a.inventory_date, a.BATCH_REF_NO, a.SHEET_REF_NO, a.BOX_PALLET_NO,nvl(a.unit_name,b.unit_name) as unit_name, - a.bar_code as inv_bar_code + a.bar_code as inv_bar_code, + a.in_order_number,a.lot_number @@ -530,6 +533,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + +