ExBooking.Policy (ExBooking v0.1.0)

View Source

Pure booking-policy predicates.

Policy checks evaluate a candidate slot against caller-supplied rules: lead time, booking window, and daily cap. Notice policies for cancellation and reschedule transitions are evaluated by the facade lifecycle functions.

Example

iex> rule = %ExBooking.AvailabilityRule{timezone: "Etc/UTC", windows: [], lead_time_min: 60}
...> resource = %ExBooking.Resource{id: "resource_1", timezone: "Etc/UTC"}
...> slot = ExBooking.Interval.new!(~U[2026-07-13 09:30:00Z], ~U[2026-07-13 10:00:00Z])
...> ExBooking.Policy.violations(slot, rule, resource, ~U[2026-07-13 09:00:00Z])
[{:lead_time, 30}]

Summary

Types

A policy violation reason.

Functions

Evaluates a cancellation or reschedule policy against now and the existing booking. Returns :ok, or {:error, :not_allowed} when the policy forbids the action, or {:error, :min_notice} when it is requested too close to the start.

Validates a lifecycle notice policy before temporal arithmetic.

Returns every policy violation for slot against a resource's rule, evaluated relative to the caller-supplied now. An empty list means the slot is allowed.

Types

reason()

@type reason() ::
  {:lead_time, pos_integer()}
  | {:outside_window, Date.t()}
  | {:daily_cap, String.t(), Date.t()}

A policy violation reason.

Functions

notice_ok(existing, arg2, now)

@spec notice_ok(ExBooking.Interval.t(), map() | nil, DateTime.t()) ::
  :ok | {:error, :not_allowed | :min_notice}

Evaluates a cancellation or reschedule policy against now and the existing booking. Returns :ok, or {:error, :not_allowed} when the policy forbids the action, or {:error, :min_notice} when it is requested too close to the start.

Examples

iex> existing = ExBooking.Interval.new!(~U[2026-07-13 09:00:00Z], ~U[2026-07-13 09:30:00Z])
...>
...> ExBooking.Policy.notice_ok(
...>   existing,
...>   %{min_notice_min: 60, allowed: true},
...>   ~U[2026-07-13 07:00:00Z]
...> )
:ok

iex> existing = ExBooking.Interval.new!(~U[2026-07-13 09:00:00Z], ~U[2026-07-13 09:30:00Z])
...>
...> ExBooking.Policy.notice_ok(
...>   existing,
...>   %{min_notice_min: 120, allowed: true},
...>   ~U[2026-07-13 08:00:00Z]
...> )
{:error, :min_notice}

validate(policy, field)

@spec validate(map() | nil, atom()) :: :ok | {:error, {:invalid, atom(), term()}}

Validates a lifecycle notice policy before temporal arithmetic.

nil is an allowed inherited policy. Non-nil policies must contain exactly :allowed and :min_notice_min with their documented types.

Examples

iex> ExBooking.Policy.validate(%{allowed: true, min_notice_min: 60}, :cancellation_policy)
:ok

violations(slot, rule, resource, now)

Returns every policy violation for slot against a resource's rule, evaluated relative to the caller-supplied now. An empty list means the slot is allowed.

Examples

iex> rule = %ExBooking.AvailabilityRule{
...>   timezone: "Etc/UTC",
...>   windows: [],
...>   lead_time_min: 120
...> }
...>
...> resource = %ExBooking.Resource{id: "res_1", timezone: "Etc/UTC"}
...> slot = ExBooking.Interval.new!(~U[2026-07-13 09:30:00Z], ~U[2026-07-13 10:00:00Z])
...> ExBooking.Policy.violations(slot, rule, resource, ~U[2026-07-13 09:00:00Z])
[{:lead_time, 90}]