Add per-event finance, event team permissions and public door sales state.
Event finance - Finance tab on the event page: P&L summary with a revenue-to-result waterfall, costs and other income in one ledger, and the partner split with payouts. Lifecycle stepper (Selling, Adding costs, Ready to close, Finalized) with what is left to do; closing the books goes through a checklist dialog that freezes the numbers. - Expense modal shows only the fields each calculation type needs, a live preview with the event's real counts, and a category suggested from the description. Date inputs follow the UI language. - Global Finance page: profit per event with outliers clipped and labelled, and a "Ready to close" list of past events whose books are still open. - Calculation service (integer PYG, basis points) with pinned regression scenarios; PYG formatting centralised in lib/money with locale-aware separators. Event team permissions - Per-event members with role presets and requireEventPermission; the header stat "Confirmed" is relabelled "Not checked in yet", which is what it counts. Public sales state - One sales state (online, door, sold out, ended, external, cancelled) for the event page, listings and JSON-LD, with the door price and tenders shown only while people can still pay at the door. Frontend unit tests run with vitest (npm test in frontend/). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
b51c1360e2
commit
e203fb6c74
@@ -0,0 +1,32 @@
|
||||
// finance_audit_log rows. Returned as TxOps so every change and its audit row
|
||||
// commit (or roll back) together.
|
||||
|
||||
import { financeAuditLog } from '../../db/index.js';
|
||||
import { generateId, getNow } from '../utils.js';
|
||||
import { insertOp, type TxOp } from '../txOps.js';
|
||||
|
||||
export type FinanceEntity =
|
||||
| 'expense' | 'other_income' | 'partner' | 'finance_state' | 'member'
|
||||
| 'expense_category' | 'expense_template' | 'expense_template_pack' | 'payment_fee';
|
||||
|
||||
export function financeAuditOp(entry: {
|
||||
eventId: string | null;
|
||||
actorUserId: string;
|
||||
entityType: FinanceEntity;
|
||||
entityId: string | null;
|
||||
action: string;
|
||||
before?: unknown;
|
||||
after?: unknown;
|
||||
}): TxOp {
|
||||
return insertOp(financeAuditLog, {
|
||||
id: generateId(),
|
||||
eventId: entry.eventId,
|
||||
actorUserId: entry.actorUserId,
|
||||
entityType: entry.entityType,
|
||||
entityId: entry.entityId,
|
||||
action: entry.action,
|
||||
beforeJson: entry.before === undefined || entry.before === null ? null : JSON.stringify(entry.before),
|
||||
afterJson: entry.after === undefined || entry.after === null ? null : JSON.stringify(entry.after),
|
||||
createdAt: getNow(),
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user