# Conflicts:
#	bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPayBillFee.java
#	bms-back/bms-system/src/main/resources/mapper/price/PrcPayBillFeeMapper.xml
This commit is contained in:
wuweihua
2026-11-14 00:32:55 +08:00
29 changed files with 1755 additions and 252 deletions
@@ -40,10 +40,81 @@ public class PayPostcodeController extends BaseController
public TableDataInfo list(PayPostcodeGroup query)
{
startPage();
List<PayPostcodeGroup> list = payPostcodeService.selectGroupList(query);
List<PayPostcodeGroup> list = payPostcodeService.selectCountryList(query);
return getDataTable(list);
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:query')")
@GetMapping("/zones")
public AjaxResult zones(PayPostcodeGroup query)
{
return success(payPostcodeService.selectZoneList(query));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:edit')")
@Log(title = "应付邮编配置", businessType = BusinessType.INSERT)
@PostMapping("/zones")
public AjaxResult addZone(@RequestBody PayPostcodeGroup zone)
{
return toAjax(payPostcodeService.addZone(zone, getUsername()));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:edit')")
@Log(title = "应付邮编配置", businessType = BusinessType.UPDATE)
@PutMapping("/zones")
public AjaxResult editZone(@RequestBody PayPostcodeGroup zone)
{
return toAjax(payPostcodeService.updateZone(zone));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:remove')")
@Log(title = "应付邮编配置", businessType = BusinessType.DELETE)
@DeleteMapping("/zones")
public AjaxResult removeZone(PayPostcodeGroup zone)
{
return toAjax(payPostcodeService.deleteZone(zone));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:edit')")
@Log(title = "应付邮编配置", businessType = BusinessType.UPDATE)
@PutMapping("/country")
public AjaxResult editCountry(@RequestBody PayPostcodeGroup country)
{
return toAjax(payPostcodeService.updateCountry(country));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:remove')")
@Log(title = "应付邮编配置", businessType = BusinessType.DELETE)
@DeleteMapping("/country")
public AjaxResult removeCountry(PayPostcodeGroup country)
{
return toAjax(payPostcodeService.deleteCountry(country));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:edit')")
@Log(title = "应付邮编配置", businessType = BusinessType.INSERT)
@PostMapping("/lines")
public AjaxResult addLine(@RequestBody PayPostcodeLine line)
{
return toAjax(payPostcodeService.addLine(line));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:edit')")
@Log(title = "应付邮编配置", businessType = BusinessType.UPDATE)
@PutMapping("/lines")
public AjaxResult editLine(@RequestBody PayPostcodeLine line)
{
return toAjax(payPostcodeService.updateLine(line));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:remove')")
@Log(title = "应付邮编配置", businessType = BusinessType.DELETE)
@DeleteMapping("/lines/{lineIds}")
public AjaxResult removeLines(@PathVariable Long[] lineIds)
{
return toAjax(payPostcodeService.deleteLines(lineIds));
}
/** 按国家去重区块,供附加费编辑分区下拉 */
@PreAuthorize("@ss.hasPermi('data:payPostcode:list')")
@GetMapping("/blockOptions")
@@ -228,6 +228,44 @@ class PayCostCalculatorTest
assertTrue(hasFee(result, "偏远附加费", "0.70"));
}
@Test
void countryRemoteHitWithoutAZoneUsesTheFeePostcodeTier()
{
PayProduct product = new PayProduct();
product.setProductName("CTT 48H");
product.setCurrency("EUR");
product.setWeightBands(new ArrayList<>(List.of(band("0", "5", "2.05", "马德里"))));
PaySurcharge balearic = fee(1L, "偏远附加费", "7.1", "EUR", "POSTCODE", "07");
balearic.setZoneName("Balearic Islands 07邮编开头");
balearic.setPostcodeParam("07");
PaySurcharge canary = fee(2L, "偏远附加费", "8.9", "EUR", "POSTCODE", "35,38");
canary.setZoneName("Canary Islands 35、38邮编开头");
canary.setPostcodeParam("35,38");
PaySurcharge extra = fee(3L, "偏远附加费", "4", "EUR", "EXTRA_KG", "1");
extra.setZoneName("Balearic Islands 07邮编开头");
extra.setPostcodeParam("07");
extra.setPriceUnit("EUR/KG");
product.setSurcharges(List.of(balearic, canary, extra));
List<PayRemoteBook.Hit> hits = List.of(new PayRemoteBook.Hit("", null, "", ""));
PayOrderCostResult light = PayCostCalculator.calculate(product, new BigDecimal("0.8"),
null, null, null, "07008", "马德里", null, 1, hits, false, false, "ES", "西班牙");
assertTrue(hasFee(light, "偏远附加费", "7.1"));
assertTrue(light.getFees().stream().noneMatch(fee -> fee.getFeeName().equals("偏远附加费")
&& fee.getAmount().compareTo(new BigDecimal("8.9")) == 0));
assertTrue(light.getFees().stream().noneMatch(fee -> fee.getAmount().compareTo(new BigDecimal("4")) == 0));
PayOrderCostResult heavy = PayCostCalculator.calculate(product, new BigDecimal("3"),
null, null, null, "07008", "马德里", null, 1, hits, false, false, "ES", "西班牙");
assertTrue(hasFee(heavy, "偏远附加费", "7.1"));
assertTrue(hasFee(heavy, "偏远附加费", "8"));
List<PayRemoteBook.Hit> named = List.of(new PayRemoteBook.Hit("", null, "", "Aland Islands"));
PayOrderCostResult skipped = PayCostCalculator.calculate(product, new BigDecimal("0.8"),
null, null, null, "07008", "马德里", null, 1, named, false, false, "ES", "西班牙");
assertTrue(skipped.getFees().stream().noneMatch(fee -> "偏远附加费".equals(fee.getFeeName())));
}
@Test
void remoteHitsFollowTheProductGroupAndCountry()
{
@@ -68,6 +68,24 @@ class PaySurchargeConfigCalcTest
assertTrue(peak.getFees().stream().noneMatch(fee -> fee.getFeeName().contains("超尺寸")));
}
@Test
void sumOverThreeHundredChargesEachExtraTenCentimetres()
{
PayOrderCostResult result = PayCostCalculator.calculate(sumStep(), new BigDecimal("0.039"),
new BigDecimal("300"), new BigDecimal("300"), new BigDecimal("300"),
null, null, null, 8);
assertTrue(hasFee(result, "基础运费", "2.40"));
assertTrue(hasFee(result, "超尺寸附加费", "2.43"));
assertTrue(hasFee(result, "超尺寸附加费", "378.00"));
assertEquals(new BigDecimal("382.83"), result.getPayTotal());
PayOrderCostResult oneStep = PayCostCalculator.calculate(sumStep(), new BigDecimal("0.039"),
new BigDecimal("100"), new BigDecimal("100"), new BigDecimal("101"),
null, null, null, 8);
assertTrue(hasFee(oneStep, "超尺寸附加费", "2.43"));
assertTrue(hasFee(oneStep, "超尺寸附加费", "6.30"));
}
private static boolean hasFee(PayOrderCostResult result, String name, String amount)
{
return result.getFees().stream().anyMatch(fee -> name.equals(fee.getFeeName())
@@ -79,6 +97,28 @@ class PaySurchargeConfigCalcTest
return Date.from(LocalDate.of(year, month, day).atStartOfDay(ZoneId.systemDefault()).toInstant());
}
private static PayProduct sumStep()
{
PayProduct product = new PayProduct();
product.setProductName("CTT 48H");
product.setCurrency("EUR");
product.setWeightBands(List.of(band("0", "1", "2.40")));
PaySurcharge flat = fee("超尺寸附加费", "2.43", "SIZE");
PaySurcharge step = fee("超尺寸附加费", "6.30", "SIZE");
step.setChargeText("6.3EUR/增加10cm");
product.setSurcharges(List.of(flat, step));
PaySurchargeRule rule = new PaySurchargeRule();
rule.setCalcRule("SIZE");
rule.setEnabled("1");
Map<String, Object> detail = new LinkedHashMap<>();
detail.put("matchMode", "ANY");
detail.put("sumMin", new BigDecimal("300"));
detail.put("exceedStepCm", new BigDecimal("10"));
rule.setDetail(detail);
product.setBillingRules(List.of(rule));
return product;
}
private static PayProduct imile()
{
PayProduct product = new PayProduct();