From eb5e14e2a1376094f91dbd8666ebb0c9e9cd9d85 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 18 Mar 2026 07:14:28 +0100 Subject: [PATCH] release: v2.2.56 email layout + supplier invoice stabilization --- RELEASE_NOTES_v2.2.56.md | 22 ++++++++ app/billing/backend/supplier_invoices.py | 58 ++++++++++++++++++++- app/billing/frontend/supplier_invoices.html | 43 +++++++++------ app/emails/frontend/emails.html | 52 +++++++++++++++++- 4 files changed, 157 insertions(+), 18 deletions(-) create mode 100644 RELEASE_NOTES_v2.2.56.md diff --git a/RELEASE_NOTES_v2.2.56.md b/RELEASE_NOTES_v2.2.56.md new file mode 100644 index 0000000..7394c1d --- /dev/null +++ b/RELEASE_NOTES_v2.2.56.md @@ -0,0 +1,22 @@ +# Release Notes v2.2.56 + +Dato: 2026-03-18 + +## Fokus +Stabilisering af email-visning og hardening af supplier-invoices flows. + +## Aendringer +- Rettet layout-overflow i email-detaljevisning, saa lange emner, afsenderadresser, HTML-indhold og filnavne ikke skubber kolonnerne ud af layoutet. +- Tilfoejet robust wrapping/truncering i emails UI for bedre responsiv opfoersel. +- Tilfoejet manglende "Klar til Bogforing" tab i supplier-invoices navigation. +- Rettet endpoint mismatch for AI template-analyse i supplier-invoices frontend. +- Fjernet JS-funktionskonflikter i supplier-invoices ved at adskille single/bulk send flows. +- Tilfoejet backend endpoint til at markere supplier-invoices som betalt. +- Fjernet route-konflikt for send-to-economic ved at flytte legacy placeholder til separat sti. +- Forbedret approve-flow ved at bruge dynamisk brugeropslag i stedet for hardcoded vaerdi. + +## Berorte filer +- app/emails/frontend/emails.html +- app/billing/frontend/supplier_invoices.html +- app/billing/backend/supplier_invoices.py +- RELEASE_NOTES_v2.2.56.md diff --git a/app/billing/backend/supplier_invoices.py b/app/billing/backend/supplier_invoices.py index 2eed551..f92ef92 100644 --- a/app/billing/backend/supplier_invoices.py +++ b/app/billing/backend/supplier_invoices.py @@ -1703,6 +1703,10 @@ async def delete_supplier_invoice(invoice_id: int): class ApproveRequest(BaseModel): approved_by: str + +class MarkPaidRequest(BaseModel): + paid_date: Optional[date] = None + @router.post("/supplier-invoices/{invoice_id}/approve") async def approve_supplier_invoice(invoice_id: int, request: ApproveRequest): """Approve supplier invoice for payment""" @@ -1735,6 +1739,58 @@ async def approve_supplier_invoice(invoice_id: int, request: ApproveRequest): raise HTTPException(status_code=500, detail=str(e)) +@router.post("/supplier-invoices/{invoice_id}/mark-paid") +async def mark_supplier_invoice_paid(invoice_id: int, request: MarkPaidRequest): + """Mark supplier invoice as paid.""" + try: + invoice = execute_query_single( + "SELECT id, invoice_number, status FROM supplier_invoices WHERE id = %s", + (invoice_id,) + ) + + if not invoice: + raise HTTPException(status_code=404, detail=f"Faktura {invoice_id} ikke fundet") + + if invoice['status'] == 'paid': + return {"success": True, "invoice_id": invoice_id, "status": "paid"} + + if invoice['status'] not in ('approved', 'sent_to_economic'): + raise HTTPException( + status_code=400, + detail=( + f"Faktura har status '{invoice['status']}' - " + "kun 'approved' eller 'sent_to_economic' kan markeres som betalt" + ) + ) + + execute_update( + """UPDATE supplier_invoices + SET status = 'paid', updated_at = CURRENT_TIMESTAMP + WHERE id = %s""", + (invoice_id,) + ) + + logger.info( + "✅ Marked supplier invoice %s (ID: %s) as paid (date: %s)", + invoice['invoice_number'], + invoice_id, + request.paid_date, + ) + + return { + "success": True, + "invoice_id": invoice_id, + "status": "paid", + "paid_date": request.paid_date, + } + + except HTTPException: + raise + except Exception as e: + logger.error(f"❌ Failed to mark invoice {invoice_id} as paid: {e}") + raise HTTPException(status_code=500, detail=str(e)) + + @router.post("/supplier-invoices/{invoice_id}/send-to-economic") async def send_to_economic(invoice_id: int): """ @@ -2204,7 +2260,7 @@ async def upload_supplier_invoice(file: UploadFile = File(...)): -@router.post("/supplier-invoices/{invoice_id}/send-to-economic") +@router.post("/supplier-invoices/{invoice_id}/send-to-economic-legacy-unimplemented") async def send_invoice_to_economic(invoice_id: int): """Send supplier invoice to e-conomic - requires separate implementation""" raise HTTPException(status_code=501, detail="e-conomic integration kommer senere") diff --git a/app/billing/frontend/supplier_invoices.html b/app/billing/frontend/supplier_invoices.html index 5337a71..a5e09f3 100644 --- a/app/billing/frontend/supplier_invoices.html +++ b/app/billing/frontend/supplier_invoices.html @@ -173,6 +173,11 @@ Til Betaling +