The ZUGFeRD / Factur-X standard is a hybrid electronic invoice format that consists of two parts:
-
A PDF visual, human-readable representation of the invoice.
-
An XML file that contains invoice data in a structured form that can be processed automatically.
TX Text Control X19 supports the embedding of attachments in PDF/A-3b documents and also the extraction of an attachment. This sample shows 3 steps of the creation process using TX Text Control:
- Creating the required ZUGFeRD XML.
- Creating the visual representation.
- Export both to a valid PDF/A-3b document.
Embedding Existing XML
In case, you already have a valid XML representation created by a third-party tool or an ERP system, you can easily embed this XML to a PDF document using the Save ╰ TX Text Control .NET for Windows Forms
╰ TXTextControl Namespace
╰ ServerTextControl Class
╰ Save Method
Saves the complete contents of a document with the specified format. method by specifying an Embedded
╰ TXTextControl Namespace
╰ EmbeddedFile Class
The EmbeddedFile class represents a file embedded in another document. in the SaveSettings.
string xmlZugferd = ""; // your XML | |
string metaData = ""; // required RDF meta data | |
TXTextControl.SaveSettings saveSettings = new TXTextControl.SaveSettings(); | |
// create a new embedded file | |
var zugferdInvoice = new TXTextControl.EmbeddedFile( | |
"ZUGFeRD-invoice.xml", | |
Encoding.UTF8.GetBytes(xmlZugferd), | |
metaData); | |
zugferdInvoice.Description = "ZUGFeRD-invoice"; | |
zugferdInvoice.Relationship = "Alternative"; | |
zugferdInvoice.MIMEType = "application/xml"; | |
zugferdInvoice.LastModificationDate = DateTime.Now; | |
// set the embedded files | |
saveSettings.EmbeddedFiles = new TXTextControl.EmbeddedFile[] { | |
new TXTextControl.EmbeddedFile( | |
"ZUGFeRD-invoice.xml", | |
Encoding.UTF8.GetBytes(xmlZugferd), | |
metadata) }; | |
// export the PDF | |
textControl1.Save("test.pdf", TXTextControl.StreamType.AdobePDFA, saveSettings); |
Create ZUGFeRD XML
For demo purposes, we implemented the helper class TXTextControl.DocumentServer.PDF.Zugferd.Invoice that creates a valid ZUGFeRD XML. The method CreateSampleInvoice returns the required XML that is embedded into the created PDF document.
private Invoice CreateSampleInvoice() { | |
// new zugferd invoice | |
Invoice invoice = new Invoice("A12345", DateTime.Now, CurrencyCode.USD); | |
invoice.Type = InvoiceType.Invoice; | |
invoice.Profile = Profile.Comfort; | |
// buyer | |
invoice.Buyer = new TradeParty { | |
ID = "TX_1", | |
Name = "Text Control GmbH", | |
ContactName = "Peter Paulsen", | |
City = "Bremen", | |
Postcode = "28217", | |
Country = CountryCode.DE, | |
Street = "Überseetor 18" | |
}; | |
// seller | |
invoice.Seller = new TradeParty { | |
ID = "TX_2", | |
Name = "Text Control, LLC", | |
ContactName = "Jack Jackson", | |
City = "Charlotte, NC", | |
Postcode = "28210", | |
Country = CountryCode.US, | |
Street = "6926 Shannon Willow Rd, Suite 400", | |
}; | |
// add tax id's | |
invoice.Seller.SpecifiedTaxRegistrations.Add( | |
new TaxID() { ID = "US12367623", Scheme = TaxScheme.VA }); | |
// add products | |
List<LineItem> lineItems = new List<LineItem>(); | |
lineItems.Add(new LineItem() { | |
Price = 200, | |
ProductID = "A123", | |
Name = "Product A", | |
Quantity = 5, | |
Total = 1000, | |
UnitCode = QuantityCodes.C62 | |
}); | |
// add line items to invoice | |
foreach (LineItem item in lineItems) | |
invoice.LineItems.Add(item); | |
// set the total amount | |
invoice.TotalAmount = 1000; | |
return invoice; | |
} |
In the sample application, a very simple template is used to create the visual representation of the invoice:
The following code loads the template into a TextControl and uses Mail
╰ DocumentServer Namespace
╰ MailMerge Class
The MailMerge class is a .NET component that can be used to effortlessly merge template documents with database content in .NET projects, such as ASP.NET web applications, web services or Windows services. to merge the sample data into the document. The CreateXml method of the Invoice class returns the valid ZUGFeRD XML. Together with the required meta data, the XML is embedded and exported to a valid PDF/A-3b document.
TXTextControl.DocumentServer.MailMerge mm = new TXTextControl.DocumentServer.MailMerge(); | |
mm.TextComponent = textControl1; | |
textControl1.Load("invoice.tx", TXTextControl.StreamType.InternalUnicodeFormat); | |
Invoice invoice = CreateSampleInvoice(); | |
// merge data into template | |
mm.MergeJsonData(JsonConvert.SerializeObject(invoice)); | |
// create the XML | |
string xmlZugferd = invoice.CreateXml(); | |
// get the required meta data | |
string metaData = MetaData.GetMetaData(); | |
TXTextControl.SaveSettings saveSettings = new TXTextControl.SaveSettings(); | |
// create a new embedded file | |
var zugferdInvoice = new TXTextControl.EmbeddedFile( | |
"ZUGFeRD-invoice.xml", | |
Encoding.UTF8.GetBytes(xmlZugferd), | |
metaData); | |
zugferdInvoice.Description = "ZUGFeRD-invoice"; | |
zugferdInvoice.Relationship = "Alternative"; | |
zugferdInvoice.MIMEType = "application/xml"; | |
zugferdInvoice.LastModificationDate = DateTime.Now; | |
// set the embedded files | |
saveSettings.EmbeddedFiles = new TXTextControl.EmbeddedFile[] { | |
new TXTextControl.EmbeddedFile( | |
"ZUGFeRD-invoice.xml", | |
Encoding.UTF8.GetBytes(xmlZugferd), | |
metaData) }; | |
// export the PDF | |
textControl1.Save("test.pdf", TXTextControl.StreamType.AdobePDFA, saveSettings); |
The ZUGFeRD XML
The XML document that is embedded in the PDF is listed below:
<?xml version="1.0" encoding="utf-8"?> | |
<rsm:CrossIndustryInvoice xmlns:a="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:10" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"> | |
<rsm:ExchangedDocumentContext> | |
<ram:GuidelineSpecifiedDocumentContextParameter> | |
<ram:ID>urn:cen.eu:en16931:2017#compliant#urn:zugferd.de:2p0:comfort</ram:ID> | |
</ram:GuidelineSpecifiedDocumentContextParameter> | |
</rsm:ExchangedDocumentContext> | |
<rsm:ExchangedDocument> | |
<ram:ID>A12345</ram:ID> | |
<ram:TypeCode>380</ram:TypeCode> | |
<ram:IssueDateTime> | |
<udt:DateTimeString format="102">20210203</udt:DateTimeString> | |
</ram:IssueDateTime> | |
</rsm:ExchangedDocument> | |
<rsm:SupplyChainTradeTransaction> | |
<ram:IncludedSupplyChainTradeLineItem> | |
<ram:AssociatedDocumentLineDocument> | |
<ram:LineID>1</ram:LineID> | |
</ram:AssociatedDocumentLineDocument> | |
<ram:SpecifiedTradeProduct> | |
<ram:Name>Product A</ram:Name> | |
</ram:SpecifiedTradeProduct> | |
<ram:SpecifiedLineTradeAgreement> | |
<ram:NetPriceProductTradePrice> | |
<ram:ChargeAmount>200</ram:ChargeAmount> | |
</ram:NetPriceProductTradePrice> | |
</ram:SpecifiedLineTradeAgreement> | |
<ram:SpecifiedLineTradeDelivery> | |
<ram:BilledQuantity unitCode="C62">5</ram:BilledQuantity> | |
</ram:SpecifiedLineTradeDelivery> | |
<ram:SpecifiedLineTradeSettlement> | |
<ram:ApplicableTradeTax> | |
<ram:TypeCode>VAT</ram:TypeCode> | |
<ram:CategoryCode>S</ram:CategoryCode> | |
<ram:RateApplicablePercent>19</ram:RateApplicablePercent> | |
</ram:ApplicableTradeTax> | |
<ram:SpecifiedTradeSettlementLineMonetarySummation> | |
<ram:LineTotalAmount>1000.00</ram:LineTotalAmount> | |
</ram:SpecifiedTradeSettlementLineMonetarySummation> | |
</ram:SpecifiedLineTradeSettlement> | |
</ram:IncludedSupplyChainTradeLineItem> | |
<ram:ApplicableHeaderTradeAgreement> | |
<ram:SellerTradeParty> | |
<ram:Name>Text Control, LLC</ram:Name> | |
<ram:PostalTradeAddress> | |
<ram:PostcodeCode>28210</ram:PostcodeCode> | |
<ram:LineOne>Jack Jackson</ram:LineOne> | |
<ram:LineTwo>6926 Shannon Willow Rd, Suite 400</ram:LineTwo> | |
<ram:CityName>Charlotte, NC</ram:CityName> | |
<ram:CountryID>US</ram:CountryID> | |
</ram:PostalTradeAddress> | |
<ram:SpecifiedTaxRegistration> | |
<ram:ID schemeID="VA">US12367623</ram:ID> | |
</ram:SpecifiedTaxRegistration> | |
</ram:SellerTradeParty> | |
<ram:BuyerTradeParty> | |
<ram:Name>Text Control GmbH</ram:Name> | |
<ram:PostalTradeAddress> | |
<ram:PostcodeCode>28217</ram:PostcodeCode> | |
<ram:LineOne>Peter Paulsen</ram:LineOne> | |
<ram:LineTwo>Überseetor 18</ram:LineTwo> | |
<ram:CityName>Bremen</ram:CityName> | |
<ram:CountryID>DE</ram:CountryID> | |
</ram:PostalTradeAddress> | |
</ram:BuyerTradeParty> | |
</ram:ApplicableHeaderTradeAgreement> | |
<ram:ApplicableHeaderTradeDelivery> | |
<ram:ActualDeliverySupplyChainEvent> | |
<ram:OccurrenceDateTime> | |
<udt:DateTimeString format="102">20210203</udt:DateTimeString> | |
</ram:OccurrenceDateTime> | |
</ram:ActualDeliverySupplyChainEvent> | |
</ram:ApplicableHeaderTradeDelivery> | |
<ram:ApplicableHeaderTradeSettlement> | |
<ram:InvoiceCurrencyCode>USD</ram:InvoiceCurrencyCode> | |
<ram:ApplicableTradeTax> | |
<ram:CalculatedAmount>190.00</ram:CalculatedAmount> | |
<ram:TypeCode>VAT</ram:TypeCode> | |
<ram:BasisAmount>1000.00</ram:BasisAmount> | |
<ram:CategoryCode>S</ram:CategoryCode> | |
<ram:RateApplicablePercent>19</ram:RateApplicablePercent> | |
</ram:ApplicableTradeTax> | |
<ram:SpecifiedTradePaymentTerms> | |
<ram:DueDateDateTime> | |
<udt:DateTimeString format="102">20210305</udt:DateTimeString> | |
</ram:DueDateDateTime> | |
</ram:SpecifiedTradePaymentTerms> | |
<ram:SpecifiedTradeSettlementHeaderMonetarySummation> | |
<ram:LineTotalAmount>1000.00</ram:LineTotalAmount> | |
<ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount> | |
<ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount> | |
<ram:TaxBasisTotalAmount>1000.00</ram:TaxBasisTotalAmount> | |
<ram:TaxTotalAmount currencyID="USD">190.00</ram:TaxTotalAmount> | |
<ram:GrandTotalAmount>1190.00</ram:GrandTotalAmount> | |
<ram:DuePayableAmount>1190.00</ram:DuePayableAmount> | |
</ram:SpecifiedTradeSettlementHeaderMonetarySummation> | |
</ram:ApplicableHeaderTradeSettlement> | |
</rsm:SupplyChainTradeTransaction> | |
</rsm:CrossIndustryInvoice> |
In Acrobat Reader
When the resulting PDF document is opened in Acrobat Reader, you can check the PDF/A-3b conformance using the Standards tab:
Additionally, you can verify the attachments:
Validating the Conformance
After validating the ZUGFeRD document using validation services such as the ZF/FX Validation (https://www.zugferd-community.net/de/dashboard/validation), you can see that the created document passes all tests:
You can download the sample project from our GitHub repository that contains the ZUGFeRD helper classes to create a valid XML document from scratch.