Die YAML-Datei beschreibt, wie CSV-Spalten auf Rechnungsdaten und Positionen gemappt werden.
Grundstruktur#
csv:
separator: ","
encoding: "UTF-8"
hasHeader: true
decimalSeparator: "."
dateFormat: "dd.MM.yyyy"
zugferd:
version: "2.3"
profile: "Extended"
format: "CII"
mapping:
invoice: {}
buyer: {}
seller: {}
delivery: {}
orderReference: {}
lineItems: {}
totals: {}
paymentTerms: {}FieldMapping#
Fast alle Mapping-Felder verwenden dieselbe FieldMapping-Struktur:
feldName:
value: "Fester Wert"
column: "CSV_SPALTE"
default: "Fallback"
scheme: "VA"
rules:
- when:
column: "PRODUCT_CODE"
regex: "^003"
value: "DAY"| Schlüssel | Beschreibung |
|---|---|
value | Fester Wert. Hat Vorrang vor allen anderen Angaben. |
column | CSV-Spalte, aus der der Wert gelesen wird. |
default | Fallback, wenn value, column und rules keinen Wert liefern. |
scheme | Optionaler Schema-Qualifier, z. B. für elektronische Adresse oder Steuerregistrierung. |
rules | Geordnete Regex-Regeln, mit denen Werte aus anderen CSV-Spalten abgeleitet werden. |
Auflösungsreihenfolge:
value, wenn gesetztcolumn, wenn gesetzt und der CSV-Wert nicht leer istrulesvon oben nach untendefault, wenn gesetzt- leerer String bzw. fachlicher Code-Fallback im Mapper
Regex-Regeln#
Regex-Regeln erlauben flexible Ableitungen ohne Codeänderung. Die erste passende Regel gewinnt. Ungültige Ausdrücke werden geloggt und ignoriert.
unitCode:
default: "C62"
rules:
- when:
column: "PRODUCT_CODE"
regex: "^002"
value: "ANN"
- when:
column: "PRODUCT_CODE"
regex: "^003"
value: "DAY"
- when:
column: "PRODUCT_NAME"
regex: "(?i)vor-ort-schulung|schulung"
value: "DAY"Groß-/Kleinschreibung lässt sich mit Inline-Optionen wie (?i) steuern. Im columns-Modus werden Regelspalten positionsbezogen aufgelöst: bei column: "PRODUCT_CODE" und Suffix-Muster wird für Position 0 PRODUCT_CODE_0, für Position 1 PRODUCT_CODE_1 geprüft.
Beispiel für den Rechnungskopf#
invoice:
invoiceNumber:
column: "INVOICE_NO"
invoiceDate:
column: "INVOICE_DUEDATE"
currency:
value: "EUR"
orderReferenceId:
column: "SALESORDER_ID"
referenceOrderNo:
column: "SALESORDER_ID"
name:
value: "WARENRECHNUNG"
note:
column: "INVOICE_NOTE"Beispiel für Käuferdaten#
buyer:
name:
column: "ACCOUNT_NAME"
postalCode:
column: "INVOICE_BILL_CODE"
city:
column: "INVOICE_BILL_CITY"
street:
column: "INVOICE_BILL_STREET"
country:
value: "DE"
contact:
column: "CONTACT_LASTNAME"
taxId:
column: "BUYER_VAT_ID"
taxScheme:
value: "VA"
electronicAddress:
column: "BUYER_VAT_ID"
scheme: "GermanyVatNumber"taxScheme akzeptiert FC (Steuernummer) oder VA (Umsatzsteuer-ID). Unterstützte Werte für scheme bei electronicAddress: GermanyVatNumber, LuxemburgVatNumber.
Beispiel für Verkäuferdaten#
Verkäuferdaten können aus CSV-Spalten kommen oder als feste Stammdaten in der YAML-Datei stehen. Für wiederkehrende Verkäuferdaten sind feste Werte empfohlen.
seller:
name:
value: "Muster Lieferant GmbH"
postalCode:
value: "80333"
city:
value: "Muenchen"
street:
value: "Lieferantenstrasse 20"
country:
value: "DE"
taxRegistrations:
- value: "201/113/40209"
scheme: "FC"
- value: "DE123456789"
scheme: "VA"
electronicAddress:
value: "DE123456789"
scheme: "GermanyVatNumber"| Scheme | Bedeutung |
|---|---|
FC | Steuernummer |
VA | Umsatzsteuer-ID |
taxRegistrations unterstützt sowohl feste Werte per value als auch CSV-Werte per column.
Beispiel für Lieferdaten#
delivery:
deliveryNoteNumber:
column: "DELIVERY_NOTE_NO"
deliveryNoteDate:
column: "DELIVERY_NOTE_DATE"
actualDeliveryDate:
column: "DELIVERY_DATE"Alle drei Felder sind optional. deliveryNoteNumber und deliveryNoteDate werden gemeinsam als Lieferscheinreferenz geschrieben. actualDeliveryDate setzt das tatsächliche Lieferdatum.
Beispiel für Bestellreferenz#
orderReference:
orderNumber:
column: "ORDER_NO"
orderDate:
column: "ORDER_DATE"orderNumber entspricht BT-13 (Bestellnummer des Käufers). orderDate ist optional.
Beispiel für lineItems im rows-Modus mit Rabatt#
lineItems:
mode: "rows"
fields:
name:
column: "Artikel_Name"
description:
column: "Artikel_Beschreibung"
sellerAssignedId:
column: "Artikelnummer"
netUnitPrice:
column: "Einzelpreis_Netto"
billedQuantity:
column: "Menge"
taxPercent:
column: "MwSt_Prozent"
unitCode:
value: "C62"
taxType:
value: "VAT"
taxCategoryCode:
value: "S"
allowanceCharge:
enabled: true
isDiscount:
value: true
chargePercentage:
column: "Rabatt_Prozent"
reason:
column: "Rabatt_Grund"isDiscount: true erzeugt einen Rabatt (TradeAllowance), false einen Zuschlag (TradeCharge). Im columns-Modus wird Rabatt stattdessen über discountPercent in fields konfiguriert.
Beispiel für lineItems im columns-Modus#
lineItems:
mode: "columns"
columnPattern:
style: "suffix"
separator: "_"
startIndex: 0
zeroPadding: 0
fields:
name:
column: "PRODUCT_NAME"
sellerAssignedId:
column: "PRODUCT_CODE"
netUnitPrice:
column: "PRODUCT_PRICE"
billedQuantity:
column: "PRODUCT_QUANTITY"
taxPercent:
column: "INVOICE_TAX"
discountPercent:
column: "PRODUCT_DISCOUNT"
fixedFields:
unitCode:
default: "C62"
rules:
- when:
column: "PRODUCT_CODE"
regex: "^002"
value: "ANN"
- when:
column: "PRODUCT_CODE"
regex: "^003"
value: "DAY"
- when:
column: "PRODUCT_NAME"
regex: "(?i)vor-ort-schulung|schulung"
value: "DAY"
taxType:
value: "VAT"
taxCategoryCode:
value: "S"Wichtig dabei:
PRODUCT_NAME,PRODUCT_PRICEund ähnliche Felder werden als Fragment für nummerierte Spalten wiePRODUCT_NAME_0verwendet.INVOICE_TAXkann im selben Block als globale Rechnungs-Spalte verwendet werden und gilt dann für jede erzeugte Position.sellerAssignedIdist für interne Produktnummern.descriptionbleibt für echte Artikelbeschreibungen reserviert.fixedFieldsunterstützt vollständigesFieldMappinginklusiverules— nützlich z. B. für positionsabhängige Einheitencodes.
Rabatte#
discountPercent akzeptiert Werte wie 10, 10.00 oder 10%. Der Rabatt wird validierungsfreundlich als rabattierter Netto-Einzelpreis abgebildet:
- Brutto-Listenpreis →
GrossPriceProductTradePrice(= Originalpreis) - Rabattierter Netto-Einzelpreis →
NetPriceProductTradePrice(netPrice × (1 − percent/100), 4 Dezimalstellen) - Zeilennettobetrag = rabattierter Einzelpreis × Menge
Es wird kein AppliedTradeAllowanceCharge für discountPercent-Positionsrabatte erzeugt. Dadurch bleiben EN-16931-Regeln wie BR-S-08 konsistent.
Im rows-Modus gibt es zusätzlich lineItems.allowanceCharge für weitere Rabatte oder Zuschläge auf Positionsebene, unabhängig von discountPercent.
Summen#
Automatisch (empfohlen, wenn Preise, Mengen und Steuerprozentsatz vollständig aus der CSV kommen):
totals:
mode: "auto"Manuell (nur sinnvoll, wenn die CSV fachlich geprüfte Summen liefert):
totals:
mode: "manual"
lineTotalAmount:
column: "INVOICE_SUBTOTAL"
allowanceTotalAmount:
value: "0"
taxBasisAmount:
column: "INVOICE_SUBTOTAL"
taxTotalAmount:
column: "INVOICE_TAXTOTAL"
grandTotalAmount:
column: "INVOICE_TOTAL"
totalPrepaidAmount:
value: "0"Empfehlung#
Die YAML-Datei sollte gemeinsam mit dem CSV-Export versioniert werden. Dadurch bleibt nachvollziehbar, welche CSV-Struktur zu welcher Ausgabe geführt hat.
Praxisbeispiel: columns-Modus mit suffix-Spalten.