diff --git a/mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/domain/dto/nc/SKitem.java b/mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/domain/dto/nc/SKitem.java index 9794a8474..a6b024cc4 100644 --- a/mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/domain/dto/nc/SKitem.java +++ b/mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/domain/dto/nc/SKitem.java @@ -70,4 +70,6 @@ public class SKitem { @ApiModelProperty( "") private String def75; + @ApiModelProperty( "费用科目") + private String def29; } \ No newline at end of file diff --git a/mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/domain/dto/nc/Ysitem.java b/mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/domain/dto/nc/Ysitem.java index fe7ef23b3..591674a1c 100644 --- a/mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/domain/dto/nc/Ysitem.java +++ b/mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/domain/dto/nc/Ysitem.java @@ -83,8 +83,8 @@ public class Ysitem { @ApiModelProperty( "") private String def75; -// @ApiModelProperty( "") -// private String def29; + @ApiModelProperty( "费用类型") + private String def29; //税率id private String taxcodeid; diff --git a/mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/domain/dto/wlhy/TmsOrderAddDTO.java b/mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/domain/dto/wlhy/TmsOrderAddDTO.java index 2eb4f9834..6ad5c72a7 100644 --- a/mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/domain/dto/wlhy/TmsOrderAddDTO.java +++ b/mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/domain/dto/wlhy/TmsOrderAddDTO.java @@ -473,4 +473,7 @@ TmsOrderAddDTO implements Serializable { @ApiModelProperty("执行单号") private String executeOrderNumber; + + @ApiModelProperty("订单来源 0,oms 1,tms") + private String orderSource; } diff --git a/mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/domain/po/UserPo.java b/mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/domain/po/UserPo.java index 8e2d71869..c801c53d7 100644 --- a/mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/domain/po/UserPo.java +++ b/mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/domain/po/UserPo.java @@ -250,4 +250,7 @@ public class UserPo { @ApiModelProperty("备注") private String remark; -} + + @ApiModelProperty("结算币种") + private String settlementCurrency; +} \ No newline at end of file diff --git a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/application/service/contractManage/ContractManageApplicationService.java b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/application/service/contractManage/ContractManageApplicationService.java index 816feef03..f22d0d317 100644 --- a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/application/service/contractManage/ContractManageApplicationService.java +++ b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/application/service/contractManage/ContractManageApplicationService.java @@ -129,111 +129,137 @@ public class ContractManageApplicationService { return contractManageDomainService.queryList(contractManageDO); } - public BigDecimal getAmount(List subjectAndPriceReturnList) { +// public BigDecimal getAmount(List subjectAndPriceReturnList) { +// if (subjectAndPriceReturnList == null || subjectAndPriceReturnList.size() == 1) { +// SubjectAndPriceReturn subjectAndPriceReturn = subjectAndPriceReturnList.get(0); +// Long billingRulesId = subjectAndPriceReturn.getBillingRulesId(); +// String name = subjectAndPriceReturn.getName(); +// BillingRulesPO billingRule = contractManageDetailMapper.getBillingRules(billingRulesId); +// List billingParams = contractManageDetailMapper.getBillingParams(billingRulesId); +// if (billingParams != null && billingParams.size() > 0) { +// BillingParamsPO billingParam = billingParams.get(0); +// String billingParamsJson = billingParam.getBillingParamsJson(); +// String preSetRules = billingParam.getPreSetRules(); +// List> preSetRulesList = JSON.parseObject(preSetRules, new TypeReference>>() { +// }); +// List> billingParamsList = JSON.parseObject(billingParamsJson, new TypeReference>>() { +// }); +// if (billingParamsList != null && billingParamsList.size() ==2) { +// Map targetMap = billingParamsList.stream() +// .filter(map -> name.equals(map.get("fieldsName"))) // 关键匹配条件 +// .findFirst() // 取第一个 +// .orElse(null); // 没找到返回null +// String chargingId = (String) targetMap.get("chargingId"); +// Integer sort = (Integer) targetMap.get("sort"); +// Map reles = preSetRulesList.get(0); +// String price = (String) reles.get("fields"+sort); +// String billingFormula = billingRule.getBillingFormula(); +// billingFormula = billingFormula.replace(chargingId, price); +// //需要判断阶梯类型进行获取各计费标志的取值,拼接公式 +// List billingParamsEntityList = JSON.parseArray(billingParamsJson, BillingParamsDetailDTO.class); +// //将计费参数实体分成两组,即:固定参数和条件参数 +// List fixedParamsEntityList = billingParamsEntityList.stream().filter(item -> ObjectUtil.equal(item.getLadderType(),1)).collect(Collectors.toList()); +// List ladderParamsEntityList = billingParamsEntityList.stream().filter(item -> !ObjectUtil.equal(item.getLadderType(),1)).collect(Collectors.toList()); +// if (fixedParamsEntityList != null && fixedParamsEntityList.size() > 0) { +// if (subjectAndPriceReturn.getNum() != null) { +// for (BillingParamsDetailDTO ladderParamsEntity : fixedParamsEntityList) { +// String chargingId1 = ladderParamsEntity.getChargingId(); +// if (chargingId1 != chargingId) { +// billingFormula = billingFormula.replace(chargingId1, subjectAndPriceReturn.getNum().toEngineeringString()); +// } +// } +// } +// } +// return DynamicCalculationUtil.calculate(billingFormula); +// } else { +// +// } +// } +// } else { +// SubjectAndPriceReturn aReturn = subjectAndPriceReturnList.get(0); +// Long id = aReturn.getBillingRulesId(); +// BillingRulesPO Rule = contractManageDetailMapper.getBillingRules(id); +// String billingFormula = Rule.getBillingFormula(); +// for (SubjectAndPriceReturn subjectAndPriceReturn : subjectAndPriceReturnList) { +// Long billingRulesId = subjectAndPriceReturn.getBillingRulesId(); +// String name = subjectAndPriceReturn.getName(); +// BillingRulesPO billingRule = contractManageDetailMapper.getBillingRules(billingRulesId); +// List billingParams = contractManageDetailMapper.getBillingParams(billingRulesId); +// if (billingParams != null && billingParams.size() > 0) { +// BillingParamsPO billingParam = billingParams.get(0); +// String billingParamsJson = billingParam.getBillingParamsJson(); +// String preSetRules = billingParam.getPreSetRules(); +// List> preSetRulesList = JSON.parseObject(preSetRules, new TypeReference>>() { +// }); +// List> billingParamsList = JSON.parseObject(billingParamsJson, new TypeReference>>() { +// }); +// if (billingParamsList != null && billingParamsList.size() ==2) { +// } else { +// Map targetMap = billingParamsList.stream() +// .filter(map -> name.equals(map.get("fieldsName"))) // 关键匹配条件 +// .findFirst() // 取第一个 +// .orElse(null); // 没找到返回null +// String chargingId = (String) targetMap.get("chargingId"); +// Integer sort = (Integer) targetMap.get("sort"); +// Map reles = preSetRulesList.get(0); +// String price = (String) reles.get("fields"+sort); +// //String billingFormula = billingRule.getBillingFormula(); +// billingFormula = billingFormula.replace(chargingId, price); +// //需要判断阶梯类型进行获取各计费标志的取值,拼接公式 +// List billingParamsEntityList = JSON.parseArray(billingParamsJson, BillingParamsDetailDTO.class); +// //将计费参数实体分成两组,即:固定参数和条件参数 +// List fixedParamsEntityList = billingParamsEntityList.stream().filter(item -> ObjectUtil.equal(item.getLadderType(),1)).collect(Collectors.toList()); +// List ladderParamsEntityList = billingParamsEntityList.stream().filter(item -> !ObjectUtil.equal(item.getLadderType(),1)).collect(Collectors.toList()); +// if (fixedParamsEntityList != null && fixedParamsEntityList.size() > 0) { +// if (subjectAndPriceReturn.getNum() != null) { +// for (Map ladderParamsEntity : billingParamsList) { +// String chargingId1 = (String) ladderParamsEntity.get("chargingId"); +// String fieldsName = (String) ladderParamsEntity.get("fieldsName"); +// if ("纸箱贴标单价".equals(name)) { +// if ("纸箱数量".equals(fieldsName)) { +// billingFormula = billingFormula.replace(chargingId1, subjectAndPriceReturn.getNum().toEngineeringString()); +// } +// } else if ("木箱贴标单价".equals(name)){ +// if ("木箱数量".equals(fieldsName)) { +// billingFormula = billingFormula.replace(chargingId1, subjectAndPriceReturn.getNum().toEngineeringString()); +// } +// } +// } +// } +// } +// +// } +// } +// } +// return DynamicCalculationUtil.calculate(billingFormula); +// } +// return BigDecimal.ZERO; +// } + public Map getAmount(List subjectAndPriceReturnList) { + Map map = new HashMap<>(); if (subjectAndPriceReturnList == null || subjectAndPriceReturnList.size() == 1) { - SubjectAndPriceReturn subjectAndPriceReturn = subjectAndPriceReturnList.get(0); - Long billingRulesId = subjectAndPriceReturn.getBillingRulesId(); - String name = subjectAndPriceReturn.getName(); - BillingRulesPO billingRule = contractManageDetailMapper.getBillingRules(billingRulesId); - List billingParams = contractManageDetailMapper.getBillingParams(billingRulesId); - if (billingParams != null && billingParams.size() > 0) { - BillingParamsPO billingParam = billingParams.get(0); - String billingParamsJson = billingParam.getBillingParamsJson(); - String preSetRules = billingParam.getPreSetRules(); - List> preSetRulesList = JSON.parseObject(preSetRules, new TypeReference>>() { - }); - List> billingParamsList = JSON.parseObject(billingParamsJson, new TypeReference>>() { - }); - if (billingParamsList != null && billingParamsList.size() ==2) { - Map targetMap = billingParamsList.stream() - .filter(map -> name.equals(map.get("fieldsName"))) // 关键匹配条件 - .findFirst() // 取第一个 - .orElse(null); // 没找到返回null - String chargingId = (String) targetMap.get("chargingId"); - Integer sort = (Integer) targetMap.get("sort"); - Map reles = preSetRulesList.get(0); - String price = (String) reles.get("fields"+sort); - String billingFormula = billingRule.getBillingFormula(); - billingFormula = billingFormula.replace(chargingId, price); - //需要判断阶梯类型进行获取各计费标志的取值,拼接公式 - List billingParamsEntityList = JSON.parseArray(billingParamsJson, BillingParamsDetailDTO.class); - //将计费参数实体分成两组,即:固定参数和条件参数 - List fixedParamsEntityList = billingParamsEntityList.stream().filter(item -> ObjectUtil.equal(item.getLadderType(),1)).collect(Collectors.toList()); - List ladderParamsEntityList = billingParamsEntityList.stream().filter(item -> !ObjectUtil.equal(item.getLadderType(),1)).collect(Collectors.toList()); - if (fixedParamsEntityList != null && fixedParamsEntityList.size() > 0) { - if (subjectAndPriceReturn.getNum() != null) { - for (BillingParamsDetailDTO ladderParamsEntity : fixedParamsEntityList) { - String chargingId1 = ladderParamsEntity.getChargingId(); - if (chargingId1 != chargingId) { - billingFormula = billingFormula.replace(chargingId1, subjectAndPriceReturn.getNum().toEngineeringString()); - } - } - } - } - return DynamicCalculationUtil.calculate(billingFormula); - } else { - - } - } } else { SubjectAndPriceReturn aReturn = subjectAndPriceReturnList.get(0); Long id = aReturn.getBillingRulesId(); BillingRulesPO Rule = contractManageDetailMapper.getBillingRules(id); String billingFormula = Rule.getBillingFormula(); for (SubjectAndPriceReturn subjectAndPriceReturn : subjectAndPriceReturnList) { - Long billingRulesId = subjectAndPriceReturn.getBillingRulesId(); - String name = subjectAndPriceReturn.getName(); - BillingRulesPO billingRule = contractManageDetailMapper.getBillingRules(billingRulesId); - List billingParams = contractManageDetailMapper.getBillingParams(billingRulesId); - if (billingParams != null && billingParams.size() > 0) { - BillingParamsPO billingParam = billingParams.get(0); - String billingParamsJson = billingParam.getBillingParamsJson(); - String preSetRules = billingParam.getPreSetRules(); - List> preSetRulesList = JSON.parseObject(preSetRules, new TypeReference>>() { - }); - List> billingParamsList = JSON.parseObject(billingParamsJson, new TypeReference>>() { - }); - if (billingParamsList != null && billingParamsList.size() ==2) { - } else { - Map targetMap = billingParamsList.stream() - .filter(map -> name.equals(map.get("fieldsName"))) // 关键匹配条件 - .findFirst() // 取第一个 - .orElse(null); // 没找到返回null - String chargingId = (String) targetMap.get("chargingId"); - Integer sort = (Integer) targetMap.get("sort"); - Map reles = preSetRulesList.get(0); - String price = (String) reles.get("fields"+sort); - //String billingFormula = billingRule.getBillingFormula(); - billingFormula = billingFormula.replace(chargingId, price); - //需要判断阶梯类型进行获取各计费标志的取值,拼接公式 - List billingParamsEntityList = JSON.parseArray(billingParamsJson, BillingParamsDetailDTO.class); - //将计费参数实体分成两组,即:固定参数和条件参数 - List fixedParamsEntityList = billingParamsEntityList.stream().filter(item -> ObjectUtil.equal(item.getLadderType(),1)).collect(Collectors.toList()); - List ladderParamsEntityList = billingParamsEntityList.stream().filter(item -> !ObjectUtil.equal(item.getLadderType(),1)).collect(Collectors.toList()); - if (fixedParamsEntityList != null && fixedParamsEntityList.size() > 0) { - if (subjectAndPriceReturn.getNum() != null) { - for (Map ladderParamsEntity : billingParamsList) { - String chargingId1 = (String) ladderParamsEntity.get("chargingId"); - String fieldsName = (String) ladderParamsEntity.get("fieldsName"); - if ("纸箱贴标单价".equals(name)) { - if ("纸箱数量".equals(fieldsName)) { - billingFormula = billingFormula.replace(chargingId1, subjectAndPriceReturn.getNum().toEngineeringString()); - } - } else if ("木箱贴标单价".equals(name)){ - if ("木箱数量".equals(fieldsName)) { - billingFormula = billingFormula.replace(chargingId1, subjectAndPriceReturn.getNum().toEngineeringString()); - } - } - } - } - } - - } + BigDecimal price = subjectAndPriceReturn.getPrice(); + BigDecimal num = subjectAndPriceReturn.getNum(); + String chargingId = subjectAndPriceReturn.getChargingId(); + String isFee = subjectAndPriceReturn.getIsFee(); + if (isFee != null && "1".equals(isFee)) { + billingFormula = billingFormula.replace(chargingId, price.toEngineeringString()); + } else { + billingFormula = billingFormula.replace(chargingId, num.toEngineeringString()); } } - return DynamicCalculationUtil.calculate(billingFormula); + BigDecimal calculate = DynamicCalculationUtil.calculate(billingFormula); + map.put("amount", calculate); + map.put("billingRulesId", id); + return map; } - return BigDecimal.ZERO; + return map; } public List getSubjectAndPrice(SubjectAndPriceDTO contractManageDTO) { @@ -274,14 +300,16 @@ public class ContractManageApplicationService { BillingParamsPO billingParam = billingParams.get(0); String billingParamsJson = billingParam.getBillingParamsJson(); String preSetRules = billingParam.getPreSetRules(); + Long billingParamsId = billingParam.getBillingParamsId(); List> preSetRulesList = JSON.parseObject(preSetRules, new TypeReference>>() {}); List> billingParamsList = JSON.parseObject(billingParamsJson, new TypeReference>>() {}); Map stringObjectMap1 = preSetRulesList.get(0); for (Map stringObjectMap : billingParamsList) { String fieldsName = (String) stringObjectMap.get("fieldsName"); - if (fieldsName != null && ("装卸费单价".equals(fieldsName) || - "纸箱贴标单价".equals(fieldsName)||"木箱贴标单价".equals(fieldsName) - || "进出仓操作费单价".equals(fieldsName))) { + String isShow = (String) stringObjectMap.get("isShow"); + String isFee = (String) stringObjectMap.get("isFee"); + String isPush = (String) stringObjectMap.get("isPush"); + if ("1".equals(isFee)) { Integer sort = (Integer) stringObjectMap.get("sort"); String chargingId = (String) stringObjectMap.get("chargingId"); String fields = (String) stringObjectMap.get("fields"); @@ -292,6 +320,80 @@ public class ContractManageApplicationService { subjectAndPriceReturn.setChargingId(chargingId); subjectAndPriceReturn.setFields(fields); subjectAndPriceReturn.setBillingRulesId(billingRulesId); + subjectAndPriceReturn.setIsShow(isShow); + subjectAndPriceReturn.setIsFee(isFee); + subjectAndPriceReturn.setIsPush(isPush); + subjectAndPriceReturn.setRulesId(billingParamsId); + result.add(subjectAndPriceReturn); + } + } + } + } + } + } + } + } + } + return result; + } + + public List getSubject(SubjectAndPriceDTO contractManageDTO) { + List result = new ArrayList<>(); + Long settlementCustomersId = contractManageDTO.getSettlementCustomersId(); + Long organizationId = contractManageDTO.getOrganizationId(); + String sunjectCode = contractManageDTO.getSubjectCode(); + Long topOrganizationId = contractManageDTO.getTopOrganizationId(); + List UserContractManages = contractManageMapper.selectList(new LambdaQueryWrapper() + .eq(ContractManage::getSettlementCustomersId, settlementCustomersId) + .eq(ContractManage::getDelFlag, 1) + .eq(ContractManage::getOrganizationId, organizationId) + .eq(ContractManage::getTopOrganizationId, topOrganizationId) + .eq(ContractManage::getCommonContractFlag, 2)); + if (UserContractManages != null && UserContractManages.size() > 0) { + }else{ + List commonContractManages = contractManageMapper.selectList(new LambdaQueryWrapper() + .eq(ContractManage::getDelFlag, 1) + .eq(ContractManage::getOrganizationId, organizationId) + .eq(ContractManage::getTopOrganizationId, topOrganizationId) + .eq(ContractManage::getCommonContractFlag, 1)); + if (commonContractManages != null && commonContractManages.size() > 0) { + ContractManage contractManage = commonContractManages.get(0); + Long contractManageId = contractManage.getContractManageId(); + List contractManageDetails = contractManageDetailMapper.selectList(new LambdaQueryWrapper() + .eq(ContractManageDetail::getContractManageId, contractManageId) + .eq(ContractManageDetail::getDelFlag, 1)); + if (contractManageDetails != null && contractManageDetails.size() > 0) { + for (ContractManageDetail contractManageDetail : contractManageDetails) { + String code = contractManageDetail.getFirstSubjectCode(); + if (sunjectCode.equals(code)) { + Long accountingStrategyId = contractManageDetail.getAccountingStrategyId(); + BillingRulesPO billingRule = contractManageDetailMapper.getBillingRules(accountingStrategyId); + if (billingRule != null) { + Long billingRulesId = billingRule.getBillingRulesId(); + List billingParams = contractManageDetailMapper.getBillingParams(billingRulesId); + if (billingParams != null && billingParams.size() > 0) { + BillingParamsPO billingParam = billingParams.get(0); + String billingParamsJson = billingParam.getBillingParamsJson(); + String preSetRules = billingParam.getPreSetRules(); + Long billingParamsId = billingParam.getBillingParamsId(); + List> billingParamsList = JSON.parseObject(billingParamsJson, new TypeReference>>() {}); + for (Map stringObjectMap : billingParamsList) { + String fieldsName = (String) stringObjectMap.get("fieldsName"); + String isShow = (String) stringObjectMap.get("isShow"); + String isFee = (String) stringObjectMap.get("isFee"); + String isPush = (String) stringObjectMap.get("isPush"); + if ("1".equals(isShow)) { + String chargingId = (String) stringObjectMap.get("chargingId"); + String fields = (String) stringObjectMap.get("fields"); + SubjectAndPriceReturn subjectAndPriceReturn = new SubjectAndPriceReturn(); + subjectAndPriceReturn.setName(fieldsName); + subjectAndPriceReturn.setChargingId(chargingId); + subjectAndPriceReturn.setFields(fields); + subjectAndPriceReturn.setBillingRulesId(billingRulesId); + subjectAndPriceReturn.setIsShow(isShow); + subjectAndPriceReturn.setIsFee(isFee); + subjectAndPriceReturn.setIsPush(isPush); + subjectAndPriceReturn.setRulesId(billingParamsId); result.add(subjectAndPriceReturn); } } diff --git a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/interfaces/dto/contractManage/SubjectAndPriceReturn.java b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/interfaces/dto/contractManage/SubjectAndPriceReturn.java index 3becb1cd5..6ba87605d 100644 --- a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/interfaces/dto/contractManage/SubjectAndPriceReturn.java +++ b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/interfaces/dto/contractManage/SubjectAndPriceReturn.java @@ -1,15 +1,23 @@ package com.mhd.basic.interfaces.dto.contractManage; import lombok.Data; - import java.math.BigDecimal; + @Data public class SubjectAndPriceReturn { + private Long rulesId; private String name; private BigDecimal price; private String chargingId; private Long billingRulesId; private String fields; private BigDecimal num; + private String isShow; + private String isPush; + private String isFee; + private String subjectCode; + private String subjectName; + private String serviceItemsCode; + private String serviceItemsName; } \ No newline at end of file diff --git a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/interfaces/facade/contractManage/ContractManageApi.java b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/interfaces/facade/contractManage/ContractManageApi.java index 4f26e2e60..2dd6e4bd1 100644 --- a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/interfaces/facade/contractManage/ContractManageApi.java +++ b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/interfaces/facade/contractManage/ContractManageApi.java @@ -59,6 +59,17 @@ public class ContractManageApi extends BaseController{ return AjaxResult.success(contractManageApplicationService.getSubjectAndPrice(subjectAndPriceDTO)); } + /** + * 获取科目和单价 + */ + @ApiOperation("获取需要显示的计费字段") + @GetMapping("/getSubject") + public AjaxResult getSubject(SubjectAndPriceDTO subjectAndPriceDTO) + { + //转换实体 + return AjaxResult.success(contractManageApplicationService.getSubject(subjectAndPriceDTO)); + } + /** * 获取科目和单价 */ diff --git a/mhd-modules/mhd-system/src/main/resources/bootstrap.yml b/mhd-modules/mhd-system/src/main/resources/bootstrap.yml index 2afad33b3..d2ad81e8f 100644 --- a/mhd-modules/mhd-system/src/main/resources/bootstrap.yml +++ b/mhd-modules/mhd-system/src/main/resources/bootstrap.yml @@ -14,20 +14,20 @@ spring: nacos: discovery: # server-addr: 127.0.0.1:8848 - server-addr: 10.33.0.129:6010 +# server-addr: 10.33.0.129:6010 # 线上测试环境配置 容器名+端口号 -# server-addr: 10.102.192.5:6848 -# username: nacos -# password: manhuoda@2023 + server-addr: 10.102.192.5:6848 + username: nacos + password: manhuoda@2023 #线上正式环境 # server-addr: 10.102.192.105:6848 config: # server-addr: 127.0.0.1:8848 - server-addr: 10.33.0.129:6010 +# server-addr: 10.33.0.129:6010 # 线上测试环境配置 容器名+端口号 -# server-addr: 10.102.192.5:6848 -# username: nacos -# password: manhuoda@2023 + server-addr: 10.102.192.5:6848 + username: nacos + password: manhuoda@2023 #线上正式环境 # server-addr: 10.102.192.105:6848 group: DEFAULT_GROUP # 默认分组就是DEFAULT_GROUP,如果使用默认分组可以不配置 diff --git a/mhd-user-center/src/main/resources/mapper/UserMapper.xml b/mhd-user-center/src/main/resources/mapper/UserMapper.xml index b9e38a167..0af63c215 100644 --- a/mhd-user-center/src/main/resources/mapper/UserMapper.xml +++ b/mhd-user-center/src/main/resources/mapper/UserMapper.xml @@ -79,8 +79,9 @@ a.payment_bank, a.payment_account, a.invoice_title, - a.tax_number - FROM "USER" a + a.tax_number, + b.SETTLEMENT_CURRENCY + FROM "USER" a left join USER_SHIPPER b on a.user_id = b.user_id where a.del_flag = 1 diff --git a/mhd_bms/src/main/java/com/mhd/bms/application/server/businessDocument/BusinessDocumentApplicationService.java b/mhd_bms/src/main/java/com/mhd/bms/application/server/businessDocument/BusinessDocumentApplicationService.java index c48aaa3d3..d722338b5 100644 --- a/mhd_bms/src/main/java/com/mhd/bms/application/server/businessDocument/BusinessDocumentApplicationService.java +++ b/mhd_bms/src/main/java/com/mhd/bms/application/server/businessDocument/BusinessDocumentApplicationService.java @@ -1023,6 +1023,7 @@ public class BusinessDocumentApplicationService { businessDocumentDO.setTopOrganizationId(businessDocumentDO.getTopOrganizationId()); businessDocumentDO.setOrganizationId(businessDocumentDO.getOrganizationId()); businessDocumentDO.setOrganizationName(businessDocumentDO.getOrganizationName()); + businessDocumentDO.setOriginalBusinessNum(businessDocumentDO.getOriginalBusinessNum()); //调用费用计算,计算费用金额进行保存 // CostCalculationDTO costCalculationDTO = new CostCalculationDTO(); // costCalculationDTO.setOriginalBusinessNum(businessDocumentDO.getOriginalBusinessNum()); diff --git a/mhd_bms/src/main/java/com/mhd/bms/domain/billManage/repository/persistence/BillManageImpl.java b/mhd_bms/src/main/java/com/mhd/bms/domain/billManage/repository/persistence/BillManageImpl.java index 07727abc7..d08e95350 100644 --- a/mhd_bms/src/main/java/com/mhd/bms/domain/billManage/repository/persistence/BillManageImpl.java +++ b/mhd_bms/src/main/java/com/mhd/bms/domain/billManage/repository/persistence/BillManageImpl.java @@ -276,6 +276,12 @@ public class BillManageImpl extends ServiceImpl im } else { item.setDef75("T04"); } + String invoiceItem1 = item1.getInvoiceItem(); + if (invoiceItem1 != null && !invoiceItem1.isEmpty()) { + String[] split = invoiceItem1.split(","); + item.setDef29(split[0]); + //item.setDef29(invoiceItem1); + } item.setTaxcodeid("ZL01"); item.setInvoiceno(invoiceNumber); ysitemList.add(item); @@ -558,6 +564,11 @@ public class BillManageImpl extends ServiceImpl im } else { item.setDef75("T10"); } + String invoiceItem1 = firstItem.getInvoiceItem(); + if (invoiceItem1 != null && !invoiceItem1.isEmpty()) { + String[] split = invoiceItem1.split(","); + item.setDef29(split[0]); + } item.setPk_currtype(settlementCurrencyNcCode); item.setMoney_cr(String.valueOf(totalInvoiceValue)); item.setMoney_bal(String.valueOf(totalInvoiceValue)); diff --git a/mhd_bms/src/main/resources/bootstrap.yml b/mhd_bms/src/main/resources/bootstrap.yml index 086a1e8b7..d00f66d31 100644 --- a/mhd_bms/src/main/resources/bootstrap.yml +++ b/mhd_bms/src/main/resources/bootstrap.yml @@ -16,19 +16,19 @@ spring: cloud: nacos: discovery: - # server-addr: 127.0.0.1:8848 +# server-addr: 127.0.0.1:8848 # 线上测试环境配置 容器名+端口号 - server-addr: 10.33.0.129:6010 -# server-addr: 10.102.192.5:6848 -# username: nacos -# password: manhuoda@2023 +# server-addr: 10.33.0.129:6010 + server-addr: 10.102.192.5:6848 + username: nacos + password: manhuoda@2023 config: - # server-addr: 127.0.0.1:8848 +# server-addr: 127.0.0.1:8848 # 线上测试环境配置 容器名+端口号 - server-addr: 10.33.0.129:6010 -# server-addr: 10.102.192.5:6848 -# username: nacos -# password: manhuoda@2023 +# server-addr: 10.33.0.129:6010 + server-addr: 10.102.192.5:6848 + username: nacos + password: manhuoda@2023 group: DEFAULT_GROUP # 默认分组就是DEFAULT_GROUP,如果使用默认分组可以不配置 file-extension: yml #默认properties # 开启nacos自动刷新,如果这个配置没有或者为false会导致配置不能自动刷新 diff --git a/mhd_finance/src/main/java/com/linke/finance/domain/reconciliation/repository/persistence/ReconciliationImpl.java b/mhd_finance/src/main/java/com/linke/finance/domain/reconciliation/repository/persistence/ReconciliationImpl.java index b0ca83ee4..8e6ee732a 100644 --- a/mhd_finance/src/main/java/com/linke/finance/domain/reconciliation/repository/persistence/ReconciliationImpl.java +++ b/mhd_finance/src/main/java/com/linke/finance/domain/reconciliation/repository/persistence/ReconciliationImpl.java @@ -1590,6 +1590,12 @@ public class ReconciliationImpl extends ServiceImpl getFeeDetail(Long id) { + List businessOrderAccounts = businessOrderAccountMapper.selectList(new LambdaQueryWrapper().eq(BusinessOrderAccount::getOrderId, id).eq(BusinessOrderAccount::getIsDelete, 0)); + return businessOrderAccounts; + } } diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/businessDocumentCargoMulti/entity/BusinessDocumentCargoMulti.java b/mhd_oms/src/main/java/com/mhd/oms/domain/businessDocumentCargoMulti/entity/BusinessDocumentCargoMulti.java index b633cea83..09bd2c45b 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/businessDocumentCargoMulti/entity/BusinessDocumentCargoMulti.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/businessDocumentCargoMulti/entity/BusinessDocumentCargoMulti.java @@ -80,6 +80,8 @@ public class BusinessDocumentCargoMulti extends BaseVOEntity{ private String weightUnitId; @ApiModelProperty(value = "重量单位名称") private String weightUnit; + @ApiModelProperty(value = "体积") + private BigDecimal materialVolume; @ApiModelProperty(value = "数量单位ID") diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/businessDocumentOrder/entity/BusinessDocumentOrder.java b/mhd_oms/src/main/java/com/mhd/oms/domain/businessDocumentOrder/entity/BusinessDocumentOrder.java index e46c72d4c..f0df40b7b 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/businessDocumentOrder/entity/BusinessDocumentOrder.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/businessDocumentOrder/entity/BusinessDocumentOrder.java @@ -731,4 +731,17 @@ public class BusinessDocumentOrder extends BaseVOEntity{ // // @ApiModelProperty(value = "开户银行") // private String accountBank; + + @ApiModelProperty(value = "业务主管") + private String salesManager; + + @ApiModelProperty(value = "审核意见") + private String reviewOpinion; + + @ApiModelProperty(value = "订单来源") + private String orderSource; + + + @ApiModelProperty(value = "出入库单号") + private String entryNumber; } diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/businessDocumentOrder/repository/facade/IBusinessDocumentOrderService.java b/mhd_oms/src/main/java/com/mhd/oms/domain/businessDocumentOrder/repository/facade/IBusinessDocumentOrderService.java index adff5acb2..f78b70f0c 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/businessDocumentOrder/repository/facade/IBusinessDocumentOrderService.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/businessDocumentOrder/repository/facade/IBusinessDocumentOrderService.java @@ -45,7 +45,7 @@ public interface IBusinessDocumentOrderService extends IService businessOrderAccountList; + @ApiModelProperty("业务单地址集合") private List businessDocumentAddressMultiDTOList; diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/businessDocumentOrder/service/BusinessDocumentOrderDomainService.java b/mhd_oms/src/main/java/com/mhd/oms/domain/businessDocumentOrder/service/BusinessDocumentOrderDomainService.java index 19d362419..1f910ed14 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/businessDocumentOrder/service/BusinessDocumentOrderDomainService.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/businessDocumentOrder/service/BusinessDocumentOrderDomainService.java @@ -18,6 +18,8 @@ import com.mhd.oms.domain.businessDocumentOrder.repository.facade.IBusinessDocum import com.mhd.oms.domain.businessDocumentOrder.repository.mapper.BusinessDocumentOrderMapper; import com.mhd.oms.domain.businessDocumentOrder.repository.po.BusinessDocumentOrderPO; import com.mhd.oms.domain.businessDocumentOrder.repository.todo.BusinessDocumentOrderDO; +import com.mhd.oms.domain.businessOrderAccount.BusinessOrderAccount; +import com.mhd.oms.domain.businessOrderAccount.repository.mapper.BusinessOrderAccountMapper; import com.mhd.oms.domain.orderType.entity.OrderType; import com.mhd.oms.interfaces.dto.businessDocumentAddressMulti.BusinessDocumentAddressMultiDTO; import com.mhd.oms.interfaces.dto.businessDocumentCargoMulti.BusinessDocumentCargoMultiDTO; @@ -61,6 +63,9 @@ public class BusinessDocumentOrderDomainService { @Resource private BusinessDocumentOrderMapper businessDocumentOrderMapper; + + @Resource + private BusinessOrderAccountMapper businessOrderAccountMapper; /** * 分页查询【请填写功能名称】列表 */ @@ -168,6 +173,10 @@ public class BusinessDocumentOrderDomainService { tmsOrder.setRealCreateBy(String.valueOf(u.getUserid())); tmsOrder.setRealCreateName(u.getUsername()); tmsOrder.setAppointShipper(userShipperPo.getShipperEnterpriseName());//20250-07-29修改:订单表委托方保存公司名字,而不是姓名 + tmsOrder.setOrderSource(businessDocumentOrderDO.getOrderSource()); + tmsOrder.setEntryNumber(businessDocumentOrderDO.getEntryNumber()); +// tmsOrder.setSalesManager(u.getUserPo().getUserName()); + String salesmanCodeNc = businessDocumentOrderDO.getSalesmanId(); if (salesmanCodeNc != null){ String makerCodeNc = businessDocumentOrderService.selectByMakerCodeNc(salesmanCodeNc); @@ -311,6 +320,31 @@ public class BusinessDocumentOrderDomainService { //保存货物信息及地址信息 saveAddress2CargoInfo(tmsOrder.getId(), allCargoList, loadingAddressList, unloadAddressList); + List tmsOrderAccountList=businessDocumentOrderDO.getBusinessOrderAccountList(); + if(ObjectUtil.isNotNull(tmsOrderAccountList)&&tmsOrderAccountList.size()>0){ + for (BusinessOrderAccount tmsOrderAccount:tmsOrderAccountList){ + tmsOrderAccount.setIsDelete(0); + tmsOrderAccount.setOrderId(String.valueOf(tmsOrder.getId())); + tmsOrderAccount.setCreateBy(String.valueOf(u.getUserid())); + tmsOrderAccount.setCreateTime(new Date()); + // 设置组织信息 + if (businessDocumentOrderDO.getOrganizationId() != null) { + tmsOrderAccount.setOrganizationId(businessDocumentOrderDO.getOrganizationId()); + } + if (businessDocumentOrderDO.getOrganizationName() != null) { + tmsOrderAccount.setOrganizationName(businessDocumentOrderDO.getOrganizationName()); + } + if (businessDocumentOrderDO.getTopOrganizationId() != null) { + tmsOrderAccount.setTopOrganizationId(businessDocumentOrderDO.getTopOrganizationId()); + } + BigDecimal amount = tmsOrderAccount.getAmount(); +// if (ObjectUtil.isNotEmpty(amount) && amount.compareTo(BigDecimal.ZERO) > 0) { +// tmsOrderAccountMapper.insert(tmsOrderAccount); + businessOrderAccountMapper.insert(tmsOrderAccount); + +// } + } + } return istrue; } @@ -532,6 +566,39 @@ public class BusinessDocumentOrderDomainService { //保存货物信息及地址信息 saveAddress2CargoInfo(tmsOrder.getId(), allCargoList, loadingAddressList, unloadAddressList); + + //删除原来的费用科目 + List tmsOrderAccountList1=businessOrderAccountMapper.selectList(new LambdaQueryWrapper().eq(BusinessOrderAccount::getOrderId, businessDocumentOrderDO.getId()).eq(BusinessOrderAccount::getIsDelete, 0)); + if(ObjectUtil.isNotNull(tmsOrderAccountList1)&&tmsOrderAccountList1.size()>0){ + for (BusinessOrderAccount tmsOrderAccount:tmsOrderAccountList1){ + tmsOrderAccount.setIsDelete(1); + tmsOrderAccount.setUpdateBy(String.valueOf(u.getUserid())); + tmsOrderAccount.setUpdateTime(new Date()); + businessOrderAccountMapper.updateById(tmsOrderAccount); + } + } + //保存费用科目信息 + List tmsOrderAccountList=businessDocumentOrderDO.getBusinessOrderAccountList(); + if(ObjectUtil.isNotNull(tmsOrderAccountList)&&tmsOrderAccountList.size()>0){ + for (BusinessOrderAccount tmsOrderAccount:tmsOrderAccountList){ + tmsOrderAccount.setIsDelete(0); + tmsOrderAccount.setOrderId(String.valueOf(businessDocumentOrderDO.getId())); + tmsOrderAccount.setCreateBy(String.valueOf(u.getUserid())); + tmsOrderAccount.setCreateTime(new Date()); + // 设置组织信息 + if (businessDocumentOrderDO.getOrganizationId() != null) { + tmsOrderAccount.setOrganizationId(businessDocumentOrderDO.getOrganizationId()); + } + if (businessDocumentOrderDO.getOrganizationName() != null) { + tmsOrderAccount.setOrganizationName(businessDocumentOrderDO.getOrganizationName()); + } + if (businessDocumentOrderDO.getTopOrganizationId() != null) { + tmsOrderAccount.setTopOrganizationId(businessDocumentOrderDO.getTopOrganizationId()); + } + tmsOrderAccount.setId(IdUtil.randomUUID()); + businessOrderAccountMapper.insert(tmsOrderAccount); + } + } return istrue; } @@ -553,6 +620,7 @@ public class BusinessDocumentOrderDomainService { tmsCargoInfo.setOrderId(String.valueOf(id)); tmsCargoInfo.setCargoWeight(tmsCargoInfoDTO.getWeight()==null ? BigDecimal.ZERO: tmsCargoInfoDTO.getWeight()); tmsCargoInfo.setCargoNum(tmsCargoInfoDTO.getCargoNum()==null ? BigDecimal.ZERO: tmsCargoInfoDTO.getCargoNum()); + tmsCargoInfo.setMaterialVolume(tmsCargoInfoDTO.getMaterialVolume()==null ? BigDecimal.ZERO: tmsCargoInfoDTO.getMaterialVolume()); businessDocumentCargoMultiMapper.insert(tmsCargoInfo); } @@ -654,10 +722,10 @@ public class BusinessDocumentOrderDomainService { return businessDocumentOrderService.getInfo(id); } - public Boolean audit( Long[] ids, Long reviewStatus) + public Boolean audit( Long[] ids, Long reviewStatus, String SalesManager,String reviewOpinion) { - return businessDocumentOrderService.audit(ids,reviewStatus); + return businessDocumentOrderService.audit(ids,reviewStatus,SalesManager,reviewOpinion); } public Boolean execute(Long[] ids) { return businessDocumentOrderService.execute(ids); @@ -705,4 +773,11 @@ public class BusinessDocumentOrderDomainService { return serviceRequire.toString(); } + public BusinessDocumentCargoMulti getCargoContent(Long id){ + BusinessDocumentCargoMulti businessDocumentCargoMulti = businessDocumentCargoMultiMapper.selectOne(new LambdaQueryWrapper().eq(BusinessDocumentCargoMulti::getOrderId, id)); + if (businessDocumentCargoMulti != null){ + return businessDocumentCargoMulti ; + } + return null; + } } diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/businessOrderAccount/BusinessOrderAccount.java b/mhd_oms/src/main/java/com/mhd/oms/domain/businessOrderAccount/BusinessOrderAccount.java new file mode 100644 index 000000000..89a01c323 --- /dev/null +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/businessOrderAccount/BusinessOrderAccount.java @@ -0,0 +1,107 @@ +package com.mhd.oms.domain.businessOrderAccount; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.mhd.common.core.annotation.Excel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * @author: brb + * @description: + * @create: 2026-04-11 10:46 + */ +@Data +@TableName("business_order_account") +public class BusinessOrderAccount { + private static final long serialVersionUID = 1L; + + /**主键*/ + @TableId(type = IdType.ID_WORKER_STR) + private String id; + /**创建人*/ + @ApiModelProperty(value = "创建人") + @Excel(name = "创建人", width = 15) + private String createBy; + /**创建日期*/ + @ApiModelProperty(value = "创建日期") + + @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") + private Date createTime; + /**更新人*/ + @ApiModelProperty(value = "更新人") + @Excel(name = "更新人", width = 15) + private String updateBy; + /**更新日期*/ + @ApiModelProperty(value = "更新日期") + + @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") + private Date updateTime; + /**所属部门*/ + @ApiModelProperty(value = "所属部门") + @Excel(name = "所属部门", width = 15) + private String sysOrgCode; + /**删除标识*/ + @ApiModelProperty(value = "删除标识") + @Excel(name = "删除标识", width = 15) + private Integer isDelete; + /**所属组织*/ + @ApiModelProperty(value = "所属组织") + @Excel(name = "所属组织", width = 15) + private String orgName; + /**组织ID*/ + @ApiModelProperty(value = "组织ID") + @Excel(name = "组织ID", width = 15) + private Long organizationId; + /**一级组织ID*/ + @ApiModelProperty(value = "一级组织ID") + @Excel(name = "一级组织ID", width = 15) + private Long topOrganizationId; + /**组织名称*/ + @ApiModelProperty(value = "组织名称") + @Excel(name = "组织名称", width = 15) + private String organizationName; + /**订单id*/ + @ApiModelProperty(value = "订单id") + @Excel(name = "订单id", width = 15) + private String orderId; + /**科目id*/ + @ApiModelProperty(value = "科目id") + @Excel(name = "科目id", width = 15) + private Long accountId; + /**科目收支类型(1-应收,2-应付*/ + @ApiModelProperty(value = "科目收支类型(1-应收,2-应付") + @Excel(name = "科目收支类型(1-应收,2-应付", width = 15) + private Long accountType; + /**科目编码*/ + @ApiModelProperty(value = "科目编码") + @Excel(name = "科目编码", width = 15) + private String subjectCode; + /**科目名称*/ + @ApiModelProperty(value = "科目名称") + @Excel(name = "科目名称", width = 15) + private String subjectName; + /**科目费率*/ + @ApiModelProperty(value = "科目费率") + @Excel(name = "科目费率", width = 15) + private BigDecimal rate; + + /**金额*/ + @ApiModelProperty(value = "金额") + @Excel(name = "金额", width = 15) + private BigDecimal amount; + @ApiModelProperty(value = "无税费用") + private BigDecimal taxFreeFee; + @ApiModelProperty(value = "税额") + private BigDecimal taxAmount; + @ApiModelProperty(value = "收款帐户") + private String receiveAccount; +} diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/businessOrderAccount/repository/mapper/BusinessOrderAccountMapper.java b/mhd_oms/src/main/java/com/mhd/oms/domain/businessOrderAccount/repository/mapper/BusinessOrderAccountMapper.java new file mode 100644 index 000000000..baf272b56 --- /dev/null +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/businessOrderAccount/repository/mapper/BusinessOrderAccountMapper.java @@ -0,0 +1,33 @@ +package com.mhd.oms.domain.businessOrderAccount.repository.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.mhd.oms.domain.businessOrderAccount.BusinessOrderAccount; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 业务订单科目Mapper接口 + * + * @author gen + * @date 2026-04-11 + */ +@Mapper +public interface BusinessOrderAccountMapper extends BaseMapper { + + /** + * 查询业务订单科目列表 + * + * @param businessOrderAccount 业务订单科目 + * @return 业务订单科目集合 + */ + List selectBusinessOrderAccountList(BusinessOrderAccount businessOrderAccount); + + /** + * 根据订单ID查询业务订单科目 + * + * @param orderId 订单ID + * @return 业务订单科目集合 + */ + List selectBusinessOrderAccountByOrderId(String orderId); +} \ No newline at end of file diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/executeOrder/entity/ExecuteOrder.java b/mhd_oms/src/main/java/com/mhd/oms/domain/executeOrder/entity/ExecuteOrder.java index 53d4620ac..3dd1c6119 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/executeOrder/entity/ExecuteOrder.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/executeOrder/entity/ExecuteOrder.java @@ -68,6 +68,26 @@ public class ExecuteOrder extends BaseVOEntity{ @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") private Long topOrganizationId; + @ApiModelProperty("$column.columnComment") + @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") + private String vehicleTypeName; + + @ApiModelProperty("$column.columnComment") + @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") + private Long orderShippingType; + + @ApiModelProperty("$column.columnComment") + @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") + private String appointShipper; + @ApiModelProperty("$column.columnComment") + @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") + private String unloadName; + + @ApiModelProperty("$column.columnComment") + @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") + private String loadingName; + + @ApiModelProperty( "下发状态 0-无状态 1-未下发 2-已下发 ") private Long issueStatus; @@ -85,4 +105,18 @@ public class ExecuteOrder extends BaseVOEntity{ @ApiModelProperty("业务单状态 0-未下发 1-已下发 2-已完成 3-已取消 4-已拦截") private Long orderStatus; + @ApiModelProperty("预约单号") + private String reservationOrderNumber; + + @ApiModelProperty("tms单号") + private String tmsOrderNumber; + + @ApiModelProperty("作业情况") + private String jobStatus; + + @ApiModelProperty("预计运输时间") + private Date documentDate; + + @ApiModelProperty("备注") + private String shippingNote; } diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/executeOrder/repository/persistence/ExecuteOrderImpl.java b/mhd_oms/src/main/java/com/mhd/oms/domain/executeOrder/repository/persistence/ExecuteOrderImpl.java index 4582fdd1a..c2173702b 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/executeOrder/repository/persistence/ExecuteOrderImpl.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/executeOrder/repository/persistence/ExecuteOrderImpl.java @@ -153,6 +153,7 @@ public class ExecuteOrderImpl extends ServiceImpl organizationIdList; @ApiModelProperty(name = "权限菜单ID") private Long permissionMenuId; + + @ApiModelProperty("预约单号") + private String reservationOrderNumber; + + @ApiModelProperty("tms单号") + private String tmsOrderNumber; + + @ApiModelProperty("业务单号") + private String businessOrderNumber; + + + @ApiModelProperty("作业情况") + private String jobStatus; + + @ApiModelProperty("预计运输时间") + private Date documentDate; + + @ApiModelProperty("备注") + private String shippingNote; } diff --git a/mhd_oms/src/main/java/com/mhd/oms/interfaces/dto/businessDocumentCargoMulti/BusinessDocumentCargoMultiDTO.java b/mhd_oms/src/main/java/com/mhd/oms/interfaces/dto/businessDocumentCargoMulti/BusinessDocumentCargoMultiDTO.java index c1bfb0a5f..fc6120cf1 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/interfaces/dto/businessDocumentCargoMulti/BusinessDocumentCargoMultiDTO.java +++ b/mhd_oms/src/main/java/com/mhd/oms/interfaces/dto/businessDocumentCargoMulti/BusinessDocumentCargoMultiDTO.java @@ -99,4 +99,7 @@ public class BusinessDocumentCargoMultiDTO extends BaseVOEntity{ @ApiModelProperty("") private String materialCode; + @ApiModelProperty("体积") + private BigDecimal materialVolume; + } diff --git a/mhd_oms/src/main/java/com/mhd/oms/interfaces/dto/businessDocumentOrder/BusinessDocumentOrderDTO.java b/mhd_oms/src/main/java/com/mhd/oms/interfaces/dto/businessDocumentOrder/BusinessDocumentOrderDTO.java index 7b9b8b548..86835f170 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/interfaces/dto/businessDocumentOrder/BusinessDocumentOrderDTO.java +++ b/mhd_oms/src/main/java/com/mhd/oms/interfaces/dto/businessDocumentOrder/BusinessDocumentOrderDTO.java @@ -4,6 +4,7 @@ import com.mhd.common.core.annotation.Excel; import com.mhd.oms.domain.businessDocumentAddressMulti.entity.BusinessDocumentAddressMulti; import com.mhd.oms.domain.businessDocumentAddressMulti.repository.todo.BusinessDocumentAddressMultiDO; import com.mhd.oms.domain.businessDocumentCargoMulti.entity.BusinessDocumentCargoMulti; +import com.mhd.oms.domain.businessOrderAccount.BusinessOrderAccount; import com.mhd.oms.interfaces.dto.businessDocumentAddressMulti.BusinessDocumentAddressMultiDTO; import com.mhd.oms.interfaces.dto.businessDocumentCargoMulti.BusinessDocumentCargoMultiDTO; import lombok.Data; @@ -753,6 +754,17 @@ public class BusinessDocumentOrderDTO extends BaseVOEntity{ @ApiModelProperty(value = "开户银行") private String accountBank; + @ApiModelProperty(value = "业务主管") + private String salesManager; + @ApiModelProperty(value = "审核意见") + private String reviewOpinion; + + @ApiModelProperty("订单来源") + private String orderSource; + + @ApiModelProperty(value = "出入库单号") + private String entryNumber; + @ApiModelProperty("业务单地址集合") private List businessDocumentAddressMultiDTOList; @@ -769,4 +781,7 @@ public class BusinessDocumentOrderDTO extends BaseVOEntity{ @ApiModelProperty(value = "卸货地址集合") private List unloadAddressList; + @ApiModelProperty("费用科目明细") + private List businessOrderAccountList; + } diff --git a/mhd_oms/src/main/java/com/mhd/oms/interfaces/dto/executeOrder/ExecuteOrderDTO.java b/mhd_oms/src/main/java/com/mhd/oms/interfaces/dto/executeOrder/ExecuteOrderDTO.java index 2e93096e2..9d74bd988 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/interfaces/dto/executeOrder/ExecuteOrderDTO.java +++ b/mhd_oms/src/main/java/com/mhd/oms/interfaces/dto/executeOrder/ExecuteOrderDTO.java @@ -91,9 +91,41 @@ public class ExecuteOrderDTO extends BaseVOEntity{ private Long topOrganizationId; + @ApiModelProperty("$column.columnComment") + @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") + private String vehicleTypeName; + + @ApiModelProperty("$column.columnComment") + @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") + private Long orderShippingType; + + @ApiModelProperty("$column.columnComment") + @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") + private String appointShipper; + @ApiModelProperty("$column.columnComment") + @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") + private String unloadName; + + @ApiModelProperty("$column.columnComment") + @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") + private String loadingName; + + @ApiModelProperty("业务单号") + private String businessOrderNumber; + + @ApiModelProperty(name = "组织ID集合") private List organizationIdList; @ApiModelProperty(name = "权限菜单ID") private Long permissionMenuId; + + @ApiModelProperty("作业情况") + private String jobStatus; + + @ApiModelProperty("预计运输时间") + private Date documentDate; + + @ApiModelProperty("备注") + private String shippingNote; } diff --git a/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/businessDocumentOrder/BusinessDocumentOrderApi.java b/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/businessDocumentOrder/BusinessDocumentOrderApi.java index 4de65d716..4dced3b3b 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/businessDocumentOrder/BusinessDocumentOrderApi.java +++ b/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/businessDocumentOrder/BusinessDocumentOrderApi.java @@ -64,6 +64,13 @@ public class BusinessDocumentOrderApi extends BaseController{ } } + @ApiOperation("根据业务单id查询费用明细") + @GetMapping("/getFeeDetail/{id}") + public AjaxResult getFeeDetail(@PathVariable("id") Long id) + { + return AjaxResult.success(businessDocumentOrderApplicationService.getFeeDetail(id)); + } + /** * 批量删除【业务单】 */ @@ -89,9 +96,9 @@ public class BusinessDocumentOrderApi extends BaseController{ */ @ApiOperation("业务单审核") @GetMapping(value = "/audit") - public AjaxResult audit(@RequestParam("ids") Long[] ids,@RequestParam("reviewStatus") Long reviewStatus) + public AjaxResult audit(@RequestParam("ids") Long[] ids,@RequestParam("reviewStatus") Long reviewStatus,@RequestParam("salesManager") String salesManager,@RequestParam("reviewOpinion") String reviewOpinion) { - return AjaxResult.success(businessDocumentOrderApplicationService.audit(ids,reviewStatus)); + return AjaxResult.success(businessDocumentOrderApplicationService.audit(ids,reviewStatus,salesManager,reviewOpinion)); } /** @@ -103,6 +110,12 @@ public class BusinessDocumentOrderApi extends BaseController{ { return toAjax(businessDocumentOrderApplicationService.execute(ids)); } + @ApiOperation("获取业务单的货物内容") + @GetMapping("/getCargoContent/{id}") + public AjaxResult getCargoContent(@PathVariable("id") Long id) + { + return AjaxResult.success(businessDocumentOrderApplicationService.getCargoContent(id)); + } diff --git a/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/executeOrder/ExecuteOrderApi.java b/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/executeOrder/ExecuteOrderApi.java index 099bce344..a77f0c8eb 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/executeOrder/ExecuteOrderApi.java +++ b/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/executeOrder/ExecuteOrderApi.java @@ -2,6 +2,8 @@ package com.mhd.oms.interfaces.facade.executeOrder; import java.util.List; +import com.mhd.common.security.utils.SecurityUtils; +import com.mhd.system.api.model.LoginUser; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @@ -103,6 +105,15 @@ public class ExecuteOrderApi extends BaseController{ return toAjax(executeOrderApplicationService.cancelIssueDocuments(ids)); } + @ApiOperation("获取当前登录人信息") + @GetMapping("/getCurrentUser") + public LoginUser getCurrentUser() + { + LoginUser u = SecurityUtils.getLoginUser(); +// u.getUserPo().getUserName(); + return u; + } + diff --git a/mhd_oms/src/main/resources/mapper/businessDocumentOrder/BusinessDocumentOrderMapper.xml b/mhd_oms/src/main/resources/mapper/businessDocumentOrder/BusinessDocumentOrderMapper.xml index 31d66cc90..67bd0e33f 100644 --- a/mhd_oms/src/main/resources/mapper/businessDocumentOrder/BusinessDocumentOrderMapper.xml +++ b/mhd_oms/src/main/resources/mapper/businessDocumentOrder/BusinessDocumentOrderMapper.xml @@ -186,6 +186,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + and ORDER_SOURCE = #{orderSource} + and CREATE_COMPANY_ID = #{createCompanyId} diff --git a/mhd_oms/src/main/resources/mapper/businessOrderAccount/BusinessOrderAccountMapper.xml b/mhd_oms/src/main/resources/mapper/businessOrderAccount/BusinessOrderAccountMapper.xml new file mode 100644 index 000000000..e78914880 --- /dev/null +++ b/mhd_oms/src/main/resources/mapper/businessOrderAccount/BusinessOrderAccountMapper.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select id, create_by, create_time, update_by, update_time, sys_org_code, is_delete, org_name, + organization_id, top_organization_id, organization_name, order_id, account_id, account_type, + subject_code, subject_name, rate, amount, tax_free_fee, tax_amount, receive_account + from business_order_account + + + + + + + \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/application/service/handoverTaskOrder/HandoverTaskOrderApplicationService.java b/mhd_wms/src/main/java/com/mhd/wms/application/service/handoverTaskOrder/HandoverTaskOrderApplicationService.java index c64618805..4b4a8aaf5 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/application/service/handoverTaskOrder/HandoverTaskOrderApplicationService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/application/service/handoverTaskOrder/HandoverTaskOrderApplicationService.java @@ -268,11 +268,13 @@ public class HandoverTaskOrderApplicationService { // 1. PDA上传图片插入交接作业单 handoverTaskOrderService.update(new LambdaUpdateWrapper() .eq(HandoverTaskOrder::getOrderNumber, orderNumber) + .set(HandoverTaskOrder::getBillingJson, handoverTaskOrderDO.getBillingJson()) .set(HandoverTaskOrder::getPictureApp, handoverTaskOrderDO.getPictureApp())); // 2. PDA上传图片插入出库管理,状态改为已出库 stockOutOrderService.update(new LambdaUpdateWrapper() .eq(StockOutOrder::getOutOrderNumber, orderNumber) .set(StockOutOrder::getStatus, "9") + .set(StockOutOrder::getBillingJson, handoverTaskOrderDO.getBillingJson()) .set(StockOutOrder::getPictureApp, handoverTaskOrderDO.getPictureApp())); // 3. 参考PC端完成交接:根据orderNumber查询交接单ID,执行库存扣减+交接状态更新 List handoverList = handoverTaskOrderService.list( @@ -286,8 +288,9 @@ public class HandoverTaskOrderApplicationService { if (!handoverTaskOrderIds.isEmpty()) { HandoverTaskOrderDO completeDO = new HandoverTaskOrderDO(); completeDO.setHandoverTaskOrderIds(handoverTaskOrderIds); + completeDO.setBillingJson(handoverTaskOrderDO.getBillingJson()); handoverTaskOrderDomainService.completeHandover(completeDO); } } } -} +} \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockInOrder/StockInOrderApplicationService.java b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockInOrder/StockInOrderApplicationService.java index b2de72033..f49ab7ca3 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockInOrder/StockInOrderApplicationService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockInOrder/StockInOrderApplicationService.java @@ -3,7 +3,12 @@ package com.mhd.wms.application.service.stockInOrder; import cn.hutool.core.util.ObjectUtil; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; import com.alibaba.fastjson2.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.mhd.common.core.domain.dto.BusinessDataPushDTO; import com.mhd.common.core.domain.po.UserPo; import com.mhd.common.core.enums.DictCode; import com.mhd.common.core.exception.ServiceException; @@ -11,6 +16,7 @@ import com.mhd.common.core.utils.StringUtils; import com.mhd.common.core.utils.poi.ExcelUtil; import com.mhd.common.core.web.domain.AjaxResult; import com.mhd.common.security.utils.SecurityUtils; +import com.mhd.system.api.BmsServiceFeign; import com.mhd.system.api.SystemServiceFeign; import com.mhd.system.api.UserServiceFeign; import com.mhd.system.api.domain.SysDictData; @@ -18,17 +24,29 @@ import com.mhd.system.api.domain.WarehouseFeignPO; 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.handoverTaskOrder.entity.HandoverTaskOrder; +import com.mhd.wms.domain.handoverTaskOrder.repository.facade.IHandoverTaskOrderService; import com.mhd.wms.domain.inMaterialDetail.entity.InMaterialDetail; import com.mhd.wms.domain.inMaterialDetail.repository.todo.InMaterialDetailDO; import com.mhd.wms.domain.materialBaseInfo.entity.MaterialBaseInfo; import com.mhd.wms.domain.materialBaseInfo.repository.facade.IMaterialBaseInfoService; import com.mhd.wms.domain.materialBaseInfo.repository.po.MaterialBaseInfoPO; import com.mhd.wms.domain.materialBaseInfo.repository.todo.MaterialBaseInfoDO; +import com.mhd.wms.domain.receiptOrderAccount.entity.ReceiptOrderAccount; +import com.mhd.wms.domain.receiptOrderAccount.repository.facade.IReceiptOrderAccountService; +import com.mhd.wms.domain.stockInOrder.entity.StockInOrder; +import com.mhd.wms.domain.stockInOrder.repository.facade.IStockInOrderService; import com.mhd.wms.domain.stockInOrder.entity.StockInOrder; import com.mhd.wms.domain.stockInOrder.repository.po.StockInOrderPO; import com.mhd.wms.domain.stockInOrder.repository.todo.StockInOrderDO; import com.mhd.wms.domain.stockInOrder.service.StockInOrderDomainService; import com.mhd.wms.interfaces.dto.stockInOrder.StockInOrderDTO; +import com.mhd.wms.domain.stockOutOrder.entity.StockOutOrder; +import com.mhd.wms.domain.stockOutOrder.repository.facade.IStockOutOrderService; +import com.mhd.wms.domain.stockOutOrder.repository.todo.StockOutOrderDO; +import com.mhd.wms.domain.stockReceiptOrder.entity.StockReceiptOrder; +import com.mhd.wms.domain.stockReceiptOrder.repository.facade.IStockReceiptOrderService; +import com.mhd.wms.domain.stockReceiptOrder.repository.todo.StockReceiptOrderDO; import com.mhd.wms.interfaces.dto.stockInOrder.StockInOrderImportRowDTO; import lombok.extern.slf4j.Slf4j; import org.apache.poi.ss.usermodel.*; @@ -37,6 +55,7 @@ import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.springframework.web.multipart.MultipartFile; +import javax.annotation.Resource; import java.io.InputStream; import java.math.BigDecimal; import java.text.ParseException; @@ -58,12 +77,24 @@ import java.util.stream.Collectors; public class StockInOrderApplicationService { @Autowired private StockInOrderDomainService stockInOrderDomainService; - @Autowired + @Resource private UserServiceFeign userServiceFeign; - @Autowired + @Resource private SystemServiceFeign systemServiceFeign; + @Resource + private BmsServiceFeign bmsServiceFeign; @Autowired private IMaterialBaseInfoService materialBaseInfoService; + @Resource + private IReceiptOrderAccountService receiptOrderAccountService; + @Autowired + private IStockInOrderService stockInOrderService; + @Autowired + private IStockReceiptOrderService stockReceiptOrderService; + @Autowired + private IStockOutOrderService stockOutOrderService; + @Autowired + private IHandoverTaskOrderService handoverTaskOrderService; /** @@ -157,7 +188,13 @@ public class StockInOrderApplicationService { } } } - return stockInOrderDomainService.queryList(stockInOrderDO); + List stockInOrderPOS = stockInOrderDomainService.queryList(stockInOrderDO); + for (StockInOrderPO stockInOrderPO : stockInOrderPOS) { + Long inOrderId = stockInOrderPO.getInOrderId(); + List list = receiptOrderAccountService.list(new LambdaQueryWrapper().eq(ReceiptOrderAccount::getOrderId, inOrderId)); + stockInOrderPO.setReceiptOrderAccountList(list); + } + return stockInOrderPOS; } @@ -203,6 +240,176 @@ public class StockInOrderApplicationService { return stockInOrderDomainService.update(stockInOrderDO); } + public Boolean saveAmount(StockInOrderDO stockInOrderDO) { + boolean r = true; + Long inOrderId = stockInOrderDO.getInOrderId(); + String inOrderNumber = stockInOrderDO.getInOrderNumber(); + String billingJson = stockInOrderDO.getBillingJson(); + if (billingJson != null) { + stockInOrderService.update(null,new LambdaUpdateWrapper().set(StockInOrder::getBillingJson,billingJson).eq(StockInOrder::getInOrderId,inOrderId)); + stockReceiptOrderService.update(null,new LambdaUpdateWrapper().set(StockReceiptOrder::getBillingJson,billingJson).eq(StockReceiptOrder::getInOrderNumber,inOrderNumber)); + } + receiptOrderAccountService.remove(new QueryWrapper().lambda().eq(ReceiptOrderAccount::getOrderId, inOrderId)); + List receiptOrderAccountList = stockInOrderDO.getReceiptOrderAccountList(); + if (receiptOrderAccountList != null && !receiptOrderAccountList.isEmpty()) { + for (ReceiptOrderAccount receiptOrderAccount : receiptOrderAccountList) { + receiptOrderAccount.setOrderId(inOrderId); + } + r = receiptOrderAccountService.saveBatch(receiptOrderAccountList); + wholeRentSynchronizationZXF(inOrderId); + } + return r; + } + + public Boolean saveOutAmount(StockOutOrderDO stockOutOrderDO) { + boolean r = true; + Long outOrderId = stockOutOrderDO.getOutOrderId(); + String outOrderNumber = stockOutOrderDO.getOutOrderNumber(); + String billingJson = stockOutOrderDO.getBillingJson(); + if (billingJson != null) { + stockOutOrderService.update(null,new LambdaUpdateWrapper().set(StockOutOrder::getBillingJson,billingJson).eq(StockOutOrder::getOutOrderId,outOrderId)); + handoverTaskOrderService.update(null,new LambdaUpdateWrapper().set(HandoverTaskOrder::getBillingJson,billingJson).eq(HandoverTaskOrder::getOrderNumber,outOrderNumber)); + } + receiptOrderAccountService.remove(new QueryWrapper().lambda().eq(ReceiptOrderAccount::getOrderId, outOrderId)); + List receiptOrderAccountList = stockOutOrderDO.getReceiptOrderAccountList(); + if (receiptOrderAccountList != null && !receiptOrderAccountList.isEmpty()) { + for (ReceiptOrderAccount receiptOrderAccount : receiptOrderAccountList) { + receiptOrderAccount.setOrderId(outOrderId); + } + r = receiptOrderAccountService.saveBatch(receiptOrderAccountList); + wholeRentSynchronizationZXF(outOrderId); + } + return r; + } + + /** + * 定时任务整租推送到bms装卸费 + */ + public void wholeRentSynchronizationZXF(Long busId) { + StockInOrder stockInOrder = stockInOrderService.getOne(new QueryWrapper().lambda().eq(StockInOrder::getInOrderId, busId),false); + StockOutOrder stockOutOrder = stockOutOrderService.getOne(new QueryWrapper().lambda().eq(StockOutOrder::getOutOrderId, busId),false); + if (stockInOrder != null) { + Long shipperId = stockInOrder.getShipperId(); + Long organizationId = stockInOrder.getOrganizationId(); + String organizationName = stockInOrder.getOrganizationName(); + Long topOrganizationId = stockInOrder.getTopOrganizationId(); + String inOrderNumber = stockInOrder.getInOrderNumber(); + String settlementCurrency = stockInOrder.getSettlementCurrency(); + String salesmanId = stockInOrder.getSalesmanId(); + List accounts = receiptOrderAccountService.list(new QueryWrapper().lambda().eq(ReceiptOrderAccount::getOrderId, busId)); + for (ReceiptOrderAccount account : accounts) { + BigDecimal amount = account.getAmount(); + String subjectCode = account.getSubjectCode(); + String subjectName = account.getSubjectName(); + + String serviceItemsCode = account.getServiceItemsCode(); + if (shipperId == null) { + continue; + } + BusinessDataPushDTO businessDataPushDTO = new BusinessDataPushDTO(); + businessDataPushDTO.setOrganizationId(organizationId); + businessDataPushDTO.setTopOrganizationId(topOrganizationId); + businessDataPushDTO.setOrganizationName(organizationName); + businessDataPushDTO.setBelongModuleCode("wms"); + businessDataPushDTO.setBillAmount(account.getAmount());//计费金额 + businessDataPushDTO.setEstimatedCost(account.getSettlementAmount());//计算金额 + businessDataPushDTO.setOriginalBusinessNum(inOrderNumber); + String amountJson = account.getAmountJson(); + if (amountJson != null) { + List> billingParamsList = JSON.parseObject(amountJson, new TypeReference>>() {}); + com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject(); + for (Map stringObjectMap : billingParamsList) { + String isFee = (String) stringObjectMap.get("isFee"); + if ("1".equals(isFee)) { + jsonObject.put((String) stringObjectMap.get("fields"), stringObjectMap.get("price")); + } else { + jsonObject.put((String) stringObjectMap.get("fields"), stringObjectMap.get("num")); + } + } + businessDataPushDTO.setDocumentFormJson(jsonObject.toJSONString()); + } + /*if ("装卸费".equals(subjectName)) { + jsonObject.put("loading_unloading_unit_price", account.getPrice());//装卸货单价 + jsonObject.put("cargo_quantity",account.getNum());//货物数量 + } else if ("贴标费".equals(subjectName)) { + jsonObject.put("wooden_case_labeling_unit_price", account.getPrice());//木箱单价 + jsonObject.put("carton_labeling_unit_price",account.getPrice());//纸箱单价 + jsonObject.put("wooden_case_quantity",account.getNum());//木箱数量 + jsonObject.put("carton_quantity",account.getNum());//纸箱数量 + } else if ("进出仓操作费".equals(subjectName)) { + jsonObject.put("cargo_quantity", account.getNum());//货物数量 + jsonObject.put("warehouse_handling_unit_price",account.getPrice());//进出仓操作费单价 + }*/ + + businessDataPushDTO.setDocumentTypeCode("WMS_ckjccd"); + businessDataPushDTO.setSettlementEntityId(shipperId); + businessDataPushDTO.setSecondSubjectCode(subjectCode); + businessDataPushDTO.setServiceItemsCode(serviceItemsCode); + businessDataPushDTO.setDataSources(1); + businessDataPushDTO.setTaxRate(account.getRate()); + + businessDataPushDTO.setSettlementCurrency(settlementCurrency); + businessDataPushDTO.setSalesmanId(salesmanId); + if (amount != null&&amount.compareTo(BigDecimal.ZERO)!=0) { + bmsServiceFeign.wholeRentSynchronizationZXF(businessDataPushDTO); + } + } + } else if (stockOutOrder != null) { + Long shipperId = stockOutOrder.getShipperId(); + Long organizationId = stockOutOrder.getOrganizationId(); + String organizationName = stockOutOrder.getOrganizationName(); + Long topOrganizationId = stockOutOrder.getTopOrganizationId(); + String inOrderNumber = stockOutOrder.getOutOrderNumber(); + String settlementCurrency = stockOutOrder.getSettlementCurrency(); + String salesmanId = stockOutOrder.getSalesmanId(); + List accounts = receiptOrderAccountService.list(new QueryWrapper().lambda().eq(ReceiptOrderAccount::getOrderId, busId)); + for (ReceiptOrderAccount account : accounts) { + String subjectCode = account.getSubjectCode(); + String subjectName = account.getSubjectName(); + String serviceItemsCode = account.getServiceItemsCode(); + if (shipperId == null) { + continue; + } + BusinessDataPushDTO businessDataPushDTO = new BusinessDataPushDTO(); + businessDataPushDTO.setOrganizationId(organizationId); + businessDataPushDTO.setTopOrganizationId(topOrganizationId); + businessDataPushDTO.setOrganizationName(organizationName); + businessDataPushDTO.setBelongModuleCode("wms"); + businessDataPushDTO.setBillAmount(account.getAmount());//计费金额 + businessDataPushDTO.setEstimatedCost(account.getSettlementAmount());//计算金额 + businessDataPushDTO.setOriginalBusinessNum(inOrderNumber); + String amountJson = account.getAmountJson(); + if (amountJson!=null) { + List> billingParamsList = JSON.parseObject(amountJson, new TypeReference>>() {}); + com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject(); + for (Map stringObjectMap : billingParamsList) { + String isFee = (String) stringObjectMap.get("isFee"); + if ("1".equals(isFee)) { + jsonObject.put((String) stringObjectMap.get("fields"), stringObjectMap.get("price")); + } else { + jsonObject.put((String) stringObjectMap.get("fields"), stringObjectMap.get("num")); + } + } + businessDataPushDTO.setDocumentFormJson(jsonObject.toJSONString()); + } + businessDataPushDTO.setDocumentTypeCode("WMS_ckjccd"); + businessDataPushDTO.setSettlementEntityId(shipperId); + businessDataPushDTO.setSecondSubjectCode(subjectCode); + businessDataPushDTO.setServiceItemsCode(serviceItemsCode); + businessDataPushDTO.setDataSources(1); + businessDataPushDTO.setTaxRate(account.getRate()); + + businessDataPushDTO.setSettlementCurrency(settlementCurrency); + businessDataPushDTO.setSalesmanId(salesmanId); + bmsServiceFeign.wholeRentSynchronizationZXF(businessDataPushDTO); + } + } else { + throw new RuntimeException("未找到业务单!"); + } + + log.info("定时任务整租推送到bms触发--结束"); + } + /** * 批量删除入库单 * 只有已创建状态(status = 1)的入库单可以删除 @@ -1640,6 +1847,21 @@ public class StockInOrderApplicationService { stockInOrderDO.setWarehouseName(warehouseFeignPO.getWarehouseName()); } + /** + * 导入入库单:解析出的货主用户是否属于当前登录用户同一组织(organizationId)。 + * 仅当登录用户带有 organizationId 时启用过滤;否则保持与旧行为一致。 + */ + private boolean shipperMatchesImporterOrganization(UserPo userPo, Long loginOrganizationId) { + if (loginOrganizationId == null) { + return true; + } + if (userPo == null) { + return false; + } + Long oid = userPo.getOrganizationId(); + return oid != null && loginOrganizationId.equals(oid); + } + /** * @description 根据货主名称或编号获取货主ID(用于导入时提前获取货主ID) * @param shipperName 货主名称 @@ -1650,7 +1872,13 @@ public class StockInOrderApplicationService { if (StringUtils.isBlank(shipperName) && StringUtils.isBlank(shipperCode)) { return null; } - + + Long loginOrganizationId = null; + LoginUser loginUser = SecurityUtils.getLoginUser(); + if (loginUser != null && loginUser.getUserPo() != null) { + loginOrganizationId = loginUser.getUserPo().getOrganizationId(); + } + Long shipperId = null; // 优先尝试:如果名称是纯数字,可能是误传的ID,直接按ID查询 @@ -1660,29 +1888,37 @@ public class StockInOrderApplicationService { AjaxResult ajaxResult = userServiceFeign.getInfo(possibleId); if ("200".equals(String.valueOf(ajaxResult.get("code"))) && ajaxResult.get("data") != null) { UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class); - if (userPo != null) { + if (userPo != null && shipperMatchesImporterOrganization(userPo, loginOrganizationId)) { shipperId = userPo.getUserId(); - log.info("根据货主名称(实际为ID)找到货主ID:{}", shipperId); + log.info("根据货主名称(实际为ID)找到货主ID:{},organizationId={}", shipperId, loginOrganizationId); return shipperId; } + if (userPo != null) { + log.info("按ID查到用户但与当前登录组织不一致,忽略。userId={},货主organizationId={},当前登录organizationId={}", + userPo.getUserId(), userPo.getOrganizationId(), loginOrganizationId); + } } } catch (Exception e) { log.debug("尝试将货主名称作为ID查询失败,货主名称:{},错误:{}", shipperName, e.getMessage()); } } - // 如果仍未找到,尝试根据名称查询 + // 如果仍未找到,尝试根据名称查询(用户中心 user_name 等值匹配) if (shipperId == null && StringUtils.isNotEmpty(shipperName) && !shipperName.matches("\\d+")) { try { AjaxResult ajaxResult = userServiceFeign.getInfoByName(shipperName); String code = String.valueOf(ajaxResult.get("code")); if ("200".equals(code) && ajaxResult.get("data") != null) { UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class); - if (userPo != null) { + if (userPo != null && shipperMatchesImporterOrganization(userPo, loginOrganizationId)) { shipperId = userPo.getUserId(); - log.info("根据货主名称找到货主ID,货主名称:{},货主ID:{}", shipperName, shipperId); + log.info("根据货主名称找到货主ID,货主名称:{},货主ID:{},organizationId={}", shipperName, shipperId, loginOrganizationId); return shipperId; } + if (userPo != null) { + log.info("按名称查到用户但与当前登录组织不一致,继续从货主列表匹配。userId={},货主organizationId={},当前登录organizationId={}", + userPo.getUserId(), userPo.getOrganizationId(), loginOrganizationId); + } } } catch (Exception e) { log.debug("根据货主名称查询失败,货主名称:{},错误:{}", shipperName, e.getMessage()); @@ -1752,10 +1988,23 @@ public class StockInOrderApplicationService { } if (matched && userId != null) { - shipperId = Long.valueOf(String.valueOf(userId)); - log.info("从货主列表中找到货主ID,货主名称:{},货主编号:{},货主ID:{}", - shipperName, shipperCode, shipperId); - return shipperId; + Long candidateId = Long.valueOf(String.valueOf(userId)); + try { + AjaxResult infoRes = userServiceFeign.getInfo(candidateId); + if ("200".equals(String.valueOf(infoRes.get("code"))) && infoRes.get("data") != null) { + UserPo up = JSON.parseObject(JSONObject.toJSONString(infoRes.get("data")), UserPo.class); + if (shipperMatchesImporterOrganization(up, loginOrganizationId)) { + shipperId = candidateId; + log.info("从货主列表中找到货主ID,货主名称:{},货主编号:{},货主ID:{},organizationId={}", + shipperName, shipperCode, shipperId, loginOrganizationId); + return shipperId; + } + log.info("货主列表匹配到用户但与当前登录组织不一致,跳过。userId={},货主organizationId={},当前登录organizationId={}", + candidateId, up != null ? up.getOrganizationId() : null, loginOrganizationId); + } + } catch (Exception ex) { + log.debug("校验货主组织时查询用户信息失败,userId={},{}", candidateId, ex.getMessage()); + } } } } diff --git a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockOutOrder/StockOutOrderApplicationService.java b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockOutOrder/StockOutOrderApplicationService.java index 12b404e10..0349a3ff3 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockOutOrder/StockOutOrderApplicationService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockOutOrder/StockOutOrderApplicationService.java @@ -40,6 +40,8 @@ import com.mhd.wms.domain.outMaterialDetail.service.OutMaterialDetailDomainServi import com.mhd.wms.domain.pickingMaterialDetail.repository.facade.IPickingMaterialDetailService; import com.mhd.wms.domain.pickingMaterialDetail.repository.po.PickingMaterialDetailPO; import com.mhd.wms.domain.stockInOrder.entity.StockInOrder; +import com.mhd.wms.domain.receiptOrderAccount.entity.ReceiptOrderAccount; +import com.mhd.wms.domain.receiptOrderAccount.repository.facade.IReceiptOrderAccountService; import com.mhd.wms.domain.stockOutOrder.entity.StockOutOrder; import com.mhd.wms.domain.stockOutOrder.repository.facade.IStockOutOrderService; import com.mhd.wms.domain.stockOutOrder.repository.po.StockOutOrderPO; @@ -86,6 +88,8 @@ public class StockOutOrderApplicationService { private IOutMaterialDetailService outMaterialDetailService; @Autowired private IPickingMaterialDetailService pickingMaterialDetailService; + @Autowired + private IReceiptOrderAccountService receiptOrderAccountService; /** @@ -212,6 +216,8 @@ public class StockOutOrderApplicationService { // 复核总数量:从out_material_detail汇总check_quantity BigDecimal checkSum = materialDetailList.stream().map(OutMaterialDetailPO::getCheckQuantity).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add); stockOutOrderPO.setCheckQuantity(checkSum); + List list = receiptOrderAccountService.list(new LambdaQueryWrapper().eq(ReceiptOrderAccount::getOrderId, stockOutOrderPO.getOutOrderId())); + stockOutOrderPO.setReceiptOrderAccountList(list); } return stockOutOrderPOS; } @@ -868,12 +874,32 @@ public class StockOutOrderApplicationService { */ public Boolean cancelAssign(StockOutOrderDO stockOutOrderDO){ StockOutOrderPO infoChildren = getInfoChildren(stockOutOrderDO.getOutOrderId()); - BigDecimal alreadyAllocationQuantityAll = infoChildren.getMaterialDetailList().stream().map(OutMaterialDetailPO::getAlreadyAllocationQuantity) - .filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal alreadyAllocationQuantityAll = BigDecimal.ZERO; + if (infoChildren != null && !CollectionUtils.isEmpty(infoChildren.getMaterialDetailList())) { + for (OutMaterialDetailPO line : infoChildren.getMaterialDetailList()) { + alreadyAllocationQuantityAll = alreadyAllocationQuantityAll.add(sumAlreadyAllocationInclusive(line)); + } + } stockOutOrderDO.setAlreadyAllocationQuantityAll(alreadyAllocationQuantityAll); return stockOutOrderDomainService.cancelAssign(stockOutOrderDO); } + /** 计划行(含子行)已分配数量之和,用于单头汇总、取消分配等 */ + private static BigDecimal sumAlreadyAllocationInclusive(OutMaterialDetailPO node) { + if (node == null) { + return BigDecimal.ZERO; + } + BigDecimal s = node.getAlreadyAllocationQuantity() != null ? node.getAlreadyAllocationQuantity() : BigDecimal.ZERO; + List ch = node.getChildren(); + if (CollectionUtils.isEmpty(ch)) { + return s; + } + for (OutMaterialDetailPO c : ch) { + s = s.add(sumAlreadyAllocationInclusive(c)); + } + return s; + } + /** * @description 手动取消分配(点击确认后直接取消分配) * @author ZhouGY @@ -1057,16 +1083,15 @@ public class StockOutOrderApplicationService { outMaterialDetailDO.setAllowModify(2); //未分配过货 统计到当前分配单作业分配数 } - totalAllocationQuantity = outMaterialDetailDO.getAllocationQuantity(); + // 主行「已分配数量」仅记主行本行分配量;子行各自带自己的已分配,不累加到主行(避免双库位时主项显示成主+子) + BigDecimal parentAllocationQuantity = outMaterialDetailDO.getAllocationQuantity(); //判断是否存在子项 List returnOutMaterialDetailDOChildList = new ArrayList<>(); List outMaterialDetailDOChildList = outMaterialDetailDO.getChildren(); if (!CollectionUtils.isEmpty(outMaterialDetailDOChildList)){ - BigDecimal totalNowAllocationQuantity = BigDecimal.ZERO;//当前作业分配数量 for (OutMaterialDetailDO outMaterialDetailDOChild : outMaterialDetailDOChildList){ OutMaterialDetailPO outMaterialDetailPOChildDb = outMaterialDetailDbMap.get(outMaterialDetailDOChild.getMaterialDetailId()); if (outMaterialDetailPOChildDb != null){ - totalAllocationQuantity = totalAllocationQuantity.add(outMaterialDetailDOChild.getAllocationQuantity()); returnOutMaterialDetailDOChildList.add(outMaterialDetailDOChild); continue; } @@ -1088,11 +1113,9 @@ public class StockOutOrderApplicationService { returnOutMaterialDetailDOChild.setLevel(2); returnOutMaterialDetailDOChild.setParentUniqueId(outMaterialDetailPO.getUniqueId()); returnOutMaterialDetailDOChildList.add(returnOutMaterialDetailDOChild); - totalAllocationQuantity = totalAllocationQuantity.add(returnOutMaterialDetailDOChild.getAllocationQuantity()); } } - //主单当分配作业数量和 - outMaterialDetailDO.setAlreadyAllocationQuantity(totalAllocationQuantity); + outMaterialDetailDO.setAlreadyAllocationQuantity(parentAllocationQuantity); OutMaterialDetailDO returnOutMaterialDetailDO = new OutMaterialDetailDO(); BeanUtils.copyProperties(outMaterialDetailPO, returnOutMaterialDetailDO); BeanUtils.copyProperties(outMaterialDetailDO, returnOutMaterialDetailDO, IgnoreNullUtil.getNullPropertyNames(outMaterialDetailDO)); @@ -1122,6 +1145,21 @@ public class StockOutOrderApplicationService { stockOutOrderDO.setWarehouseName(warehouseFeignPO.getWarehouseName()); } + /** + * 出库单按名称/ID解析货主:解析出的用户是否属于当前登录用户同一组织(organizationId)。 + * 仅当登录用户带有 organizationId 时启用过滤;否则保持与旧行为一致。 + */ + private boolean shipperMatchesImporterOrganization(UserPo userPo, Long loginOrganizationId) { + if (loginOrganizationId == null) { + return true; + } + if (userPo == null) { + return false; + } + Long oid = userPo.getOrganizationId(); + return oid != null && loginOrganizationId.equals(oid); + } + /** * @description 封装货主信息 * @author ZhouGY @@ -1130,12 +1168,23 @@ public class StockOutOrderApplicationService { */ private void shipperParam(StockOutOrderDO stockOutOrderDO){ String customerName = stockOutOrderDO.getCustomerName(); - if (customerName == null || !customerName.matches("\\d+")) { + if (StringUtils.isEmpty(customerName)) { + return; + } + Long loginOrganizationId = null; + LoginUser loginUser = SecurityUtils.getLoginUser(); + if (loginUser != null && loginUser.getUserPo() != null) { + loginOrganizationId = loginUser.getUserPo().getOrganizationId(); + } + if (!customerName.matches("\\d+")) { AjaxResult ajaxResult = userServiceFeign.getInfoByName(customerName); if(!"200".equals(String.valueOf(ajaxResult.get("code")))){ throw new ServiceException("获取客户信息失败"); } UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class); + if (!shipperMatchesImporterOrganization(userPo, loginOrganizationId)) { + throw new ServiceException("当前登录用户组织下不存在该货主信息或客户名称与组织不匹配"); + } stockOutOrderDO.setShipperId(userPo.getUserId()); stockOutOrderDO.setShipperCode(userPo.getUserMemberCode()); stockOutOrderDO.setShipperName(userPo.getUserName()); @@ -1145,6 +1194,9 @@ public class StockOutOrderApplicationService { throw new ServiceException("获取货主信息失败"); } UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class); + if (!shipperMatchesImporterOrganization(userPo, loginOrganizationId)) { + throw new ServiceException("当前登录用户组织下不存在该货主信息或客户名称与组织不匹配"); + } stockOutOrderDO.setShipperId(userPo.getUserId()); stockOutOrderDO.setShipperCode(userPo.getUserMemberCode()); stockOutOrderDO.setShipperName(userPo.getUserName()); @@ -1159,12 +1211,23 @@ public class StockOutOrderApplicationService { */ private void customerParam(StockOutOrderDO stockOutOrderDO){ String customerName = stockOutOrderDO.getCustomerName(); - if (customerName == null || !customerName.matches("\\d+")) { + if (StringUtils.isEmpty(customerName)) { + return; + } + Long loginOrganizationId = null; + LoginUser loginUser = SecurityUtils.getLoginUser(); + if (loginUser != null && loginUser.getUserPo() != null) { + loginOrganizationId = loginUser.getUserPo().getOrganizationId(); + } + if (!customerName.matches("\\d+")) { AjaxResult ajaxResult = userServiceFeign.getInfoByName(customerName); if(!"200".equals(String.valueOf(ajaxResult.get("code")))){ throw new ServiceException("获取客户信息失败"); } UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class); + if (!shipperMatchesImporterOrganization(userPo, loginOrganizationId)) { + throw new ServiceException("当前登录用户组织下不存在该客户信息或客户名称与组织不匹配"); + } stockOutOrderDO.setCustomerId(userPo.getUserId()); stockOutOrderDO.setCustomerCode(userPo.getUserMemberCode()); stockOutOrderDO.setCustomerName(userPo.getUserName()); @@ -1174,6 +1237,9 @@ public class StockOutOrderApplicationService { throw new ServiceException("获取客户信息失败"); } UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class); + if (!shipperMatchesImporterOrganization(userPo, loginOrganizationId)) { + throw new ServiceException("当前登录用户组织下不存在该客户信息或客户名称与组织不匹配"); + } stockOutOrderDO.setCustomerId(userPo.getUserId()); stockOutOrderDO.setCustomerCode(userPo.getUserMemberCode()); stockOutOrderDO.setCustomerName(userPo.getUserName()); @@ -1291,7 +1357,11 @@ public class StockOutOrderApplicationService { outMaterialDetailPOList.forEach(outMaterialDetailPO -> { BigDecimal quantity = outMaterialDetailPO.getQuantity(); // 计划数量 BigDecimal alreadyAllocationQuantity = outMaterialDetailPO.getAlreadyAllocationQuantity(); // 已分配数量 - + List ch = outMaterialDetailPO.getChildren(); + if (!CollectionUtils.isEmpty(ch)) { + alreadyAllocationQuantity = sumAlreadyAllocationInclusive(outMaterialDetailPO); + } + // 判断按钮显示类型 // 已分配数量 = 0:显示"库存分配"按钮(类型1) // 已分配数量 = 计划数量:显示"取消分配"按钮(类型2) @@ -1307,9 +1377,8 @@ public class StockOutOrderApplicationService { } // 递归处理子级 - List children = outMaterialDetailPO.getChildren(); - if (!CollectionUtils.isEmpty(children)) { - setAllocationButtonTypeRecursively(children); + if (!CollectionUtils.isEmpty(ch)) { + setAllocationButtonTypeRecursively(ch); } }); } 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 5e5eb0d24..f229ab2a6 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 @@ -39,6 +39,7 @@ import com.mhd.wms.domain.receiptMaterialDetail.repository.todo.ReceiptMaterialD import com.mhd.wms.domain.receiptMaterialDetail.service.ReceiptMaterialDetailDomainService; import com.mhd.wms.domain.receiptOrderAccount.entity.ReceiptOrderAccount; import com.mhd.wms.domain.receiptOrderAccount.repository.facade.IReceiptOrderAccountService; +import com.mhd.wms.domain.stockInOrder.repository.facade.IStockInOrderService; import com.mhd.wms.domain.stockInOrder.repository.todo.StockInOrderDO; import com.mhd.wms.domain.stockReceiptOrder.repository.po.StockReceiptOrderPO; import com.mhd.wms.domain.stockReceiptOrder.repository.todo.NoReceiptOrderDO; @@ -53,12 +54,14 @@ import org.springframework.util.CollectionUtils; import java.lang.reflect.Field; import java.math.BigDecimal; +import java.math.RoundingMode; import java.text.ParseException; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -98,6 +101,8 @@ public class StockReceiptOrderApplicationService { private IdGenerator idGenerator; @Autowired private IReceiptOrderAccountService receiptOrderAccountService; + @Autowired + private IStockInOrderService stockInOrderService; /** @@ -294,8 +299,9 @@ public class StockReceiptOrderApplicationService { stockReceiptOrderPO.setTotalGrossWeight(totalGrossWeight); stockReceiptOrderPO.setTotalVolume(totalVolume); stockReceiptOrderPO.setTotalArea(totalArea); - // 扁平化明细:将子项收货数据合并到主项 - flattenMaterialDetailList(receiptMaterialDetailPOList); + // 扁平化明细:将子项收货数据合并到主项(按汇总已收推导状态,见方法内注释) + flattenMaterialDetailList(receiptMaterialDetailPOList, + stockReceiptOrderPO.getStatus() != null && stockReceiptOrderPO.getStatus() == 3); // PC 端子项计划数量不展示:递归清空所有子项的 quantity clearChildQuantityRecursively(receiptMaterialDetailPOList); // 计算待收货数量 = 计划数量 - 已收货数量 @@ -1218,10 +1224,15 @@ public class StockReceiptOrderApplicationService { fillPendingReceiptQuantityRecursively(materialDetailList); syncReceiptQuantityCumulativeDisplayRecursively(materialDetailList); } + // pending* = plan* − already_receipt_*(主行 already* 已为全部已收汇总) fillPlanAndPendingMetricsRecursively(materialDetailList); - // PDA 绑定 total* 展示「待收」= plan − 已收;已收货行不覆盖 + // 未完成行:total* 与 pending* 同值,即「计划总的 − 全部已收」 overwriteTotalWithPendingForPdaDisplayRecursively(materialDetailList); clearChildQuantityRecursively(materialDetailList); + // 仅在未按 tab 筛明细时纠正整单头状态;筛成「待收/已收」子集时不能据子集推断整单是否已收完 + if (receiptStatus == null) { + refreshPdaReceiptOrderHeaderStatusFromDerivedPlanLines(stockReceiptOrderPO, materialDetailList); + } } return stockReceiptOrderPO; } @@ -1234,7 +1245,44 @@ public class StockReceiptOrderApplicationService { } /** - * PDA 界面「总净重/总毛重/体积/面积」绑定 total*:有计划时展示待收(pending*);无计划联表时保留原 total*(累计实绩)。 + * PDA 详情:header.status 直接来自库表;若库表仍为部分收货(2),但 flatten 后各计划主行已是收尾明细状态且整单收货数已不少于计划,则将返回头状态纠正为已收货(3),避免列表/详情长期显示「部分收货」。 + */ + private void refreshPdaReceiptOrderHeaderStatusFromDerivedPlanLines(StockReceiptOrderPO order, + List planRoots) { + if (order == null || order.getStatus() == null || order.getStatus() != 2) { + return; + } + if (CollectionUtils.isEmpty(planRoots)) { + return; + } + for (ReceiptMaterialDetailPO p : planRoots) { + if (p == null) { + continue; + } + if (p.getLevel() != null && p.getLevel() != 1) { + continue; + } + if (!isPdaTerminalReceiptDetailStatus(p.getReceiptStatus())) { + return; + } + } + BigDecimal rq = order.getReceiptQuantity() != null ? order.getReceiptQuantity() : BigDecimal.ZERO; + BigDecimal pq = order.getQuantity() != null ? order.getQuantity() : BigDecimal.ZERO; + if (rq.compareTo(pq) >= 0) { + order.setStatus(3); + } + } + + /** + * PDA:指定计划行(卡片)下分批收货子行列表(level=2),域服务已挂序列号。 + */ + public List listLevel2ChildrenByParentForApp(Long receiptOrderId, Long parentMaterialDetailId) { + return stockReceiptOrderDomainService.listLevel2ChildrenByParentForApp(receiptOrderId, parentMaterialDetailId); + } + + /** + * PDA 详情:将 total* 覆盖为待收(与 pending* 同值),便于前端仍绑 total* 时展示「计划 − 主项+子项全部已收」。 + * 回传收货时由 {@link #pickThisReceiptMetricIncrementPda} 识别并按件数比例分摊增量。 */ private void overwriteTotalWithPendingForPdaDisplayRecursively(List list) { if (CollectionUtils.isEmpty(list)) { @@ -1415,8 +1463,16 @@ public class StockReceiptOrderApplicationService { */ public Boolean receivingGoodsByApp(StockReceiptOrderDO stockReceiptOrderDO){ List list = stockReceiptOrderDO.getMaterialDetailList(); - // 超计划提示:实际收货数量 > 待收数量(计划-已收) 时,先提示确认 - checkOverPlanReceiptForApp(stockReceiptOrderDO); + StockReceiptOrderPO dbOrder = stockReceiptOrderDomainService.getInfo(stockReceiptOrderDO.getReceiptOrderId()); + if (dbOrder == null) { + throw new ServiceException("收货单不存在"); + } + ReceiptMaterialDetailDO queryAll = new ReceiptMaterialDetailDO(); + queryAll.setReceiptOrderNumber(dbOrder.getReceiptOrderNumber()); + List dbListAll = receiptMaterialDetailDomainService.queryList(queryAll); + preserveParentReceiptLineHierarchyFromDb(stockReceiptOrderDO, dbListAll); + // 超计划:按「计划父行 + 其下 level=2 子行」累计已收 算待收 + checkOverPlanReceiptForApp(stockReceiptOrderDO, dbListAll); // 记录 PDA 传入时第一项是否已有 children boolean firstItemHadChildrenBefore = !CollectionUtils.isEmpty(list) && !CollectionUtils.isEmpty(list.get(0).getChildren()); @@ -1437,6 +1493,30 @@ public class StockReceiptOrderApplicationService { && !CollectionUtils.isEmpty(listAfter.get(0).getChildren()); stockReceiptOrderDO.setPdaSkipInjectBatchChildLine(skipInjectAfterAssign); stockReceiptOrderDO.setFromPda(true); + // assign 后若仍有真实子行,不再 inject(避免与已有子项结构冲突) + boolean skipInjectAfterAssign = firstItemHadChildrenBefore + && !CollectionUtils.isEmpty(stockReceiptOrderDO.getMaterialDetailList()) + && !CollectionUtils.isEmpty(stockReceiptOrderDO.getMaterialDetailList().get(0).getChildren()); + Map dbByIdForInject = dbListAll.stream() + .filter(x -> x.getMaterialDetailId() != null) + .collect(Collectors.toMap(ReceiptMaterialDetailPO::getMaterialDetailId, Function.identity(), (a, b) -> a)); + Map dbByUidForInject = dbListAll.stream() + .filter(x -> x.getUniqueId() != null) + .collect(Collectors.toMap(ReceiptMaterialDetailPO::getUniqueId, Function.identity(), (a, b) -> a)); + int injectIdx = 0; + for (ReceiptMaterialDetailDO line : stockReceiptOrderDO.getMaterialDetailList()) { + ReceiptMaterialDetailPO dbLine = null; + if (line.getMaterialDetailId() != null) { + dbLine = dbByIdForInject.get(line.getMaterialDetailId()); + } + if (dbLine == null && line.getUniqueId() != null) { + dbLine = dbByUidForInject.get(line.getUniqueId()); + } + if (dbLine != null && !(skipInjectAfterAssign && injectIdx == 0)) { + injectPdaFlatReceiptAsSyntheticChild(line, dbLine, dbListAll); + } + injectIdx++; + } StockReceiptOrderDO assembleStockReceiptOrderDO = assembleParamByReceipt(stockReceiptOrderDO, false); if (CollectionUtils.isEmpty(assembleStockReceiptOrderDO.getMaterialDetailList())) { throw new ServiceException("无有效收货数据,请确认已填写收货数量(收货数量不能全部为0)"); @@ -1445,17 +1525,13 @@ public class StockReceiptOrderApplicationService { return stockReceiptOrderDomainService.receivingGoods(assembleStockReceiptOrderDO); } - private void checkOverPlanReceiptForApp(StockReceiptOrderDO stockReceiptOrderDO) { + private void checkOverPlanReceiptForApp(StockReceiptOrderDO stockReceiptOrderDO, List dbList) { if (stockReceiptOrderDO == null || CollectionUtils.isEmpty(stockReceiptOrderDO.getMaterialDetailList())) { return; } - StockReceiptOrderPO dbOrder = stockReceiptOrderDomainService.getInfo(stockReceiptOrderDO.getReceiptOrderId()); - if (dbOrder == null) { + if (CollectionUtils.isEmpty(dbList)) { return; } - ReceiptMaterialDetailDO queryDO = new ReceiptMaterialDetailDO(); - queryDO.setReceiptOrderNumber(dbOrder.getReceiptOrderNumber()); - List dbList = receiptMaterialDetailDomainService.queryList(queryDO); Map dbById = dbList.stream() .filter(x -> x.getMaterialDetailId() != null) .collect(Collectors.toMap(ReceiptMaterialDetailPO::getMaterialDetailId, Function.identity(), (a, b) -> a)); @@ -1470,6 +1546,9 @@ public class StockReceiptOrderApplicationService { /** * 方案二子行 level=2 在库中 quantity 常为 0,不能再用单行 plan-already 校验,须按计划父行汇总已收。 */ + /** + * 分批收货:计划数量在 level=1 父行;待收 = 计划父行 quantity −(父行+其下 level=2 子行 already_receipt 汇总) + */ private void validateOverPlanNode(ReceiptMaterialDetailDO item, Map dbById, Map dbByUniqueId, @@ -1578,6 +1657,316 @@ public class StockReceiptOrderApplicationService { return sum.compareTo(BigDecimal.ZERO) > 0; } + /** 雪花/长整型 id 相较,避免部分环境下引用类型不一致 */ + private static boolean sameLongId(Long a, Long b) { + if (a == null || b == null) { + return false; + } + return a.longValue() == b.longValue(); + } + + /** + * 是否为本计划父行下的 level=2 实子行(可参与已收汇总)。 + * 排除 parent_unique_id 空/0;排除与主行同 unique_id 的镜像行(同源只计主行对象一次)。 + */ + private static boolean isLevel2ChildRowUnderPlanParent(ReceiptMaterialDetailPO planParent, ReceiptMaterialDetailPO x) { + if (planParent == null || x == null) { + return false; + } + if (x.getLevel() == null || x.getLevel() != 2) { + return false; + } + Long puid = x.getParentUniqueId(); + if (puid == null || Long.valueOf(0).equals(puid)) { + return false; + } + Long uid = planParent.getUniqueId(); + Long inUid = planParent.getInUniqueId(); + boolean linked = (uid != null && sameLongId(uid, puid)) || (inUid != null && sameLongId(inUid, puid)); + if (!linked) { + return false; + } + if (planParent.getUniqueId() != null && sameLongId(planParent.getUniqueId(), x.getUniqueId())) { + return false; + } + return true; + } + + /** 计划父行:level=1 自身;level=2 则按 parent_unique_id 找到主计划行 */ + private static ReceiptMaterialDetailPO resolveReceiptPlanParentRow(ReceiptMaterialDetailPO db, + List dbList) { + if (db == null || CollectionUtils.isEmpty(dbList)) { + return db; + } + if (db.getLevel() == null || db.getLevel() == 1) { + return db; + } + if (db.getLevel() == 2 && db.getParentUniqueId() != null) { + Long puid = db.getParentUniqueId(); + for (ReceiptMaterialDetailPO x : dbList) { + if (x == null) { + continue; + } + if (puid.equals(x.getUniqueId()) || puid.equals(x.getInUniqueId())) { + return x; + } + } + } + return db; + } + + /** + * 父行自身 + 其下 level=2(parent 指向父)的已收数量之和。 + *

主行本行必须取传入的 {@code planParent} 上的累计字段,再在列表中只加子行;勿依赖在 {@code dbList} 中再次按 material_detail_id + * 匹配主行,否则 JDBC 类型/映射不一致时会出现「只加子行、主行 100 丢失」。

+ */ + private static BigDecimal sumAlreadyReceiptUnderPlanParent(ReceiptMaterialDetailPO planParent, + List dbList) { + if (planParent == null || CollectionUtils.isEmpty(dbList)) { + return BigDecimal.ZERO; + } + BigDecimal sum = planParent.getAlreadyReceiptQuantity() != null + ? planParent.getAlreadyReceiptQuantity() : BigDecimal.ZERO; + for (ReceiptMaterialDetailPO x : dbList) { + if (x == null || !isLevel2ChildRowUnderPlanParent(planParent, x)) { + continue; + } + BigDecimal ar = x.getAlreadyReceiptQuantity() != null ? x.getAlreadyReceiptQuantity() : BigDecimal.ZERO; + sum = sum.add(ar); + } + return sum; + } + + /** 与 {@link #sumAlreadyReceiptUnderPlanParent} 同范围,汇总任意「已收」指标(毛/净重、体积、面积等) */ + private static BigDecimal sumAlreadyMetricUnderPlanParent(ReceiptMaterialDetailPO planParent, + List dbList, + Function alreadyGetter) { + if (planParent == null || CollectionUtils.isEmpty(dbList) || alreadyGetter == null) { + return BigDecimal.ZERO; + } + BigDecimal base = alreadyGetter.apply(planParent); + BigDecimal sum = base != null ? base : BigDecimal.ZERO; + for (ReceiptMaterialDetailPO x : dbList) { + if (x == null || !isLevel2ChildRowUnderPlanParent(planParent, x)) { + continue; + } + BigDecimal v = alreadyGetter.apply(x); + sum = sum.add(v != null ? v : BigDecimal.ZERO); + } + return sum; + } + + /** 首笔不拆子行;已有子行或主行+子行已有累计实收时再拆 */ + private static boolean shouldPdaSplitIntoChildRow(ReceiptMaterialDetailPO dbLine, + List allDbLines) { + if (dbLine == null || CollectionUtils.isEmpty(allDbLines)) { + return true; + } + ReceiptMaterialDetailPO plan = resolveReceiptPlanParentRow(dbLine, allDbLines); + if (plan == null) { + return true; + } + Long uid = plan.getUniqueId(); + Long inUid = plan.getInUniqueId(); + boolean hasL2 = allDbLines.stream().anyMatch(x -> x != null && x.getLevel() != null && x.getLevel() == 2 + && x.getParentUniqueId() != null + && ((uid != null && uid.equals(x.getParentUniqueId())) + || (inUid != null && inUid.equals(x.getParentUniqueId())))); + if (hasL2) { + return true; + } + BigDecimal sum = sumAlreadyReceiptUnderPlanParent(plan, allDbLines); + return sum.compareTo(BigDecimal.ZERO) > 0; + } + + private static boolean isCorruptedStandaloneLineAsLevel2(ReceiptMaterialDetailPO dbLine) { + if (dbLine == null || dbLine.getLevel() == null || dbLine.getLevel() != 2) { + return false; + } + return dbLine.getParentUniqueId() == null || Objects.equals(dbLine.getParentUniqueId(), 0L); + } + + /** 合成子行挂在计划父行的 uniqueId;误标为 level=2 且无父时,按同物料 level=1 行定位 */ + private static Long resolveParentUniqueIdForPdaInjectChild(ReceiptMaterialDetailPO dbLine, + List allDbLines) { + if (dbLine == null) { + return null; + } + if (isCorruptedStandaloneLineAsLevel2(dbLine) && dbLine.getMaterialDetailId() != null + && !CollectionUtils.isEmpty(allDbLines)) { + for (ReceiptMaterialDetailPO x : allDbLines) { + if (x != null && Objects.equals(x.getMaterialDetailId(), dbLine.getMaterialDetailId()) + && x.getLevel() != null && x.getLevel() == 1) { + return x.getUniqueId(); + } + } + } + ReceiptMaterialDetailPO plan = resolveReceiptPlanParentRow(dbLine, allDbLines); + return plan != null ? plan.getUniqueId() : dbLine.getUniqueId(); + } + + /** 请求行与库主计划行 level 不一致时纠正,避免误当子行 */ + private void preserveParentReceiptLineHierarchyFromDb(StockReceiptOrderDO order, List dbList) { + if (order == null || CollectionUtils.isEmpty(order.getMaterialDetailList()) || CollectionUtils.isEmpty(dbList)) { + return; + } + Map byId = dbList.stream() + .filter(x -> x.getMaterialDetailId() != null) + .collect(Collectors.toMap(ReceiptMaterialDetailPO::getMaterialDetailId, Function.identity(), (a, b) -> a)); + Map byUid = dbList.stream() + .filter(x -> x.getUniqueId() != null) + .collect(Collectors.toMap(ReceiptMaterialDetailPO::getUniqueId, Function.identity(), (a, b) -> a)); + for (ReceiptMaterialDetailDO line : order.getMaterialDetailList()) { + ReceiptMaterialDetailPO db = null; + if (line.getMaterialDetailId() != null) { + db = byId.get(line.getMaterialDetailId()); + } + if (db == null && line.getUniqueId() != null) { + db = byUid.get(line.getUniqueId()); + } + if (db != null && db.getLevel() != null && db.getLevel() == 1 + && line.getLevel() != null && line.getLevel() == 2) { + line.setLevel(1); + line.setParentUniqueId(null); + } + } + } + + private static void stripPdaUiParentCopyChildren(ReceiptMaterialDetailDO line, ReceiptMaterialDetailPO dbLine) { + if (line == null || CollectionUtils.isEmpty(line.getChildren())) { + return; + } + Long parentUid = line.getUniqueId() != null ? line.getUniqueId() : (dbLine != null ? dbLine.getUniqueId() : null); + List realOnly = new ArrayList<>(); + for (ReceiptMaterialDetailDO c : line.getChildren()) { + if (c == null) { + continue; + } + if (parentUid != null && parentUid.equals(c.getUniqueId())) { + continue; + } + realOnly.add(c); + } + line.setChildren(realOnly); + } + + /** getInfoByApp 挂在 children 里的已落库子行,再次收货时需去掉,否则 inject 误判已有子项 */ + private static void stripPdaExistingDisplayedChildrenForResplit(ReceiptMaterialDetailDO line, ReceiptMaterialDetailPO dbLine, + List allDbLines) { + if (line == null || CollectionUtils.isEmpty(line.getChildren()) || dbLine == null || CollectionUtils.isEmpty(allDbLines)) { + return; + } + Long puid = dbLine.getUniqueId(); + Long pInUid = dbLine.getInUniqueId(); + List keep = new ArrayList<>(); + for (ReceiptMaterialDetailDO c : line.getChildren()) { + if (c == null) { + continue; + } + Long mid = c.getMaterialDetailId(); + Long cuid = c.getUniqueId(); + boolean isExistingDbChild = false; + for (ReceiptMaterialDetailPO x : allDbLines) { + if (x == null || x.getLevel() == null || x.getLevel() != 2 || x.getParentUniqueId() == null) { + continue; + } + boolean parentOk = (puid != null && puid.equals(x.getParentUniqueId())) + || (pInUid != null && pInUid.equals(x.getParentUniqueId())); + if (!parentOk) { + continue; + } + if (mid != null && mid.equals(x.getMaterialDetailId())) { + isExistingDbChild = true; + break; + } + if (cuid != null && cuid.equals(x.getUniqueId())) { + isExistingDbChild = true; + break; + } + } + if (!isExistingDbChild) { + keep.add(c); + } + } + line.setChildren(keep); + } + + private static boolean hasPdaInjectMetricIncrement(ReceiptMaterialDetailDO line, ReceiptMaterialDetailPO dbLine) { + if (line == null || dbLine == null) { + return false; + } + BigDecimal dbNet = dbLine.getAlreadyReceiptNetWeight() != null ? dbLine.getAlreadyReceiptNetWeight() : BigDecimal.ZERO; + BigDecimal dbGross = dbLine.getAlreadyReceiptGrossWeight() != null ? dbLine.getAlreadyReceiptGrossWeight() : BigDecimal.ZERO; + BigDecimal dbVol = dbLine.getAlreadyReceiptVolume() != null ? dbLine.getAlreadyReceiptVolume() : BigDecimal.ZERO; + BigDecimal dbArea = dbLine.getAlreadyReceiptArea() != null ? dbLine.getAlreadyReceiptArea() : BigDecimal.ZERO; + return pickThisReceiptMetricIncrement(line.getReceiptNetWeight(), line.getTotalNetWeight(), dbNet).compareTo(BigDecimal.ZERO) > 0 + || pickThisReceiptMetricIncrement(line.getReceiptGrossWeight(), line.getTotalGrossWeight(), dbGross).compareTo(BigDecimal.ZERO) > 0 + || pickThisReceiptMetricIncrement(line.getReceiptVolume(), line.getTotalVolume(), dbVol).compareTo(BigDecimal.ZERO) > 0 + || pickThisReceiptMetricIncrement(line.getReceiptArea(), line.getTotalArea(), dbArea).compareTo(BigDecimal.ZERO) > 0; + } + + /** + * PDA 单次仅传主行(无真实子结构需拆时):按业务可拆成一条 level=2 子行。 + * 首笔仅落主行不拆;第二笔起或已有子行再拆。脏主行(误标 level=2)纠正不受「首笔不拆」限制。 + */ + private void injectPdaFlatReceiptAsSyntheticChild(ReceiptMaterialDetailDO line, ReceiptMaterialDetailPO dbLine, + List allDbLines) { + if (line == null || dbLine == null) { + return; + } + stripPdaUiParentCopyChildren(line, dbLine); + stripPdaExistingDisplayedChildrenForResplit(line, dbLine, allDbLines); + if (dbLine.getLevel() != null && dbLine.getLevel() == 2 && !isCorruptedStandaloneLineAsLevel2(dbLine)) { + return; + } + if (!CollectionUtils.isEmpty(line.getChildren())) { + return; + } + if (!shouldPdaSplitIntoChildRow(dbLine, allDbLines) && !isCorruptedStandaloneLineAsLevel2(dbLine)) { + return; + } + BigDecimal rq = line.getReceiptQuantity(); + boolean hasQty = rq != null && rq.compareTo(BigDecimal.ZERO) > 0; + boolean hasMetricBatch = hasPdaInjectMetricIncrement(line, dbLine); + if (!hasQty && !hasMetricBatch) { + return; + } + ReceiptMaterialDetailDO child = new ReceiptMaterialDetailDO(); + BeanUtils.copyProperties(line, child, "children", "materialDetailId", "uniqueId", "level", "parentUniqueId"); + child.setUniqueId(idGenerator.snowflakeId(SnowFlakeConstants.wmsId)); + child.setChildren(null); + child.setLevel(2); + child.setParentUniqueId(resolveParentUniqueIdForPdaInjectChild(dbLine, allDbLines)); + if (hasQty) { + child.setReceiptQuantity(rq); + } + child.setReceiptGrossWeight(line.getReceiptGrossWeight()); + child.setReceiptNetWeight(line.getReceiptNetWeight()); + child.setReceiptVolume(line.getReceiptVolume()); + child.setReceiptArea(line.getReceiptArea()); + child.setTotalGrossWeight(line.getTotalGrossWeight()); + child.setTotalNetWeight(line.getTotalNetWeight()); + child.setTotalVolume(line.getTotalVolume()); + child.setTotalArea(line.getTotalArea()); + child.setAlreadyReceiptQuantity(null); + child.setAlreadyReceiptGrossWeight(null); + child.setAlreadyReceiptNetWeight(null); + child.setAlreadyReceiptVolume(null); + child.setAlreadyReceiptArea(null); + line.setChildren(Collections.singletonList(child)); + line.setReceiptQuantity(BigDecimal.ZERO); + line.setReceiptGrossWeight(null); + line.setReceiptNetWeight(null); + line.setReceiptVolume(null); + line.setReceiptArea(null); + line.setTotalGrossWeight(null); + line.setTotalNetWeight(null); + line.setTotalVolume(null); + line.setTotalArea(null); + line.setLevel(1); + line.setParentUniqueId(null); + } + /** * 收货时:将 children 中第一条的值赋给主项,并删除第一条。 * PDA 收两条时只生成 2 条(主项 + 第二条子项),主项展示第一条子项的数据。 @@ -1867,6 +2256,10 @@ public class StockReceiptOrderApplicationService { return stockReceiptOrderDomainService.completeReceipt(receiptOrderId, true); } + public void updateInOrder(StockReceiptOrderDTO stockReceiptOrderDTO){ + stockReceiptOrderDomainService.updateInOrder(stockReceiptOrderDTO); + } + public Boolean genStockShelfOrder(Long receiptOrderId){ return stockReceiptOrderDomainService.genStockShelfOrder(receiptOrderId); } @@ -2004,6 +2397,65 @@ public class StockReceiptOrderApplicationService { return totalField; } + private static boolean isApproxEqualReceiptMetric(BigDecimal a, BigDecimal b) { + if (a == null && b == null) { + return true; + } + if (a == null || b == null) { + return false; + } + return a.subtract(b).abs().compareTo(new BigDecimal("0.000001")) <= 0; + } + + /** + * PDA:详情里 total* 为「待收」= 计划 − 组内主项+子项全部已收;提交时若仍等于当前组剩余指标, + * 则按本行本次收货件数占「组内待收件数」比例分摊本次毛/净重/体积/面积增量。 + * 否则按 {@link #pickThisReceiptMetricIncrement}(累计实绩)处理。 + */ + private static BigDecimal pickThisReceiptMetricIncrementPda( + BigDecimal receiptField, + BigDecimal totalField, + BigDecimal dbSingleRowAlready, + ReceiptMaterialDetailPO dbLine, + List dbList, + Function planMetricGetter, + Function alreadyMetricGetter, + BigDecimal thisReceiptQty) { + if (receiptField != null) { + return receiptField; + } + if (totalField == null) { + return BigDecimal.ZERO; + } + if (dbLine == null || CollectionUtils.isEmpty(dbList) || thisReceiptQty == null + || thisReceiptQty.compareTo(BigDecimal.ZERO) <= 0) { + return pickThisReceiptMetricIncrement(receiptField, totalField, dbSingleRowAlready); + } + ReceiptMaterialDetailPO plan = resolveReceiptPlanParentRow(dbLine, dbList); + if (plan == null) { + return pickThisReceiptMetricIncrement(receiptField, totalField, dbSingleRowAlready); + } + BigDecimal planMetric = planMetricGetter.apply(plan); + if (planMetric == null) { + return pickThisReceiptMetricIncrement(receiptField, totalField, dbSingleRowAlready); + } + BigDecimal sumAlready = sumAlreadyMetricUnderPlanParent(plan, dbList, alreadyMetricGetter); + BigDecimal remainingMetric = planMetric.subtract(sumAlready); + if (remainingMetric.compareTo(BigDecimal.ZERO) < 0) { + remainingMetric = BigDecimal.ZERO; + } + BigDecimal planQty = plan.getQuantity() != null ? plan.getQuantity() : BigDecimal.ZERO; + BigDecimal sumAlreadyQty = sumAlreadyReceiptUnderPlanParent(plan, dbList); + BigDecimal pendingQty = planQty.subtract(sumAlreadyQty); + if (pendingQty.compareTo(BigDecimal.ZERO) <= 0) { + return pickThisReceiptMetricIncrement(receiptField, totalField, dbSingleRowAlready); + } + if (isApproxEqualReceiptMetric(totalField, remainingMetric)) { + return remainingMetric.multiply(thisReceiptQty).divide(pendingQty, 8, RoundingMode.HALF_UP); + } + return pickThisReceiptMetricIncrement(receiptField, totalField, dbSingleRowAlready); + } + /** * PC 收货确认:页面提交为「当前全量实绩」,直接取 receipt* / total* 落库,不与历史累计做差或相加。 */ @@ -2219,6 +2671,7 @@ public class StockReceiptOrderApplicationService { throw new ServiceException("收货单已完成收货"); } StockReceiptOrderDO returnStockReceiptOrderDO = new StockReceiptOrderDO(); + returnStockReceiptOrderDO.setBillingJson(stockReceiptOrderDO.getBillingJson()); returnStockReceiptOrderDO.setReceiptOrderAccountList(stockReceiptOrderDO.getReceiptOrderAccountList()); returnStockReceiptOrderDO.setUpdateTime(stockReceiptOrderDO.getUpdateTime()); returnStockReceiptOrderDO.setReceiptOrderId(stockReceiptOrderPO.getReceiptOrderId()); @@ -2282,14 +2735,25 @@ public class StockReceiptOrderApplicationService { ? receiptMaterialDetailPO.getAlreadyReceiptNetWeight() : BigDecimal.ZERO; BigDecimal dbParentGrossForGate = receiptMaterialDetailPO.getAlreadyReceiptGrossWeight() != null ? receiptMaterialDetailPO.getAlreadyReceiptGrossWeight() : BigDecimal.ZERO; - boolean hasReceiptByMetrics = pickThisReceiptMetricIncrement( + BigDecimal gateParentQty = receiptQuantity; + boolean hasReceiptByMetrics = pickThisReceiptMetricIncrementPda( receiptMaterialDetailDO.getReceiptNetWeight(), receiptMaterialDetailDO.getTotalNetWeight(), - dbParentNetForGate).compareTo(BigDecimal.ZERO) > 0 - || pickThisReceiptMetricIncrement( + dbParentNetForGate, + receiptMaterialDetailPO, + receiptMaterialDetailPODbList, + ReceiptMaterialDetailPO::getPlanNetWeight, + ReceiptMaterialDetailPO::getAlreadyReceiptNetWeight, + gateParentQty).compareTo(BigDecimal.ZERO) > 0 + || pickThisReceiptMetricIncrementPda( receiptMaterialDetailDO.getReceiptGrossWeight(), receiptMaterialDetailDO.getTotalGrossWeight(), - dbParentGrossForGate).compareTo(BigDecimal.ZERO) > 0; + dbParentGrossForGate, + receiptMaterialDetailPO, + receiptMaterialDetailPODbList, + ReceiptMaterialDetailPO::getPlanGrossWeight, + ReceiptMaterialDetailPO::getAlreadyReceiptGrossWeight, + gateParentQty).compareTo(BigDecimal.ZERO) > 0; if (!hasReceiptByMetrics && !CollectionUtils.isEmpty(children)) { for (ReceiptMaterialDetailDO c : children) { if (c == null) { @@ -2303,8 +2767,19 @@ public class StockReceiptOrderApplicationService { ? cdb.getAlreadyReceiptNetWeight() : BigDecimal.ZERO; BigDecimal cDbGross = cdb != null && cdb.getAlreadyReceiptGrossWeight() != null ? cdb.getAlreadyReceiptGrossWeight() : BigDecimal.ZERO; - if (pickThisReceiptMetricIncrement(c.getReceiptNetWeight(), c.getTotalNetWeight(), cDbNet).compareTo(BigDecimal.ZERO) > 0 - || pickThisReceiptMetricIncrement(c.getReceiptGrossWeight(), c.getTotalGrossWeight(), cDbGross).compareTo(BigDecimal.ZERO) > 0) { + BigDecimal gateChildQty = c.getReceiptQuantity() != null ? c.getReceiptQuantity() : BigDecimal.ZERO; + if (pickThisReceiptMetricIncrementPda( + c.getReceiptNetWeight(), c.getTotalNetWeight(), cDbNet, cdb, + receiptMaterialDetailPODbList, + ReceiptMaterialDetailPO::getPlanNetWeight, + ReceiptMaterialDetailPO::getAlreadyReceiptNetWeight, + gateChildQty).compareTo(BigDecimal.ZERO) > 0 + || pickThisReceiptMetricIncrementPda( + c.getReceiptGrossWeight(), c.getTotalGrossWeight(), cDbGross, cdb, + receiptMaterialDetailPODbList, + ReceiptMaterialDetailPO::getPlanGrossWeight, + ReceiptMaterialDetailPO::getAlreadyReceiptGrossWeight, + gateChildQty).compareTo(BigDecimal.ZERO) > 0) { hasReceiptByMetrics = true; break; } @@ -2347,10 +2822,22 @@ public class StockReceiptOrderApplicationService { 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); + BigDecimal childGross = pickThisReceiptMetricIncrementPda( + receiptMaterialDetailDOChild.getReceiptGrossWeight(), receiptMaterialDetailDOChild.getTotalGrossWeight(), + childDbAlreadyGross, receiptMaterialDetailPOChildDb, receiptMaterialDetailPODbList, + ReceiptMaterialDetailPO::getPlanGrossWeight, ReceiptMaterialDetailPO::getAlreadyReceiptGrossWeight, childQty); + BigDecimal childNet = pickThisReceiptMetricIncrementPda( + receiptMaterialDetailDOChild.getReceiptNetWeight(), receiptMaterialDetailDOChild.getTotalNetWeight(), + childDbAlreadyNet, receiptMaterialDetailPOChildDb, receiptMaterialDetailPODbList, + ReceiptMaterialDetailPO::getPlanNetWeight, ReceiptMaterialDetailPO::getAlreadyReceiptNetWeight, childQty); + BigDecimal childVol = pickThisReceiptMetricIncrementPda( + receiptMaterialDetailDOChild.getReceiptVolume(), receiptMaterialDetailDOChild.getTotalVolume(), + childDbAlreadyVol, receiptMaterialDetailPOChildDb, receiptMaterialDetailPODbList, + ReceiptMaterialDetailPO::getPlanVolume, ReceiptMaterialDetailPO::getAlreadyReceiptVolume, childQty); + BigDecimal childArea = pickThisReceiptMetricIncrementPda( + receiptMaterialDetailDOChild.getReceiptArea(), receiptMaterialDetailDOChild.getTotalArea(), + childDbAlreadyArea, receiptMaterialDetailPOChildDb, receiptMaterialDetailPODbList, + ReceiptMaterialDetailPO::getPlanArea, ReceiptMaterialDetailPO::getAlreadyReceiptArea, childQty); // PC 端子行常只回填 totalNetWeight/totalGrossWeight,不回传 receiptQuantity;用本次称重增量兜底为件数(与千克等重量计量物料一致) if (childQty.compareTo(BigDecimal.ZERO) == 0 && childNet.compareTo(BigDecimal.ZERO) > 0) { childQty = childNet; @@ -2429,10 +2916,22 @@ public class StockReceiptOrderApplicationService { 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 parentReceiptGross = pickThisReceiptMetricIncrementPda( + receiptMaterialDetailDO.getReceiptGrossWeight(), receiptMaterialDetailDO.getTotalGrossWeight(), + dbParentBeforeGross, receiptMaterialDetailPO, receiptMaterialDetailPODbList, + ReceiptMaterialDetailPO::getPlanGrossWeight, ReceiptMaterialDetailPO::getAlreadyReceiptGrossWeight, mainItemActualQuantity); + BigDecimal parentReceiptNet = pickThisReceiptMetricIncrementPda( + receiptMaterialDetailDO.getReceiptNetWeight(), receiptMaterialDetailDO.getTotalNetWeight(), + dbParentBeforeNet, receiptMaterialDetailPO, receiptMaterialDetailPODbList, + ReceiptMaterialDetailPO::getPlanNetWeight, ReceiptMaterialDetailPO::getAlreadyReceiptNetWeight, mainItemActualQuantity); + BigDecimal parentReceiptVol = pickThisReceiptMetricIncrementPda( + receiptMaterialDetailDO.getReceiptVolume(), receiptMaterialDetailDO.getTotalVolume(), + dbParentBeforeVol, receiptMaterialDetailPO, receiptMaterialDetailPODbList, + ReceiptMaterialDetailPO::getPlanVolume, ReceiptMaterialDetailPO::getAlreadyReceiptVolume, mainItemActualQuantity); + BigDecimal parentReceiptArea = pickThisReceiptMetricIncrementPda( + receiptMaterialDetailDO.getReceiptArea(), receiptMaterialDetailDO.getTotalArea(), + dbParentBeforeArea, receiptMaterialDetailPO, receiptMaterialDetailPODbList, + ReceiptMaterialDetailPO::getPlanArea, ReceiptMaterialDetailPO::getAlreadyReceiptArea, mainItemActualQuantity); // 主行 already_* 只累计主行本行毛净重体面积;子行各自落子行记录,避免主行重复叠加子行导致与数量口径不一致 BigDecimal mainGrossIncrement = parentReceiptGross; BigDecimal mainNetIncrement = parentReceiptNet; @@ -2490,6 +2989,11 @@ public class StockReceiptOrderApplicationService { ReceiptMaterialDetailDO returnReceiptMaterialDetailDO = new ReceiptMaterialDetailDO(); BeanUtils.copyProperties(receiptMaterialDetailPO, returnReceiptMaterialDetailDO); BeanUtils.copyProperties(receiptMaterialDetailDO, returnReceiptMaterialDetailDO, IgnoreNullUtil.getNullPropertyNames(receiptMaterialDetailDO)); + // 主行本次收货件数为 0、仅子行有收货时:不从请求覆盖主行批次号(避免 PDA 把子行新批次回写到主行,冲掉首笔批次) + if (mainItemActualQuantity.compareTo(BigDecimal.ZERO) == 0 + && !CollectionUtils.isEmpty(returnReceiptMaterialDetailDOChildList)) { + returnReceiptMaterialDetailDO.setBatchNumber(receiptMaterialDetailPO.getBatchNumber()); + } returnReceiptMaterialDetailDO.setTotalNetWeight(receiptMaterialDetailDO.getTotalNetWeight()); returnReceiptMaterialDetailDO.setTotalGrossWeight(receiptMaterialDetailDO.getTotalGrossWeight()); returnReceiptMaterialDetailDO.setTotalVolume(receiptMaterialDetailDO.getTotalVolume()); 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 b4db95550..89d4abe22 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 @@ -57,9 +57,11 @@ import org.springframework.util.CollectionUtils; import java.lang.reflect.Field; import java.math.BigDecimal; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -204,31 +206,17 @@ public class StockShelfOrderApplicationService { /** * 获取上架单详细信息 + * * @param shelfOrderId 上架单ID - * @param addParentCopyWhenNoChildren 主项无子项时是否添加 parent_copy:true-PDA 详情页从 children 读取数据需要;false-PC 端收货无子项时上架不显示虚拟子项 + * @param addParentCopyWhenNoChildren 历史参数名保留:为 true 时表示走 {@link #getInfo(Long, boolean, Integer)} 中的 PDA 详情流水线(扁平化、待上架、重量展示等);不再向 children 注入 + * parent_copy,避免与主行重复两条;无子项时由前端从主项字段读取,与 {@link com.mhd.wms.domain.stockShelfOrder.service.StockShelfOrderDomainService#getInfoByApp(Long)} 一致。为 false 时走 PC 端汇总与扁平化。 */ public StockShelfOrderPO getInfo(Long shelfOrderId, boolean addParentCopyWhenNoChildren) { StockShelfOrderPO stockShelfOrderPO = stockShelfOrderDomainService.getInfo(shelfOrderId); ShelfMaterialDetailDO shelfMaterialDetailDO = new ShelfMaterialDetailDO(); shelfMaterialDetailDO.setShelfOrderNumber(stockShelfOrderPO.getShelfOrderNumber()); List shelfMaterialDetailPOList = shelfMaterialDetailDomainService.queryListChildren(shelfMaterialDetailDO); - // PDA:主项无子项时添加 parent_copy 到 children,供详情页展示(详情页从 children 读取数据);PC:不添加,避免收货无子项时上架显示虚拟子项 - if (addParentCopyWhenNoChildren) { - for (ShelfMaterialDetailPO parent : shelfMaterialDetailPOList) { - if (CollectionUtils.isEmpty(parent.getChildren())) { - ShelfMaterialDetailPO parentCopy = new ShelfMaterialDetailPO(); - BeanUtils.copyProperties(parent, parentCopy, "children"); - parentCopy.setLevel(2); - parentCopy.setParentUniqueId(parent.getUniqueId()); - parentCopy.setQuantity(null); - parentCopy.setChildren(new ArrayList<>()); - List children = new ArrayList<>(); - children.add(parentCopy); - parent.setChildren(children); - } - } - } - + // 性能优化:批量获取批次属性,避免N+1查询问题 // 1. 收集所有唯一的materialBaseInfoId Set materialBaseInfoIdSet = shelfMaterialDetailPOList.stream() @@ -322,11 +310,40 @@ public class StockShelfOrderApplicationService { // 第一次上架:主项无子项时,上架数量默认等于收货数量(quantity 由上架单生成时取自收货数量),供 PDA 表单默认展示 fillFirstShelvesQuantityDefault(shelfMaterialDetailPOList); - + + // PC 端(addParentCopyWhenNoChildren==false):单头 total* 仍按明细树递归汇总;明细行净重/毛重/体积/面积做「计划−已上架」覆盖,保持 shelf_material_detail 库表值 + if (!addParentCopyWhenNoChildren) { + BigDecimal totalNetWeight = BigDecimal.ZERO; + BigDecimal totalGrossWeight = BigDecimal.ZERO; + BigDecimal totalVolume = BigDecimal.ZERO; + BigDecimal totalArea = BigDecimal.ZERO; + if (!CollectionUtils.isEmpty(shelfMaterialDetailPOList)) { + for (ShelfMaterialDetailPO detail : shelfMaterialDetailPOList) { + totalNetWeight = totalNetWeight.add(sumShelfDetailRecursively(detail, ShelfMaterialDetailPO::getTotalNetWeight)); + totalGrossWeight = totalGrossWeight.add(sumShelfDetailRecursively(detail, ShelfMaterialDetailPO::getTotalGrossWeight)); + totalVolume = totalVolume.add(sumShelfDetailRecursively(detail, ShelfMaterialDetailPO::getTotalVolume)); + totalArea = totalArea.add(sumShelfDetailRecursively(detail, ShelfMaterialDetailPO::getTotalArea)); + } + } + stockShelfOrderPO.setTotalNetWeight(totalNetWeight); + stockShelfOrderPO.setTotalGrossWeight(totalGrossWeight); + stockShelfOrderPO.setTotalVolume(totalVolume); + stockShelfOrderPO.setTotalArea(totalArea); + boolean shelfOrderCompleted = stockShelfOrderPO.getStatus() != null && stockShelfOrderPO.getStatus() == 3; + flattenShelfMaterialDetailList(shelfMaterialDetailPOList, shelfOrderCompleted); + clearChildQuantityShelfRecursively(shelfMaterialDetailPOList); + fillPendingShelvesQuantityRecursively(shelfMaterialDetailPOList); + syncMaterialMoreDetailWeightValuesRecursively(shelfMaterialDetailPOList); + } + stockShelfOrderPO.setMaterialDetailList(shelfMaterialDetailPOList); - log.info("返回上架单信息,shelfOrderId={}, materialDetailList大小={}", - stockShelfOrderPO.getShelfOrderId(), - shelfMaterialDetailPOList != null ? shelfMaterialDetailPOList.size() : 0); + log.info("返回上架单信息,shelfOrderId={}, materialDetailList大小={}, totalNetWeight={}, totalGrossWeight={}, totalVolume={}, totalArea={}", + stockShelfOrderPO.getShelfOrderId(), + shelfMaterialDetailPOList != null ? shelfMaterialDetailPOList.size() : 0, + stockShelfOrderPO.getTotalNetWeight(), + stockShelfOrderPO.getTotalGrossWeight(), + stockShelfOrderPO.getTotalVolume(), + stockShelfOrderPO.getTotalArea()); return stockShelfOrderPO; } @@ -351,9 +368,12 @@ public class StockShelfOrderApplicationService { if (shelfStatus != null) { materialDetailList = filterShelfMaterialDetailsByShelfStatus(materialDetailList, shelfStatus); } - // 已上架完成(3/4/5):主项无子项时注入的 parent_copy 与主项为同一明细,子行可能仍带「本次提交」的 shelves_quantity=0, - // 导致「上架数量」误显示为 0;与主项对齐累计已上架数量后再做展示计算 + // 兼容历史:若 children 中仍有镜像子行(与主项同 uniqueId),已收尾时与主项对齐累计已上架,再扁平化/剔除镜像 alignParentCopyShelfQuantityWithParentForTerminal(materialDetailList); + boolean shelfOrderCompleted = stockShelfOrderPO.getStatus() != null && stockShelfOrderPO.getStatus() == 3; + flattenShelfMaterialDetailList(materialDetailList, shelfOrderCompleted); + // 与域层 getInfoByApp 一致:不再注入 parent_copy;若旧客户端缓存等仍带镜像子行,从树中剔除以免详情列表出现两条 + removeShelfParentCopyMirrorChildrenRecursively(materialDetailList); // PDA 待上架数量 = 计划数量 - 已上架数量,仅接口计算(不落库) fillPendingShelvesQuantityRecursively(materialDetailList); // PDA 展示:shelvesQuantity 显示为累计已上架数量(与 receipt 口径一致);已上架完成行不再用本次提交量 @@ -364,10 +384,19 @@ public class StockShelfOrderApplicationService { Map planWeightMetrics = loadReceiptPlanWeightMetrics(stockShelfOrderPO.getReceiptOrderNumber()); overwriteTotalWithPendingForPdaWeightDisplayRecursively(materialDetailList, planWeightMetrics); syncMaterialMoreDetailWeightValuesRecursively(materialDetailList); + // 与收货 PDA getInfoByApp 一致:保留 children;仅清空子行「计划数量」quantity(见 clearChildQuantityRecursively),不在此剔除分库位 level=2 子行 + clearChildQuantityShelfRecursively(materialDetailList); stockShelfOrderPO.setMaterialDetailList(materialDetailList); return stockShelfOrderPO; } + /** + * PDA:按父计划行查询分批上架子行(level=2),与收货 {@link com.mhd.wms.application.service.stockReceiptOrder.StockReceiptOrderApplicationService#listLevel2ChildrenByParentForApp} 对称。 + */ + public List listLevel2ChildrenByParentForApp(Long shelfOrderId, Long parentMaterialDetailId) { + return stockShelfOrderDomainService.listLevel2ChildrenByParentForApp(shelfOrderId, parentMaterialDetailId); + } + private List filterShelfMaterialDetailsByShelfStatus(List source, Integer shelfStatus) { if (CollectionUtils.isEmpty(source) || shelfStatus == null) { return source; @@ -399,6 +428,46 @@ public class StockShelfOrderApplicationService { return true; } + /** + * 递归汇总明细及其子项的某字段值(与收货 {@link com.mhd.wms.application.service.stockReceiptOrder.StockReceiptOrderApplicationService} 中 + * sumDetailRecursively 一致,用于 PC 单头 total*) + */ + private static BigDecimal sumShelfDetailRecursively(ShelfMaterialDetailPO detail, Function getter) { + BigDecimal sum = BigDecimal.ZERO; + if (detail == null || getter == null) { + return sum; + } + BigDecimal v = getter.apply(detail); + if (v != null) { + sum = sum.add(v); + } + List children = detail.getChildren(); + if (!CollectionUtils.isEmpty(children)) { + for (ShelfMaterialDetailPO child : children) { + sum = sum.add(sumShelfDetailRecursively(child, getter)); + } + } + return sum; + } + + /** + * PC 端子项计划数量不展示:递归清空所有子项的 quantity(与收货 clearChildQuantityRecursively 一致) + */ + private void clearChildQuantityShelfRecursively(List shelfMaterialDetailPOList) { + if (CollectionUtils.isEmpty(shelfMaterialDetailPOList)) { + return; + } + for (ShelfMaterialDetailPO detail : shelfMaterialDetailPOList) { + List children = detail.getChildren(); + if (!CollectionUtils.isEmpty(children)) { + for (ShelfMaterialDetailPO child : children) { + child.setQuantity(null); + clearChildQuantityShelfRecursively(child.getChildren()); + } + } + } + } + /** * PDA 待上架数量递归计算:待上架数量 = max(0, 计划数量 - 已上架数量) */ @@ -450,6 +519,418 @@ public class StockShelfOrderApplicationService { } } + /** + * 扁平化明细:主行保留父子结构;主行「已上架数量」与上架状态仍按主行+子行汇总(与分批场景一致)。 + * 主行净重/毛重/体积/面积不再用主+子汇总覆盖,保留库表主行单行值(子行仍为自身行明细)。 + * + * @param shelfOrderCompleted 上架单是否已整单完成(status=3);为 true 时少上为 4,与域服务完成口径一致 + */ + private void flattenShelfMaterialDetailList(List shelfMaterialDetailPOList, + boolean shelfOrderCompleted) { + if (CollectionUtils.isEmpty(shelfMaterialDetailPOList)) { + return; + } + List allNodes = new ArrayList<>(); + collectShelfMaterialDetailNodesRecursively(shelfMaterialDetailPOList, allNodes); + Map> childrenByParentUid = new HashMap<>(); + for (ShelfMaterialDetailPO node : allNodes) { + if (node == null || node.getLevel() == null || node.getLevel() != 2) { + continue; + } + Long puid = node.getParentUniqueId(); + if (puid == null || Long.valueOf(0).equals(puid)) { + continue; + } + childrenByParentUid.computeIfAbsent(puid, k -> new ArrayList<>()).add(node); + } + for (ShelfMaterialDetailPO parent : shelfMaterialDetailPOList) { + if (parent == null) { + continue; + } + if (parent.getLevel() != null && parent.getLevel() != 1) { + continue; + } + BigDecimal qtySum = sumAlreadyShelvesUnderPlanParent(parent, allNodes); + Integer derived = deriveShelfStatusFromAggregatedVsPlan(qtySum, parent.getQuantity(), shelfOrderCompleted); + + parent.setAlreadyShelvesQuantity(qtySum); + if (derived != null) { + parent.setShelvesStatus(derived); + } + + LinkedHashMap mergedChildren = new LinkedHashMap<>(); + mergeShelfChildRowsIntoMap(mergedChildren, parent.getChildren()); + Long uid = parent.getUniqueId(); + Long inUid = parent.getInUniqueId(); + if (uid != null) { + mergeShelfChildRowsIntoMap(mergedChildren, childrenByParentUid.get(uid)); + } + if (inUid != null && !inUid.equals(uid)) { + mergeShelfChildRowsIntoMap(mergedChildren, childrenByParentUid.get(inUid)); + } + if (mergedChildren.isEmpty()) { + continue; + } + for (ShelfMaterialDetailPO child : mergedChildren.values()) { + if (child == null) { + continue; + } + if (parent.getUniqueId() != null && parent.getUniqueId().equals(child.getUniqueId())) { + child.setQuantity(null); + continue; + } + child.setQuantity(null); + if (derived != null && child.getLevel() != null && child.getLevel() == 2) { + child.setShelvesStatus(derived); + } + } + } + } + + /** + * 主行展示用上架状态:按「主行+子行汇总已上架」与主行计划量比较。 + */ + private static Integer deriveShelfStatusFromAggregatedVsPlan(BigDecimal aggregatedShelves, BigDecimal planQty, + boolean shelfOrderCompleted) { + BigDecimal r = aggregatedShelves != null ? aggregatedShelves : BigDecimal.ZERO; + BigDecimal p = planQty != null ? planQty : BigDecimal.ZERO; + if (shelfOrderCompleted) { + int cmp = r.compareTo(p); + if (cmp > 0) { + return 5; + } + if (cmp < 0) { + return 4; + } + return 3; + } + if (r.compareTo(BigDecimal.ZERO) == 0) { + return 1; + } + int cmp = r.compareTo(p); + if (cmp < 0) { + return 2; + } + if (cmp > 0) { + return 5; + } + return 3; + } + + private static void collectShelfMaterialDetailNodesRecursively(List list, List out) { + if (CollectionUtils.isEmpty(list)) { + return; + } + for (ShelfMaterialDetailPO n : list) { + if (n == null) { + continue; + } + out.add(n); + collectShelfMaterialDetailNodesRecursively(n.getChildren(), out); + } + } + + private static void mergeShelfChildRowsIntoMap(Map byKey, List children) { + if (CollectionUtils.isEmpty(children)) { + return; + } + for (ShelfMaterialDetailPO c : children) { + if (c == null) { + continue; + } + Long key = c.getUniqueId(); + if (key == null) { + key = c.getMaterialDetailId(); + } + if (key == null) { + continue; + } + byKey.putIfAbsent(key, c); + } + } + + private static boolean sameLongId(Long a, Long b) { + if (a == null || b == null) { + return false; + } + return a.longValue() == b.longValue(); + } + + private static boolean isLevel2ChildShelfRowUnderPlanParent(ShelfMaterialDetailPO planParent, ShelfMaterialDetailPO x) { + if (planParent == null || x == null) { + return false; + } + if (x.getLevel() == null || x.getLevel() != 2) { + return false; + } + Long puid = x.getParentUniqueId(); + if (puid == null || Long.valueOf(0).equals(puid)) { + return false; + } + Long uid = planParent.getUniqueId(); + Long inUid = planParent.getInUniqueId(); + boolean linked = (uid != null && sameLongId(uid, puid)) || (inUid != null && sameLongId(inUid, puid)); + if (!linked) { + return false; + } + if (planParent.getUniqueId() != null && sameLongId(planParent.getUniqueId(), x.getUniqueId())) { + return false; + } + return true; + } + + private static BigDecimal sumAlreadyShelvesUnderPlanParent(ShelfMaterialDetailPO planParent, + List dbList) { + if (planParent == null || CollectionUtils.isEmpty(dbList)) { + return BigDecimal.ZERO; + } + BigDecimal sum = planParent.getAlreadyShelvesQuantity() != null + ? planParent.getAlreadyShelvesQuantity() : BigDecimal.ZERO; + for (ShelfMaterialDetailPO x : dbList) { + if (x == null || !isLevel2ChildShelfRowUnderPlanParent(planParent, x)) { + continue; + } + BigDecimal ar = x.getAlreadyShelvesQuantity() != null ? x.getAlreadyShelvesQuantity() : BigDecimal.ZERO; + sum = sum.add(ar); + } + return sum; + } + + private static BigDecimal sumAlreadyShelfMetricUnderPlanParent(ShelfMaterialDetailPO planParent, + List dbList, + Function alreadyGetter) { + if (planParent == null || CollectionUtils.isEmpty(dbList) || alreadyGetter == null) { + return BigDecimal.ZERO; + } + BigDecimal base = alreadyGetter.apply(planParent); + BigDecimal sum = base != null ? base : BigDecimal.ZERO; + for (ShelfMaterialDetailPO x : dbList) { + if (x == null || !isLevel2ChildShelfRowUnderPlanParent(planParent, x)) { + continue; + } + BigDecimal v = alreadyGetter.apply(x); + sum = sum.add(v != null ? v : BigDecimal.ZERO); + } + return sum; + } + + /** + * 计划主行维度累计(重量/体面积):主行库表单行 + 树下 level=2 子行。 + * 待上架展示用「计划 − 已上架」时,子行需按整卡扣减;主行接口字段不再汇总后仍用此合计参与计算。 + */ + private static BigDecimal sumShelfPlanRowAggregatedAlreadyMetric(ShelfMaterialDetailPO planParent, + Function alreadyGetter) { + if (planParent == null || alreadyGetter == null) { + return BigDecimal.ZERO; + } + BigDecimal base = alreadyGetter.apply(planParent); + BigDecimal sum = base != null ? base : BigDecimal.ZERO; + List ch = planParent.getChildren(); + if (CollectionUtils.isEmpty(ch)) { + return sum; + } + for (ShelfMaterialDetailPO c : ch) { + if (c == null || c.getLevel() == null || c.getLevel() != 2) { + continue; + } + if (planParent.getUniqueId() != null && planParent.getUniqueId().equals(c.getUniqueId())) { + continue; + } + BigDecimal v = alreadyGetter.apply(c); + if (v != null) { + sum = sum.add(v); + } + } + return sum; + } + + /** 计划父行:level=1 自身;level=2 则按 parent_unique_id 定位主计划行(对齐收货 {@code resolveReceiptPlanParentRow}) */ + private static ShelfMaterialDetailPO resolveShelfPlanParentRow(ShelfMaterialDetailPO db, + List dbList) { + if (db == null || CollectionUtils.isEmpty(dbList)) { + return db; + } + if (db.getLevel() == null || db.getLevel() == 1) { + return db; + } + if (db.getLevel() == 2 && db.getParentUniqueId() != null) { + Long puid = db.getParentUniqueId(); + for (ShelfMaterialDetailPO x : dbList) { + if (x == null) { + continue; + } + if (puid.equals(x.getUniqueId()) || puid.equals(x.getInUniqueId())) { + return x; + } + } + } + return db; + } + + /** + * 首次可只落主行不拆;已有 level=2 子行或主行+子行已有累计已上架时再拆(对齐收货 {@code shouldPdaSplitIntoChildRow}) + */ + private static boolean shouldPdaSplitIntoShelfChildRow(ShelfMaterialDetailPO dbLine, + List allDbLines) { + if (dbLine == null || CollectionUtils.isEmpty(allDbLines)) { + return true; + } + ShelfMaterialDetailPO plan = resolveShelfPlanParentRow(dbLine, allDbLines); + if (plan == null) { + return true; + } + Long uid = plan.getUniqueId(); + Long inUid = plan.getInUniqueId(); + boolean hasL2 = allDbLines.stream().anyMatch(x -> x != null && x.getLevel() != null && x.getLevel() == 2 + && x.getParentUniqueId() != null + && ((uid != null && uid.equals(x.getParentUniqueId())) + || (inUid != null && inUid.equals(x.getParentUniqueId())))); + if (hasL2) { + return true; + } + BigDecimal sum = sumAlreadyShelvesUnderPlanParent(plan, allDbLines); + return sum.compareTo(BigDecimal.ZERO) > 0; + } + + private static boolean isCorruptedStandaloneLineAsLevel2Shelf(ShelfMaterialDetailPO dbLine) { + if (dbLine == null || dbLine.getLevel() == null || dbLine.getLevel() != 2) { + return false; + } + return dbLine.getParentUniqueId() == null || Objects.equals(dbLine.getParentUniqueId(), 0L); + } + + private static void stripPdaUiParentCopyChildrenShelf(ShelfMaterialDetailDO line, ShelfMaterialDetailPO dbLine) { + if (line == null || CollectionUtils.isEmpty(line.getChildren())) { + return; + } + Long parentUid = line.getUniqueId() != null ? line.getUniqueId() : (dbLine != null ? dbLine.getUniqueId() : null); + List realOnly = new ArrayList<>(); + for (ShelfMaterialDetailDO c : line.getChildren()) { + if (c == null) { + continue; + } + if (parentUid != null && parentUid.equals(c.getUniqueId())) { + continue; + } + realOnly.add(c); + } + line.setChildren(realOnly); + } + + /** getInfo 挂在 children 里的已落库子行,再次上架时需去掉,否则无法走「拆新子行」注入(对齐收货 stripPdaExistingDisplayedChildrenForResplit) */ + private static void stripPdaExistingDisplayedChildrenForResplitShelf(ShelfMaterialDetailDO line, + ShelfMaterialDetailPO dbLine, + List allDbLines) { + if (line == null || CollectionUtils.isEmpty(line.getChildren()) || dbLine == null || CollectionUtils.isEmpty(allDbLines)) { + return; + } + Long puid = dbLine.getUniqueId(); + Long pInUid = dbLine.getInUniqueId(); + List keep = new ArrayList<>(); + for (ShelfMaterialDetailDO c : line.getChildren()) { + if (c == null) { + continue; + } + Long mid = c.getMaterialDetailId(); + Long cuid = c.getUniqueId(); + boolean isExistingDbChild = false; + for (ShelfMaterialDetailPO x : allDbLines) { + if (x == null || x.getLevel() == null || x.getLevel() != 2 || x.getParentUniqueId() == null) { + continue; + } + boolean parentOk = (puid != null && puid.equals(x.getParentUniqueId())) + || (pInUid != null && pInUid.equals(x.getParentUniqueId())); + if (!parentOk) { + continue; + } + if (mid != null && mid.equals(x.getMaterialDetailId())) { + isExistingDbChild = true; + break; + } + if (cuid != null && cuid.equals(x.getUniqueId())) { + isExistingDbChild = true; + break; + } + } + if (!isExistingDbChild) { + keep.add(c); + } + } + line.setChildren(keep); + } + + /** 本次上架毛/净重、体积、面积增量(对齐收货 pickThisReceiptMetricIncrement;上架无 receipt* 字段,用 total*) */ + private static BigDecimal pickThisShelfMetricIncrement(BigDecimal receiptField, BigDecimal totalField, + BigDecimal dbTotalAlreadyBefore) { + if (receiptField != null) { + return receiptField; + } + if (totalField == null) { + return BigDecimal.ZERO; + } + if (dbTotalAlreadyBefore == null) { + return totalField; + } + if (totalField.compareTo(dbTotalAlreadyBefore) == 0) { + return BigDecimal.ZERO; + } + if (totalField.compareTo(dbTotalAlreadyBefore) > 0) { + return totalField.subtract(dbTotalAlreadyBefore); + } + return totalField; + } + + private static boolean hasPdaShelfMetricIncrement(ShelfMaterialDetailDO line, ShelfMaterialDetailPO dbLine) { + if (line == null || dbLine == null) { + return false; + } + BigDecimal dbNet = dbLine.getTotalNetWeight() != null ? dbLine.getTotalNetWeight() : BigDecimal.ZERO; + BigDecimal dbGross = dbLine.getTotalGrossWeight() != null ? dbLine.getTotalGrossWeight() : BigDecimal.ZERO; + BigDecimal dbVol = dbLine.getTotalVolume() != null ? dbLine.getTotalVolume() : BigDecimal.ZERO; + BigDecimal dbArea = dbLine.getTotalArea() != null ? dbLine.getTotalArea() : BigDecimal.ZERO; + return pickThisShelfMetricIncrement(null, line.getTotalNetWeight(), dbNet).compareTo(BigDecimal.ZERO) > 0 + || pickThisShelfMetricIncrement(null, line.getTotalGrossWeight(), dbGross).compareTo(BigDecimal.ZERO) > 0 + || pickThisShelfMetricIncrement(null, line.getTotalVolume(), dbVol).compareTo(BigDecimal.ZERO) > 0 + || pickThisShelfMetricIncrement(null, line.getTotalArea(), dbArea).compareTo(BigDecimal.ZERO) > 0; + } + + private static Long resolveParentUniqueIdForPdaInjectChildShelf(ShelfMaterialDetailPO dbLine, + List allDbLines) { + if (dbLine == null) { + return null; + } + if (isCorruptedStandaloneLineAsLevel2Shelf(dbLine) && dbLine.getMaterialDetailId() != null + && !CollectionUtils.isEmpty(allDbLines)) { + for (ShelfMaterialDetailPO x : allDbLines) { + if (x != null && Objects.equals(dbLine.getMaterialDetailId(), x.getMaterialDetailId()) + && x.getLevel() != null && x.getLevel() == 1) { + return x.getUniqueId(); + } + } + } + ShelfMaterialDetailPO plan = resolveShelfPlanParentRow(dbLine, allDbLines); + return plan != null ? plan.getUniqueId() : dbLine.getUniqueId(); + } + + /** + * PDA 详情:从树上移除与主行同 material_detail_id / unique_id 的镜像子行(旧逻辑注入的 parent_copy),避免与主行并列两条。 + */ + private void removeShelfParentCopyMirrorChildrenRecursively(List list) { + if (CollectionUtils.isEmpty(list)) { + return; + } + for (ShelfMaterialDetailPO parent : list) { + if (parent == null) { + continue; + } + List ch = parent.getChildren(); + if (!CollectionUtils.isEmpty(ch)) { + ch.removeIf(c -> isShelfParentCopyPo(parent, c)); + removeShelfParentCopyMirrorChildrenRecursively(ch); + } + } + } + /** * 判断子项是否为 getInfo 时注入的 parent_copy(与主项同 materialDetailId 或 uniqueId) */ @@ -551,9 +1032,23 @@ public class StockShelfOrderApplicationService { return result; } + /** + * PDA/PC 详情:未完成行将 total* 覆盖为「待上架重量/体积」= 计划 − 累计已上架。 + * 与收货 {@link com.mhd.wms.application.service.stockReceiptOrder.StockReceiptOrderApplicationService#fillPlanAndPendingMetricsRecursively} 一致: + * level=2 子行计算时用计划主行(level=1)上已汇总的 alreadyShelves*,不能用子行本行累计, + * 否则「计划」是整张卡的计划,「已减」却只有子行一批,待上架会偏大。 + */ private void overwriteTotalWithPendingForPdaWeightDisplayRecursively( List list, Map planWeightMetrics + ) { + overwriteTotalWithPendingForPdaWeightDisplayRecursively(list, planWeightMetrics, null); + } + + private void overwriteTotalWithPendingForPdaWeightDisplayRecursively( + List list, + Map planWeightMetrics, + ShelfMaterialDetailPO planParent ) { if (CollectionUtils.isEmpty(list)) { return; @@ -562,6 +1057,10 @@ public class StockShelfOrderApplicationService { if (d == null) { continue; } + ShelfMaterialDetailPO nextPlanParent = planParent; + if (d.getLevel() != null && d.getLevel() == 1) { + nextPlanParent = d; + } // 已上架:不覆盖,展示累计已上架实绩(与 DB 同口径) if (isShelfTerminalShelvesStatus(d.getShelvesStatus())) { // 参考收货:已完成行不参与「计划−待收」,total* 直接展示累计 already @@ -577,7 +1076,7 @@ public class StockShelfOrderApplicationService { if (d.getAlreadyShelvesArea() != null) { d.setTotalArea(d.getAlreadyShelvesArea()); } - overwriteTotalWithPendingForPdaWeightDisplayRecursively(d.getChildren(), planWeightMetrics); + overwriteTotalWithPendingForPdaWeightDisplayRecursively(d.getChildren(), planWeightMetrics, nextPlanParent); continue; } @@ -593,17 +1092,38 @@ public class StockShelfOrderApplicationService { BigDecimal alreadyVol = d.getAlreadyShelvesVolume() != null ? d.getAlreadyShelvesVolume() : BigDecimal.ZERO; BigDecimal alreadyArea = d.getAlreadyShelvesArea() != null ? d.getAlreadyShelvesArea() : BigDecimal.ZERO; + // level=1 有子行:待上架 = 计划 − (主行+子行)已上架;flatten 不再把主行重量汇总后,此处必须用整卡累计参与扣减,否则会只减主行 + if (d.getLevel() != null && d.getLevel() == 1 && !CollectionUtils.isEmpty(d.getChildren())) { + alreadyNet = sumShelfPlanRowAggregatedAlreadyMetric(d, ShelfMaterialDetailPO::getAlreadyShelvesNetWeight); + alreadyGross = sumShelfPlanRowAggregatedAlreadyMetric(d, ShelfMaterialDetailPO::getAlreadyShelvesGrossWeight); + alreadyVol = sumShelfPlanRowAggregatedAlreadyMetric(d, ShelfMaterialDetailPO::getAlreadyShelvesVolume); + alreadyArea = sumShelfPlanRowAggregatedAlreadyMetric(d, ShelfMaterialDetailPO::getAlreadyShelvesArea); + } + + // level=2 子行:计划为整张卡;已上架量用主行+子行 DB 累计之和(主行自身字段不再汇总时仍按整卡扣计划) + if (planParent != null && d.getLevel() != null && d.getLevel() == 2) { + alreadyNet = sumShelfPlanRowAggregatedAlreadyMetric(planParent, ShelfMaterialDetailPO::getAlreadyShelvesNetWeight); + alreadyGross = sumShelfPlanRowAggregatedAlreadyMetric(planParent, ShelfMaterialDetailPO::getAlreadyShelvesGrossWeight); + alreadyVol = sumShelfPlanRowAggregatedAlreadyMetric(planParent, ShelfMaterialDetailPO::getAlreadyShelvesVolume); + alreadyArea = sumShelfPlanRowAggregatedAlreadyMetric(planParent, ShelfMaterialDetailPO::getAlreadyShelvesArea); + } + // 参考收货:只对「有计划值」的字段覆盖 total*,否则保留原 total* if (planNet == null && planGross == null && planVol == null && planArea == null) { - overwriteTotalWithPendingForPdaWeightDisplayRecursively(d.getChildren(), planWeightMetrics); + overwriteTotalWithPendingForPdaWeightDisplayRecursively(d.getChildren(), planWeightMetrics, nextPlanParent); continue; } // 兜底:待上架(1/2) 且已上架数量为 0 时, // DB 里的 total_* 可能被初始化为“计划值”,此时不应把它当作 already。 // 按“数量为准”把 already 权重当 0,使 pending 展示为计划值。 + // level=2 时与收货一致:用主行累计数量判断是否已有上架实绩。 BigDecimal alreadyShelvesQty = d.getAlreadyShelvesQuantity() != null ? d.getAlreadyShelvesQuantity() : BigDecimal.ZERO; boolean hasAlreadyQty = alreadyShelvesQty.compareTo(BigDecimal.ZERO) > 0; + if (planParent != null && d.getLevel() != null && d.getLevel() == 2) { + BigDecimal pq = planParent.getAlreadyShelvesQuantity() != null ? planParent.getAlreadyShelvesQuantity() : BigDecimal.ZERO; + hasAlreadyQty = pq.compareTo(BigDecimal.ZERO) > 0; + } if (!hasAlreadyQty) { alreadyNet = BigDecimal.ZERO; alreadyGross = BigDecimal.ZERO; @@ -624,7 +1144,7 @@ public class StockShelfOrderApplicationService { d.setTotalArea(calcPendingMetric(planArea, alreadyArea)); } - overwriteTotalWithPendingForPdaWeightDisplayRecursively(d.getChildren(), planWeightMetrics); + overwriteTotalWithPendingForPdaWeightDisplayRecursively(d.getChildren(), planWeightMetrics, nextPlanParent); } } @@ -743,6 +1263,15 @@ public class StockShelfOrderApplicationService { public Boolean upShelfByApp(StockShelfOrderDO stockReceiptOrderDO){ // 标记 PDA:权重/数量都按“累计”语义处理(与收货保持一致) stockReceiptOrderDO.setFromApp(Boolean.TRUE); + StockShelfOrderPO dbOrder = stockShelfOrderDomainService.getInfo(stockReceiptOrderDO.getShelfOrderId()); + if (dbOrder == null) { + throw new ServiceException("上架单不存在"); + } + ShelfMaterialDetailDO queryAll = new ShelfMaterialDetailDO(); + queryAll.setShelfOrderNumber(dbOrder.getShelfOrderNumber()); + List dbListAll = shelfMaterialDetailDomainService.queryList(queryAll); + preserveParentShelfLineHierarchyFromDb(stockReceiptOrderDO, dbListAll); + List shelfMaterialDetailDOList = stockReceiptOrderDO.getMaterialDetailList(); boolean firstItemHadChildrenBefore = !CollectionUtils.isEmpty(shelfMaterialDetailDOList) && !CollectionUtils.isEmpty(shelfMaterialDetailDOList.get(0).getChildren()); @@ -764,7 +1293,7 @@ public class StockShelfOrderApplicationService { shelfMaterialDetailDO.setStorageSectionId(firstChild.getStorageSectionId()); shelfMaterialDetailDO.setStorageLocationId(firstChild.getStorageLocationId()); shelfMaterialDetailDO.setContainerId(firstChild.getContainerId()); - shelfMaterialDetailDO.setLevel(firstChild.getLevel()); + // 不把子行 level 复制到主项;assembleParamByShelf 会以库表主行 level 为准 shelfMaterialDetailDO.setMaterialDetailSerialNumberList(firstChild.getMaterialDetailSerialNumberList()); // 保留其余子项(从索引1开始),统一设为 level 2 List restChildren = new ArrayList<>(); @@ -777,6 +1306,30 @@ public class StockShelfOrderApplicationService { } }); } + // 与收货 receivingGoodsByApp 一致:assign 后按库表剥离 UI 镜像/已落库展示子行,必要时合成新的 level=2 承接本次量,避免多次提交仍写主行(对齐 injectPdaFlatReceiptAsSyntheticChild) + boolean skipInjectAfterAssign = firstItemHadChildrenBefore + && !CollectionUtils.isEmpty(stockReceiptOrderDO.getMaterialDetailList()) + && !CollectionUtils.isEmpty(stockReceiptOrderDO.getMaterialDetailList().get(0).getChildren()); + Map dbByIdForInject = dbListAll.stream() + .filter(x -> x.getMaterialDetailId() != null) + .collect(Collectors.toMap(ShelfMaterialDetailPO::getMaterialDetailId, Function.identity(), (a, b) -> a)); + Map dbByUidForInject = dbListAll.stream() + .filter(x -> x.getUniqueId() != null) + .collect(Collectors.toMap(ShelfMaterialDetailPO::getUniqueId, Function.identity(), (a, b) -> a)); + int injectIdx = 0; + for (ShelfMaterialDetailDO line : stockReceiptOrderDO.getMaterialDetailList()) { + ShelfMaterialDetailPO dbLine = null; + if (line.getMaterialDetailId() != null) { + dbLine = dbByIdForInject.get(line.getMaterialDetailId()); + } + if (dbLine == null && line.getUniqueId() != null) { + dbLine = dbByUidForInject.get(line.getUniqueId()); + } + if (dbLine != null && !(skipInjectAfterAssign && injectIdx == 0)) { + injectPdaFlatShelfAsSyntheticChild(line, dbLine, dbListAll); + } + injectIdx++; + } //上架装配参数 StockShelfOrderDO assembleStockShelfOrderDO = assembleParamByShelf(stockReceiptOrderDO); assembleStockShelfOrderDO.setFromApp(Boolean.TRUE); @@ -1019,6 +1572,29 @@ public class StockShelfOrderApplicationService { if (shelfMaterialDetailPO == null){ throw new ServiceException("物料明细不存在"); } + // PDA 注入虚拟子行时:净重毛重体积面积只落在子行,主计划行不再把本次增量再累加一遍。 + // upShelfByApp 中 injectPdaFlatShelfAsSyntheticChild 会先写入 children 再进入本方法,需用标志位与下面「无 children」虚拟子行等价处理。 + boolean injectedVirtualShelfChild = Boolean.TRUE.equals(shelfMaterialDetailDO.getPdaShelfSyntheticChildInjected()); + // PDA 常只传主行 materialDetailId、本次数量在 shelvesQuantity,不带 children:第二次起会走主行 UPDATE。 + // 与带子项时一致:计划主行(level=1)且已有上架实绩时,用虚拟子项承接本次量,主行本次数量置 0,子循环走 INSERT 新行。 + if (!injectedVirtualShelfChild && fromApp && CollectionUtils.isEmpty(shelfMaterialDetailDO.getChildren())) { + BigDecimal parentSqRaw = shelfMaterialDetailDO.getShelvesQuantity() == null ? BigDecimal.ZERO : shelfMaterialDetailDO.getShelvesQuantity(); + BigDecimal dbAlreadyMain = shelfMaterialDetailPO.getAlreadyShelvesQuantity() != null + ? shelfMaterialDetailPO.getAlreadyShelvesQuantity() : BigDecimal.ZERO; + if (shelfMaterialDetailPO.getLevel() != null && shelfMaterialDetailPO.getLevel() == 1 + && dbAlreadyMain.compareTo(BigDecimal.ZERO) > 0 + && parentSqRaw.compareTo(BigDecimal.ZERO) > 0) { + ShelfMaterialDetailDO virtualChild = new ShelfMaterialDetailDO(); + BeanUtils.copyProperties(shelfMaterialDetailDO, virtualChild); + virtualChild.setMaterialDetailId(null); + virtualChild.setUniqueId(null); + shelfMaterialDetailDO.setChildren(Collections.singletonList(virtualChild)); + shelfMaterialDetailDO.setShelvesQuantity(BigDecimal.ZERO); + injectedVirtualShelfChild = true; + // 请求主行仍带本次扫描库位;末尾 copy 到 return 时会覆盖库表主行。子行已承载新库位,主行保留库表原库位。 + restorePlanLineStorageFromDb(shelfMaterialDetailDO, shelfMaterialDetailPO); + } + } List children = shelfMaterialDetailDO.getChildren(); BigDecimal childrenShelvesQuantitySum = BigDecimal.ZERO; if (!CollectionUtils.isEmpty(children)) { @@ -1033,6 +1609,15 @@ public class StockShelfOrderApplicationService { //未进行上架直接跳过 continue; } + // PDA:本次上架量只在子行、主行 shelvesQuantity=0 时,upShelfByApp 会把「第一个子行」的仓库/库位回填到主行 DO(见首子赋值逻辑),assemble 末尾再 merge 到 return,会把本次库位写回库表主行覆盖原库位。 + // 与虚拟子行分支里的 restorePlanLineStorageFromDb 一致:主行恢复为库表值;库表主行尚无库位时不恢复,以免清空后无法走下方 setStorageLocationInfo。 + if (fromApp && !CollectionUtils.isEmpty(shelfMaterialDetailDO.getChildren()) + && shelvesQuantity.compareTo(BigDecimal.ZERO) == 0) { + Long dbMainLocId = shelfMaterialDetailPO.getStorageLocationId(); + if (dbMainLocId != null && dbMainLocId != 0L) { + restorePlanLineStorageFromDb(shelfMaterialDetailDO, shelfMaterialDetailPO); + } + } BigDecimal mainItemActualQuantity = shelvesQuantity;//主项本次上架数(不含子项) BigDecimal childrenActualQuantity = BigDecimal.ZERO;//子项本次上架总数 // PDA 权重/体积/面积:记录“本次增量” @@ -1079,6 +1664,19 @@ public class StockShelfOrderApplicationService { } } BigDecimal childShelvesQty = shelfMaterialDetailDOChild.getShelvesQuantity() != null ? shelfMaterialDetailDOChild.getShelvesQuantity() : BigDecimal.ZERO; + // PDA:计划主行(level=1)或已落库的子行(level=2)上已有上架实绩时,再次携带同一 materialDetailId 提交应与「收货」分拆一致:INSERT 新子行(level=2),不在同一行上累加覆盖;否则会 UPDATE 旧子行导致“第二次上架盖住第一次”。 + if (fromApp && shelfMaterialDetailPOChildDb != null) { + Integer dbPlanLevel = shelfMaterialDetailPOChildDb.getLevel(); + BigDecimal dbAlreadyShelved = shelfMaterialDetailPOChildDb.getAlreadyShelvesQuantity() != null + ? shelfMaterialDetailPOChildDb.getAlreadyShelvesQuantity() : BigDecimal.ZERO; + boolean lineHasShelvedHistory = Integer.valueOf(1).equals(dbPlanLevel) + || Integer.valueOf(2).equals(dbPlanLevel); + if (lineHasShelvedHistory + && dbAlreadyShelved.compareTo(BigDecimal.ZERO) > 0 + && childShelvesQty.compareTo(BigDecimal.ZERO) > 0) { + shelfMaterialDetailPOChildDb = null; + } + } if (fromApp) { // 子项未上架数量时,不累加重量增量 BigDecimal childNetInc = childShelvesQty.compareTo(BigDecimal.ZERO) > 0 @@ -1180,7 +1778,9 @@ public class StockShelfOrderApplicationService { } setStorageLocationInfo(returnShelfMaterialDetailDOChild); returnShelfMaterialDetailDOChild.setAllowModify(2); - returnShelfMaterialDetailDOChild.setLevel(2); + // 库表已存在的行:保留其 level(计划主行=1、分批子行=2)。不可一律写 2,否则 PDA 把计划行 id 放在 children 里时会误把主行改成子行。 + Integer dbChildLevel = shelfMaterialDetailPOChildDb.getLevel(); + returnShelfMaterialDetailDOChild.setLevel(dbChildLevel != null ? dbChildLevel : 2); returnShelfMaterialDetailDOChild.setParentUniqueId(shelfMaterialDetailPO.getUniqueId()); // 子项不维护独立计划数量,计划量仅由主项承载 returnShelfMaterialDetailDOChild.setQuantity(null); @@ -1192,6 +1792,8 @@ public class StockShelfOrderApplicationService { BeanUtils.copyProperties(shelfMaterialDetailPO, returnShelfMaterialDetailDOChild, "materialDetailId","createBy","createByName","createTime", "updateBy","updateByName","updateTime"); BeanUtils.copyProperties(shelfMaterialDetailDOChild, returnShelfMaterialDetailDOChild, IgnoreNullUtil.getNullPropertyNames(shelfMaterialDetailDOChild)); + // 新子行必须 INSERT;请求里若仍带上一笔子行的 materialDetailId,上面会把本段误判为 UPDATE + returnShelfMaterialDetailDOChild.setMaterialDetailId(null); if (fromApp) { // 子项不存在:new already = 0 + 本次增量(并不超过计划) WeightMetrics childPlan = shelfMaterialDetailDOChild.getInUniqueId() != null @@ -1253,6 +1855,30 @@ public class StockShelfOrderApplicationService { childrenActualQuantity = childrenActualQuantity.add(returnShelfMaterialDetailDOChild.getShelvesQuantity()); } } + // PDA 分批上架:子行已承载本次量时,主行平面 shelvesQuantity 不应再计入主项累计(与 inject 成功后主行=0 一致)。 + // inject 因 UI 仍带 children 等提前 return 时,主行与子行会双计,此处兜底。 + boolean pdaSplitChildCarriesThisShelf = false; + if (fromApp && shouldPdaSplitIntoShelfChildRow(shelfMaterialDetailPO, shelfMaterialDetailPODbList) + && !CollectionUtils.isEmpty(shelfMaterialDetailDOChildList)) { + boolean anyChildPositiveQty = false; + for (ShelfMaterialDetailDO ch : shelfMaterialDetailDOChildList) { + if (ch != null && ch.getShelvesQuantity() != null + && ch.getShelvesQuantity().compareTo(BigDecimal.ZERO) > 0) { + anyChildPositiveQty = true; + break; + } + } + if (anyChildPositiveQty && shelfMaterialDetailPO.getLevel() != null + && shelfMaterialDetailPO.getLevel() == 1) { + mainItemActualQuantity = BigDecimal.ZERO; + pdaSplitChildCarriesThisShelf = true; + // inject 未把主行 shelvesQuantity 置 0 时,上面「shelvesQuantity==0 才 restore」分支不执行,主行 DO 仍带本次子行库位,merge 会覆盖库表主项库位;与子行兜底双计一致,此处恢复计划主行库位。 + Long dbMainLocId = shelfMaterialDetailPO.getStorageLocationId(); + if (dbMainLocId != null && dbMainLocId != 0L) { + restorePlanLineStorageFromDb(shelfMaterialDetailDO, shelfMaterialDetailPO); + } + } + } BigDecimal dbParentAlready = shelfMaterialDetailPO.getAlreadyShelvesQuantity() != null ? shelfMaterialDetailPO.getAlreadyShelvesQuantity() : BigDecimal.ZERO; // PC:already_shelves_quantity 使用本次上架量;PDA 保持累计口径 @@ -1280,10 +1906,22 @@ public class StockShelfOrderApplicationService { ? shelfMaterialDetailPO.getTotalArea() : BigDecimal.ZERO; - BigDecimal newAlreadyNet = oldAlreadyNet.add(netIncrement); - BigDecimal newAlreadyGross = oldAlreadyGross.add(grossIncrement); - BigDecimal newAlreadyVol = oldAlreadyVol.add(volIncrement); - BigDecimal newAlreadyArea = oldAlreadyArea.add(areaIncrement); + BigDecimal newAlreadyNet; + BigDecimal newAlreadyGross; + BigDecimal newAlreadyVol; + BigDecimal newAlreadyArea; + if (injectedVirtualShelfChild || pdaSplitChildCarriesThisShelf) { + // 与分拆子行一致:本次 total_* 增量只落在子行;主行保持库表累计不变(否则 netIncrement 已由子循环写入子行,父行再 old+net 会双计)。 + newAlreadyNet = oldAlreadyNet; + newAlreadyGross = oldAlreadyGross; + newAlreadyVol = oldAlreadyVol; + newAlreadyArea = oldAlreadyArea; + } else { + newAlreadyNet = oldAlreadyNet.add(netIncrement); + newAlreadyGross = oldAlreadyGross.add(grossIncrement); + newAlreadyVol = oldAlreadyVol.add(volIncrement); + newAlreadyArea = oldAlreadyArea.add(areaIncrement); + } WeightMetrics plan = shelfMaterialDetailPO.getInUniqueId() != null ? planWeightMetrics.get(shelfMaterialDetailPO.getReceiptUniqueId() != null @@ -1334,6 +1972,8 @@ public class StockShelfOrderApplicationService { ShelfMaterialDetailDO returnShelfMaterialDetailDO = new ShelfMaterialDetailDO(); BeanUtils.copyProperties(shelfMaterialDetailPO, returnShelfMaterialDetailDO); BeanUtils.copyProperties(shelfMaterialDetailDO, returnShelfMaterialDetailDO, IgnoreNullUtil.getNullPropertyNames(shelfMaterialDetailDO)); + // 主行 level 以库表为准,避免 upShelfByApp 等路径把 firstChild.level 合到主项后覆盖为 2 + returnShelfMaterialDetailDO.setLevel(shelfMaterialDetailPO.getLevel()); if (shelfMaterialDetailPO.getShelvesStatus() == 1){ //首次上架 //是否开启了序列号管理 @@ -1355,6 +1995,109 @@ public class StockShelfOrderApplicationService { return returnStockShelfOrderDO; } + /** + * 将计划主行上的仓库/库区/库位/容器恢复为库表现值,避免 PDA 二次上架时把「本次子行库位」写回主行。 + */ + private void restorePlanLineStorageFromDb(ShelfMaterialDetailDO parentDo, ShelfMaterialDetailPO dbPo) { + if (parentDo == null || dbPo == null) { + return; + } + parentDo.setWarehouseId(dbPo.getWarehouseId()); + parentDo.setWarehouseCode(dbPo.getWarehouseCode()); + parentDo.setWarehouseName(dbPo.getWarehouseName()); + parentDo.setStorageSectionId(dbPo.getStorageSectionId()); + parentDo.setStorageCode(dbPo.getStorageCode()); + parentDo.setStorageName(dbPo.getStorageName()); + parentDo.setStorageLocationId(dbPo.getStorageLocationId()); + parentDo.setStorageLocationCode(dbPo.getStorageLocationCode()); + parentDo.setStorageLocationName(dbPo.getStorageLocationName()); + parentDo.setContainerId(dbPo.getContainerId()); + parentDo.setContainerCode(dbPo.getContainerCode()); + parentDo.setContainerType(dbPo.getContainerType()); + parentDo.setContainerTypeName(dbPo.getContainerTypeName()); + } + + /** + * 请求行与库主计划行 level 不一致时纠正,避免误当子行(对齐收货 preserveParentReceiptLineHierarchyFromDb)。 + */ + private void preserveParentShelfLineHierarchyFromDb(StockShelfOrderDO order, List dbList) { + if (order == null || CollectionUtils.isEmpty(order.getMaterialDetailList()) || CollectionUtils.isEmpty(dbList)) { + return; + } + Map byId = dbList.stream() + .filter(x -> x.getMaterialDetailId() != null) + .collect(Collectors.toMap(ShelfMaterialDetailPO::getMaterialDetailId, Function.identity(), (a, b) -> a)); + Map byUid = dbList.stream() + .filter(x -> x.getUniqueId() != null) + .collect(Collectors.toMap(ShelfMaterialDetailPO::getUniqueId, Function.identity(), (a, b) -> a)); + for (ShelfMaterialDetailDO line : order.getMaterialDetailList()) { + ShelfMaterialDetailPO db = null; + if (line.getMaterialDetailId() != null) { + db = byId.get(line.getMaterialDetailId()); + } + if (db == null && line.getUniqueId() != null) { + db = byUid.get(line.getUniqueId()); + } + if (db != null && db.getLevel() != null && db.getLevel() == 1 + && line.getLevel() != null && line.getLevel() == 2) { + line.setLevel(1); + line.setParentUniqueId(null); + } + } + } + + /** + * PDA 单次传主行平面(无真实子结构需拆时):与收货 {@code injectPdaFlatReceiptAsSyntheticChild} 对齐—— + * 去掉 UI 镜像行与已落库展示子行后,将本次上架数量与 total* 指标挪到新建 level=2 子行,主行清零并恢复库表库位,避免第 2、3 次仍累加到主项、覆盖主行库位。 + */ + private void injectPdaFlatShelfAsSyntheticChild(ShelfMaterialDetailDO line, ShelfMaterialDetailPO dbLine, + List allDbLines) { + if (line == null || dbLine == null) { + return; + } + stripPdaUiParentCopyChildrenShelf(line, dbLine); + stripPdaExistingDisplayedChildrenForResplitShelf(line, dbLine, allDbLines); + if (dbLine.getLevel() != null && dbLine.getLevel() == 2 && !isCorruptedStandaloneLineAsLevel2Shelf(dbLine)) { + return; + } + if (!CollectionUtils.isEmpty(line.getChildren())) { + return; + } + if (!shouldPdaSplitIntoShelfChildRow(dbLine, allDbLines) && !isCorruptedStandaloneLineAsLevel2Shelf(dbLine)) { + return; + } + BigDecimal sq = line.getShelvesQuantity(); + boolean hasQty = sq != null && sq.compareTo(BigDecimal.ZERO) > 0; + boolean hasMetricBatch = hasPdaShelfMetricIncrement(line, dbLine); + if (!hasQty && !hasMetricBatch) { + return; + } + ShelfMaterialDetailDO child = new ShelfMaterialDetailDO(); + BeanUtils.copyProperties(line, child, "children", "materialDetailId", "uniqueId", "level", "parentUniqueId"); + child.setUniqueId(idGenerator.snowflakeId(SnowFlakeConstants.wmsId)); + child.setChildren(null); + child.setLevel(2); + child.setParentUniqueId(resolveParentUniqueIdForPdaInjectChildShelf(dbLine, allDbLines)); + if (hasQty) { + child.setShelvesQuantity(sq); + } + child.setTotalNetWeight(line.getTotalNetWeight()); + child.setTotalGrossWeight(line.getTotalGrossWeight()); + child.setTotalVolume(line.getTotalVolume()); + child.setTotalArea(line.getTotalArea()); + child.setAlreadyShelvesQuantity(null); + line.setChildren(Collections.singletonList(child)); + line.setShelvesQuantity(BigDecimal.ZERO); + line.setTotalNetWeight(null); + line.setTotalGrossWeight(null); + line.setTotalVolume(null); + line.setTotalArea(null); + line.setLevel(1); + line.setParentUniqueId(null); + restorePlanLineStorageFromDb(line, dbLine); + line.setPdaShelfSyntheticChildInjected(true); + } + /** * @description 设置上架库位信息 * @author ZhouGY diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/handoverTaskOrder/entity/HandoverTaskOrder.java b/mhd_wms/src/main/java/com/mhd/wms/domain/handoverTaskOrder/entity/HandoverTaskOrder.java index d1878b73b..53f593487 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/handoverTaskOrder/entity/HandoverTaskOrder.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/handoverTaskOrder/entity/HandoverTaskOrder.java @@ -142,5 +142,6 @@ public class HandoverTaskOrder extends BaseVOEntity { @ApiModelProperty("作业人姓名") private String operatorsName; - -} + @ApiModelProperty("计费信息") + private String billingJson; +} \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/handoverTaskOrder/repository/po/HandoverTaskOrderPO.java b/mhd_wms/src/main/java/com/mhd/wms/domain/handoverTaskOrder/repository/po/HandoverTaskOrderPO.java index 6b1077fbb..ba3f625e1 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/handoverTaskOrder/repository/po/HandoverTaskOrderPO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/handoverTaskOrder/repository/po/HandoverTaskOrderPO.java @@ -141,5 +141,6 @@ public class HandoverTaskOrderPO extends BaseVOEntity { @ApiModelProperty("物料明细(根据复核单数据生成,数量为复核数量)") private List materialDetailList; - -} + @ApiModelProperty("计费信息") + private String billingJson; +} \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/handoverTaskOrder/repository/todo/HandoverTaskOrderDO.java b/mhd_wms/src/main/java/com/mhd/wms/domain/handoverTaskOrder/repository/todo/HandoverTaskOrderDO.java index 04f91dd83..21fc3823c 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/handoverTaskOrder/repository/todo/HandoverTaskOrderDO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/handoverTaskOrder/repository/todo/HandoverTaskOrderDO.java @@ -142,4 +142,6 @@ public class HandoverTaskOrderDO extends BaseVOEntity { @ApiModelProperty("app上传的图片") private String pictureApp; -} + + private String billingJson; +} \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/handoverTaskOrder/service/HandoverTaskOrderDomainService.java b/mhd_wms/src/main/java/com/mhd/wms/domain/handoverTaskOrder/service/HandoverTaskOrderDomainService.java index e02fa6b68..200140ad0 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/handoverTaskOrder/service/HandoverTaskOrderDomainService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/handoverTaskOrder/service/HandoverTaskOrderDomainService.java @@ -27,6 +27,7 @@ import com.mhd.wms.domain.outMaterialDetail.entity.OutMaterialDetail; import com.mhd.wms.domain.outMaterialDetail.repository.mapper.OutMaterialDetailMapper; import com.mhd.wms.domain.pickingMaterialDetail.repository.mapper.PickingMaterialDetailMapper; import com.mhd.wms.domain.pickingMaterialDetail.repository.po.PickingMaterialDetailPO; +import com.mhd.wms.domain.stockOutOrder.repository.facade.IStockOutOrderService; import com.mhd.wms.domain.taskHandoverMaterialDetail.repository.po.TaskHandoverMaterialDetailPO; import com.mhd.wms.domain.shiftManage.repository.po.ShiftManagePO; import com.mhd.wms.domain.shiftManage.repository.todo.ShiftManageDO; @@ -74,6 +75,8 @@ public class HandoverTaskOrderDomainService { private IMaterialBarCodeService materialBarCodeService; @Autowired private IMaterialInventoryService materialInventoryService; + @Autowired + private IStockOutOrderService stockOutOrderService; /** @@ -171,14 +174,8 @@ public class HandoverTaskOrderDomainService { detail.setMaterialCode(omd.getMaterialCode() != null ? omd.getMaterialCode() : omd.getMaterialNo()); detail.setMaterialName(omd.getMaterialName() != null ? omd.getMaterialName() : omd.getCommodityName()); detail.setBarCode(omd.getBarCode()); - // 需要复核时:交接展示以出库明细上的复核计量为准(完成复核时由复核单同步写入 check_*) - if (Integer.valueOf(1).equals(review)) { - detail.setWeightLimit(omd.getCheckNetWeight() != null ? omd.getCheckNetWeight() : omd.getWeightLimit()); - detail.setVolumeLimit(omd.getCheckVolume() != null ? omd.getCheckVolume() : omd.getVolumeLimit()); - } else { - detail.setWeightLimit(omd.getWeightLimit()); - detail.setVolumeLimit(omd.getVolumeLimit()); - } + detail.setWeightLimit(omd.getWeightLimit()); + detail.setVolumeLimit(omd.getVolumeLimit()); detail.setQuantity(omd.getQuantity()); detail.setPickingQuantity(pickQty); detail.setCheckQuantity(handoverQuantity); @@ -291,11 +288,14 @@ public class HandoverTaskOrderDomainService { for (Long handoverTaskOrderId : handoverTaskOrderIds) { pushOms(handoverTaskOrderId); } + HandoverTaskOrder handoverTaskOrder = handoverTaskOrderService.getById(handoverTaskOrderIds.get(0)); + stockOutOrderService.update(null,new UpdateWrapper().lambda().set(StockOutOrder::getBillingJson,handoverTaskOrderDO.getBillingJson()).eq(StockOutOrder::getOutOrderNumber,handoverTaskOrder.getOrderNumber())); return handoverTaskOrderService.update(null, new UpdateWrapper().lambda() .set(HandoverTaskOrder::getStatus, 2) .set(HandoverTaskOrder::getUpdateBy, loginUser.getUserid()) .set(HandoverTaskOrder::getUpdateByName, loginUser.getUsername()) .set(HandoverTaskOrder::getUpdateTime, new Date()) + .set(HandoverTaskOrder::getBillingJson, handoverTaskOrderDO.getBillingJson()) .in(HandoverTaskOrder::getHandoverTaskOrderId, handoverTaskOrderIds) ); } diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/outMaterialDetail/repository/persistence/OutMaterialDetailImpl.java b/mhd_wms/src/main/java/com/mhd/wms/domain/outMaterialDetail/repository/persistence/OutMaterialDetailImpl.java index b447da8d0..e091736a5 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/outMaterialDetail/repository/persistence/OutMaterialDetailImpl.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/outMaterialDetail/repository/persistence/OutMaterialDetailImpl.java @@ -322,8 +322,17 @@ public class OutMaterialDetailImpl extends ServiceImpl 0) { @@ -407,13 +407,22 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl receiptMaterialDetailList = new ArrayList<>(); // 批量修改更多属性和新增序列号 List materialMoreDetailList = new ArrayList<>(); List materialDetailSerialNumberList = new ArrayList<>(); for (ReceiptMaterialDetailDO receiptMaterialDetailDO : receiptMaterialDetailDOList){ + extractBatchAttributesToReceiptDetail(receiptMaterialDetailDO); + // 自动生成批次号并校验唯一性(包括子项) + generateAndValidateBatchNumber(receiptMaterialDetailDO, shipperId, currentInOrderNumber); + // 当 materialMoreDetailList 为空时(如 PDA 未传),从 receiptMaterialDetailDO 的 batch_number、material_status_code 等字段构建,确保更多属性能保存并回显 + if (CollectionUtils.isEmpty(receiptMaterialDetailDO.getMaterialMoreDetailList())) { + receiptMaterialDetailDO.setMaterialMoreDetailList(buildMaterialMoreDetailFromReceiptFields(receiptMaterialDetailDO)); + } // 批次号:默认取 Sheet Ref NO's(sheetRefNo),不再自动生成 PC 流水号(逻辑见 generateAndValidateBatchNumber) generateAndValidateBatchNumber(receiptMaterialDetailDO, shipperId); //更多属性 @@ -745,7 +754,7 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl children = receiptMaterialDetailDO.getChildren(); if (!CollectionUtils.isEmpty(children)) { for (ReceiptMaterialDetailDO child : children) { - generateAndValidateBatchNumber(child, shipperId); + generateAndValidateBatchNumber(child, shipperId, currentInOrderNumber); } } } @@ -1237,9 +1270,11 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl wrapper = new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper() .eq(MaterialInventory::getShipperId, shipperId) .eq(MaterialInventory::getMaterialBaseInfoId, materialBaseInfoId) .eq(MaterialInventory::getBatchNumber, batchNumber) - .eq(MaterialInventory::getDelFlag, 1); + .eq(MaterialInventory::getDelFlag, 1) + .eq(MaterialInventory::getInOrderNumber, currentInOrderNumber); // 如果库存属性值不为空,需要精确匹配;如果为空,查询库存属性值为空或null的记录 if (materialStatusCode != null && !materialStatusCode.trim().isEmpty()) { wrapper.eq(MaterialInventory::getMaterialStatusCode, materialStatusCode); } else { - // 如果库存属性值为空,查询库存属性值为null或空字符串的记录 wrapper.and(w -> w.isNull(MaterialInventory::getMaterialStatusCode) .or() .eq(MaterialInventory::getMaterialStatusCode, "")); } List existingInventoryList = materialInventoryMapper.selectList(wrapper); - - // 如果存在相同的货主+商品+库存属性值+批次号的记录,抛出异常 + if (!CollectionUtils.isEmpty(existingInventoryList)) { String statusCodeDesc = (materialStatusCode != null && !materialStatusCode.trim().isEmpty()) ? ",库存属性值:" + materialStatusCode : ",库存属性值:空"; - throw new ServiceException("批次号【" + batchNumber + "】已存在,货主ID【" + shipperId + "】+商品ID【" + materialBaseInfoId + "】" + statusCodeDesc + "相同的记录不允许使用重复的批次号"); + throw new ServiceException("批次号【" + batchNumber + "】在本入库单「" + currentInOrderNumber + + "」下已存在库存,货主ID【" + shipperId + "】+商品ID【" + materialBaseInfoId + "】" + statusCodeDesc + + ",不允许重复使用"); } } } diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/receiptOrderAccount/entity/ReceiptOrderAccount.java b/mhd_wms/src/main/java/com/mhd/wms/domain/receiptOrderAccount/entity/ReceiptOrderAccount.java index 040b9b44e..3f7cadb60 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/receiptOrderAccount/entity/ReceiptOrderAccount.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/receiptOrderAccount/entity/ReceiptOrderAccount.java @@ -112,4 +112,7 @@ public class ReceiptOrderAccount extends BaseVOEntity { @ApiModelProperty(value = "单价") @Excel(name = "单价", width = 15) private BigDecimal price; + + @ApiModelProperty(value = "计算价格json") + private String amountJson; } \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/shelfMaterialDetail/repository/facade/IShelfMaterialDetailService.java b/mhd_wms/src/main/java/com/mhd/wms/domain/shelfMaterialDetail/repository/facade/IShelfMaterialDetailService.java index a2598f51e..4ecf44072 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/shelfMaterialDetail/repository/facade/IShelfMaterialDetailService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/shelfMaterialDetail/repository/facade/IShelfMaterialDetailService.java @@ -26,6 +26,11 @@ public interface IShelfMaterialDetailService extends IService queryListChildren(ShelfMaterialDetailDO shelfMaterialDetailDO); + /** + * PDA:指定计划行(卡片 material_detail_id)下所有 level=2 分批上架子行;可含首笔仅落主行时的主行快照。 + */ + public List queryLevel2ChildrenByParentMaterialDetailId(String shelfOrderNumber, Long parentMaterialDetailId); + /** * 新增物料明细 */ diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/shelfMaterialDetail/repository/persistence/ShelfMaterialDetailImpl.java b/mhd_wms/src/main/java/com/mhd/wms/domain/shelfMaterialDetail/repository/persistence/ShelfMaterialDetailImpl.java index 15a19c181..35aa716e3 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/shelfMaterialDetail/repository/persistence/ShelfMaterialDetailImpl.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/shelfMaterialDetail/repository/persistence/ShelfMaterialDetailImpl.java @@ -31,8 +31,10 @@ import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.ArrayList; +import java.util.Comparator; import java.util.Date; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; /** @@ -123,6 +125,103 @@ public class ShelfMaterialDetailImpl extends ServiceImpl queryLevel2ChildrenByParentMaterialDetailId(String shelfOrderNumber, + Long parentMaterialDetailId) { + List empty = new ArrayList<>(); + if (shelfOrderNumber == null || parentMaterialDetailId == null) { + return empty; + } + ShelfMaterialDetailDO q = new ShelfMaterialDetailDO(); + q.setShelfOrderNumber(shelfOrderNumber); + List all = shelfMaterialDetailMapper.queryList(q); + if (CollectionUtils.isEmpty(all)) { + return empty; + } + ShelfMaterialDetailPO anchor = all.stream() + .filter(p -> parentMaterialDetailId.equals(p.getMaterialDetailId())) + .findFirst() + .orElse(null); + if (anchor == null) { + return empty; + } + ShelfMaterialDetailPO parent = anchor; + if (anchor.getLevel() != null && anchor.getLevel() == 2 && anchor.getParentUniqueId() != null) { + Long puid = anchor.getParentUniqueId(); + ShelfMaterialDetailPO plan = all.stream() + .filter(row -> puid.equals(row.getUniqueId()) || puid.equals(row.getInUniqueId())) + .findFirst() + .orElse(null); + if (plan != null) { + parent = plan; + } + } + Long pid = parent.getUniqueId(); + Long inPid = parent.getInUniqueId(); + if (pid == null && inPid == null) { + return empty; + } + final Long fpid = pid; + final Long finPid = inPid; + List children = all.stream() + .filter(m -> m.getLevel() != null && m.getLevel() == 2) + .filter(m -> { + Long p = m.getParentUniqueId(); + if (p == null) { + return false; + } + return (fpid != null && p.equals(fpid)) || (finPid != null && p.equals(finPid)); + }) + .sorted(Comparator.comparing(ShelfMaterialDetailPO::getCreateTime, Comparator.nullsLast(Comparator.naturalOrder())) + .thenComparing(ShelfMaterialDetailPO::getMaterialDetailId, Comparator.nullsLast(Comparator.naturalOrder()))) + .collect(Collectors.toList()); + children.forEach(this::enrichShelfRowMaterialMoreDetail); + // 首笔只落主计划行、后续批次才 INSERT 子行时:主行上仍有累计已上架,列表需在子行之外再带一条「主行首笔」快照 + if (!children.isEmpty() && parent.getLevel() != null && parent.getLevel() == 1 + && parent.getAlreadyShelvesQuantity() != null + && parent.getAlreadyShelvesQuantity().compareTo(BigDecimal.ZERO) > 0) { + ShelfMaterialDetailPO mainSnap = new ShelfMaterialDetailPO(); + BeanUtils.copyProperties(parent, mainSnap); + enrichShelfRowMaterialMoreDetail(mainSnap); + children.add(0, mainSnap); + } + // 未拆 level=2 子行、已上架全部记在主计划行时:仍返回一条与主行一致的快照,供 PDA「历史上架列表」展示 + if (children.isEmpty() && parent.getAlreadyShelvesQuantity() != null + && parent.getAlreadyShelvesQuantity().compareTo(BigDecimal.ZERO) > 0) { + ShelfMaterialDetailPO mainSnap = new ShelfMaterialDetailPO(); + BeanUtils.copyProperties(parent, mainSnap); + enrichShelfRowMaterialMoreDetail(mainSnap); + children.add(mainSnap); + } + return children; + } + + /** + * 与 queryListChildren 中单行一致:批次更多属性 + 从上架明细填充 attributeValue。 + */ + private void enrichShelfRowMaterialMoreDetail(ShelfMaterialDetailPO row) { + if (row == null) { + return; + } + MaterialMoreDetailDO materialMoreDetailDO = new MaterialMoreDetailDO(); + Long materialDetailUniqueIdForQuery = row.getReceiptUniqueId() != null + ? row.getReceiptUniqueId() : row.getUniqueId(); + materialMoreDetailDO.setMaterialDetailUniqueId(materialDetailUniqueIdForQuery); + List materialMoreDetailList = IMaterialMoreDetailService.queryList(materialMoreDetailDO); + if (CollectionUtils.isEmpty(materialMoreDetailList)) { + AjaxResult ajaxResult = systemServiceFeign.getBatchDetailListByMaterialBaseInfoId(row.getMaterialBaseInfoId()); + if (ajaxResult != null && "200".equals(String.valueOf(ajaxResult.get("code")))) { + List batchList = JSON.parseArray(JSONObject.toJSONString(ajaxResult.get("data")), BatchDetailFeignPO.class); + materialMoreDetailList = filterAndConvertToMaterialMoreDetail(batchList); + } + } + if (materialMoreDetailList == null) { + materialMoreDetailList = new ArrayList<>(); + } + fillAttributeValueFromShelfMaterialDetail(row, materialMoreDetailList); + row.setMaterialMoreDetailList(materialMoreDetailList); + } + /** * 过滤 isDisplay=1 的批次属性并转换为 MaterialMoreDetailPO,与收货/PC 端一致 */ @@ -309,9 +408,13 @@ public class ShelfMaterialDetailImpl extends ServiceImpl shelfMaterialDetailChildList = new ArrayList<>(); if (!CollectionUtils.isEmpty(inMaterialDetailDOChildList)){ for (ShelfMaterialDetailDO shelfMaterialDetailDOChild : inMaterialDetailDOChildList){ + // 与收货 batchReceiptUpdate 一致:不强行 setLevel(2)。PDA 可能在 children 中带 parent_copy(与主行同 material_detail_id/unique_id), + // 若再强制 level=2,saveOrUpdateBatch 后写会覆盖主行,把主行改成 level=2。 + if (isShelfParentCopyMirrorRow(shelfMaterialDetailDO, shelfMaterialDetailDOChild)) { + continue; + } ShelfMaterialDetail shelfMaterialDetailChild = new ShelfMaterialDetail(); BeanUtils.copyProperties(shelfMaterialDetailDOChild, shelfMaterialDetailChild); - shelfMaterialDetailChild.setLevel(2); shelfMaterialDetailChild.setCreateBy(loginUser.getUserid()); shelfMaterialDetailChild.setCreateByName(loginUser.getUsername()); shelfMaterialDetailChild.setCreateTime(new Date()); @@ -359,6 +462,33 @@ public class ShelfMaterialDetailImpl extends ServiceImpl receiptOrderAccountList; + @ApiModelProperty("结算币种") + private String settlementCurrency; + @ApiModelProperty("业务员ID") + private String salesmanId; + @ApiModelProperty("业务员名称") + private String salesmanName; + @ApiModelProperty("批号") private String batchNumber; diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/stockInOrder/repository/todo/StockInOrderDO.java b/mhd_wms/src/main/java/com/mhd/wms/domain/stockInOrder/repository/todo/StockInOrderDO.java index 4d17f7a14..e9915f1a1 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/stockInOrder/repository/todo/StockInOrderDO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/stockInOrder/repository/todo/StockInOrderDO.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.mhd.common.core.annotation.Excel; import com.mhd.common.core.web.domain.BaseVOEntity; import com.mhd.wms.domain.inMaterialDetail.repository.todo.InMaterialDetailDO; +import com.mhd.wms.domain.receiptOrderAccount.entity.ReceiptOrderAccount; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; @@ -379,4 +380,15 @@ public class StockInOrderDO extends BaseVOEntity { @ApiModelProperty("入库明细-物料编码,模糊匹配") private String materialCode; + + @ApiModelProperty(name = "费用参数json") + private String billingJson; + @ApiModelProperty("费用") + List receiptOrderAccountList; + @ApiModelProperty("结算币种") + private String settlementCurrency; + @ApiModelProperty("业务员ID") + private String salesmanId; + @ApiModelProperty("业务员名称") + private String salesmanName; } \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/entity/StockOutOrder.java b/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/entity/StockOutOrder.java index 3729104fe..b42b8ff80 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/entity/StockOutOrder.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/entity/StockOutOrder.java @@ -395,4 +395,14 @@ public class StockOutOrder extends BaseVOEntity { @Excel(name = "制单日期", width = 30, dateFormat = "yyyy-MM-dd") private Date documentDate; + @ApiModelProperty("计费信息") + private String billingJson; + + @ApiModelProperty("结算币种") + private String settlementCurrency; + @ApiModelProperty("业务员ID") + private String salesmanId; + @ApiModelProperty("业务员名称") + private String salesmanName; + } \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/repository/listener/ExcelParseService.java b/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/repository/listener/ExcelParseService.java index 79e50a57b..378ae5270 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/repository/listener/ExcelParseService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/repository/listener/ExcelParseService.java @@ -7,6 +7,7 @@ import com.alibaba.excel.read.builder.ExcelReaderBuilder; import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.mhd.common.core.domain.po.SysDictDataVo; import com.mhd.common.core.domain.po.UserPo; @@ -35,6 +36,7 @@ import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; @@ -155,10 +157,20 @@ public class ExcelParseService { } private void initParam(StockOutOrderDO stockOutOrderDO) { - //设置货主信息 - shipperParam(stockOutOrderDO); - //设置客户信息 - customerParam(stockOutOrderDO); + String customerName = stockOutOrderDO.getCustomerName(); + if (StringUtils.isEmpty(customerName)) { + return; + } + UserPo userPo = resolveCustomerShipperUserPoForImport(customerName); + if (userPo == null) { + throw new ServiceException("获取客户信息失败:未在名称与货主列表中匹配到当前组织下的客户,请核对名称或改用客户编号/ID"); + } + stockOutOrderDO.setShipperId(userPo.getUserId()); + stockOutOrderDO.setShipperCode(userPo.getUserMemberCode()); + stockOutOrderDO.setShipperName(userPo.getUserName()); + stockOutOrderDO.setCustomerId(userPo.getUserId()); + stockOutOrderDO.setCustomerCode(userPo.getUserMemberCode()); + stockOutOrderDO.setCustomerName(userPo.getUserName()); } /** @@ -168,66 +180,6 @@ public class ExcelParseService { return stockOutOrderDomainService.insert(stockOutOrderDO); } - /** - * @description 封装货主信息 - * @author ZhouGY - * @date 2024/5/9 20:43 - * @param stockOutOrderDO - */ - private void shipperParam(StockOutOrderDO stockOutOrderDO){ - String customerName = stockOutOrderDO.getCustomerName(); - if (StringUtils.isEmpty(customerName)) return; - if (!customerName.matches("\\d+")) { - AjaxResult ajaxResult = userServiceFeign.getInfoByName(customerName); - if(!"200".equals(String.valueOf(ajaxResult.get("code")))){ - throw new ServiceException("获取客户信息失败"); - } - UserPo userPo = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class); - stockOutOrderDO.setShipperId(userPo.getUserId()); - stockOutOrderDO.setShipperCode(userPo.getUserMemberCode()); - stockOutOrderDO.setShipperName(userPo.getUserName()); - } else { - AjaxResult ajaxResult = userServiceFeign.getInfo(Long.valueOf(customerName)); - if(!"200".equals(String.valueOf(ajaxResult.get("code")))){ - throw new ServiceException("获取货主信息失败"); - } - UserPo userPo = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class); - stockOutOrderDO.setShipperId(userPo.getUserId()); - stockOutOrderDO.setShipperCode(userPo.getUserMemberCode()); - stockOutOrderDO.setShipperName(userPo.getUserName()); - } - } - - /** - * @description 封装客户信息 - * @author ZhouGY - * @date 2024/5/9 20:43 - * @param stockOutOrderDO - */ - private void customerParam(StockOutOrderDO stockOutOrderDO){ - String customerName = stockOutOrderDO.getCustomerName(); - if (StringUtils.isEmpty(customerName)) return; - if (!customerName.matches("\\d+")) { - AjaxResult ajaxResult = userServiceFeign.getInfoByName(customerName); - if(!"200".equals(String.valueOf(ajaxResult.get("code")))){ - throw new ServiceException("获取客户信息失败"); - } - UserPo userPo = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class); - stockOutOrderDO.setCustomerId(userPo.getUserId()); - stockOutOrderDO.setCustomerCode(userPo.getUserMemberCode()); - stockOutOrderDO.setCustomerName(userPo.getUserName()); - } else { - AjaxResult ajaxResult = userServiceFeign.getInfo(Long.valueOf(customerName)); - if(!"200".equals(String.valueOf(ajaxResult.get("code")))){ - throw new ServiceException("获取客户信息失败"); - } - UserPo userPo = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class); - stockOutOrderDO.setCustomerId(userPo.getUserId()); - stockOutOrderDO.setCustomerCode(userPo.getUserMemberCode()); - stockOutOrderDO.setCustomerName(userPo.getUserName()); - } - } - /** * 校验导入明细是否已在当前货主下维护物料基础信息 */ @@ -302,41 +254,139 @@ public class ExcelParseService { return errorMsg; } + /** + * 导入出库单:解析出的货主用户是否属于当前登录用户同一组织(organizationId)。 + * 仅当登录用户带有 organizationId 时启用过滤;否则保持与旧行为一致。 + */ + private boolean shipperMatchesImporterOrganization(UserPo userPo, Long loginOrganizationId) { + if (loginOrganizationId == null) { + return true; + } + if (userPo == null) { + return false; + } + Long oid = userPo.getOrganizationId(); + return oid != null && loginOrganizationId.equals(oid); + } + + /** + * 按客户名称或数字ID解析货主用户,逻辑与入库单导入一致:getInfoByName → 货主列表兜底,均做 organizationId 校验。 + */ + private UserPo resolveCustomerShipperUserPoForImport(String customerName) { + if (StringUtils.isEmpty(customerName)) { + return null; + } + Long loginOrganizationId = null; + LoginUser loginUser = SecurityUtils.getLoginUser(); + if (loginUser != null && loginUser.getUserPo() != null) { + loginOrganizationId = loginUser.getUserPo().getOrganizationId(); + } + String shipperName = customerName.trim(); + if (StringUtils.isEmpty(shipperName)) { + return null; + } + + // 纯数字:按用户ID查询 + if (shipperName.matches("\\d+")) { + try { + Long possibleId = Long.valueOf(shipperName); + AjaxResult ajaxResult = userServiceFeign.getInfo(possibleId); + if ("200".equals(String.valueOf(ajaxResult.get("code"))) && ajaxResult.get("data") != null) { + UserPo userPo = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class); + if (userPo != null && shipperMatchesImporterOrganization(userPo, loginOrganizationId)) { + return userPo; + } + } + } catch (Exception e) { + // ignore + } + return null; + } + + // 按名称查询(用户中心) + try { + AjaxResult ajaxResult = userServiceFeign.getInfoByName(shipperName); + if ("200".equals(String.valueOf(ajaxResult.get("code"))) && ajaxResult.get("data") != null) { + UserPo userPo = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class); + if (userPo != null && shipperMatchesImporterOrganization(userPo, loginOrganizationId)) { + return userPo; + } + } + } catch (Exception e) { + // 继续货主列表兜底 + } + + // 货主列表兜底(与入库单 getShipperIdByNameOrCode 一致) + try { + AjaxResult shipperListResult = userServiceFeign.userShipperListAll(); + if ("200".equals(String.valueOf(shipperListResult.get("code"))) && shipperListResult.get("data") != null) { + Object data = shipperListResult.get("data"); + List> shipperList = null; + if (data instanceof List) { + @SuppressWarnings("unchecked") + List rawList = (List) data; + shipperList = new ArrayList<>(); + for (Object item : rawList) { + if (item instanceof Map) { + @SuppressWarnings("unchecked") + Map mapItem = (Map) item; + shipperList.add(mapItem); + } else { + Map mapItem = JSON.parseObject(JSONObject.toJSONString(item), Map.class); + shipperList.add(mapItem); + } + } + } else { + String jsonStr = JSONObject.toJSONString(data); + shipperList = JSON.parseObject(jsonStr, new TypeReference>>(){}); + } + + if (shipperList != null && !shipperList.isEmpty()) { + String normalizedShipperName = shipperName; + for (Map shipper : shipperList) { + Object userId = shipper.get("userId"); + Object userName = shipper.get("userName"); + if (userName == null) { + userName = shipper.get("name"); + } + if (userName == null) { + userName = shipper.get("shipperName"); + } + boolean matched = false; + if (StringUtils.isNotEmpty(normalizedShipperName) && userName != null) { + String normalizedUserName = String.valueOf(userName).trim(); + if (normalizedShipperName.equals(normalizedUserName) + || normalizedUserName.contains(normalizedShipperName)) { + matched = true; + } + } + if (matched && userId != null) { + Long candidateId = Long.valueOf(String.valueOf(userId)); + AjaxResult infoRes = userServiceFeign.getInfo(candidateId); + if ("200".equals(String.valueOf(infoRes.get("code"))) && infoRes.get("data") != null) { + UserPo up = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(infoRes.get("data")), UserPo.class); + if (shipperMatchesImporterOrganization(up, loginOrganizationId)) { + return up; + } + } + } + } + } + } + } catch (Exception e) { + // ignore + } + return null; + } + /** * @description 根据客户名称获取货主ID(用于导入时提前获取货主ID) * @param customerName 客户名称(在出库单中,客户名称就是货主名称) * @return 货主ID,如果找不到则返回null */ private Long getShipperIdByCustomerName(String customerName) { - if (StringUtils.isEmpty(customerName)) { - return null; - } - - try { - if (!customerName.matches("\\d+")) { - // 按名称查询 - AjaxResult ajaxResult = userServiceFeign.getInfoByName(customerName); - if ("200".equals(String.valueOf(ajaxResult.get("code")))) { - UserPo userPo = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class); - if (userPo != null) { - return userPo.getUserId(); - } - } - } else { - // 按ID查询 - AjaxResult ajaxResult = userServiceFeign.getInfo(Long.valueOf(customerName)); - if ("200".equals(String.valueOf(ajaxResult.get("code")))) { - UserPo userPo = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class); - if (userPo != null) { - return userPo.getUserId(); - } - } - } - } catch (Exception e) { - // 如果查询失败,返回null,后续在shipperParam方法中会再次尝试 - } - - return null; + UserPo userPo = resolveCustomerShipperUserPoForImport(customerName); + return userPo != null ? userPo.getUserId() : null; } /** diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/repository/po/StockOutOrderPO.java b/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/repository/po/StockOutOrderPO.java index 7a9e9750e..4754da21f 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/repository/po/StockOutOrderPO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/repository/po/StockOutOrderPO.java @@ -5,6 +5,7 @@ import com.mhd.common.core.annotation.Excel; import com.mhd.common.core.web.domain.BaseVOEntity; import com.mhd.wms.domain.outMaterialDetail.repository.po.OutMaterialCheckPO; import com.mhd.wms.domain.outMaterialDetail.repository.po.OutMaterialDetailPO; +import com.mhd.wms.domain.receiptOrderAccount.entity.ReceiptOrderAccount; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -406,4 +407,14 @@ public class StockOutOrderPO extends BaseVOEntity { @Excel(name = "承运商名称") private String carrierName; + @ApiModelProperty("计费信息") + private String billingJson; + @ApiModelProperty("结算币种") + private String settlementCurrency; + @ApiModelProperty("业务员ID") + private String salesmanId; + @ApiModelProperty("业务员名称") + private String salesmanName; + @ApiModelProperty("费用") + List receiptOrderAccountList; } \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/repository/todo/StockOutOrderDO.java b/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/repository/todo/StockOutOrderDO.java index d487c2495..398d3c4d7 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/repository/todo/StockOutOrderDO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/repository/todo/StockOutOrderDO.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.mhd.common.core.annotation.Excel; import com.mhd.common.core.web.domain.BaseVOEntity; import com.mhd.wms.domain.outMaterialDetail.repository.todo.OutMaterialDetailDO; +import com.mhd.wms.domain.receiptOrderAccount.entity.ReceiptOrderAccount; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; @@ -441,4 +442,14 @@ public class StockOutOrderDO extends BaseVOEntity { @ApiModelProperty("承运商名称") @Excel(name = "承运商名称") private String carrierName; + @ApiModelProperty("计费信息") + private String billingJson; + @ApiModelProperty("结算币种") + private String settlementCurrency; + @ApiModelProperty("业务员ID") + private String salesmanId; + @ApiModelProperty("业务员名称") + private String salesmanName; + @ApiModelProperty("费用") + List receiptOrderAccountList; } \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/stockReceiptOrder/entity/StockReceiptOrder.java b/mhd_wms/src/main/java/com/mhd/wms/domain/stockReceiptOrder/entity/StockReceiptOrder.java index d01544e79..b379008b5 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/stockReceiptOrder/entity/StockReceiptOrder.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/stockReceiptOrder/entity/StockReceiptOrder.java @@ -129,8 +129,9 @@ public class StockReceiptOrder extends BaseVOEntity { @ApiModelProperty("备注") @Excel(name = "备注") private String remark; + @ApiModelProperty(name = "费用参数json") + private String billingJson; - -} +} \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/stockReceiptOrder/repository/po/StockReceiptOrderPO.java b/mhd_wms/src/main/java/com/mhd/wms/domain/stockReceiptOrder/repository/po/StockReceiptOrderPO.java index be061fd15..06f53a37d 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/stockReceiptOrder/repository/po/StockReceiptOrderPO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/stockReceiptOrder/repository/po/StockReceiptOrderPO.java @@ -180,4 +180,7 @@ public class StockReceiptOrderPO extends StockInOrderBasePO { @ApiModelProperty("序号") private String serialNumber; + + @ApiModelProperty(name = "费用参数json") + private String billingJson; } \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/stockReceiptOrder/repository/todo/StockReceiptOrderDO.java b/mhd_wms/src/main/java/com/mhd/wms/domain/stockReceiptOrder/repository/todo/StockReceiptOrderDO.java index e6b8163b8..5e650b786 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/stockReceiptOrder/repository/todo/StockReceiptOrderDO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/stockReceiptOrder/repository/todo/StockReceiptOrderDO.java @@ -185,4 +185,7 @@ public class StockReceiptOrderDO extends StockInOrderBaseDO { @ApiModelProperty("费用") List receiptOrderAccountList; + + @ApiModelProperty(name = "费用参数json") + private String billingJson; } \ No newline at end of file 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 1b6c2fc68..0fe6f0eed 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 @@ -448,8 +448,9 @@ public class StockReceiptOrderDomainService { genStockReceiptTaskOrderByReceivingGoods(stockReceiptOrderPO,stockReceiptOrderDO); //收货后上架前 生成质检 genQualityInspectionByReceivingGoods(stockReceiptOrderDO); - saveAmount(stockReceiptOrderDO); + //saveAmount(stockReceiptOrderDO); //更新入库单状态 + stockReceiptOrderPO.setBillingJson(stockReceiptOrderDO.getBillingJson()); updateStockInOrder(stockReceiptOrderPO); //修改收货单 设置收货单收货需要更新的数据数据 return updateStockReceiptOrder(stockReceiptOrderDO, stockReceiptOrderPO); @@ -468,60 +469,7 @@ public class StockReceiptOrderDomainService { } } - /** - * 定时任务整租推送到bms装卸费 - */ - public void wholeRentSynchronizationZXF(Long busId) { - StockReceiptOrder stockReceiptOrder = stockReceiptOrderService.getById(busId); - String inOrderNumber = stockReceiptOrder.getInOrderNumber(); - StockInOrder stockInOrder = stockInOrderService.getOne(new QueryWrapper().lambda().eq(StockInOrder::getInOrderNumber, inOrderNumber),false); - Long shipperId = stockInOrder.getShipperId(); - Long organizationId = stockInOrder.getOrganizationId(); - String organizationName = stockInOrder.getOrganizationName(); - Long topOrganizationId = stockInOrder.getTopOrganizationId(); - List accounts = receiptOrderAccountService.list(new QueryWrapper().lambda().eq(ReceiptOrderAccount::getOrderId, busId)); - for (ReceiptOrderAccount account : accounts) { - String subjectCode = account.getSubjectCode(); - String subjectName = account.getSubjectName(); - String serviceItemsCode = account.getServiceItemsCode(); - if (shipperId == null) { - continue; - } - log.info("开始执行{}", com.alibaba.fastjson.JSONObject.toJSONString(stockReceiptOrder)); - BusinessDataPushDTO businessDataPushDTO = new BusinessDataPushDTO(); - businessDataPushDTO.setOrganizationId(organizationId); - businessDataPushDTO.setTopOrganizationId(topOrganizationId); - businessDataPushDTO.setOrganizationName(organizationName); - businessDataPushDTO.setBelongModuleCode("wms"); - businessDataPushDTO.setBillAmount(account.getAmount());//计费金额 - businessDataPushDTO.setEstimatedCost(account.getSettlementAmount());//计算金额 - com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject(); - if ("装卸费".equals(subjectName)) { - jsonObject.put("loading_unloading_unit_price", account.getPrice());//装卸货单价 - jsonObject.put("cargo_quantity",account.getNum());//货物数量 - } else if ("贴标费".equals(subjectName)) { - jsonObject.put("wooden_case_labeling_unit_price", account.getPrice());//木箱单价 - jsonObject.put("carton_labeling_unit_price",account.getPrice());//纸箱单价 - jsonObject.put("wooden_case_quantity",account.getNum());//木箱数量 - jsonObject.put("carton_quantity",account.getNum());//纸箱数量 - } else if ("进出仓操作费".equals(subjectName)) { - jsonObject.put("cargo_quantity", account.getNum());//货物数量 - jsonObject.put("warehouse_handling_unit_price",account.getPrice());//进出仓操作费单价 - } - businessDataPushDTO.setDocumentFormJson(jsonObject.toJSONString()); - businessDataPushDTO.setDocumentTypeCode("WMS_ckjccd"); - businessDataPushDTO.setSettlementEntityId(shipperId); - businessDataPushDTO.setSecondSubjectCode(subjectCode); - businessDataPushDTO.setServiceItemsCode(serviceItemsCode); - businessDataPushDTO.setDataSources(1); - businessDataPushDTO.setTaxRate(account.getRate()); - //businessDataPushDTO.setSettlementCurrency(leasePO.getSettlementCurrency()); - //businessDataPushDTO.setSalesmanId(leasePO.getSalesmanId()); - bmsServiceFeign.wholeRentSynchronizationZXF(businessDataPushDTO); - } - log.info("定时任务整租推送到bms触发--结束"); - } /** * 同步更新入库单明细的收货数量(总毛重/总净重/总面积/总体积不再写入入库单明细,逻辑已注释保留) @@ -720,6 +668,91 @@ public class StockReceiptOrderDomainService { * @author ZhouGY * @date 2024/6/14 17:27 */ + /** + * 整单完成判断:只认计划主行(level 空或 1)。分批子行(level=2)不应单独占一票,否则易与主行同组已收尾仍计为「未完结」。 + */ + private static boolean isReceiptPlanLineForOrderCompletionGate(ReceiptMaterialDetailDO d) { + Integer lv = d.getLevel(); + return lv == null || lv == 1; + } + + private static boolean sameLongIdForReceiptGate(Long a, Long b) { + if (a == null || b == null) { + return false; + } + return a.longValue() == b.longValue(); + } + + /** + * 是否与 {@link com.mhd.wms.application.service.stockReceiptOrder.StockReceiptOrderApplicationService} 中 + * PDA flatten / 超收校验用的「计划父行下 level=2」范围一致。 + */ + private static boolean isLevel2ChildUnderPlanForReceiptCompletionGate(ReceiptMaterialDetailPO plan, ReceiptMaterialDetailPO x) { + if (plan == null || x == null) { + return false; + } + if (x.getLevel() == null || x.getLevel() != 2) { + return false; + } + Long puid = x.getParentUniqueId(); + if (puid == null || Long.valueOf(0).equals(puid)) { + return false; + } + Long uid = plan.getUniqueId(); + Long inUid = plan.getInUniqueId(); + boolean linked = (uid != null && sameLongIdForReceiptGate(uid, puid)) + || (inUid != null && sameLongIdForReceiptGate(inUid, puid)); + if (!linked) { + return false; + } + return plan.getUniqueId() == null || !sameLongIdForReceiptGate(plan.getUniqueId(), x.getUniqueId()); + } + + private static BigDecimal nzBdGate(BigDecimal v) { + return v != null ? v : BigDecimal.ZERO; + } + + /** 计划父行自身 already_receipt + 其下归属子行,与 PDA 汇总口径一致 */ + private static BigDecimal sumAlreadyReceiptUnderPlanForWholeOrderGate(ReceiptMaterialDetailPO plan, + List allRows) { + if (plan == null || CollectionUtils.isEmpty(allRows)) { + return BigDecimal.ZERO; + } + BigDecimal sum = nzBdGate(plan.getAlreadyReceiptQuantity()); + for (ReceiptMaterialDetailPO x : allRows) { + if (isLevel2ChildUnderPlanForReceiptCompletionGate(plan, x)) { + sum = sum.add(nzBdGate(x.getAlreadyReceiptQuantity())); + } + } + return sum; + } + + private static boolean isReceiptPlanLinePoForGate(ReceiptMaterialDetailPO p) { + if (p == null) { + return false; + } + Integer lv = p.getLevel(); + return lv == null || lv == 1; + } + + /** + * 计划主行是否仍阻塞整单完成:状态为待收/收货中,且(主+子)累计已收仍低于计划量。 + * 多批次拆子行后主行 receipt_status 可能长期为 2,但累计已收已满,不得再阻塞。 + */ + private static boolean isPlanLineStillBlockingWholeOrderCompletion(ReceiptMaterialDetailPO plan, + List allDbLines) { + Integer st = plan.getReceiptStatus(); + if (st == null || st >= 3) { + return false; + } + BigDecimal planQty = plan.getQuantity(); + if (planQty == null) { + planQty = BigDecimal.ZERO; + } + BigDecimal sumAlready = sumAlreadyReceiptUnderPlanForWholeOrderGate(plan, allDbLines); + return sumAlready.compareTo(planQty) < 0; + } + @Transactional(rollbackFor = Exception.class) public Boolean updateStockReceiptOrder(StockReceiptOrderDO stockReceiptOrderDO, StockReceiptOrderPO stockReceiptOrderPO) { LoginUser loginUser = SecurityUtils.getLoginUser(); @@ -738,13 +771,32 @@ public class StockReceiptOrderDomainService { int addArm = stockReceiptOrderDO.getActualReceiptMaterialQuantity() != null ? stockReceiptOrderDO.getActualReceiptMaterialQuantity() : 0; stockReceiptOrder.setReceiptMaterialQuantity(prevRmq + addArm); } + stockReceiptOrder.setBillingJson(stockReceiptOrderDO.getBillingJson()); stockReceiptOrder.setStatus(2); stockReceiptOrder.setUpdateBy(loginUser.getUserid()); stockReceiptOrder.setUpdateByName(loginUser.getUsername()); stockReceiptOrder.setUpdateTime(new Date()); stockReceiptOrderService.updateById(stockReceiptOrder); - //获取所有明细中的收货状态小于3的数量--未完成收货的明细 - long receiptMaterialQuantity = stockReceiptOrderDO.getMaterialDetailList().stream().filter(receiptMaterialDetailDO -> receiptMaterialDetailDO.getReceiptStatus() < 3).count(); + // 必须以落库后的全量明细为准:请求体里的主行 receipt_status 在多批次拆子行后可能仍为「收货中」, + // 但主行+子行 already_receipt 已满计划量,不得阻塞 completeReceipt。 + long receiptMaterialQuantity = 0L; + if (StringUtils.isNotBlank(stockReceiptOrderPO.getReceiptOrderNumber())) { + ReceiptMaterialDetailDO qAll = new ReceiptMaterialDetailDO(); + qAll.setReceiptOrderNumber(stockReceiptOrderPO.getReceiptOrderNumber()); + List allDbLines = receiptMaterialDetailService.queryList(qAll); + if (!CollectionUtils.isEmpty(allDbLines)) { + receiptMaterialQuantity = allDbLines.stream() + .filter(StockReceiptOrderDomainService::isReceiptPlanLinePoForGate) + .filter(p -> isPlanLineStillBlockingWholeOrderCompletion(p, allDbLines)) + .count(); + } + } else { + receiptMaterialQuantity = stockReceiptOrderDO.getMaterialDetailList().stream() + .filter(d -> d != null && isReceiptPlanLineForOrderCompletionGate(d)) + .filter(receiptMaterialDetailDO -> receiptMaterialDetailDO.getReceiptStatus() != null + && receiptMaterialDetailDO.getReceiptStatus() < 3) + .count(); + } //收货数量大于等于计划数量 直接完成收货 if (stockReceiptOrder.getReceiptQuantity().compareTo(stockReceiptOrderPO.getQuantity()) >= 0 && receiptMaterialQuantity == 0){ completeReceipt(stockReceiptOrderPO.getReceiptOrderId(), stockReceiptOrderDO.getFromPda()); @@ -765,6 +817,7 @@ public class StockReceiptOrderDomainService { StockInOrder stockInOrder = new StockInOrder(); stockInOrder.setInOrderNumber(stockReceiptOrderPO.getInOrderNumber()); stockInOrder.setStatus(3); + stockInOrder.setBillingJson(stockReceiptOrderPO.getBillingJson()); stockInOrder.setUpdateBy(loginUser.getUserid()); stockInOrder.setUpdateByName(loginUser.getUsername()); stockInOrder.setUpdateTime(new Date()); @@ -837,10 +890,22 @@ public class StockReceiptOrderDomainService { .set(StockReceiptOrder::getUpdateTime, new Date()) .eq(StockReceiptOrder::getReceiptOrderId, receiptOrderId)); //推送bms - wholeRentSynchronizationZXF(receiptOrderId); + //wholeRentSynchronizationZXF(receiptOrderId); return update; } + public void updateInOrder(StockReceiptOrderDTO stockReceiptOrderDTO) { + String inOrderNumber = stockReceiptOrderDTO.getInOrderNumber(); + Long receiptOrderId = stockReceiptOrderDTO.getReceiptOrderId(); + String billingJson = stockReceiptOrderDTO.getBillingJson(); + if (inOrderNumber == null) { + StockReceiptOrder stockReceiptOrder = stockReceiptOrderService.getById(receiptOrderId); + inOrderNumber = stockReceiptOrder.getInOrderNumber(); + } + stockInOrderService.update(null, new UpdateWrapper().lambda().set(StockInOrder::getBillingJson,billingJson).eq(StockInOrder::getInOrderNumber, inOrderNumber)); + stockReceiptOrderService.update(null, new UpdateWrapper().lambda().set(StockReceiptOrder::getBillingJson,billingJson).eq(StockReceiptOrder::getReceiptOrderId, receiptOrderId)); + } + /** * 收货单完成时:按累计已收与计划数量比较,更新明细 receipt_status(3 正常收完 / 4 少收 / 5 超收) *

PC 主子行拆分收货时:计划数量只在主行(level=1),子行 quantity 常为 0;须按「主行已收 + 其下子行已收」与主行计划比较, diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/stockShelfOrder/repository/po/StockShelfOrderPO.java b/mhd_wms/src/main/java/com/mhd/wms/domain/stockShelfOrder/repository/po/StockShelfOrderPO.java index abe8d130d..4d1b8910c 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/stockShelfOrder/repository/po/StockShelfOrderPO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/stockShelfOrder/repository/po/StockShelfOrderPO.java @@ -105,4 +105,21 @@ public class StockShelfOrderPO extends StockInOrderBasePO { @ApiModelProperty("物料明细") private List materialDetailList; + /** 详情接口按行递归汇总(与收货单 getInfo 一致),供 PC 展示 */ + @ApiModelProperty("总净重(KG)") + @Excel(name = "总净重(KG)") + private BigDecimal totalNetWeight; + + @ApiModelProperty("总毛重(KG)") + @Excel(name = "总毛重(KG)") + private BigDecimal totalGrossWeight; + + @ApiModelProperty("总体积(CBM)") + @Excel(name = "总体积(CBM)") + private BigDecimal totalVolume; + + @ApiModelProperty("总面积(SQM)") + @Excel(name = "总面积(SQM)") + private BigDecimal totalArea; + } 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 8149ad2f9..b648be8fa 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 @@ -7,6 +7,7 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.mhd.common.core.constant.SnowFlakeConstants; import com.mhd.common.core.domain.po.UserPo; @@ -264,7 +265,33 @@ public class StockShelfOrderDomainService { return stockShelfOrderPO; } - + /** + * PDA:指定计划行(卡片)下所有 level=2 分批上架子行(库表真实子行,不含 parent_copy),附带序列号。 + * + * @param shelfOrderId 上架单主键 + * @param parentMaterialDetailId 卡片对应 shelf_material_detail.material_detail_id(可误传为某子行 id,将解析到其父计划行) + */ + public List listLevel2ChildrenByParentForApp(Long shelfOrderId, Long parentMaterialDetailId) { + StockShelfOrderPO order = stockShelfOrderService.getInfo(shelfOrderId); + if (order == null) { + throw new ServiceException("上架单不存在"); + } + List children = shelfMaterialDetailService.queryLevel2ChildrenByParentMaterialDetailId( + order.getShelfOrderNumber(), parentMaterialDetailId); + if (CollectionUtils.isEmpty(children)) { + return new ArrayList<>(); + } + InMaterialDetailSerialNumberDO snDo = new InMaterialDetailSerialNumberDO(); + snDo.setOrderNumber(order.getShelfOrderNumber()); + List snList = inMaterialDetailSerialNumberService.queryList(snDo); + Map> snMap = snList.stream() + .collect(Collectors.groupingBy(InMaterialDetailSerialNumberPO::getMaterialDetailUniqueId)); + for (ShelfMaterialDetailPO ch : children) { + List sns = ch.getUniqueId() != null ? snMap.get(ch.getUniqueId()) : null; + ch.setMaterialDetailSerialNumberList(!CollectionUtils.isEmpty(sns) ? sns : new ArrayList<>()); + } + return children; + } /** * @description 任务下发 @@ -320,6 +347,10 @@ public class StockShelfOrderDomainService { genContainerUsageRecord(stockShelfOrderDO); //修改物料明细信息 shelfMaterialDetailService.batchShelfUpdate(stockShelfOrderDO); + LoginUser loginUserUpShelf = SecurityUtils.getLoginUser(); + String userRealNameUpShelf = resolveUserRealNameForShelf(loginUserUpShelf); + refreshShelfMaterialDetailShelvesStatusAfterPartialUpShelf(stockShelfOrderPO.getShelfOrderNumber(), loginUserUpShelf, + userRealNameUpShelf); //同步更新入库单明细的上架数量/上架状态 syncShelvesQuantityToInMaterialDetail(stockShelfOrderDO); //生成 上架作业单 @@ -659,11 +690,225 @@ public class StockShelfOrderDomainService { if (abnormal == 1){ genInOrderAbnormal(stockShelfOrderPO); } + String userRealNameComplete = resolveUserRealNameForShelf(loginUser); + updateShelfMaterialDetailShelvesStatusWhenOrderCompleted(stockShelfOrderPO, loginUser, userRealNameComplete); //推送业务数据到BMS系统 // pushSyncBmsDomainService.pushInShelfOrder(stockShelfOrderPO.getInOrderNumber()); return true; } + /** + * 分批/单次上架提交后:按主行+子行汇总「累计已上架」与主行计划量比较,刷新各明细 shelves_status(待上 1 / 上中 2 / 满 3 / 超 5) + */ + private void refreshShelfMaterialDetailShelvesStatusAfterPartialUpShelf(String shelfOrderNumber, + LoginUser loginUser, String userRealName) { + if (StringUtils.isBlank(shelfOrderNumber) || loginUser == null) { + return; + } + Date updateTime = new Date(); + List details = shelfMaterialDetailService.list( + new QueryWrapper().lambda() + .eq(ShelfMaterialDetail::getShelfOrderNumber, shelfOrderNumber) + .eq(ShelfMaterialDetail::getDelFlag, 1)); + if (CollectionUtils.isEmpty(details)) { + return; + } + Map> childrenByParentUniqueId = new HashMap<>(); + for (ShelfMaterialDetail d : details) { + if (isShelfDetailChildRow(d) && d.getParentUniqueId() != null) { + childrenByParentUniqueId.computeIfAbsent(d.getParentUniqueId(), k -> new ArrayList<>()).add(d); + } + } + Set parentUniqueIdsInOrder = details.stream() + .filter(d -> !isShelfDetailChildRow(d)) + .map(ShelfMaterialDetail::getUniqueId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + for (ShelfMaterialDetail parent : details) { + if (isShelfDetailChildRow(parent)) { + continue; + } + Integer status; + List children = parent.getUniqueId() == null ? null + : childrenByParentUniqueId.get(parent.getUniqueId()); + if (!CollectionUtils.isEmpty(children)) { + BigDecimal groupShelved = nzShelf(parent.getAlreadyShelvesQuantity()); + for (ShelfMaterialDetail ch : children) { + groupShelved = groupShelved.add(nzShelf(ch.getAlreadyShelvesQuantity())); + } + status = deriveShelfDetailStatusWhileOrderOpen(groupShelved, parent.getQuantity()); + } else { + status = deriveShelfDetailStatusWhileOrderOpen(parent.getAlreadyShelvesQuantity(), parent.getQuantity()); + } + parent.setShelvesStatus(status); + parent.setUpdateBy(loginUser.getUserid()); + parent.setUpdateByName(userRealName); + parent.setUpdateTime(updateTime); + if (!CollectionUtils.isEmpty(children)) { + for (ShelfMaterialDetail ch : children) { + ch.setShelvesStatus(status); + ch.setUpdateBy(loginUser.getUserid()); + ch.setUpdateByName(userRealName); + ch.setUpdateTime(updateTime); + } + } + } + for (ShelfMaterialDetail d : details) { + if (isShelfDetailChildRow(d) && d.getParentUniqueId() != null + && !parentUniqueIdsInOrder.contains(d.getParentUniqueId())) { + d.setShelvesStatus(deriveShelfDetailStatusWhileOrderOpen(d.getAlreadyShelvesQuantity(), d.getQuantity())); + d.setUpdateBy(loginUser.getUserid()); + d.setUpdateByName(userRealName); + d.setUpdateTime(updateTime); + } + } + flushShelfMaterialDetailShelvesStatusColumnsOnly(details, loginUser, userRealName); + } + + /** + * 整单完成上架:按累计已上架与计划比较,更新明细 shelves_status(3 已上满 / 4 少上 / 5 超上) + */ + private void updateShelfMaterialDetailShelvesStatusWhenOrderCompleted(StockShelfOrderPO stockShelfOrderPO, + LoginUser loginUser, String userRealName) { + if (stockShelfOrderPO == null || StringUtils.isBlank(stockShelfOrderPO.getShelfOrderNumber()) || loginUser == null) { + return; + } + Date updateTime = new Date(); + List details = shelfMaterialDetailService.list( + new QueryWrapper().lambda() + .eq(ShelfMaterialDetail::getShelfOrderNumber, stockShelfOrderPO.getShelfOrderNumber()) + .eq(ShelfMaterialDetail::getDelFlag, 1)); + if (CollectionUtils.isEmpty(details)) { + return; + } + Map> childrenByParentUniqueId = new HashMap<>(); + for (ShelfMaterialDetail d : details) { + if (isShelfDetailChildRow(d) && d.getParentUniqueId() != null) { + childrenByParentUniqueId.computeIfAbsent(d.getParentUniqueId(), k -> new ArrayList<>()).add(d); + } + } + Set parentUniqueIdsInOrder = details.stream() + .filter(d -> !isShelfDetailChildRow(d)) + .map(ShelfMaterialDetail::getUniqueId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + for (ShelfMaterialDetail parent : details) { + if (isShelfDetailChildRow(parent)) { + continue; + } + Integer status; + List children = parent.getUniqueId() == null ? null + : childrenByParentUniqueId.get(parent.getUniqueId()); + if (!CollectionUtils.isEmpty(children)) { + BigDecimal groupShelved = nzShelf(parent.getAlreadyShelvesQuantity()); + for (ShelfMaterialDetail ch : children) { + groupShelved = groupShelved.add(nzShelf(ch.getAlreadyShelvesQuantity())); + } + status = resolveShelfDetailStatusOnOrderComplete(groupShelved, parent.getQuantity()); + } else { + status = resolveShelfDetailStatusOnOrderComplete(parent.getAlreadyShelvesQuantity(), parent.getQuantity()); + } + parent.setShelvesStatus(status); + parent.setUpdateBy(loginUser.getUserid()); + parent.setUpdateByName(userRealName); + parent.setUpdateTime(updateTime); + if (!CollectionUtils.isEmpty(children)) { + for (ShelfMaterialDetail ch : children) { + ch.setShelvesStatus(status); + ch.setUpdateBy(loginUser.getUserid()); + ch.setUpdateByName(userRealName); + ch.setUpdateTime(updateTime); + } + } + } + for (ShelfMaterialDetail d : details) { + if (isShelfDetailChildRow(d) && d.getParentUniqueId() != null + && !parentUniqueIdsInOrder.contains(d.getParentUniqueId())) { + d.setShelvesStatus(resolveShelfDetailStatusOnOrderComplete(d.getAlreadyShelvesQuantity(), d.getQuantity())); + d.setUpdateBy(loginUser.getUserid()); + d.setUpdateByName(userRealName); + d.setUpdateTime(updateTime); + } + } + flushShelfMaterialDetailShelvesStatusColumnsOnly(details, loginUser, userRealName); + } + + /** + * 只落库上架状态及审计字段。{@link ShelfMaterialDetail} 查询结果中 total_* 与 alreadyShelves* 曾映射同一列, + * 使用 {@code updateBatchById} 会生成重复的 SET 列名(达梦报错)。此处按主键逐条 {@code update(wrapper)} 仅更新必要列。 + */ + private void flushShelfMaterialDetailShelvesStatusColumnsOnly(List details, LoginUser loginUser, + String userRealName) { + if (CollectionUtils.isEmpty(details) || loginUser == null) { + return; + } + for (ShelfMaterialDetail d : details) { + if (d == null || d.getMaterialDetailId() == null) { + continue; + } + shelfMaterialDetailService.update(null, new LambdaUpdateWrapper() + .set(ShelfMaterialDetail::getShelvesStatus, d.getShelvesStatus()) + .set(ShelfMaterialDetail::getUpdateBy, loginUser.getUserid()) + .set(ShelfMaterialDetail::getUpdateByName, userRealName) + .set(ShelfMaterialDetail::getUpdateTime, d.getUpdateTime() != null ? d.getUpdateTime() : new Date()) + .eq(ShelfMaterialDetail::getMaterialDetailId, d.getMaterialDetailId())); + } + } + + private static boolean isShelfDetailChildRow(ShelfMaterialDetail d) { + return d.getLevel() != null && d.getLevel() == 2 + && d.getParentUniqueId() != null && d.getParentUniqueId() != 0L; + } + + private static BigDecimal nzShelf(BigDecimal v) { + return v != null ? v : BigDecimal.ZERO; + } + + /** 进行中:1 待上架 / 2 上架中 / 3 已上满 / 5 超上 */ + private static Integer deriveShelfDetailStatusWhileOrderOpen(BigDecimal alreadyShelvesQuantity, BigDecimal quantity) { + BigDecimal already = alreadyShelvesQuantity != null ? alreadyShelvesQuantity : BigDecimal.ZERO; + BigDecimal plan = quantity != null ? quantity : BigDecimal.ZERO; + if (already.compareTo(BigDecimal.ZERO) == 0) { + return 1; + } + int cmp = already.compareTo(plan); + if (cmp < 0) { + return 2; + } + if (cmp > 0) { + return 5; + } + return 3; + } + + /** 完成整单:3 已上满 / 4 少上 / 5 超上 */ + private static Integer resolveShelfDetailStatusOnOrderComplete(BigDecimal alreadyShelvesQuantity, BigDecimal quantity) { + BigDecimal already = alreadyShelvesQuantity != null ? alreadyShelvesQuantity : 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; + } + + private static String resolveUserRealNameForShelf(LoginUser loginUser) { + if (loginUser == null) { + return ""; + } + if (loginUser.getUserPo() != null && loginUser.getUserPo().getUserName() != null + && !loginUser.getUserPo().getUserName().trim().isEmpty()) { + return loginUser.getUserPo().getUserName(); + } + if (loginUser.getRealname() != null && !loginUser.getRealname().trim().isEmpty()) { + return loginUser.getRealname(); + } + return loginUser.getUsername() != null ? loginUser.getUsername() : ""; + } + private synchronized void stockIn(List shelfMaterialDetailDOList, StockShelfOrderDO stockReceiptOrderDO) { for (ShelfMaterialDetail shelfMaterialDetail : shelfMaterialDetailDOList) { Long materialBaseInfoId = shelfMaterialDetail.getMaterialBaseInfoId(); diff --git a/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/handoverTaskOrder/HandoverTaskOrderDTO.java b/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/handoverTaskOrder/HandoverTaskOrderDTO.java index 1f64a802a..882b70500 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/handoverTaskOrder/HandoverTaskOrderDTO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/handoverTaskOrder/HandoverTaskOrderDTO.java @@ -172,4 +172,6 @@ public class HandoverTaskOrderDTO extends BaseVOEntity { @ApiModelProperty("app上传的图片") private String pictureApp; -} + + private String billingJson; +} \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/stockInOrder/StockInOrderDTO.java b/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/stockInOrder/StockInOrderDTO.java index f1c28feed..821b7aa27 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/stockInOrder/StockInOrderDTO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/stockInOrder/StockInOrderDTO.java @@ -2,6 +2,7 @@ package com.mhd.wms.interfaces.dto.stockInOrder; import com.fasterxml.jackson.annotation.JsonFormat; import com.mhd.common.core.annotation.Excel; +import com.mhd.wms.domain.receiptOrderAccount.entity.ReceiptOrderAccount; import com.mhd.wms.interfaces.dto.inMaterialDetail.InMaterialDetailDTO; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -376,4 +377,15 @@ public class StockInOrderDTO extends StockInOrderBaseDTO { @ApiModelProperty("入库明细-物料编码,模糊匹配,与前端参数 materialCode 一致") private String materialCode; + + @ApiModelProperty(name = "费用参数json") + private String billingJson; + @ApiModelProperty("费用") + List receiptOrderAccountList; + @ApiModelProperty("结算币种") + private String settlementCurrency; + @ApiModelProperty("业务员ID") + private String salesmanId; + @ApiModelProperty("业务员名称") + private String salesmanName; } \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/stockOutOrder/StockOutOrderDTO.java b/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/stockOutOrder/StockOutOrderDTO.java index 9a36362a5..01a316880 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/stockOutOrder/StockOutOrderDTO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/stockOutOrder/StockOutOrderDTO.java @@ -3,6 +3,7 @@ package com.mhd.wms.interfaces.dto.stockOutOrder; import com.fasterxml.jackson.annotation.JsonAlias; import com.fasterxml.jackson.annotation.JsonFormat; import com.mhd.common.core.annotation.Excel; +import com.mhd.wms.domain.receiptOrderAccount.entity.ReceiptOrderAccount; import com.mhd.wms.interfaces.dto.outMaterialDetail.OutMaterialDetailDTO; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -430,4 +431,14 @@ public class StockOutOrderDTO extends StockOutOrderBaseDTO { @ApiModelProperty("承运商名称") @Excel(name = "承运商名称") private String carrierName; + @ApiModelProperty("计费信息") + private String billingJson; + @ApiModelProperty("结算币种") + private String settlementCurrency; + @ApiModelProperty("业务员ID") + private String salesmanId; + @ApiModelProperty("业务员名称") + private String salesmanName; + @ApiModelProperty("费用") + List receiptOrderAccountList; } \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/stockReceiptOrder/StockReceiptOrderDTO.java b/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/stockReceiptOrder/StockReceiptOrderDTO.java index c8d636b29..47c50905d 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/stockReceiptOrder/StockReceiptOrderDTO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/stockReceiptOrder/StockReceiptOrderDTO.java @@ -156,4 +156,7 @@ public class StockReceiptOrderDTO extends StockInOrderBaseDTO { @ApiModelProperty("费用") List receiptOrderAccountList; + + @ApiModelProperty(name = "费用参数json") + private String billingJson; } \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApi/stockInOrder/StockInOrderApi.java b/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApi/stockInOrder/StockInOrderApi.java index 734bfd32f..b16947a36 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApi/stockInOrder/StockInOrderApi.java +++ b/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApi/stockInOrder/StockInOrderApi.java @@ -10,8 +10,11 @@ import com.mhd.wms.domain.inMaterialDetail.entity.InMaterialDetail; import com.mhd.wms.domain.stockInOrder.entity.StockInOrder; import com.mhd.wms.domain.stockInOrder.repository.po.StockInOrderPO; import com.mhd.wms.domain.stockInOrder.repository.todo.StockInOrderDO; +import com.mhd.wms.domain.stockOutOrder.repository.todo.StockOutOrderDO; import com.mhd.wms.interfaces.assember.stockInOrder.StockInOrderAssembler; +import com.mhd.wms.interfaces.assember.stockOutOrder.StockOutOrderAssembler; import com.mhd.wms.interfaces.dto.stockInOrder.StockInOrderDTO; +import com.mhd.wms.interfaces.dto.stockOutOrder.StockOutOrderDTO; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @@ -34,6 +37,8 @@ public class StockInOrderApi extends BaseController { @Resource private StockInOrderAssembler stockInOrderAssembler; + @Resource + private StockOutOrderAssembler stockOutOrderAssembler; /** * 分页查询入库单列表 @@ -65,6 +70,28 @@ public class StockInOrderApi extends BaseController { } } + /** + * 编辑入库单 + */ + @ApiOperation("编辑入库单") + @PostMapping("/saveAmount") + public AjaxResult saveAmount(@RequestBody StockInOrderDTO stockInOrderDTO) + { + StockInOrderDO stockInOrderDO = stockInOrderAssembler.toDO(stockInOrderDTO); + return toAjax(stockInOrderApplicationService.saveAmount(stockInOrderDO)); + } + + /** + * 编辑入库单 + */ + @ApiOperation("编辑入库单") + @PostMapping("/saveOutAmount") + public AjaxResult saveOutAmount(@RequestBody StockOutOrderDTO stockOutOrderDTO) + { + StockOutOrderDO stockOutOrderDO = stockOutOrderAssembler.toDO(stockOutOrderDTO); + return toAjax(stockInOrderApplicationService.saveOutAmount(stockOutOrderDO)); + } + /** * 批量删除入库单 */ diff --git a/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApi/stockReceiptOrder/StockReceiptOrderApi.java b/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApi/stockReceiptOrder/StockReceiptOrderApi.java index 178f883e9..56baaf263 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApi/stockReceiptOrder/StockReceiptOrderApi.java +++ b/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApi/stockReceiptOrder/StockReceiptOrderApi.java @@ -98,6 +98,14 @@ public class StockReceiptOrderApi extends BaseController { return toAjax(stockReceiptOrderApplicationService.completeReceipt(receiptOrderId)); } + @ApiOperation("完成收货") + @PostMapping("/completeReceiptAndUpdateJson") + public AjaxResult completeReceipt(@RequestBody StockReceiptOrderDTO stockReceiptOrderDTO) { + Long receiptOrderId = stockReceiptOrderDTO.getReceiptOrderId(); + stockReceiptOrderApplicationService.updateInOrder(stockReceiptOrderDTO); + return toAjax(stockReceiptOrderApplicationService.completeReceipt(receiptOrderId)); + } + @ApiOperation("整单收货") @GetMapping("/entireReceipt/{receiptOrderIds}") public AjaxResult entireReceipt(@PathVariable("receiptOrderIds") Long[] receiptOrderIds) { @@ -111,4 +119,4 @@ public class StockReceiptOrderApi extends BaseController { return AjaxResult.success(list); } -} +} \ No newline at end of file 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 4e71b6abf..40e3234fd 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 @@ -64,13 +64,14 @@ public class StockReceiptOrderAppApi extends BaseController { } /** - * PDA:查询当前卡片(计划行)下全部分批收货子行(level=2,库表真实子行,无 parent_copy) + * PDA:查询某计划行(卡片)下所有 level=2 分批收货子行(含首笔仅落主行时的主行快照),附带序列号。 */ - @ApiOperation("查询指定收货明细下的分批子行列表(level=2)") + @ApiOperation("按父计划行查询分批收货子行(level=2)") @GetMapping("/listLevel2ChildrenByParent") public AjaxResult listLevel2ChildrenByParent( @ApiParam(value = "收货单ID", required = true) @RequestParam Long receiptOrderId, - @ApiParam(value = "卡片对应明细主键 material_detail_id", required = true) @RequestParam Long materialDetailId) { + @ApiParam(value = "收货明细 material_detail_id(计划行或子行均可,会解析到计划父行)", required = true) + @RequestParam Long materialDetailId) { List list = stockReceiptOrderApplicationService.listLevel2ChildrenByParentForApp( receiptOrderId, materialDetailId); return AjaxResult.success(list); @@ -93,6 +94,7 @@ public class StockReceiptOrderAppApi extends BaseController { @ApiOperation("完成收货") @PostMapping("/completeReceipt") public AjaxResult completeReceipt(@RequestBody StockReceiptOrderDTO stockReceiptOrderDTO) { + stockReceiptOrderApplicationService.updateInOrder(stockReceiptOrderDTO); return toAjax(stockReceiptOrderApplicationService.completeReceiptByApp(stockReceiptOrderDTO.getReceiptOrderId())); } @@ -112,4 +114,4 @@ public class StockReceiptOrderAppApi extends BaseController { return toAjax(stockReceiptOrderApplicationService.noOrderReceipt(stockReceiptOrderDO)); } -} +} \ No newline at end of file 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 37e94a3a9..50bd9dda0 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 @@ -5,11 +5,13 @@ import com.mhd.common.core.web.domain.AjaxResult; import com.mhd.common.core.web.page.TableDataInfoApi; import com.mhd.common.security.utils.SecurityUtils; import com.mhd.wms.application.service.stockShelfOrder.StockShelfOrderApplicationService; +import com.mhd.wms.domain.shelfMaterialDetail.repository.po.ShelfMaterialDetailPO; import com.mhd.wms.domain.stockShelfOrder.repository.po.StockShelfOrderPO; import com.mhd.wms.domain.stockShelfOrder.repository.todo.StockShelfOrderDO; import com.mhd.wms.interfaces.assember.stockShelfOrder.StockShelfOrderAssembler; import com.mhd.wms.interfaces.dto.stockShelfOrder.StockShelfOrderDTO; import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @@ -47,7 +49,7 @@ public class StockShelfOrderAppApi extends BaseController { } /** - * 获取上架单详细信息(PDA:主项无子项时添加 parent_copy,供详情页从 children 读取数据) + * 获取上架单详细信息(PDA:与收货 getInfoByApp 一致保留父子结构;子行计划数量在服务端清空,见 StockShelfOrderApplicationService#getInfo) */ @ApiOperation("获取上架单") @GetMapping(value = "/getInfo") @@ -58,6 +60,19 @@ public class StockShelfOrderAppApi extends BaseController { return AjaxResult.success(stockShelfOrderApplicationService.getInfo(shelfOrderId, true, shelfStatus)); } + /** + * PDA:查询某计划行(卡片)下所有 level=2 分批上架子行(含首笔仅落主行时的主行快照),附带序列号。 + */ + @ApiOperation("按父计划行查询分批上架子行(level=2)") + @GetMapping("/listLevel2ChildrenByParent") + public AjaxResult listLevel2ChildrenByParent( + @ApiParam(value = "上架单ID", required = true) @RequestParam Long shelfOrderId, + @ApiParam(value = "上架明细 material_detail_id(计划行或子行均可,会解析到计划父行)", required = true) + @RequestParam Long materialDetailId) { + List list = stockShelfOrderApplicationService.listLevel2ChildrenByParentForApp( + shelfOrderId, materialDetailId); + return AjaxResult.success(list); + } @ApiOperation("上架") @PostMapping("/upShelf") diff --git a/mhd_wms/src/main/resources/bootstrap.yml b/mhd_wms/src/main/resources/bootstrap.yml index 4123b7a99..02b11d559 100644 --- a/mhd_wms/src/main/resources/bootstrap.yml +++ b/mhd_wms/src/main/resources/bootstrap.yml @@ -14,24 +14,24 @@ spring: nacos: discovery: # server-addr: 127.0.0.1:8848 - server-addr: 10.33.0.129:6010 - # 线上测试环境配置 容器名+端口号 - # server-addr: 10.102.192.5:6848 - # username: nacos - # password: manhuoda@2023 - #线上正式环境 - # server-addr: 10.102.192.105:6848 + # server-addr: 10.33.0.129:6010 + # 线上测试环境配置 容器名+端口号 + server-addr: 10.102.192.5:6848 + username: nacos + password: manhuoda@2023 + #线上正式环境 +# server-addr: 10.102.192.105:6848 config: # server-addr: 127.0.0.1:8848 - server-addr: 10.33.0.129:6010 + # server-addr: 10.33.0.129:6010 # 线上测试环境配置 容器名+端口号 - # server-addr: 10.102.192.5:6848 - # username: nacos - # password: manhuoda@2023 + server-addr: 10.102.192.5:6848 + username: nacos + password: manhuoda@2023 #线上正式环境 # server-addr: 10.102.192.105:6848 # 配置文件格式 file-extension: yml # 共享配置 shared-configs: - - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} \ No newline at end of file + - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} diff --git a/mhd_wms/src/main/resources/mapper/handoverTaskOrder/HandoverTaskOrderMapper.xml b/mhd_wms/src/main/resources/mapper/handoverTaskOrder/HandoverTaskOrderMapper.xml index 37e2a11d5..79a8362fe 100644 --- a/mhd_wms/src/main/resources/mapper/handoverTaskOrder/HandoverTaskOrderMapper.xml +++ b/mhd_wms/src/main/resources/mapper/handoverTaskOrder/HandoverTaskOrderMapper.xml @@ -40,6 +40,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + @@ -48,7 +49,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" a.platform_code, a.platform_name, a.platform_use_time_id, a.platform_use_start_time, a.platform_use_end_time, a.platform_use_status, a.order_type_code, a.order_type_name, a.expect_time, a.warehouse_id, a.warehouse_code, a.warehouse_name, a.shipper_id, a.shipper_name, a.order_number, a.picking_order_number, a.remark, a.task_distribution, a.task_distribution_time, a.create_time, a.create_by, a.create_by_name, a.update_time, - a.update_by, a.update_by_name, a.del_flag, a.picture_app + a.update_by, a.update_by_name, a.del_flag, a.picture_app,a.billing_json diff --git a/mhd_wms/src/main/resources/mapper/stockInOrder/StockInOrderMapper.xml b/mhd_wms/src/main/resources/mapper/stockInOrder/StockInOrderMapper.xml index d6f3c6075..3613b2d8e 100644 --- a/mhd_wms/src/main/resources/mapper/stockInOrder/StockInOrderMapper.xml +++ b/mhd_wms/src/main/resources/mapper/stockInOrder/StockInOrderMapper.xml @@ -81,8 +81,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + + + + + + a.in_order_id, a.organization_id, a.organization_name, a.top_organization_id, a.notice_number, a.in_order_number, a.status, + a.audit_status, a.audit_remark, a.audit_by, a.audit_by_name, a.audit_time, a.warehouse_id, a.warehouse_code, a.warehouse_name, a.shipper_id, a.shipper_code, + a.shipper_name, a.order_type_code, a.order_type_name, a.supplier_id, a.supplier_code, a.supplier_name, a.expect_time, a.supply_chain_number, + a.priority_level_code, a.priority_level_name, a.direct_warehouse, a.annex_url, a.material_quantity, a.quantity,a.billing_json,a.SETTLEMENT_CURRENCY, + a.SALESMAN_ID,a.SALESMAN_NAME, + -- 计划入库数量:入库明细表 in_material_detail 的 quantity 汇总 (select ifnull(sum(imd.quantity), 0) diff --git a/mhd_wms/src/main/resources/mapper/stockOutOrder/StockOutOrderMapper.xml b/mhd_wms/src/main/resources/mapper/stockOutOrder/StockOutOrderMapper.xml index b5c129e52..8b198f3a3 100644 --- a/mhd_wms/src/main/resources/mapper/stockOutOrder/StockOutOrderMapper.xml +++ b/mhd_wms/src/main/resources/mapper/stockOutOrder/StockOutOrderMapper.xml @@ -82,6 +82,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + + + @@ -97,7 +101,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" a.CONTACT_PERSON,a.VEHICLE_MODEL_PLATE,a.ENTRUST_NO,a.TEL,a.DRIVER_SIGN,a.FAX,a.DECLARE_CUSTOMS,a.MANUFACTURER, a.CUSTOMS_DECLARER_INFO,a.DELIVERY_ADDR,a.ENTRY_EXIT_CUSTOMS,a.DEPARTURE_ARRIVAL_COUNTRY,a.CARRIER,a.CONTAINER_NO,a.CONTAINER_NO_NAME,a.OUTBOUND_DATE, a.COMPLETE_TIME,a.ORDER_DATE,a.TRANSPORT_MODE_CODE,a.TRANSPORT_MODE_NAME,a.SUPERVISION_MODE_CODE,a.SUPERVISION_MODE_NAME, - a.CUSTOMS_INSPECTION_FLAG,a.NEED_DECLARE_FLAG,a.NEED_TRANSPORT_FLAG,a.picture_app + a.CUSTOMS_INSPECTION_FLAG,a.NEED_DECLARE_FLAG,a.NEED_TRANSPORT_FLAG,a.picture_app,a.billing_json,a.SETTLEMENT_CURRENCY, + a.SALESMAN_ID,a.SALESMAN_NAME diff --git a/mhd_wms/src/main/resources/mapper/stockReceiptOrder/StockReceiptOrderMapper.xml b/mhd_wms/src/main/resources/mapper/stockReceiptOrder/StockReceiptOrderMapper.xml index f575a6ff9..57252c476 100644 --- a/mhd_wms/src/main/resources/mapper/stockReceiptOrder/StockReceiptOrderMapper.xml +++ b/mhd_wms/src/main/resources/mapper/stockReceiptOrder/StockReceiptOrderMapper.xml @@ -42,6 +42,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + @@ -50,7 +51,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" a.status, a.platform_id, a.platform_code, a.platform_name, a.platform_use_time_id, a.platform_use_start_time, a.platform_use_end_time, a.platform_use_status, a.quantity, a.receipt_quantity, a.receipt_material_quantity, a.material_quantity, a.abnormal, a.task_distribution, a.task_distribution_time, a.operators_by, a.operators_name, a.remark, a.create_time, a.create_by, a.create_by_name, - a.update_time, a.update_by, a.update_by_name, a.del_flag + a.update_time, a.update_by, a.update_by_name, a.del_flag, a.billing_json @@ -155,26 +156,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ORDER BY a.create_time DESC - - - - - \ No newline at end of file diff --git a/sql/wkx20260403.sql b/sql/wkx20260403.sql index 99515425c..37665075e 100644 --- a/sql/wkx20260403.sql +++ b/sql/wkx20260403.sql @@ -6,7 +6,45 @@ COMMENT ON COLUMN "NGWL_TEST_SYSTEM"."EXPENSE_ACCOUNT"."IN_ORDER_DISPLAY" IS ' COMMENT ON COLUMN "NGWL_TEST_SYSTEM"."EXPENSE_ACCOUNT"."OUT_ORDER_DISPLAY" IS '出库单是否固定显示 0-否 1-是'; +ALTER TABLE "NGWL_TEST_WMS"."STOCK_OUT_ORDER" ADD COLUMN "SALESMAN_NAME" VARCHAR(100); +ALTER TABLE "NGWL_TEST_WMS"."STOCK_OUT_ORDER" ADD COLUMN "SETTLEMENT_CURRENCY" VARCHAR(100); + +ALTER TABLE "NGWL_TEST_WMS"."STOCK_OUT_ORDER" ADD COLUMN "SALESMAN_ID" VARCHAR(100); + +COMMENT ON COLUMN "NGWL_TEST_WMS"."STOCK_OUT_ORDER"."SALESMAN_NAME" IS '业务员名称'; + +COMMENT ON COLUMN "NGWL_TEST_WMS"."STOCK_OUT_ORDER"."SETTLEMENT_CURRENCY" IS '结算币种'; + +COMMENT ON COLUMN "NGWL_TEST_WMS"."STOCK_OUT_ORDER"."SALESMAN_ID" IS '业务员id'; + +ALTER TABLE "NGWL_TEST_WMS"."STOCK_IN_ORDER" ADD COLUMN "SALESMAN_NAME" VARCHAR(100); + +ALTER TABLE "NGWL_TEST_WMS"."STOCK_IN_ORDER" ADD COLUMN "SETTLEMENT_CURRENCY" VARCHAR(100); + +ALTER TABLE "NGWL_TEST_WMS"."STOCK_IN_ORDER" ADD COLUMN "SALESMAN_ID" VARCHAR(100); + +COMMENT ON COLUMN "NGWL_TEST_WMS"."STOCK_IN_ORDER"."SALESMAN_NAME" IS '业务员名称'; + +COMMENT ON COLUMN "NGWL_TEST_WMS"."STOCK_IN_ORDER"."SETTLEMENT_CURRENCY" IS '结算币种'; + +COMMENT ON COLUMN "NGWL_TEST_WMS"."STOCK_IN_ORDER"."SALESMAN_ID" IS '业务员id'; + +ALTER TABLE "NGWL_TEST_WMS"."STOCK_OUT_ORDER" ADD COLUMN "BILLING_JSON" CLOB; + +COMMENT ON COLUMN "NGWL_TEST_WMS"."STOCK_OUT_ORDER"."BILLING_JSON" IS '计费信息'; + +ALTER TABLE "NGWL_TEST_WMS"."STOCK_IN_ORDER" ADD COLUMN "BILLING_JSON" CLOB; + +COMMENT ON COLUMN "NGWL_TEST_WMS"."STOCK_IN_ORDER"."BILLING_JSON" IS '计费信息'; + +ALTER TABLE "NGWL_TEST_WMS"."HANDOVER_TASK_ORDER" ADD COLUMN "BILLING_JSON" CLOB; + +COMMENT ON COLUMN "NGWL_TEST_WMS"."HANDOVER_TASK_ORDER"."BILLING_JSON" IS '计费信息'; + +ALTER TABLE "NGWL_TEST_WMS"."STOCK_RECEIPT_ORDER" ADD COLUMN "BILLING_JSON" CLOB; + +COMMENT ON COLUMN "NGWL_TEST_WMS"."STOCK_RECEIPT_ORDER"."BILLING_JSON" IS '计费信息'; /* @@ -22,7 +60,7 @@ COMMENT ON COLUMN "NGWL_TEST_SYSTEM"."EXPENSE_ACCOUNT"."OUT_ORDER_DISPLAY" IS ' Target Server Version : 8014116 (08.01.4116) File Encoding : 65001 - Date: 03/04/2026 16:20:24 + Date: 10/04/2026 21:00:36 */ @@ -31,35 +69,36 @@ COMMENT ON COLUMN "NGWL_TEST_SYSTEM"."EXPENSE_ACCOUNT"."OUT_ORDER_DISPLAY" IS ' -- ---------------------------- DROP TABLE IF EXISTS "NGWL_TEST_WMS"."RECEIPT_ORDER_ACCOUNT"; CREATE TABLE "NGWL_TEST_WMS"."RECEIPT_ORDER_ACCOUNT" ( - "ID" VARCHAR(36) NOT NULL, - "SYS_ORG_CODE" VARCHAR(64) DEFAULT NULL, - "IS_DELETE" INT DEFAULT '0', - "ORG_NAME" VARCHAR(255) DEFAULT NULL, - "ORGANIZATION_ID" INT DEFAULT '0', - "TOP_ORGANIZATION_ID" INT DEFAULT '0', - "ORGANIZATION_NAME" VARCHAR(255) DEFAULT NULL, - "ORDER_ID" BIGINT DEFAULT NULL, - "ACCOUNT_ID" INT DEFAULT '0', - "ACCOUNT_TYPE" INT DEFAULT '0', - "SUBJECT_CODE" VARCHAR(255) DEFAULT NULL, - "SUBJECT_NAME" VARCHAR(255) DEFAULT NULL, - "RATE" DECIMAL(10,2) DEFAULT '0.00', - "AMOUNT" DECIMAL(10,2) DEFAULT '0.00', - "TAX_AMOUNT" DECIMAL(10,2), - "TAX_FREE_FEE" DECIMAL(10,2), - "RECEIVE_ACCOUNT" VARCHAR2(200), - "SETTLEMENT_AMOUNT" DECIMAL(10,2), - "PRICE" DECIMAL(10,2), - "NUM" DECIMAL(10,2), - "SERVICE_ITEMS_CODE" VARCHAR2(255), - "SERVICE_ITEMS_NAME" VARCHAR2(255), - "CREATE_TIME" TIMESTAMP(6), - "CREATE_BY" BIGINT DEFAULT 0, - "CREATE_BY_NAME" VARCHAR(20 CHAR) DEFAULT '', + "ID" VARCHAR(36) NOT NULL, + "SYS_ORG_CODE" VARCHAR(64) DEFAULT NULL, + "IS_DELETE" INT DEFAULT '0', + "ORG_NAME" VARCHAR(255) DEFAULT NULL, + "ORGANIZATION_ID" INT DEFAULT '0', + "TOP_ORGANIZATION_ID" INT DEFAULT '0', + "ORGANIZATION_NAME" VARCHAR(255) DEFAULT NULL, + "ORDER_ID" BIGINT DEFAULT NULL, + "ACCOUNT_ID" INT DEFAULT '0', + "ACCOUNT_TYPE" INT DEFAULT '0', + "SUBJECT_CODE" VARCHAR(255) DEFAULT NULL, + "SUBJECT_NAME" VARCHAR(255) DEFAULT NULL, + "RATE" DECIMAL(10,2) DEFAULT '0.00', + "AMOUNT" DECIMAL(10,2) DEFAULT '0.00', + "TAX_AMOUNT" DECIMAL(10,2), + "TAX_FREE_FEE" DECIMAL(10,2), + "RECEIVE_ACCOUNT" VARCHAR2(200), + "SETTLEMENT_AMOUNT" DECIMAL(10,2), + "PRICE" DECIMAL(10,2), + "NUM" DECIMAL(10,2), + "SERVICE_ITEMS_CODE" VARCHAR2(255), + "SERVICE_ITEMS_NAME" VARCHAR2(255), + "CREATE_TIME" TIMESTAMP(6), + "CREATE_BY" BIGINT DEFAULT 0, + "CREATE_BY_NAME" VARCHAR(20 CHAR) DEFAULT '', "UPDATE_TIME" TIMESTAMP(6), "UPDATE_BY" BIGINT DEFAULT 0, "UPDATE_BY_NAME" VARCHAR(20 CHAR) DEFAULT '', - "DEL_FLAG" TINYINT DEFAULT 1 + "DEL_FLAG" TINYINT DEFAULT 1, + "AMOUNT_JSON" CLOB ) ; COMMENT ON COLUMN "NGWL_TEST_WMS"."RECEIPT_ORDER_ACCOUNT"."SYS_ORG_CODE" IS '所属部门'; @@ -88,6 +127,7 @@ COMMENT ON COLUMN "NGWL_TEST_WMS"."RECEIPT_ORDER_ACCOUNT"."UPDATE_TIME" IS '最 COMMENT ON COLUMN "NGWL_TEST_WMS"."RECEIPT_ORDER_ACCOUNT"."UPDATE_BY" IS '最后修改人用户ID'; COMMENT ON COLUMN "NGWL_TEST_WMS"."RECEIPT_ORDER_ACCOUNT"."UPDATE_BY_NAME" IS '修改人姓名'; COMMENT ON COLUMN "NGWL_TEST_WMS"."RECEIPT_ORDER_ACCOUNT"."DEL_FLAG" IS '删除标记:0-无状态,1-正常,2-已删除'; +COMMENT ON COLUMN "NGWL_TEST_WMS"."RECEIPT_ORDER_ACCOUNT"."AMOUNT_JSON" IS '计算价格参数json'; -- ---------------------------- -- Primary Key structure for table RECEIPT_ORDER_ACCOUNT diff --git a/sql/wms_update20260414zq.sql b/sql/wms_update20260414zq.sql new file mode 100644 index 000000000..70df7f153 --- /dev/null +++ b/sql/wms_update20260414zq.sql @@ -0,0 +1,5 @@ +alter table NGWL_TEST_WMS.MATERIAL_BASE_INFO + add COPY_CODE TINYINT default 2; + +comment +on column NGWL_TEST_WMS.MATERIAL_BASE_INFO.COPY_CODE is '是否抄码: 1-是 2-否'; \ No newline at end of file