ZUGFeRD 2.1/ Factur-X 1.0 for Dynamics 365 FO

ZUGFeRD 2.1/ Factur-X 1.0 for Dynamics 365 FO

We are excited to announce the release of the common German-French electronic invoice ZUGFeRD / Factur-X in Dynamics 365 for Finance and SCM. This plug-and-play solution in its “Light” version does not require any customisation and can be easily installed in the standard Electronic Reporting module of D365. It supports the ZUGFeRD 2.1.1/Factur-X 1.0 profile EN 16931, also known as the “COMFORT” profile, which meets all tax law requirements and must be accepted by customers unless explicitly denied.

In the ZUGFeRD/Factur-X standard, the invoicing information is included in an XML payload attached to a human-readable PDF file (see https://de.wikipedia.org/wiki/ZUGFeRD). This is in contrast to the Italian electronic invoicing system, where a PDF is embedded in a Base64 encoded block within an XML. The PDF document is just a visualisation of the electronic content, what counts is the XML attachment. The XML file is always named factur-x.xml and it is attached to at the PDF document level, not to a single PDF page:

Here is an example: factur-x.xml

Our solution, which utilizes Configurable business documents in D365, supports Sales invoices with separate buyer, seller, and order accounts. Other types of invoices such as the Free text invoice or any of the 3 Project invoices, can be provided upon request at a discounted price. Our solution also handles form notes, line and header notes and footers, line discounts, total discounts, and cash discounts, document level charges, properly reflecting VAT for domestic, EU, and export sales. The settlement instructions orchestrate a SEPA credit transfer or a SEPA direct debit withdrawal; partially prepaid invoices are properly interpreted. The solution is available in French, German, and British English.

Price

The solution is offered at a fixed fee per end customer / D365 tenant:
Version Price Deliverables Notes
Light €890 A ZUGFeRD Sales invoice ER configuration, the XML file only This option does not require any X++ customisations or 3rd party software and can be installed and used right away.
Light+ €1200 Same as the Light version but with 5 hours of prepaid support and installation  
Heavy €2200 Contains the full solution, including a PDF template, and a PDF post-processor with 8 hours of prepaid support. Includes the iTextSharp 5.5.13.2 .NET library under the GNU Affero General Public License
Includes the BouncyCastle 1.8.9 .NET cryptographic library under a variant of the MIT license.

Setup and use

 
  1.  Import the Electronic configuration “ZUGFeRD Sales invoice” provided to you (Organisation administration > Electronic reporting > Configurations, button Exchange / Load from XML file). For the ease of installation, configuration and integration, the standard Invoice model Invoice model v 277 and the standard Invoice model mapping 277.258 are used, make sure they have been imported upfront.
  2. Beware: the standard Invoice model mapping from Microsoft has a number of shortcomings. For instance, the buyer and seller addresses are passed in a de-normalized form as multi line strings. As a walkaround, some heuristics and regular expressions have been applied to extract the ISO2 code of the country and the zip (postal) code. A well-known modification to the standard Invoice model mapping will fix that and reinforce the report. Futhermore, the current Microsoft Invoice model mapping does not pass the EU Tax directives to the report. At the moment, the report relies on the non-EU Tax exempt codes in the same way as the standard Excel invoice does. To leverage the Tax directives, fix the model mapping, then modify the ZipFolder/InvoicePDF/SalesTax/SalesTax* mappings in ZUGFeRD Sales invoice format like this:
    IF(OR(@.Value.TaxExemptDescription<>"",@.Value.TaxDirective<>""),
    IF(@.Value.TaxExemptDescription<>"",@.Value.TaxExemptDescription,@.Value.TaxDirective),
    @"GER_LABEL:PlusVAT")
  3. Under the button Configurations / Application specific parameters / Setup, provide a mapping of the VAT (en-us: Sales tax) Print codes to the ZUGFeRD categories S, K, AE, G, O (for example, the 19% and 7% VAT belong to the “S” category). Also provide a mapping of the D365 Unit of measure codes to the UNECE Recommendation No. 20 list called “Codes for Units of Measure Used in International Trade” (see https://tfig.unece.org/contents/recommendation-20.htm). For instance, a piece has the standard code H87. A sample parameter setup can be downloaded here: 03-01-2023 03.29.45 pm_ZUGFeRD Sales invoice.277.11
  4. Pay attention to the sample VAT print codes on the screenshot above: the standard Invoice model mapping does not pass the tax rates to the report, and the VAT Print code must contain the VAT rate in numbers, if applicable. In other words, they should look like “19%” and “7%” in Germany or “20%” and “5,5%”in France. The mapping of the sales units of measure is against the language-specific, translated unit code (if exists), not the UoM symbol used in D365 globally, i.e. not pcs but Stk. Once both the mappings have been established, set the Application specific parameters State to Completed.
  5. Open Sales ledger (en-us: Accounts receivable) > Setup > Forms > Form setup. Make sure that the VAT specification option is set to Registration currency. You will also probably Print VAT number on invoice, show some invoice line inventory dimensions and/or notes, and display external item numbers (Item number in forms = Both).
  6. Finally, open Print management and select the Report format = ZUGFeRD Sales invoice at the Customer invoice node. The Light version setup ends here.
  7. For the Heavy version, first deploy the X++ customisations and libraries provided.
  8. Create a new File document type in the Organisation administration > Document management > Document types list. Name it exactly like this: ZUGFeRD.
  9. Create a new ER destination (Organisation administration > Electronic reporting > Electronic reporting destination) for the report ZUGFeRD Sales invoice. Under File destination, add a new line and divert the ZipFolder file component to the Archive: click Settings, then Archive, set Enabled and Save in job archive, and choose file Type = ZUGFeRD. The Archive destination is namely the only one to plug in/subscribe to.
  10.  Make sure that the feature Configure action-dependent ER destinations is turned OFF: https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/analytics/er-action-dependent-destinations. It doesn’t work well anyway.
  11. The steps to configure the Heavy version end here. The Electronic Reporting engine will fill out the PDF form, populate an XML file and put both into a ZIP (i.e. a folder). This ZIP file is intercepted, unpacked, and the XML part is embedded into the PDF, adding some links and attributes required. The resulting PDF is rendered on the screen in a separate browser window. Other output destinations than the Screen may be offered upon request at a discounted price. The PDF file is not fully PDF-A/3 compliant, but it can be read and parsed, the XML payload passes all validations. Please bear in mind that PDF forms never contain repeatable ranges or cells. This is the reason why the number of invoice lines is currently limited by 10, this number will be extended on demand; see also Design ER configurations to fill in PDF templates – Finance & Operations | Dynamics 365 | Microsoft Learn.
  12. Print or reprint an invoice with the option Use print management turned on.
  13. The resulting PDF document is displayed on the screen (the Light version offers an XML file to download). Here is a sample, you buy what you see:



Useful links:

Batch jobs in D365: a Russian roulette

Batch jobs in D365: a Russian roulette

Real world production scenarios include automated batch tasks executed in the background with some cadence: Batch processing overview – Finance & Operations. They apply to sets of documents fetched at the run time, for example to sales orders delivered, but not invoiced yet. Obviously, every day the query with the documents should return a different set with the recently despatched sales orders. It is called Late selection: Late selection in D365FO – D365Tour. So far so known.

As the complexity of the business grows, so does the complexity of the batch jobs. You’ll need jobs consisting of multiple tasks, executed one after another. It is called task dependency, or task Constraints. One of the latest unpleasant discoveries was the fact, that you cannot always rely on the sequence of steps set in the batch job: the most useful tasks, such as the SalesFormLetter_Invoice and its likes (used to update sales and purchase orders with order confirmations, delivery notes and invoices) act as orchestrators and spin off child batch tasks for simultaneous, multi-threaded sales order, purchase order, production order processing. These child tasks are not constrained (!) and get executed at a first come, first served basis. They may still run while the master task SalesFormLetter_Invoice seemingly ends and relays the baton to the next task. This leads to interference and racing conditions. You better evaluate the average execution time of the master controller task as a whole, put these controllers into different batch jobs, schedule them at a safe time distance from one another.

Heterogenous batch jobs as the one shown below pose a different challenge.

Here is the how-to instruction:

  1. Spin off the first task from the main menu (here: Production control > Periodic tasks > Production order status update) and choose Run in the background / Batch processing. This will be your starting point, a template for the batch job.
  2. Locate the batch job in the My batch jobs list, set the status to Withheld and start editing.
  3. Every task within a batch job needs a Class name. Now you know the class name of the first task: ProdMultiCostEstimation. To add the next task, you have to manually specify its Class name. The owners of this framework provided a lookup list, but it is slow and completely dysfunctional: it shows just a fraction of the possible executable RunBase or SysOperation classes, sometimes it crashes if there are some bad customizations in the source code. If you don’t know the class name, repeat the step 1 to reveal it.
  4. Add the next task, type the class name in. The first time it will take the system up to 20-30 seconds to accept and retrieve the Class description.
  5. Most batch tasks need a query. Click Parameters to populate it. Here you experience another nasty trait of the batch framework: the query shown is the last one you used in the system elsewhere. It is not necessarily the one really persisting at the batch task. Another user is not going to see your query criteria at all: only the owner/creator has the control. *1) *2) *3)
  6. On the Batch task details tab, Constraints, choose the predecessor task to build a chain. You many need to change the Expected status to Ended or error if the batch job has to continue with the next task on an error somewhere in the chain.
  7. Check the recurrence, remove the Alerts if needed, and put the Batch job back to Waiting.

1) Lessons learned: take a screenshot of every query and parameter, document it thoroughly to pass the maintenance to the Dynamics system administrator.

2) In certain cases a manually added task does not let edit the execution parameters and/or the query. Sometimes(e.g. on sales order updates) it helps to execute the same periodic task in the normal user session once. This is the reason why it is often hard to pre-configure the batch jobs in a “Golden Config” environment: it may need real transactions to execute against. Sometimes it wishes to be initialised from the main menu and nowhere else because badly programmed. In such a case, start your step 1 – the key task – from this critical periodic task. Should there be 2 such bitchy tasks in one batch job chain, it is over. They must be separated into different batch jobs.  

3) As a really bad surprize came the fact that even the owner has no control over the query: if you use the Late selection, in a chain of nearly identical tasks as the ones below, the QUERY OF THE LAST TASK IS APPLIED TO EVERY TASK of the kind, at least in the case of the production order status updates.

You should let the bloody job run one first time, then put the batch job back on hold and adjust the queries in the tasks once more, then save and re-activate the batch job.

Austrian VAT declaration / Umsatzsteuervoranmeldung 2020

Austrian VAT declaration / Umsatzsteuervoranmeldung 2020

Following up on my latest blog, let me continue with the specific setup for the VAT return in Austria. This electronic VAT declaration called Umsatzsteuervoranmeldung “UVA” must be uploaded monthly or quarterly (depending on the company’s turnover) in a proprietary XML format to the web site FinanzOnline of BMF, the Austrian Ministry of Finance. The interface is well maintained by the DACH support team for Dynamics, but there was nowhere on the Internet a description of the barebone setup. Well, up until now.

The only documentation is the class TaxReport_ReportAT, which is used by the periodic function VAT payment in the Tax module to produce a “UVA” declaration, both printed and the electronic. I reverse engineered it, and it should be noted that

  • It requires a non-continuous number sequence XML VAT package number to form a message ID.
  • The printed PDF version is not accepted by the ministry anymore, but it is quite useful to visualize and check the VAT return prior to the booking. The latest template required by the class can be downloaded here.
  • The printed form expects an exotic address format of the legal entity primary address, one with a separate house number Street number.
  • The tax number (not to mix with the European VAT (UID)-number) MUST be present in the legal entity, Tax registration number field in the format xxx/yyyy-ZZ, where ZZ is the number of the BMF’s local office. The same can be seen without dashes and slashes on FinanzOnline.
  • The class uses a set of hardcoded 4 digit codes to map tax codes to cells on the tax return. There are cells (and the respective XML elements) for a total tax base per tax period per VAT rate, or a tax amount per tax period per VAT rate.

Below are the most relevant VAT return cell codes. For more information on the individual VAT return cells, please refer to the comprehensive description (de-at) on the BMF site.
You should add the 16 codes to the table VAT reporting codes with the Report layout = Austrian report layout.

Reporting codeReport textBrief description
1122Gesamt Umsatzsteuer: 20% NormalsteuersatzTotal sales VAT: full 20%
1022Gesamt Bemessungsgrundlage: 20% NormalsteuersatzTotal sales base: full 20%
1011Bemessungsgrundlage: Ausfuhrlieferungen § 6 Abs. 1 Z 1 iVm § 7Sales base: Export 3rd country tangible
1021Bemessungsgrundlage: Steuerschuldübergang § 19, grenzüberschreitende LeistungenSales base: Reverse charge incl. export of services IC, 3rd
1020Bemessungsgrundlage: übrige steuerfreie Umsätze ohne VorsteuerabzugSales base: Other exempt sales
1017Bemessungsgrundlage: IgL Art. 6 Abs. 1 ohne FahrzSales base: IC delivery
1160Vorsteuer ohne…Total purchase VAT except for…
1157Steuerschuldübergang bei Bezug gemäß § 19 Abs. 1 zweiter Satz, § 19 Abs. 1cIC purchase payable VAT: Reverse charge on service acquis
1166Vorsteuer: Steuerschuldübergang gemäß §19, grenzüberschreitende LeistungenIC purchase receivable VAT: reverse charge on service acquis
1183Vorsteuer: Einfuhrumsatzsteuer geschuldet (§ 12 Abs. 1 Z 2 lit. b)Purchase 3rd country import VAT (payable)
1172IgE Steuerschuld: 20% NormalsteuersatzIC purchase payable VAT: full 20%
1072IgE Bemessungsgrundlage: 20% NormalsteuersatzIC purchase payable base: full 20%
1106Gesamt Umsatzsteuer: 13% ermäßigter SteuersatzTotal sales VAT: reduced 13% (agro B2C)
1006Gesamt Bemessungsgrundlage: 13% ermäßigter SteuersatzTotal sales base: reduced 13% (agro B2C)
1129Gesamt Umsatzsteuer: 10% ermäßigter SteuersatzTotal sales VAT: reduced 10% (foodstuffs, print media)
1029Gesamt Bemessungsgrundlage: 10% ermäßigter SteuersatzTotal sales base: reduced 10% (foodstuffs, print media)

 

Finally, the above 16 reporting cells are assigned to my 12 VAT codes in the VAT codes table:

Report setupexFexSeuFeuAeuReuSNRTFdoFdoAdoHdoR
Taxable sales        1022102210061029
Duty-free sale101110211017101710171021 1020    
VAT payable        1122112211061129
Taxable purchases            
Duty-free purchase            
VAT receivable        1160116011601160
Taxable import  107210721073       
Offset taxable import            
Import VAT/ purchase VAT1183 1172117211731157      
Offset import VAT/ purchase VAT     1166      
(EU sales list excluded)yesyes    yesyesyesyesyesyes
(Country type)3rd3rdEUEUEUEU DomDomDomDomDom

The Report setup – credit note of the VAT code records is identical.

The full list of the Austrian VAT reporting codes can be downloaded here. The not relevant codes are marked “N/A”. My criteria for the relevance for a typical manufacturing or a service business were:

  • Reselling of cars, scrap, gas, electricity, CO2 certificates are ‘exotic’ businesses, as well as seafaring, trucking, taxi services, real estate agencies;
  • Small businesses below the 100 000 EUR turnover threshold would never use Dynamics AX either;
  • The Jungholz and Mittelberg exclave valleys with the German VAT are too small to get noticed;
  • It is not practical to apply a dedicated tax code to goods intended for the self-consumption by the company owner: such goods do not reduce the income/corporate tax base either and should better not appear in the accounting at all, or be simply sold to the owner via a sales order as everything else.

Happy tax paying!