Generate Luxembourg quarterly VAT declarations (TVA_DECT) in eCDF XML format for AED submission. Use when working with Luxembourg VAT returns, eCDF XML generation, or fixing VAT declaration validation errors for Luxembourg businesses.
Generate Luxembourg quarterly VAT declarations (TVA_DECT) in eCDF XML format for AED submission.
Copy the example config:
cp vat_config.example.json vat_config.json
Edit vat_config.json with your company details:
MatrNbr: Your matricule numberRCSNbr: Your RCS numberVATNbr: Your VAT numbereCDFPrefix: Your eCDF prefixPrepare your CSV file with expenses (see example_csv_format.md)
Run the generator:
python3 generate_vat_declarations.py
generate_vat_declarations.py - Main scriptvat_config.example.json - Configuration templateexample_csv_format.md - CSV format documentationFIELD_FORMULAS.md - eCDF field formulas reference⚠️ CRITICAL: This skill documents hard-learned lessons from fixing VAT declaration errors. Read completely before generating XML.
Generate Luxembourg quarterly VAT declarations (TVA_DECT) in eCDF XML format for AED submission. Based on painful real-world debugging of validation errors.
The eCDF validator checks exact field sequence, not just presence. One field out of order = rejection.
Correct Order:
Numeric 012-105 → Choice 204/205/491/492/493 → Numeric 403/418/453 → Numeric 042/416/417/451/452
Common Mistake:
<!-- WRONG - 042 at wrong position -->
<NumericField id="042">0,00</NumericField>
<Choice id="204">1</Choice>
<!-- CORRECT -->
<Choice id="204">1</Choice>
<Choice id="205">0</Choice>
<Choice id="491">0</Choice>
<Choice id="492">0</Choice>
<Choice id="493">0</Choice>
<NumericField id="403">0</NumericField>
<NumericField id="418">0</NumericField>
<NumericField id="453">0</NumericField>
<NumericField id="042">0,00</NumericField>
<NumericField id="416">0,00</NumericField>
<NumericField id="417">0,00</NumericField>
<NumericField id="451">0,00</NumericField>
<NumericField id="452">0,00</NumericField>
⚠️ Important: These fields may or may not be required depending on the declaration year:
For 2024 declarations: Only 204 and 205 are needed
<Choice id="204">1</Choice>
<Choice id="205">0</Choice>
For 2025+ declarations: All 5 Choice fields may be required
<Choice id="204">1</Choice>
<Choice id="205">0</Choice>
<Choice id="491">0</Choice>
<Choice id="492">0</Choice>
<Choice id="493">0</Choice>
Error if wrong: "Les champs suivants ne sont pas autorisés, ou mal placés: 491, 492, 493"
Solution: Try without 491/492/493 first. If you get this error, add them.
The validator adds rounded XML values to check formulas, not raw float values.
Example of failure:
462 = 3.513900 → XML shows "3,51"
464 = 11.281427 → XML shows "11,28"
Validator computes: 3,51 + 11,28 = 14,79
But if you calculate from unrounded:
410 = 3.513900 + 11.281427 = 14.795327 → XML shows "14,80"
14,80 ≠ 14,79 → VALIDATION ERROR!
Solution: Calculate derived fields from already-rounded components:
field_410 = round(field_462, 2) + round(field_464, 2)
| Field | Formula | Notes |
|---|---|---|
| 409 | 436 + 435 + 463 + 765 | Total services requiring reverse charge |
| 410 | 462 + 464 + 766 | Total VAT on services received |
| 076 | 046 + 056 + 407 + 410 + 768 + 227 | Total output VAT |
| 093 | 458 + 459 + 460 + 090 + 461 + 092 + 228 | Total input VAT |
| 461 | 464 + 462 + 766 | Deductible reverse charge |
| 463 | 751 + 951 + 753 + 953 + 755 + 955 + 441 + 445 | Non-EU base |
| 464 | 752 + 952 + 754 + 954 + 756 + 956 + 442 | Non-EU VAT |
Common mistake: Labeling coworking as "Rent - No VAT" when it's actually services with 17% VAT.
Real example:
Always verify actual VAT amount on PDF, don't rely on description.
# See generate_vat_declarations.py for full implementation
python3 generate_vat_declarations.py
CSV file with columns:
Company config (vat_config.json):
{
"company": {
"MatrNbr": "YOUR_MATRICULE_NUMBER",
"RCSNbr": "YOUR_RCS_NUMBER",
"VATNbr": "YOUR_VAT_NUMBER",
"eCDFPrefix": "YOUR_ECDF_PREFIX"
}
}
| Provider Type | Fields | Treatment |
|---|---|---|
| Luxembourg suppliers | 458 | Direct VAT deduction |
| Non-EU services (USA) | 751/752/463/464/461 | Reverse charge at 17% |
| EU services (France, etc) | 741/742/436/462/461 | Reverse charge at 17% |
Before submitting, verify:
| Error | Meaning | Fix |
|---|---|---|
| "Champs 491, 492, 493 non autorisés ou mal placés" | Choice fields missing/wrong position | Add all 5 Choice fields in correct order |
| "Champ 409 = champs (436 + 435 + 463 + 765)" | Formula error for field 409 | Calculate from rounded components |
| "Champ 410 = champs (462 + 464 + 766)" | Formula error for field 410 | Calculate from rounded components |
| "Champ 076 = champs (046 + 056 + 407 + 410 + 768 + 227)" | Formula error for field 076 | Set 076 = 410 for expense-only declarations |
generate_vat_declarations.py - Working script with all fixesvat_config.json - Company configuration templateexample_csv_format.md - CSV column requirements