test: 新增金蝶分录费用项按大类税率拆分逻辑单元测试

覆盖同大类多税率拆行、运输+装卸拆行、费用项档案分类判定、残差勾稽、空费用项兜底、同组金额合并六个场景
This commit is contained in:
刘泉佳
2026-10-13 11:34:33 +08:00
parent f2b00b22af
commit 60c1cbe98d
@@ -0,0 +1,139 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to the License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* 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<String, BigDecimal> feeItems = new LinkedHashMap<>();
feeItems.put("运输费", new BigDecimal("2000"));
feeItems.put("附加运输补贴", new BigDecimal("1120"));
Map<String, BigDecimal> taxRateByRule = Map.of(
"运输费", new BigDecimal("9"),
"附加运输补贴", new BigDecimal("6"));
List<FeeLineSplit> 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<String, BigDecimal> feeItems = new LinkedHashMap<>();
feeItems.put("运输费", new BigDecimal("3120"));
feeItems.put("装卸费", new BigDecimal("800"));
Map<String, BigDecimal> taxRateByRule = Map.of(
"运输费", new BigDecimal("9"),
"装卸费", new BigDecimal("6"));
List<FeeLineSplit> 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<String, BigDecimal> feeItems = Map.of("吊装作业", new BigDecimal("500"));
Map<String, String> feeCategoryByName = Map.of("吊装作业", "装卸");
List<FeeLineSplit> splits = KingdeeApBillSyncSupport.splitFeeItems(feeItems, feeCategoryByName, Map.of(), new BigDecimal("500"));
assertEquals(1, splits.size());
assertTrue(splits.get(0).isLoading());
}
/** 残差勾稽:费用项JSON未含运费(历史数据)时,结算金额与费用项合计的差额并入运输类无税率组 */
@Test
void residualGoesToFreightDefaultGroup() {
Map<String, BigDecimal> feeItems = new LinkedHashMap<>();
feeItems.put("运输费", new BigDecimal("2000"));
List<FeeLineSplit> 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<FeeLineSplit> 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<String, BigDecimal> feeItems = new LinkedHashMap<>();
feeItems.put("装卸费", new BigDecimal("500"));
feeItems.put("装卸吊装费", new BigDecimal("300"));
feeItems.put("其他费用", new BigDecimal("100"));
List<FeeLineSplit> 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());
}
}