Build a VAT Ledger into the D300 VAT Return XML
Skill: Convert a VAT ledger into the Romanian D300 (Decont de TVA) XML for ANAF
Region: Romania (România)
Category: VAT — D300 Decont de TVA (ANAF, formular 300)
Does: Takes a VAT ledger (jurnale de vânzări/cumpărări) and produces the D300 XML (declaratie300) — output and input TVA by rate, intra-EU acquisitions and reverse-charge rows, official rând (row) numbering, and the resulting sold TVA — submitted electronically to ANAF.
Standard: ANAF formular 300 (Decont de taxă pe valoarea adăugată), XML validated by ANAF DUKIntegrator (PDF inteligent)
This XML is the periodic VAT return (
declaratie300) filed with ANAF. Filing is monthly (or quarterly for taxpayers whose prior-year turnover was below €100,000 with no intra-EU acquisitions), due by the 25th of the month following the period. Figures must reconcile with the RO e-Factura and SAF-T (D406) data for the same period. The AI produces the XML; the user validates with DUKIntegrator and submits. Verify the current TVA rates and row layout before use.
When this applies
- A VAT-registered Romanian taxable person filing the periodic Decont de TVA for a month or quarter.
- The output is one
declaratie300carrying the company id, period, and the official rows for collected (colectată) and deductible (deductibilă) VAT. - Excluded: the D301 special VAT return, the D390 recapitulative statement (VIES), and the D394 informative declaration — those are separate forms.
Conversion procedure
- Read the source. Accept the VAT journals as CSV/JSON, an accounting export, or pasted summaries of sales and purchases by rate. Parse company id, period, and amounts per category.
- Extract fields. Identify: CUI, company name, fiscal year, reporting month/quarter; taxable base and VAT for domestic supplies by rate (19/9/5); intra-EU supplies and acquisitions; reverse-charge (taxare inversă) operations; exempt/zero-rated; deductible input VAT by rate; any prior-period carry-forward (sold negativ reportat). If a required base or VAT figure is missing, stop and ask.
- Normalize. Round every amount to whole RON (the D300 is filed in lei, no decimals). Dates → period as
luna+an. Map each ledger category to its officialrând. - Compute. Recompute VAT = base × rate for each rate; sum collected VAT (TVA colectată), sum deductible VAT (TVA deductibilă); derive the balance: TVA de plată (if collected > deductible) or TVA de recuperat (if deductible > collected), after applying any carried-forward negative.
- Emit the return. Build
declaratie300with the populatedrandrows per the Document structure, using the worked example as the template. - Validate. Work through the Validation checklist; run through ANAF DUKIntegrator and reconcile against e-Factura/SAF-T.
Source → D300 field map
| From the source | → Target element / field |
|---|---|
| Company CUI | declaratie300/@cif |
| Company name | declaratie300/@d_rec (declarant) / identification block |
| Reporting month | declaratie300/@luna |
| Reporting year | declaratie300/@an |
| Domestic supplies 19% base | rand_1 (@b base) |
| Domestic supplies 19% VAT | rand_1 (@v valoare TVA) |
| Domestic supplies 9% base/VAT | rand_2 (@b, @v) |
| Domestic supplies 5% base/VAT | rand_3 (@b, @v) |
| Intra-EU supplies (exempt) | rand_14 |
| Intra-EU acquisitions of goods (base/VAT) | rand_5 |
| Reverse-charge supplies received (taxare inversă) | rand_12 |
| Total collected VAT | rand_16 (total TVA colectată) |
| Deductible input VAT 19% | rand_24 |
| Intra-EU acquisitions deductible VAT | rand_25 |
| Reverse-charge deductible VAT | rand_27 |
| Total deductible VAT | rand_30 (total TVA deductibilă) |
| VAT to pay (sold pozitiv) | rand_33 / rand_38 (TVA de plată) |
| VAT to refund (sold negativ) | rand_35 / rand_40 (TVA de recuperat) |
| Carried-forward negative balance | rand_38 (sold negativ reportat) |
Row numbers follow the official formular 300 layout; populate only the rows that apply.
Document structure
declaratie300 (@cif, @luna, @an, @d_rec, @total_plata_a, @sumaramburs ...)
├── (identification attributes — CIF, period, declarant)
├── rand_1 (livrari 19% : @b base, @v TVA) ← TVA colectată
├── rand_2 (livrari 9%)
├── rand_3 (livrari 5%)
├── rand_5 (achizitii intracomunitare bunuri)
├── rand_12 (taxare inversa — beneficiar)
├── rand_14 (livrari intracomunitare scutite)
├── rand_16 (TOTAL TVA colectată)
├── rand_24 (achizitii 19% deductibile : @b, @v) ← TVA deductibilă
├── rand_25 (achizitii intracomunitare — deductibil)
├── rand_27 (taxare inversa — deductibil)
├── rand_30 (TOTAL TVA deductibilă)
├── rand_33 (sold TVA de plata in perioada)
├── rand_35 (sold negativ de TVA in perioada)
├── rand_38 (TVA de plata / sold negativ reportat)
└── rand_40 (TVA de recuperat)
The D300 is a flat sequence of numbered rand rows (each typically with base @b and value @v attributes) under a single declaratie300 root holding the identification attributes. Only the applicable rows are emitted; totals rows (rand_16, rand_30) and balance rows (rand_38/rand_40) are always computed.
Code tables
Romanian TVA rates (cota de TVA)
| Rate | Applies to |
|---|---|
19 |
Cota standard (standard) |
9 |
Aliment, medicamente, apă, cazare hotelieră (reduced) |
5 |
Cărți, locuințe sociale, anumite livrări (reduced) |
0 |
Scutit cu drept de deducere / livrări intracomunitare, export |
Period attributes
| Attribute | Values |
|---|---|
@luna |
1–12 for monthly filers; 3/6/9/12 for quarterly (last month of quarter) |
@an |
Four-digit fiscal year (e.g. 2026) |
Key D300 rows (rânduri, selected official numbering)
| Row | Meaning |
|---|---|
rand_1 |
Livrări de bunuri/servicii taxabile cu cota 19% |
rand_2 |
Livrări taxabile cu cota 9% |
rand_3 |
Livrări taxabile cu cota 5% |
rand_5 |
Achiziții intracomunitare de bunuri pentru care beneficiarul este obligat la plata TVA |
rand_12 |
Achiziții de bunuri/servicii — taxare inversă (beneficiar) |
rand_14 |
Livrări intracomunitare de bunuri scutite |
rand_16 |
TOTAL TVA colectată |
rand_24 |
Achiziții taxabile cu cota 19% — TVA deductibilă |
rand_25 |
Achiziții intracomunitare — TVA deductibilă |
rand_27 |
Taxare inversă — TVA deductibilă |
rand_30 |
TOTAL TVA deductibilă |
rand_33 |
Sumă negativă a TVA în perioada de raportare |
rand_38 |
TVA de plată |
rand_40 |
Sumă negativă a TVA de recuperat |
Calculation rules
- VAT per rate:
rand_n/@v=rand_n/@b× rate ÷ 100, rounded to the nearest whole RON (D300 has no decimals). - Reverse charge / intra-EU acquisitions: VAT is reported in both a collected row (
rand_5,rand_12) and a deductible row (rand_25,rand_27) at the same amount when fully deductible (net effect zero). - TVA colectată (
rand_16) = Σ of all collected-VAT rows (rand_1..rand_15value columns). - TVA deductibilă (
rand_30) = Σ of all deductible-VAT rows (rand_24..rand_29). - Balance: if
rand_16>rand_30→ TVA de plată =rand_16−rand_30(rand_38); ifrand_30>rand_16→ sold negativ (rand_33/rand_40), carried forward or refunded. - Apply any sold negativ reportat from the prior period before the final de plată / de recuperat.
- All amounts whole RON; recompute every total and the balance — flag any mismatch with the source.
Worked example (end-to-end)
Input — pasted VAT journals
Firma: Exemplu Distributie SRL, CUI 12345678
Perioada: luna 5, an 2026 (lunar)
Jurnal vanzari:
Livrari interne cota 19%: baza 100.000 lei, TVA 19.000 lei
Jurnal cumparari:
Achizitii interne cota 19%: baza 40.000 lei, TVA deductibil 7.600 lei
Achizitie intracomunitara bunuri: baza 10.000 lei (TVA 1.900 lei, integral deductibil)
Fara sold negativ reportat.
After extraction + normalization (intermediate)
{
"cif": "12345678", "luna": "5", "an": "2026",
"colectata": {
"rand_1": { "b": 100000, "v": 19000 },
"rand_5": { "b": 10000, "v": 1900 }
},
"deductibila": {
"rand_24": { "b": 40000, "v": 7600 },
"rand_25": { "b": 10000, "v": 1900 }
},
"totalColectata": 20900,
"totalDeductibila": 9500,
"soldReportat": 0,
"tvaDePlata": 11400
}
Output — D300 declaration
<?xml version="1.0" encoding="UTF-8"?>
<declaratie300 xmlns="mfp:anaf:dgti:d300:declaratie:v1" cif="12345678" luna="5" an="2026" d_rec="Exemplu Distributie SRL" total_plata_a="11400" sumaramburs="0">
<rand_1 b="100000" v="19000"/>
<rand_5 b="10000" v="1900"/>
<rand_16 v="20900"/>
<rand_24 b="40000" v="7600"/>
<rand_25 b="10000" v="1900"/>
<rand_30 v="9500"/>
<rand_38 v="11400"/>
</declaratie300>
Normalisations shown: amounts rounded to whole lei (no decimals); domestic 19% supply → rand_1 (b=100000, v=19000, recomputed 100000 × 19% = 19000); intra-EU acquisition reported in both rand_5 (collected 1900) and rand_25 (deductible 1900), net zero; rand_16 = 19000 + 1900 = 20900; rand_30 = 7600 + 1900 = 9500; balance rand_38 = 20900 − 9500 = 11400 (TVA de plată), with no sold negativ reportat. This XML is loaded into ANAF DUKIntegrator, which produces the D300 PDF inteligent for submission by the 25th.
Validation checklist
- All required figures extracted; AI asked about anything missing or ambiguous (no invented bases or VAT amounts)
-
@cifset;@lunaand@anmatch the reporting period and filing frequency (monthly/quarterly) - Each supply/acquisition mapped to the correct
randwith base@band value@v - VAT per rate recomputed = base × rate ÷ 100, rounded to whole RON
- Reverse-charge and intra-EU acquisitions reported in both collected and deductible rows where applicable
-
rand_16(TVA colectată) = sum of collected-VAT rows;rand_30(deductibilă) = sum of deductible rows - Balance correct: de plată (
rand_38) when colectată > deductibilă, else de recuperat (rand_40) - Any prior-period sold negativ reportat applied before the final balance
- All amounts whole RON, no decimals; recomputed totals match the source or discrepancy flagged
- Figures reconcile with RO e-Factura and SAF-T (D406) for the period; file passes ANAF DUKIntegrator
Last updated: 2026-06-13 — verify the active D300 row layout, Romanian TVA rates, filing thresholds/deadlines, and ANAF DUKIntegrator schema before use.