新增路线产品

This commit is contained in:
liuminghui
2026-11-06 13:39:26 +08:00
parent b4da248815
commit 6f342d424f
32 changed files with 1850 additions and 785 deletions
@@ -26,6 +26,63 @@ class PayCostCalculatorTest
assertTrue(result.getSkipped().stream().anyMatch(text -> text.contains("签名费")));
}
@Test
void spainCttAddsPerKgAfterTheLastWeightBand()
{
PayProduct product = new PayProduct();
product.setProductName("西班牙CTT");
product.setCurrency("EUR");
product.setWeightBands(new ArrayList<>(List.of(
band("0", "1", "2.10", "Mainland / Mad High Density"),
band("4", "5", "3.18", "Mainland / Mad High Density"))));
PaySurcharge extra = fee(31L, "每公斤续重", "0.27", "EUR", "EXTRA_KG", "5");
extra.setZoneName("Mainland / Mad High Density");
extra.setPriceUnit("EUR/KG");
product.setSurcharges(List.of(extra));
PayOrderCostResult inside = PayCostCalculator.calculate(product, new BigDecimal("5"),
null, null, null, null, "Mainland / Mad High Density", null, 1);
assertTrue(hasFee(inside, "基础运费", "3.18"));
assertTrue(inside.getFees().stream().noneMatch(fee -> "每公斤续重".equals(fee.getFeeName())));
PayOrderCostResult over = PayCostCalculator.calculate(product, new BigDecimal("7"),
null, null, null, null, "Mainland / Mad High Density", null, 1);
assertTrue(hasFee(over, "基础运费", "3.18"));
assertTrue(hasFee(over, "每公斤续重", "0.54"));
assertEquals(new BigDecimal("3.72"), over.getPayTotal());
}
@Test
void extraKgFollowsTheSameServiceSection()
{
PayProduct product = new PayProduct();
product.setProductName("岛屿");
product.setCurrency("EUR");
PayWeightBand standard = band("0", "1", "13.12", "Canary Islands / Minor Islands");
standard.setSectionName("2. INSULAR RATES / STANDARD");
standard.setWeightLabel("Up to 1 kg");
PayWeightBand express = band("0", "1", "14.10", "Canary Islands / Minor Islands");
express.setSectionName("2. INSULAR RATES / EXPRESS");
express.setWeightLabel("Up to 1 kg");
product.setWeightBands(new ArrayList<>(List.of(standard, express)));
PaySurcharge standardKg = fee(41L, "每公斤续重", "1.86", "EUR", "EXTRA_KG", "1");
standardKg.setZoneName("Canary Islands / Minor Islands");
standardKg.setSectionName("2. INSULAR RATES / STANDARD");
standardKg.setPriceUnit("EUR/KG");
PaySurcharge expressKg = fee(42L, "每公斤续重", "4.72", "EUR", "EXTRA_KG", "1");
expressKg.setZoneName("Canary Islands / Minor Islands");
expressKg.setSectionName("2. INSULAR RATES / EXPRESS");
expressKg.setPriceUnit("EUR/KG");
product.setSurcharges(List.of(standardKg, expressKg));
PayOrderCostResult over = PayCostCalculator.calculate(product, new BigDecimal("2"),
null, null, null, null, "Canary Islands / Minor Islands", null, 1);
assertTrue(hasFee(over, "基础运费", "13.12"));
assertTrue(hasFee(over, "每公斤续重", "1.86"));
assertEquals(1, over.getFees().stream().filter(fee -> "每公斤续重".equals(fee.getFeeName())).count());
assertEquals(new BigDecimal("14.98"), over.getPayTotal());
}
@Test
void overweightOutsideTheCardDoesNotInventFreight()
{
@@ -9,6 +9,7 @@ import java.util.List;
import java.util.stream.Stream;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Test;
import com.bms.price.domain.PayOrderCostResult;
import com.bms.price.domain.PayPreview;
import com.bms.price.domain.PayProduct;
import com.bms.price.domain.PaySurcharge;
@@ -482,6 +483,10 @@ class PayWorkbookParserTest
void spainCttIslandsReadsFiveRateTables() throws Exception
{
Path file = Path.of("D:/payment/西班牙CTT带电专线(岛屿+其他地区).xlsx");
if (!Files.exists(file))
{
file = Path.of("D:/A-payment/西班牙CTT带电专线(岛屿+其他地区).xlsx");
}
Assumptions.assumeTrue(Files.exists(file));
PayPreview preview = parser.parseMatched(Files.readAllBytes(file), file.getFileName().toString(),
"西班牙CTT带电专线(岛屿+其他地区)", List.of("西班牙CTT带电专线(岛屿+其他地区)"));
@@ -491,45 +496,70 @@ class PayWorkbookParserTest
assertEquals("续重计费", ctt.getChargeType());
assertTrue(covers(ctt.getExtraPerKg(), "1.86"));
assertTrue(covers(ctt.getExtraPerKg(), "5.79"));
assertEquals(48, ctt.getWeightBands().size());
assertEquals(4, ctt.getSurcharges().size());
assertEquals(24, ctt.getWeightBands().size());
assertEquals(24, ctt.getSurcharges().stream().filter(fee -> "每公斤续重".equals(fee.getFeeName())).count());
assertEquals(4, ctt.getSurcharges().stream().filter(fee -> "Cubic Capacity".equals(fee.getFeeName())).count());
assertTrue(ctt.getWeightBands().stream().anyMatch(band -> "2. INSULAR RATES / STANDARD".equals(band.getSectionName())
&& "Balearic Islands Economy 48H / Majorca".equals(band.getZoneName()) && "西班牙".equals(band.getCountryName()) && "ES".equals(band.getCountryCode())
&& "Up to 1 kg".equals(band.getWeightLabel()) && decimal(band, "3.39") && "每件".equals(band.getChargeName())
&& "EUR/件".equals(band.getPriceUnit()) && band.getWeightMax().compareTo(java.math.BigDecimal.ONE) == 0));
assertTrue(ctt.getWeightBands().stream().anyMatch(band -> "2. INSULAR RATES / STANDARD".equals(band.getSectionName())
&& "Canary Islands / Minor Islands".equals(band.getZoneName()) && "Additional Kg".equals(band.getWeightLabel())
&& decimal(band, "1.86") && "每公斤".equals(band.getChargeName()) && band.getWeightMin() == null));
assertTrue(ctt.getWeightBands().stream().noneMatch(band -> band.getWeightLabel() != null && band.getWeightLabel().contains("Additional")));
assertTrue(ctt.getSurcharges().stream().anyMatch(fee -> "每公斤续重".equals(fee.getFeeName())
&& "2. INSULAR RATES / STANDARD".equals(fee.getSectionName())
&& "Canary Islands / Minor Islands".equals(fee.getZoneName()) && decimalFee(fee, "1.86")
&& "EUR".equals(fee.getCurrency()) && "EUR/KG".equals(fee.getPriceUnit())
&& "EXTRA_KG".equals(fee.getCalcRule()) && "1".equals(fee.getCalcParam())));
assertTrue(ctt.getWeightBands().stream().anyMatch(band -> "2. INSULAR RATES / EXPRESS".equals(band.getSectionName())
&& "Canary Islands / Mayor Islands".equals(band.getZoneName()) && "Up to 1 kg".equals(band.getWeightLabel())
&& decimal(band, "7.46")));
assertTrue(ctt.getWeightBands().stream().anyMatch(band -> "Price WITH CUSTOMS CLEARANCE / STANDARD".equals(band.getSectionName())
&& "Canary Islands (*) / Mayor Islands".equals(band.getZoneName()) && decimal(band, "5.33")));
assertTrue(ctt.getWeightBands().stream().anyMatch(band -> "Price WITH CUSTOMS CLEARANCE / EXPRESS".equals(band.getSectionName())
&& "Portuguese Island / Island".equals(band.getZoneName()) && "Additional Kg".equals(band.getWeightLabel())
&& decimal(band, "5.79")));
assertTrue(ctt.getSurcharges().stream().anyMatch(fee -> "每公斤续重".equals(fee.getFeeName())
&& "Price WITH CUSTOMS CLEARANCE / EXPRESS".equals(fee.getSectionName())
&& "Portuguese Island / Island".equals(fee.getZoneName()) && decimalFee(fee, "5.79")));
assertTrue(ctt.getWeightBands().stream().anyMatch(band -> band.getSectionName().contains("CEUTA")
&& "Ceuta".equals(band.getZoneName()) && "Up to 1 kg".equals(band.getWeightLabel()) && decimal(band, "7.61")));
assertTrue(ctt.getWeightBands().stream().anyMatch(band -> band.getSectionName().contains("CEUTA")
&& "Andorra".equals(band.getZoneName()) && "Additional Kg".equals(band.getWeightLabel()) && decimal(band, "2.85")));
assertTrue(ctt.getSurcharges().stream().allMatch(fee -> "Cubic Capacity".equals(fee.getFeeName()) && fee.getAmount() == null
&& "MANUAL".equals(fee.getCalcRule())));
assertTrue(ctt.getSurcharges().stream().anyMatch(fee -> "2. INSULAR RATES / STANDARD".equals(fee.getSectionName())
assertTrue(ctt.getSurcharges().stream().anyMatch(fee -> "每公斤续重".equals(fee.getFeeName())
&& fee.getSectionName().contains("CEUTA") && "Andorra".equals(fee.getZoneName()) && decimalFee(fee, "2.85")));
assertTrue(ctt.getSurcharges().stream().filter(fee -> "Cubic Capacity".equals(fee.getFeeName()))
.allMatch(fee -> fee.getAmount() == null && "MANUAL".equals(fee.getCalcRule())));
assertTrue(ctt.getSurcharges().stream().anyMatch(fee -> "Cubic Capacity".equals(fee.getFeeName())
&& "2. INSULAR RATES / STANDARD".equals(fee.getSectionName())
&& fee.getChargeText().contains("167 kg/m3") && fee.getChargeText().contains("333 kg/m3")
&& fee.getFeeDesc().contains("Balearic Islands Economy 48H / Majorca")
&& fee.getFeeDesc().contains("Canary Islands / Interislands")));
assertTrue(ctt.getSurcharges().stream().anyMatch(fee -> "2. INSULAR RATES / EXPRESS".equals(fee.getSectionName())
assertTrue(ctt.getSurcharges().stream().anyMatch(fee -> "Cubic Capacity".equals(fee.getFeeName())
&& "2. INSULAR RATES / EXPRESS".equals(fee.getSectionName())
&& fee.getFeeDesc().contains("Portuguese Island / Island")));
assertTrue(ctt.getSurcharges().stream().noneMatch(fee -> fee.getSectionName() != null && fee.getSectionName().contains("CEUTA")));
assertTrue(ctt.getSurcharges().stream().noneMatch(fee -> "Cubic Capacity".equals(fee.getFeeName())
&& fee.getSectionName() != null && fee.getSectionName().contains("CEUTA")));
assertTrue(ctt.getWeightBands().stream().noneMatch(band -> band.getZoneName() != null && band.getZoneName().contains("19E")));
assertTrue(ctt.getSurcharges().stream().noneMatch(fee -> fee.getFeeName() != null && (fee.getFeeName().contains("计费重量")
|| fee.getFeeName().contains("4.95") || fee.getFeeName().contains("退货"))));
PayOrderCostResult oneKg = PayCostCalculator.calculate(ctt, new java.math.BigDecimal("1"), null, null, null, null,
"Balearic Islands Economy 48H / Majorca", null, 1);
assertEquals(new java.math.BigDecimal("3.39"), oneKg.getPayTotal());
assertTrue(oneKg.getFees().stream().noneMatch(fee -> "每公斤续重".equals(fee.getFeeName())));
PayOrderCostResult twoKg = PayCostCalculator.calculate(ctt, new java.math.BigDecimal("2"), null, null, null, null,
"Balearic Islands Economy 48H / Majorca", null, 1);
assertEquals(new java.math.BigDecimal("4.24"), twoKg.getPayTotal());
assertEquals(1, twoKg.getFees().stream().filter(fee -> "每公斤续重".equals(fee.getFeeName())
&& fee.getAmount().compareTo(new java.math.BigDecimal("0.85")) == 0).count());
PayOrderCostResult island = PayCostCalculator.calculate(ctt, new java.math.BigDecimal("2"), null, null, null, null,
"Portuguese Island / Island", null, 1);
assertEquals(new java.math.BigDecimal("12.41"), island.getPayTotal());
assertEquals(1, island.getFees().stream().filter(fee -> "每公斤续重".equals(fee.getFeeName())
&& fee.getAmount().compareTo(new java.math.BigDecimal("3.34")) == 0).count());
}
@Test
void spainCttFillsCountryAndContinuedWeight() throws Exception
{
Path file = Path.of("D:/payment/西班牙CTT.xlsx");
if (!Files.exists(file))
{
file = Path.of("D:/A-payment/西班牙CTT.xlsx");
}
Assumptions.assumeTrue(Files.exists(file));
PayPreview preview = parser.parseMatched(Files.readAllBytes(file), file.getFileName().toString(), "西班牙CTT",
List.of("西班牙CTT"));
@@ -538,7 +568,7 @@ class PayWorkbookParserTest
assertEquals("西班牙", ctt.getCountryScope());
assertEquals("续重计费", ctt.getChargeType());
assertTrue(covers(ctt.getExtraPerKg(), "0.82"));
assertEquals(72, ctt.getWeightBands().size());
assertEquals(60, ctt.getWeightBands().size());
assertTrue(ctt.getWeightBands().stream().anyMatch(band -> "西班牙".equals(band.getCountryName()) && "ES".equals(band.getCountryCode())
&& "Mainland / Mad High Density".equals(band.getZoneName()) && "1kg".equals(band.getWeightLabel())
&& decimal(band, "2.1") && "每件".equals(band.getChargeName())
@@ -547,12 +577,19 @@ class PayWorkbookParserTest
assertTrue(ctt.getWeightBands().stream().anyMatch(band -> "Mainland / Portugal".equals(band.getZoneName())
&& "5kg".equals(band.getWeightLabel()) && decimal(band, "3.95")
&& band.getWeightMin().compareTo(new java.math.BigDecimal("4")) == 0));
assertTrue(ctt.getWeightBands().stream().anyMatch(band -> "Balearic Islands Economy 48H / Majorca".equals(band.getZoneName())
&& "Kg.ad.".equals(band.getWeightLabel()) && decimal(band, "0.82") && "每公斤".equals(band.getChargeName())
&& band.getWeightMin() == null));
assertTrue(ctt.getWeightBands().stream().noneMatch(band -> band.getWeightLabel() != null
&& (band.getWeightLabel().contains("Kg.ad") || band.getWeightLabel().contains("预估"))));
assertTrue(ctt.getWeightBands().stream().noneMatch(band -> "每公斤".equals(band.getChargeName())));
assertEquals(12, ctt.getSurcharges().stream().filter(fee -> "每公斤续重".equals(fee.getFeeName())).count());
assertTrue(ctt.getSurcharges().stream().anyMatch(fee -> "每公斤续重".equals(fee.getFeeName())
&& "Balearic Islands Economy 48H / Majorca".equals(fee.getZoneName()) && decimalFee(fee, "0.82")
&& "EUR".equals(fee.getCurrency()) && "EUR/KG".equals(fee.getPriceUnit())
&& "EXTRA_KG".equals(fee.getCalcRule()) && "5".equals(fee.getCalcParam())
&& fee.getFeeDesc().contains("超过5kg")));
assertTrue(ctt.getSurcharges().stream().anyMatch(fee -> "每公斤续重".equals(fee.getFeeName())
&& "Canary Islands / Minor Islands".equals(fee.getZoneName()) && decimalFee(fee, "1.83")));
assertTrue(ctt.getWeightBands().stream().anyMatch(band -> "Canary Islands / Minor Islands".equals(band.getZoneName())
&& "1kg".equals(band.getWeightLabel()) && decimal(band, "13.11")));
assertTrue(ctt.getWeightBands().stream().noneMatch(band -> band.getWeightLabel() != null && band.getWeightLabel().contains("预估")));
}
@Test