Expenses were stored as positive amounts (DB convention) and buildRows()
never negated them, so they were added to the running budget total
instead of subtracted. Negate expense amounts for team-wallet
transactions, mirroring the existing signedFlowAmount() convention in
teams.service.ts.
Separately, addFooters() placed footer text inside the reserved bottom
margin without an explicit height option, which made pdfkit's
LineWrapper treat every footer draw as overflowing the page and call
continueOnNewPage() twice per page - inflating page counts 3x with
blank trailing pages. Bounding the footer text to its own small height
box prevents pdfkit's automatic pagination from firing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The PDF export was an unformatted list of doc.text() lines and only
showed real cash movements (payment type). Rebuilds it as a proper
two-section report: a branded header band, a bordered/zebra-striped
table with colored amounts and bold running balance for cash
movements, and a second "Forderungen" section listing fine/levy/fee
entries created in the period with their own total. Tables paginate
across pages and every page gets a footer with page numbers.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
- 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.