Einleitung
Meine Anwendung ist wie bei Vorbereitung beschrieben vorbereitet. Mit dem Ablauf habe ich mich vertraut gemacht und wähle den direkten Weg über das Füllen der Tabellen. Die Umstellung meiner Anwendung kann beginnen.
Die Anwendung ist vergleichsweise einfach aufgebaut. Die Kopfdaten einer Rechnung stehen in der Tabelle tblRechnungen. Die Positionsdaten stehen in der Tabelle tblRechnungPositionen. Die Werte in den Tabellen werden beim Erstellen der Rechnung aus den Stammdaten von Auftrag, Kunden etc. zusammengestellt. In dern Rechnungstabellen hat schon eine Aggregation stattgefunden. Über Schlüsselwerte kann auf die ursprünglichen Auftragswerte zurückgegriffen werden. Als Zahlungsmöglichkeit ist ausschließlich eine Überweisung vorgesehen.
Das Vorgehen strukturiere ich anhand der Struktur einer XRechnung laut Spezifikation. Durch das eingeschränkte Modell meiner Rechnung werde ich nicht alle Möglichkeiten der XRechnung nutzen.
Die Spezifikation
Alle notwendigen Informationen finden sich in der Spezifikation XRechnung. Bei der Anleitung verweise ich immer wieder auf die entsprechenden Stellen. Es empfiehlt sich, dass Dokument verfügbar zu haben.
Wie die einzelnen Bereiche (Business Groups) einer Rechnung in Beziehung zueinander stehen, ob und wie oft sie angegeben werden müssen, kann man in der Strukturabbildung erkennen. Das ist Abbildung 9.1 auf Seite 25.

Welche Daten (Business Terms) in welcher Business Group (BG) verpflichtend sind, steht in der der Beschreibung zu den entsprechenden BGs ab Seite 33.
Das Vorgehen
Für jede Business Group ist in der Datenbank eine passende Tabelle vorbereitet. Ausgehend von BG-0 INVOICE wird jede BG mit den entsprechenden Daten aus dem bisherigen Rechnungsmodell gefüllt. Ein RecordSet hält die Rechnungsdaten bereit und ein RecordSet repräsentiert die BG mit ihren Business Terms und nimmt die Daten auf. Danach werden die eingebetteten Business Groups nach demselben Schema verarbeitet.
Inden folgenden Absätzen kann am Code nachvollzogen werden, wie und welche Business Terms mit Daten versorgt werden. Am Ende kommt eine valide XRechnung heraus.
Im letzten Absatz wird die integration in eine bestehende Anwendung demonstriert.
INVOICE – BG-0
Alles beginnt mit dem Wurzelelement INVOICE.
Das semantische Datenmodell beschreibt eine Baumstruktur bestehend aus geschachtelten Informationselementen. Das Wurzelelement dieser Baumstruktur wird im Standard XRechnung als „INVOICE“ bezeichnet. Es stellt selbst kein Informationselement dar, besitzt somit beispielsweise wie sein Pendant aus der EN 16931-1 keine eigene Kennung, wurde jedoch als Hilfsmittel eingeführt, um in seinem Kontext die obersten Informationselemente der Rechnung beschreiben zu können.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 33
Die Function invoice_Add bekommt als Aufrufparameter den Primärschlüsselwert der Tabelle tblRechnungen. Wenn zu dem Wert eine Rechnung gefunden wird, wird eine INVOICE angelegt. Zuerst werden die Business Terms der INVOICE eingetragen. Danach werden die Business Groups nacheinander mit den Rechnungsdaten gefüllt.
Public Function invoice_Add(ByVal lng_RechnungID As Long) As Long
Dim lng_INV_ID As Long
Dim rs_Rechnung As DAO.Recordset
Dim rs_INVOICE As DAO.Recordset
Set rs_Rechnung = CodeDb.OpenRecordset("SELECT * " & _
"FROM tblRechnungen " & _
"WHERE Rechnung = " & lng_RechnungID) ' Rechnung abrufen
If rs_Rechnung.RecordCount = 1 Then ' Rechnung gefunden und eindeutig
Set rs_INVOICE = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_tbl_INVOICE " _
, dbOpenDynaset, dbAppendOnly) ' INVOICE zum Neuanlegen
rs_INVOICE.AddNew ' Erstellen
rs_INVOICE!INV_CREATE = Now ' Zeitpunkt Erstellung
rs_INVOICE.Update ' Speichern
rs_INVOICE.MoveFirst
rs_INVOICE.MoveLast
lng_INV_ID = rs_INVOICE!INV_ID ' ID auslesen
rs_INVOICE.Edit ' Bearbeiten
' Business Terms eintragen
rs_INVOICE!INV_INVOICE_NUMBER_CONTENT = rs_Rechnung!Rechnungsnummer ' BT-1
rs_INVOICE!INV_INVOICE_ISSUE_DATE = rs_Rechnung!RechnungDatum ' BT-2
rs_INVOICE!INV_INVOICE_TYPE_CODE = "380" ' BT-3 - vgl. vbax_tbl_CODELIST
rs_INVOICE!INV_INVOICE_CURRENCY_CODE = rs_Rechnung!Währung ' BT-5 - vgl. vbax_tbl_CODELIST
rs_INVOICE!INV_BUYER_REFERENCE = Nz(rs_Rechnung!ExterneAuftragsnummer, "n.a.") ' BT-10
rs_INVOICE!INV_PROJECT_REFERENCE = rs_Rechnung!Auftragsnummer ' BT-11
rs_INVOICE!INV_PAYMENT_TERMS = "Zahlbar innerhalb von 14 Tagen, ohne Abzug." ' BT-20
rs_INVOICE.Update
' Business Groups eintragen
invoice_note_Add lng_INV_ID, lng_RechnungID ' BG-1
process_control_Add lng_INV_ID ' BG-2
seller_Add lng_INV_ID ' BG-4
buyer_Add lng_INV_ID, lng_RechnungID ' BG-7
payment_Instructions_Add lng_INV_ID ' BG-16
invoice_line_Add lng_INV_ID, lng_RechnungID ' BG-25
vat_breakdown_Add lng_INV_ID ' BG-23
document_totals_Add lng_INV_ID ' BG-22
rs_INVOICE.Close: Set rs_INVOICE = Nothing
End If
rs_Rechnung.Close: Set rs_Rechnung = Nothing
invoice_Add = lng_INV_ID
End Function
INVOICE NOTE – BG-1
Eine Gruppe von Informationselementen für rechnungsrelevante Erläuterungen mit Hinweisen auf den Rechnungsbetreff.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 50
Die Function invoice_note_Add bekommt als Aufrufparameter den Primärschlüsselwert der neu angelegen INVOICE und der Tabelle tblRechnungen. Bei meiner Anwendung stehen die relevanten Informationen in den Hauptdaten zur Rechnung. Das Laden der Daten ist in dieser Funktionc redundant, weil sie von der aufrufenden Funktion bereits geladen wurden. Da sie bei einer anderen Architektur aber auch in einer separaten Tabelle stehen könnten, finde ich diesen doppelten Ansatz trotzdem sinnvoll.
Bevor eine weitere INVOICE NOTE angelegt wird, wird immer geprüft, ob es auch einen Wert dafür gibt.
Private Function invoice_note_Add(ByVal lng_INV_ID As Long, ByVal lng_RechnungID As Long) As Long
Dim rs_Rechnung As DAO.Recordset
Dim rs_INVOICE_NOTE As DAO.Recordset
' BG-1 INVOICE NOTE
Set rs_Rechnung = CodeDb.OpenRecordset("SELECT * " & _
"FROM tblRechnungen " & _
"WHERE Rechnung = " & lng_RechnungID) ' Rechnung abrufen
Set rs_INVOICE_NOTE = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_tbl_INVOICE_NOTE " _
, dbOpenDynaset, dbAppendOnly) ' INVOICE_NOTE zum Neuanlegen
If Len(Nz(rs_Rechnung!RechnungBetreff, "")) > 0 Then ' INVOICE NOTE für Betreff anlegen
rs_INVOICE_NOTE.AddNew
rs_INVOICE_NOTE!INT_INV_ID = lng_INV_ID ' Fremdschlüssel
rs_INVOICE_NOTE!INT_INVOICE_NOTE = rs_Rechnung!RechnungBetreff ' BT-22
rs_INVOICE_NOTE.Update
End If
If Len(Nz(rs_Rechnung!RechnungText, "")) > 0 Then ' INVOICE NOTE für Text anlegen
rs_INVOICE_NOTE.AddNew
rs_INVOICE_NOTE!INT_INV_ID = lng_INV_ID ' Fremdschlüssel
rs_INVOICE_NOTE!INT_INVOICE_NOTE = rs_Rechnung!RechnungText ' BT-22
rs_INVOICE_NOTE.Update
End If
If Len(Nz(rs_Rechnung!RechnungSchluß, "")) > 0 Then ' INVOICE NOTE für Schluß-1 anlegen
rs_INVOICE_NOTE.AddNew
rs_INVOICE_NOTE!INT_INV_ID = lng_INV_ID ' Fremdschlüssel
rs_INVOICE_NOTE!INT_INVOICE_NOTE = rs_Rechnung!RechnungSchluß ' BT-22
rs_INVOICE_NOTE.Update
End If
If Len(Nz(rs_Rechnung!Rechnungsschluss2, "")) > 0 Then ' INVOICE NOTE für Rechnungsschluss2 anlegen
rs_INVOICE_NOTE.AddNew
rs_INVOICE_NOTE!INT_INV_ID = lng_INV_ID ' Fremdschlüssel
rs_INVOICE_NOTE!INT_INVOICE_NOTE = rs_Rechnung!Rechnungsschluss2 ' BT-22
rs_INVOICE_NOTE.Update
End If
If Len(Nz(rs_Rechnung!Rechnungsschluss3, "")) > 0 Then ' INVOICE NOTE für Rechnungsschluss2 anlegen
rs_INVOICE_NOTE.AddNew
rs_INVOICE_NOTE!INT_INV_ID = lng_INV_ID ' Fremdschlüssel
rs_INVOICE_NOTE!INT_INVOICE_NOTE = rs_Rechnung!Rechnungsschluss3 ' BT-22
rs_INVOICE_NOTE.Update
End If
rs_INVOICE_NOTE.Close: Set rs_INVOICE_NOTE = Nothing
rs_Rechnung.Close: Set rs_Rechnung = Nothing
End Function
PROCESS CONTROL – BG-2
Eine Gruppe von Informationselementen, die Informationen über den Geschäftsprozess und für die Rechnung geltende Regeln enthalten.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 56
In den BT dieser BG wird festgelegt, nach welcher Spezifikation die Rechnung aufgebaut ist und wie sie geprüft werden muss. In der Regel werden hier feste Werte eingetragen, die für alle ausgestellten Rechnungen dann identisch sind.
Die Function process_control_Add bekommt als Aufrufparameter den Primärschlüsselwert der neu angelegen INVOICE. Zu der INV_ID wird eine notwendiger PROCESS CONTROL Datensatz angelegt.
Private Function process_control_Add(ByVal lng_INV_ID As Long) As Long
Dim rs_PROCESS_CONTROL As DAO.Recordset
' BG-2 PROCESS CONTROL
' Eine Gruppe von Informationselementen, die Informationen über den Geschäftsprozess und für die Rechnung geltende Regeln enthalten.
Set rs_PROCESS_CONTROL = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_tbl_PROCESS_CONTROL " _
, dbOpenDynaset, dbAppendOnly) ' PROCESS_CONTROL zum Neuanlegen
rs_PROCESS_CONTROL.AddNew
rs_PROCESS_CONTROL!PRC_INV_ID = lng_INV_ID ' Fremdschlüssel
rs_PROCESS_CONTROL!PRC_BUSINESS_PROCESS_TYPE = "urn:fdc:peppol.eu:2017:poacc:billing:01:1.0" ' BT-23
rs_PROCESS_CONTROL!PRC_SPECIFICATION_IDENTIFIER_CONTENT = "urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0" ' BT-24 (XRechnung)
' rs_PROCESS_CONTROL!PRC_SPECIFICATION_IDENTIFIER_CONTENT = "urn:cen.eu:en16931:2017" ' BT-24 (EN 16931)
rs_PROCESS_CONTROL.Update
rs_PROCESS_CONTROL.Close: Set rs_PROCESS_CONTROL = Nothing
End Function
SELLER – BG-4
Eine Gruppe von Informationselementen, die Informationen über den Verkäufer enthalten.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 57
Der Verkäufer wird auch als Rechnungsersteller bezeichnit. In meiner Anwendung bin ich der Verkäufer. Meine Stammdaten habe ich in der Tabelle tblParameter gespeichert, auf die ich über die Function parameter_GET(„…“) zugreifen kann. So oder so ähnlich ist das sicher in vielen Anwendungen umgesetzt.
Die Function seller_Add bekommt als Aufrufparameter den Primärschlüsselwert der neu angelegen INVOICE. Zu der INV_ID wird ein SELLER Datensatz angelegt. Nach den BT werden die beiden notwendigen BG angelegt. Als Aufrufparemeter wird der Primörschlüssel des neuen SELLER Datensatzes mitgegeben.
Private Function seller_Add(ByVal lng_INV_ID As Long) As Long
Dim rs_SELLER As DAO.Recordset
Dim lng_SLR_ID As Long
' BG-4 SELLER
Set rs_SELLER = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_tbl_SELLER " _
, dbOpenDynaset, dbAppendOnly) ' SELLER zum Neuanlegen
rs_SELLER.AddNew
rs_SELLER!SLR_INV_ID = lng_INV_ID ' Fremdschlüssel
' Business Terms eintragen
rs_SELLER!SLR_SELLER_NAME = parameter_GET("Rechnung_Von") ' BT-27
rs_SELLER!SLR_SELLER_ELECTRONIC_ADDRESS_CONTENT = parameter_GET("Rechnung_EMail") ' BT.34
rs_SELLER!SLR_SELLER_ELECTRONIC_ADDRESS_SCHEME_IDENTIFIER = "EM"
rs_SELLER!SLR_SELLER_VAT_IDENTIFIER_CONTENT = parameter_GET("Umsatzsteuer_ID") ' BT-31
rs_SELLER!SLR_SELLER_VAT_IDENTIFIER_SCHEME_IDENTIFIER = "VA"
rs_SELLER!SLR_SELLER_TAX_REGISTRATION_IDENTIFIER_CONTENT = parameter_GET("Steuer_Nummer") ' BT-32
rs_SELLER!SLR_SELLER_TAX_REGISTRATION_IDENTIFIER_SCHEME_IDENTIFIER = "FC"
rs_SELLER.Update
rs_SELLER.MoveFirst
lng_SLR_ID = rs_SELLER!SLR_ID ' neuer Primärschlüssel
rs_SELLER.Close: Set rs_SELLER = Nothing
' Business Groups eintragen
seller_contact_Add lng_SLR_ID ' BG-5
seller_postal_address_Add lng_SLR_ID ' BG-6
End Function
SELLER POSTAL ADDRESS – BG-5
Eine Gruppe von Informationselementen, die Informationen über die Verkäuferanschrift enthalten.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 59
Die Werte zur Verkäuferanschrift kommen ebenfalls aus der Tabelle tblParameter.
Private Function seller_postal_address_Add(ByVal lng_SLR_ID As Long) As Long
Dim rs_SELLER_POSTAL_ADDRESS As DAO.Recordset
' BG-5 SELLER POSTAL ADDRESS
Set rs_SELLER_POSTAL_ADDRESS = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_tbl_SELLER_POSTAL_ADDRESS " _
, dbOpenDynaset, dbAppendOnly) ' SELLER POSTAL ADDRESS zum Neuanlegen
rs_SELLER_POSTAL_ADDRESS.AddNew
rs_SELLER_POSTAL_ADDRESS!SPA_SLR_ID = lng_SLR_ID ' Fremdschlüssel
' Business Terms eintragen
rs_SELLER_POSTAL_ADDRESS!SPA_SELLER_ADDRESS_LINE_1 = parameter_GET("Rechnung_Von_Anschrift") ' BT-35
rs_SELLER_POSTAL_ADDRESS!SPA_SELLER_CITY = parameter_GET("Rechnung_Von_Ort") ' BT-37
rs_SELLER_POSTAL_ADDRESS!SPA_SELLER_POST_CODE = parameter_GET("Rechnung_Von_PLZ") ' BT-38
rs_SELLER_POSTAL_ADDRESS!SPA_SELLER_COUNTRY_CODE = parameter_GET("Rechnung_Von_Land") ' BT-40 - vgl. vbax_tbl_CODELIST
rs_SELLER_POSTAL_ADDRESS.Update
rs_SELLER_POSTAL_ADDRESS.Close: Set rs_SELLER_POSTAL_ADDRESS = Nothing
End Function
SELLER CONTACT – BG-6
Eine Gruppe von Informationselementen, die Kontaktinformationen des Verkäufers enthalten.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 58
Die Kontaktinformationen kommen ebenfalls aus der Tabelle tblParameter.
Private Function seller_contact_Add(ByVal lng_SLR_ID As Long) As Long
Dim rs_SELLER_CONTACT As DAO.Recordset
' BG-6 SELLER CONTACT
Set rs_SELLER_CONTACT = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_tbl_SELLER_CONTACT " _
, dbOpenDynaset, dbAppendOnly) ' SELLER CONTACT zum Neuanlegen
rs_SELLER_CONTACT.AddNew
rs_SELLER_CONTACT!SCN_SLR_ID = lng_SLR_ID ' Fremdschlüssel
' Business Terms eintragen
rs_SELLER_CONTACT!SCN_SELLER_CONTACT_POINT = parameter_GET("Rechnung_Kontakt") ' BT-41
rs_SELLER_CONTACT!SCN_SELLER_CONTACT_TELEPHONE_NUMBER = parameter_GET("Rechnung_Kontakt_Nummer") ' BT-42
rs_SELLER_CONTACT!SCN_SELLER_CONTACT_EMAIL_ADDRESS = parameter_GET("Rechnung_Kontakt_Mail") ' BT-43
rs_SELLER_CONTACT.Update
rs_SELLER_CONTACT.Close: Set rs_SELLER_CONTACT = Nothing
End Function
BUYER – BG-7
Eine Gruppe von Informationselementen, die Informationen über den Erwerber enthalten.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 38
Der Erwerber wird auch als Rechnungsempfänger oder Kunde bezeichnet. Die entsprechenden Daten stehen bereits in der Tabelle tblRechnungen. Dort sind sie aber schon aggregiert, so dass ich z.B. bei der Anschrift nicht mehr einzeln auf Postleitzahl und Ort zugreifen kann. In tblRechnungen steht aber auch der Primärschlüssel zum Auftrag und damit zum Erwerber. Damit hole ich die Daten direkt aus den Stammdaten. Dieser Weg ist aber nur unmittelbar beim Erstellen der Rechnung möglich, weil sich die Stammdaten später ändern können und somit nicht mehr dier korrekten Daten ermittelt werden können.
Die Function buyer_Add bekommt als Aufrufparameter den Primärschlüsselwert der neu angelegen INVOICE und den Primärschlüssel der Rechnung. Zur Rechnung werden die Kundendaten geladen und zur INV_ID ein BUYER Datensatz angelegt. Nach den BT werden die beiden BG angelegt. Als Aufrufparameter wird der Primörschlüssel des neuen BUYER Datensatzes mitgegeben
Private Function buyer_Add(ByVal lng_INV_ID As Long, ByVal lng_RechnungID As Long) As Long
Dim rs_Kunde As DAO.Recordset
Dim rs_BUYER As DAO.Recordset
Dim lng_BYR_ID As Long
' BG-7 BUYER
Set rs_Kunde = CodeDb.OpenRecordset("SELECT tblRechnungen.* " & _
" , tblAufträge.* " & _
" , qryKontakt.* " & _
"FROM ( tblRechnungen " & _
" LEFT JOIN " & _
" tblAufträge ON tblRechnungen.Auftrag = tblAufträge.Auftrag) " & _
" LEFT JOIN " & _
" qryKontakt ON tblAufträge.Kontakt = qryKontakt.Kontakt " & _
"WHERE tblRechnungen.Rechnung = " & lng_RechnungID) ' Auftrag bzw. Kunde zu Rechnung abrufen
Set rs_BUYER = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_tbl_BUYER " _
, dbOpenDynaset, dbAppendOnly) ' BUYER zum Neuanlegen
rs_BUYER.AddNew
rs_BUYER!BYR_INV_ID = lng_INV_ID ' Fremdschlüssel
' Business Terms eintragen
rs_BUYER!BYR_BUYER_NAME = rs_Kunde!KontaktName ' BT-44
rs_BUYER!BYR_BUYER_VAT_IDENTIFIER_CONTENT = Nz(rs_Kunde!UmsatzsteuerID, "") ' BT-48
If Len(Nz(rs_Kunde!UmsatzsteuerID, "")) > 0 Then
rs_BUYER!BYR_BUYER_VAT_IDENTIFIER_SCHEME_IDENTIFIER = "VAT"
End If
rs_BUYER!BYR_BUYER_ELECTRONIC_ADDRESS_CONTENT = Nz(rs_Kunde![qryKontakt.EMail], "") ' BT-49
If Len(Nz(rs_Kunde![qryKontakt.EMail])) > 0 Then
rs_BUYER!BYR_BUYER_ELECTRONIC_ADDRESS_SCHEME_IDENTIFIER = "EM"
End If
rs_BUYER.Update
rs_BUYER.MoveFirst
lng_BYR_ID = rs_BUYER!BYR_ID ' neuer Primärschlüssel
rs_BUYER.Close: Set rs_BUYER = Nothing
' Business Groups eintragen
buyer_postal_address_Add lng_BYR_ID, Nz(rs_Kunde![qryKontakt.Kontakt], 0) ' BG-8
buyer_contact_Add lng_BYR_ID, Nz(rs_Kunde!AnsprechPartner, 0) ' BG-9
rs_Kunde.Close: Set rs_Kunde = Nothing
End Function
BUYER POSTAL ADDRESS – BG-8
Eine Gruppe von Informationselementen, die Informationen über die Anschrift des Erwerbers enthalten. Es ist eine gültige, vollständige Anschrift anzugeben.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 40
Die Werte zur Anschrift des Erwerbers kommen aus der Abfrage qryKontakt. Der passende Schlüsselwert kommt vom Auftrag zur Rechnung.
Private Function buyer_postal_address_Add(ByVal lng_BYR_ID As Long, ByVal lng_Kontakt As Long) As Long
Dim rs_BUYER_POSTAL_ADDRESS As DAO.Recordset
Dim rs_Kontakt As DAO.Recordset
' BG-8 BUYER POSTAL ADDRESS
Set rs_BUYER_POSTAL_ADDRESS = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_tbl_BUYER_POSTAL_ADDRESS " _
, dbOpenDynaset, dbAppendOnly) ' BUYER POSTAL ADDRESS zum Neuanlegen
Set rs_Kontakt = CodeDb.OpenRecordset("SELECT * " & _
"FROM qryKontakt " & _
"WHERE Kontakt = " & lng_Kontakt)
If rs_Kontakt.RecordCount > 0 Then ' Adresse gefunden
rs_Kontakt.MoveFirst
rs_BUYER_POSTAL_ADDRESS.AddNew
rs_BUYER_POSTAL_ADDRESS!BPA_BYR_ID = lng_BYR_ID ' Fremdschlüssel
' Business Terms eintragen
rs_BUYER_POSTAL_ADDRESS!BPA_BUYER_ADDRESS_LINE_1 = rs_Kontakt!Straße & " " & rs_Kontakt!Hausnummer ' BT-50
rs_BUYER_POSTAL_ADDRESS!BPA_BUYER_CITY = rs_Kontakt!Ort ' BT-52
rs_BUYER_POSTAL_ADDRESS!BPA_BUYER_POST_CODE = rs_Kontakt!PLZ ' BT-53
rs_BUYER_POSTAL_ADDRESS!BPA_BUYER_COUNTRY_CODE = rs_Kontakt!ISO_3166 ' BT-55 - vgl. vbax_tbl_CODELIST
rs_BUYER_POSTAL_ADDRESS.Update
End If
rs_BUYER_POSTAL_ADDRESS.Close: Set rs_BUYER_POSTAL_ADDRESS = Nothing
End Function
BUYER CONTACT – BG-9
Eine Gruppe von Informationselementen, die Angaben zum Ansprechpartner oder der Kontaktstelle beim Erwerber enthalten. Kontaktinformationen sollen nicht zum Zweck der Weiterleitung der empfangenen Rechnung durch die rechnungsempfangende Stelle verwendet werden; für diesen Zweck soll die „Buyer reference“ (BT-10) verwendet werden.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 39
Die Kontaktinformationen kommen aus der Abfrage qryKontakt. Der passende Schlüsselwert kommt aus der Spalte Ansprechpartner vom Auftrag zur Rechnung.
Private Function buyer_contact_Add(ByVal lng_BYR_ID As Long, ByVal lng_Kontakt As Long) As Long
Dim rs_BUYER_CONTACT As DAO.Recordset
Dim rs_Kontakt As DAO.Recordset
' BG-9 BUYER CONTACT
Set rs_BUYER_CONTACT = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_tbl_BUYER_CONTACT " _
, dbOpenDynaset, dbAppendOnly) ' BUYER CONTACT zum Neuanlegen
Set rs_Kontakt = CodeDb.OpenRecordset("SELECT * " & _
"FROM qryKontakt " & _
"WHERE Kontakt = " & lng_Kontakt)
If rs_Kontakt.RecordCount > 0 Then ' Ansprechpartner gefunden
rs_Kontakt.MoveFirst
rs_BUYER_CONTACT.AddNew
rs_BUYER_CONTACT!BCN_BYR_ID = lng_BYR_ID ' Fremdschlüssel
' Business Terms eintragen
rs_BUYER_CONTACT!BCN_BUYER_CONTACT_POINT = rs_Kontakt!KontaktName ' BT-56
rs_BUYER_CONTACT!BCN_BUYER_CONTACT_TELEPHONE_NUMBER = rs_Kontakt!Telefon ' BT-57
rs_BUYER_CONTACT!BCN_BUYER_CONTACT_EMAIL_ADDRESS = rs_Kontakt!EMail ' BT-58
rs_BUYER_CONTACT.Update
End If
rs_BUYER_CONTACT.Close: Set rs_BUYER_CONTACT = Nothing
End Function
PAYMENT INSTRUCTIONS – BG-16
Eine Gruppe von Informationselementen, die Informationen darüber enthalten, wie die Zahlung erfolgen soll.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 54
Die Function payment_Instructions_Add bekommt als Aufrufparameter den Primärschlüsselwert der neu angelegen INVOICE. Bei meiner Anwendung wird nur die Zahlungsart SEPA-Überweisung akzeptiert. Daher ist dieser Abschnitt nicht allzu komplex. Die Kontodaten werden in der entsprechenden BG hinterlegt.
Private Function payment_Instructions_Add(ByVal lng_INV_ID As Long) As Long
Dim rs_PAYMENT_INSTRUCTIONS As DAO.Recordset
Dim lng_PMI_ID As Long
' BG-16 PAYMENT INSTRUCTIONS
Set rs_PAYMENT_INSTRUCTIONS = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_tbl_PAYMENT_INSTRUCTIONS " _
, dbOpenDynaset, dbAppendOnly) ' PAYMENT INSTRUCTIONS zum Neuanlegen
rs_PAYMENT_INSTRUCTIONS.AddNew
rs_PAYMENT_INSTRUCTIONS!PMI_INV_ID = lng_INV_ID ' Fremdschlüssel
' Business Terms eintragen
rs_PAYMENT_INSTRUCTIONS!PMI_PAYMENT_MEANS_TYPE_CODE = "58" ' BT-81 - akzeptiere nur "58: SEPA credit transfer"
rs_PAYMENT_INSTRUCTIONS!PMI_PAYMENT_MEANS_TEXT = "SEPA credit transfer" ' BT-82 - akzeptiere nur "58: SEPA credit transfer"
rs_PAYMENT_INSTRUCTIONS.Update
rs_PAYMENT_INSTRUCTIONS.MoveFirst
lng_PMI_ID = rs_PAYMENT_INSTRUCTIONS!PMI_ID ' neuer Primärschlüssel
rs_PAYMENT_INSTRUCTIONS.Close: Set rs_PAYMENT_INSTRUCTIONS = Nothing
' Business Groups eintragen
credit_transfer_Add lng_PMI_ID ' BG-17
End Function
CREDIT TRANSFER – BG-17
Eine Gruppe von Informationselementen, die Informationen über das Bankkonto geben, auf das die Überweisung zu leisten ist.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 40
Die Function credit_transfer_Add bekommt als Aufrufparameter den Primärschlüsselwert der neu angelegen PAYMENT INSTRUCTIONS. Bei CREDIT TRANSFER wird das Konto eingetragen, das für die Zahlung verwendet werden soll.
Private Function credit_transfer_Add(ByVal lng_PMI_ID As Long) As Long
Dim rs_CREDIT_TRANSFER As DAO.Recordset
' BG-17 CREDIT TRANSFER
Set rs_CREDIT_TRANSFER = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_tbl_CREDIT_TRANSFER " _
, dbOpenDynaset, dbAppendOnly) ' CDREDIT TRANSFER zum Neuanlegen
rs_CREDIT_TRANSFER.AddNew
rs_CREDIT_TRANSFER!CTR_PMI_ID = lng_PMI_ID ' Fremdschlüssel
' Business Terms eintragen
rs_CREDIT_TRANSFER!CTR_PAYMENT_ACCOUNT_IDENTIFIER_CONTENT = parameter_GET("Rechnung_Konto") ' BT-84
rs_CREDIT_TRANSFER!CTR_PAYMENT_ACCOUNT_NAME = "Thomas Braun" ' BT-85
rs_CREDIT_TRANSFER.Update
rs_CREDIT_TRANSFER.Close: Set rs_CREDIT_TRANSFER = Nothing
End Function
INVOICE LINE – BG-25
Eine Gruppe von Informationselementen, die Informationen über einzelne Rechnungspositionen enthalten.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 46
In der Spezifikation steht die INVOICE LINE an der letzten Stelle in der Reihenfolge. Für die Logik einer Rechnung kommt sie in der Rehenfolge weiter vorne. Daher kommt es an der Stelle zu einem Sprung in der Nummerierung der BG.
Die Function invoice_line_Add bekommt als Aufrufparameter den Primärschlüsselwert der neu angelegen INVOICE und den Primärschlüsselwert der Rechnung. Zur Rechnung werden zuerst alle Rechnungspositionen geladen. Danach werden die BT und BG pro Rechnungsposition eingetragen.
Der Maßeinheit für dei Abrechnung muss in diesem Abschnitt besondere Beachtung geschenkt werden. Diese müssen aus den Listen UN/ECE Recommendation No. 20 „Codes for Units of Measure Used in International Trade“ und UN/ECE Recommendation No 21 „Codes for Passengers, Types of Cargo, Packages and Packaging Materials“ ausgewählt werden (https://unece.org/trade/uncefact/cl-recommendations). In den Listen stehen nur die englischen Beszeichnungen. Um meine deutschen Bezeichnugnen weiter verwenden zu können, habe ich die Stammdatentabelle für die Einheiten um die Spalte UNIT_OF_MEASURE ergänzt.
Private Function invoice_line_Add(ByVal lng_INV_ID As Long, ByVal lng_RechnungID As Long) As Long
Dim rs_Positionen As DAO.Recordset
Dim rs_INVOICE_LINE As DAO.Recordset
Dim lng_INL_ID As Long
' BG-25 INVOICE LINE
Set rs_Positionen = CodeDb.OpenRecordset("SELECT tblRechnungPositionen.* " & _
" , tblEinheiten.* " & _
"FROM tblRechnungPositionen " & _
" LEFT JOIN " & _
" tblEinheiten ON tblRechnungPositionen.Einheit = tblEinheiten.Einheit " & _
"WHERE Rechnung = " & lng_RechnungID) ' Positionen zu Rechnung abrufen
Set rs_INVOICE_LINE = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_tbl_INVOICE_LINE " _
, dbOpenDynaset, dbAppendOnly) ' INVOICE LINE zum Neuanlegen
If rs_Positionen.RecordCount > 0 Then
rs_Positionen.MoveFirst
Do While Not rs_Positionen.EOF
rs_INVOICE_LINE.AddNew
rs_INVOICE_LINE!ILN_INV_ID = lng_INV_ID ' Fremdschlüssel
' Business Terms eintragen
rs_INVOICE_LINE!ILN_INVOICE_LINE_IDENTIFIER_CONTENT = rs_Positionen!RechnungPosition ' BT-126
rs_INVOICE_LINE!ILN_INVOICE_LINE_NOTE = rs_Positionen!PositionText ' BT-127
rs_INVOICE_LINE!ILN_INVOICED_QUANTITY = rs_Positionen!Anzahl ' BT-129
rs_INVOICE_LINE!ILN_INVOICED_QUANTITY_UNIT_OF_MEASURE_CODE = rs_Positionen!UNIT_OF_MEASURE ' BT-130 - vgl. vbax_tbl_CODELIST
rs_INVOICE_LINE!ILN_INVOICE_LINE_NET_AMOUNT = rs_Positionen!Anzahl * rs_Positionen!EinzelPreis ' BT-131
rs_INVOICE_LINE.Update
rs_INVOICE_LINE.MoveLast
lng_INL_ID = rs_INVOICE_LINE!ILN_ID ' neuer Primärschlüssel
' Business Groups eintragen
invoice_line_period_Add lng_INL_ID, Nz(rs_Positionen!DatumAbgabe) ' BG-26
price_details_Add lng_INL_ID, Nz(rs_Positionen!EinzelPreis, 0) ' BG-29
line_vat_information_Add lng_INL_ID, lng_RechnungID ' BG-30
item_information_Add lng_INL_ID, rs_Positionen!RechnungPosition ' BG-31
rs_Positionen.MoveNext
Loop
End If
rs_INVOICE_LINE.Close: Set rs_INVOICE_LINE = Nothing
rs_Positionen.Close: Set rs_Positionen = Nothing
End Function
INVOICE LINE PERIOD – BG-26
Eine Gruppe von Informationselementen, die Informationen über den für die Rechnungsposition maßgeblichen Abrechnungszeitraum enthalten.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 49
Die Function invoice_line_period_Add bekommt als Aufrufparameter den Primärschlüsselwert der neu angelegen INVOICE LINE und einen Datumswerte, der das Ende des Abrechnungszeitraums dieser Rechnungsposition angibt. In meiner Anwendung kann bei Positionen optional ein End- bzw. Abgabedatum angegeben werden.
Private Function invoice_line_period_Add(ByVal lng_ILN_ID As Long, ByVal dat_END As Date) As Long
Dim rs_INVOICE_LINE_PERIOD As DAO.Recordset
' BG-26 INVOICE LINE PERIOD
If dat_END <> "00:00:00" Then ' Datum angegeben
Set rs_INVOICE_LINE_PERIOD = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_INVOICE_LINE_PERIOD " _
, dbOpenDynaset, dbAppendOnly) ' INVOICE LINE PERIOD zum Neuanlegen
rs_INVOICE_LINE_PERIOD.AddNew
rs_INVOICE_LINE_PERIOD!ILP_ILN_ID = lng_ILN_ID ' Fremdschlüssel
' Business Terms eintragen
rs_INVOICE_LINE_PERIOD!ILP_INVOICE_LINE_PERIOD_END_DATE = dat_END ' BT-135 - Abgabedatum entspricht dem Ende des Zeitraums
rs_INVOICE_LINE_PERIOD.Update
rs_INVOICE_LINE_PERIOD.Close: Set rs_INVOICE_LINE_PERIOD = Nothing
End If
End Function
PRICE DETAILS – BG-29
Eine Gruppe von Informationselementen, die Informationen über den Preis für die in der betreffenden Rechnungsposition in Rechnung gestellten Waren und Dienstleistungen enthalten.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 55
Die Function price_Detail_Add bekommt als Aufrufparameter den Primärschlüsselwert der neu angelegen INVOICE LINE und den Einzelpreis (netto) dieser Rechnungsposition.
Private Function price_details_Add(ByVal lng_ILN_ID As Long, ByVal dbl_EinzelPreis As Double) As Long
Dim rs_PRICE_DETAILS As DAO.Recordset
' BG-26 PRICE DETAILS
Set rs_PRICE_DETAILS = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_tbl_PRICE_DETAILS " _
, dbOpenDynaset, dbAppendOnly) ' PRICE DETAILS zum Neuanlegen
rs_PRICE_DETAILS.AddNew
rs_PRICE_DETAILS!PCD_ILN_ID = lng_ILN_ID ' Fremdschlüssel
' Business Terms eintragen
rs_PRICE_DETAILS!PCD_ITEM_NET_PRICE = dbl_EinzelPreis ' BT-146 - bei diesem Datenmodell ist nur der Nettopreis notwendig
rs_PRICE_DETAILS.Update
rs_PRICE_DETAILS.Close: Set rs_PRICE_DETAILS = Nothing
End Function
LINE VAT INFORMATION – BG-30
Eine Gruppe von Informationselementen, die Informationen über die Umsatzsteuer enthalten, die für die in der betreffenden Zeile in Rechnung gestellten Waren und Dienstleistungen gilt.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 52
Die Function line_vat_information_Add bekommt als Aufrufparameter den Primärschlüsselwert der neu angelegen INVOICE LINE und den Primärschlüssel der Rechnung anstatt der Rechnungsposition, weil die Umsatzsteuerinformationen auf Ebene Rechnung hinterlegt sind. Ich nutze eine vereinfachte Darstellung und verwende nur die Umsatzsteuerkategorien „S – Standard“ für alle Inlandsrechnungen und „AE – VAT Revese Charge“ für Rechnugnen an Unternehmen im Ausland.
Private Function line_vat_information_Add(ByVal lng_ILN_ID As Long, ByVal lng_RechnungID As Long) As Long
Dim rs_LINE_VAT_INFORMATION As DAO.Recordset
Dim rs_Rechnung As DAO.Recordset
' BG-30 LINE VAT INFORMATION
Set rs_LINE_VAT_INFORMATION = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_tbl_LINE_VAT_INFORMATION " _
, dbOpenDynaset, dbAppendOnly) ' LINE VAT INFORMATION zum Neuanlegen
Set rs_Rechnung = CodeDb.OpenRecordset("SELECT * " & _
"FROM tblRechnungen " & _
"WHERE Rechnung = " & lng_RechnungID) ' Umsatzsteuerinformationen gelten für gesamte Rechnung
rs_LINE_VAT_INFORMATION.AddNew
rs_LINE_VAT_INFORMATION!LVI_ILN_ID = lng_ILN_ID ' Fremdschlüssel
' Business Terms eintragen
rs_LINE_VAT_INFORMATION!LVI_INVOICED_ITEM_VAT_RATE = Nz(rs_Rechnung!Umsatzsteuersatz, 0) ' BT-152
If rs_LINE_VAT_INFORMATION!LVI_INVOICED_ITEM_VAT_RATE = 0 Then
rs_LINE_VAT_INFORMATION!LVI_INVOICED_ITEM_VAT_CATEGORY_CODE = "AE" ' BT-151 - bei Steuersatz von 0% gehe ich von VAT Reverse Charge aus
Else
rs_LINE_VAT_INFORMATION!LVI_INVOICED_ITEM_VAT_CATEGORY_CODE = "S" ' BT-151 - bei Steuersatz <> 0% gehe ich von Standard aus
End If
rs_LINE_VAT_INFORMATION.Update
rs_LINE_VAT_INFORMATION.Close: Set rs_LINE_VAT_INFORMATION = Nothing
rs_Rechnung.Close: Set rs_Rechnung = Nothing
End Function
ITEM INFORMATION – BG-31
Eine Gruppe von Informationselementen, die Informationen über die in Rechnung gestellten Waren und Dienstleistungen enthalten.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 51
Die Function item_information_Add bekommt als Aufrufparameter den Primärschlüsselwert der neu angelegen INVOICE LINE und den Primärschlüssel der Rechnungsposition. Ich stelle in der Regel Dienstleistungen in Rechnung und verwende an Stelle eines Artikelstamms eine Liste von Auftragsarten.
Private Function item_information_Add(ByVal lng_ILN_ID As Long, ByVal lng_Position As Long) As Long
Dim rs_ITEM_INFORMATION As DAO.Recordset
Dim lng_ITI_ID As Long
Dim rs_Position As DAO.Recordset
' BG-31 ITEM INFORMATION
Set rs_ITEM_INFORMATION = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_tbl_ITEM_INFORMATION " _
, dbOpenDynaset, dbAppendOnly) ' ITEM INFORMATION zum Neuanlegen
Set rs_Position = CodeDb.OpenRecordset("SELECT tblRechnungPositionen.* " & _
" , tblAuftragsarten.* " & _
"FROM tblRechnungPositionen " & _
" LEFT JOIN tblAuftragsarten " & _
" ON tblRechnungPositionen.Auftragsart = tblAuftragsarten.Auftragsart " & _
"WHERE RechnungPosition = " & lng_Position) ' ITEM entspricht Auftragsart
rs_ITEM_INFORMATION.AddNew
rs_ITEM_INFORMATION!ITI_ILN_ID = lng_ILN_ID ' Fremdschlüssel
' Business Terms eintragen
rs_ITEM_INFORMATION!ITI_ITEM_NAME = rs_Position!Auftragsartbezeichnung ' BT-153
rs_ITEM_INFORMATION.Update
rs_ITEM_INFORMATION.MoveFirst
lng_ITI_ID = rs_ITEM_INFORMATION!ITI_ID
' Business Groups eintragen
item_attributes_Add lng_ITI_ID, Nz(rs_Position!Sprache, 0) ' BG-32
rs_ITEM_INFORMATION.Close: Set rs_ITEM_INFORMATION = Nothing
rs_Position.Close: Set rs_Position = Nothing
End Function
ITEM ATTRIBUTES – BG-32
Eine Gruppe von Informationselementen, die Informationen über die Eigenschaften der in Rechnung gestellten Waren und Dienstleistungen enthalten.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 51
Die Function item_attributes_Add bekommt als Aufrufparameter den Primärschlüsselwert der zur Rechnungsposition neu angelegen ITEM INFORMATION und den Sprachschlüssel der Rechnungsposition. Meine Anwendung habe ich in erster Linie als Auftrags- und Rechnungsverwaltung für DolmetscherInnen und ÜbersetzerInnen entwickelt. In der Berufsgruppe ist es üblich, ihre Leistung pro Arbeiotssprache zu berechnen. Die Sprache findet sich bei der XRechnung als ATTRIBUTE zu einem ITEM einer INVOICE LINE wieder.
Private Function item_attributes_Add(ByVal lng_ITI_ID As Long, ByVal lng_Sprache As Long) As Long
Dim rs_ITEM_ATTRIBUTES As DAO.Recordset
Dim rs_Sprache As DAO.Recordset
' BG-32 ITEM ATTRIBUTES
Set rs_ITEM_ATTRIBUTES = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_ITEM_ATTRIBUTES " _
, dbOpenDynaset, dbAppendOnly) ' ITEM ATTRIBUTES zum Neuanlegen
Set rs_Sprache = CodeDb.OpenRecordset("SELECT * " & _
"FROM tblSprache " & _
"WHERE Sprache = " & lng_Sprache) ' Sprache ist ein ATTRIBUTE
If rs_Sprache.RecordCount > 0 Then ' Sprache vorhanden
rs_Sprache.MoveFirst
rs_ITEM_ATTRIBUTES.AddNew
rs_ITEM_ATTRIBUTES!ITA_ITI_ID = lng_ITI_ID ' Fremdschlüssel
' Business Terms eintragen
rs_ITEM_ATTRIBUTES!ITA_ITEM_ATTRIBUTE_NAME = "Sprache" ' BT-160
rs_ITEM_ATTRIBUTES!ITA_ITEM_ATTRIBUTE_VALUE = rs_Sprache!Sprechkennzeichen ' BT-161
rs_ITEM_ATTRIBUTES.Update
End If
rs_ITEM_ATTRIBUTES.Close: Set rs_ITEM_ATTRIBUTES = Nothing
rs_Sprache.Close: Set rs_Sprache = Nothing
End Function
VAT BREAKDOWN – BG-23
Eine Gruppe von Informationselementen, die Informationen über die Umsatzsteueraufschlüsselung nach verschiedenen Kategorien, Steuersätzen und Ausnahmegründen enthalten.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 61
Die Function vat_breakdown_Add bekommt als Aufrufparameter den Primärschlüsselwert der neu angelegen INVOICE. Anhand der INV_ID werden aus den angelegten INVOICE LINE Daten die Steuerbeträge ausgelesen und summiert. Es erfolgt eine Aufschlüsselung nach Umsatzsteuerkategorie und Umsatzsteuersatz.
Private Function vat_breakdown_Add(ByVal lng_INV_ID As Long) As Long
Dim rs_LINE_VAT_INFORMATION As DAO.Recordset
Dim rs_VAT_BREAKDOWN As DAO.Recordset
' BG-23 VAT BREAKDOWN
Set rs_LINE_VAT_INFORMATION = CodeDb.OpenRecordset("SELECT INVOICE_LINE.ILN_INV_ID " & _
" , LINE_VAT_INFORMATION.LVI_INVOICED_ITEM_VAT_CATEGORY_CODE " & _
" , LINE_VAT_INFORMATION.LVI_INVOICED_ITEM_VAT_RATE " & _
" , Sum(Nz(INVOICE_LINE.ILN_INVOICE_LINE_NET_AMOUNT, 0)) AS SUM_TAXABLE_AMOUNT " & _
"FROM vbax_tbl_INVOICE_LINE AS INVOICE_LINE " & _
" LEFT JOIN vbax_tbl_LINE_VAT_INFORMATION AS LINE_VAT_INFORMATION " & _
" ON INVOICE_LINE.ILN_ID = LINE_VAT_INFORMATION.LVI_ILN_ID " & _
"WHERE INVOICE_LINE.ILN_INV_ID = " & lng_INV_ID & " " & _
"GROUP BY INVOICE_LINE.ILN_INV_ID " & _
" , LINE_VAT_INFORMATION.LVI_INVOICED_ITEM_VAT_CATEGORY_CODE " & _
" , LINE_VAT_INFORMATION.LVI_INVOICED_ITEM_VAT_RATE ")
' LINE VAT INFORMATION aggregieren
Set rs_VAT_BREAKDOWN = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_tbl_VAT_BREAKDOWN" _
, dbOpenDynaset, dbAppendOnly) ' VAT BREAKDOWN zum Neuanlegen
If rs_LINE_VAT_INFORMATION.RecordCount > 0 Then
rs_LINE_VAT_INFORMATION.MoveFirst
Do While Not rs_LINE_VAT_INFORMATION.EOF ' Kategorien durchlaufen
rs_VAT_BREAKDOWN.AddNew
rs_VAT_BREAKDOWN!VBR_INV_ID = lng_INV_ID ' Fremdschlüssel
rs_VAT_BREAKDOWN!VBR_VAT_CATEGORY_TAXABLE_AMOUNT = fctRound(rs_LINE_VAT_INFORMATION!SUM_TAXABLE_AMOUNT, 2) ' BT-116
rs_VAT_BREAKDOWN!VBR_VAT_CATEGORY_CODE = rs_LINE_VAT_INFORMATION!LVI_INVOICED_ITEM_VAT_CATEGORY_CODE ' BT-118
rs_VAT_BREAKDOWN!VBR_VAT_CATEGORY_RATE = rs_LINE_VAT_INFORMATION!LVI_INVOICED_ITEM_VAT_RATE ' BT-119
rs_VAT_BREAKDOWN!VBR_VAT_CATEGORY_TAX_AMOUNT = fctRound(rs_LINE_VAT_INFORMATION!SUM_TAXABLE_AMOUNT, 2) _
* (rs_LINE_VAT_INFORMATION!LVI_INVOICED_ITEM_VAT_RATE / 100) ' BT-117
rs_VAT_BREAKDOWN!VBR_VAT_CATEGORY_TAX_AMOUNT = fctRound(rs_VAT_BREAKDOWN!VBR_VAT_CATEGORY_TAX_AMOUNT, 2)
rs_VAT_BREAKDOWN.Update
rs_LINE_VAT_INFORMATION.MoveNext
Loop
End If
rs_VAT_BREAKDOWN.Close: Set rs_VAT_BREAKDOWN = Nothing
rs_LINE_VAT_INFORMATION.Close: Set rs_LINE_VAT_INFORMATION = Nothing
End Function
DOCUMENT TOTALS – BG-22
Eine Gruppe von Informationselementen, die die monetären Gesamtbeträge der Rechnung enthalten.
Spezifikation Standard XRechnung Version 3.0.2 – Seite 45
Die Function document_totals_Add bekommt als Aufrufparameter den Primärschlüsselwert der neu angelegen INVOICE. Anhand der INV_ID werden aus diversen Quellen Gesamtbeträge ermittelt und als DOCUMENT TOTALS eingetragen.
Private Function document_totals_Add(ByVal lng_INV_ID As Long) As Long
Dim rs_TOTAL As DAO.Recordset
Dim rs_DOCUMENT_TOTALS As DAO.Recordset
' BG-22 DOCUMENT TOTALS
Set rs_DOCUMENT_TOTALS = CodeDb.OpenRecordset("SELECT * " & _
"FROM vbax_tbl_DOCUMENT_TOTALS" _
, dbOpenDynaset, dbAppendOnly) ' VAT DOCUMENT TOTALS zum Neuanlegen
rs_DOCUMENT_TOTALS.AddNew
rs_DOCUMENT_TOTALS!DCT_INV_ID = lng_INV_ID ' Fremdschlüssel
' Summen aus diversen Quellen holen
Set rs_TOTAL = CodeDb.OpenRecordset("SELECT SUM(DLA_Document_level_allowance_amount) " & _
"FROM vbax_tbl_DOCUMENT_LEVEL_ALLOWANCES " & _
"WHERE DLA_INV_ID = " & lng_INV_ID)
If rs_TOTAL.RecordCount > 0 Then
rs_TOTAL.MoveFirst
rs_DOCUMENT_TOTALS!DCT_SUM_OF_ALLOWANCES_ON_DOCUMENT_LEVEL = fctRound(Nz(rs_TOTAL(0), 0)) ' BT-107
End If
Set rs_TOTAL = CodeDb.OpenRecordset("SELECT SUM(DLC_Document_level_charge_amount) " & _
"FROM vbax_tbl_DOCUMENT_LEVEL_CHARGES " & _
"WHERE DLC_INV_ID = " & lng_INV_ID)
If rs_TOTAL.RecordCount > 0 Then
rs_TOTAL.MoveFirst
rs_DOCUMENT_TOTALS!DCT_SUM_OF_CHARGES_ON_DOCUMENT_LEVEL = fctRound(Nz(rs_TOTAL(0), 0)) ' BT-108
End If
Set rs_TOTAL = CodeDb.OpenRecordset("SELECT SUM(ILN_INVOICE_LINE_NET_AMOUNT) AS SUM_OF_INVOICE_LINE_NET_AMOUNT " & _
" , SUM(ILN_INVOICE_LINE_NET_AMOUNT * ( LVI_INVOICED_ITEM_VAT_RATE / 100)) AS SUM_OF_INVOICE_TOTAL_VAT_AMOUNT " & _
"FROM vbax_tbl_INVOICE_LINE AS INVOICE_LINE " & _
" LEFT JOIN vbax_tbl_LINE_VAT_INFORMATION AS LINE_VAT_INFORMATION " & _
" ON INVOICE_LINE.ILN_ID = LINE_VAT_INFORMATION.LVI_ILN_ID " & _
"WHERE INVOICE_LINE.ILN_INV_ID = " & lng_INV_ID & " ")
If rs_TOTAL.RecordCount > 0 Then
rs_TOTAL.MoveFirst
rs_DOCUMENT_TOTALS!DCT_INVOICE_TOTAL_VAT_AMOUNT = fctRound(Nz(rs_TOTAL!SUM_OF_INVOICE_TOTAL_VAT_AMOUNT, 0)) ' BT-110
rs_DOCUMENT_TOTALS!DCT_SUM_OF_INVOICE_LINE_NET_AMOUNT = fctRound(Nz(rs_TOTAL!Sum_Of_Invoice_Line_Net_Amount, 0)) ' BT-106
End If
' diverse Berechnungen
rs_DOCUMENT_TOTALS!DCT_INVOICE_TOTAL_AMOUNT_WITHOUT_VAT = Nz(rs_DOCUMENT_TOTALS!DCT_SUM_OF_INVOICE_LINE_NET_AMOUNT, 0) _
- Nz(rs_DOCUMENT_TOTALS!DCT_SUM_OF_ALLOWANCES_ON_DOCUMENT_LEVEL, 0) _
+ Nz(rs_DOCUMENT_TOTALS!DCT_SUM_OF_CHARGES_ON_DOCUMENT_LEVEL, 0) ' BT-108
rs_DOCUMENT_TOTALS!DCT_INVOICE_TOTAL_AMOUNT_WITH_VAT = Nz(rs_DOCUMENT_TOTALS!DCT_INVOICE_TOTAL_AMOUNT_WITHOUT_VAT, 0) _
+ Nz(rs_DOCUMENT_TOTALS!DCT_INVOICE_TOTAL_VAT_AMOUNT, 0) ' BT-112
rs_DOCUMENT_TOTALS!DCT_AMOUNT_DUE_FOR_PAYMENT = Nz(rs_DOCUMENT_TOTALS!DCT_INVOICE_TOTAL_AMOUNT_WITH_VAT, 0) _
- Nz(rs_DOCUMENT_TOTALS!DCT_PAID_AMOUNT, 0) ' BT-115
rs_DOCUMENT_TOTALS.Update
rs_DOCUMENT_TOTALS.Close: Set rs_DOCUMENT_TOTALS = Nothing
rs_TOTAL.Close: Set rs_TOTAL = Nothing
End Function
Nahtlose Integration
In der Anwendung gibt es eine Funktion, die die Auftragsdaten zu Rechungsdaten macht und den Primärschlüssel der Rechnung vergibt. Vor dem Schließen des Auftragsformulars wird jetzt die XRechnung erstellt.
...
Forms(AufrufFormular)![Rechnung] = lngRechnung
rechnung_XRechnung_SAVE lngRechnung ' 20250102 tb: XRechnung speichern
DoCmd.Close acForm, AufrufFormular
...
Die Function rechnung_XRechnung_SAVE besteht aus folgenden Arbeitsschritten:
- Speicherort und Dateinamen für XRechnung aus Parameter ermitteln
- Rechnungsnummer und Zeitpunkt ergänzen
- vbax_INVOICE_EXPORT_File aufrufen
Public Function rechnung_XRechnung_SAVE(ByVal lng_Rechnung As Long) As String
Dim str_XRECHNUNG_FOLDER As String
Dim str_XRECHNUNG_PREFIX As String
Dim str_NummerRechnung As String
str_XRECHNUNG_FOLDER = parameter_GET("XRechnung_Directory") ' Ablageverzeichnis
str_XRECHNUNG_PREFIX = parameter_GET("XRechnung_Prefix") ' Präfix
str_NummerRechnung = tLookup("Rechnungsnummer" _
, "tblRechnungen" _
, "Rechnung = " & lng_Rechnung) ' Rechnungsnummer
If Len(str_XRECHNUNG_FOLDER) = 0 Then ' kein Standardablageverzeichnis
str_XRECHNUNG_FOLDER = directory_Choose("Speicherort für XRechnung auswählen") ' Verzeichnisauswahldialog
End If
If Len(str_XRECHNUNG_FOLDER) > 0 Then ' Verzeichnis angegeben
If Len(str_XRECHNUNG_PREFIX) > 0 Then
str_XRECHNUNG_PREFIX = str_XRECHNUNG_PREFIX & "_" ' Unterstrich nach Präfix ergänzen, falls vorhanden
End If
If Len(str_NummerRechnung) > 0 Then
str_NummerRechnung = str_NummerRechnung & "_" ' Unterstrich nach Rechnungsnummer ergänzen, falls vorhanden
End If
vbax_INVOICE_EXPORT_File lng_Rechnung _
, str_XRECHNUNG_FOLDER & "\" & _
str_XRECHNUNG_PREFIX & _
str_NummerRechnung & _
Format(Now, "yyyyMMdd_hhnnss") & ".xml" ' XRechnung erstellen, speichern, bei Rechnung hinterlegen
End If
End Function
Die Function vbax_INVOICE_EXPORT_File besteht aus folgenden Arbeitsschritten:
- aus den Rechnungsdaten vbax-Rechnungsdaten machen
- aus den vbax-Rechnungsdaten ein vbax-Objekt machen
- aus dem vbax-Objekt eine Cross-Industry-Invoice-Objekt machen
- Document-Object-Model aus Cross-Industry-Invoice-Objekt auslesen
- Document-Object-Model als xml-Datei unter dem angegbenen Namen speichern
- Document-Object-Model und ID der vbax-Rechnungsdaten bei Rechnungsdaten speichern
Public Function vbax_INVOICE_EXPORT_File(ByVal lng_Rechnung As Long _
, ByVal str_FILE As String) As String
Dim vbax_OBJECT As New vbax_XML_NODE
Dim vbax_CII As New vbax_XML_NODE
Dim vbax_INVOICE As New vbax_xr_INVOICE
Dim lng_INV_ID As Long
Dim str_DOM As String
lng_INV_ID = invoice_Add(lng_Rechnung)
Set vbax_INVOICE = vbax_Adapter.data2xr(lng_INV_ID)
Set vbax_CII = vbax_Adapter.xr2cii(vbax_INVOICE)
str_DOM = vbax_CII.xml_DOM
vbax_hl_TEXT.UTF8_SAVE str_FILE, str_DOM
Set vbax_INVOICE = Nothing
Set vbax_CII = Nothing
vbax_Rechnung_Update lng_Rechnung, str_DOM, lng_INV_ID
vbax_INVOICE_EXPORT_File = str_DOM
End Function