Rechnung in Fremdwährung
Eine Rechnung in GBP, deren Steuerbetrag zusätzlich in EUR ausgewiesen wird – samt Umrechnungskurs und Kursdatum. Dazu Steuervertreter, abweichender Zahlungsempfänger, Abrechnungszeitraum, Anzahlung und Abschläge auf Positionsebene.
Grundlage ist die offizielle Beispielrechnung
X07_01_Fremdwaehrung aus der Factur-X-/ZUGFeRD-Dokumentation
(FeRD-Beispielpaket, ZUGFeRD 2.5.0, Profil EXTENDED). Der Code unten
erzeugt genau diesen Beleg, Feld für Feld und in derselben Reihenfolge.
Einige Verweise auf dieser Seite führen in die vertiefende Dokumentation im Kunden-Bereich und verlangen eine Anmeldung.
Das ist der anspruchsvollste der drei Beispielbelege: Er bringt in einem einzigen Dokument zusammen, was sonst über viele Seiten verstreut ist. Wenn Sie zum ersten Mal einen EXTENDED-Beleg aufbauen, ist die Erweiterte Warenrechnung der bessere Einstieg; hier geht es um die Sonderfälle.
Was dieses Beispiel zeigt
- Zwei Währungen: Rechnungswährung GBP (BT-5), Buchungswährung EUR (BT-6)
- Steuerbetrag doppelt – einmal je Währung (BT-110 und BT-111) – plus Umrechnungskurs (BG-X-41)
- Steuervertreter des Verkäufers (BG-11) und abweichender Zahlungsempfänger (BG-10)
- Abschläge auf Positionsebene als
SpecifiedTradeAllowanceCharge - Abrechnungszeitraum (BT-73/BT-74) und Anzahlung (BT-113)
1. Rechnungskopf und die zwei Währungen
Die entscheidende Zeile ist invoice.TaxCurrency. Alle Beträge im
Beleg stehen in der Rechnungswährung BT-5, hier GBP; die Buchungswährung BT-6
betrifft ausschließlich den zusätzlich ausgewiesenen Steuerbetrag.
// BT-5 Rechnungswährung ist GBP – in DIESER Währung stehen alle Beträge.
FacturXInvoice invoice = FacturXInvoice.CreateInvoice(
invoiceNo: "47110815",
invoiceDate: new DateTime(2025, 12, 1),
currency: CurrencyCodes.GBP);
invoice.Type = InvoiceType.Invoice;
invoice.Name = "RECHNUNG"; // BT-X-2
invoice.BusinessProcess = "Beispielgeschäftsprozess"; // BT-23
// BT-6: Buchungswährung. Sobald sie gesetzt ist und sich von BT-5 unterscheidet,
// erwartet die EN 16931 den Steuerbetrag zusätzlich in dieser Währung.
invoice.TaxCurrency = CurrencyCodes.EUR;
' BT-5 Rechnungswährung ist GBP – in DIESER Währung stehen alle Beträge.
Dim invoice As FacturXInvoice = FacturXInvoice.CreateInvoice(
invoiceNo:="47110815",
invoiceDate:=New DateTime(2025, 12, 1),
currency:=CurrencyCodes.GBP)
invoice.Type = InvoiceType.Invoice
invoice.Name = "RECHNUNG" ' BT-X-2
invoice.BusinessProcess = "Beispielgeschäftsprozess" ' BT-23
' BT-6: Buchungswährung. Sobald sie gesetzt ist und sich von BT-5 unterscheidet,
' erwartet die EN 16931 den Steuerbetrag zusätzlich in dieser Währung.
invoice.TaxCurrency = CurrencyCodes.EUR
2. Freitexte
Der Code TXD (steuerliche Information) erklärt dem menschlichen
Leser, warum überhaupt zwei Währungen im Dokument auftauchen – eine sinnvolle
Ergänzung zu den strukturierten Feldern weiter unten.
Zeilenumbrüche und Einrückungen innerhalb einer Notiz sind im XML signifikant. Die Tabulatoren im ersten Aufruf stehen nicht zur Zierde da – sie stammen zeichengenau aus der Referenzdatei, und ohne sie meldet die Gegenprobe einen Unterschied.
// Die erste Notiz ist mehrzeilig. Zeilenumbrüche und Einrückung sind im XML
// signifikant – hier stehen genau die Tabulatoren, die die Referenzdatei enthält.
invoice.AddNote("Mitglieder der Geschäftsleitung\n\t\t\t\tH. Meier Geschäftsführer"
+ "\n\t\t\t\tT. Müller Prokurist\n\t\t\t\tHRB Braunschweig 12345",
subjectCode: SubjectCodes.REG);
invoice.AddNote("Vom 17. Dezember 2025 bis 6. Januar 2026 haben wir Betriebsferien.",
subjectCode: SubjectCodes.AAI);
// TXD = steuerliche Information. Erklärt dem Leser, warum zwei Währungen auftauchen.
invoice.AddNote("Aus konzern-internen Gründen wird der Steuerbetrag sowohl in der "
+ "Rechungswährung (EUR) als auch in der Buchwährung (GBP) ausgegeben.",
subjectCode: SubjectCodes.TXD);
invoice.AddNote("ZUGFeRD vers 2.5.0 (Extended)", subjectCode: SubjectCodes.ACB);
invoice.AddNote("Dies ist ein Beispiel zur empfohlenen Darstellung von Fremdwährungsrechnungen",
subjectCode: SubjectCodes.ACB);
' Die erste Notiz ist mehrzeilig. Zeilenumbrüche und Einrückung sind im XML
' signifikant – hier stehen genau die Tabulatoren, die die Referenzdatei enthält.
invoice.AddNote("Mitglieder der Geschäftsleitung" & vbLf & vbTab & vbTab & vbTab & vbTab &
"H. Meier Geschäftsführer" & vbLf & vbTab & vbTab & vbTab & vbTab &
"T. Müller Prokurist" & vbLf & vbTab & vbTab & vbTab & vbTab &
"HRB Braunschweig 12345",
subjectCode:=SubjectCodes.REG)
invoice.AddNote("Vom 17. Dezember 2025 bis 6. Januar 2026 haben wir Betriebsferien.",
subjectCode:=SubjectCodes.AAI)
' TXD = steuerliche Information. Erklärt dem Leser, warum zwei Währungen auftauchen.
invoice.AddNote("Aus konzern-internen Gründen wird der Steuerbetrag sowohl in der " &
"Rechungswährung (EUR) als auch in der Buchwährung (GBP) ausgegeben.",
subjectCode:=SubjectCodes.TXD)
invoice.AddNote("ZUGFeRD vers 2.5.0 (Extended)", subjectCode:=SubjectCodes.ACB)
invoice.AddNote("Dies ist ein Beispiel zur empfohlenen Darstellung von Fremdwährungsrechnungen",
subjectCode:=SubjectCodes.ACB)
3. Verkäufer und Steuervertreter
Der Steuervertreter (BG-11) ist eine eigenständige Partei mit eigener USt-IdNr. – typisch, wenn ein ausländischer Lieferant im Inland durch einen Fiskalvertreter auftritt. Er wird wie eine normale Partei gesetzt, seine Steuernummer aber über eine eigene Methode.
// Verkäufer (BG-4) – ohne Ansprechpartner und ohne GLN.
invoice.SetSeller(
name: "Rohstoff AG Salzgitter",
postcode: "38226",
city: "Salzgitter",
street: "Marktstr. 153",
country: CountryCodes.DE,
id: "12345676");
invoice.AddSellerTaxRegistration("DE123456788", TaxRegistrationSchemeID.VA);
// Steuervertreter des Verkäufers (BG-11): eigene Partei mit eigener USt-IdNr.
invoice.SellerTaxRepresentative = new Party()
{
Name = "Global Supplies Financial Services",
Postcode = "12345",
Street = "Friedrichstraße 165",
City = "Berlin",
Country = CountryCodes.DE
};
invoice.AddSellerTaxRepresentativeTaxRegistration("DE136695976", TaxRegistrationSchemeID.VA);
' Verkäufer (BG-4) – ohne Ansprechpartner und ohne GLN.
invoice.SetSeller(
name:="Rohstoff AG Salzgitter",
postcode:="38226",
city:="Salzgitter",
street:="Marktstr. 153",
country:=CountryCodes.DE,
id:="12345676")
invoice.AddSellerTaxRegistration("DE123456788", TaxRegistrationSchemeID.VA)
' Steuervertreter des Verkäufers (BG-11): eigene Partei mit eigener USt-IdNr.
invoice.SellerTaxRepresentative = New Party() With
{
.Name = "Global Supplies Financial Services",
.Postcode = "12345",
.Street = "Friedrichstraße 165",
.City = "Berlin",
.Country = CountryCodes.DE
}
invoice.AddSellerTaxRepresentativeTaxRegistration("DE136695976", TaxRegistrationSchemeID.VA)
4. Käufer
Zwei Kleinigkeiten, die oft gesucht werden: street2 füllt
ram:LineTwo, also die zweite Adresszeile, und die elektronische
Adresse des Käufers (BT-49) nimmt hier eine Leitweg-ID auf.
// Käufer (BG-7). street2 füllt ram:LineTwo – die zweite Adresszeile ("Hof 3").
invoice.SetBuyer(
name: "Metallbau Leipzig GmbH & Co. KG",
postcode: "12345",
city: "Leipzig",
street: "Pappelallee 15",
street2: "Hof 3",
country: CountryCodes.DE,
id: "75969813");
// BT-49: elektronische Adresse des Käufers, Schema 0204 = Leitweg-ID.
invoice.SetBuyerElectronicAddress("04011000-1234512345-35",
ElectronicAddressSchemeIdentifiers.LeitwegId);
' Käufer (BG-7). street2 füllt ram:LineTwo – die zweite Adresszeile ("Hof 3").
invoice.SetBuyer(
name:="Metallbau Leipzig GmbH & Co. KG",
postcode:="12345",
city:="Leipzig",
street:="Pappelallee 15",
street2:="Hof 3",
country:=CountryCodes.DE,
id:="75969813")
' BT-49: elektronische Adresse des Käufers, Schema 0204 = Leitweg-ID.
invoice.SetBuyerElectronicAddress("04011000-1234512345-35",
ElectronicAddressSchemeIdentifiers.LeitwegId)
5. Lieferung und Abrechnungszeitraum
Auch der Warenempfänger trägt eine elektronische Adresse. Anders als bei
Verkäufer und Käufer gibt es dafür keine Set…-Methode: Das Feld
ElectronicAddress hängt direkt an der Partei und wird nur im
EXTENDED-Profil geschrieben.
// Warenempfänger (BG-13)
invoice.ShipTo = new Party()
{
ID = new GlobalID(null, "75969815"),
Name = "Metallbau Leipzig GmbH & Co. KG",
Postcode = "12347",
Street = "Eichenpromenade 37",
Street2 = "Tor 1",
City = "Metallstadt",
Country = CountryCodes.DE,
// BT-X-160: elektronische Adresse des Warenempfängers, hier eine D-U-N-S-Nummer
// unter Schema 0060. Jede Partei trägt dieses Feld – für Verkäufer und Käufer
// sind es BT-34 bzw. BT-49, für alle übrigen ein eigenes BT-X-Feld, das nur im
// Profil EXTENDED geschrieben wird.
ElectronicAddress = new ElectronicAddress()
{
Address = "999999999",
ElectronicAddressSchemeID = ElectronicAddressSchemeIdentifiers.DunsNumber
}
};
invoice.ActualDeliveryDate = new DateTime(2025, 11, 25); // BT-72
// BT-73 / BT-74: Abrechnungszeitraum des gesamten Belegs
invoice.SetBillingPeriod(new DateTime(2025, 11, 1), new DateTime(2025, 11, 30));
' Warenempfänger (BG-13)
invoice.ShipTo = New Party() With
{
.ID = New GlobalID(Nothing, "75969815"),
.Name = "Metallbau Leipzig GmbH & Co. KG",
.Postcode = "12347",
.Street = "Eichenpromenade 37",
.Street2 = "Tor 1",
.City = "Metallstadt",
.Country = CountryCodes.DE,
' BT-X-160: elektronische Adresse des Warenempfängers, hier eine D-U-N-S-Nummer
' unter Schema 0060. Jede Partei trägt dieses Feld – für Verkäufer und Käufer
' sind es BT-34 bzw. BT-49, für alle übrigen ein eigenes BT-X-Feld, das nur im
' Profil EXTENDED geschrieben wird.
.ElectronicAddress = New ElectronicAddress() With
{
.Address = "999999999",
.ElectronicAddressSchemeID = ElectronicAddressSchemeIdentifiers.DunsNumber
}
}
invoice.ActualDeliveryDate = New DateTime(2025, 11, 25) ' BT-72
' BT-73 / BT-74: Abrechnungszeitraum des gesamten Belegs
invoice.SetBillingPeriod(New DateTime(2025, 11, 1), New DateTime(2025, 11, 30))
6. Zahlungsempfänger und Bankverbindung
Bezahlt wird nicht an den Verkäufer, sondern an dessen Finanzdienstleister
(BG-10). Die Bankverbindung wird getrennt davon über
AddCreditorFinancialAccount gesetzt.
// Zahlungsempfänger (BG-10): bezahlt wird nicht an den Verkäufer, sondern an dessen
// Finanzdienstleister. Schema 0060 = D-U-N-S-Nummer.
invoice.Payee = new Party()
{
GlobalID = new GlobalID(GlobalIDSchemeIdentifiers.DUNS, "432156789"),
Name = "Global Supplies Financial Services",
Postcode = "12345",
Street = "Friedrichstraße 165",
City = "Berlin",
Country = CountryCodes.DE
};
// Kein Informationstext und kein BIC – die Referenz gibt beides nicht aus.
invoice.SetPaymentMeans(PaymentMeansTypeCodes.SEPACreditTransfer);
invoice.AddCreditorFinancialAccount(
iban: "DE77 3707 0060 0321 9870 00",
bic: null,
name: "Global Supplies Financial Services");
' Zahlungsempfänger (BG-10): bezahlt wird nicht an den Verkäufer, sondern an dessen
' Finanzdienstleister. Schema 0060 = D-U-N-S-Nummer.
invoice.Payee = New Party() With
{
.GlobalID = New GlobalID(GlobalIDSchemeIdentifiers.DUNS, "432156789"),
.Name = "Global Supplies Financial Services",
.Postcode = "12345",
.Street = "Friedrichstraße 165",
.City = "Berlin",
.Country = CountryCodes.DE
}
' Kein Informationstext und kein BIC – die Referenz gibt beides nicht aus.
invoice.SetPaymentMeans(PaymentMeansTypeCodes.SEPACreditTransfer)
invoice.AddCreditorFinancialAccount(
iban:="DE77 3707 0060 0321 9870 00",
bic:=Nothing,
name:="Global Supplies Financial Services")
7. Position mit Abschlägen
Eine einzige Position, aber mit dem Unterschied, der in der Praxis am häufigsten verwechselt wird: Es gibt zwei verschiedene Rabattarten auf Positionsebene.
| Methode | XML-Element | Wirkung |
|---|---|---|
AddTradeAllowance |
ram:AppliedTradeAllowanceCharge(innerhalb des Bruttopreises) |
Betrag pro Einheit. Senkt den Nettopreis. So arbeitet die Warenrechnung. |
AddSpecifiedTradeAllowance |
ram:SpecifiedTradeAllowanceCharge(im Positions-Settlement) |
Betrag für die gesamte Position. Senkt die Positionssumme, der Preis bleibt unverändert. Dieser Weg wird hier genutzt. |
Konkret: Der Stückpreis bleibt bei 100 GBP, die Positionssumme fällt durch die beiden Abschläge von 1.000 auf 850 GBP.
// 10 Stahlcoils zu 100 GBP = 1.000 GBP, davon zwei Abschläge (100 + 50) → 850 GBP.
TradeLineItem coil = invoice.AddTradeLineItem(
lineID: "1",
name: "Stahlcoil",
netUnitPrice: 100m,
grossUnitPrice: 100m,
unitCode: QuantityCodes.H87,
unitQuantity: 1m,
billedQuantity: 10m,
lineTotalAmount: 850m, // nach Abzug der beiden Abschläge unten
taxType: TaxTypes.VAT,
categoryCode: TaxCategoryCodes.S,
taxPercent: 19m,
sellerAssignedID: "CO-123/V2A",
buyerAssignedID: "Toolbox 0815");
coil.GrossQuantity = 1m; // ram:BasisQuantity im Bruttopreis
coil.OriginTradeCountry = CountryCodes.DE; // BT-159 Ursprungsland
// Positionsnotiz ohne SubjectCode, wieder mit der Einrückung aus der Referenz.
coil.AddNote("Materialzertifikat X-234 gem ISO XYZ.\n\t\t\t\t\t\tWare bleibt bis zur "
+ "vollständigen Bezahlung unser Eigentum.\n\t\t\t\t\t");
// Bestellbezug mit Bestellposition, aber ohne Datum
coil.SetBuyerOrderReferencedDocument("ORDER84359", orderReferencedDate: null,
orderReferencedLineId: "1");
// Abschlag 1: prozentual, 10 % von 1.000. ReasonCode 64 = besondere Vereinbarung.
coil.AddSpecifiedTradeAllowance(
currency: CurrencyCodes.GBP,
basisAmount: 1000m,
actualAmount: 100m,
chargePercentage: 10m,
reason: "Lagerware",
reasonCode: AllowanceReasonCodes.SpecialAgreement);
// Abschlag 2: fester Betrag. ReasonCode 70 = Incoterm-Rabatt.
coil.AddSpecifiedTradeAllowance(
currency: CurrencyCodes.GBP,
basisAmount: 1000m,
actualAmount: 50m,
reason: "Direktbelieferung",
reasonCode: AllowanceReasonCodes.IncotermDiscount);
' 10 Stahlcoils zu 100 GBP = 1.000 GBP, davon zwei Abschläge (100 + 50) → 850 GBP.
Dim coil As TradeLineItem = invoice.AddTradeLineItem(
lineID:="1",
name:="Stahlcoil",
netUnitPrice:=100D,
grossUnitPrice:=100D,
unitCode:=QuantityCodes.H87,
unitQuantity:=1D,
billedQuantity:=10D,
lineTotalAmount:=850D, ' nach Abzug der beiden Abschläge unten
taxType:=TaxTypes.VAT,
categoryCode:=TaxCategoryCodes.S,
taxPercent:=19D,
sellerAssignedID:="CO-123/V2A",
buyerAssignedID:="Toolbox 0815")
coil.GrossQuantity = 1D ' ram:BasisQuantity im Bruttopreis
coil.OriginTradeCountry = CountryCodes.DE ' BT-159 Ursprungsland
' Positionsnotiz ohne SubjectCode, wieder mit der Einrückung aus der Referenz.
coil.AddNote("Materialzertifikat X-234 gem ISO XYZ." & vbLf &
vbTab & vbTab & vbTab & vbTab & vbTab & vbTab &
"Ware bleibt bis zur vollständigen Bezahlung unser Eigentum." & vbLf &
vbTab & vbTab & vbTab & vbTab & vbTab)
' Bestellbezug mit Bestellposition, aber ohne Datum
coil.SetBuyerOrderReferencedDocument("ORDER84359", orderReferencedDate:=Nothing,
orderReferencedLineId:="1")
' Abschlag 1: prozentual, 10 % von 1.000. ReasonCode 64 = besondere Vereinbarung.
coil.AddSpecifiedTradeAllowance(
currency:=CurrencyCodes.GBP,
basisAmount:=1000D,
actualAmount:=100D,
chargePercentage:=10D,
reason:="Lagerware",
reasonCode:=AllowanceReasonCodes.SpecialAgreement)
' Abschlag 2: fester Betrag. ReasonCode 70 = Incoterm-Rabatt.
coil.AddSpecifiedTradeAllowance(
currency:=CurrencyCodes.GBP,
basisAmount:=1000D,
actualAmount:=50D,
reason:="Direktbelieferung",
reasonCode:=AllowanceReasonCodes.IncotermDiscount)
8. Zu- und Abschläge auf Dokumentenebene
Ein Zuschlag für Einwegverpackung und ein prozentualer Stammkundenrabatt. Beide
teilen sich im XML dasselbe Element ram:SpecifiedTradeAllowanceCharge
und werden nur über ram:ChargeIndicator unterschieden. Der Writer
schreibt sie in der Reihenfolge, in der sie hinzugefügt werden – deshalb steht
der Zuschlag im Code zuerst.
// Zuschlag zuerst – der Writer schreibt Zu- und Abschläge in der Reihenfolge, in der
// sie hinzugefügt werden, und die Referenz führt den Zuschlag vorn.
invoice.AddTradeCharge(
basisAmount: null, // die Referenz gibt hier keine Bemessungsgrundlage aus
currency: CurrencyCodes.GBP,
actualAmount: 30m,
reason: "Einwegverpackung",
taxTypeCode: TaxTypes.VAT,
taxCategoryCode: TaxCategoryCodes.S,
taxPercent: 19m,
reasonCode: ChargeReasonCodes.Miscellaneous); // ABK
invoice.AddTradeAllowance(
basisAmount: 850m,
currency: CurrencyCodes.GBP,
actualAmount: 21.25m,
chargePercentage: 2.5m,
reason: "Stammkundenrabatt",
taxTypeCode: TaxTypes.VAT,
taxCategoryCode: TaxCategoryCodes.S,
taxPercent: 19m,
reasonCode: AllowanceReasonCodes.FixedLongTerm); // 102
' Zuschlag zuerst – der Writer schreibt Zu- und Abschläge in der Reihenfolge, in der
' sie hinzugefügt werden, und die Referenz führt den Zuschlag vorn.
invoice.AddTradeCharge(
basisAmount:=Nothing, ' die Referenz gibt hier keine Bemessungsgrundlage aus
currency:=CurrencyCodes.GBP,
actualAmount:=30D,
reason:="Einwegverpackung",
taxTypeCode:=TaxTypes.VAT,
taxCategoryCode:=TaxCategoryCodes.S,
taxPercent:=19D,
reasonCode:=ChargeReasonCodes.Miscellaneous) ' ABK
invoice.AddTradeAllowance(
basisAmount:=850D,
currency:=CurrencyCodes.GBP,
actualAmount:=21.25D,
chargePercentage:=2.5D,
reason:="Stammkundenrabatt",
taxTypeCode:=TaxTypes.VAT,
taxCategoryCode:=TaxCategoryCodes.S,
taxPercent:=19D,
reasonCode:=AllowanceReasonCodes.FixedLongTerm) ' 102
9. Umsatzsteuer in Rechnungswährung
Zunächst ganz normal, in GBP: 850,00 + 30,00 − 21,25 = 858,75, davon 19 % = 163,1625 → 163,16 GBP.
// BT-110: Steuerbetrag in Rechnungswährung (GBP).
invoice.AddApplicableTradeTax(
basisAmount: 858.75m,
percent: 19m,
taxAmount: 163.16m,
typeCode: TaxTypes.VAT,
categoryCode: TaxCategoryCodes.S,
allowanceChargeBasisAmount: 8.75m, // +30,00 − 21,25
lineTotalBasisAmount: 850m);
' BT-110: Steuerbetrag in Rechnungswährung (GBP).
invoice.AddApplicableTradeTax(
basisAmount:=858.75D,
percent:=19D,
taxAmount:=163.16D,
typeCode:=TaxTypes.VAT,
categoryCode:=TaxCategoryCodes.S,
allowanceChargeBasisAmount:=8.75D, ' +30,00 − 21,25
lineTotalBasisAmount:=850D)
10. Steuerbetrag in Buchungswährung und Umrechnungskurs
Für die Umsatzsteuer-Meldung beim Finanzamt reicht der Steuerbetrag in Fremdwährung nicht: Art. 230 der EU-Mehrwertsteuer-Systemrichtlinie (2006/112/EG) verlangt den Betrag zusätzlich in der Landeswährung des Verkäufers. Dafür gibt es drei zusammengehörige Angaben:
| Code | Feld | Bedeutung |
|---|---|---|
| BT-6 | TaxCurrency |
Die Buchungswährung selbst, hier EUR. |
| BT-111 | TaxTotalAmountInAccountingCurrency |
Derselbe Steuerbetrag, in BT-6 umgerechnet: 183,14 EUR. |
| BG-X-41 | TaxCurrencyExchange (Gruppe) | Der Kurs, mit dem umgerechnet wurde. |
| BT-X-258 | SourceCurrency |
Rechnungswährung, also BT-5 (GBP). Leitet FactoorSharp automatisch ab. |
| BT-X-259 | TargetCurrency |
Buchungswährung, also BT-6 (EUR). |
| BT-X-260 | ConversionRate |
Der eigentliche Kurs, hier 1,12244. |
| BT-X-261 | ConversionRateTimestamp |
Kursdatum, optional. Hier der Tag der Lieferung, 25.11.2025. |
Ohne BG-X-41 stünde nur das Ergebnis im Beleg, nicht der Weg dorthin – für eine Buchhaltung, die den Betrag nachrechnen oder gegen den Tageskurs prüfen will, ist genau das die fehlende Angabe.
Warum eine Methode für drei Business Terms? Weil die EN 16931-Geschäftsregel BR-53 fordert: Ist BT-6 vorhanden, muss BT-111 mitgeliefert werden. Und der Kurs in BG-X-41 ist die Rechtfertigung für den Wert in BT-111. Getrennte Setter hätten es erlaubt, einen Steuerbetrag in Buchungswährung zu setzen, ohne je zu sagen, mit welchem Kurs er entstanden ist – oder umgekehrt einen Kurs zu hinterlegen, der zu keinem gemeldeten Betrag passt.
// Ein Aufruf schreibt BT-111, BT-6 und die komplette Gruppe BG-X-41:
// 163,16 GBP × 1,12244 = 183,14 EUR
// Die Quellwährung leitet die Methode automatisch von invoice.Currency (BT-5) ab.
invoice.SetTaxCurrencyExchange(
taxTotalInAccountingCurrency: 183.14m,
accountingCurrency: CurrencyCodes.EUR,
conversionRate: 1.12244m,
conversionRateTimestamp: new DateTime(2025, 11, 25));
' Ein Aufruf schreibt BT-111, BT-6 und die komplette Gruppe BG-X-41:
' 163,16 GBP × 1,12244 = 183,14 EUR
' Die Quellwährung leitet die Methode automatisch von invoice.Currency (BT-5) ab.
invoice.SetTaxCurrencyExchange(
taxTotalInAccountingCurrency:=183.14D,
accountingCurrency:=CurrencyCodes.EUR,
conversionRate:=1.12244D,
conversionRateTimestamp:=New DateTime(2025, 11, 25))
Die frühere Methode SetTaxTotalInAccountingCurrency setzte nur
BT-111 und BT-6, ohne Kurs. Sie wurde mit Version 20.0 entfernt;
verwenden Sie SetTaxCurrencyExchange.
Zum Kurs selbst: BT-X-260 ist im Schema als reines xs:decimal ohne
Stellenbegrenzung definiert, und die FeRD-Referenz schreibt fünf
Nachkommastellen. Der Writer rundet deshalb adaptiv – auf zwei Stellen, wenn das
verlustfrei möglich ist, sonst auf bis zu fünf – und gibt 1,12244 exakt wieder.
Das Kursdatum steht wie alle Datumsfelder im UN/CEFACT-Format 102 (JJJJMMTT).
BG-X-41 gibt es nur im Profil EXTENDED und ausschließlich CII-seitig.
UBL kennt mit cac:TaxExchangeRate zwar ein strukturell
vergleichbares Element, das liegt aber außerhalb der EN 16931-CIUS und wird
von FactoorSharp daher nicht bedient – siehe
UBL vs. CII.
11. Zahlungsbedingungen
Zwei Stufen, hier bewusst als reiner Freitext mit Datum. Wie ein Skonto stattdessen maschinell auswertbar wird, zeigt die Warenrechnung.
// Zwei Stufen als reiner Freitext plus Datum – ohne PaymentTermsType.Skonto, also
// ohne maschinell auswertbaren Skonto-Block.
invoice.AddTradePaymentTerms("Zahlbar ohne Abschlag bis ", new DateTime(2025, 12, 31));
invoice.AddTradePaymentTerms("Zahlbar mit 2% Skonto bis", new DateTime(2025, 12, 14));
' Zwei Stufen als reiner Freitext plus Datum – ohne PaymentTermsType.Skonto, also
' ohne maschinell auswertbaren Skonto-Block.
invoice.AddTradePaymentTerms("Zahlbar ohne Abschlag bis ", New DateTime(2025, 12, 31))
invoice.AddTradePaymentTerms("Zahlbar mit 2% Skonto bis", New DateTime(2025, 12, 14))
12. Gesamtsummen
Alle Summen stehen in GBP. Neu gegenüber den anderen Beispielen ist die Anzahlung (BT-113), die vom Bruttobetrag abgezogen wird:
| BT-Code | Parameter | Rechenweg (GBP) |
|---|---|---|
| BT-106 | lineTotalAmount |
850,00 (Positionssumme nach den beiden Abschlägen) |
| BT-108 | chargeTotalAmount |
30,00 (Einwegverpackung) |
| BT-107 | allowanceTotalAmount |
21,25 (Stammkundenrabatt) |
| BT-109 | taxBasisAmount |
850,00 + 30,00 − 21,25 = 858,75 |
| BT-110 | taxTotalAmount |
858,75 × 19 % = 163,16 |
| BT-112 | grandTotalAmount |
858,75 + 163,16 = 1.021,91 |
| BT-113 | totalPrepaidAmount |
500,00. Wie einzelne Abschläge aufgeschlüsselt werden, steht unter Anzahlungen. |
| BT-115 | duePayableAmount |
1.021,91 − 500,00 = 521,91 |
// Alle Werte in GBP, der Rechnungswährung – auch der Steuerbetrag.
invoice.SetTotals(
lineTotalAmount: 850m, // BT-106
chargeTotalAmount: 30m, // BT-108
allowanceTotalAmount: 21.25m, // BT-107
taxBasisAmount: 858.75m, // BT-109
taxTotalAmount: 163.16m, // BT-110
grandTotalAmount: 1021.91m, // BT-112
totalPrepaidAmount: 500m, // BT-113 Anzahlung
duePayableAmount: 521.91m); // BT-115
' Alle Werte in GBP, der Rechnungswährung – auch der Steuerbetrag.
invoice.SetTotals(
lineTotalAmount:=850D, ' BT-106
chargeTotalAmount:=30D, ' BT-108
allowanceTotalAmount:=21.25D, ' BT-107
taxBasisAmount:=858.75D, ' BT-109
taxTotalAmount:=163.16D, ' BT-110
grandTotalAmount:=1021.91D, ' BT-112
totalPrepaidAmount:=500D, ' BT-113 Anzahlung
duePayableAmount:=521.91D) ' BT-115
13. Speichern und prüfen
invoice.Save("X07_01_Fremdwaehrung.xml",
ZUGFeRDVersion.Version25,
Profile.Extended,
ZUGFeRDFormats.CII);
invoice.Save("X07_01_Fremdwaehrung.xml",
ZUGFeRDVersion.Version25,
Profile.Extended,
ZUGFeRDFormats.CII)
Das Ergebnis muss dieselbe Baumstruktur haben wie
X07_01_Fremdwaehrung.xml aus dem FeRD-Beispielpaket. Ob der Beleg
darüber hinaus dem Regelwerk entspricht, prüfen Sie entweder
im Browser
oder direkt
aus Ihrem Code heraus.
Ein Befund ist dabei erwartbar und stammt nicht aus dem Nachbau: Die
FeRD-Referenz trägt als Leitweg-ID 04011000-1234512345-35, und
deren Prüfziffer ist falsch. Der Wert ist zeichengenau aus der Vorlage
übernommen, der Befund trifft die Vorlage also genauso. Wer die Rechnung als
eigenen Beleg verwendet, setzt an dieser Stelle eine gültige Leitweg-ID ein.
Eine Lesefassung für Menschen erzeugt der Visualizer; wie daraus ein PDF/A-3 mit eingebettetem XML wird, steht unter Umgang mit PDF-Dateien.