feat(waitlist): optional event waitlist with FIFO promote.
CI / test (push) Successful in 7m12s
CI / deploy-ift (push) Successful in 2m44s
CI / e2e-ift (push) Successful in 1m28s
CI / deploy-stage (push) Successful in 2m3s
CI / e2e-stage (push) Successful in 1m24s

Commercial calendars opt in via settings.waitlist_enabled; join when full;
auto-promote on cancel/decline/expire with email and in-app notify.

Refs EventHub/EventHubBack#72
This commit is contained in:
2026-08-14 21:44:42 +03:00
parent 29111cd514
commit fb8869fa86
15 changed files with 730 additions and 9 deletions
+34 -5
View File
@@ -8,7 +8,7 @@
list_bookings_admin/0, get_booking_admin/1,
list_event_bookings/1, list_event_bookings/2,
process_timeout_bookings/0, process_reminders/0, cancel_pending_for_owner/1,
cancel_pending_for_calendar/1]).
cancel_pending_for_calendar/1, can_manage_event_bookings/2]).
%%%-------------------------------------------------------------------
%%% @doc Создание бронирования с учётом commercial / confirmation / capacity.
@@ -133,7 +133,13 @@ confirm_booking(UserId, BookingId, decline) ->
true ->
case ensure_pending_actionable(Booking) of
{ok, _} ->
core_booking:update(BookingId, [{status, cancelled}]);
case core_booking:update(BookingId, [{status, cancelled}]) of
{ok, _} = Ok ->
_ = logic_waitlist:maybe_promote(Booking#booking.event_id),
Ok;
Err ->
Err
end;
{error, Reason} ->
{error, Reason}
end;
@@ -155,7 +161,14 @@ cancel_booking(BookingId, UserId) ->
{ok, Booking};
_ ->
case Booking#booking.user_id =:= UserId of
true -> core_booking:update(BookingId, [{status, cancelled}]);
true ->
case core_booking:update(BookingId, [{status, cancelled}]) of
{ok, _} = Ok ->
_ = logic_waitlist:maybe_promote(Booking#booking.event_id),
Ok;
Err ->
Err
end;
false -> {error, access_denied}
end
end;
@@ -462,7 +475,12 @@ maybe_timeout(#booking{id = Id, event_id = EventId, created_at = Created} = Book
Now = calendar:universal_time(),
_ = core_booking:update(Id, [{status, confirmed}, {confirmed_at, Now}]);
false ->
_ = core_booking:update(Id, [{status, cancelled}])
case core_booking:update(Id, [{status, cancelled}]) of
{ok, _} ->
_ = logic_waitlist:maybe_promote(EventId);
_ ->
ok
end
end;
false ->
ok
@@ -553,7 +571,18 @@ ensure_not_past_pending(B) ->
-spec mark_expired(binary()) -> {ok, #booking{}} | {error, term()}.
mark_expired(BookingId) ->
core_booking:update(BookingId, [{status, expired}]).
case core_booking:get_by_id(BookingId) of
{ok, #booking{event_id = EventId}} ->
case core_booking:update(BookingId, [{status, expired}]) of
{ok, _} = Ok ->
_ = logic_waitlist:maybe_promote(EventId),
Ok;
Err ->
Err
end;
{error, _} = Err ->
Err
end.
-spec event_started(#event{}, non_neg_integer()) -> boolean().
event_started(#event{start_time = Start}, NowSec) ->