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.

This article shows how to use the MailMerge TX Text Control .NET Server for ASP.NET
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.
class to merge invoice data into a template and how to embed the generated ZUGFeRD XML to the final PDF document.

ZUGFeRD-csharp

In this sample, we utilize the GitHub project ZUGFeRD-csharp that is also available as a NuGet package.

ZUGFeRD-csharp GitHub repository

ZUGFeRD-csharp NuGet package

The Template

The following screenshot shows a very simple invoice template with fields according to the following Order data structure. You can see the merge fields for the Buyer and the merge block highlighted in red to repeat the LineItems.

Invoice template

The Data Source

The class Order contains all data required for an invoice generation process including address data for the buyer, the seller and the sold line items. Some properties such as LineTotalAmount and TaxTotalAmount are calculated automatically based on the added line items.

public class Order {
public int Id { get; set; }
public DateTime OrderDate { get; set; }
public ContractParty Buyer { get; set; }
public ContractParty Seller { get; set; }
public Decimal Allowance { get; set; }
public Decimal Vat { get; set; } = 6.5M;
public List<LineItem> LineItems { get; set; } = new List<LineItem>();
public Decimal LineTotalAmount {
get {
return this.LineItems.Sum(item => item.GrossPrice * item.Quantity);
}
}
public Decimal TaxTotalAmount {
get {
return (this.LineTotalAmount / 100) * this.Vat;
}
}
public Decimal GrandTotalAmount {
get {
return this.LineTotalAmount + this.TaxTotalAmount;
}
}
public class LineItem {
public string Name { get; set; }
public string Description { get; set; }
public QuantityCodes QuantityCode { get; set; } = QuantityCodes.H87;
public int Quantity { get; set; }
public decimal GrossPrice { get; set; }
}
public class Seller : ContractParty { }
public class Buyer : ContractParty { }
public class ContractParty {
public int Id { get; set; }
public string Name { get; set; }
public string PostalCode { get; set; }
public string City { get; set; }
public string Address { get; set; }
public CountryCodes CountryCodes { get; set; }
public ContractPartyContact BuyerContact { get; set; }
}
public class ContractPartyContact {
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
view raw test.cs hosted with ❤ by GitHub

Additionally, the class Order contains a property that generates the required ZUGFeRD XML. The property get method is basically matching the data source to the required properties of the InvoiceDescriptor that generates the XML.

public byte[] ZugferdXML {
get {
var invoice = InvoiceDescriptor.CreateInvoice(this.Id.ToString(),
this.OrderDate, CurrencyCodes.USD);
invoice.SetBuyer(this.Buyer.Name,
this.Buyer.PostalCode,
this.Buyer.City,
this.Buyer.Address,
this.Buyer.CountryCodes,
this.Buyer.Id.ToString());
invoice.SetSeller(this.Seller.Name,
this.Seller.PostalCode,
this.Seller.City,
this.Seller.Address,
this.Seller.CountryCodes,
this.Seller.Id.ToString());
invoice.SetSellerContact($"{this.Seller.BuyerContact.FirstName} {this.Seller.BuyerContact.LastName}");
foreach (LineItem lineItem in this.LineItems) {
invoice.AddTradeLineItem(lineItem.Name, lineItem.Description, lineItem.QuantityCode, lineItem.Quantity, lineItem.GrossPrice, lineItem.GrossPrice, lineItem.Quantity);
}
invoice.LineTotalAmount = LineTotalAmount;
invoice.ChargeTotalAmount = invoice.LineTotalAmount;
invoice.AllowanceTotalAmount = Allowance;
invoice.TaxBasisAmount = invoice.ChargeTotalAmount;
invoice.TaxTotalAmount = TaxTotalAmount;
invoice.GrandTotalAmount = GrandTotalAmount;
MemoryStream ms = new MemoryStream();
invoice.Save(ms, ZUGFeRDVersion.Version1, Profile.Basic);
return ms.ToArray();
}
}
view raw test.cs hosted with ❤ by GitHub

Creating the Invoice

The static method Create of the Invoice class is doing the actual merging work and embeds the generated XML into the created PDF. The method uses the MailMerge TX Text Control .NET Server for ASP.NET
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.
class to merge the data into the template and embeds the ZUGFeRD XML into a PDF/A-3b document.

public static class Invoice {
public static byte[] Create(Order order) {
TXTextControl.SaveSettings saveSettings = new TXTextControl.SaveSettings();
var metaData = System.IO.File.ReadAllText("metadata.xml");
// create a new embedded file
var zugferdInvoice = new TXTextControl.EmbeddedFile(
"ZUGFeRD-invoice.xml",
order.ZugferdXML,
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[] { zugferdInvoice };
byte[] document;
using (TXTextControl.ServerTextControl tx = new ServerTextControl()) {
tx.Create();
tx.Load("template.tx", StreamType.InternalUnicodeFormat);
using (MailMerge mailMerge = new MailMerge()) {
mailMerge.TextComponent = tx;
mailMerge.MergeObject(order);
}
// export the PDF
tx.Save(out document, TXTextControl.BinaryStreamType.AdobePDFA, saveSettings);
return document;
}
}
}
view raw test.cs hosted with ❤ by GitHub

The Sample

The console application creates a new Order and calls the above Invoice.Create method and writes the created PDF document to a file.

using s2industries.ZUGFeRD;
using TXTextControl.DocumentServer.PDF.Zugferd;
Console.WriteLine("Creating ZUGFeRD Invoice...");
Order order = new Order() {
Buyer = new ContractParty() {
Address = "123 Street Dr.",
CountryCodes = CountryCodes.US,
BuyerContact = new ContractPartyContact() {
FirstName = "Jack",
LastName = "Sparrow"
},
City = "Charlotte",
Id = 123,
Name = "Company, LLC",
PostalCode = "NC 28209"
},
Seller = new ContractParty() {
Address = "333 Ave Dr.",
CountryCodes = CountryCodes.US,
BuyerContact = new ContractPartyContact() {
FirstName = "Peter",
LastName = "Jackson"
},
City = "Charlotte",
Id = 123,
Name = "Microogle, LLC",
PostalCode = "NC 28210"
},
Id = 1,
OrderDate = DateTime.Now,
Allowance = 0,
Vat = 6.5M,
LineItems = new List<LineItem> {
new LineItem() {
Name = "Product A",
Description = "Description A",
Quantity = 5,
QuantityCode = QuantityCodes.H87,
GrossPrice = 432.00M
},
new LineItem() {
Name = "Product B",
Description = "Description B",
Quantity = 2,
QuantityCode = QuantityCodes.H87,
GrossPrice = 5232.00M
},
}
};
File.WriteAllBytes("result.pdf", Invoice.Create(order));
Console.WriteLine("ZUGFeRD Invoice created successfully!");
view raw test.cs hosted with ❤ by GitHub

After opening the PDF in Acrobat Reader, you can see the created visual representation and the embedded XML in the Attachments pane.

Invoice PDF

When loading this document into a ZUGFeRD validator (ZF/FX Validation), the results show a valid ZUGFeRD PDF.

Invoice PDF

You can download the sample from our GitHub repository to test this on your own.