Wednesday, August 26, 2026
8 changes · 17.0
Resolved issues and error corrections
This update prevents errors when a newer IoT system connects to an older database that still sends device information in a previous format. It makes the device manufacturer detail optional so setup can continue smoothly across mixed versions.
Original PR description
Since b08e75adc2c85d3a9c97fe1d6a89cf68a74d7fa1, `manufacturer` field was removed in recent versions, both on IoT and database. This led to an error when an older version database is paired with an IoT on the last version and it receives the `devices`. We now use a `get` to make it optional. Backport of fc5f10fd7c23f408af9d69a7e4e9d8cf6bd4ef9e opw-6511652
Invoices and point-of-sale receipts in Saudi Arabia and the UAE now use GCC tax layouts only when the company has a VAT number. This helps businesses avoid issuing tax-style documents when they are not VAT registered, while keeping existing behavior for other GCC countries.
Original PR description
…tempalts for VAT unregistered Companies In Saudi Arabia (ZATCA), a business's legal authority to issue tax documents is dictated by annual revenue thresholds: registration is mandatory above SAR…
…tempalts for VAT unregistered Companies In Saudi Arabia (ZATCA), a business's legal authority to issue tax documents is dictated by annual revenue thresholds: registration is mandatory above SAR 375,000, voluntary between SAR 187,500 and SAR 375,000, and exempt below SAR 187,500. Per Article 53 of the KSA VAT Implementing Regulations, only a registered "Taxable Person" may issue a Tax Invoice (B2B) or a Simplified Tax Invoice (B2C). In the UAE, the Federal Tax Authority (FTA) imposes the same registration prerequisite. Previously the bilingual GCC tax layout was chosen purely from the company's country, on both the invoice report and the POS receipt. For SA and AE, we now only use the GCC report templates when the company actually has a VAT number; otherwise we fall back to the standard report template. The remaining GCC countries (BH, OM, QA, KW) are unaffected. The POS receipt flag `is_gcc_country` is renamed to `use_gcc_report` to enhance code readability task-6326221 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Factur-X invoices now keep the correct product price precision when unit prices use more decimals than the currency. This prevents valid invoices from being rejected by recipients because line totals no longer appear inconsistent in the XML.
Original PR description
Root cause: The unit prices of the Factur-X xml come from _prepare_edi_vals_to_export, which rounds them to the currency precision, and the template then writes them with two decimals. When the…
Root cause: The unit prices of the Factur-X xml come from _prepare_edi_vals_to_export, which rounds them to the currency precision, and the template then writes them with two decimals. When the Product Price precision is higher than the currency one, a unit price of 0.487 is written as 0.49 while LineTotalAmount is still computed from the real price. The xml then fails the EN16931 check that the line total equals the billed quantity times the net unit price, 0.49 * 400 = 196.00 against a LineTotalAmount of 194.80, and the receiver rejects the invoice. Fix: _export_invoice_vals in account_edi_xml_cii_facturx.py recomputes price_subtotal_unit and gross_price_total_unit without that rounding, and a format_unit_price helper writes the three unit price nodes with the Product Price precision. The values are recomputed in the Factur-X model instead of _prepare_edi_vals_to_export because that helper is also used by l10n_pe_edi. They are rounded on the Product Price precision rather than kept with all their decimals because price_unit is stored with that same precision, so writing more decimals than that gives different amounts when the xml is imported back. Steps to reproduce: 1. Go to Settings > Technical > Database Structure > Decimal Accuracy and set Product Price to 4 digits 2. Create a product with a sales price of 0.487 3. Open a customer, go to the Accounting tab, and set Format to Factur-X (CII) under Electronic Invoicing 4. Create a customer invoice for that customer with the product and a quantity of 400 5. Confirm the invoice and click Send & Print to generate the Factur-X file 6. Download the generated xml from the chatter and look at NetPriceProductTradePrice/ChargeAmount on the line => ChargeAmount is 0.49 for a BilledQuantity of 400 and a LineTotalAmount of 194.80 Ticket [link](https://www.odoo.com/odoo/project.task/5910248) opw-5910248
Saudi e-invoices in SAR now keep the required second tax total entry so they match ZATCA validation rules. This prevents compliant invoices from being rejected when the invoice and tax currency are both SAR.
Original PR description
This reverts commit 77280860a3a3557619ac13c853c37a66e9d19f2e. The reverted commit removed the second cac:TaxTotal node (in company currency, without tax subtotals) whenever the invoice currency…
This reverts commit 77280860a3a3557619ac13c853c37a66e9d19f2e. The reverted commit removed the second cac:TaxTotal node (in company currency, without tax subtotals) whenever the invoice currency matched the company currency (SAR), based on the assumption that it was an optional node only needed for foreign-currency invoices. This is wrong. Business rule BR-KSA-EN16931-09 is currency-agnostic: it requires exactly one TaxTotal without subtotals whenever cbc:TaxCurrencyCode is present in the document, regardless of whether the document and tax currencies match. Since l10n_sa_edi always sets TaxCurrencyCode, the second TaxTotal node is always required, even when both TaxTotal amounts end up identical (which is normal and expected for a same-currency invoice). ZATCA's own official "Standard Invoice" sample confirms this: a plain SAR invoice (DocumentCurrencyCode = TaxCurrencyCode = SAR) contains two TaxTotal nodes with the same TaxAmount. After the reverted commit was deployed, ZATCA started returning: [202] BR-KSA-EN16931-09 : Only one tax total (BG-22) without tax subtotals (BG-23) must be provided when tax currency code is provided. opw-6409881
The Kenyan e-invoicing form no longer shows an unnecessary blank space when there is no validation message. This keeps the form layout cleaner and avoids visual confusion for users reviewing invoices.
Original PR description
When there is no validation message, an empty div causes a whitespace gap between the header and the sheet in the form view. This commit adds `invisible="not l10n_ke_validation_message"` to the div to prevent this issue.
Odoo now correctly handles Outlook calendar events that are changed from a one-time meeting into a recurring series. This prevents the original single meeting from remaining as a duplicate after synchronization, keeping calendars cleaner and more accurate.
Original PR description
When a single event already synced with Outlook is turned into a recurring event directly in Outlook, Microsoft reuses the event in place: the seriesMaster keeps the iCalUId of the former single event, while each occurrence gets a fresh id/iCalUId. On resync, a seriesMaster is only matched against calendar.recurrence, never against calendar.event. As no recurrence exists yet, it is handled as a brand new recurrence whose occurrences are created from scratch. The original single event, which shares the master's iCalUId and the first occurrence's timeslot, is then left untouched. Drop that pre-existing single event when building a new recurrence from an inbound seriesMaster, since it is now represented by the recurrence itself. opw-5129848
HR appraisals can now be marked as done in bulk from the list view without causing an error. Each appraisal receives its own completion message and notification, making the batch action reliable for managers and HR teams.
Original PR description
Steps to reproduce: - select multiple appraisals and try to mark as done from list view. Issue: - The completion notification uses an appraisal variable assigned by a previous loop, raising an UnboundLocalError. Furthermore, message_notify() requires a singleton. Fix: - notify and post the completion message for each appraisal explicitly. task-6479018 Forward-Port-Of: odoo/enterprise#128207
The stock forecast now handles reserved items stored in sublocations correctly. This prevents reserved quantities from being shown as negative stock in transit, giving users a more accurate view of available inventory.
Original PR description
If you create & reserve a move from a sublocation of the main stock location, the forecast report would put this reserved quantity as a negative line in "Free Stock in Transit" instead of removing it…
If you create & reserve a move from a sublocation of the main stock location, the forecast report would put this reserved quantity as a negative line in "Free Stock in Transit" instead of removing it from the "Free Stock".
## Steps to reproduce (in runbot):
- Create product P, storable
- Create Delivery todo in future of 5 units of P, from WH/Stock/Shelf 1, Manually force the reservation => Check Forecasted report: Free Stock in Transit = -5
---
This commit is a followup of 8dc30be6c46ac2ea2979db3f02ed2b6fa05f6b3e and its revert commit 3e60b49d6c59372ad8237d4b3574829034825683 The new test catches the original issue, as well as the `RuntimeError` that the first fix created.
OPW-5953172
---
## Test Result without fix:
```
2026-03-05 07:52:40,477 15396 INFO oes_test_17.0 odoo.addons.stock.tests.test_report: Starting TestReports.test_report_forecast_14_reserved_from_sublocations ...
2026-03-05 07:52:40,759 15396 INFO oes_test_17.0 odoo.addons.stock.tests.test_report: ======================================================================
2026-03-05 07:52:40,759 15396 ERROR oes_test_17.0 odoo.addons.stock.tests.test_report: FAIL: TestReports.test_report_forecast_14_reserved_from_sublocations
Traceback (most recent call last):
File "/home/odoo/Odoo/src/17.0/odoo/addons/stock/tests/test_report.py", line 1369, in test_report_forecast_14_reserved_from_sublocations
self.assertEqual(lines[1]['in_transit'], False)
AssertionError: True != False
```
## Test Result with fix from 8dc30be6c46ac2ea2979db3f02ed2b6fa05f6b3e:
```
2026-03-05 07:53:56,144 15570 INFO oes_test_17.0 odoo.addons.stock.tests.test_report: Starting TestReports.test_report_forecast_14_reserved_from_sublocations ...
2026-03-05 07:53:56,430 15570 INFO oes_test_17.0 odoo.addons.stock.tests.test_report: ======================================================================
2026-03-05 07:53:56,430 15570 ERROR oes_test_17.0 odoo.addons.stock.tests.test_report: ERROR: TestReports.test_report_forecast_14_reserved_from_sublocations
Traceback (most recent call last):
File "/home/odoo/Odoo/src/17.0/odoo/addons/stock/tests/test_report.py", line 1364, in test_report_forecast_14_reserved_from_sublocations
_, _, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/Odoo/src/17.0/odoo/addons/stock/tests/test_report.py", line 49, in get_report_forecast
report_values = report.get_report_values(docids=product_ids)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/Odoo/src/17.0/odoo/addons/stock/report/stock_forecasted.py", line 459, in get_report_values
'docs': self._get_report_data(product_template_ids=docids),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/Odoo/src/17.0/odoo/addons/stock/report/stock_forecasted.py", line 125, in _get_report_data
res['lines'] = self._get_report_lines(product_template_ids, product_ids, wh_location_ids, wh_stock_location)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/Odoo/src/17.0/odoo/addons/stock/report/stock_forecasted.py", line 354, in _get_report_lines
for product_id, location_id in currents:
RuntimeError: dictionary changed size during iteration
```
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr