Files
TimeTracker/app/utils/invoice_pdf_postprocess.py
T
Dries Peeters 70510a6622 fix: quote create 500, line order, and Factur-X PDF parity
Quotes (#583):
- Add requires_approval, approval_level, and can_be_sent; wire create form
- Migrations 145 (approval columns) and 146 (quote_items.position)
- Order Quote.items by position; set positions on create/edit/duplicate/API
- Fix view template approval branch (not_required); add web regression test

Invoices / PEPPOL:
- Use the same Factur-X embed and PDF/A-3 normalization for export and
  email attachments; Associated File Data + text/xml metadata
- CII/UBL validators, pdfa3, zugferd, and invoice_pdf_postprocess helper
- Bundle compact sRGB ICC (app/resources/icc/); INVOICE_SRGB_ICC_PATH override
- Package data in setup.py; extend PEPPOL_EINVOICING.md and tests
2026-04-12 13:34:58 +02:00

44 lines
1.4 KiB
Python

"""
Shared Factur-X (ZUGFeRD) embed + PDF/A-3 post-processing for invoice PDFs.
Used by HTTP PDF export and email attachment generation so behavior matches.
"""
from __future__ import annotations
from typing import Any, Optional, Tuple
def postprocess_invoice_pdf_bytes(
pdf_bytes: bytes,
invoice: Any,
settings: Any,
) -> Tuple[bytes, Optional[str], Optional[str]]:
"""
Apply Factur-X CII embedding and optional PDF/A-3 normalization per settings.
Order: embed Factur-X XML first, then PDF/A-3 (metadata, ICC, optional Ghostscript).
Returns:
(pdf_bytes, embed_error, pdfa_error)
- If Factur-X is disabled: returns (pdf_bytes, None, None).
- On embed failure: returns (original pdf_bytes, error_message, None).
- On PDF/A failure after successful embed: returns (pdf after embed, None, error_message).
"""
if not getattr(settings, "invoices_zugferd_pdf", False):
return pdf_bytes, None, None
from app.utils.zugferd import embed_zugferd_xml_in_pdf
out_pdf, embed_err = embed_zugferd_xml_in_pdf(pdf_bytes, invoice, settings)
if embed_err:
return out_pdf, embed_err, None
if not getattr(settings, "invoices_pdfa3_compliant", False):
return out_pdf, None, None
from app.utils.pdfa3 import convert_to_pdfa3
out_pdf, pdfa_err = convert_to_pdfa3(out_pdf)
return out_pdf, None, pdfa_err