Create ZUGFeRD and XRechnung invoices with Visual FoxPro 9 – via COM or CSV

SDK members
AddPaymentMeans() AddProduct_Comfort() AddTradePaymentTerms() AddTradeTax() CreateInvoiceObject() ExportZUGFeRDXML2Disk() MergeXMLIntoPDF() SaveXML() WriteSeller() WriteTotals()
Business terms
BT-1 Invoice number BT-2 Invoice issue date BT-3 Invoice type code BT-5 Invoice currency code BT-31 Seller VAT identifier BT-72 Actual delivery date BG-25 Invoice line BG-23 VAT breakdown
Code samples
Visual FoxPro
Published

In short: Applications written in Visual FoxPro (VFP 9.0 SP2, also VFP 8) create e-invoices according to EN 16931 – ZUGFeRD 2.x, Factur-X and XRechnung – through the COM interface of the Aloaha ZUGFeRD SDK: CREATEOBJECT("Aloaha_ZUGFeRD.XML"), set the invoice data, save the XML and embed it into the existing PDF invoice. There is no need to migrate the FoxPro application. If you prefer not to program against the SDK at all, write the data to CSV files with STRTOFILE and call the command-line tool zugcmd. Both ways also read ZUGFeRD PDFs you receive.

At a glance

Way 1: COMWay 2: CSV + zugcmd
In FoxProCREATEOBJECT("Aloaha_ZUGFeRD.XML"), call methodsSTRTOFILE for four CSV files, start zugcmd
ResultXML according to EN 16931 (ZUGFeRD, Factur-X or XRechnung) and a ZUGFeRD PDF (PDF/A-3 with embedded XML)
Incoming e-invoicesExportZUGFeRDXML2Disk extracts the XML from the PDFzugcmd -r splits XML or PDF into CSV files
BitnessVisual FoxPro is always 32-bit – the SDK setup registers the 32-bit COM interface
Guidethis page, section COMsection CSV and CSV and zugcmd

Requirements

  • Windows with .NET Framework 4.7.2 or later (included in Windows 10 from version 1803 and in Windows 11). The FoxPro runtime stays as it is.
  • The SDK setup Aloaha_ZUGFeRD_SDK.zip from the downloads page. It registers the COM interface for 32-bit and 64-bit.
  • Check the registration with the included script in the 32-bit script host: C:\Windows\SysWOW64\cscript.exe //nologo zugferd_com_test.vbs
  • A licence key – a free trial licence with full functionality is available by e-mail to info@aloaha.com.

Amounts always with a decimal point

The SDK expects amounts as text with a point ("59.50"). In FoxPro, STR() and TRANSFORM() use the decimal separator from SET POINT or the Windows settings – with German or Dutch settings that is a comma. This small function always returns a point:

FUNCTION Amount(tnValue)
    RETURN STRTRAN(ALLTRIM(STR(tnValue, 15, 2)), ",", ".")
ENDFUNC

Way 1: calling the SDK via COM

Your program creates the PDF invoice as before. The SDK writes the XML and embeds it:

loAlo = CREATEOBJECT("Aloaha_ZUGFeRD.XML")
loAlo.Licensekey = "YOUR-LICENCE-KEY"
loAlo.ZUGFeRD_Profile = 1                && 0 = BASIC, 1 = EN 16931 (COMFORT), 2 = EXTENDED

* Invoice header: number (BT-1), note, date (BT-2), date format, name, language, currency (BT-5)
loAlo.CreateInvoiceObject("RE-2027-0001", "", "20270104", "102", "", "DE", "EUR")
loAlo.Document_TypeINT = 380             && BT-3, AFTER CreateInvoiceObject: 380 invoice, 381 credit note
loAlo.ActualDeliveryDate_102 = "20270104"   && BT-72: delivery date

* Seller: name, postcode, city, street, street 2, country, VAT ID (BT-31)
loAlo.WriteSeller("Muster GmbH", "20095", "Hamburg", "Hauptstr. 1", "", "DE", "DE123456789")

* Buyer
loAlo.BuyerName = "Kunde AG"
loAlo.BuyerAddressLine1 = "Marktplatz 5"
loAlo.BuyerPostCode = "80331"
loAlo.BuyerCity = "München"
loAlo.BuyerCountry = "DE"

* Payment: 58 = SEPA credit transfer (BT-81)
loAlo.AddPaymentMeans(58, "SEPA credit transfer", "DE02120300000000202051", "Muster GmbH", "", "BYLADEM1001")
loAlo.AddTradePaymentTerms("Payable within 30 days net")

* Invoice line (BG-25): 10 pieces at 5.00 EUR, 19 %
loAlo.AddProduct_Comfort(1, "", "ART-100", "10.00", "C62", "Paper A4", "500 sheets", ;
    "", "EUR", "", "C62", .F., "", "", "", Amount(5), "EUR", "1.00", ;
    "C62", "VAT", "S", "19.00", "", Amount(50), "EUR", "", "")

* VAT breakdown (BG-23) and totals (BG-22)
loAlo.AddTradeTax(Amount(9.5), "EUR", Amount(50), "EUR", "VAT", "S", "19.00")
loAlo.WriteTotals(Amount(50), Amount(59.5), Amount(59.5), Amount(50), Amount(9.5))

* Save the XML and embed it into the existing PDF invoice (.T. = overwrite the target file)
IF loAlo.SaveXML("C:\Invoices\RE-2027-0001.xml")
    loAlo.MergeXMLIntoPDF("C:\Invoices\RE-2027-0001.xml", ;
        "C:\Invoices\RE-2027-0001.pdf", "C:\Invoices\RE-2027-0001_zugferd.pdf", .T.)
ELSE
    MESSAGEBOX("Error: " + loAlo.LastError)
ENDIF

The calls are the same as in VB6 and VBA – described with all parameters in Creating ZUGFeRD and XRechnung with VB6, VB5 and VBA. Only FoxPro's own notation differs: ; at the end of a line to continue it, .T. and .F. for true and false, && for comments.

Invoice lines from a table

For many lines, call AddProduct_Comfort in a SCAN loop. NVL() protects against empty fields (.NULL.), which COM does not accept as text:

lnPos = 0
SELECT invlines
SCAN FOR invno = lcInvNo
    lnPos = lnPos + 1
    loAlo.AddProduct_Comfort(lnPos, "", ALLTRIM(NVL(itemno, "")), Amount(qty), "C62", ;
        ALLTRIM(NVL(descr, "")), "", "", "EUR", "", "C62", .F., "", "", "", ;
        Amount(price), "EUR", "1.00", "C62", "VAT", "S", Amount(vatrate), "", ;
        Amount(qty * price), "EUR", "", "")
ENDSCAN

Calculate the totals from the rounded line amounts and pass one line per VAT rate with AddTradeTax – see BR-S-08, BR-S-09 and BR-CO-17.

XRechnung for German public-sector buyers

loAlo.isKOSIT = .T.                      && XRechnung (CII) instead of ZUGFeRD/Factur-X
loAlo.LeitwegID = "04011000-12345-34"    && BT-10: the buyer's Leitweg-ID

An XRechnung also needs a seller contact with name, phone and e-mail. Which calls switch an XRechnung to Factur-X EXTENDED by accident is described in Why is my XRechnung created as Factur-X EXTENDED? (German).

Reading ZUGFeRD PDFs you receive

IF loAlo.ExportZUGFeRDXML2Disk("C:\Inbox\invoice.pdf", "C:\Inbox\invoice.xml", "YOUR-LICENCE-KEY", .T.)
    * process the XML, e.g. with XMLTOCURSOR() or MSXML
ENDIF

Way 2: CSV files and zugcmd

Without SDK programming, your application writes four CSV files (seller, buyer, lines, totals) and starts zugcmd. Columns, sample files and all parameters are described in E-invoices via CSV and zugcmd. In FoxPro:

lcDir = "C:\EInvoice\RE-2027-0001\"
lcCRLF = CHR(13) + CHR(10)
STRTOFILE("id,Name,Street1,city,email,country,postcode" + lcCRLF + ;
          "K-1001,Kunde AG,Marktplatz 5,München,einkauf@kunde.example,DE,80331" + lcCRLF, lcDir + "buyer.csv")
* ... items.csv and totals.csv the same way, seller.csv once as a master file

loShell = CREATEOBJECT("WScript.Shell")
lnRC = loShell.Run('"C:\zugcmd\zugcmd_wnd.exe" -s "C:\EInvoice\master\seller.csv" ' + ;
    '-b "' + lcDir + 'buyer.csv" -p "' + lcDir + 'items.csv" -t "' + lcDir + 'totals.csv" ' + ;
    '-i "' + lcDir + 'RE-2027-0001.pdf" -x "' + lcDir + 'RE-2027-0001.xml" ' + ;
    '-o "' + lcDir + 'RE-2027-0001_zugferd.pdf" -y "," -c ansi -l YOUR-LICENCE-KEY', 0, .T.)
IF lnRC # 0
    MESSAGEBOX("zugcmd reports error " + TRANSFORM(lnRC))
ENDIF

WScript.Shell.Run with .T. as the third parameter waits until zugcmd has finished and returns its exit code (0 = success). FoxPro writes Windows ANSI with STRTOFILE; hence -c ansi, otherwise umlauts and accents arrive garbled.

Typical errors

  • Error 1733 (class definition not found) on CREATEOBJECT: the COM interface is not registered, or only for 64-bit. Run the SDK setup again or register the DLL with the 32-bit RegAsm (C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm.exe Aloaha_ZUGFeRD.dll /codebase /tlb, as administrator, on a local drive).
  • Amounts with a comma: the validator reports wrong totals or the SDK ignores values – always pass them through Amount().
  • Invoice type stays 380: set Document_TypeINT only after CreateInvoiceObject; the second parameter of CreateInvoiceObject is a note text, not the invoice type.
  • .NULL. from table fields: catch them with NVL(field, "").
  • Check the first invoice with the KoSIT validator, see How do I validate my XRechnung before sending it?

Frequently asked questions

Can I create ZUGFeRD and XRechnung files with Visual FoxPro 9?

Yes. The Aloaha ZUGFeRD SDK has a COM interface that Visual FoxPro uses with CREATEOBJECT("Aloaha_ZUGFeRD.XML"). It creates ZUGFeRD 2.x, Factur-X and XRechnung according to EN 16931, as XML or embedded into a PDF/A-3 invoice.

Do I have to migrate my FoxPro application?

No. The application remains a Visual FoxPro application. The computer only needs .NET Framework 4.7.2; the SDK setup registers the COM interface.

Does it work with 32-bit?

Yes. Visual FoxPro is always a 32-bit application. The SDK setup registers the COM interface for 32-bit and 64-bit.

Can I read incoming ZUGFeRD invoices in FoxPro?

Yes. ExportZUGFeRDXML2Disk extracts the embedded XML from the PDF. Alternatively, zugcmd -r splits an e-invoice into CSV files that FoxPro can import directly.

Why are there commas instead of points in the amounts?

STR() and TRANSFORM() use the decimal separator from SET POINT or the Windows settings. The SDK expects a point; the Amount() function on this page replaces the comma.

Is there a trial licence?

Yes. A free 30-day trial licence with full functionality is available by e-mail to info@aloaha.com; it can be extended if needed.

Business terms in this article: BT-1 BT-2 BT-3 BT-5 BT-31 BT-72 BG-25 BG-23 BG-22 BT-10 BT-81 BT-106 BT-109 BT-110 BT-112 BT-115 BT-116