Reviewed-on: #8 Co-authored-by: Patrick Mueller <patrick@mueller-patrick.tech> Co-committed-by: Patrick Mueller <patrick@mueller-patrick.tech>
This commit was merged in pull request #8.
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
export interface EventTicketState {
|
||||
eventId: number;
|
||||
capacity: number | null;
|
||||
redemptionDeadline: Date | null;
|
||||
collectAddress: boolean;
|
||||
requireAddress: boolean;
|
||||
guestsUsed: number;
|
||||
spotsRemaining: number | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an event's voucher settings + live guest count within the caller's
|
||||
* connection/transaction. Absence of a settings row means uncapped/no
|
||||
* deadline/no address collection - the "absence over sentinels" convention
|
||||
* also used by the Feedback module.
|
||||
*
|
||||
* Pass forUpdate=true from inside the redeem transaction to lock the
|
||||
* settings row for the duration of that transaction, serializing concurrent
|
||||
* redemptions against the same event so the guestsUsed sum computed here
|
||||
* stays correct even under a last-spot race. Events with no settings row
|
||||
* (uncapped) don't need this - there's no cap to race against.
|
||||
*/
|
||||
export const getEventTicketState = async (conn: any, eventId: number, forUpdate = false): Promise<EventTicketState> => {
|
||||
const settingsQuery = `SELECT capacity, redemption_deadline, collect_address, require_address FROM event_ticket_settings WHERE event_id = ?${forUpdate ? ' FOR UPDATE' : ''}`;
|
||||
const settingsRows = await conn.query(settingsQuery, [eventId]);
|
||||
const capacity = settingsRows.length > 0 ? settingsRows[0].capacity : null;
|
||||
const redemptionDeadline = settingsRows.length > 0 ? settingsRows[0].redemption_deadline : null;
|
||||
const collectAddress = settingsRows.length > 0 ? !!settingsRows[0].collect_address : false;
|
||||
// Only meaningful when collectAddress is also true - the field isn't
|
||||
// shown/collected at all otherwise, so "required" is moot.
|
||||
const requireAddress = collectAddress && settingsRows.length > 0 ? !!settingsRows[0].require_address : false;
|
||||
|
||||
const usedRows = await conn.query(
|
||||
"SELECT COALESCE(SUM(guest_count), 0) as used FROM redemptions WHERE event_id = ? AND status = 'ACTIVE'",
|
||||
[eventId]
|
||||
);
|
||||
const guestsUsed = Number(usedRows[0].used);
|
||||
const spotsRemaining = capacity === null ? null : Math.max(0, capacity - guestsUsed);
|
||||
|
||||
return {eventId, capacity, redemptionDeadline, collectAddress, requireAddress, guestsUsed, spotsRemaining};
|
||||
};
|
||||
Reference in New Issue
Block a user