test_protocol_payment_installment.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. """分期应缴日:小数月间隔(30 天/月)与提前天数规则"""
  2. import unittest
  3. from decimal import Decimal
  4. from app.services.protocol_payment_installment import (
  5. calc_fq_installment_due_date,
  6. calc_installment_due_amounts_by_ratios,
  7. resolve_installment_due_amounts,
  8. )
  9. class TestCalcFqInstallmentDueDate(unittest.TestCase):
  10. def test_first_period_equals_start_date(self):
  11. self.assertEqual(calc_fq_installment_due_date("20260604", 0, 0.5), "20260604")
  12. def test_fractional_interval_half_month_six_periods(self):
  13. start = "20260604"
  14. interval = 0.5
  15. expected = [
  16. "20260604",
  17. "20260520",
  18. "20260604",
  19. "20260619",
  20. "20260705",
  21. "20260720",
  22. ]
  23. for i, exp in enumerate(expected):
  24. self.assertEqual(
  25. calc_fq_installment_due_date(start, i, interval),
  26. exp,
  27. msg=f"period {i + 1}",
  28. )
  29. def test_fractional_interval_0_1_advance_30_days(self):
  30. # +3 天 = 20260607,再提前 30 天
  31. self.assertEqual(calc_fq_installment_due_date("20260604", 1, 0.1), "20260508")
  32. def test_integer_interval_six_months(self):
  33. # +6 日历月 = 20261204,再提前 30 天
  34. self.assertEqual(calc_fq_installment_due_date("20260604", 1, 6), "20261104")
  35. def test_fractional_interval_0_3(self):
  36. # index=2 → 0.6 月 → 18 天 → 20260622,再提前 30 天
  37. self.assertEqual(calc_fq_installment_due_date("20260604", 2, 0.3), "20260523")
  38. def test_custom_advance_days_15(self):
  39. self.assertEqual(
  40. calc_fq_installment_due_date("20260604", 1, 6, advance_days=15),
  41. "20261119",
  42. )
  43. def test_max_contract_amount_is_split_in_decimal_cents_without_float_loss(self):
  44. total = Decimal("9999999999999999.99")
  45. amounts = resolve_installment_due_amounts(total, [], 2)
  46. self.assertEqual(amounts, [Decimal("4999999999999999.99"), Decimal("5000000000000000.00")])
  47. self.assertEqual(sum(amounts), total)
  48. def test_max_contract_amount_ratio_split_keeps_exact_tail_difference(self):
  49. total = Decimal("9999999999999999.99")
  50. amounts = calc_installment_due_amounts_by_ratios(total, [50, 50])
  51. self.assertEqual(amounts, [Decimal("4999999999999999.99"), Decimal("5000000000000000.00")])
  52. self.assertEqual(sum(amounts), total)
  53. if __name__ == "__main__":
  54. unittest.main()