feat(reports): DATEV-Monatsblatt-Export (Blanko-Vorlage) für Steuerberater
Neuer PDF-Export GET /reports/datev-monthly/export: ein Blatt pro Mitarbeiter/Monat im Layout der DATEV-Stundenaufzeichnungs-Vorlage (Beginn/Pause/Ende/Dauer + K/U/UU/F/SA/SU-Kürzel + Bemerkungen + Summe + Unterschriftsfelder). Führt time_entries, Absences und Feiertage pro Kalendertag zusammen. Außerdem: Mustervorlagen für neue Backend-Module (Model/Schema/Router/ Migration/Test) und eine Frontend-Page-Vorlage, abgeleitet vom hours_payouts-Modul als aktuellstem sauberen Muster. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CviFgc739S89xS97pvjszj
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
from datetime import date, timedelta
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from fastapi.responses import Response
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
@@ -152,6 +152,28 @@ async def export_time_report(
|
||||
headers={"Content-Disposition": f"attachment; filename={filename}.csv"})
|
||||
|
||||
|
||||
@router.get("/reports/datev-monthly/export")
|
||||
async def export_datev_monthly(
|
||||
current_user: CurrentUser,
|
||||
user_id: UUID,
|
||||
year: int = Query(..., ge=2000, le=2100),
|
||||
month: int = Query(..., ge=1, le=12),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""DATEV-Monatsblatt (Blanko-Layout) als PDF für Steuerberater-Übergabe.
|
||||
EMPLOYEE darf nur den eigenen Monat exportieren."""
|
||||
if current_user.role not in _manager_roles and user_id != current_user.id:
|
||||
raise HTTPException(403, "Nur eigenes Monatsblatt exportierbar")
|
||||
|
||||
sheet = await report_service.datev_monthly_report(
|
||||
current_user.company_id, user_id, year, month, db
|
||||
)
|
||||
content = report_service.datev_monthly_report_to_pdf(sheet)
|
||||
filename = f"datev_stundenaufzeichnung_{sheet.user_name.replace(' ', '_')}_{year}_{month:02d}.pdf"
|
||||
return Response(content=content, media_type="application/pdf",
|
||||
headers={"Content-Disposition": f"attachment; filename={filename}"})
|
||||
|
||||
|
||||
@router.get("/reports/absences/export")
|
||||
async def export_absence_report(
|
||||
current_user: CurrentUser,
|
||||
|
||||
Reference in New Issue
Block a user