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.

Abbildung 9.1. Strukturabbildung

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:

  1. Speicherort und Dateinamen für XRechnung aus Parameter ermitteln
  2. Rechnungsnummer und Zeitpunkt ergänzen
  3. 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:

  1. aus den Rechnungsdaten vbax-Rechnungsdaten machen
  2. aus den vbax-Rechnungsdaten ein vbax-Objekt machen
  3. aus dem vbax-Objekt eine Cross-Industry-Invoice-Objekt machen
  4. Document-Object-Model aus Cross-Industry-Invoice-Objekt auslesen
  5. Document-Object-Model als xml-Datei unter dem angegbenen Namen speichern
  6. 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