Functional Weave
Code in Python

hospitality.cancellation-charge@1.0.0

vectors.json

9,944 bytes · view raw

[
  {"name": "20 days' notice is free", "args": [[{"minDaysNotice": 14, "nights": null, "basisPoints": 0}, {"minDaysNotice": 7, "nights": 1, "basisPoints": 5000}, {"minDaysNotice": 0, "nights": null, "basisPoints": 10000}], [{"minor": 12000, "currency": "GBP"}, {"minor": 12000, "currency": "GBP"}, {"minor": 15000, "currency": "GBP"}], "2026-12-18", "2026-11-28"], "expect": {"daysNotice": 20, "minDaysNotice": 14, "chargedNights": 3, "chargeBase": {"minor": 39000, "currency": "GBP"}, "basisPoints": 0, "charge": {"minor": 0, "currency": "GBP"}}},
  {"name": "exactly 14 days' notice is still free", "args": [[{"minDaysNotice": 14, "nights": null, "basisPoints": 0}, {"minDaysNotice": 7, "nights": 1, "basisPoints": 5000}, {"minDaysNotice": 0, "nights": null, "basisPoints": 10000}], [{"minor": 12000, "currency": "GBP"}, {"minor": 12000, "currency": "GBP"}, {"minor": 15000, "currency": "GBP"}], "2026-12-18", "2026-12-04"], "expect": {"daysNotice": 14, "minDaysNotice": 14, "chargedNights": 3, "chargeBase": {"minor": 39000, "currency": "GBP"}, "basisPoints": 0, "charge": {"minor": 0, "currency": "GBP"}}},
  {"name": "13 days' notice: half the first night", "args": [[{"minDaysNotice": 14, "nights": null, "basisPoints": 0}, {"minDaysNotice": 7, "nights": 1, "basisPoints": 5000}, {"minDaysNotice": 0, "nights": null, "basisPoints": 10000}], [{"minor": 12000, "currency": "GBP"}, {"minor": 12000, "currency": "GBP"}, {"minor": 15000, "currency": "GBP"}], "2026-12-18", "2026-12-05"], "expect": {"daysNotice": 13, "minDaysNotice": 7, "chargedNights": 1, "chargeBase": {"minor": 12000, "currency": "GBP"}, "basisPoints": 5000, "charge": {"minor": 6000, "currency": "GBP"}}},
  {"name": "exactly 7 days' notice: half the first night", "args": [[{"minDaysNotice": 14, "nights": null, "basisPoints": 0}, {"minDaysNotice": 7, "nights": 1, "basisPoints": 5000}, {"minDaysNotice": 0, "nights": null, "basisPoints": 10000}], [{"minor": 12000, "currency": "GBP"}, {"minor": 12000, "currency": "GBP"}, {"minor": 15000, "currency": "GBP"}], "2026-12-18", "2026-12-11"], "expect": {"daysNotice": 7, "minDaysNotice": 7, "chargedNights": 1, "chargeBase": {"minor": 12000, "currency": "GBP"}, "basisPoints": 5000, "charge": {"minor": 6000, "currency": "GBP"}}},
  {"name": "6 days' notice: the whole stay", "args": [[{"minDaysNotice": 14, "nights": null, "basisPoints": 0}, {"minDaysNotice": 7, "nights": 1, "basisPoints": 5000}, {"minDaysNotice": 0, "nights": null, "basisPoints": 10000}], [{"minor": 12000, "currency": "GBP"}, {"minor": 12000, "currency": "GBP"}, {"minor": 15000, "currency": "GBP"}], "2026-12-18", "2026-12-12"], "expect": {"daysNotice": 6, "minDaysNotice": 0, "chargedNights": 3, "chargeBase": {"minor": 39000, "currency": "GBP"}, "basisPoints": 10000, "charge": {"minor": 39000, "currency": "GBP"}}},
  {"name": "cancelling on the arrival day is 0 days' notice", "args": [[{"minDaysNotice": 14, "nights": null, "basisPoints": 0}, {"minDaysNotice": 7, "nights": 1, "basisPoints": 5000}, {"minDaysNotice": 0, "nights": null, "basisPoints": 10000}], [{"minor": 12000, "currency": "GBP"}, {"minor": 12000, "currency": "GBP"}, {"minor": 15000, "currency": "GBP"}], "2026-12-18", "2026-12-18"], "expect": {"daysNotice": 0, "minDaysNotice": 0, "chargedNights": 3, "chargeBase": {"minor": 39000, "currency": "GBP"}, "basisPoints": 10000, "charge": {"minor": 39000, "currency": "GBP"}}},
  {"name": "a no-show recorded the day after arrival uses the 0-day band", "args": [[{"minDaysNotice": 14, "nights": null, "basisPoints": 0}, {"minDaysNotice": 7, "nights": 1, "basisPoints": 5000}, {"minDaysNotice": 0, "nights": null, "basisPoints": 10000}], [{"minor": 12000, "currency": "GBP"}, {"minor": 12000, "currency": "GBP"}, {"minor": 15000, "currency": "GBP"}], "2026-12-18", "2026-12-19"], "expect": {"daysNotice": -1, "minDaysNotice": 0, "chargedNights": 3, "chargeBase": {"minor": 39000, "currency": "GBP"}, "basisPoints": 10000, "charge": {"minor": 39000, "currency": "GBP"}}},
  {"name": "the notice count crosses 29 February: 23 Feb to 1 Mar 2028 is 7 days", "args": [[{"minDaysNotice": 14, "nights": null, "basisPoints": 0}, {"minDaysNotice": 7, "nights": 1, "basisPoints": 5000}, {"minDaysNotice": 0, "nights": null, "basisPoints": 10000}], [{"minor": 10000, "currency": "GBP"}], "2028-03-01", "2028-02-23"], "expect": {"daysNotice": 7, "minDaysNotice": 7, "chargedNights": 1, "chargeBase": {"minor": 10000, "currency": "GBP"}, "basisPoints": 5000, "charge": {"minor": 5000, "currency": "GBP"}}},
  {"name": "the notice count crosses a year end", "args": [[{"minDaysNotice": 14, "nights": null, "basisPoints": 0}, {"minDaysNotice": 7, "nights": 1, "basisPoints": 5000}, {"minDaysNotice": 0, "nights": null, "basisPoints": 10000}], [{"minor": 12000, "currency": "GBP"}, {"minor": 12000, "currency": "GBP"}, {"minor": 15000, "currency": "GBP"}], "2027-01-05", "2026-12-22"], "expect": {"daysNotice": 14, "minDaysNotice": 14, "chargedNights": 3, "chargeBase": {"minor": 39000, "currency": "GBP"}, "basisPoints": 0, "charge": {"minor": 0, "currency": "GBP"}}},
  {"name": "a band for two nights on a one-night stay charges the one night", "args": [[{"minDaysNotice": 0, "nights": 2, "basisPoints": 10000}], [{"minor": 9500, "currency": "GBP"}], "2026-12-18", "2026-12-18"], "expect": {"daysNotice": 0, "minDaysNotice": 0, "chargedNights": 1, "chargeBase": {"minor": 9500, "currency": "GBP"}, "basisPoints": 10000, "charge": {"minor": 9500, "currency": "GBP"}}},
  {"name": "a band for the first two nights of three", "args": [[{"minDaysNotice": 0, "nights": 2, "basisPoints": 10000}], [{"minor": 12000, "currency": "GBP"}, {"minor": 12000, "currency": "GBP"}, {"minor": 15000, "currency": "GBP"}], "2026-12-18", "2026-12-18"], "expect": {"daysNotice": 0, "minDaysNotice": 0, "chargedNights": 2, "chargeBase": {"minor": 24000, "currency": "GBP"}, "basisPoints": 10000, "charge": {"minor": 24000, "currency": "GBP"}}},
  {"name": "a third of a night rounds half-up: 33.33% of 123.45 is 41.1459", "args": [[{"minDaysNotice": 0, "nights": 1, "basisPoints": 3333}], [{"minor": 12345, "currency": "GBP"}], "2026-12-18", "2026-12-10"], "expect": {"daysNotice": 8, "minDaysNotice": 0, "chargedNights": 1, "chargeBase": {"minor": 12345, "currency": "GBP"}, "basisPoints": 3333, "charge": {"minor": 4115, "currency": "GBP"}}},
  {"name": "bands may be listed in any order", "args": [[{"minDaysNotice": 0, "nights": null, "basisPoints": 10000}, {"minDaysNotice": 14, "nights": null, "basisPoints": 0}, {"minDaysNotice": 7, "nights": 1, "basisPoints": 5000}], [{"minor": 12000, "currency": "GBP"}, {"minor": 12000, "currency": "GBP"}, {"minor": 15000, "currency": "GBP"}], "2026-12-18", "2026-12-08"], "expect": {"daysNotice": 10, "minDaysNotice": 7, "chargedNights": 1, "chargeBase": {"minor": 12000, "currency": "GBP"}, "basisPoints": 5000, "charge": {"minor": 6000, "currency": "GBP"}}},
  {"name": "a policy with no 0-day band cannot price a late cancellation", "args": [[{"minDaysNotice": 3, "nights": null, "basisPoints": 5000}], [{"minor": 12000, "currency": "GBP"}, {"minor": 12000, "currency": "GBP"}, {"minor": 15000, "currency": "GBP"}], "2026-12-18", "2026-12-17"], "expectError": "no band in the policy covers 1 days' notice"},
  {"name": "an empty policy is an error", "args": [[], [{"minor": 12000, "currency": "GBP"}, {"minor": 12000, "currency": "GBP"}, {"minor": 15000, "currency": "GBP"}], "2026-12-18", "2026-12-18"], "expectError": "policy must have at least one band"},
  {"name": "no nights is an error", "args": [[{"minDaysNotice": 14, "nights": null, "basisPoints": 0}, {"minDaysNotice": 7, "nights": 1, "basisPoints": 5000}, {"minDaysNotice": 0, "nights": null, "basisPoints": 10000}], [], "2026-12-18", "2026-12-18"], "expectError": "nightlyRates must have at least one night"},
  {"name": "two bands for the same notice are an error", "args": [[{"minDaysNotice": 0, "nights": null, "basisPoints": 10000}, {"minDaysNotice": 0, "nights": 1, "basisPoints": 5000}], [{"minor": 12000, "currency": "GBP"}, {"minor": 12000, "currency": "GBP"}, {"minor": 15000, "currency": "GBP"}], "2026-12-18", "2026-12-18"], "expectError": "policy has two bands for 0 days' notice"},
  {"name": "a charge over 100% is an error", "args": [[{"minDaysNotice": 0, "nights": null, "basisPoints": 10001}], [{"minor": 12000, "currency": "GBP"}, {"minor": 12000, "currency": "GBP"}, {"minor": 15000, "currency": "GBP"}], "2026-12-18", "2026-12-18"], "expectError": "basisPoints must be a whole number from 0 to 10000"},
  {"name": "a band of zero nights is an error", "args": [[{"minDaysNotice": 0, "nights": 0, "basisPoints": 10000}], [{"minor": 12000, "currency": "GBP"}, {"minor": 12000, "currency": "GBP"}, {"minor": 15000, "currency": "GBP"}], "2026-12-18", "2026-12-18"], "expectError": "nights must be at least 1 or null for the whole stay"},
  {"name": "a negative notice band is an error", "args": [[{"minDaysNotice": -1, "nights": null, "basisPoints": 10000}], [{"minor": 12000, "currency": "GBP"}, {"minor": 12000, "currency": "GBP"}, {"minor": 15000, "currency": "GBP"}], "2026-12-18", "2026-12-18"], "expectError": "minDaysNotice must not be negative"},
  {"name": "mixed currencies are an error", "args": [[{"minDaysNotice": 14, "nights": null, "basisPoints": 0}, {"minDaysNotice": 7, "nights": 1, "basisPoints": 5000}, {"minDaysNotice": 0, "nights": null, "basisPoints": 10000}], [{"minor": 100, "currency": "GBP"}, {"minor": 100, "currency": "EUR"}], "2026-12-18", "2026-12-11"], "expectError": "currency mismatch"},
  {"name": "an impossible date is an error", "args": [[{"minDaysNotice": 14, "nights": null, "basisPoints": 0}, {"minDaysNotice": 7, "nights": 1, "basisPoints": 5000}, {"minDaysNotice": 0, "nights": null, "basisPoints": 10000}], [{"minor": 12000, "currency": "GBP"}, {"minor": 12000, "currency": "GBP"}, {"minor": 15000, "currency": "GBP"}], "2026-02-30", "2026-12-18"], "expectError": "is not a real calendar date"}
]