Altteilesteuer
Die Werkstatt liefert einen Austauschmotor, der Kunde gibt den alten zurück – und auf den Wert dieses Altteils fällt Umsatzsteuer an, obwohl er gar nicht berechnet wird. So entsteht eine Rechnung, deren Steuerbetrag höher ist als 19 % der Nettosumme.
Deutsches Umsatzsteuerrecht. Die Altteilesteuer ist eine Besonderheit des deutschen Rechts. Grundlage sind § 3 Abs. 12 und § 10 Abs. 2 Satz 2 des Umsatzsteuergesetzes (UStG) – der Tausch mit Baraufgabe – sowie Abschnitt 10.5 Abs. 3 des Umsatzsteuer-Anwendungserlasses (UStAE) für das Austauschverfahren in der Kraftfahrzeugwirtschaft. Diese Seite zeigt die technische Abbildung in der E-Rechnung und ersetzt keine steuerliche Beratung.
Die Abbildung folgt dem Geschäftsfall 03.06a der
XRechnung-Testsuite der Koordinierungsstelle für IT-Standards (KoSIT):
03.06a-INVOICE_uncefact.xml.
Positionen, Steuerkategorien und Summen sind identisch; die Stammdaten sind
die der übrigen Beispielrechnungen dieser Dokumentation.
Worum geht es?
Im Austauschverfahren liefert die Werkstatt ein funktionsfähiges Teil und bekommt dafür zweierlei: Geld und das reparaturbedürftige Altteil. Umsatzsteuerlich ist das ein Tausch mit Baraufgabe – zum Entgelt für das Austauschteil gehört also neben der Geldzahlung auch der Wert des Altteils. Der UStAE lässt zu, diesen Wert pauschal mit 10 % des sogenannten Bruttoaustauschentgelts anzusetzen.
Im Beispiel kostet der Motor 1.000 EUR. Das Altteil ist damit 100 EUR wert, und darauf entstehen 19 EUR Umsatzsteuer. Die 100 EUR selbst zahlt der Kunde nicht – er hat sie mit dem Altteil beglichen. Die 19 EUR dagegen stehen auf der Rechnung.
Die EN 16931 kennt dafür kein eigenes Feld. Die KoSIT-Testsuite löst das mit zwei zusätzlichen Positionen, die sich im Netto aufheben, in der Steuer aber nicht:
| Pos. | Bezeichnung | Menge | Positionssumme | Kategorie | Steuer |
|---|---|---|---|---|---|
| 1 | Neumotor | 1 | 1.000,00 | S, 19 % | 190,00 |
| 2 | Bemessungsgrundlage und Umsatzsteuer auf Altteil | 1 | 100,00 | S, 19 % | 19,00 |
| 3 | Korrektur/Stornierung Bemessungsgrundlage der Umsatzsteuer auf Altteil | −1 | −100,00 | Z, 0 % | 0,00 |
| 4 | Montage | 1 | 500,00 | S, 19 % | 95,00 |
| Summe | 1.500,00 | 304,00 |
Position 2 bringt den Altteilwert in die Bemessungsgrundlage des Regelsatzes. Position 3 nimmt dieselben 100 EUR netto wieder heraus, trägt aber die Kategorie Z mit 0 % – die Steuer aus Position 2 bleibt deshalb stehen. Unter dem Strich: 1.500 EUR netto, 304 EUR Umsatzsteuer, 1.804 EUR brutto.
Was dieses Beispiel zeigt
- Eine Position mit negativer Menge und positivem Preis in einer gewöhnlichen Rechnung (Typ 380)
- Zwei Steuerkategorien in einem Beleg: S (19 %) und Z (0 %)
- Eine Steueraufschlüsselung mit negativer Bemessungsgrundlage (BT-116)
- Einen Steuerbetrag (BT-110), der bewusst nicht 19 % der Nettosumme (BT-109) entspricht
Der Code unten baut den Beleg Schritt für Schritt auf. Wer FactoorSharp noch gar nicht kennt, fängt besser bei Los geht’s an – hier liegt der Schwerpunkt auf dem, was die Altteilesteuer besonders macht. Zu jeder BT- und BG-Nummer finden Sie das zugehörige XML-Element in der Factur-X-Referenz.
1. Rechnungskopf
Eine ganz normale Handelsrechnung. Die Notiz mit dem Code TXD ist
optional und steht nicht in der KoSIT-Vorlage; sie erklärt dem Empfänger in
einem Satz, woher die zusätzlichen 19 EUR kommen.
FacturXInvoice invoice = FacturXInvoice.CreateInvoice(
invoiceNo: "R87654321012346",
invoiceDate: new DateTime(2025, 10, 1),
currency: CurrencyCodes.EUR);
// BT-3: 380 = Handelsrechnung. Die Altteilesteuer braucht keinen eigenen Dokumenttyp.
invoice.Type = InvoiceType.Invoice;
invoice.Name = "RECHNUNG"; // BT-X-2, nur EXTENDED
// Optional: Der Code TXD (steuerliche Information) erklärt dem menschlichen Leser,
// warum der Steuerbetrag höher ist als 19 % der Nettosumme.
invoice.AddNote("Lieferung im Austauschverfahren. Die Umsatzsteuer auf das Altteil ist "
+ "nach Abschn. 10.5 Abs. 3 UStAE gesondert berechnet "
+ "(Altteilwert 100,00 EUR, 19 % = 19,00 EUR).",
subjectCode: SubjectCodes.TXD);
Dim invoice As FacturXInvoice = FacturXInvoice.CreateInvoice(
invoiceNo:="R87654321012346",
invoiceDate:=New DateTime(2025, 10, 1),
currency:=CurrencyCodes.EUR)
' BT-3: 380 = Handelsrechnung. Die Altteilesteuer braucht keinen eigenen Dokumenttyp.
invoice.Type = InvoiceType.Invoice
invoice.Name = "RECHNUNG" ' BT-X-2, nur EXTENDED
' Optional: Der Code TXD (steuerliche Information) erklärt dem menschlichen Leser,
' warum der Steuerbetrag höher ist als 19 % der Nettosumme.
invoice.AddNote("Lieferung im Austauschverfahren. Die Umsatzsteuer auf das Altteil ist " &
"nach Abschn. 10.5 Abs. 3 UStAE gesondert berechnet " &
"(Altteilwert 100,00 EUR, 19 % = 19,00 EUR).",
subjectCode:=SubjectCodes.TXD)
2. Verkäufer und Käufer
Die Stammdaten spielen für die Altteilesteuer keine Rolle. Sie entsprechen denen der Erweiterten Warenrechnung.
// Verkäufer (BG-4): die Werkstatt, die das Austauschteil liefert und einbaut.
invoice.SetSeller(
name: "MUSTERLIEFERANT GMBH",
postcode: "99199",
city: "MUSTERHAUSEN",
street: "BAHNHOFSTRASSE 99",
country: CountryCodes.DE,
id: "549910",
globalID: new GlobalID(GlobalIDSchemeIdentifiers.GLN, "4333741000005"));
invoice.SetSellerContact(
emailAddress: "max.mustermann@musterlieferant.de",
phoneno: "+49 932 431 500");
// BT-31: USt-IdNr. des Verkäufers
invoice.AddSellerTaxRegistration("DE123456788", TaxRegistrationSchemeID.VA);
// Käufer (BG-7): gibt das Altteil zurück.
invoice.SetBuyer(
name: "MUSTER-KUNDE GMBH",
postcode: "40235",
city: "KUNDENSTADT",
street: "KUNDENWEG 88",
country: CountryCodes.DE,
id: "009420",
globalID: new GlobalID(GlobalIDSchemeIdentifiers.GLN, "4304171000002"));
invoice.ActualDeliveryDate = new DateTime(2025, 10, 1); // BT-72
' Verkäufer (BG-4): die Werkstatt, die das Austauschteil liefert und einbaut.
invoice.SetSeller(
name:="MUSTERLIEFERANT GMBH",
postcode:="99199",
city:="MUSTERHAUSEN",
street:="BAHNHOFSTRASSE 99",
country:=CountryCodes.DE,
id:="549910",
globalID:=New GlobalID(GlobalIDSchemeIdentifiers.GLN, "4333741000005"))
invoice.SetSellerContact(
emailAddress:="max.mustermann@musterlieferant.de",
phoneno:="+49 932 431 500")
' BT-31: USt-IdNr. des Verkäufers
invoice.AddSellerTaxRegistration("DE123456788", TaxRegistrationSchemeID.VA)
' Käufer (BG-7): gibt das Altteil zurück.
invoice.SetBuyer(
name:="MUSTER-KUNDE GMBH",
postcode:="40235",
city:="KUNDENSTADT",
street:="KUNDENWEG 88",
country:=CountryCodes.DE,
id:="009420",
globalID:=New GlobalID(GlobalIDSchemeIdentifiers.GLN, "4304171000002"))
invoice.ActualDeliveryDate = New DateTime(2025, 10, 1) ' BT-72
3. Das Austauschteil
Position 1 ist unauffällig: ein Stück, Regelsatz.
// Position 1: das Austauschteil. 1 × 1.000,00 = 1.000,00, 19 %.
invoice.AddTradeLineItem(
name: "Neumotor",
netUnitPrice: 1000.00m,
grossUnitPrice: 1000.00m,
unitCode: QuantityCodes.C62,
billedQuantity: 1m,
lineTotalAmount: 1000.00m,
taxType: TaxTypes.VAT,
categoryCode: TaxCategoryCodes.S,
taxPercent: 19m);
' Position 1: das Austauschteil. 1 × 1.000,00 = 1.000,00, 19 %.
invoice.AddTradeLineItem(
name:="Neumotor",
netUnitPrice:=1000D,
grossUnitPrice:=1000D,
unitCode:=QuantityCodes.C62,
billedQuantity:=1D,
lineTotalAmount:=1000D,
taxType:=TaxTypes.VAT,
categoryCode:=TaxCategoryCodes.S,
taxPercent:=19D)
4. Das Altteil: zwei Positionen
Hier steckt die eigentliche Abbildung. Beide Positionen haben denselben Preis von 100 EUR; sie unterscheiden sich in Menge und Steuerkategorie.
Das Vorzeichen steckt in der Menge, nicht im Preis. Die Geschäftsregel BR-27 der EN 16931 verbietet einen negativen Nettopreis (BT-146); eine negative Menge (BT-129) und damit eine negative Positionssumme (BT-131) sind dagegen zulässig.
// Position 2: der Wert des Altteils (10 % von 1.000,00) kommt in die
// Bemessungsgrundlage des Regelsatzes: 1 × 100,00 = 100,00, 19 % → 19,00 Steuer.
invoice.AddTradeLineItem(
name: "Bemessungsgrundlage und Umsatzsteuer auf Altteil",
netUnitPrice: 100.00m,
grossUnitPrice: 100.00m,
unitCode: QuantityCodes.C62,
billedQuantity: 1m,
lineTotalAmount: 100.00m,
taxType: TaxTypes.VAT,
categoryCode: TaxCategoryCodes.S,
taxPercent: 19m);
// Position 3: nimmt die 100,00 netto wieder heraus – mit Kategorie Z und 0 %,
// damit die 19,00 Steuer aus Position 2 stehen bleiben.
invoice.AddTradeLineItem(
name: "Korrektur/Stornierung Bemessungsgrundlage der Umsatzsteuer auf Altteil",
netUnitPrice: 100.00m, // positiv! (BR-27)
grossUnitPrice: 100.00m, // positiv!
unitCode: QuantityCodes.C62,
billedQuantity: -1m, // negativ!
lineTotalAmount: -100.00m,
taxType: TaxTypes.VAT,
categoryCode: TaxCategoryCodes.Z,
taxPercent: 0m); // 0 % ausdrücklich angeben (BR-Z-05)
' Position 2: der Wert des Altteils (10 % von 1.000,00) kommt in die
' Bemessungsgrundlage des Regelsatzes: 1 × 100,00 = 100,00, 19 % → 19,00 Steuer.
invoice.AddTradeLineItem(
name:="Bemessungsgrundlage und Umsatzsteuer auf Altteil",
netUnitPrice:=100D,
grossUnitPrice:=100D,
unitCode:=QuantityCodes.C62,
billedQuantity:=1D,
lineTotalAmount:=100D,
taxType:=TaxTypes.VAT,
categoryCode:=TaxCategoryCodes.S,
taxPercent:=19D)
' Position 3: nimmt die 100,00 netto wieder heraus – mit Kategorie Z und 0 %,
' damit die 19,00 Steuer aus Position 2 stehen bleiben.
invoice.AddTradeLineItem(
name:="Korrektur/Stornierung Bemessungsgrundlage der Umsatzsteuer auf Altteil",
netUnitPrice:=100D, ' positiv! (BR-27)
grossUnitPrice:=100D, ' positiv!
unitCode:=QuantityCodes.C62,
billedQuantity:=-1D, ' negativ!
lineTotalAmount:=-100D,
taxType:=TaxTypes.VAT,
categoryCode:=TaxCategoryCodes.Z,
taxPercent:=0D) ' 0 % ausdrücklich angeben (BR-Z-05)
Der Steuersatz der Korrekturposition wird ausdrücklich mit 0m
übergeben. Ohne den Parameter bliebe BT-152 leer – für die Kategorie Z
verlangt die Regel BR-Z-05 aber genau den Wert 0.
5. Die Montage
Position 4 ist wieder gewöhnlich, diesmal mit der Einheit
HUR für Stunden.
// Position 4: die Montage. 1 Stunde × 500,00 = 500,00, 19 %.
invoice.AddTradeLineItem(
name: "Montage",
netUnitPrice: 500.00m,
grossUnitPrice: 500.00m,
unitCode: QuantityCodes.HUR, // HUR = Stunde
billedQuantity: 1m,
lineTotalAmount: 500.00m,
taxType: TaxTypes.VAT,
categoryCode: TaxCategoryCodes.S,
taxPercent: 19m);
' Position 4: die Montage. 1 Stunde × 500,00 = 500,00, 19 %.
invoice.AddTradeLineItem(
name:="Montage",
netUnitPrice:=500D,
grossUnitPrice:=500D,
unitCode:=QuantityCodes.HUR, ' HUR = Stunde
billedQuantity:=1D,
lineTotalAmount:=500D,
taxType:=TaxTypes.VAT,
categoryCode:=TaxCategoryCodes.S,
taxPercent:=19D)
6. Umsatzsteuer
Je Kombination aus Kategorie und Satz steht eine Aufschlüsselung im Beleg (BG-23). Die Bemessungsgrundlage ist jeweils die Summe der Positionen dieser Kategorie (BR-S-08, BR-Z-08):
| Kategorie | Bemessungsgrundlage (BT-116) | Steuerbetrag (BT-117) |
|---|---|---|
| S, 19 % | 1.000,00 + 100,00 + 500,00 = 1.600,00 | 1.600,00 × 19 % = 304,00 |
| Z, 0 % | −100,00 | 0,00 |
// Kategorie S, 19 %: Positionen 1, 2 und 4 → 1.000,00 + 100,00 + 500,00 = 1.600,00
invoice.AddApplicableTradeTax(
basisAmount: 1600.00m,
percent: 19m,
taxAmount: 304.00m,
typeCode: TaxTypes.VAT,
categoryCode: TaxCategoryCodes.S);
// Kategorie Z, 0 %: nur Position 3 → Bemessungsgrundlage −100,00, Steuer 0,00
invoice.AddApplicableTradeTax(
basisAmount: -100.00m,
percent: 0m,
taxAmount: 0.00m,
typeCode: TaxTypes.VAT,
categoryCode: TaxCategoryCodes.Z);
' Kategorie S, 19 %: Positionen 1, 2 und 4 → 1.000,00 + 100,00 + 500,00 = 1.600,00
invoice.AddApplicableTradeTax(
basisAmount:=1600D,
percent:=19D,
taxAmount:=304D,
typeCode:=TaxTypes.VAT,
categoryCode:=TaxCategoryCodes.S)
' Kategorie Z, 0 %: nur Position 3 → Bemessungsgrundlage −100,00, Steuer 0,00
invoice.AddApplicableTradeTax(
basisAmount:=-100D,
percent:=0D,
taxAmount:=0D,
typeCode:=TaxTypes.VAT,
categoryCode:=TaxCategoryCodes.Z)
Im XML stehen die beiden Aufschlüsselungen nebeneinander. Die negative Bemessungsgrundlage ist kein Fehler, sondern der Kern der Abbildung:
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>304.00</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>1600.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>0.00</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>-100.00</ram:BasisAmount>
<ram:CategoryCode>Z</ram:CategoryCode>
<ram:RateApplicablePercent>0.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
7. Zahlungsbedingungen
Eine Angabe zur Fälligkeit braucht jede Rechnung mit positivem Zahlbetrag (BR-CO-25) – entweder als Datum (BT-9) oder als Text (BT-20). Hier stehen beide.
// BT-20 und BT-9: Zahlungsbedingung als Freitext plus Fälligkeitsdatum.
invoice.AddTradePaymentTerms(
description: "Zahlbar innerhalb 30 Tagen ohne Abzug.",
dueDate: new DateTime(2025, 10, 31));
' BT-20 und BT-9: Zahlungsbedingung als Freitext plus Fälligkeitsdatum.
invoice.AddTradePaymentTerms(
description:="Zahlbar innerhalb 30 Tagen ohne Abzug.",
dueDate:=New DateTime(2025, 10, 31))
8. Gesamtsummen
Die Summen ergeben sich aus den Positionen und den beiden Aufschlüsselungen:
| BT-Code | Parameter | Rechenweg |
|---|---|---|
| BT-106 | lineTotalAmount |
1.000,00 + 100,00 − 100,00 + 500,00 = 1.500,00 |
| BT-109 | taxBasisAmount |
1.600,00 + (−100,00) = 1.500,00 |
| BT-110 | taxTotalAmount |
304,00 + 0,00 = 304,00 |
| BT-112 | grandTotalAmount |
1.500,00 + 304,00 = 1.804,00 |
| BT-115 | duePayableAmount |
1.804,00 |
19 % von 1.500,00 wären 285,00 – im Beleg stehen 304,00. Die Differenz von 19,00 ist genau die Altteilesteuer. Die Validierung beanstandet das nicht: Die EN 16931 prüft den Steuerbetrag je Aufschlüsselung (BR-CO-17) und die Summe der Aufschlüsselungen (BR-CO-14), nicht das Verhältnis von BT-110 zu BT-109.
invoice.SetTotals(
lineTotalAmount: 1500.00m, // BT-106
taxBasisAmount: 1500.00m, // BT-109
taxTotalAmount: 304.00m, // BT-110 – 19,00 mehr als 19 % von 1.500,00
grandTotalAmount: 1804.00m, // BT-112
duePayableAmount: 1804.00m); // BT-115
invoice.SetTotals(
lineTotalAmount:=1500D, ' BT-106
taxBasisAmount:=1500D, ' BT-109
taxTotalAmount:=304D, ' BT-110 – 19,00 mehr als 19 % von 1.500,00
grandTotalAmount:=1804D, ' BT-112
duePayableAmount:=1804D) ' BT-115
9. Speichern und prüfen
invoice.Save("Altteilesteuer.xml",
ZUGFeRDVersion.Version25,
Profile.Extended,
ZUGFeRDFormats.CII);
invoice.Save("Altteilesteuer.xml",
ZUGFeRDVersion.Version25,
Profile.Extended,
ZUGFeRDFormats.CII)
Die Abbildung hängt nicht am Profil EXTENDED. Positionen, Steuern und Summen lassen sich unverändert auch als BASIC, COMFORT (EN 16931) oder XRechnung speichern, in CII ebenso wie in UBL. Für XRechnung kommen die dort üblichen Pflichtangaben hinzu, unter anderem Leitweg-ID (BT-10), Name des Ansprechpartners (BT-41), elektronische Adressen von Verkäufer und Käufer (BT-34, BT-49) und die Zahlungsangaben (BG-16).
Ob der Beleg dem Regelwerk entspricht, prüft der Validator – im Browser oder direkt aus Ihrem Code heraus. Eine Lesefassung für Menschen erzeugt der Visualizer. Beides sowie die ausführliche Dokumentation dazu finden Sie im Kunden-Bereich; wie Sie dorthin kommen, steht unter Los geht’s.