From 0514d223bba7aeaed00886fb95d3eefa5783875c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=A6=E9=B8=BF=E5=B1=95?= <18031053041@163.com> Date: Wed, 13 May 2026 16:03:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=95=E4=BB=B7=E5=88=97=E8=A1=A8=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ContractManageApplicationService.java | 187 ++++++++++++------ 1 file changed, 130 insertions(+), 57 deletions(-) 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 b35909df0..4fe0ae0b1 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 @@ -288,23 +288,39 @@ public class ContractManageApplicationService { .eq(ContractManageDetail::getContractManageId, contractManageId) .eq(ContractManageDetail::getDelFlag, 1)); if (contractManageDetails != null && contractManageDetails.size() > 0) { + Set expandedStrategyKeysThisSubject = new HashSet<>(); 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> preSetRulesList = JSON.parseObject(preSetRules, new TypeReference>>() {}); - List> billingParamsList = JSON.parseObject(billingParamsJson, new TypeReference>>() {}); - Map stringObjectMap1 = preSetRulesList.get(0); - for (Map stringObjectMap : billingParamsList) { + String lineSubjectCode = resolveSubjectCodeLine(contractManageDetail); + if (StringUtils.isEmpty(sunjectCode) || !sunjectCode.equals(lineSubjectCode)) { + continue; + } + Long accountingStrategyId = contractManageDetail.getAccountingStrategyId(); + if (accountingStrategyId == null) { + continue; + } + BillingRulesPO billingRule = contractManageDetailMapper.getBillingRules(accountingStrategyId); + if (billingRule == null || billingRule.getBillingRulesId() == null) { + continue; + } + Long billingRulesId = billingRule.getBillingRulesId(); + String strategyDedupeKey = billingStrategyDedupeKey(billingRulesId, contractManageDetail.getAccountingStrategyCode()); + if (!expandedStrategyKeysThisSubject.add(strategyDedupeKey)) { + continue; + } + 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> preSetRulesList = JSON.parseObject(preSetRules, new TypeReference>>() {}); + List> billingParamsList = JSON.parseObject(billingParamsJson, new TypeReference>>() {}); + if (preSetRulesList == null || preSetRulesList.size() == 0 || billingParamsList == null) { + continue; + } + Map stringObjectMap1 = preSetRulesList.get(0); + Set addedFeeSlotsForLine = new HashSet<>(); + for (Map stringObjectMap : billingParamsList) { String fieldsName = (String) stringObjectMap.get("fieldsName"); String isShow = (String) stringObjectMap.get("isShow"); String isFee = (String) stringObjectMap.get("isFee"); @@ -313,7 +329,15 @@ public class ContractManageApplicationService { Integer sort = (Integer) stringObjectMap.get("sort"); String chargingId = (String) stringObjectMap.get("chargingId"); String fields = (String) stringObjectMap.get("fields"); - String price = (String) stringObjectMap1.get("fields" + sort); + String feeSlotKey = billingRulesId + "|" + Objects.toString(sort, "") + "|" + Objects.toString(chargingId, ""); + if (!addedFeeSlotsForLine.add(feeSlotKey)) { + continue; + } + Object rawPrice = stringObjectMap1.get("fields" + sort); + if (rawPrice == null) { + continue; + } + String price = String.valueOf(rawPrice); SubjectAndPriceReturn subjectAndPriceReturn = new SubjectAndPriceReturn(); subjectAndPriceReturn.setName(fieldsName); subjectAndPriceReturn.setPrice(new BigDecimal(price)); @@ -326,8 +350,6 @@ public class ContractManageApplicationService { subjectAndPriceReturn.setRulesId(billingParamsId); result.add(subjectAndPriceReturn); } - } - } } } } @@ -425,12 +447,46 @@ public class ContractManageApplicationService { .anyMatch(code -> code.equalsIgnoreCase(documentTypeCode)); } + /** + * 与 {@link #resolveContractDetailExpenseSubjectCode} 一致:有二级编码则按二级匹配科目,否则按一级。 + */ + private static String resolveSubjectCodeLine(ContractManageDetail detail) { + if (detail == null) { + return null; + } + return resolveExpenseSubjectCodeFromFirstSecond(detail.getSecondSubjectCode(), detail.getFirstSubjectCode()); + } + + private static String resolveExpenseSubjectCodeFromFirstSecond(String secondSubjectCode, String firstSubjectCode) { + if (!StringUtils.isEmpty(secondSubjectCode)) { + return secondSubjectCode.trim(); + } + if (!StringUtils.isEmpty(firstSubjectCode)) { + return firstSubjectCode.trim(); + } + return null; + } + + /** + * 合同多行勾选「同一套」计费策略时,库中可能仍为不同的 accounting_strategy_id / billing_rules_id; + * 优先用结算行上的 {@code accounting_strategy_code} 去重展开,避免出现「几条科目 × 每条后面重复多套同一策略单价」的全局列表。 + */ + private static String billingStrategyDedupeKey(Long billingRulesId, String accountingStrategyCode) { + if (!StringUtils.isEmpty(accountingStrategyCode)) { + return "code:" + accountingStrategyCode.trim(); + } + if (billingRulesId != null) { + return "ruleId:" + billingRulesId; + } + return null; + } + /** * 按单据类型取合同结算行上的计费单价(计费策略展开的 isFee 项)。 - *

多条结算明细共用同一计费策略(与 {@link #getSubjectAndPrice} 一致:按计费策略 id 先解析 {@link BillingRulesPO}, - * 再以 {@code billing_rules_id} 取计费参数)时只展开一次,避免前端重复单价列。

- *

同一策略的参数 JSON 中若存在重复的 isFee 槽位(相同 sort/chargingId),或历史数据多套规则 id 实际等价, - * 返回列表会再做一次槽位级去重,避免出现两条「进出仓操作费单价」等同名列。

+ *

多条结算明细指向「界面上的同一计费策略」时,库表中可能仍为不同的 {@code billing_rules_id}, + * 仅以规则 id 去重会重复展开多次;因此对结算明细上非空的 {@link ContractManageDetailPO#getAccountingStrategyCode()} + * 优先做业务级去重(编码相同只展开一份),编码为空时再退回 {@code billing_rules_id}。

+ *

同一策略参数 JSON 内重复的 isFee 槽位仍以 {@code billingRulesId|sort|chargingId} 去重。

*/ public List getPrice(String documentTypeCode, String settlementCustomersCode,Long organizationId,Long topOrganizationId) { List result = new ArrayList<>(); @@ -444,7 +500,8 @@ public class ContractManageApplicationService { .filter(item -> contractDetailContainsDocumentType(item.getDocumentTypeCode(), documentTypeCode)) .collect(Collectors.toList()); if (contractManageDetailPOs != null && contractManageDetailPOs.size() > 0) { - Set expandedBillingRulesIds = new HashSet<>(); + /* 多行同一计费策略编码时只展开一次;无编码时再按计费规则 id 去重 */ + Set expandedStrategyKeys = new HashSet<>(); /* 计费规则 + 公式槽位,避免参数 JSON 或多次展开重复同一单价列 */ Set addedFeeSlots = new HashSet<>(); for (ContractManageDetailPO contractManageDetailPO : contractManageDetailPOs) { @@ -457,7 +514,8 @@ public class ContractManageApplicationService { continue; } Long billingRulesId = billingRulesPO.getBillingRulesId(); - if (!expandedBillingRulesIds.add(billingRulesId)) { + String strategyDedupeKey = billingStrategyDedupeKey(billingRulesId, contractManageDetailPO.getAccountingStrategyCode()); + if (!expandedStrategyKeys.add(strategyDedupeKey)) { continue; } List billingParams = contractManageDetailMapper.getBillingParams(billingRulesId); @@ -540,40 +598,55 @@ public class ContractManageApplicationService { .eq(ContractManageDetail::getContractManageId, contractManageId) .eq(ContractManageDetail::getDelFlag, 1)); if (contractManageDetails != null && contractManageDetails.size() > 0) { + Set expandedStrategyKeysThisSubject = new HashSet<>(); + Set addedFieldSlots = new HashSet<>(); 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); - } + String lineSubjectCode = resolveSubjectCodeLine(contractManageDetail); + if (StringUtils.isEmpty(sunjectCode) || !sunjectCode.equals(lineSubjectCode)) { + continue; + } + Long accountingStrategyId = contractManageDetail.getAccountingStrategyId(); + if (accountingStrategyId == null) { + continue; + } + BillingRulesPO billingRule = contractManageDetailMapper.getBillingRules(accountingStrategyId); + if (billingRule == null || billingRule.getBillingRulesId() == null) { + continue; + } + Long billingRulesId = billingRule.getBillingRulesId(); + String strategyDedupeKey = billingStrategyDedupeKey(billingRulesId, contractManageDetail.getAccountingStrategyCode()); + if (!expandedStrategyKeysThisSubject.add(strategyDedupeKey)) { + continue; + } + List billingParams = contractManageDetailMapper.getBillingParams(billingRulesId); + if (billingParams != null && billingParams.size() > 0) { + BillingParamsPO billingParam = billingParams.get(0); + String billingParamsJson = billingParam.getBillingParamsJson(); + 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)) { + Integer sort = (Integer) stringObjectMap.get("sort"); + String chargingId = (String) stringObjectMap.get("chargingId"); + String fields = (String) stringObjectMap.get("fields"); + String slotKey = billingRulesId + "|" + Objects.toString(sort, "") + "|" + Objects.toString(chargingId, ""); + if (!addedFieldSlots.add(slotKey)) { + continue; } + 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); } } }