ZUGFeRD Documentation

The ZUGFeRD Format

ZUGFeRD is a standard developed by FeRD (Forum for Electronic Invoicing in Germany) to standardize the process of creating and sharing electronic invoices. A XML format is used to enable the electronic invoice checks. This XML is generated via the ZUGFeRD API from PDFreactor. The integrator itself does not have to deal with the XML.

ZUGFeRD Profile

PDFreactor supports two out of the three profiles specified by FeRD which can be used to generate the ZUGFeRD PDF in the profiles basic and comfort. The profile extended is currently not supported. Profile determines which ZUGFeRD-properties can be generated into the ZUGFeRD PDF and which cannot. Without a profile the ZUGFeRD PDF cannot be created and the conversion will terminate with an appropriate error message.

If for example the profile is basic, properties which require the profile comfort, even if specified, will not be generated. However if the profile would be comfort, properties which only require basic will be generated, if specified. There are also properties which are always required in order to create a ZUGFeRD PDF. These properties all require the profile basic, and have to be specified in your JavaScript using the API. Furthermore with a higher profile, there won't be any new required properties. Hence it is possible to generate a ZUGFeRD PDF with the profile comfort while only specifying properties which are used in basic.

Profile Description
basic The lowest ZUGFeRD profile. Allows to set all required information. Does not allow full support for electronic checks.
comfort Higher level than basic. Allows to set more specific information, especially in terms of positions. Allows support for electronic checks to a certain degree.

PDF and XML

A ZUGFeRD PDF consists of two parts, the PDF and the XML. Everything that is visible in the PDF can be generated into the XML. Though it is not prevented programmatically, the ZUGFeRD specification states that only information that is visible or can be derived from the PDF is allowed to be generated into the XML. The last case could be the country, which is a 2-character long code. This means, if a ZUGFeRD-property is required to generate the ZUGFeRD XML and cannot be specified from the PDF, the PDF as well as the XML are invalid. There are of course some exceptions where the required information may not be specified in the PDF. This could be the zugferd-profile or the test-indicator.

The Requirements

To generate a ZUGFeRD PDF, there are some requirements that have to be met.

PDF/A3 Conformance Level

For ZUGFeRD, the PDF/A standard has to be used, which enables long term archivability. The PDF standard must also allow the attachment of the ZUGFeRD XML, which limits the options to PDF/A-3a, PDF/A-3b, PDF/A-3u and PDF/A-3a with the PDF/UA-1 specification.

JavaScript processing

To create the ZUGFeRD PDF from the PDF, the JavaScript has to be specified in either the document or the PDFreactor API. For PDFreactor to be able to process the JavaScript, the JavaScriptProcessing has to be enabled.

The following example specifies all requirements for PDFreactor to create a ZUGFeRD PDF with either the Java library or the Java wrapper:

// Create a configuration object Configuration config = new Configuration(); // Specifying the conformance config.setConformance(Conformance.PDFA3A); // Enable JavaScript config.setJavaScriptMode(JavaScriptMode.ENABLED); // Defining the JavaScript via file URL Resource zugferd = new Resource(); zugferd.setUri("file:///path/to/your/zugferd.js"); config.setUserScripts(zugferd);

ZUGFeRD Validation

PDFreactor does not validate prices and totals which have been specified via the ZUGFeRD API. When using the API, PDFreactor assumes that all positions, taxes and totals have been calculated correctly. If they were not, the document itself would not be valid. However some properties are validated. For the most part this includes properties which have to be specified as ZUGFeRD code like the document-type or the country code. This also includes codes which have been set via the options object. There are also special cases which have to be validated to ensure that the resulting ZUGFeRD PDF is correct, like the elements Gross- and NetPrice.

The Two Types of Elements

Before using the API the two types of elements have to be known. Unique and repeating elements, which follow a tree data structure.

Unique Elements

Unique elements are leaf elements directly connected to the root. This elements will only be set once via the API, but are the most important elements. In fact it is possible to create a ZUGFeRD PDF without any repeating elements. These are elements like currency to set the currency used in the document or document-type which describes the type of the document, like invoice, with ZUGFeRD codes.

Repeating Elements

While repeating elements are not required to create the ZUGFeRD PDF, they add more information to it. Depending on your PDF these elements will be set once or multiple times. Repeating elements itself are not directly connected to the root, instead they branch off the root into leaves. An example for repeating elements are positions. These branch off with the path item and the leaves holding the information of the position, like the product name (item.name) or the quantity (item.billed-quantity) for the position.

It is also possible that a repeating element branches off from another repeating element. These are called nested repeating elements. When using a ZUGFeRD-property the structure will be self-explanatory. There are also some restrictions on what leaves have to be specified. When specifying a position, the most important information is the product name (item.name) and thus has to be specified. Otherwise the element will not be generated. All other information should be specified if possible but are not a requirement.

Using ZUGFeRD-properties

To specify which value has to be passed to which element, ZUGFeRD-properties have to be used. These ZUGFeRD-properties can be fragmented into paths and properties. While most documents will not require the use of fragments, they will be useful if they are used correctly.

Fragments

A ZUGFeRD-property is made from fragments. These fragments define the tree data structure, by splitting at the "." of the ZUGFeRD-property.

// Fragmenting a ZUGFeRD-property "zugferd-profile" = "zugferd-profile" "item.name" = "item", "name" "item.tax.type" = "item", "tax", "type"

If a ZUGFeRD-property, like "zugferd-profile", does not contain a "." it is automatically a property.

Path Fragment

Paths are all fragments except the last fragment. The path is used to specify one or multiple repeating elements. The reason for this is, that a repeating element itself cannot have a value. Only the leaf elements of a repeating element can hold values. So when using a path the tree data structure will be specified.

// Path "item" ro.zugferd.get("item", 0);

If a ZUGFeRD-property contains more than one "." it means that there is a repeating element inside a repeating element. This also means that there are two paths fragments. It is not possible to specify these as a single path. Instead the first path retrieves a repeating element from the ro.zugferd object, and the second path retrieves the repeating elements from the retrieved element.

// Path "item.tax" var item = ro.zugferd.get("item", 0); item.get("tax", 0);

Because unique elements only occur once, they do not have a path.

Property Fragment

The last fragment or the ZUGFeRD-property itself, if the ZUGFeRD-property does not contain a ".", is the property. This fragment defines the leaf element to which the specified or retrieved value will be applied.

// Unique Elements ro.zugferd.set("zugferd-profile", "basic"); // Repeating elements ro.zugferd.get("item", 0).set("name", "Sample Product"); // Nested repeating elements ro.zugferd.get("item", 0).get("tax", 0).set("type", "VAT");

When to Use Fragments?

Most of the time the use of fragments is unnecessary. A ZUGFeRD PDF can be generated from a complex document without ever having to fragment a ZUGFeRD-property. Fragments are only required if a value has to be passed to a specific repeating element. Whenever the get method is called from the "ro.zugferd" object with the first fragment, to retrieve a repeating element every other method which is called on this repeating element has to be the next fragment of the ZUGFeRD-property. Let's examine the following HTML snippet for example:

<table> <thead> <tr> <th>Product</th> <th>Price</th> </tr> <thead> <tbody> <tr class="item"> <td>Position 1</td> <td>50.00</td> </tr> <tr class="item"> <td>Position 2</td> <td>4.99</td> </tr> </tbody> </table>

This table can be converted into a ZUGFeRD PDF by using fragments, but it can also be avoided:

// Without fragments // Setting the product names ro.zugferd.setFromSelectorAll("item.name", ".item td:nth-child(0)"); // Setting the product prices ro.zugferd.setFromSelectorAll("item.line-total", ".item td:nth-child(1)", { inputFormat: "." } ); // With fragments, assuming that there were at least two items specified already // Retrieving all elements with the path "item" var items = ro.zugferd.get("item"); // Iterating over the items array for (var i = 0; i < items.length; i++) { // Setting the product names items[i].setFromSelector("name", ".item:nth-child(" + i + ") td:nth-child(0)"); // Setting the product prices items[i].setFromSelector("line-total", ".item:nth-child(" + i + ") td:nth-child(1)", { inputFormat: "." } ); }

As seen above, both ways are possible but using fragments adds an extra layer of complexity. Consequently, fragments should only be used if the case requires them.

Special Cases

While the API should be as easy to use as possible, some elements and properties require more attention than others. This is either due to the ZUGFeRD specification or how they were implemented in PDFreactor.

VAT and Tax Id

While the ZUGFeRD specification does allow an unlimited amount of tax registrations, PDFreactor limits this information to two ZUGFeRD-properties per involved party. To specify this information for the selling party for example, the properties seller-vatid and seller-taxid are used.

Gross- and NetPrice Elements

Gross- and NetPrice are two elements, which are always generated if at least one of them is specified with the ZUGFeRD-properties item.gross-price-amount or item.net-price-amount. As long as the ZUGFeRD-property item.gross-price-allowance-charge.amount has not been specified to define an allowance or charge, Gross and NetPrice are the same and no special attention has to be given. If item.gross-price-allowance-charge.amount has been specified however, the net price is not allowed to be equal to the gross price and the ZUGFeRD PDF will not be generated. An appropriate exception will be thrown.

Referenced Documents

When referencing a document, like a previously sent invoice which now has to be canceled, the options object is still required to specify the current date format. However, the output format is fixed to yyyy-MM-dd'T'00:00:00 and thus has not to be specified via the options object property scheme.

document-type

To specify the document type by ZUGFeRD code, the property document-type has to be used. While the document does not have to be a commercial invoice, with the ZUGFeRD profile basic only the ZUGFeRD code 380 is allowed. Other document types may require more information than it is possible to specify with a basic profile.

charge-total and allowance-total

These two ZUGFeRD-properties are required per ZUGFeRD specification to generate the ZUGFeRD PDF. While they are required, PDFreactor will set this properties automatically with the value 0.00. This is because, these two properties may not be able to be set from the PDF. However if they are specified in the PDF these two properties should be set to ensure that the ZUGFeRD PDF is valid.

item.global-id-type

When using the ZUGFeRD-property item.global-id, it is not possible to specify the organization in which this product is registered via the options object property scheme. This is due to the fact that different products can be registered by different organizations and setting them via the API in bulk can lead to undesirable results. To specify the organization by ZUGFeRD code, the ZUGFeRD-property item.global-id-type is used instead.

mandate-reference-id

When specifying the ZUGFeRD-property mandate-reference it is possible to specify an id for this mandate. This mandate-reference-id is given by the mandate itself and has to be used. The ZUGFeRD-property mandate-reference-id is not required to generate the mandate-reference.

API Methods

ro.zugferd

To interact with the ZUGFeRD API, the ro.zugferd object has to be used. With this object it is possible to configure certain values, set default values for repeating elements and to define the input and output formats, as well as setting unique and repeating elements and retrieving repeating elements.

addMapping(key, value, options?)

Mappings can be used to set the specified value instead of the value passed to a method. This is especially useful if a human readable value was retrieved from the document, but it has to be passed as a ZUGFeRD code. Please note that the key is case sensitive and does not ignore spaces. To disable the mapping use the options object property ignoreMapping when calling a method. An errorHandler can be appended via the options object.

ro.zugferd.addMapping("Invoice", "380"); ro.zugferd.addMapping("Piece", "C62"); ro.zugferd.addMapping("England", "GB"); ro.zugferd.addMapping("USA", "US");

set(zugferdProperty, value, options?)

Sets the specified value as content for the specified ZUGFeRD-property. The value can be modified using the options object.

ro.zugferd.set("zugferd-profile", "basic");

setFromSelector(zugferdProperty, selector, options?)

Retrieves the text content of an element matching the given selector and sets it as value for the specified ZUGFeRD-property. The content of the ZUGFeRD-element can be modified using the options object.

ro.zugferd.setFromSelector("grand-total", "#grandTotal", { inputFormat: "." });

setFromSelectorAll(zugferdProperty, selector, options?)

Retrieves the text content of each element matching the given selector and sets it as value of the specified ZUGFeRD-property. If no matching elements are found, this process will create new elements. This method is not allowed for ZUGFeRD-properties with multiple paths fragments. Use the setFromSelectorAll method with the selector array for these ZUGFeRD-properties instead. The content of the ZUGFeRD-element can be modified using the options object.

ro.zugferd.setFromSelectorAll("item.name", ".items .ProductName");

setFromSelectorAll(zugferdProperty, selector[], options?)

When using this method it is possible to define each fragment with its own selector. If more selectors than fragments have been specified, the method call will be interrupted. If the selector defines a path fragment, new repeating elements with this path fragment will be created. The number of newly created repeating elements depends on how many elements have been found via the selector and how many elements already exist. It is possible to select direct child elements only, by using the ">" selector after the first selector in the array. The content of the ZUGFeRD-element can be modified using the options object.

// Non-nested elements ro.zugferd.setFromSelectorAll("item.name", [".items", ".ProductName"] ); // Nested elements // ".tax" contains the value. ro.zugferd.setFromSelectorAll("item.tax.percent", [".items", ".tax"] ); // ".percent" contains the value. ro.zugferd.setFromSelectorAll("item.tax.percent", [".items", ".tax", ".percent"] ); // > Selector ro.zugferd.setFromSelectorAll("item.tax.percent", [".items", "> tr:nth-child(2)"] );

get(pathFragment, index, options?)

Returns the repeating element with the specified path at the specified index. If no repeating element with the specified path exists, the element itself as well as all previous elements will be created. An errorHandler can be appended using the options object.

ro.zugferd.get("item", 3);

get(pathFragment, options?)

Returns an array containing all repeating elements matching the given path. If there are no repeating elements matching the specified path, an error of errorType 5000 will be passed to the errorHandler. An errorHandler can be appended using the options object. While the returned array is not live, values which have been set will still be applied.

ro.zugferd.get("item");

Elements

Elements are the repeating elements retrieved via the ro.zugferd get methods.

set(propertyFragment, value, options?)

Sets the given value as content of the specified ZUGFeRD-property. Because the repeating Element is known, only the last fragment of the ZUGFeRD-property has to be specified. The value can be modified using the options object.

// Sets the product name // Single element ro.zugferd.get("item", 3).set("name", "Sample Product"); // Multiple elements ro.zugferd.get("item").forEach( function (param) { param.set("name", "Muster Produkt"); });

setFromSelector(propertyFragment, selector, options?)

Sets the text content of an element matching the given selector as value of the specified ZUGFeRD-property. Because the repeating element is known, only the property fragment has to be specified. The content of the ZUGFeRD-element can be modified using the options object.

// Sets the product name // Single element ro.zugferd.get("item", 3).setFromSelector("name", "#specificItemName"); // Multiple elements var items = ro.zugferd.get("item"); for (var i = 0; i < items.length; i++) { items[i].setFromSelector("name", ".items:nth-child(" + (i + 1) + ") .ProductName"); }

get(pathFragment, index, options?)

When called on a repeating element, this method returns the repeating element within this element, matching the specified path fragment at the specified index. If no repeating element with the specified path fragment exists, the elements and all previous elements will be created. An errorHandler can be appended using the options object.

var item = ro.zugferd.get("item", 3); item.get("tax", 3);

get(pathFragment, options?)

When called on a repeating element, this method returns an array containing all repeating elements within the element, with the specified path fragment. If there are no repeating elements with the specified path an error with the errorType 5000 will be logged from the errorHandler. An errorHandler can be appended using the options object. While the returned array is not live, values which have been set will still be applied.

var item = ro.zugferd.get("item", 3); item.get("tax");

The "options" Object

The "options" object can be passed to a method to modify a text and to specify required information. If the ZUGFeRD-property type is Date or Number this object is required, unless the information has already been specified via the default object properties inputFormat and scheme. If information of the same property has been specified in both the options and the default object, only the options object's information will be considered.

inputFormat

The inputFormat has to be specified for ZUGFeRD-properties of the type Date and Number. For ZUGFeRD-properties of the type Date, the Date's source format has to be described as a Java pattern. If the ZUGFeRD-property is of the type Number, the decimal mark has to be specified. The inputFormat is used and processed in these two cases only. The default value for ZUGFeRD-properties of the type Number is ","

// Date ro.zugferd.set("buyer-order-reference-issue-date", "26.05.2017", { inputFormat: "dd.MM.yyyy" } ); // Number ro.zugferd.set("line-total", "12,550.85", { inputFormat: "." } );

scheme

To specify the output format of a ZUGFeRD-property of the type Date, the property scheme is needed. The format is specified by a ZUGFeRD code. Attention: Referenced documents use the type Date, but do not need an output format. Another use for scheme is for Global IDs. All codes can be found in the property list under each type. The property scheme is only used and processed in these two cases. The default Value for ZUGFeRD-properties of the type Date is 102

// Date ro.zugferd.set("document-issue-date", "26.05.2017", { inputFormat: "dd.MM.yyyy", scheme: "102" } ); // Global ID ro.zugferd.set("seller-global-id", "4000001123452", { scheme: "0088" } );

startDelimiter

The property startDelimiter allows to extract a text starting from the first occurrence of the delimiter, to the end of the text. If both startDelimiter and endDelimiter are specified, the text between the two specified delimiters is extracted.

ro.zugferd.set("seller-city", "66435 Frankfurt/M", { startDelimiter: " " }); // Result: "Frankfurt/M"

endDelimiter

The property endDelimiter allows to extract a text from the start to the last occurrence of the specified delimiter. If both startDelimiter and endDelimiter are specified, the text between the two specified delimiters is extracted.

ro.zugferd.set("seller-postcode", "66435 Frankfurt/M", { endDelimiter: " " }); // Result: "66435"

splitDelimiter

With the property splitDelimiter a text can be split at the specified delimiter. The property splitIndex can then be used to select the desired part.

splitIndex

After splitting the text with the property splitDelimiter, the desired part can be selected with the property splitIndex. If no splitDelimiter has been specified, nothing can be retrieved. The first part has the index 0.

ro.zugferd.set("zugferd-profile", "The ZUGFeRD profile is basic", { splitDelimiter: " ", splitIndex: 4 }); // Result // "basic"

processor

The property processor allows to pass your own function to a method. This enables the use of conditions for further text manipulation. It is also possible to redefine the properties inputFormat and scheme. The following read-only properties can be called as parameter:

Name Type Description
rawText String Returns the unprocessed text.
text String Returns the processed text.
propertyName String Returns the name of the property with which the method has been called.
element Element Returns the element retrieved by the selector.
content String Returns the text content of the element, including the generated before and after text.
contentBefore String Returns the generated before text content of the element.
contentAfter String Returns the generated after text content of the element.
contentText String Returns the text content of the element.
// Does not require an inputFormat, because tax.category is not of type "Number". ro.zugferd.set("tax.category", "19.00", { processor: function (param) { if (param.text == "19.00" || param.text == "7.00") { return "S"; // Default rate } } }); // Setting the decimal mark ro.zugferd.set("tax.percent", "19.00", { processor: function (param) { if (param.text.indexOf(".") !== -1) { param.inputFormat = "."; } else { param.inputFormat = ","; } } });

ignoreMapping

If mapping should be disabled for a ZUGFeRD-property use the property ignoreMapping.

// Mapping from "Invoice" to the ZUGFeRD Code "380". ro.zugferd.addMapping("Invoice", "380"); // Name of the document should be "Invoice" ro.zugferd.set("document-name", "Invoice", { ignoreMapping: true }); // Type of the document should be "380". ro.zugferd.set("document-type", "Invoice");

errorHandler

With the property errorHandler it is possible to identify and analyze possible error cases. It is also possible to retrieve information regarding the current processing step. The following information can be retrieved:

Name Type Description
methodName String Name of the method.
propertyName String The name of the ZUGFeRD-property or the key if the called method was addMapping.
value String The value which was passed to the method set or addMapping.
selectors String or [String] In case of setFromSelector, the specified selector or the selector array in case of setFromSelectorAll.
options Object The options object that was passed to the method.
message String The message of the current log.
errorType Number The type of the warning or error. There is no errorType for info. More information about the types can be found here.
level String The log level. The following levels are possible:
  • info: Information regarding newly created ZUGFeRD-elements.
  • warning: Warnings do not end the conversion. Information regarding the cause can be retrieved via the property message.
  • error: Errors do not end the conversion, but may end the JavaScript processing or lead to an invalid ZUGFeRD PDF. Information regarding the cause can be retrieved via the property message.
matchCount [Number] On level info the property matchCount contains an array of numbers, indicating how often a selector did find an element.
ro.zugferd.set("document-issue-date", "2017-06-06", { errorHandler: function (param) { if (param.level == "error") { console.log(param.level); console.log(param.errorType); console.log(param.message); } } });

Note: If no errorHandler has been specifiedvia the options or default object, it is not possible to retrieve any information regarding the ZUGFeRD processing. Possible errors cannot be analyzed.

The "default" Object

The default object is used to specify the properties inputFormat and scheme on a global level. Their values will be used if properties that are required by the current ZUGFeRD type, have not been specified via the options object. It is also possible to set default values for repeating elements.

inputFormat

With the property inputFormat it is possible to set default values for the ZUGFeRD-properties Date and Number.

Name Description
dateFormat Specifies a Java date format pattern.
decimalMark Specifies a decimal mark to process ZUGFeRD-properties of the type Number. The default value is ",".

scheme

The property scheme allows to set default values for the ZUGFeRD-properties Date and Global ID.

Name Description
dateFormat Specifies a ZUGFeRD Code as output format for a date. The code list can be found in the property list for the type Date. The default value is 102.
globalId Defines the organization the Global ID is registered with. An excerpt of possible codes can be found in the property list for the type Global ID. Because different products can be registered in different organizations, this property will not be processed for the ZUGFeRD-property item.global-id. Use the property item.global-id-type to specify the organization instead.

propertyValues

To set default values for repeating elements, the property propertyValues is used. The syntax is as follows:

propertyValues: { "propertyName": "Value", "propertyName": "Value" };

errorHandler

The property errorHandler is used in the same way as the options object. If an errorHandler is specified as default, it will be called for each method call, as long as no errorHandler is defined as an argument when calling the method.

A possible use case would be:

ro.zugferd.defaults = { inputFormat: { dateFormat: "dd-MM-yyyy", decimalMark: "." }, scheme: { globalId: "0088", dateFormat: "102" }, propertyValues: { "tax.type": "VAT", "item.tax.type": "VAT" } errorHandler: function (param) { if (param.level == "error") { console.log(param.level); console.log(param.errorType); console.log(param.message); } } };

ErrorTypes

In case of a warning or error the problem is summarized by the following types. A more detailed description can be retrieved from the message property of the errorHandler.

Type Description
1000 API usage error
2000 The value or text content of an element could not be processed with the specified options object.
3000 The value or text content of an element is invalid or invalid for the specified ZUGFeRD-property.
4000 The value or text content could not be parsed. This only occurs if the ZUGFeRD-property is either of the type Date or Number.
5000 Error while trying to access a repeating element via get or if no element could be found with the specified selectors.