From 36c264bfab7c33f5cb85e4f5e90010e70adefeef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=88=98=E6=B3=89=E4=BD=B3?= <1107186916@qq.com>
Date: Thu, 8 Oct 2026 18:39:57 +0800
Subject: [PATCH] =?UTF-8?q?Revert=20"feat:=20=E9=87=91=E8=9D=B6=E5=BA=94?=
=?UTF-8?q?=E4=BB=98/=E5=BA=94=E6=94=B6=E5=8D=95=E5=88=86=E5=BD=95?=
=?UTF-8?q?=E6=8C=89=E8=B4=B9=E7=94=A8=E5=A4=A7=E7=B1=BB=C3=97=E7=A8=8E?=
=?UTF-8?q?=E7=8E=87=E6=8B=86=E5=88=86=EF=BC=8C=E4=B8=80=E8=BD=A6=E5=A4=9A?=
=?UTF-8?q?=E8=B4=A7=E5=86=8D=E6=8C=89=E8=B4=A7=E7=89=A9=E6=8B=86=E5=88=86?=
=?UTF-8?q?"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This reverts commit 5d1c01e15eb1edccd283d49377b68800532971b0.
---
.../transport/service/KingdeeSyncContext.java | 6 +-
.../support/KingdeeApBillSyncSupport.java | 433 ++----------------
.../support/KingdeeArBillSyncSupport.java | 8 +-
3 files changed, 50 insertions(+), 397 deletions(-)
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/KingdeeSyncContext.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/KingdeeSyncContext.java
index 4a14535c..e8b95e15 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/KingdeeSyncContext.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/KingdeeSyncContext.java
@@ -24,7 +24,6 @@
*/
package org.springblade.transport.service;
-import org.springblade.system.pojo.entity.FeeItem;
import org.springblade.transport.pojo.entity.ContractManage;
import org.springblade.transport.pojo.entity.CustomerReceiptAccount;
import org.springblade.transport.pojo.entity.FormalSettlement;
@@ -46,12 +45,11 @@ public record KingdeeSyncContext(Map measureUnitCodeByName, Map<
Map apBillNoCache,
Map> settlementDetailCache,
Map settlementCache,
- Map receiptAccountCache,
- Map feeItemCacheByName) {
+ Map receiptAccountCache) {
/** 空上下文:缓存可写但初始为空,首条记录命中后全批复用 */
public static KingdeeSyncContext empty() {
return new KingdeeSyncContext(new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>(),
- new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>());
+ new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>());
}
}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/KingdeeApBillSyncSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/KingdeeApBillSyncSupport.java
index e417d376..0e65fef0 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/KingdeeApBillSyncSupport.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/KingdeeApBillSyncSupport.java
@@ -35,7 +35,6 @@ import org.springblade.core.tool.utils.Func;
import org.springblade.system.cache.SysCache;
import org.springblade.system.feign.ISysClient;
import org.springblade.system.pojo.entity.Dept;
-import org.springblade.system.pojo.entity.FeeItem;
import org.springblade.system.pojo.entity.MeasurementUnit;
import org.springblade.thirdparty.bfi.pojo.dto.BfiApBillQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiApBillSaveDTO;
@@ -83,12 +82,10 @@ import java.util.stream.Collectors;
* 推送前经 A102-4 预检应付单已生成、下推时经 A102-4 反查付款计划分录 awrp_entry_code_p。
* 两侧共用的防重键组装、A102-4 查询/反查、A102-2 保存、结算明细分录解析与档案取数统一收口在本组件;
* 财务应收单(A302-2)同步组件 {@link KingdeeArBillSyncSupport} 亦复用本组件的结算明细分录解析与档案取数方法(public 成员)。
- * 明细分录口径:正式结算单页面结算明细(每行一个运单)按 费用大类×税率 拆分,一车多货再按货物拆分:
- * 运输费大类费用拆一行、装卸大类费用拆一行,同大类税率不同再按税率拆多行,一车多货(明细下多行货物费用行)
- * 再按货物拆分;结算合计费用项(手工添加 manualFlag=1)每行一条;无有效货物费用项的明细兜底整行一条。
+ *
明细分录口径:取正式结算单页面结算明细(每行一条)+ 结算合计费用项(每行一条);
* 物料编码按项目业务类型/业务模式/装卸大类映射(见 {@link #resolveMaterialNumber});
* 计量单位编码按费用类型匹配合同计费方案规则计费单位,再匹配计量单位档案编码;
- * 数量运输费大类取货物运输量、其余默认 1;单价按结算金额/数量反算。
+ * 数量运费费用项目取运输量、其余默认 1;单价按结算金额/数量反算。
*
* @author Chill
*/
@@ -105,12 +102,6 @@ public class KingdeeApBillSyncSupport {
private static final String FREIGHT_FEE_ITEM = "运输费";
/** 结算明细行(运费)计费方案匹配费用类型 */
private static final String FREIGHT_FEE_TYPE = "物流配送";
- /** 费用大类:装卸(费用类型/费用项名称含“装卸”) */
- private static final String LOADING_FEE_TYPE = "装卸";
- /** 费用大类:运输费(未识别大类时的兜底归类) */
- private static final String FREIGHT_FEE_CATEGORY = "运输费";
- /** 分录金额勾稽允许误差(页面金额与费用项合计的分摊尾差容忍度) */
- private static final BigDecimal AMOUNT_TOLERANCE = new BigDecimal("0.01");
private final IBfiService bfiService;
private final ContractManageMapper contractManageMapper;
@@ -213,8 +204,7 @@ public class KingdeeApBillSyncSupport {
* 推送金蝶财务应付单(A102-2 财务应付单保存,由正式结算单「同步金蝶」触发)。
* 推送前先经 A102-4 按防重键(awrp_src_sys + awrp_src_code)查询:金蝶已存在财务应付单时
* 幂等跳过保存并返回已有单据编号(说明上次同步已保存成功、在后续环节中断,应续推而非拦截报错)。
- * 明细分录取页面结算明细按 费用大类×税率(一车多货再按货物)拆分 + 结算合计费用项(每行一条),
- * 结算金额逐行直送;
+ * 明细分录取页面结算明细(每行一条)+ 结算合计费用项(每行一条),结算金额逐行直送;
* 汇率日期/汇率取结算单页面维护值;付款计划 planentity 暂不传(启用方案见方法内注释),
* 当前由金蝶按明细自动汇总生成
*
@@ -301,7 +291,7 @@ public class KingdeeApBillSyncSupport {
// 【必填】外部单据类型
param.setAwrpSrcType(KingdeeBfiConstant.BFI_AP_BILL_SRC_TYPE);
- // 明细分录:结算明细按 费用大类×税率(一车多货按货物)拆分 + 结算合计费用项每行一条
+ // 明细分录:结算明细行 + 结算合计费用项各一条(不聚合)
List detailentry = new ArrayList<>();
for (BfiEntryGroup entryGroup : entryGroups) {
BfiApBillSaveEntryDTO entry = new BfiApBillSaveEntryDTO();
@@ -415,8 +405,8 @@ public class KingdeeApBillSyncSupport {
// ==================== 结算明细分录解析(结算明细行 + 结算合计费用项) ====================
/**
- * 解析正式结算明细为应付单分录:按所属正式结算单分组,逐结算单解析——页面结算明细按 费用大类×税率
- * (一车多货再按货物)拆分 + 结算合计费用项(手工添加)每行一条;分录携带所属正式结算单id
+ * 解析正式结算明细为应付单分录(不聚合):按所属正式结算单分组,逐结算单取页面结算明细
+ * (每行一条分录)与结算合计费用项(每行一条分录);分录携带所属正式结算单id
* (多结算单付款申请 A103-1 下推时按结算单分组勾稽各自应付单付款计划分录)。
* 应收单(A302-2)、收票单(A303-2)分录与本解析同源同口径
*
@@ -442,18 +432,15 @@ public class KingdeeApBillSyncSupport {
}
/**
- * 解析单张正式结算单分录:页面结算明细(每行一个运单)按 费用大类×税率 拆分,一车多货再按货物拆分;
- * 结算合计费用项(手工添加)每行一条。
+ * 解析单张正式结算单分录:页面结算明细每行一条 + 结算合计费用项每行一条。
* 取数口径:
- * 结算明细费用行(一车多货每货物一行)费用项JSON逐项归类——合同计费方案规则定(费用大类, 税率),
- * 费用项档案兜底,名称特征再兜底;运输费大类费用拆一行、装卸大类费用拆一行,同大类税率不同再拆多行;
- * 物料编码按费用大类/项目业务类型/业务模式映射——装卸大类费用行映射“装卸”;国际运输业务模式
+ * 物料编码按项目业务类型/业务模式/装卸大类映射——装卸大类费用行映射“装卸”;国际运输业务模式
* (或国际货物运输代理服务项目业务类型)映射“国际货物运输代理服务”;国内映射“国内道路货物运输服务-”+运单运输方式;
- * 计量单位编码按费用项/费用大类匹配合同计费方案规则计费单位,再按计量单位档案取编码;
- * 数量运输费大类取货物运输量合计(未维护兜底 1)、其余费用大类默认 1;单价按结算金额/数量反算;
- * 结算金额(含税)按费用项金额拆分归集,不含税按行不含税×行内含税占比分摊(行不含税缺失不送);
- * 无运费项的货物费用行运费(freightAmount)并入运输费大类(与页面合计口径一致);
- * 运输货物/车号按拆分行货物/结算明细车号传;分录标识:未拆分取单据号,拆分行取单据号-费用大类-税率(-货物)。
+ * 计量单位编码按费用类型/费用项匹配合同计费方案规则计费单位,再按计量单位档案取编码;
+ * 数量运费费用项目取运输量(未维护兜底 1)、结算合计费用项默认 1;单价按结算金额/数量反算;
+ * 结算金额:结算明细行取结算金额(含税)、结算合计费用项行取合计行结算金额;
+ * 运输货物/车号仅结算明细行传(货物名称/车号);分录标识:结算明细行取单据号、
+ * 结算合计费用项行取结算单号-费用类型-费用项拼接。
*
* @param settlement 正式结算单
* @param settlementDetails 该结算单下的结算明细
@@ -469,20 +456,14 @@ public class KingdeeApBillSyncSupport {
ContractManage contract = requireContract(settlement.getContractId(), context);
// 合同计费方案规则:费用类型/费用项 -> 计费单位
Map billingUnitByRule = billingUnitByRule(contract);
- // 合同计费方案规则:费用项 -> (费用大类, 税率),结算明细费用项拆分归类主来源
- Map feeClassByRule = feeClassByRule(contract);
- // 费用项档案:费用项名称 -> 档案(费用大类/税率兜底来源)
- Map feeItemArchive = feeItemArchiveByName(context);
// 计量单位档案:单位名称 -> 计量单位编码
Map unitCodeByName = measureUnitCodeByName(context);
- // 结算明细货物费用行:一车多货按货物拆分与费用项归类取数来源
+ // 结算明细费用行:判断运单是否存在装卸大类费用
Map> feesByDetailId = detailFeesByDetailId(settlementDetails);
List entryGroups = new ArrayList<>();
- int detailEntryCount = 0;
for (FormalSettlementDetail settlementDetail : settlementDetails) {
- detailEntryCount += appendDetailEntries(entryGroups, settlement, project, settlementDetail,
- feesByDetailId.getOrDefault(settlementDetail.getId(), List.of()),
- billingUnitByRule, feeClassByRule, unitCodeByName, feeItemArchive);
+ appendDetailEntry(entryGroups, settlement, project, settlementDetail,
+ feesByDetailId.getOrDefault(settlementDetail.getId(), List.of()), billingUnitByRule, unitCodeByName);
}
// 结算合计只取手工添加的费用项(manualFlag=1);系统自动汇总行是结算明细金额的再汇总,再送会与明细重复
List manualSummaryFees = listSummaryFees(settlement.getId()).stream()
@@ -495,130 +476,20 @@ public class KingdeeApBillSyncSupport {
throw new ServiceException("推送金蝶失败:正式结算单[" + Func.toStr(settlement.getFormalSettlementNo())
+ "]无结算明细与结算合计费用项,无法解析分录");
}
- // 分录解析摘要(联调排查:结算明细按大类/税率/货物拆分后条数+手工添加的结算合计费用项条数,物料/计量单位/分录标识逐条见下方分录生成日志)
- log.info("金蝶应付单分录解析完成:正式结算单[{}],结算明细{}条拆为{}条分录 + 手工结算合计{}条 = 共{}条分录",
- settlement.getFormalSettlementNo(), settlementDetails.size(), detailEntryCount,
- manualSummaryFees.size(), entryGroups.size());
+ // 分录解析摘要(联调排查:明细条数=结算明细行+手工添加的结算合计费用项,物料/计量单位/分录标识逐条见下方分录生成日志)
+ log.info("金蝶应付单分录解析完成:正式结算单[{}],结算明细{}条 + 手工结算合计{}条 = 共{}条分录",
+ settlement.getFormalSettlementNo(), settlementDetails.size(),
+ entryGroups.size() - settlementDetails.size(), entryGroups.size());
return entryGroups;
}
/**
- * 单条结算明细(一个运单)拆分生成分录:货物费用行费用项按 费用大类×税率 归集,每组一条分录,
- * 一车多货(明细下多行货物费用行)再按货物拆分;仅拆出一组时保持一条、分录标识取单据号。
- * 取数口径:费用项JSON逐项归类(合同计费方案规则定 费用大类×税率,费用项档案兜底、名称特征再兜底);
- * 无运费项的货物费用行运费(freightAmount)并入运输费大类参与拆分(与页面合计口径一致);
- * 含税金额按费用项金额归集;不含税按行不含税×行内费用项含税占比分摊(末项兜差额,行不含税缺失不送);
- * 数量运输费大类取货物运输量合计(未维护兜底 1)、其余费用大类默认 1;单价按结算金额/数量反算;
- * 运输货物按拆分行货物名称、车号取结算明细车号;分录标识未拆分取单据号、拆分行取单据号-费用大类-税率(-货物)。
- *
- * @return 该明细生成的分录条数
- */
- private int appendDetailEntries(List entryGroups, FormalSettlement settlement, ProjectApply project,
- FormalSettlementDetail detail, List detailFees,
- Map billingUnitByRule, Map feeClassByRule,
- Map unitCodeByName, Map feeItemArchive) {
- String sourceDesc = "结算明细[" + Func.toStr(detail.getDocumentNo()) + "]";
- Map groups = new LinkedHashMap<>();
- boolean multiCargo = detailFees.size() > 1;
- for (FormalSettlementDetailFee detailFee : detailFees) {
- Map feeItems = parseFeeItems(detailFee.getFeeItemsJson());
- // 页面合计口径:费用项JSON无运费项时,运费(freightAmount)并入运输费大类参与拆分
- if (feeItems.keySet().stream().noneMatch(this::isFreightFeeItem)
- && money(detailFee.getFreightAmount()).compareTo(BigDecimal.ZERO) > 0) {
- feeItems.put(FREIGHT_FEE_ITEM, money(detailFee.getFreightAmount()));
- }
- if (feeItems.isEmpty()) {
- continue;
- }
- BigDecimal rowItemTotal = feeItems.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
- if (money(detailFee.getSettlementAmountTax()).subtract(rowItemTotal).abs().compareTo(AMOUNT_TOLERANCE) > 0) {
- log.warn("金蝶应付单分录拆分:{}货物费用行[{}]结算金额(含税)[{}]与费用项合计[{}]不一致,按费用项拆分归集,请核对页面费用项维护",
- sourceDesc, Func.toStr(detailFee.getCargoName(), detailFee.getLineNo()),
- money(detailFee.getSettlementAmountTax()), rowItemTotal);
- }
- // 行内不含税按各费用项含税占比分摊,末项兜差额,保证行合计不因四舍五入漂移
- BigDecimal rowAmountNoTax = detailFee.getSettlementAmountNoTax() == null ? null : money(detailFee.getSettlementAmountNoTax());
- BigDecimal allocatedNoTax = BigDecimal.ZERO;
- // 一车多货按货物拆分(货物名称缺失兜底行号);单车货物不按货物拆分
- String cargoKey = multiCargo ? firstNonBlank(detailFee.getCargoName(), detailFee.getLineNo(), "货物") : null;
- List> itemList = new ArrayList<>(feeItems.entrySet());
- for (int index = 0; index < itemList.size(); index++) {
- Map.Entry item = itemList.get(index);
- String feeItem = item.getKey();
- BigDecimal amount = money(item.getValue());
- FeeClassInfo classInfo = classifyFeeItem(feeItem, feeClassByRule, feeItemArchive);
- String feeType = feeCategoryOf(feeItem, classInfo);
- DetailSplitKey splitKey = new DetailSplitKey(cargoKey, feeType, taxRateText(classInfo.taxRate()));
- DetailSplitGroup group = groups.computeIfAbsent(splitKey, key -> new DetailSplitGroup());
- if (group.firstFeeItem == null) {
- group.firstFeeItem = feeItem;
- }
- group.transportGoods = firstNonBlank(detailFee.getCargoName(), group.transportGoods);
- group.amountTax = group.amountTax.add(amount);
- if (isFreightFeeItem(feeItem)) {
- group.freightQuantity = group.freightQuantity.add(
- detailFee.getTransportQuantity() == null ? BigDecimal.ZERO : money(detailFee.getTransportQuantity()));
- }
- if (rowAmountNoTax != null) {
- BigDecimal share = index == itemList.size() - 1
- ? rowAmountNoTax.subtract(allocatedNoTax)
- : rowAmountNoTax.multiply(amount).divide(rowItemTotal, 2, RoundingMode.HALF_UP);
- allocatedNoTax = allocatedNoTax.add(share);
- group.amountNoTax = (group.amountNoTax == null ? BigDecimal.ZERO : group.amountNoTax).add(share);
- }
- }
- }
- if (groups.isEmpty()) {
- // 历史数据兜底:货物费用行缺失或费用项JSON为空时按明细整行生成分录,避免整单无法推送
- log.warn("金蝶应付单分录拆分:{}无有效货物费用项(货物费用行缺失或费用项JSON为空),按明细整行兜底生成分录", sourceDesc);
- appendWholeDetailEntry(entryGroups, settlement, project, detail, detailFees, billingUnitByRule, unitCodeByName);
- return 1;
- }
- // 分录唯一标识前缀(awrp_entry_code):结算明细单据号;未维护时兜底明细行id,避免候选键为空被金蝶拦截
- String baseEntryCode = Func.isBlank(detail.getDocumentNo()) ? String.valueOf(detail.getId()) : detail.getDocumentNo().trim();
- boolean singleGroup = groups.size() == 1;
- for (Map.Entry splitEntry : groups.entrySet()) {
- DetailSplitKey splitKey = splitEntry.getKey();
- DetailSplitGroup group = splitEntry.getValue();
- boolean loadingFee = splitKey.feeType().contains("装卸");
- String materialNumber = resolveMaterialNumber(loadingFee, project, detail.getTransportType(), sourceDesc);
- // 计量单位编码:费用项优先、费用大类兜底匹配合同计费方案计费单位,再匹配计量单位档案
- String measureunitNumber = findMeasureunitNumber(billingUnitByRule, unitCodeByName, group.firstFeeItem, splitKey.feeType());
- if (Func.isBlank(measureunitNumber)) {
- if (isFreightFeeItem(group.firstFeeItem) || FREIGHT_FEE_TYPE.equals(splitKey.feeType())) {
- // 运输费大类主行计量单位缺失直接拦截(与原整行口径一致)
- throw new ServiceException("推送金蝶失败:" + sourceDesc + "未在合同计费方案中配置计费单位,请先维护计费方案规则");
- }
- // 其他费用大类未配置计费单位时兜底运费计费单位(数量默认 1,单位仅作展示口径),避免历史合同缺配置阻塞推送
- log.warn("金蝶应付单分录拆分:{}费用大类[{}](费用项[{}])未配置计费单位,兜底运费计费单位", sourceDesc, splitKey.feeType(), group.firstFeeItem);
- measureunitNumber = resolveMeasureunitNumber(billingUnitByRule, unitCodeByName, FREIGHT_FEE_ITEM, FREIGHT_FEE_TYPE, sourceDesc);
- }
- // 数量:运输费大类取货物运输量合计,其余费用大类默认 1
- BigDecimal quantity = group.freightQuantity.compareTo(BigDecimal.ZERO) > 0 ? group.freightQuantity : BigDecimal.ONE;
- BigDecimal amount = money(group.amountTax);
- BigDecimal price = entryPrice(amount, quantity);
- String entryCode = singleGroup ? baseEntryCode
- : baseEntryCode + "-" + splitKey.feeType() + "-" + Func.toStr(splitKey.taxRateText(), "其他")
- + (splitKey.cargoName() == null ? "" : "-" + splitKey.cargoName());
- entryGroups.add(new BfiEntryGroup(materialNumber, measureunitNumber, entryCode, quantity, price, amount,
- group.amountNoTax == null ? null : money(group.amountNoTax),
- group.transportGoods == null ? detail.getCargoName() : group.transportGoods,
- detail.getVehicleNo(), settlement.getId()));
- log.info("金蝶应付单分录生成:来源[{}],分录标识[{}],费用大类[{}],税率[{}],物料编码[{}],计量单位[{}],数量[{}],单价[{}],含税金额[{}],不含税金额[{}]",
- sourceDesc, entryCode, splitKey.feeType(), Func.toStr(splitKey.taxRateText(), "未识别"),
- materialNumber, measureunitNumber, quantity, price, amount, group.amountNoTax == null ? null : money(group.amountNoTax));
- }
- return groups.size();
- }
-
- /**
- * 结算明细整行兜底分录(历史数据:货物费用行缺失或费用项JSON为空时使用):
- * 物料按项目业务类型/业务模式/装卸大类映射,数量取运输量(兜底 1),
+ * 单条结算明细行生成一条分录:物料按项目业务类型/业务模式/装卸大类映射,数量取运输量(兜底 1),
* 金额取结算金额(含税),不含税取结算金额(不含税),运输货物/车号取货物名称/车号,分录标识取单据号
*/
- private void appendWholeDetailEntry(List entryGroups, FormalSettlement settlement, ProjectApply project,
- FormalSettlementDetail detail, List detailFees,
- Map billingUnitByRule, Map unitCodeByName) {
+ private void appendDetailEntry(List entryGroups, FormalSettlement settlement, ProjectApply project,
+ FormalSettlementDetail detail, List detailFees,
+ Map billingUnitByRule, Map unitCodeByName) {
String sourceDesc = "结算明细[" + Func.toStr(detail.getDocumentNo()) + "]";
// 该条运单存在装卸大类费用(明细费用项或明细费用行费用项含“装卸”)时物料映射为装卸
boolean loadingFee = hasLoadingFeeItem(detail.getFeeItemsJson())
@@ -738,24 +609,6 @@ public class KingdeeApBillSyncSupport {
return unitCode;
}
- /**
- * 计量单位编码查找(不拦截):费用项优先、费用类型兜底匹配合同计费方案规则计费单位,
- * 再按计量单位档案(单位名称匹配)取计量单位编码,供结算明细拆分行按费用大类兜底取数
- *
- * @return 计量单位编码,任一环节缺失返回 null
- */
- private String findMeasureunitNumber(Map billingUnitByRule, Map unitCodeByName,
- String feeItem, String feeType) {
- String billingUnit = Func.isBlank(feeItem) ? null : billingUnitByRule.get(feeItem.trim());
- if (Func.isBlank(billingUnit) && Func.isNotBlank(feeType)) {
- billingUnit = billingUnitByRule.get(feeType.trim());
- }
- if (Func.isBlank(billingUnit)) {
- return null;
- }
- return unitCodeByName.get(billingUnit.trim());
- }
-
/**
* 合同计费方案规则解析:费用类型/费用项 -> 计费单位(取首个配置了计费单位的规则,
* 计费方案 JSON 解析失败按未配置处理,由计量单位解析处统一拦截报错)
@@ -765,203 +618,41 @@ public class KingdeeApBillSyncSupport {
*/
private Map billingUnitByRule(ContractManage contract) {
Map mapping = new HashMap<>();
- for (Map, ?> rule : billingPlanRules(contract)) {
- String billingUnit = textValue(rule.get("billingUnit"));
- if (Func.isBlank(billingUnit)) {
- continue;
- }
- String feeItem = textValue(rule.get("feeItem"));
- String feeType = textValue(rule.get("feeType"));
- if (Func.isNotBlank(feeItem)) {
- mapping.putIfAbsent(feeItem, billingUnit);
- }
- if (Func.isNotBlank(feeType)) {
- mapping.putIfAbsent(feeType, billingUnit);
- }
- }
- log.info("合同[{}]计费方案解析:{}项费用类型/费用项配置计费单位{}", contract.getContractNo(), mapping.size(), mapping);
- return mapping;
- }
-
- /**
- * 合同计费方案规则费用归类解析:费用项/费用类型 -> (费用大类, 税率)。
- * 规则同时按费用项、费用类型两个维度登记(先登记优先,与计费单位解析同口径),
- * 供结算明细费用项按 费用大类×税率 拆分归类取数
- *
- * @param contract 结算合同
- * @return 费用项/费用类型 -> 费用归类映射
- */
- private Map feeClassByRule(ContractManage contract) {
- Map mapping = new HashMap<>();
- for (Map, ?> rule : billingPlanRules(contract)) {
- String feeItem = textValue(rule.get("feeItem"));
- String feeType = textValue(rule.get("feeType"));
- if (Func.isBlank(feeItem) && Func.isBlank(feeType)) {
- continue;
- }
- FeeClassInfo classInfo = new FeeClassInfo(feeType, feeAmount(rule.get("taxRate")));
- if (Func.isNotBlank(feeItem)) {
- mapping.putIfAbsent(feeItem, classInfo);
- }
- if (Func.isNotBlank(feeType)) {
- mapping.putIfAbsent(feeType, classInfo);
- }
- }
- log.info("合同[{}]计费方案费用归类解析:{}项费用项/费用类型(费用大类, 税率){}", contract.getContractNo(), mapping.size(), mapping);
- return mapping;
- }
-
- /**
- * 合同计费方案规则平铺:解析计费方案JSON全部方案下的规则(保持配置顺序;
- * 计费方案 JSON 兼容历史数据,解析失败按未配置处理,由取用处统一拦截/兜底)
- *
- * @param contract 结算合同
- * @return 规则列表(可能为空)
- */
- private List