ANAF declarations (base)¶
The Romania - ANAF Declarations Base (l10n_ro_declaration) module is the common
framework of the Romanian tax declarations filed with ANAF. Each declaration has its own module, which
computes the declaration from the posted journal items of the period, builds the official XML file,
and checks it before it is filed. The base module provides what all of them share: the period and
deadline handling, the status flow, the validation messages, the declarant data, the validation of
the XML against the official schema, and the connection to the ANAF validator DUKIntegrator.
Declaration |
Content |
Legal basis |
Module |
|---|---|---|---|
VAT return (Decont de TVA), monthly, quarterly, semi-annual or annual, with the reconciliation with the ANAF e-TVA pre-filled return. |
OPANAF 174/2026, periods from January 2026. |
|
|
Recapitulative statement of the intra-Community operations (Declarația recapitulativă, VIES), monthly. |
OPANAF 705/2020. |
|
|
Informative statement on the domestic supplies and acquisitions (Declarația informativă). |
OPANAF 3769/2015 as replaced by OPANAF 2194/2025, operations from August 2025. |
|
|
SAF-T file (Fișierul Standard de Control Fiscal). |
See the SAF-T page. |
|
|
Annual profit tax return, and helper for the quarterly micro-enterprise tax. |
OPANAF 206/2025, reporting year 2025. |
|
|
Annual financial statements and annual accounting reports, and the half-year report. |
OMF 2036/2025 (financial year 2025), OMF 1194/2025 (half-year report). |
|
The declarations are installed from the Apps menu; install the module of each declaration. The base module is installed automatically as a dependency. The D390 and D394 modules require the D300 module (they check their totals against the VAT return of the same period), and the D101 module requires the financial statements module.
Important
The declarations are available only for companies whose fiscal country is Romania and whose currency is RON. A declaration cannot be created for another company, and the computation is refused if the company currency is not RON.
The amounts of the declarations are rounded to whole lei (half up), as required by the ANAF forms.
The declarations are prepared in Odoo, but filing them with ANAF is a manual step outside Odoo, see Filing with ANAF.
Configuration¶
Company data¶
Go to and scroll to the Romanian ANAF Declarations section, which is displayed for Romanian companies. The values are stored on the company and proposed on every new declaration.
Setting |
Fields |
Used for |
|---|---|---|
Declarant |
Declarant Last Name, Declarant First Name, Declarant Position, Declarant CNP/CUI, Declarant Phone, Declarant Email |
The person who signs the declarations (nume, prenume, funcție). The last name, first name and position are mandatory: the validation fails if one of them is empty. The phone and email default to those of the company. |
Activity and VAT Period |
Main CAEN Code, VAT Period, Declaration Bank Account |
The CAEN code of the main activity actually carried out (exactly 4 digits); the VAT period (Monthly, Quarterly, Semi-annual or Annual), which is proposed as the period type of new declarations; and the bank account printed on the declarations (by default, the first bank account of the company). |
Fiscal Representative |
Representative Name, Representative CUI/CNP, Representative Address |
Optional. The proxy (împuternicit) who files the declarations on behalf of the company. |
DUKIntegrator Validation |
DUK Validator Service URL, DUK Validator Service Token, Request DUK PDF |
The connection to the ANAF validator, see Validation with DUKIntegrator. |
The declaration modules add their own settings to this section; for example, the D394 module adds the data of the person who prepares the declaration.
The company needs a valid CUI in its
Tax ID field: the validation checks its control digit. A company whose Tax ID does not
start with RO is not registered for VAT, and the VAT declarations show a warning.
Access rights¶
The menu is displayed to the users who have access to a company whose fiscal country is Romania and who have an accounting access right. Accountants can create and modify the declarations, users with read-only accounting access can only read them, and accounting advisers (managers) can also delete them and edit the configuration. A user only sees the declarations of the companies selected in the company switcher.
Tax codes and mapping rules¶
The declarations do not read the taxes directly. Every tax of the Romanian chart of accounts is linked to a Romanian tax code, which tells each declaration where the operation is reported: the rows of the D300, the operation type of the D390, and so on. The link is the Romanian Tax Code field of the tax (), which is filled in automatically for the taxes of the Romanian chart of accounts.
Accounting advisers can review and complete the catalogue in (this menu is reserved to them):
Romanian Tax Codes: the codes, with the VAT rate, the kind of operation and the D300, D390 and D394 treatment of each code. This is global master data, shared by all companies.
Tax Mapping Rules: rules that assign a tax code to an operation according to the tax, the type of document, the fiscal position, the location of the partner (Romania, EU, non-EU), the product category or a date range. They are used, for example, for the historic taxes at 19%, 9% and 5%, and for the VAT on payment taxes.
Note
If a tax used in the period has no tax code and no rule, the declaration shows an error message and the operation is left out. Link the tax to a code, or create a rule, and compute the declaration again.
Prepare a declaration¶
All the declarations work in the same way. Open the declaration from and click New.
Choose the period. The Period Type is proposed from the VAT Period of the company, and the year and the period number from the last finished period. The form shows the dates of the period (Period) and the legal Deadline. The declarant data is copied from the company and can be changed on the declaration.
Click Compute. The rows of the declaration are filled in from the posted journal items of the period, and the declaration moves to the Computed status. The local checks run at the same time and their findings are listed in the Validation tab.
Review the rows and complete the data that cannot be computed from the accounting. Edited values are kept when the declaration is recomputed with Recompute.
Click Validate. Odoo runs the local checks again, builds the XML, checks it against the official XSD schema, and, if the DUK validator is configured, validates it with DUKIntegrator. If no finding is an error, the declaration moves to Validated; otherwise it stays Computed.
Click Export XML. The XML file is attached to the declaration and downloaded, and the declaration moves to Exported.
File the declaration with ANAF (see Filing with ANAF), then click Mark as Submitted.
The XML file is named <form>_<CUI>_<period>_v<version>.xml, for example D300_12345678_2026-01_v1.xml
(2026-T1 for a quarter, 2026-S1 for a semester, 2026 for a year).
Deadlines¶
The Deadline is computed from the end of the period. If it falls on a weekend or on a Romanian public holiday (calendar of the localization base), it moves to the next working day.
D300 and D390: the 25th of the month following the period.
D394: the 30th of the month following the period.
D101: the 25th of June of the following year.
Annual financial statements: 150 days after the end of the year; half-year report: 45 days.
Corrections¶
A declaration that is exported, submitted or archived cannot be modified. To correct it, click Create Rectificative (Create Corrected Declaration in the D394). Odoo copies the declaration as a new version of the same period (Declaration Type Rectificative, Version + 1), linked to the declaration it corrects, and you compute, validate, export and file it like the first one. When the corrected version is marked as submitted, the previous versions are archived. The exact content of a rectificative depends on the declaration: see its page.
Validation messages¶
The findings of the checks are saved as validation messages. The buttons Errors and Warnings at the top of the declaration open them, and lists those of all the declarations, with filters on the severity and on the source of the message (XSD, DUKIntegrator, or the local checks). Each message has a code, the row concerned and, when it applies, the journal entry and the partner, to open them directly.
An error blocks the validation. A warning does not: read it, and correct the accounting or the declaration if it is justified.
Validation with DUKIntegrator¶
DUKIntegrator is the Java program with which ANAF checks the declarations before they are filed;
it contains the official validation rules of each form. Odoo checks every XML against the XSD schema
bundled with the module on its own, but the ANAF rules are stricter. Odoo therefore sends the XML to
a small DUK validator service, which runs DUKIntegrator and returns the result. The service is
shipped with the module in addons/l10n_ro_declaration/tools/duk_service and is installed
separately from Odoo, on a server that can reach static.anaf.ro.
Note
The ANAF programs (jar files) are not part of the module and are not redistributed: they are downloaded from the ANAF website with the script provided.
What the validation checks¶
When you click Validate, Odoo runs three checks in this order and records the result in the Validation tab:
The local checks of the declaration (company data, declarant, rules of the form, cross-checks with other declarations).
The XSD check (XSD Check): Valid, Invalid, or Schema missing.
The DUKIntegrator check (DUK Validation).
DUK Validation |
Meaning |
|---|---|
Valid |
DUKIntegrator answered |
Valid with warnings |
DUKIntegrator reported only warnings ( |
Errors |
DUKIntegrator reported at least one error ( |
Not configured |
No service URL is configured. The step is skipped, without any message, and the declaration can reach the Validated status without having been checked by ANAF’s rules. |
Service unavailable |
The service did not answer, answered with an error (for example, the token is wrong), or DUKIntegrator could not run (for example, the validator of the form is not installed). Odoo records a warning, which does not block the validation. |
Warning
Validated only means that Odoo found no error. If DUK Validation is Not configured or Service unavailable, the declaration has not been validated by DUKIntegrator. Install the service and make sure the status is Valid before filing.
When Request DUK PDF is ticked (the default), the service also returns the official PDF produced by ANAF’s program, with the XML attached, if the validation succeeds. It is attached to the declaration as DUK PDF. The D101 and the financial statements are validated without the PDF: ANAF’s PDF of these forms contains the annexes of the declaration (notes, reports), which are assembled with the ANAF assistance program.
Install the DUK validator service¶
The service needs Java (OpenJDK 21 was used to verify it) and Python 3, and it is started with the
files of ANAF in one folder (DUK_HOME). The module provides a Dockerfile that contains Java and
Python.
Download the ANAF programs. On a machine that can reach
static.anaf.ro, run the scriptdownload_duk.shof the service folder with the destination folder and the forms to validate:$ ./download_duk.sh /srv/duk D300 D390 D394 D406The script downloads
DUKIntegrator.jar, its libraries, the configuration, and the validator and PDF jars of every requested form (D300Validator.jar,D300Pdf.jar…) from the update feed of ANAF (versiuni.xml). Request all the forms that you use; for example, addD101,S1002,S1003,S1004andS1005for the profit tax return and the financial statements. WhenD406is requested, the script also installsDUKIntegrator_AnLunaUI.jar, the period-aware validator used for the SAF-T file (see SAF-T D406 (Romania)). Run the script again when ANAF publishes new versions of the validators.Choose a token. The service refuses to start without a token (
DUK_TOKEN), which Odoo sends as a bearer token. Use a long random secret. The--insecureoption starts the service without a token and is only meant for private test machines.Start the service. For example, with Docker:
$ docker build -t eyssen/duk-service . $ docker run -d --name duk -p 127.0.0.1:8080:8080 -e DUK_TOKEN=<secret> \ -v /srv/duk:/opt/duk:ro eyssen/duk-service
Or directly on the server:
DUK_HOME=/srv/duk DUK_PORT=8080 DUK_TOKEN=<secret> python3 duk_service.py. By default, the service listens on127.0.0.1only.Check it.
curl http://localhost:8080/healthanswers{"status": "ok"}, andcurl -H "Authorization: Bearer <secret>" http://localhost:8080/infolists the installed validators.
Important
Do not expose the service on the Internet. Publish the port on a private interface or a private network that only the Odoo server can reach, and keep the token secret.
The service is configured with environment variables:
Variable |
Default |
Meaning |
|---|---|---|
|
|
Folder with |
|
none |
Bearer token, mandatory unless the service is started with |
|
|
Address and port of the service ( |
|
|
Seconds allowed for one validation. Raise it for large SAF-T files. |
|
|
Number of validations that run at the same time. A request that waits more than
|
|
400 MB |
Maximum size of the XML file. |
|
|
Java executable and extra options, for example |
Connect Odoo to the service¶
Go to , section Romanian ANAF Declarations, setting DUKIntegrator Validation, and fill in:
DUK Validator Service URL: the base URL of the service, for example
http://duk:8080. Leave it empty to skip the ANAF validation.DUK Validator Service Token: the
DUK_TOKENof the service. Only administrators see this field.Request DUK PDF: tick it to receive the official PDF.
Instead of configuring each company, the service can be set once for the database with the system
parameters l10n_ro_declaration.duk_service_url and l10n_ro_declaration.duk_service_token
(developer mode, ). A company that has its own URL uses its own token; the token of the system
parameter is only sent to the URL of the system parameter, never to a URL typed on a company. The
parameters l10n_ro_declaration.duk_service_timeout (seconds, 120 by default) and
l10n_ro_declaration.duk_raw_threshold (bytes, 20 MB by default; larger files are streamed to the
service) can also be set.
Filing with ANAF¶
Odoo prepares and checks the declarations, but it does not send them to ANAF: there is no connection to the ANAF filing services in the declaration modules. After the validation:
Click Export XML and, if it was requested, open the DUK PDF in the Validation tab.
File the declaration with ANAF yourself, for example through the SPV (Spațiul Privat Virtual, the private virtual space of the taxpayer on the ANAF portal), with the file that the portal requires for the form.
Back in Odoo, click Mark as Submitted. Optionally, enter the Submission Date and the Registration Number (număr de înregistrare) that ANAF gave to the declaration. These two fields are informative: Odoo does not check them.
Note
The e-Factura integration, which sends invoices to the SPV, is a separate feature and does not file the declarations.