Initial support for e-invoices: German ZUGFeRD v2.x and French Factur-X#1705
Open
andreiaugustin wants to merge 1 commit intofoliojs:masterfrom
Open
Initial support for e-invoices: German ZUGFeRD v2.x and French Factur-X#1705andreiaugustin wants to merge 1 commit intofoliojs:masterfrom
andreiaugustin wants to merge 1 commit intofoliojs:masterfrom
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
In the last few years, a handful of European countries have started adopting legislations encouraging businesses to adopt electronic invoicing practices, going as far as being a mandatory requirement for some public establishments. Furthermore, the United States Treasury estimated that implementing e-invoicing across the entire federal government would reduce costs by 50%.
Various standards exists - global, national, regional and proprietary. However, none of them prevail and most of them are not interoperable with one another. Source.
In my personal experience, we have great demand for the German
ZUGFeRDand the FrenchFactur-Xstandards (which in the latest versions, are very, very similar).PDFKit is already in an excellent position to produce compliant PDFs with the aforementioned European, national, e-invoice standards since it already supports XMP metadata, file embedding and PDF/A-3, which is the PDF subset these standard are built upon.
With this feature, I am hoping we can introduce a high-level API to make it easier to create ZUGFeRD and Factur-X e-invoice PDFs and have a good structure for extending support to other e-invoice standards in the future.
Feature
What kind of change does this PR introduce?
This PR introduces a structure for e-invoice mixins and initial support for ZUGFeRD v2.X and Factur-X through a new API:
Both formats are implemented separately behind a common entry point. Although nearly identical, keeping them independent at least initially would allow us to easily diverge if their specs starts differing in the near future as the EU may attempt establishing a bloc-wide standard?
The possible values for
formatare: 'zugferd' or 'facturx' at the moment.The
srcparameter can be aBuffer,ArrayBufferorstringas it is directly passed down to thedoc.file().The
optionsare optional as most internal logic is defaulted for what I understand to be best practices at the time of writing.Both formats accept similar
options:profile,version(overrides) anddocumentType(defaults to 'INVOICE'). These mostly change what is pasted into the XMP metadata: the embedded XML file has varying profiles e.g. minimum, basic, extended, en 16931 etc. and these define what and how the information is structured in the XML file. Validators require the profile in the PDF's metadata.I have been using the following service to verify the ZUGFeRD compliance.
I would love to get some feedback and thoughts, especially on the API naming?
Also, very important to note the refactoring of
PDFMetadatais the most significant change outside the new feature. It now has separate concerns where_bodyaccumulates metadata blocks as they are appended andend()assembles the complete XML in one shot with all registered namespace interpolated into therdf:RDFopening tag. Its existing interface is unchanged, but very important to note is_metadatais now only populated afterend()- before that, it is an empty string rather than a partial document like before. As far as I can tell at first glance, nothing seems to callgetXML()orgetLength()beforeend(), but it's worth a second pair of eyes just in case.Another thing to note is the guard against PDF/A-3 subset relies on
initPDFA()normalising the subset string to an integer (PDF/A-3b,PDF/A-3aandPDF/A-3all become3). This isn't a documented contract anywhere, it just happens to be how it works today and if that normalisation ever changes, the guard would silently break.Finally, worth mentioning: the
metadata.registerNamespace(prefix, uri)and its mixin counterpartregisterXMPNamespacewere added to support thexmlns:fxnamespace requirement, but they are no restricted to e-invoice, so they can be used in the future if anybody else wishes to inject a namespace ontordf:RDF.I am leaving the 'ready to be merged' option unchecked for now as I am working on a couple examples we could add for this, especially since we have the xml files we use in the unit tests, it would be quite cool.
Checklist: