Commit Graph

115 Commits

Author SHA1 Message Date
Bastian Wagner
7b499b361f feat: add buildReceivableRows for fine/levy/fee entries
Cashbox export previously only saw payment transactions. This adds
the query for fine/levy/fee entries (Forderungen) that the redesigned
PDF report will show in a separate section.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 10:22:59 +02:00
Bastian Wagner
0bad154971 fix: remove invalid default on CashboxExportSubscription.recipients
MySQL/MariaDB reject a DEFAULT value on TEXT-backed columns (TypeORM's
simple-array maps to TEXT), so table creation failed with
"BLOB, TEXT, GEOMETRY or JSON column 'recipients' can't have a default
value". The service always assigns recipients before saving, so no
DB-level default was ever needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 09:56:39 +02:00
Bastian Wagner
da5998487a fix: address cashbox-export whole-branch review findings
- Reject dates that are not strict YYYY-MM-DD (was accepting full ISO
  datetimes, which silently produced empty exports instead of a 400)
  and reject from > to with a 400 before touching the team/DB.
- Emit the cashbox_export_download and cashbox_export_subscription_update
  audit log events that were declared but never fired, matching the
  audit trail every sibling feature already has.
- Restore full type checking on the pdfkit import via `import = require()`
  instead of an untyped require() with an eslint-disable.
- Tighten a cashbox.spec.ts assertion to check the exact dialog class
  instead of expect.anything(), so it can't pass with the wrong dialog
  wired to the Export button.
- Style and announce the export dialogs' error messages using this
  codebase's established error-message/role=alert pattern.
2026-08-04 09:20:44 +02:00
Bastian Wagner
ce0b500d7a fix: re-check canBook() inside export dialog methods (defense in depth)
openExportDialog()/openExportSubscriptionDialog() only guarded on teamId
truthiness, relying solely on the template @if for permission gating.
Every other permission-gated method in Cashbox (submitPlayerBooking,
reverseBooking) re-checks the permission internally too. Add the same
guard here, plus a test asserting direct invocation without booking
rights does not call dialog.open.
2026-08-04 08:59:49 +02:00
Bastian Wagner
1c214c5f06 feat: wire cashbox export and subscription dialogs into Cashbox page
Adds an Export button (opens CashboxExportDialog directly) plus a
secondary menu (opens CashboxExportSubscriptionDialog) to the journal
toolbar, gated by the existing canBook permission signal.
2026-08-04 08:53:05 +02:00
Bastian Wagner
148269da11 fix: add error handling to CashboxExportSubscriptionDialog 2026-08-04 08:39:10 +02:00
Bastian Wagner
db061a7ef7 feat: add CashboxExportSubscriptionDialog 2026-08-04 08:34:01 +02:00
Bastian Wagner
11b70b9337 feat: add error handling to CashboxExportDialog 2026-08-04 08:29:22 +02:00
Bastian Wagner
5c3ff52689 feat: add CashboxExportDialog 2026-08-04 08:24:57 +02:00
Bastian Wagner
a65c7b35b3 feat: add CashboxExportApi 2026-08-04 08:19:09 +02:00
Bastian Wagner
72fa1d4331 feat: add cashbox export model and FileDownloadService 2026-08-04 08:14:58 +02:00
Bastian Wagner
d628d5e4d7 fix: add LoggingModule import to CashboxExportModule 2026-08-04 08:10:04 +02:00
Bastian Wagner
57869d5fc1 feat: register CashboxExportModule 2026-08-04 08:03:29 +02:00
Bastian Wagner
eed8266da2 fix: add error handling for CashboxExportScheduler subscription processing
- Wrap runOne(subscription) in try/catch to ensure one subscription failure doesn't block remaining subscriptions
- Log failed subscriptions with new 'cashbox_export_subscription_run_fail' event
- Add new LOGEVENT type for subscription run failures
- Add test to verify second subscription processes even when first fails (continues processing independently)
- All 7 tests passing: 6 original + 1 new failure handling test

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 07:56:39 +02:00
Bastian Wagner
5779483b21 feat: add CashboxExportScheduler for recurring PDF mailing
- Implement CashboxExportScheduler with @Cron(EVERY_DAY_AT_4AM)
- Query due subscriptions (active=true, nextRunDate <= today)
- For each subscription: fetch team, build PDF, send email, advance nextRunDate
- Support monthly/quarterly/yearly intervals via INTERVAL_MONTHS map
- Add cashbox_export_subscription_run to LOGEVENT type for logging
- All 6 tests passing: empty state, monthly/quarterly/yearly periods, multiple subscriptions

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 07:49:58 +02:00
Bastian Wagner
196898b993 feat: add MailService.cashboxExport and email template 2026-08-04 07:44:12 +02:00
Bastian Wagner
42e2bbc4ff feat: add cashbox export subscription endpoints
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 07:39:20 +02:00
Bastian Wagner
a11eb73ce9 feat: add CashboxExportSubscription entity and service 2026-08-04 07:28:01 +02:00
Bastian Wagner
009aae1f2b feat: add cashbox export download endpoint 2026-08-03 21:37:14 +02:00
Bastian Wagner
18df224386 test: enforce permission check ordering in CashboxExportService 2026-08-03 21:33:36 +02:00
Bastian Wagner
396dc29cf5 feat: add CashboxExportService.exportForUser 2026-08-03 21:30:22 +02:00
Bastian Wagner
f8857f71e1 feat: add buildPdf for cashbox export
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 21:20:57 +02:00
Bastian Wagner
0b408f7d73 fix: use symmetric rounding for negative amounts in formatGermanAmount 2026-08-03 21:16:05 +02:00
Bastian Wagner
c6df6a6d38 fix: handle negative-zero and half-cent rounding in formatGermanAmount 2026-08-03 21:12:27 +02:00
Bastian Wagner
cab04c5869 feat: add buildCsv for cashbox export 2026-08-03 21:08:03 +02:00
Bastian Wagner
cf7c3efb0f fix: add null type guards to buildRows to prevent crashes on missing types 2026-08-03 21:02:52 +02:00
Bastian Wagner
a9df62a249 feat: add buildRows for cashbox export row filtering 2026-08-03 20:57:36 +02:00
Bastian Wagner
d8883d4687 chore: add pdfkit for cashbox PDF export 2026-08-03 20:51:48 +02:00
Bastian Wagner
15d5f1d4e4 docs: add implementation plan for cashbox export feature
Task-by-task TDD plan covering manual CSV/PDF export, the recurring
PDF-mailing subscription, and the frontend wiring, grounded in the
existing recurring-transactions module and mail service as precedent.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 20:46:42 +02:00
Bastian Wagner
b8bcf329c5 docs: add design spec for cashbox export + recurring PDF mailing
Covers on-demand CSV/PDF export of real cash-affecting transactions
and an optional per-team recurring PDF mailing to arbitrary email
addresses, following the same brainstorming process used for
recurring transactions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 20:35:19 +02:00
Bastian Wagner
9e55c0549b feat: add recurring transactions (Wiederkehrende Buchungen)
Lets treasurers/captains/coaches define recurring fee/levy dues that
are automatically booked for all active players on a monthly,
quarterly, or yearly schedule via a daily cron job, instead of having
to book them manually every cycle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 20:20:57 +02:00
Bastian Wagner
6531f2553f fix: wrap team creation in a transaction, add more-menu entry point, fix lint
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 17:27:23 +02:00
Bastian Wagner
b03198baa6 feat: wire create-team dialog into team-select 2026-08-03 16:19:05 +02:00
Bastian Wagner
bb6b045a2a feat: add CreateTeamDialog component 2026-08-03 16:04:31 +02:00
Bastian Wagner
a05ffd0c7f feat: add MyTeamsStore.refresh for forced reloads 2026-08-03 15:56:43 +02:00
Bastian Wagner
886e4e6941 feat: add TeamsApi.createTeam 2026-08-03 15:51:38 +02:00
Bastian Wagner
c1478f07f1 feat: make team creator a captain of the new team 2026-08-03 15:44:12 +02:00
Bastian Wagner
92eacbc5bb feat: allow any logged-in user to create a team 2026-08-03 15:38:43 +02:00
Bastian Wagner
09da67b8ef Fix Mobile Layout 2026-08-03 15:25:37 +02:00
Bastian Wagner
145ebb924a docs: add implementation plan for team creation via UI
Task-by-task plan covering the loosened create-team role guard,
auto-captain membership on creation, the new TeamsApi/MyTeamsStore
methods, the CreateTeamDialog component, and wiring it into
team-select.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 15:14:47 +02:00
Bastian Wagner
560fcfc11a docs: add design spec for team creation via UI
Brainstormed with the user: any logged-in user should be able to
self-service create a team and becomes its captain, via a dialog on
team-select. Team deletion/archiving is scoped out as a separate
follow-up feature.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 15:03:59 +02:00
Bastian Wagner
84bab04523 fix export type 2026-08-03 15:01:49 +02:00
Bastian Wagner
b21641f37a ag grid 2026-08-03 14:49:35 +02:00
Bastian Wagner
71d76725a4 euro symbol 2026-08-03 11:40:42 +02:00
Bastian Wagner
862a1bea8d Merge branch 'worktree-theoretischer-kassenstand' 2026-08-03 11:32:36 +02:00
Bastian Wagner
3cb8cd9a4a fix: strengthen deactivation-exclusion test and align sign rule with canonical logic
- teams.service.spec.ts: pick a checkpoint older than the adjustment's own
  month so the exclusion test actually fails without the exclusion filter
- teams.service.ts: only negate fine/levy/fee amounts when positive,
  matching TeamMembersService.recomputeBalance and Transaction.setBalance()
  exactly, instead of negating unconditionally
- teams.service.ts: outstanding-history helper now returns a positive
  value when players owe money, matching the house convention already
  established by getOverview()'s team.outstanding
- overview.spec.ts: assert the balance chart's legend becomes visible
- teams.service.spec.ts: add coverage for inactive-player exclusion and
  a positive-balance (prepaid credit) case

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 11:24:34 +02:00
Bastian Wagner
3d774a3455 overflow 2026-08-03 11:16:15 +02:00
Bastian Wagner
ebfaac7590 feat: show theoretical balance line in the cash-balance chart
Adds a second, dashed line to the existing balance-history chart that
includes currently open player dues, so managers can see at a glance
how far the actual cash balance lags behind what has been pledged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 11:05:11 +02:00
Bastian Wagner
d8f13d674d refactor: extract shared backward-reconstruction logic
Extract the month-by-month backward-walk algorithm (used for both
team-level cash balance and player-level debt history) into a single
shared private helper `reconstructBackward()`. This eliminates code
duplication while preserving behavior:

- Team-level balanceHistory: maps movements through signedFlowAmount(),
  rounds each point, calls the shared helper
- Player-level balance history: maps transactions using type.id rule,
  skips rounding (only rounds at final merge to avoid compounding
  errors), calls the shared helper

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 10:58:48 +02:00
Bastian Wagner
1b6ce57fbf feat: add theoretical balance history to team overview stats
Reconstructs each active player's balance per month (same backward
technique as the existing cash-balance history) so the overview stats
endpoint can report what the team balance would be if all currently
open dues had already been paid.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 10:44:22 +02:00