[19.0] account_edi_ubl_cii: CII import rounds unit price to 2 decimals, causing a rounding line and wrong tax total
Odoo Version
- 17.0
- 18.0
- 19.0
- Other (specify)
Steps to Reproduce
Odoo Version
19.0
Modules involved:
accountaccount_edi_ubl_ciil10n_fr_pdp
Steps to Reproduce
Import a Factur-X/CII vendor bill containing one invoice line with these values:
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Test product</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>5.3280</ram:ChargeAmount>
<ram:BasisQuantity unitCode="C62">1.0000</ram:BasisQuantity>
<ram:AppliedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator>
<ram:ActualAmount>2.3070</ram:ActualAmount>
</ram:AppliedTradeAllowanceCharge>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>3.0210</ram:ChargeAmount>
<ram:BasisQuantity unitCode="C62">1.0000</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="C62">10368.0000</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>5.50</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>31321.73</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
Use these document-level totals:
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>31321.73</ram:LineTotalAmount>
<ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>
<ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>
<ram:TaxBasisTotalAmount>31321.73</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">1722.70</ram:TaxTotalAmount>
<ram:GrandTotalAmount>33044.43</ram:GrandTotalAmount>
<ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
<ram:DuePayableAmount>33044.43</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
The calculation expressed by the CII document is:
Gross unit price: 5.3280
Unit price discount: -2.3070
Net unit price: 3.0210
3.0210 × 10,368 = 31,321.728
Rounded line total = 31,321.73
VAT 5.5% = 1,722.70
Grand total = 33,044.43
This case can also be added to the existing CII import tests, near:
addons/account_edi_ubl_cii/tests/test_files/import/facturx/invoice/fr/
test_partial_import_invoice_line_line_extension_amount_full_price_node_and_invoiced_quantity.xml
Current Behavior
Odoo reconstructs the gross unit price as:
round(3.0210 + 2.3070, 2) = 5.33
The imported product line consequently has approximately:
Quantity: 10,368
Unit price: 5.33
Line subtotal: 31,342.46
VAT 5.5%: 1,723.84
Odoo then creates an additional untaxed line named Rounding to bring the untaxed total back to EUR 31,321.73.
The untaxed total is compensated, but the VAT and grand total remain incorrect because the rounding line has no tax.
The exact difference may vary slightly when additional CII line-level allowances or charges are present, but the root cause remains the rounding of the unit price from 5.3280 to 5.33.
Expected Behavior
Odoo should preserve sufficient precision when importing the unit price.
The imported bill should have:
Untaxed amount: 31,321.73
VAT: 1,722.70
Grand total: 33,044.43
No artificial Rounding invoice line should be necessary.
At minimum:
invoice.amount_untaxed == 31321.73
invoice.amount_tax == 1722.70
invoice.amount_total == 33044.43
Technical Analysis
The problem appears to be caused by:
addons/account_edi_ubl_cii/models/account_edi_cii.py
_import_cii_invoice_line_add_price_unit_quantity_discount()
Current code:
price_unit = round(
(price_subtotal + price_discount_amount) / price_quantity,
2,
)
For this example:
price_subtotal = 3.0210
price_discount_amount = 2.3070
price_quantity = 1
price_unit = round(5.3280, 2)
price_unit = 5.33
The lost precision is multiplied by the billed quantity:
(5.33 - 5.328) × 10,368 = 20.736
Unit prices in EN 16931 are not restricted to the two-decimal precision of monetary totals. Rounding the reconstructed unit price to the currency precision before multiplying it by the quantity can therefore create a material difference.
The additional Rounding line is created later by:
_import_cii_invoice_fix_untaxed_amount()
It compensates the untaxed total but has no tax. The VAT is consequently calculated from the incorrect product-line subtotal.
The XML tax correction is not applied when the tax difference exceeds the hard-coded tolerance in:
account.edi.common._import_invoice_fix_taxes_amounts()
As a result, the imported bill may have a grand total different from the legally received electronic invoice.
Suspected Regression
The dedicated CII import pipeline was introduced by:
- https://github.com/odoo/odoo/pull/261572
- https://github.com/odoo/odoo/pull/284123
- https://github.com/odoo/odoo/commit/5baa55712be21e210c875faa6713598cca35d7b5
Before this refactoring, the generic importer preserved the gross price precision:
price_unit = gross_price_unit / basis_qty
It then inferred the discount from the CII LineTotalAmount.
The previous calculation therefore retained 5.3280 instead of replacing it with 5.33.
Proposed Direction
Do not round the reconstructed CII unit price to two decimals at this stage:
price_unit = (
price_subtotal + price_discount_amount
) / price_quantity
Alternatively, use GrossPriceProductTradePrice/ChargeAmount directly when it is provided and consistent with the net price and price discount.
A regression test should verify that:
invoice.amount_untaxed == 31321.73
invoice.amount_tax == 1722.70
invoice.amount_total == 33044.43
and that no invoice line named Rounding is created.
Log Output
No traceback is produced. The import succeeds but creates incorrect accounting amounts.
Support Ticket
Not available.
Additional Information
The issue was initially detected on a real incoming French Factur-X invoice. The original document cannot be shared for confidentiality reasons, so all business-identifying information has been removed from this report.
AI disclosure: This issue was prepared by OpenAI Codex on behalf of the reporter, based on an analysis of the Factur-X data and the Odoo 19.0 source code. The technical findings and reproduction steps were generated by Codex.
Log Output
Support Ticket
No response
Source: odoo/odoo