Creating Valid XRechnung / ZUGFeRD Invoices with ASP.NET Core C#
This article shows how to create valid XRechnung and ZUGFeRD invoices with ASP.NET Core C#. The invoice is created with the help MailMerge component and the ZUGFeRD-csharp library.

Particularly in Europe, electronic invoice formats are becoming increasingly popular as they are required by law under certain conditions. There are two main types: XRechnung and ZUGFeRD or Factur-X, which are identical.
XRechnung or ZUGFeRD?
XRechnung is a pure XML format designed to be used for processing digital invoices. ZUGFeRD combines the human-readable PDF format with a machine-readable XML format. Since the release of ZUGFeRD version 2.1, both the resulting XML from XRechnung as well as the way in which the XML is integrated into a PDF file can be combined.
TX Text Control provides you with the tools you need to create the PDF/A-3b file with the embedded XML. This example uses the popular ZUGFeRD-csharp library, which is available on GitHub and NuGet.
PDF/A-3b
ZUGFeRD-csharp can be used to generate valid XML documents for all of the profiles, including the XRechnung profile. This generated XML is then embedded into a generated PDF document along with the necessary metadata describing the embedded document, which is required to produce a true PDF/A-3b document.
Sample Implementation
The sample application implements the XRechnung class, which holds all the data needed to create the invoice and also uses the ZUGFeRD-csharp library to generate the necessary XML.
The following code shows how to create a new XRechnung object using sample data.
XRechnung xRechnung = new XRechnung()
{
InvoiceNumber = "471102",
InvoiceDate = new DateTime(2013, 6, 5),
Currency = CurrencyCodes.EUR,
OrderNumber = "AB-312",
DeliveryDate = new DateTime(2013, 6, 3),
PaymentTerms = "Zahlbar innerhalb 30 Tagen netto bis 04.07.2023",
PaymentDueDate = new DateTime(2023, 07, 04),
Seller = new Seller()
{
Name = "Lieferant GmbH",
Street = "Lieferantenstraße",
ZipCode = "80333",
City = "München",
VATID = "DE123456789",
TaxRegistrationSchemeID = TaxRegistrationSchemeID.VA,
Contact = "Max Mustermann",
Phone = "+4942142706710",
Email = "max@mustermann.de"
},
Buyer = new Buyer()
{
Name = "Kunden Mitte AG",
Street = "Kundenstraße",
ZipCode = "69876",
City = "Frankfurt",
VATID = "DE234567890",
TaxRegistrationSchemeID = TaxRegistrationSchemeID.VA,
Contact = "Hans Muster",
OrganizationUnit = "Einkauf",
Email = "hans@muster.de",
Phone = "22342424",
OrderReferenceDocument = "2013-471102",
OrderReferenceDocumentDate = new DateTime(2013, 5, 5)
},
LineItems = new List<LineItem>()
{
new LineItem()
{
Name = "Item name",
Description = "Detail description",
Quantity = 1,
Unit = QuantityCodes.H87,
UnitPrice = 10m,
TaxCategory = TaxCategoryCodes.S,
TaxType = TaxTypes.VAT,
TaxPercent = 19
}
}
};
The CreateXML method is then called to generate the XML, which is then used in an Embedded
string xmlZugferd = xRechnung.CreateXML();
// load Xml file
string metaData = File.ReadAllText("metadata.xml");
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[] { zugferdInvoice };
Finally, to generate the human-readable version of the invoice, a template is merged with the XRechnung object.
using (TXTextControl.ServerTextControl tx = new TXTextControl.ServerTextControl())
{
tx.Create();
// load the document
tx.Load("template.tx", TXTextControl.StreamType.InternalUnicodeFormat);
// merge the data
using (MailMerge mm = new MailMerge())
{
mm.TextComponent = tx;
mm.MergeObject(xRechnung);
}
// save the document
tx.Save("test.pdf", TXTextControl.StreamType.AdobePDFA, saveSettings);
}
When you open this created PDF document in Adobe Acrobat Reader, you will be able to see the visual representation and the embedded XML in the Attachments pane.
You can prove the validity of the generated invoice by uploading it to any ZUGFeRD validation service.
The implementation of the XRechnung class implicitly performs the necessary calculations, including taxes, based on the line items created.
using s2industries.ZUGFeRD;
namespace InvoiceGenerator
{
public class XRechnung
{
public string InvoiceNumber { get; set; } = Guid.NewGuid().ToString();
public DateTime InvoiceDate { get; set; } = DateTime.Now;
public CurrencyCodes Currency { get; set; } = CurrencyCodes.EUR;
public string OrderNumber { get; set; }
public DateTime DeliveryDate { get; set; }
public string PaymentTerms { get; set; } = "Zahlbar innerhalb 30 Tagen netto bis 04.07.2023";
public DateTime PaymentDueDate { get; set; } = DateTime.Now.AddDays(30);
public Seller Seller { get; set; }
public Buyer Buyer { get; set; }
public List<LineItem> LineItems { get; set; }
public decimal TotalNetAmount
{
get
{
return LineItems.Sum(x => x.LineTotal);
}
set
{
TotalNetAmount = value;
}
}
public decimal TotalTaxAmount
{
get
{
return LineItems.Sum(x => x.TaxAmount);
}
set
{
TotalTaxAmount = value;
}
}
public decimal TotalGrossAmount
{
get
{
return LineItems.Sum(x => x.Total);
}
set
{
TotalGrossAmount = value;
}
}
public decimal TotalAllowanceChargeAmount { get; set; } = 0;
public decimal TotalChargeAmount { get; set; } = 0;
public decimal TotalPrepaidAmount { get; set; } = 0;
public decimal TotalRoundingAmount { get; set; } = 0;
public decimal TotalDueAmount {
get
{
return TotalGrossAmount - TotalPrepaidAmount + TotalTaxAmount;
}
}
// create XML from XRechnung object with s2industries.ZUGFeRD
public string CreateXML()
{
InvoiceDescriptor desc = InvoiceDescriptor.CreateInvoice(this.InvoiceNumber, this.InvoiceDate, this.Currency);
desc.ReferenceOrderNo = this.OrderNumber;
desc.SetBuyer(this.Buyer.Name, this.Buyer.ZipCode, this.Buyer.City, this.Buyer.Street, CountryCodes.DE, this.Buyer.Phone);
desc.AddBuyerTaxRegistration(this.Buyer.VATID, TaxRegistrationSchemeID.VA);
desc.SetBuyerContact(this.Buyer.Contact);
desc.SetBuyerOrderReferenceDocument(this.Buyer.OrderReferenceDocument, this.Buyer.OrderReferenceDocumentDate);
desc.SetSeller(this.Seller.Name, this.Seller.ZipCode, this.Seller.City, this.Seller.Street, CountryCodes.DE, this.Seller.Phone);
desc.AddSellerTaxRegistration(this.Seller.VATID, TaxRegistrationSchemeID.VA);
desc.SetSellerContact(this.Seller.Contact, this.Seller.OrganizationUnit, this.Seller.Email, this.Seller.Phone);
desc.ActualDeliveryDate = this.DeliveryDate;
desc.SetTotals(
this.TotalNetAmount,
this.TotalChargeAmount,
this.TotalAllowanceChargeAmount,
this.TotalGrossAmount,
this.TotalTaxAmount,
this.TotalNetAmount + this.TotalTaxAmount,
this.TotalPrepaidAmount,
this.TotalDueAmount);
desc.SetTradePaymentTerms(this.PaymentTerms, this.PaymentDueDate);
foreach (LineItem lineItem in this.LineItems)
{
desc.AddTradeLineItem(lineItem.Name, lineItem.Description, lineItem.Unit, lineItem.Quantity, lineItem.UnitPrice + (lineItem.UnitPrice * lineItem.TaxPercent / 100), lineItem.UnitPrice, lineItem.Quantity, lineItem.TaxType, lineItem.TaxCategory, lineItem.TaxPercent);
}
desc.AddApplicableTradeTax(this.TotalNetAmount, 19m, TaxTypes.VAT, TaxCategoryCodes.S);
desc.SetPaymentMeans(PaymentMeansTypeCodes.ClearingBetweenPartners);
// new memory stream
MemoryStream stream = new MemoryStream();
desc.Save(stream, ZUGFeRDVersion.Version21, Profile.XRechnung);
// FileStream to XML
stream.Seek(0, SeekOrigin.Begin);
StreamReader reader = new StreamReader(stream);
string xmlZugferd = reader.ReadToEnd();
reader.Close();
return xmlZugferd;
}
}
public class LineItem
{
public string Name { get; set; }
public string Description { get; set; }
public QuantityCodes Unit { get; set; }
public decimal Quantity { get; set; }
public decimal UnitPrice { get; set; }
public decimal LineTotal {
get
{
return Quantity * UnitPrice;
}
set
{
LineTotal = value;
}
}
public decimal TaxAmount
{
get
{
return LineTotal * (TaxPercent / 100);
}
set
{
TaxAmount = value;
}
}
public decimal Total
{
get
{
return LineTotal;
}
set
{
Total = value;
}
}
public TaxTypes TaxType { get; set; }
public TaxCategoryCodes TaxCategory { get; set; }
public decimal TaxPercent { get; set; }
}
public class Buyer
{
public string Name { get; set; }
public string ZipCode { get; set; }
public string City { get; set; }
public string Street { get; set; }
public CountryCodes Country { get; set; }
public string VATID { get; set; }
public TaxRegistrationSchemeID TaxRegistrationSchemeID { get; set; }
public string Contact { get; set; }
public string OrganizationUnit { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string OrderReferenceDocument { get; set; }
public DateTime OrderReferenceDocumentDate { get; set; }
}
public class Seller : Buyer
{
public string TaxNumber { get; set; }
public string TaxNumberType { get; set; }
}
}
Please feel free to download the sample application from our GitHub repository to do your own testing.
Download and Fork This Sample on GitHub
We proudly host our sample code on github.com/TextControl.
Please fork and contribute.
Requirements for this sample
- Visual Studio 2022
- TX Text Control .NET Server 32.0
ASP.NET
Integrate document processing into your applications to create documents such as PDFs and MS Word documents, including client-side document editing, viewing, and electronic signatures.
- Angular
- Blazor
- React
- JavaScript
- ASP.NET MVC, ASP.NET Core, and WebForms
Related Posts
Visualize and Preview XRechnung, ZUGFeRD, and Factur-X Documents in .NET C#
This article shows how to visualize and preview ZUGFeRD, XRechnung, and Factur-X documents in .NET C#. It uses TX Text Control .NET Server to render the documents from the XML data.
Creating ZUGFeRD 2.3 (XRechnung, Factur-X) Documents with .NET C#
This article shows how to create ZUGFeRD 2.3 compliant invoices using TX Text Control .NET Server. ZUGFeRD 2.3 is the latest version of the ZUGFeRD data model and complies with the European…
When to Generate Documents Server-Side Instead of Client-Side: A Focus on…
When it comes to document generation, deciding whether to handle the task server-side or client-side is a key architectural decision for any organization. This article discusses the benefits of…
Using XRechnung / ZUGFeRD XML to Create PDF/A-3b Invoices with ASP.NET Core C#
This article shows how to create invoices with XRechnung and ZUGFeRD XML files using ASP.NET Core C# and the MailMerge class of TX Text Control .NET Server. The MailMerge class is used to merge…
Getting Started Video Tutorial: How to use the MailMerge and…
This video tutorial shows how to use the MailMerge and ServerTextControl classes in an ASP.NET Core application using C#. This tutorial is part of the TX Text Control Getting Started series…