Financial correctness (donation-leg model):
- Donations are no longer mutated when assigned to a registration; assignment now
creates an immutable "leg" record referencing the original donation instead.
- Fixed several places where money was double-counted once a donation was partially
or fully assigned (Payments, Revenue summary, Cashup reconciliation, Finance
report, Profit report, Master Orders, Revenue Detailed).
- Payments now record who recorded them (recordedBy), separate from who they're for.
Cashup:
- Per-user cash denomination counting (optional, any time) replaces the single
event-wide manual entry; the event's cash actual is the live sum of these counts.
- New "Payment accountability by staff member" breakdown across all methods, and a
read-only "Report" tab that opens automatically once an event is closed.
Reports page redesign:
- New shell: sidebar of universal filters (events, date range, past/inactive/closed
toggles), searchable/categorized report grid, and a popup viewer with
Print/Email/Excel/WhatsApp actions plus an in-app Reporting Guide.
- Visual pass: colored stat tiles and bar charts on most reports, matching mockups.
- PDF exports (download/Print/Email/WhatsApp) now share a branded design mirroring
the web report — colored header, stat tiles, bar chart, highlighted totals.
- Excel export now produces a styled .xlsx (via exceljs) instead of a plain CSV.
- Master Orders' "Donations made" table is now included in every export channel.
Bug fixes discovered while testing exports:
- Report emails now go through the shared, DB-configurable mail utility instead of
a one-off transporter that ignored Site Settings SMTP config.
- WhatsApp report sends now surface the actual WAWP API error and auto-recover a
disconnected session, instead of a bare axios status-code message.
Also: Admin-editable notification preference, richer Admin Registrations dashboard,
{{payment.link}} placeholder for Email/WhatsApp Attendees, and background
email/WhatsApp attendee sending.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
46 lines
2.7 KiB
TypeScript
46 lines
2.7 KiB
TypeScript
import type { LucideIcon } from "lucide-react";
|
|
import {
|
|
Calendar,
|
|
Users,
|
|
PieChart,
|
|
Ticket,
|
|
TrendingUp,
|
|
FileText,
|
|
Box,
|
|
ListChecks,
|
|
Heart,
|
|
Camera,
|
|
FileBarChart,
|
|
BarChart3,
|
|
ClipboardList,
|
|
} from "lucide-react";
|
|
|
|
export type ReportCategory = "Financial" | "Registration" | "Ticketing" | "Donations" | "Cashup" | "Other";
|
|
|
|
export const REPORT_CATEGORIES: ReportCategory[] = ["Financial", "Registration", "Ticketing", "Donations", "Cashup", "Other"];
|
|
|
|
export const REPORTS = [
|
|
{ key: "payments", label: "Payments between dates", description: "View payments within a date range", category: "Financial", icon: Calendar, fields: 4 },
|
|
{ key: "attendees", label: "Attendees per event (grouped by option)", description: "Grouped by option", category: "Registration", icon: Users, fields: 3 },
|
|
{ key: "regTypes", label: "Registration type counts", description: "Count by registration type", category: "Registration", icon: PieChart, fields: 2 },
|
|
{ key: "usage", label: "Ticket usage summary", description: "Summary of ticket usage", category: "Ticketing", icon: Ticket, fields: 3 },
|
|
{ key: "revenue", label: "Revenue summary (by method)", description: "Summary of revenue by payment method", category: "Financial", icon: TrendingUp, fields: 5 },
|
|
{ key: "revenueDetailed", label: "Revenue detailed", description: "Detailed revenue breakdown", category: "Financial", icon: FileText, fields: 6 },
|
|
{ key: "masterOrders", label: "Master orders breakdown", description: "Overview of orders, payments, and donations for the selected filters", category: "Registration", icon: Box, fields: 4 },
|
|
{ key: "regStatus", label: "Registration status breakdown", description: "Registration status overview", category: "Registration", icon: ListChecks, fields: 3 },
|
|
{ key: "donations", label: "Donations breakdown", description: "Breakdown of donations", category: "Donations", icon: Heart, fields: 3 },
|
|
{ key: "cashup", label: "Cashup reconciliation", description: "Reconcile cashup totals", category: "Cashup", icon: Camera, fields: 4 },
|
|
{ key: "financeReport", label: "Finance report (revenue & costs)", description: "Revenue & costs overview", category: "Financial", icon: FileBarChart, fields: 6 },
|
|
{ key: "profitReport", label: "Profit report", description: "View profit report", category: "Financial", icon: BarChart3, fields: 5 },
|
|
{ key: "cashupAudit", label: "Cashup audit trail", description: "Audit trail of cashup actions", category: "Cashup", icon: ClipboardList, fields: 6 },
|
|
] as const satisfies ReadonlyArray<{
|
|
key: string;
|
|
label: string;
|
|
description: string;
|
|
category: ReportCategory;
|
|
icon: LucideIcon;
|
|
fields: number;
|
|
}>;
|
|
|
|
export type ReportKey = typeof REPORTS[number]["key"];
|