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()); + } +}