Repository navigation
PDFCLOUD-6571 Add ZUGFeRD PDF creation - #57
datalogics-tsmith wants to merge 9 commits into
Conversation
✅ Deploy Preview for pdfrest-python ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
- Add typed rendering options for invoice appearance and localization. - Validate uploaded resources, color channels, fonts, and regeneration. - Serialize the public input shape into the pdfRest wire contract. Assisted-by: Codex
- Add synchronous and asynchronous helpers for uploaded invoice XML. - Support optional PDFs, logos, rendering controls, and request options. - Cover serialization, validation, response mapping, and both transports. Assisted-by: Codex
- Exercise every closed rendering option through both client transports. - Verify regenerated PDFs, response metadata, and server-side rejection. - Add a deterministic minimum-profile invoice fixture. Assisted-by: Codex
- Add a standalone typed example with a deterministic invoice fixture. - Verify the generated PDF and print useful response metadata. - Link the helper from the API guide and example inventories. Assisted-by: Codex
10508bb to
7d951b6
Compare
There was a problem hiding this comment.
Requesting changes on 7d951b6291e4dad1395286f1ea5b20bfa2833f89. Please split XML generation from supplied-PDF conversion before publishing the API. Two helpers are preferred:
convert_invoice_xml_to_zugferd_pdf(invoice, ...)convert_pdf_to_zugferd_pdf(pdf, *, invoice, allow_regeneration=False, ...)
The supplied-PDF helper should reject logo/render options when regeneration permission is disabled, and explain that those options apply only if replacement actually occurs. A three-helper alternative with preservation-only conversion plus convert_pdf_to_zugferd_pdf_allowing_regeneration is acceptable. The existing naming/design thread now records the complete proposal, shared request/payload requirements, and the still-open convention discussion. This is the requested design direction; the guidelines' coherent-contract exception supports combining preservation and permitted replacement in the required-PDF helper.
The other findings are covered without duplicate threads:
- Null-language exception and accepted aliases: the existing language-validation thread now includes the reproduced sync/async
label_language=NoneAttributeError, the required validation-error behavior, and the previously reported alias/canonicalization fix. - Unit validation/MIME/boundary coverage: the existing coverage thread now specifies the missing paired resource guards, supported MIME variants, optional serialization, response assertions and request counts.
- Live contract coverage: that same coverage thread now includes isolated options, invalid catalogs/bounds, observable font/render assertions, preservation, mismatch rejection and permitted replacement. Existing positive live literals pass; successful conversion alone does not establish every rendering behavior.
- Prefer built-in string constraints: one new, lower-priority cleanup thread requests constrained internal string aliases and small semantic validators, including the verified Pydantic union-ordering caveat. Existing color/resource adaptation remains appropriate custom logic.
The earlier required minor-version bump and shared published-font catalog comments remain applicable and were left unchanged. Apply the final API consistently to both transports, examples, tests and documentation. Preserve compatibility for any names already released.
Validation during this review on the unchanged HEAD: the non-live Nox matrix passed on Python 3.10–3.14 with 3,231 passes and 10 expected skips per interpreter; all 12 focused ZUGFeRD live tests passed on Python 3.11; the new example passed on Python 3.10; all four client-class function gates passed across the five interpreters. Read-only Ruff formatting, changed-file Ruff lint, basedpyright, strict docs and diff whitespace checks passed. Public MockTransport probes reproduced the null-language exception through both clients. Repository-wide Ruff encounters 39 errors in an existing untracked local notebook outside this PR.
The full service-wide live suite, full local example matrix and mutating local pre-commit hooks were not repeated; the new live module/example and relevant read-only checks were exercised, and recorded PR CI on this HEAD is successful for the full test/example matrices, live job and pre-commit. This update edits the existing changes-requested review and relevant threads rather than submitting another overlapping review. No source files were edited.
- Separate XML rendering from supplied-PDF preservation and require explicit permission for replacement-only options. - Canonicalize supported label-language aliases and share the readable font catalog across conversion APIs. - Cover sync and async serialization, validation, response handling, and request customization. Assisted-by: Codex
- Exercise every closed render-option value through sync and async clients. - Verify visual preservation, observable rendering changes, mismatch rejection, and explicitly permitted replacement. - Send invalid option boundaries to the service and assert response metadata and warnings. Assisted-by: Codex
- Rename the XML generation example: create_zugferd_pdf/ -> convert_invoice_xml_to_zugferd_pdf/ - Add a supplied-PDF example that makes regeneration permission explicit. - Explain preservation and replacement behavior in the API guidance. Assisted-by: Codex
- Record the new public ZUGFeRD conversion helpers as a minor release. - Keep the locked editable package metadata synchronized. Assisted-by: Codex
|
Reopening immediately to trigger GitHub Actions for the updated head commit; the review fixes are pushed and all review threads are resolved. |
- Incorporate the Apache-2.0 licensing and contributor documentation from the 1.4.1 release preparation. - Retain version 1.5.0 for the new public conversion workflows and keep lock metadata synchronized. Assisted-by: Codex
PDFCLOUD-6571
Why this change
The Python SDK does not expose pdfRest's ZUGFeRD PDF operation, so callers cannot use the typed clients to turn CII invoice XML into a validated ZUGFeRD or Factur-X PDF/A-3 invoice or safely combine that XML with an existing visual PDF. This adds both workflows to the synchronous and asynchronous clients while making the replacement risk explicit.
What changed (high level)
The public API is split by caller intent.
convert_invoice_xml_to_zugferd_pdfalways renders a PDF from uploaded CII XML and accepts appearance controls.convert_pdf_to_zugferd_pdfstarts from an uploaded PDF, preserves it by default, and requiresallow_regeneration=Truebefore replacement-only logo or rendering options are accepted.Dedicated Pydantic payload models own resource validation and wire serialization. ZUGFeRD label languages use constrained strings plus canonicalization for English, German, and French aliases, and the structured-document and ZUGFeRD APIs now share one readable-font catalog while retaining their existing public aliases.
The package version advances to 1.5.0. Runnable examples and API guidance cover each workflow separately.
Behavior changes
Callers choose XML rendering or supplied-PDF preservation before making the request, so invalid option combinations are rejected locally instead of being exposed through one mode-dependent signature. The supplied-PDF workflow rejects logo and rendering controls unless regeneration is explicitly permitted. If regeneration is not permitted and visual consistency cannot be confirmed, the service error is surfaced.
Supported two-letter, three-letter, and regional label-language forms are canonicalized to
en,de, orfr; explicitNone, unsupported languages, malformed tags, unsupported symbol fonts, invalid MIME types, multiple single-resource inputs, malformed colors, and unsafe output prefixes fail as Pydantic validation errors before transport.These changes replace the provisional
create_zugferd_pdfhelper introduced only within this unmerged PR; no released SDK API is removed.Validation
The complete non-live suite passed on Python 3.10 through 3.14 with 3,308 tests passed, 10 expected skips, and 96% overall coverage on each interpreter. The client class-function coverage gate passed at its 90% threshold.
The endpoint-specific live suite exercised all closed render-option values, server-side invalid boundaries, visual rendering changes, matching-PDF preservation, mismatch rejection, explicitly permitted replacement, response metadata, and warnings through both sync and async clients. All 56 live cases were verified across the full run and focused correction rerun. Both standalone examples completed against the live service.
Ruff formatting and linting, basedpyright, the complete pre-commit suite, strict MkDocs build, and wheel/sdist build all passed. Pre-commit and package build were rerun after merging current
main. The full repository-wide live suite was not run; live validation was scoped to this endpoint.Risks and follow-ups
The former #55 stack dependency is resolved and the branch includes current
main. Font availability remains deployment-specific; published names are discoverable suggestions while installed text-capable font names remain accepted. Main-repository CI provides the final clean-environment verification.