Functional Weave
Code in TypeScript

finance.early-payment-discount@1.0.0

vectors.json

5,900 bytes · view raw

[
  {"name": "2/10 net 30 paid on day 4 earns 2%", "args": [{"minor": 100000, "currency": "GBP"}, "2026-03-01", {"kind": "net", "n": 30, "discountBasisPoints": 200, "discountDays": 10}, "2026-03-05"], "expect": {"available": true, "discount": {"minor": 2000, "currency": "GBP"}, "amountToPay": {"minor": 98000, "currency": "GBP"}, "discountDeadline": "2026-03-11", "dueDate": "2026-03-31"}},
  {"name": "paid on the tenth day after the invoice: the window is inclusive", "args": [{"minor": 100000, "currency": "GBP"}, "2026-03-01", {"kind": "net", "n": 30, "discountBasisPoints": 200, "discountDays": 10}, "2026-03-11"], "expect": {"available": true, "discount": {"minor": 2000, "currency": "GBP"}, "amountToPay": {"minor": 98000, "currency": "GBP"}, "discountDeadline": "2026-03-11", "dueDate": "2026-03-31"}},
  {"name": "paid on the eleventh day: the discount has gone", "args": [{"minor": 100000, "currency": "GBP"}, "2026-03-01", {"kind": "net", "n": 30, "discountBasisPoints": 200, "discountDays": 10}, "2026-03-12"], "expect": {"available": false, "discount": {"minor": 0, "currency": "GBP"}, "amountToPay": {"minor": 100000, "currency": "GBP"}, "discountDeadline": "2026-03-11", "dueDate": "2026-03-31"}},
  {"name": "paid after the due date: no discount", "args": [{"minor": 100000, "currency": "GBP"}, "2026-03-01", {"kind": "net", "n": 30, "discountBasisPoints": 200, "discountDays": 10}, "2026-04-15"], "expect": {"available": false, "discount": {"minor": 0, "currency": "GBP"}, "amountToPay": {"minor": 100000, "currency": "GBP"}, "discountDeadline": "2026-03-11", "dueDate": "2026-03-31"}},
  {"name": "net 30 without a discount has no deadline", "args": [{"minor": 100000, "currency": "GBP"}, "2026-03-01", {"kind": "net", "n": 30, "discountBasisPoints": 0, "discountDays": 0}, "2026-03-02"], "expect": {"available": false, "discount": {"minor": 0, "currency": "GBP"}, "amountToPay": {"minor": 100000, "currency": "GBP"}, "discountDeadline": null, "dueDate": "2026-03-31"}},
  {"name": "the discount is rounded half-up once: 2% of 1234.57 is 24.69", "args": [{"minor": 123457, "currency": "GBP"}, "2026-03-01", {"kind": "net", "n": 30, "discountBasisPoints": 200, "discountDays": 10}, "2026-03-02"], "expect": {"available": true, "discount": {"minor": 2469, "currency": "GBP"}, "amountToPay": {"minor": 120988, "currency": "GBP"}, "discountDeadline": "2026-03-11", "dueDate": "2026-03-31"}},
  {"name": "an exact half penny rounds up: 2% of 0.25", "args": [{"minor": 25, "currency": "GBP"}, "2026-03-01", {"kind": "net", "n": 30, "discountBasisPoints": 200, "discountDays": 10}, "2026-03-02"], "expect": {"available": true, "discount": {"minor": 1, "currency": "GBP"}, "amountToPay": {"minor": 24, "currency": "GBP"}, "discountDeadline": "2026-03-11", "dueDate": "2026-03-31"}},
  {"name": "1.5/10: 1.5% of 999.99", "args": [{"minor": 99999, "currency": "GBP"}, "2026-03-01", {"kind": "net", "n": 30, "discountBasisPoints": 150, "discountDays": 10}, "2026-03-10"], "expect": {"available": true, "discount": {"minor": 1500, "currency": "GBP"}, "amountToPay": {"minor": 98499, "currency": "GBP"}, "discountDeadline": "2026-03-11", "dueDate": "2026-03-31"}},
  {"name": "window crosses a month end in a leap year", "args": [{"minor": 50000, "currency": "GBP"}, "2024-02-25", {"kind": "net", "n": 30, "discountBasisPoints": 200, "discountDays": 10}, "2024-03-06"], "expect": {"available": true, "discount": {"minor": 1000, "currency": "GBP"}, "amountToPay": {"minor": 49000, "currency": "GBP"}, "discountDeadline": "2024-03-06", "dueDate": "2024-03-26"}},
  {"name": "paying before the invoice date is early too", "args": [{"minor": 100000, "currency": "GBP"}, "2026-03-01", {"kind": "net", "n": 30, "discountBasisPoints": 200, "discountDays": 10}, "2026-02-27"], "expect": {"available": true, "discount": {"minor": 2000, "currency": "GBP"}, "amountToPay": {"minor": 98000, "currency": "GBP"}, "discountDeadline": "2026-03-11", "dueDate": "2026-03-31"}},
  {"name": "a zero total has a zero discount", "args": [{"minor": 0, "currency": "GBP"}, "2026-03-01", {"kind": "net", "n": 30, "discountBasisPoints": 200, "discountDays": 10}, "2026-03-02"], "expect": {"available": true, "discount": {"minor": 0, "currency": "GBP"}, "amountToPay": {"minor": 0, "currency": "GBP"}, "discountDeadline": "2026-03-11", "dueDate": "2026-03-31"}},
  {"name": "zero-decimal currency", "args": [{"minor": 100000, "currency": "JPY"}, "2026-03-01", {"kind": "net", "n": 30, "discountBasisPoints": 200, "discountDays": 10}, "2026-03-02"], "expect": {"available": true, "discount": {"minor": 2000, "currency": "JPY"}, "amountToPay": {"minor": 98000, "currency": "JPY"}, "discountDeadline": "2026-03-11", "dueDate": "2026-03-31"}},
  {"name": "a same-day-only discount with 0 discount days", "args": [{"minor": 100000, "currency": "GBP"}, "2026-03-01", {"kind": "end-of-month", "n": 1, "discountBasisPoints": 300, "discountDays": 0}, "2026-03-01"], "expect": {"available": true, "discount": {"minor": 3000, "currency": "GBP"}, "amountToPay": {"minor": 97000, "currency": "GBP"}, "discountDeadline": "2026-03-01", "dueDate": "2026-04-30"}},
  {"name": "a negative total is refused", "args": [{"minor": -100, "currency": "GBP"}, "2026-03-01", {"kind": "net", "n": 30, "discountBasisPoints": 200, "discountDays": 10}, "2026-03-02"], "expectError": "invoice total must not be negative"},
  {"name": "terms whose discount outlasts the due date are refused", "args": [{"minor": 100000, "currency": "GBP"}, "2026-03-01", {"kind": "net", "n": 30, "discountBasisPoints": 200, "discountDays": 40}, "2026-03-02"], "expectError": "the discount period ends after the due date"},
  {"name": "an impossible payment date is refused", "args": [{"minor": 100000, "currency": "GBP"}, "2026-03-01", {"kind": "net", "n": 30, "discountBasisPoints": 200, "discountDays": 10}, "2026-02-30"], "expectError": "not a real calendar date"}
]