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
}
}
};
view raw test.cs hosted with ❤ by GitHub

The CreateXML method is then called to generate the XML, which is then used in an EmbeddedFile TX Text Control .NET Server for ASP.NET
TXTextControl Namespace
EmbeddedFile Class
The EmbeddedFile class represents a file embedded in another document.
object along with the XML metadata.

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 };
view raw test.cs hosted with ❤ by GitHub

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);
}
view raw test.cs hosted with ❤ by GitHub

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.

Created XRechnung with TX Text Control

You can prove the validity of the generated invoice by uploading it to any ZUGFeRD validation service.

Created XRechnung with TX Text Control

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; }
}
}
view raw test.cs hosted with ❤ by GitHub

Please feel free to download the sample application from our GitHub repository to do your own testing.