Task List Reports

Report Export Enhancements

Agent: complete tasks in order. Mark [x] when done. Each task is self-contained.


Task 1: Summary Statistics Block ⭐ Quick Win

Complexity: 2/5 | Files: 2

Add optional summary row showing sum/average/count for numeric columns.

Implementation

[MODIFY] report.py

  • In report_export(), compute aggregates for amount column from rows: python stats = { "sum": sum(r.get("amount", 0) for r in rows), "avg": sum(...) / len(rows) if rows else 0, "count": len(rows) }
  • Pass stats to template context

[MODIFY] export.html

  • Add toggle checkbox in #pdf-controls: "Show summary"
  • Add summary row below table in both CSV/PDF views: ```html
    Total: €{{ stats.sum|format_currency }}

```

Verification

  • [ ] Export CSV with 5+ rows, verify sum row appears
  • [ ] Toggle summary off, verify row hidden in export

Task 2: Date Range Auto-Label ⭐ Quick Win

Complexity: 2/5 | Files: 2

Auto-populate "Period: Jan 1 – Dec 31, 2025" from active filter state.

Implementation

[MODIFY] report.py

  • In report_export(), read filter state from session or query params
  • Extract date_from and date_to, format as human-readable string
  • Pass date_range_label to template

[MODIFY] export.html

  • Add editable input below subtitle in PDF header: html <input id="report-period" value="{{ date_range_label }}" placeholder="Period..." />
  • Include in PDF meta line

Verification

  • [ ] Apply date filter on /report, go to export, verify period auto-filled
  • [ ] Edit the period text, verify it exports with custom text

Task 3: Aggregate Total Row ⭐ Quick Win

Complexity: 1/5 | Files: 1

Show "Total: €X,XXX.XX" as final row in export table.

Implementation

[MODIFY] export.html

  • After {% endfor %} in tbody, add: ```html
    Total {{ stats.sum|format_currency }}

``` - Use JS to dynamically recalculate if cells are edited

[MODIFY] report-export.js

  • Add recalculateTotal() function triggered on cell blur
  • Update total row value

Verification

  • [ ] Export shows correct sum
  • [ ] Edit an amount cell, verify total updates

Task 4: Excel XLSX Export

Complexity: 3/5 | Files: 2

Add native Excel export with formatting (SheetJS library).

Implementation

[MODIFY] export.html

  • Add XLSX option to mode toggle: html <input type="radio" name="export-mode" value="xlsx" aria-label="Excel" />
  • Include SheetJS CDN: https://cdn.sheetjs.com/xlsx-0.20.0/package/dist/xlsx.full.min.js

[MODIFY] report-export.js

  • Add exportXlsx() function: javascript function exportXlsx() { const headers = getCsvHeaderInputs().map(i => i.value); const data = [headers, ...getRowsAsArrays()]; const ws = XLSX.utils.aoa_to_sheet(data); const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Report"); XLSX.writeFile(wb, getFilename() + ".xlsx"); }
  • Wire up to export button when mode is "xlsx"

Verification

  • [ ] Select XLSX mode, export, open in Excel
  • [ ] Verify headers and data match edited values

Task 5: Template Presets (Save/Load)

Complexity: 4/5 | Files: 3

Save column config, title patterns, theme as reusable preset.

Implementation

[NEW] Preset data model

  • Store in data/users/{uuid}/report_presets.json: json [ { "id": "tax-export", "name": "Tax Export", "columns": ["booking_date", "merchant", "amount", "cl_category"], "title": "Tax Deductions {{year}}", "theme": "blue" } ]

[MODIFY] report.py

  • Add endpoints:
  • GET /report/presets – list presets
  • POST /report/presets – save new preset
  • DELETE /report/presets/{id} – delete preset

[MODIFY] export.html

  • Add preset dropdown + save button in header controls
  • On select, apply preset values to inputs

Verification

  • [ ] Create preset "Tax Export", reload page, verify it appears in dropdown
  • [ ] Select preset, verify columns/title/theme applied
  • [ ] Delete preset, verify removed

Task 6: Custom Header Fields

Complexity: 2/5 | Files: 1

Add editable fields: Preparer, Client, Account Number.

Implementation

[MODIFY] export.html

  • Add fields after subtitle in #pdf-header: ```html

``` - Include these in PDF render (hide in CSV mode)

Verification

  • [ ] Fill custom fields, export PDF, verify visible
  • [ ] CSV export should NOT include these fields

Task 7: Category Pie Chart in PDF

Complexity: 4/5 | Files: 2

Embed a mini pie chart showing spend by category.

Implementation

[MODIFY] report.py

  • Compute category breakdown from selected rows: python breakdown = {} for row in rows: cat = row.get("cl_category", "Unknown") breakdown[cat] = breakdown.get(cat, 0) + abs(row.get("amount", 0))
  • Pass to template

[MODIFY] export.html

  • Add Chart.js CDN
  • Add canvas element in PDF preview (toggle-able)
  • Render doughnut chart from breakdown data
  • In exportPdf(), convert canvas to image before html2pdf

Verification

  • [ ] Select rows with multiple categories, verify chart renders
  • [ ] Export PDF, verify chart appears as image

Task 8: Logo Upload/Branding

Complexity: 3/5 | Files: 3

Allow user to upload logo for PDF header.

Implementation

[NEW] Logo storage

  • Store at data/users/{uuid}/logo.png
  • Max size: 200KB, resize on upload

[MODIFY] report.py

  • Add POST /report/logo – save uploaded logo
  • Add GET /report/logo – serve user's logo
  • Pass has_logo boolean to export template

[MODIFY] export.html

  • Add logo upload button in PDF controls
  • Display logo in PDF header if exists: html {% if has_logo %} <img src="/report/logo" class="h-12" /> {% endif %}

Verification

  • [ ] Upload logo, verify displayed in preview
  • [ ] Export PDF, verify logo appears
  • [ ] Remove logo, verify header returns to text-only

Task 9: Merchant Grouping

Complexity: 3/5 | Files: 2

Collapse transactions by merchant into summary rows.

Implementation

[MODIFY] report.py

  • Add query param ?group_by=merchant
  • Group rows and compute per-merchant totals: python grouped = {} for row in rows: m = row.get("merchant", "Unknown") if m not in grouped: grouped[m] = {"count": 0, "total": 0} grouped[m]["count"] += 1 grouped[m]["total"] += row.get("amount", 0)

[MODIFY] export.html

  • Add toggle: "Group by merchant"
  • When active, show grouped view with count + total columns

Verification

  • [ ] Enable grouping, verify merchants collapsed
  • [ ] Export CSV with grouped view

Task 10: Print-Optimized PDF

Complexity: 2/5 | Files: 2

Better page breaks, repeat headers on each page.

Implementation

[MODIFY] export-theme-blue.css

  • Add print media styles: css @media print { thead { display: table-header-group; } tr { page-break-inside: avoid; } }

[MODIFY] report-export.js

  • In exportPdf(), configure html2pdf options: javascript pagebreak: { mode: ['avoid-all', 'css', 'legacy'] }

Verification

  • [ ] Export 50+ row PDF, verify headers repeat
  • [ ] Verify no rows split across pages

Task 11: Custom Footer Rows (Sum + Free-Text)

Complexity: 3/5 | Files: 2

Allow users to add custom rows after the data table: auto-calculated sum row, and/or free-text annotation rows.

Use Cases

  • Sum row: "Total Expenses: €1,234.56"
  • Subtotals: Group by category with subtotal per group
  • Free-text: "All amounts exclude VAT" or "Approved by: _____"
  • Signature line: "Signature: ___ Date: _____"

Implementation

[MODIFY] export.html

  • Add "Add Row" button below PDF table with dropdown: ```html

```

  • Row templates: ```html
Total: €{{ stats.sum|format_currency }}
Signature: _________________ Date: __________

```

[MODIFY] report-export.js

  • Add addCustomRow(type) function: javascript function addCustomRow(type) { const container = document.getElementById('pdf-custom-rows'); const template = document.querySelector(`[data-row-template="${type}"]`); const clone = template.content.cloneNode(true); container.appendChild(clone); if (type === 'sum') recalculateSum(); }
  • Ensure custom rows are included in PDF render
  • Add drag-to-reorder capability (optional)

Behavior

Row Type Content Editable
Sum Auto-calculated from amount column Label only
Text Free-form input ✅ Full
Signature "Signature: ___ Date: ___" Label only

Verification

  • [ ] Add sum row, verify it shows correct total
  • [ ] Add text row, enter custom note, export PDF
  • [ ] Add multiple rows, verify order preserved in export
  • [ ] Remove a row, verify it disappears
  • [ ] Edit cell values, verify sum row updates

Priority Order

# Task Effort Impact Recommended
1 Summary Stats Low High ✅ First
3 Total Row Low High ✅ First
11 Custom Footer Rows Medium High ✅ First
2 Date Range Label Low Medium ✅ Second
4 Excel Export Medium High ✅ Second
10 Print-Optimized Low Medium ✅ Third
6 Custom Headers Low Medium Third
5 Template Presets Medium High Fourth
9 Merchant Grouping Medium Medium Later
7 Category Pie Medium Medium Later
8 Logo Upload Medium Medium Later