From 60c1cbe98da4ead86ab45e1ecda69845a75d8d06 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=88=98=E6=B3=89=E4=BD=B3?= <1107186916@qq.com>
Date: Tue, 13 Oct 2026 11:34:33 +0800
Subject: [PATCH] =?UTF-8?q?test:=20=E6=96=B0=E5=A2=9E=E9=87=91=E8=9D=B6?=
=?UTF-8?q?=E5=88=86=E5=BD=95=E8=B4=B9=E7=94=A8=E9=A1=B9=E6=8C=89=E5=A4=A7?=
=?UTF-8?q?=E7=B1=BB=E7=A8=8E=E7=8E=87=E6=8B=86=E5=88=86=E9=80=BB=E8=BE=91?=
=?UTF-8?q?=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
覆盖同大类多税率拆行、运输+装卸拆行、费用项档案分类判定、残差勾稽、空费用项兜底、同组金额合并六个场景
---
.../transport/KingdeeEntrySplitTest.java | 139 ++++++++++++++++++
1 file changed, 139 insertions(+)
create mode 100644 blade-service/blade-transport/src/test/java/org/springblade/transport/KingdeeEntrySplitTest.java
diff --git a/blade-service/blade-transport/src/test/java/org/springblade/transport/KingdeeEntrySplitTest.java b/blade-service/blade-transport/src/test/java/org/springblade/transport/KingdeeEntrySplitTest.java
new file mode 100644
index 00000000..1b34b596
--- /dev/null
+++ b/blade-service/blade-transport/src/test/java/org/springblade/transport/KingdeeEntrySplitTest.java
@@ -0,0 +1,139 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ *
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ *
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ *
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ *
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ *
+ * Using this software signifies agreement to the License, and the software
+ * must not be used for illegal purposes.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ *
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.transport;
+
+import org.junit.jupiter.api.Test;
+import org.springblade.transport.support.KingdeeApBillSyncSupport;
+import org.springblade.transport.support.KingdeeApBillSyncSupport.FeeLineSplit;
+
+import java.math.BigDecimal;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * 金蝶应付/应收单分录拆分逻辑测试(纯函数,无环境依赖):
+ * 结算明细费用项按 费用大类(运输/装卸)→ 税率 拆分行,验证三个联调场景与残差勾稽
+ *
+ * @author Chill
+ */
+class KingdeeEntrySplitTest {
+
+ /** 场景1:同费用大类(运输)、多税率 → 按税率拆两行 */
+ @Test
+ void splitFreightByTaxRate() {
+ Map feeItems = new LinkedHashMap<>();
+ feeItems.put("运输费", new BigDecimal("2000"));
+ feeItems.put("附加运输补贴", new BigDecimal("1120"));
+ Map taxRateByRule = Map.of(
+ "运输费", new BigDecimal("9"),
+ "附加运输补贴", new BigDecimal("6"));
+ List splits = KingdeeApBillSyncSupport.splitFeeItems(feeItems, Map.of(), taxRateByRule, new BigDecimal("3120"));
+ assertEquals(2, splits.size());
+ assertFalse(splits.get(0).isLoading());
+ assertEquals(new BigDecimal("9"), splits.get(0).getTaxRate());
+ assertEquals(new BigDecimal("2000"), splits.get(0).getAmount());
+ assertEquals("-9", splits.get(0).taxRateSuffix());
+ assertFalse(splits.get(1).isLoading());
+ assertEquals(new BigDecimal("6"), splits.get(1).getTaxRate());
+ assertEquals(new BigDecimal("1120"), splits.get(1).getAmount());
+ assertEquals("-6", splits.get(1).taxRateSuffix());
+ }
+
+ /** 场景2:运输费 + 装卸费 → 运输行 + 装卸行(装卸行税率独立) */
+ @Test
+ void splitFreightAndLoading() {
+ Map feeItems = new LinkedHashMap<>();
+ feeItems.put("运输费", new BigDecimal("3120"));
+ feeItems.put("装卸费", new BigDecimal("800"));
+ Map taxRateByRule = Map.of(
+ "运输费", new BigDecimal("9"),
+ "装卸费", new BigDecimal("6"));
+ List splits = KingdeeApBillSyncSupport.splitFeeItems(feeItems, Map.of(), taxRateByRule, new BigDecimal("3920"));
+ assertEquals(2, splits.size());
+ assertFalse(splits.get(0).isLoading());
+ assertEquals(new BigDecimal("3120"), splits.get(0).getAmount());
+ assertTrue(splits.get(1).isLoading());
+ assertEquals(new BigDecimal("6"), splits.get(1).getTaxRate());
+ assertEquals(new BigDecimal("800"), splits.get(1).getAmount());
+ }
+
+ /** 费用项档案分类判定:名称不含“装卸”的费用项,档案费用类型名称含“装卸”即归装卸大类 */
+ @Test
+ void loadingCategoryFromFeeItemArchive() {
+ Map feeItems = Map.of("吊装作业", new BigDecimal("500"));
+ Map feeCategoryByName = Map.of("吊装作业", "装卸");
+ List splits = KingdeeApBillSyncSupport.splitFeeItems(feeItems, feeCategoryByName, Map.of(), new BigDecimal("500"));
+ assertEquals(1, splits.size());
+ assertTrue(splits.get(0).isLoading());
+ }
+
+ /** 残差勾稽:费用项JSON未含运费(历史数据)时,结算金额与费用项合计的差额并入运输类无税率组 */
+ @Test
+ void residualGoesToFreightDefaultGroup() {
+ Map feeItems = new LinkedHashMap<>();
+ feeItems.put("运输费", new BigDecimal("2000"));
+ List splits = KingdeeApBillSyncSupport.splitFeeItems(feeItems, Map.of(), Map.of("运输费", new BigDecimal("9")), new BigDecimal("2020"));
+ assertEquals(2, splits.size());
+ assertEquals(new BigDecimal("2000"), splits.get(0).getAmount());
+ assertFalse(splits.get(1).isLoading());
+ assertNull(splits.get(1).getTaxRate());
+ assertEquals(new BigDecimal("20"), splits.get(1).getAmount());
+ assertEquals("", splits.get(1).taxRateSuffix());
+ }
+
+ /** 费用项JSON为空:整行结算金额归运输类无税率组单行 */
+ @Test
+ void emptyFeeItemsFallbackToFreightLine() {
+ List splits = KingdeeApBillSyncSupport.splitFeeItems(Map.of(), Map.of(), Map.of(), new BigDecimal("3120"));
+ assertEquals(1, splits.size());
+ assertFalse(splits.get(0).isLoading());
+ assertNull(splits.get(0).getTaxRate());
+ assertEquals(new BigDecimal("3120"), splits.get(0).getAmount());
+ }
+
+ /** 税率未配置的费用项归入无税率组,同大类同税率费用项金额合并 */
+ @Test
+ void mergeSameCategorySameRate() {
+ Map feeItems = new LinkedHashMap<>();
+ feeItems.put("装卸费", new BigDecimal("500"));
+ feeItems.put("装卸吊装费", new BigDecimal("300"));
+ feeItems.put("其他费用", new BigDecimal("100"));
+ List splits = KingdeeApBillSyncSupport.splitFeeItems(feeItems, Map.of(), Map.of(), new BigDecimal("900"));
+ assertEquals(2, splits.size());
+ assertTrue(splits.get(0).isLoading());
+ assertEquals(new BigDecimal("800"), splits.get(0).getAmount());
+ assertNull(splits.get(0).getTaxRate());
+ assertEquals("装卸费", splits.get(0).getFirstFeeItem());
+ assertFalse(splits.get(1).isLoading());
+ assertEquals(new BigDecimal("100"), splits.get(1).getAmount());
+ }
+}