D112 — payroll: wage income tax + social contributions¶
The monthly employer declaration with per-employee detail. This file is a
completion guide: what the declaration settles, who files it and when, and
how each section maps onto the XSD attributes anafpy authors — followed by the
technical XSD/DUK layer. ANAF's validator jar (D112Validator.jar) and the
published structure annex + instructions are the authority; this guide is a
distilled bridge, not a re-implementation of the rules. The largest classic form
(~30 complex types). Live-proven 2026-07-17 with D112Validator.jar J26.0.3
(feed directory D112_209): both a nil employer-only instance and a
single-employee instance (identification + asiguratA + asiguratE1/E3)
validated clean (ok). The code lists are large enough to live in a companion
file — d112-nomenclatoare.md.
Purpose & legal basis¶
D112 is the joint declaration of everything payroll owes the state for one month: the wage income tax withheld at source (impozit pe veniturile din salarii), the social contributions — employee pension CAS (25%), employee health CASS (10%), the employer work-insurance contribution CAM (2.25%), plus employer CAS surcharges on hazardous/special work conditions — and the nominal record (evidența nominală) of every insured person. It is a title de creanță producing legal effects from the filing date. Because it is a joint obligation across four authorities, the wage-tax half goes to ANAF and the contribution halves feed CNPP (pensions), CNAS (health) and ANOFM (unemployment).
- Current model: approved by joint order OPANAF/OPCNPP/OPCNAS/OPANOFM
2066/248/1377/3103/2025 (20.08.2025), applicable from the August-2025
reporting month. The 01/2026 revision — form version
D112_A7.2.6(v7), structure annex dated 03.02.2026 — refreshes the parameters (minimum wage, the 300/200-lei non-taxable threshold) under OUG 156/2024, OUG 89/2025 and OUG 91/2025, without a new approving order. Legal anchors: art. 147 of the Fiscal Code (Legea 227/2015) for the filing obligation and OUG 158/2005 for sick-leave indemnities. - Periodicity: monthly is the default period. A quarterly election exists for small employers (below) — but quarterly filing still means one declaration per month, submitted by the quarter's deadline.
Who files & when¶
- Who: employers and assimilated income payers under art. 80 of the Fiscal
Code — companies, PFAs with employees, NGOs, public institutions, and the
authorities that declare on behalf of non-salaried insured (ANOFM for the
unemployed, CNPP, CNAS, MAE) — for every month in which an insured person
exists. Filing an "empty" period with no insured persons ends the person's
health-insurance coverage and is flagged by the validator (see the gotchas),
so an employer with staff always has at least one
asigurat. - Deadline: the 25th (inclusive) of the month following the reporting month (monthly filers) or following the quarter (quarterly filers). Confirmed by two independent sources: the ANAF filling instructions (Anexa 6/7) and the CECCAR/PortalPFA practitioner guides.
- Monthly vs quarterly election (art. 147 alin.(4) Fiscal Code): the period
is the calendar quarter for associations/foundations and other
no-patrimonial entities; for profit-tax payers with prior-year revenue ≤
€100,000 and ≤ 3 average employees; and for micro-enterprise-tax payers with
≤ 3 average employees. Everyone else files monthly. A quarterly filer still
authors one D112 per month (
luna_r/an_rname the month), and if an employee takes sick leave or loses insured status mid-quarter the declaration for that month is due by the 25th of the next month, not at quarter-end. - Corrections: D112 has its own rectificative mechanism on the root —
d_rec="1"marks a declarație rectificativă andtip_rec(1–9) states the reason. A rectificative is a complete replacement of the period's declaration (full employer + nominal detail), and it can be filed only if an initial declaration exists; the same period cannot receive an initial and a rectificative on the same day. Correcting a person's CNP fillscnpAnt/numeAnt/prenAnt(the previous identity). This is distinct from D710, which rectifies declared payment obligations on already filed D100/D112 — the payroll nominal detail itself is corrected through a rectificative D112, not D710.
Filling guide¶
The document is a real XML tree (unlike D300's single flat element): one
<declaratieUnica> root carries the reporting period + declarant, one required
<angajator> (employer totals), and zero-or-more <asigurat> (per-insured
detail). Employer-level amounts are aggregations the jar recomputes from the
per-insured detail — author the detail correctly and the totals must match, or
validation fails.
declaratieUnica (luna_r, an_r, d_rec/tip_rec, declarant name/function)
├─ angajator (cif, caen, den, casaAng, datCAM, bifa_CAM, totalPlata_A)
│ ├─ angajatorA × (1..41) creanțe: one per obligation (cod obligație → sumă)
│ ├─ angajatorB headcounts + total gross wage fund
│ ├─ angajatorC1 aggregated income/base by work condition (required, may be empty)
│ ├─ angajatorC2, C3 sick-leave / accident aggregations (required, may be empty)
│ ├─ angajatorC4, C5 CAM base/amount (present when CAM is owed)
│ ├─ angajatorD, E1..E4 other aggregations (optional)
│ └─ angajatorF1, F2 secondary work-points (optional)
└─ asigurat × (0..n) (cnpAsig, names, dataAng/dataSf, casaSn, asigCI, asigSO, Timp_E3, …)
├─ det1, coAsigurati detachment / co-insured (optional)
├─ asiguratA | B1..B4 | C ONE of the three contract-shape groups (A xor B xor C)
├─ asiguratD × (0..10) sick-leave certificates
└─ asiguratE1, E2, E3 income-tax detail (E3 required; E1/E2 for base/extra income)
Parameters (v7, 01/2026 — read them from the structure annex, they change with
each revision). Cipens employee CAS = 25%; Cisan employee CASS =
10%; pCAM = 2.25%; employer CAS CacasD (hazardous) = 4%,
CacasS (special) = 8%, CacasN (normal) = 0%. Minimum gross wage
salMin = 4050 (months 01–06/2026), 4325 (07–12), 4582
(construction). Non-taxable salary top-up Suma300 = 300 (01–06), 200
(07–12). Average gross earning / death-aid castigMed = 8620. All amounts
are positive integers; contributions round arithmetically (≥ 0.5 up), with
subunit contribution values rounded up to 1 leu.
Employer identification (angajator)¶
| Attribute | Form field | Notes |
|---|---|---|
cif |
Cod de identificare fiscală | required; check-digit enforced. Also admits a 13-digit CNP-like value for individual employers |
cifS |
CIF succesor | optional (art. 90 alin.(4) Cod procedură fiscală) |
caen |
Cod CAEN | required; closed enum (Nomenclator 1) |
den |
Denumire | required |
casaAng |
Casă de asigurări de sănătate | required; 2-char county sigla (nomenclatoare); must match the office county, must ≠ AOPSNAJ |
datCAM |
Datorează CAM | required 0/1 |
bifa_CAM |
Îndeplinește condițiile facilităților construcții/agricultură | required 0/1 |
bifa_AgCon |
Bifă activități construcții/agricultură | 1 = yes; absent/22 = no |
caenC |
Cod CAEN construcții/agricultură | when bifa_AgCon set |
cifAf1/cifAf2/pond1 (+ _a) |
Cifră de afaceri (curent / anterior) | construction/agriculture turnover test |
totalPlata_A |
Total obligații de plată | required; = Σ A_plata across all creanțe (a control sum) |
adrSoc/telSoc/…/mailFisc |
address & contact | optional |
Employer creanțe (angajatorA, one element per obligation)¶
Each obligation the employer owes for the month is a separate angajatorA
element (up to 41 of them). A_codOblig picks the obligation and
A_codBugetar is its budget code (auto-derived) — the full list is
Nomenclator 3.
Each element declares four amounts:
| Attribute | Field | Notes |
|---|---|---|
A_codOblig |
Cod obligație | required; unique per declaration (no duplicate codes) |
A_codBugetar |
Cod bugetar | required; 5503XXXXXX for most, 20470300XX/20A470600X for CAM |
A_datorat |
1. Suma datorată | required; the jar recomputes it from the per-insured detail (below) |
A_deductibil |
2. Suma deductibilă | optional — absent counts as 0 (the validated instances below omit it); nonzero only for wage tax offset by Law-111 union amounts |
A_scutit |
2a. Suma scutită/exceptată | required; 0 except construction/agriculture/IT exemptions |
A_plata |
4. Suma de plată | required; = A_datorat − A_deductibil − A_scutit ≥ 0 |
The recomputation the validator enforces (the load-bearing ones):
| Obligation | A_datorat = |
|---|---|
602 wage tax |
no formula from E3 unless angajatorF1/F2 are present — set it to Σ E3_15 (the tax withheld, = Timp_E3) |
412 CAS |
Σ asigurat(A_14) + Σ B4_8 + Σ B4_20 + Σ C_11 + Σ C_26 |
432 CASS |
Σ asigurat(A_12) + Σ B4_6 + Σ C_9 |
480 CAM |
Round(C4_baza · 2.25%), where C4_baza = Σ(A_5 + B4_14 + C_29) − C5_baza and the amount is read from angajatorC4/@C4_ct — so angajatorC4 must be present when CAM is owed, else the computed CAM is 0 (a warning) |
481/482 employer CAS |
Round(4%·…) / Round(8%·…) on hazardous/special bases (from section C1) |
Employer headcounts (angajatorB, one element)¶
| Attribute | Field | = count of insured where… |
|---|---|---|
B_cnp |
Nr. asigurați șomaj | baza_AJS is true |
B_sanatate |
Nr. asigurați concedii și indemnizații | asigCI=1 and A_1/B1_1 not an exempt type |
B_pensie |
Nr. asigurați care datorează CAS | A_14 > 0 (or B4_8/B4_20 > 0) |
B_sal |
Nr. salariați | A_1/B1_1 ∈ the salaried set (1, 2, 8, 10, 25, 27, 28, 46, 48, 51, 52, 54) |
B_brutSalarii |
Total fond de salarii brute | (C3_13 − C3_14) + Σ A_11 + Σ B4_5 |
nrSal1_111…nrSal3_111, bazaCAS_111, CAS_111 |
Legea 111/2022 voluntary insured | optional |
The asigurat (per-insured) block¶
Identity + insurance flags on the element, then exactly one of the three
contract-shape groups: asiguratA (a single ongoing employment), the asiguratB1
family (several contract lines / mid-month changes), or asiguratC (non-salaried
insured declared by a third party). asiguratE3 (income-tax detail) is
always required for an A/B/C record; asiguratE1/E2 summarise base-function
and other income and are required for A/B/C in (1, 19, 25).
| Attribute | Field | Notes |
|---|---|---|
idAsig |
Nr. crt. | record counter |
cnpAsig |
CNP/NIF | required; check-digit + year/month/sex + min-age-15 enforced, must be unique in the file |
cisAsig |
CIS (cod la sănătate) | for NIF holders (warning if absent) |
numeAsig/prenAsig |
Nume / Prenume | required |
cnpAnt/numeAnt/prenAnt |
previous identity | only for d_rec=1 corrections |
dataAng/dataSf |
entry / exit into insured category | dd.mm.yyyy; dataAng ≤ dataSf ≤ last day of the month |
casaSn |
Casă de sănătate | required; usually = casaAng; _N for a zilier or a non-CASS-paying detached |
asigCI |
Asigurat concedii (1/2) | required |
asigSO |
Asigurat șomaj (1/2) | required |
asigScu/asigExc/motivExc |
income-tax / min-wage-CAS-CASS exemptions | see nomenclatoare |
Timp_E3 |
Total impozit reținut | required; = Σ E3_15 across the record's E3 sections |
plata_CAS/plata_CASS/plata_CAM |
pays-flags | only for detached persons |
asiguratA (single employment) — the wage detail. The insured type A_1
(Nomenclator 5)
drives which contributions are owed via the dat_CAS/dat_CASS/dat_CAM/
baza_AJS/eSalariat flags:
| Attribute | Field | Notes / formula |
|---|---|---|
A_1 |
Tip asigurat (contract) | required; Nomenclator 5 |
A_2 |
Pensionar | required; 1/0 |
A_3 |
Tip contract (timp de lucru) | required; Nomenclator 12 (N, P1–P7) |
A_4 |
Ore normă zilnică | required; 6/7/8 |
A_sal1 |
Salariu de bază brut din CIM | required (A_sal1 > 0 and/or A_sal2 > 0) |
A_sal2 |
Venit brut realizat | required |
A_5 |
Bază CAM | > 0 when dat_CAM true |
A_6/A_7/A_8 |
Ore lucrate / suspendate / zile lucrate | A_6 ≤ NZL·A_4 for N; A_8 ≤ NZL |
A_9 |
Bază indemnizație șomaj | > 0 when baza_AJS true and A_6 > 0 |
A_11 |
Bază CASS | 0 when dat_CASS false |
A_12 |
CASS | required; = Round(A_11 · 10%) |
A_13 |
Bază CAS | = A_11 when dat_CAS true |
A_14 |
CAS | required; = Round(A_13 · 25%) |
A_13P/A_14P, A_11P/A_12P |
part-time min-wage CAS/CASS ceilings | art. 146(5⁶)/168(6¹) |
A_13S |
Suma de 300 lei netaxabilă (L168/2022) | only A_1=51 |
asiguratE3 (income-tax detail) — required. E3_1 = section (A/B/C),
E3_2 = insured type (mirrors A_1), E3_3 = 1 for base-function income,
E3_4 = P (reporting period) / A (other period). Then E3_8 gross,
E3_9 mandatory social contributions, E3_12/E3_13 deductions, E3_14 =
E3_8 − E3_9 − E3_12 − E3_13 (taxable base, 0 ≤ E3_14 ≤ E3_8), E3_15 =
Round(E3_14 · 10%) (tax, 0 ≤ E3_15 ≤ E3_14), E3_16 net collected. When
E3_3=1, the asiguratE1 summary must equal the E3 sums (E1_1 = Σ E3_8,
E1_6 = Σ E3_14, E1_7 = Σ E3_15, …).
Common scenarios¶
Both instances below validated clean (ok) against D112Validator.jar
J26.0.3 on 2026-07-17, authored against the v7 namespace
mfp:anaf:dgti:declaratie_unica:declaratie:v7. The synthetic cif="1234565" is
check-digit valid; cnpAsig="1850615410019" is a checksum-valid CNP (male,
1985-06-15, Bucharest).
1 — Nil month (an employer with no insured persons). Employer envelope only:
one angajatorA for wage tax at zero, an all-zero angajatorB, and the empty
angajatorC1/C2/C3 that must be present (below). totalPlata_A="0".
<?xml version="1.0" encoding="UTF-8"?>
<declaratieUnica xmlns="mfp:anaf:dgti:declaratie_unica:declaratie:v7"
luna_r="6" an_r="2026"
nume_declar="Popescu" prenume_declar="Ion" functie_declar="Administrator">
<angajator cif="1234565" caen="6201" den="EXEMPLU TEST SRL"
casaAng="_B" datCAM="1" bifa_CAM="0" totalPlata_A="0">
<angajatorA A_codBugetar="5503XXXXXX" A_codOblig="602"
A_datorat="0" A_scutit="0" A_plata="0"/>
<angajatorB B_cnp="0" B_sanatate="0" B_pensie="0" B_brutSalarii="0" B_sal="0"/>
<angajatorC1/>
<angajatorC2/>
<angajatorC3/>
</angajator>
</declaratieUnica>
2 — One full-time employee (normal conditions, gross 8 000 lei, June
2026, no dependents so the personal deduction is 0 above salMin+2000). CAS
= 8000·25% = 2000, CASS = 8000·10% = 800, CAM = 8000·2.25% = 180, taxable
base = 8000−2800 = 5200, tax = 5200·10% = 520; totalPlata_A =
520+2000+800+180 = 3500. Note the four creanțe, the reconciling angajatorB
counts, the filled angajatorC1 (normal-condition income) and angajatorC4
carrying the CAM amount, and the asigurat with asiguratA + asiguratE1 +
asiguratE3.
<?xml version="1.0" encoding="UTF-8"?>
<declaratieUnica xmlns="mfp:anaf:dgti:declaratie_unica:declaratie:v7"
luna_r="6" an_r="2026"
nume_declar="Popescu" prenume_declar="Ion" functie_declar="Administrator">
<angajator cif="1234565" caen="6201" den="EXEMPLU TEST SRL"
casaAng="_B" datCAM="1" bifa_CAM="0" totalPlata_A="3500">
<angajatorA A_codBugetar="5503XXXXXX" A_codOblig="602" A_datorat="520" A_scutit="0" A_plata="520"/>
<angajatorA A_codBugetar="5503XXXXXX" A_codOblig="412" A_datorat="2000" A_scutit="0" A_plata="2000"/>
<angajatorA A_codBugetar="5503XXXXXX" A_codOblig="432" A_datorat="800" A_scutit="0" A_plata="800"/>
<angajatorA A_codBugetar="20470300XX" A_codOblig="480" A_datorat="180" A_scutit="0" A_plata="180"/>
<angajatorB B_cnp="1" B_sanatate="1" B_pensie="1" B_brutSalarii="8000" B_sal="1"/>
<angajatorC1 C1_11="8000" C1_T1="8000"/>
<angajatorC2/>
<angajatorC3/>
<angajatorC4 C4_baza="8000" C4_ct="180"/>
</angajator>
<asigurat idAsig="1" cnpAsig="1850615410019" numeAsig="Ionescu" prenAsig="Vasile"
dataAng="01.03.2020" casaSn="_B" asigCI="1" asigSO="1" Timp_E3="520">
<asiguratA A_1="1" A_2="0" A_3="N" A_4="8" A_5="8000" A_6="168" A_7="0" A_8="21" A_9="8000"
A_11="8000" A_12="800" A_13="8000" A_14="2000" A_sal1="8000" A_sal2="8000"/>
<asiguratE1 E1_1="8000" E1_2="2800" E1_3="0" E1_4="0" E1_41="0" E1_42="0" E1_421="0" E1_422="0"
E1_5="0" E1_6="5200" E1_7="520"/>
<asiguratE3 E3_1="A" E3_2="1" E3_3="1" E3_4="P" E3_8="8000" E3_9="2800"
E3_14="5200" E3_15="520" E3_16="4680" E3_19="0" E3_21="0"/>
</asigurat>
</declaratieUnica>
3 — Correction (rectificativă). Re-author the complete declaration for
the period with d_rec="1" and a tip_rec reason (e.g. tip_rec="1" for an
ordinary rectification); if a CNP was wrong, add cnpAnt/numeAnt/prenAnt to
the affected asigurat. An initial declaration for that luna_r/an_r must
already have been filed. There is no partial "delta" — a rectificative D112
replaces the whole month.
Special attention & gotchas¶
The pitfalls below trace either to direct XSD/validator verification (the
empty-C1–C3 requirement, the angajatorC4-for-CAM rule, the CNP checksum, the
computed-totals reconciliation, and the malformed A_sal* XSD tags were each
observed against D112Validator.jar J26.0.3) or to an authoritative source
(the structure annex and joint order 2066/248/1377/3103/2025 for the parameters,
creanțe formulas and deadline; the CECCAR/PortalPFA guides corroborate the
deadline and quarterly election). No uncorroborated practitioner claim is carried.
- The live wire format is v7, but the newest published XSD is v6. Author
against namespace
mfp:anaf:dgti:declaratie_unica:declaratie:v7(note the legacy internal namedeclaratie_unica— D112's historical title, not today's D212). The v6 XSD (d112_10102024.xsd) is the closest schema but lags the wire in several places (below); the structure annex + validator jar win. - The published v6 XSD does not even parse strictly. The
A_sal1,A_sal2,B1_sal1andB1_sal2attribute declarations are malformed (name="A_sal1 type="…"— a missing closing quote). Do not feed the XSD to a strict XSD validator expecting it to load; DUK validates from bytecode, not the XSD, so the jar is authoritative for these fields. angajatorA,angajatorB,angajatorC1,angajatorC2,angajatorC3must all be present — C1–C3 even as empty elements (all their attributes are optional). The error when they are missing is misleading: "secțiunea 'angajatorD' este greșit poziționată sau lipsesc secțiuni anterioare obligatorii" names whatever section follows, not the missing C1–C3.angajatorDand beyond are optional.angajatorC4must be present when CAM is owed.A_datorat(480)reads the CAM amount fromangajatorC4/@C4_ct; omitangajatorC4and the jar computes CAM as0and raises a mismatch warning (A21.46) against the value you typed on the480creanță. Author<angajatorC4 C4_baza="Σ A_5" C4_ct="Round(C4_baza·2.25%)"/>.- Employer totals are recomputed from the per-insured detail — they are not
free inputs.
A_datorat(412)=Σ A_14,A_datorat(432)=Σ A_12,B_pensie/B_sanatate/B_salare counts,B_brutSalarii=Σ A_11,C1_11=Σ A_13, andtotalPlata_A=Σ A_plata. Get the detail right first; a mismatch is anERR(orATTfor the count rows).A_plataon every creanță isA_datorat − A_deductibil − A_scutit. - Contribution rates are attributes of the value, not the attribute name.
A_12=Round(A_11·10%)andA_14=Round(A_13·25%); the employer CAM is 2.25%, employer CAS on hazardous/special conditions 4%/8%. Read the current rates and the minimum wage from the structure annex parameters — they changed at 01/2026 (min wage 4050→4325 mid-year) and again with each OUG. - The insured type
A_1/B1_1decides which contributions are owed. The jar derivesdat_CAS/dat_CASS/dat_CAM/baza_AJS/eSalariatfromA_1(a militaryA_1=2owes no CAS/unemployment; azilierA_1=3owes CAS only; construction/agriculture/IT25/48/54get reduced CAS and CASS exemptions). Section A cannot coexist with B or C for the same person; types3/34/36are section-A-only,16/17/23/24are section-B-only. See Nomenclator 5. - The CNP is checksum-validated by the jar (weights
2 7 9 1 4 6 3 5 8 2 7 9, mod 11,10→1), plus year/month/sex coherence and a minimum insurance age of 15, and must be unique in the file ('CNP-ul trebuie să fie unic'). Synthetic test data needs a genuinely valid CNP. Str_A_cod_obligListSType(the XSD's 22-code obligation enum) is stale. The v7 form uses ~37 obligation codes (the structure annex Nomenclator 3); the jar accepts them, and the budget code moved from the XSD's5502XXXXXX/20470101XXto5503XXXXXX(and CAM20470300XX/20A470600X). Use the nomenclatoare table, not the XSD enum.angajatorAcardinality: XSD says 29, the structure annex says 41. The v6 XSD capsangajatorAatmaxOccurs="29"; the v7 structure annex documents "1‑41 apariții". The jar follows v7 — do not treat 29 as the ceiling.- Filing an empty period ends health coverage. The structure annex warns
(creanța 19 note) that a declaration with no insured persons closes the
insured period at CNAS. An employer with staff must carry the
asiguratdetail every month; a genuinely nil month is only for an employer with no active insured. - Cross-form consistency. The wage-tax half of D112 (
Timp_E3, creanța 602) is not re-declared on D100 — D100 carries the other withheld taxes; the two must not double-count wage tax. The nominal detail (names, contracts, entry/exit dates) is expected to reconcile with REGES-Online/REVISAL registrations — a person on the payroll here should have a registered contract. The per-insured CAS/CASS bases feed the individual's future pension/health record, so an under-declared base surfaces later as a benefit gap, not an immediate D112 error.
v7 (live wire format; no standalone XSD published)¶
- The live namespace is
mfp:anaf:dgti:declaratie_unica:declaratie:v7(note the internal namedeclaratie_unica— D112's historical title, not today's D212). The newest XSD ANAF publishes (d112_10102024.xsd) declares v6; every 2025/2026 soft-page row still links that same v6 file, and the validator zip contains no schema (validation is pure bytecode). The structure PDF (structura_D112_0126_030226.pdf) is the only v7 documentation. DUK's namespace error states the expected namespace — trust it (with a current jar) and author v7 against the v6 XSD + structure PDF deltas. - Root
declaratieUnica:luna_r,an_r, declarant name/function (optionald_rec/tip_recfor rectifications); childrenangajator(required) + repeatingasigurat. angajatorrequired attributes:cif,caen,den,casaAng(health-house code: county sigla,_B= Bucharest,_A/_T= defence/transport houses),datCAM0/1,bifa_CAM0/1,totalPlata_A.- Mandatory employer sections in v7:
angajatorA,angajatorB,angajatorC1,angajatorC2,angajatorC3— C1–C3 must be present even as empty elements (all their attributes are optional). The error when they are missing is misleading: "sectiunea 'angajatorD' este gresit pozitionata sau lipsesc sectiuni anterioare obligatorii" points at whatever section follows, not at the missing C1–C3.angajatorDitself is optional. angajatorA(the tax-obligation row):A_codOblig+A_codBugetarpairing is jar-enforced, and v7 changed the wage-tax pairing:602(wage income tax) now pairs withA_codBugetar="5503XXXXXX"— both v6 enum values (20470101XX,5502XXXXXX) are rejected ("incorect asociat cu cod obligatie"). Budget codes are X-padded to 10 chars. CAM pairs with20470300XX. (Recovered from the jar'sParameters_v36constant pool; the error message does not tell you the expected value, unlike D100's.)angajatorB(headcount/base summary):B_cnp,B_sanatate,B_pensie,B_brutSalarii,B_sal— all required, zero on an employees-less month.cui/cifcheck digit enforced;CifSTypealso admits 13-digit CNP-like values ([1-9]\d{12}) for individual employers.- Minimal valid instance (employer with no insured persons, June 2026):
<?xml version="1.0" encoding="UTF-8"?>
<declaratieUnica xmlns="mfp:anaf:dgti:declaratie_unica:declaratie:v7"
luna_r="6" an_r="2026"
nume_declar="Popescu" prenume_declar="Ion" functie_declar="Administrator">
<angajator cif="1234565" caen="6201" den="EXEMPLU TEST SRL"
casaAng="_B" datCAM="1" bifa_CAM="0" totalPlata_A="0">
<angajatorA A_codBugetar="5503XXXXXX" A_codOblig="602"
A_datorat="0" A_scutit="0" A_plata="0"/>
<angajatorB B_cnp="0" B_sanatate="0" B_pensie="0" B_brutSalarii="0" B_sal="0"/>
<angajatorC1/>
<angajatorC2/>
<angajatorC3/>
</angajator>
</declaratieUnica>
Open items¶
- Per-employee (
asigurat) authoring is now DUK-verified (2026-07-17): a single full-timeasiguratA+asiguratE1/E3record validated clean (see scenario 2). Not yet exercised: theasiguratB1multi-contract family, theasiguratC/asiguratDsick-leave path, detachment (det1), and the Law-111/2022 voluntary-contribution fields. - The jar's version directories (
v28/v32/v6/v1… insideD112Validator.jar) show it keeps validators for many wire generations and dispatches on the declared period — old periods still validate against their era's rules.