EPO Consulting Wiki - EInvoice - ZUGFeRD

This is an old version of this page. To the new page please click here

Das ist eine alte Version dieser Seite. Zur neuen Seite klicken sie hier

Create a PDFA-3B pdf file from an invoice - PDF and a CII XML-invoice by means of an ADS server. This package connects the e-invoice with the ZUGFeRD package.


  • 'EPO connector' installed
  • 'EPO outgoing invoice ledger' installed
  • 'EPO ZUGFeRD base package' installed
  • Adobe ADS server installed and reachable
  • RFC destination 'ADS' (or similar name) to the ADS server maintained
  • EPO number range /EPO1/NOR is already defined

Download the installation packages from the EPO NextCloud:

  • folder 'EPO eInvoice ZUGFeRD'
  • EPO_LedgerOI_ZUGFeRD_v<version>_...zip


Import the latest version of the ZIP file - see importing EPO transport packages.


Send the e-invoice via e-mail

EPO customizing

Transaction /EPO1/EXC

create the e-mail service

  • EPO Connector Area Menu
  • EPO Connector Configuration
  • Maintain EPO Connector services

Create a new outgoing service:

  • Service: EPO_ZF_EMAIL
  • Direction: O - out of SAP
  • check 'Operation mandatory
  • Description: 'create e-mail with ZUGFeRD in SOST'


map a service id to the service

  • EPO Connector Area Menu
  • EPO Connector Configuration
  • Outbound Service Configuration
  • Maintain service assignment by SY-SYSID

Create an entry for each SAP - system (development, test, productive):

  • SAP system ID: ..the SAP ID
  • Service name id: EPO_ZF_EMAIL
  • Service: EPO_ZF_EMAIL
  • Operation: E-Mail
  • Description: E-mail with SOST


create the operation

  • EPO Connector Area Menu
  • EPO Connector Configuration
  • Outbound Service Configuration
  • EPO Client
  • Out: Maintain EPO Client service configuration

Create a new operation:

  • Service: EPO_ZF_EMAIL
  • Operatition: E-Mail
  • NR object: /EPO1/NOR
  • Number Range Number: 01
  • Protocol: 3 UM - E.Mail via SCOT
  • Processing type: S synchronous
  • EPO Header: X (store outgoing and incoming messages)
  • UM Content type: HTM Content-Type: text/html
  • FILE,UM compression: (none)
  • FILE,UM comp>n Bytes: 0
  • Description: E-mail in SOST


customizing e-mail function module - /EPO1/EC_EB_WSFM

Create one line for each SAP system-ID:

  • SAP System ID: <SAP system ID>
  • Service ID: EPO_ZF_MAIL
  • No response storage: X


customizing ZUGFeRD profile - /EPO1/INV_ZUG_PR

The desired ZUGFeRD profile can be customized, depending on the invoice type:

  • profile:
  • 0 XRECHNUNG - UBL format
  • 1 basic - CII format
  • 2 en 16931 - CII format
  • 3 extended - CII format
  • service ID: ADS
  • operation: create_pdf


Mail subject / body text - SO10

Create texts in each used language:

Transaction SO10

  • textname:
  • /EPO1/INV_EMAIL_SUBJECT - for the subject text
  • /EPO1/INV_EMAIL_BODY - for the e-mail body text
  • text-id: ST
  • language: <each_used_language>

The first '&' - character in the subject will be replaced by the invoice number.

If the SO10-text is not available, a standard text will be used.


e-mail processing, data flow

This chapter describes the data flow in simple steps (not in detail). The XML is stored with 'is invoice' - sign 'Y', the PDF ist stored with the sign 'X'.

Select an invoice in the outgoing invoice ledger (transaction /EPO1/OIL) and press the 'SEND'-button.

  • case 'SEND'
  • function module /EPO1/OI_SEND
  • read function module from /EPO1/EC_EB_WSFM (e.g. /EPO1/INV_LED_ZUG_SEND_MAIL)
  • function module /EPO1/INV_LED_ZUG_SEND_MAIL
  • form PREPARE_ZUGFERD_PDF - merge XML and PDF into ZUGFeRD - PDF
  • form SAVE_ZUGFERD_PDF - save the ZUGFeRD PDF back into the outgoing invoice ledger
  • find sender/receiver(s)
  • get subject/mail body from SO10 - texts


redefinition of ZUGFeRD classes

Derive from the base classes, redefine required methods



Base classes:


customizing table /EPO1/SUBCLASSES

Maintain the subclasses-table in order to use the new classes (only as example - use the real names of the newly created classes!).

Class/Interface Mode Class/Interface


Correction of sales contact - methods H35_ACCOUNTINGSUPPLIERPARTY

Default: the contact data of sales bureau 'ZXRE' is used to fill the name, telephone number and e-mail address.

If this sales bureau is not maintained, or when a logic is required to get the sales contact information, these methods has to be redefined.

Data to be supplied:

  • m_ubl21- / m_ublcn21-accountingsupplierparty-party-contact-name
  • m_ubl21- / m_ublcn21-accountingsupplierparty-party-contact-telephone
  • m_ubl21- / m_ublcn21-accountingsupplierparty-party-contact-electronicmail


Correction of rounding errors - methods H54_CREDITNOTELINE, H54_INVOICELINE

The CII version 1.0 requires the piece prices with 4 decimals. In order to get a valid XML, the product of piece price * number of pieces has to match the position price exactly.

In UBL, the piece-price is only calculated with 2 digits, which is sometimes not fine enough. Additionally, there are value combinations, which cannot represent exact values as required.


  • netto price = 6,77€ for 300 pieces
  • price per piece with 4 decimals:
0,0225 * 300 = 6,75 (too less)
0,0226 * 300 = 6,78 (too much)
-> it is not possible to calculate a piece price, where 'piece price * number of pieces' matches the position price.

Correction steps for price calculation (only performing required steps!):

  1. calculate the piece price with 4 decimals (instead with 2 decimals, which is standard for UBL-XML)
  2. correct rounding errors (if required)
  3. use the position price as piece-price, use the position quantity as base unit for the price calculation

Please note, that the last correction will produce an XML, which does not exactly represent the PDF representation (which is a requirement for ZUGFeRD), but there is no other possiblity to get a valid XML wich passes a validator.

added data declaration:

    DATA lv_curvalue_4   TYPE p LENGTH 15 DECIMALS 4.
    DATA lv_netwr_check  TYPE netwr.

inserted code (after the assignment of piece-prices and base unit):

    " check/correct piece price
    IF is_it_gen-fkimg > 0.
      l_curvalue = ls_price-priceamount-element_value.
      l_curvalue = l_curvalue * is_it_gen-fkimg.
      IF l_curvalue <> ls_it_price-netwr.
        " calculate the precise price (with 4 decimals instead of only 2)
        lv_curvalue_4 = ls_it_price-netwr / is_it_gen-fkimg.

        " check result, try to correct the last digit
        lv_netwr_check = lv_curvalue_4 * is_it_gen-fkimg.
        IF lv_netwr_check > ls_it_price-netwr.
          lv_curvalue_4 = lv_curvalue_4 - '0.0001'.
        ELSEIF lv_netwr_check < ls_it_price-netwr.
          lv_curvalue_4 = lv_curvalue_4 + '0.0001'.

        ls_price-priceamount-element_value = /epo1/cl_ubl_helpers=>move_and_condense( lv_curvalue_4 ).

      " final check/correction for piece price
      lv_curvalue_4  = ls_price-priceamount-element_value.
      lv_netwr_check = lv_curvalue_4 * is_it_gen-fkimg.
      IF lv_netwr_check <> ls_it_price-netwr.
        " set piece - price to position price, set base quantity to position quantity
        " (just to satisfy the validator)
        ls_price-priceamount-element_value  = /epo1/cl_ubl_helpers=>move_and_condense( ls_it_price-netwr ).

        ls_it_price-kpein = is_it_gen-fkimg.
        ls_price-basequantity-element_value = /epo1/cl_ubl_helpers=>move_and_condense( ls_it_price-kpein ).



Connection: outgoing invoice ledger / ZUGFeRD


NextCloud: Kundenprojekte / EPO / SoftwareDownload / EPO eInvoice ZUGFeRD


Version 1.3.2

Transport order WK1K902860 29.06.2022

  • correction for mail recipient: use RE, not RG

Aktivities before import:

  • none


Version 1.3.1

Transport order WK1K902691 14.03.2022

  • H23, BuyerReference from M_INV-HD_REF-PURCH_NO

Aktivities before import:

  • none


Version 1.3.0

Transport order WK1K902478 16.12.2021

  • suppport for subclasses in the e-mail send function module (print program accepts subclasses-key = 'ZUGF'

Aktivities before import:

  • none


Version 1.2.3

Transport order WK1K902359 23.11.2021

  • print program accepts subclasses-ID 'ZUGF' for invoice and credit note
  • print program handles new parameter for schematron - checks

Aktivities before import:

  • update also the package ZUGFeRD to version 1.4.6 (or newer)
  • update also the package e-Invoice to version 2.4.5 (or newer)


Version 1.2.2

Transport order WK1K902340 18.11.2021

  • correction: read ZUGFeRD version / profile from existing XML invoice instead from database tables

Aktivities before import:

  • update also the package ZUGFeRD to version 1.4.5 (or newer)
  • update also the package e-Invoice to version 2.4.4 (or newer)


Version 1.2.1

Transport order WK1K902107 16.06.2021

  • correction SKONTO: base amount, base date and period

Aktivities before import:

  • update also the package ZUGFeRD to version 1.4.2 (or newer)


Version 1.2.0

Transport order WK1K901989 25.06.2021

  • support for SKONTO information in XML structure

Aktivities before import:

  • update the package e-Invoice to version 2.3.0 (or newer)


Version 1.1.2

Transport order WK1K901893 10.05.2021

  • try to restore NAST after calling the external print program

Aktivities during import:

  • none


Version 1.1.1

Transport order WK1K901887 10.05.2021

  • correction: undo the insertion of a new method parameter in the UBL base class

Aktivities during import:

  • update also the package ZUGFeRD to version 1.3.0


Version 1.1.0

!! do not use !!

Transport order WK1K901876 06.05.2021

  • support for version 1.0

Aktivities during import:

  • update also the package ZUGFeRD to version 1.3.0
  • update also the e-Invoice package to version 2.3.0


Version 1.0.1

Transport order WK1K901653 22.02.2021

  • correction transformation UBL -> CII

Aktivities after import:

  • none


Version 1.0.0

Transport order WK1K901531 12.01.2021

  • initial version

Aktivities after import:

  • none