feat(sprint9): Phase 2 — Financial report generators (EÜR, Kassenbuch, Beitragsbescheinigung)

Implements Sprint 9 Phase 2 financial report generators:

- MemberReportParameters: new parameter record for per-member reports
- EurReportGenerator: Einnahmen-Überschuss-Rechnung (§4(3) EStG)
  - PDF: professional layout with income/expense sections, monthly breakdown
  - CSV: semicolon-delimited, ISO-8859-1, German decimal format
  - JSON: ELSTER-compatible structure for Steuerberater import
- KassenbuchExportGenerator: GoBD-compliant cash book export
  - PDF: landscape A4, running balance, sequential Beleg-Nr
  - CSV: GoBD-compliant format with injection prevention
  - Includes opening balance calculation and period totals
- BeitragsbescheinigungGenerator: membership fee confirmation per member
  - PDF: club letterhead, payment table, signature lines
  - For member tax purposes (Sonderausgaben)
- ReportGeneratorService: added getAvailableTypes() method
- ReportController: added GET /api/v1/reports/types endpoint

All generators are @Service beans auto-discovered by ReportGeneratorService.
Docker build verified green.
This commit is contained in:
Patrick Plate
2026-06-15 12:22:53 +02:00
parent 26a77dd269
commit a29c38756c
6 changed files with 1155 additions and 2 deletions
@@ -5,9 +5,12 @@ import de.cannamanage.api.dto.report.MonthlyReportResponse;
import de.cannamanage.api.dto.report.RecallReportResponse;
import de.cannamanage.domain.entity.Club;
import de.cannamanage.domain.entity.TenantContext;
import de.cannamanage.domain.enums.ExportFormat;
import de.cannamanage.domain.enums.MemberStatus;
import de.cannamanage.domain.enums.ReportType;
import de.cannamanage.service.CsvReportGenerator;
import de.cannamanage.service.PdfReportGenerator;
import de.cannamanage.service.ReportGeneratorService;
import de.cannamanage.service.ReportService;
import de.cannamanage.service.model.report.MemberListReport;
import de.cannamanage.service.model.report.MonthlyReport;
@@ -20,7 +23,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.time.YearMonth;
import java.util.UUID;
import java.util.*;
/**
* REST controller for compliance and operational reports.
@@ -34,15 +37,41 @@ public class ReportController {
private final PdfReportGenerator pdfGenerator;
private final CsvReportGenerator csvGenerator;
private final ClubRepository clubRepository;
private final ReportGeneratorService reportGeneratorService;
public ReportController(ReportService reportService,
PdfReportGenerator pdfGenerator,
CsvReportGenerator csvGenerator,
ClubRepository clubRepository) {
ClubRepository clubRepository,
ReportGeneratorService reportGeneratorService) {
this.reportService = reportService;
this.pdfGenerator = pdfGenerator;
this.csvGenerator = csvGenerator;
this.clubRepository = clubRepository;
this.reportGeneratorService = reportGeneratorService;
}
/**
* List all available report types with their supported export formats.
* GET /api/v1/reports/types
*/
@GetMapping("/types")
@PreAuthorize("hasRole('ADMIN') or @staffPermissions.has(#root, T(de.cannamanage.domain.enums.StaffPermission).VIEW_COMPLIANCE_REPORT)")
public ResponseEntity<List<Map<String, Object>>> listReportTypes() {
Map<ReportType, Set<ExportFormat>> availableTypes = reportGeneratorService.getAvailableTypes();
List<Map<String, Object>> response = new ArrayList<>();
for (var entry : availableTypes.entrySet()) {
Map<String, Object> typeInfo = new LinkedHashMap<>();
typeInfo.put("type", entry.getKey().name());
typeInfo.put("formats", entry.getValue().stream()
.map(ExportFormat::name)
.sorted()
.toList());
response.add(typeInfo);
}
return ResponseEntity.ok(response);
}
/**