Extended goods invoice

A complete goods invoice in the EXTENDED profile, rebuilt step by step: six line items with packaging details and item discounts, two tax rates, document-level invoice discounts, transport costs, an early payment discount, and a ship-to party and invoicee that both differ from the buyer.

This is not just any example, but the official sample invoice X19_01_Warenrechnung from the Factur-X / ZUGFeRD documentation (FeRD sample package, ZUGFeRD 2.5.0, EXTENDED profile). The code below produces exactly that document – field by field, in the same order. Put the reference XML next to the output and you will see the same tree structure.

Some links on this page lead into the in-depth documentation in the customer area and require a sign-in.

In business terms it is a delivery from a food wholesaler to a supermarket branch. That mixture is what makes the example instructive: almost every field that raises questions in day-to-day work appears in it at least once.

The sections below build on one another. All snippets belong to one program and can be written one after another in this order. The comments name the codes from EN 16931 and from the ZUGFeRD EXTENDED extension; the reference gives you the matching XML element for each of them.

Every EXTENDED field in this example – document name, test indicator, invoicee, packaging details, the components of a sales unit, transport costs and the extended tax bases – is only written if the document is in fact saved as Profile.Extended at the end. A smaller profile is not an error; the fields simply drop out without a word.

1. Invoice header

CreateInvoice sets the three mandatory header fields: invoice number (BT-1), invoice date (BT-2) and invoice currency (BT-5). Everything else is attached to the returned object afterwards.

2. Free-text notes

Free text ends up in ram:IncludedNote (BG-1). Two codes control how machine-readable it is: subjectCode (BT-21, UNTDID 4451) says what the note is about, contentCode (BT-X-5) is an additional standardised text block.

The two codes cannot be combined freely: ST1, ST2 and ST3 belong to AAK (discount and bonus agreements), while EEV, WEB and VEV belong to AAJ (retention of title).

The note texts, product names and discount reasons stay in German throughout this page: they are the payload of the official reference document, and translating them would break the comparison with it.

3. Seller

SetSeller fills ram:SellerTradeParty (BG-4). Besides the address, the party carries two identifiers: the internal supplier number (id, BT-29) and the GLN (globalID with schemeID 0088). Contact, electronic address and tax registration are added through their own methods.

4. Buyer

ram:BuyerTradeParty (BG-7) works identically. One point matters for the following sections: the buyer here is the head office – the goods go to a branch, and the invoice goes to a third site.

5. Document references in the header

Four references tie the invoice into the surrounding document flow: purchase order, invoice data sheet, despatch advice and delivery date. Other kinds of reference – project and contract numbers, for instance – are covered in document references.

6. Ship-to party and invoicee

The ship-to party (BG-13) and the invoicee (BG-X-36) are not set through Set… methods but as Party objects. The ship-to party carries only a GLN and no internal ID here; ShipToContact.OrgUnit additionally puts the receiving department of the branch into the document.

7. Invoice lines

Six line items (BG-25), each with a speciality of its own. The recurring pattern is the same in all six:

Parameter BT code Meaning
lineID BT-126 Line number. If it is omitted, FactoorSharp assigns it automatically – see line IDs.
id BT-157 GTIN with schemeID 0160 (GS1), in FactoorSharp GlobalIDSchemeIdentifiers.EAN.
sellerAssignedID BT-155 The supplier's item number.
buyerAssignedID BT-156 The buyer's item number for the same goods.
grossUnitPrice BT-148 Gross price, i.e. the list price before item discounts.
netUnitPrice BT-146 Net price after item discounts – the basis of the line total.
lineTotalAmount BT-131 Line total = netUnitPrice × billedQuantity.
PackageQuantity / PackageUnitCode BT-X-9 Shipping unit, EXTENDED only. XCT = carton, XBC = crate, XBO = bottle, XPX = pallet.

Line 1 – item attribute and shipping unit

The simplest line: no discounts, one item attribute (BG-32) and the number of cartons the goods arrive in. Item attributes have a page of their own: product characteristics.

Line 2 – item discounts inside the gross price

Gross and net price differ here because two item discounts are involved. These discounts do not live at document level but as ram:AppliedTradeAllowanceCharge inside the gross price (BT-147).

The amounts are per unit, not for the whole line: 1.50 − 0.03 − 0.02 = 1.45. FactoorSharp does not compute the net price – you set it, and the discounts explain it.

Line 3 – free goods

Ten pieces of the same item free of charge. The line stays in the document so that the delivered quantity remains traceable, but contributes € 0.00 to the total. The reason sits next to it as the line description (BT-154).

Lines 4 and 5 – differing units and a buyer item number

Line 4 shows that the billing unit and the shipping unit may differ: billed in crates, shipped in bottles. Line 5 is the matching empties deposit and additionally carries the buyer's item number (BT-156).

Line 6 – mixed pallet with its components

The pallet is billed as a single line, but its content is broken down through IncludedReferencedProducts (BG-X-1). That breakdown is purely informational: prices and taxes remain attached to the parent line.

8. Document-level invoice discounts

Two discounts – one percentage based, one a fixed amount – are mapped through ram:SpecifiedTradeAllowanceCharge (BG-20).

A document-level discount always applies to one tax rate only. Since this document mixes 19 % and 7 %, each discount has to be added twice, each time with the matching basis amount. Two discounts therefore become four calls. The order in the XML follows the order of the calls in your code.

The basis amounts are not simply the line totals: at 19 % lines 1, 4 and 5 would add up to € 326.50, but only € 280.00 was agreed – the empties deposit and part of the goods are exempt from the discount. At 7 % the full sum of lines 2, 3 and 6 applies: € 130.70.

9. Transport costs

Logistics costs have a dedicated element in CII and are not the same as an ordinary charge via AddTradeCharge. In XRechnung the element is not permitted; in ZUGFeRD EXTENDED it is.

10. VAT breakdown

One ram:ApplicableTradeTax group (BG-23) is mandatory per combination of tax rate and tax category – two of them here. FactoorSharp does not add the amounts up for you; the values come from your accounting and are set explicitly. The arithmetic for this document:

Field 19 % (lines 1, 4, 5) 7 % (lines 2, 3, 6)
lineTotalBasisAmount 326.50 130.70
allowanceChargeBasisAmount −5.60 − 2.50 + 3.00 = −5.10 −2.61 − 0.50 = −3.11
basisAmount 326.50 − 5.10 = 321.40 130.70 − 3.11 = 127.59
taxAmount 321.40 × 19 % = 61.066 → 61.07 127.59 × 7 % = 8.9313 → 8.93

The transport charge enters the 19 % row with a positive sign, the discounts with a negative one. More on handling tax amounts, in particular with a differing tax currency, is covered under VAT amounts.

11. Payment terms with an early payment discount

The Skonto is not only a sentence in free text but also machine-readable in the XML – that is what PaymentTermsType.Skonto is for.

12. Document totals

SetTotals writes ram:SpecifiedTradeSettlementHeaderMonetarySummation (BG-22). These values, too, are set rather than calculated:

BT code Parameter Calculation
BT-106 lineTotalAmount 100.00 + 72.50 + 0.00 + 180.00 + 46.50 + 58.20 = 457.20
BT-108 chargeTotalAmount 3.00 (transport costs)
BT-107 allowanceTotalAmount 5.60 + 2.61 + 2.50 + 0.50 = 11.21
BT-109 taxBasisAmount 457.20 + 3.00 − 11.21 = 448.99
BT-110 taxTotalAmount 61.07 + 8.93 = 70.00
BT-112 grandTotalAmount 448.99 + 70.00 = 518.99
BT-113 totalPrepaidAmount 0.00 – no prepayment. How instalments are itemised is covered under advance payments.
BT-115 duePayableAmount 518.99 − 0.00 = 518.99

13. Saving

Only at save time does it become clear which of the fields set above actually end up in the XML. Version, profile and syntax belong together:

How the same invoice is produced as a PDF/A-3 with embedded XML instead is described in working with PDF files; the remaining ways to save are covered under loading and saving.

14. Cross-check

Because the target is a known reference file, the result can be checked directly: the generated file has to have the same tree structure as X19_01_Warenrechnung.xml from the FeRD sample package. Numbers are compared numerically, so that 1.00 and 1.0000 count as equal – FactoorSharp writes prices adaptively with two decimal places.

Whether the invoice also complies with the rule set is something you check either in the browser or straight from your code. For a human look at the document, the visualizer renders a readable version:

That is a plain rendition, not a legal document and not a hybrid ZUGFeRD PDF – details under visualization.