Friday, December 19, 2025
10 changes · 18.0
Resolved issues and error corrections
This update resolves a problem during the migration process where a required tax group wasn't being created, leading to errors. The migration script now automatically creates all necessary tax groups if they don't already exist, ensuring accurate tax setup after upgrades. This prevents errors related to missing tax groups.
Original PR description
Before this commit: migration script only creates a new tax group. After this commit: migration script will create all tax groups that are required for new taxes if they do not already exist Why:…
Before this commit:
migration script only creates a new tax group.
After this commit:
migration script will create all tax groups that are required for new taxes if they do not already exist
Why:
During the migration if the tax group is not found then the value error is raised
There are 2 reason of why the tax group is not found :
1. User deletes it by themselves
2. In the upgrade script of account in version saas~16.2.1.2 the pre-migrate script where global scope of tax groups was converted to company-specific, [Ref](https://github.com/odoo/upgrade/blob/b4f278aa9f32dc5edab814af0c2a0339cd7400a6/migrations/account/saas~16.2.1.2/pre-migrate.py#L173) If the tax groups are not associated with any tax or any account_move_line then it is deleted.
User Traceback :
` File "/home/odoo/src/odoo/17.0/odoo/addons/base/models/ir_model.py", line 2203, in _xmlid_lookup
raise ValueError('External ID not found in the system: %s' % xmlid)
ValueError: External ID not found in the system: account.1_l10n_id_tax_group_non_luxury_goods`
account_tax_group records in production :
```
kdes_3444743=> select id,name from account_tax_group;
id | name
----+---------------------------------------------------------------
1 | {"en_US": "Taxes", "id_ID": "Pajak"}
2 | {"en_US": "Luxury Good Taxes", "id_ID": "Pajak Barang Mewah"}
3 | {"en_US": "Non-luxury Good Taxes", "id_ID": "Pajak Barang"}
4 | {"en_US": "Zero-rated Taxes", "id_ID": "Pajak Nol"}
5 | {"en_US": "Tax Exempted", "id_ID": "Bebas Pajak"}
(5 rows)
```
Query executed [here](https://github.com/odoo/upgrade/blob/b4f278aa9f32dc5edab814af0c2a0339cd7400a6/migrations/account/saas~16.2.1.2/pre-migrate.py#L152) :
```
WITH company AS (
SELECT "company_id" AS id,
"tax_group_id" AS tg_id
FROM "account_move_line"
WHERE "company_id" IS NOT NULL
AND "tax_group_id" IS NOT NULL
UNION
SELECT "company_id" AS id,
"tax_group_id" AS tg_id
FROM "account_tax"
WHERE "company_id" IS NOT NULL
AND "tax_group_id" IS NOT NULL
)
INSERT INTO account_tax_group ("country_id", "create_date", "create_uid", "name", "preceding_subtotal", "sequence", "write_date", "write_uid", company_id, _tmp_orig_id)
SELECT "tg"."country_id", "tg"."create_date", "tg"."create_uid", "tg"."name", "tg"."preceding_subtotal", "tg"."sequence", "tg"."write_date", "tg"."write_uid", company.id, tg.id
FROM account_tax_group tg,
company
WHERE company.tg_id = tg.id
```
Above selection query on user's DB :
```
kdes_3444743=> SELECT "company_id" AS id,
"tax_group_id" AS tg_id
FROM "account_move_line"
WHERE "company_id" IS NOT NULL
AND "tax_group_id" IS NOT NULL
UNION
SELECT "company_id" AS id,
"tax_group_id" AS tg_id
FROM "account_tax"
WHERE "company_id" IS NOT NULL
AND "tax_group_id" IS NOT NULL;
id | tg_id
----+-------
1 | 1
1 | 2
(2 rows)
```
As only 2 tax groups are associated with the account_move_line and account_tax
They are only being inserted to the able along with the company id prefix and company_id field set
, remaining enteries are deleted in [next query](https://github.com/odoo/upgrade/blob/b4f278aa9f32dc5edab814af0c2a0339cd7400a6/migrations/account/saas~16.2.1.2/pre-migrate.py#L173).
Same is the case with the records in [ir_model_data](https://github.com/odoo/upgrade/blob/b4f278aa9f32dc5edab814af0c2a0339cd7400a6/migrations/account/saas~16.2.1.2/pre-migrate.py#L174-L196).
OPW : 5358546
UPG : 3444743
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#238981This update fixes an issue where holiday carryover days were incorrectly calculated, leading to a discrepancy in the number of days expiring. The change ensures that accrued holiday days are accurately added before the expiration date is determined, preventing incorrect counts and improving holiday management.
Original PR description
To reproduce: ============= - Create an accrual plan: - Carryover date: allocation - One level: - Accrues 2 days. - Accrual date: monthly on 1st of each month - Starts immediately on allocation start…
To reproduce:
=============
- Create an accrual plan:
- Carryover date: allocation
- One level:
- Accrues 2 days.
- Accrual date: monthly on 1st of each month - Starts immediately on allocation start date - Carryover policy: all days carry over - Carried over days validity: 3 months.
- Create an allocation that uses the above accrual plan on 23/09/2025:
- Starts on 01/07/2024
We should have 30 days in total with 24 expiring on 01/10/2025 but we only have 22 expiring on 01/10/2025.
Problem:
========
When `accrued_gain_time` of the accrual plan is 'start', in the `_process_accrual_plans` method, the property `expiring_days` is set when the first accrual still hasn't been added to the `number_of_days` (it is usually added at the [end of the loop](https://github.com/odoo/odoo/blob/18.0/addons/hr_holidays/models/hr_leave_allocation.py#L596)).
Solution:
=========
In the `_process_accrual_plans`, add the accrued days to the `number_of_days` before the `expiring_days` is set.
[opw-4963163](https://www.odoo.com/odoo/all-tasks/4963163)This update resolves an error that occurred when sending customer statements. Previously, removing the email template during the sending process caused a system error. The fix ensures the system correctly uses the specified email template or the current user's email address, improving the reliability of customer statement delivery.
Original PR description
Currently, an error occurs when a user sends a customer statement. **Steps to Reproduce ([Video](https://drive.google.com/file/d/1soOylzCVnNCNsWUBizeBQ9vfFlI5pzSP/view)):** - Install the…
Currently, an error occurs when a user sends a customer statement. **Steps to Reproduce ([Video](https://drive.google.com/file/d/1soOylzCVnNCNsWUBizeBQ9vfFlI5pzSP/view)):** - Install the `account_reports` module. - Go to `Invoicing` > `Customers` > `Customers`. - Switch to `List view`, select `a customer`, then click on `Actions` > `Open Customer Statements`. - Click `Send`, remove the `Email Template`, add a `subject`, and then click `Print & Send`. **Error:** `ValueError: Expected singleton: mail.template()` After [this commit], which checks whether the template has an email_from, when a user sends the customer statement and removes the email template, it still tries to access the template to fetch email_from for a particular customer [1]. If no email template is used, this results in an error [2] when going to extract the email_from. This commit ensures that email_from is taken from the email template if one is used; otherwise, it uses the current user's email address [3], which matches the default behavior. [this commit]: https://github.com/odoo/enterprise/commit/22c46e4f63e7b2dc0eee16fc807656cd4de21fb7 [1]- https://github.com/odoo/enterprise/blob/dc4d5633407ccc728d30de5ce2072a80c16b2766/account_reports/wizard/account_report_send.py#L246 [2]: https://github.com/odoo/odoo/blob/0dabb221225fba96c0e55779afadd9f12b369777/addons/mail/models/mail_render_mixin.py#L691-L693 [3]: https://github.com/odoo/odoo/blob/0dabb221225fba96c0e55779afadd9f12b369777/addons/mail/models/mail_thread.py#L2891-L2892 sentry-7106576491
This update automatically applies the 'Regime not subject to localization rules' fiscal position to invoices when a customer in Tenerife, Las Palmas, Ceuta, or Melilla is the delivery address. Previously, this required manual setup. This change simplifies invoice processing for Spanish businesses operating on the mainland and ensures compliance with local tax regulations.
Original PR description
Description of the issue/feature this PR addresses: If the company is on the mainland and the delivery address is in the states Tenerife, Las Palmas, Ceuta or Melilla, then the fiscal position 'Regime not subject to localization rules' (fp_not_subject_tai) should apply automatically. Current behavior before PR: In an invoice if the delivery address is in the states Tenerife, Las Palmas, Ceuta or Melilla, you had to set the fiscal position 'Regime not subject to localization rules' (fp_not_subject_tai) manually. Desired behavior after PR is merged: In an invoice when the partner shipping is in the state Tenerife, Las Palmas, Ceuta or Melilla, the fiscal position 'Regime not subject to localization rules' (fp_not_subject_tai) auto apply. @chklop @jco-odoo @rafaelbn please review MT-13114 @moduon --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update allows users to directly format and edit eCommerce descriptions on product pages through the website's web editor. Previously, these descriptions were fixed and couldn't be customized. This change enhances the user experience and provides greater flexibility for product presentation.
Original PR description
Steps to reproduce: - Open the product page. - Add an eCommerce description from the frontend and try to edit it using the web editor. Cause: The format of the eCommerce description cannot be changed from the frontend. Fix: Removed the "oe_structure" class to allow formatting changes from the frontend web editor. With this fix, users can now modify and format the eCommerce description \ directly from the frontend.
This update corrects a previous issue where newly created serial numbers in the Barcode app were automatically assigned to the current company. This prevented their use across different companies, particularly in intercompany scenarios. The fix removes this automatic assignment, allowing serial numbers to be used flexibly without company restrictions.
Original PR description
## Context In the barcode app (`stock_barcode`), users can update inventory counts by scanning a product's barcode or by manually entering the barcode. ## Issue When the barcode is entered manually,…
## Context In the barcode app (`stock_barcode`), users can update inventory counts by scanning a product's barcode or by manually entering the barcode. ## Issue When the barcode is entered manually, the lot/serial number is created with the *Company* field set to the current company. This causes issues when working with intercompany flows, because lots with a company assigned cannot be used by other companies. This behavior is also inconsistent with the other ways of updating a company's inventory. In fact, the following flows create serial/lot numbers with no company assigned: - Inventory / Products / Products / *Forecasted Report* or *On Hand* - Inventory / Operations / Adjustments / Physical Inventory - Barcode / Inventory Count / Add product (add the serial number from the *Inventory Count* screen, **not** by clicking on the cogwheel in the top-right corner) ## Cause The line assigning a `company_id` was added by https://github.com/odoo/enterprise/commit/c0151bce3c60c69e7cadeb719a81c4a702b71c34. At the time, that behavior was consistent with the backend behavior, as the `company_id` of a lot/serial number would always be set to `self.env.company`. In fact, the feature allowing a lot/serial to be shared among multiple companies was introduced later, in saas-17.2 (https://github.com/odoo/odoo/commit/99b39b72c7e65e85af6f06dcb6b02867623f3f69). This last commit adds a compute method for the `stock.lot.company_id` field: https://github.com/odoo/odoo/blob/6026866900fd0ac1bf6495ae249cd08f56c85342/addons/stock/models/stock_lot.py#L130-L136 Since then, lot/serial numbers shouldn't be created with a `company_id`, as this restrict other companies to use those numbers. Users can always add a company to a lot/serial number later if necessary. ## Solution The line assigning a `company_id` to the `stock.lot` can be removed, as it does not reflect the current behavior (saas-17.2+). Nowadays, a `company_id` should be set **only** if the user wants a lot/serial number to be used by a specific company; it should not be the default behavior. ## Steps to reproduce 1. Install *Barcode* (`stock_barcode`). 2. In Inventory / Configuration / Settings, enable *Lots & Serial Numbers*. 3. In Settings / Users & Companies / Companies, create a second company. Use either company for the following steps. 4. Create a product tracked *By Unique Serial Number*. 5. Open the Barcode app, then click *Inventory Count*. 6. Scan your product (or add it manually, but **do not** set the *Serial/Lot Number*). 7. Scan "SN001" (or add it manually through the cogwheel menu), then click *Apply*. 8. Go to Inventory / Products / Lots / Serial Numbers. 9. The serial number created from the Barcode app is assigned to the current company. opw-5264216
This update fixes a previous issue where scanning GS1 barcodes on product packaging didn't automatically add the correct quantity to the sale. Now, when a GS1 barcode on packaging is scanned, the system accurately reflects the quantity of the product being sold. This improves the accuracy of sales transactions.
Original PR description
Before this commit, scanning a GS1 barcode for a product packaging did not add the quantity. opw-5003035 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#233922
This update corrects a bug where invoice due dates were incorrectly calculated when users had their time zones set to UTC. The change removes a timezone conversion step, ensuring due dates are calculated accurately based on the user's local time. This prevents invoices from appearing due prematurely.
Original PR description
This commit fixes the incorrect due date calculation of invoices. If user timezone is set to any UTC-* timezone, then the due date is calculated as the previous day to the actual due date. This is because the function `deserializeDateTime` was used, which considers the input date as UTC timezone and converts it to system timezone. For example, if the due date is "2025-11-20 00:00:00" and the system timezone is UTC-3, then the calculated due date is "2025-11-19 21:00:00". So when getting the difference from today's date (assuming today is "2025-11-20"), the difference is 1 day (which is not the expected value). This commit replaces the call of `deserializeDateTime` with `deserializeDate`, which removes the system timezone conversion. opw-5160764 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves an issue where nested HTML editor operations caused cursor state conflicts. The change introduces a stack-based cursor management system, ensuring accurate synchronization of cursor updates across different contexts and preventing data inconsistencies. This enhances the stability and reliability of the HTML editor.
Original PR description
Summary: Refactor `preserveSelection()` to use a stack-based approach (`preservedCursors` array) instead of a single cursor reference. This allows nested calls to `preserveSelection()` to operate…
Summary:
Refactor `preserveSelection()` to use a stack-based approach (`preservedCursors` array) instead of a single cursor reference. This allows nested calls to `preserveSelection()` to operate independently while keeping cursor updates synchronized across active contexts.
Problem:
Using a single stored cursor caused issues in nested calls to `preserveSelection()`:
1. **State overwrite:** Inner calls could overwrite or clear the outer cursor.
2. **Stale references:** If an inner function replaced a DOM node, the outer cursor could still point to a removed node and fail on restore.
Solution:
Use an array of cursor subscribers
- **Shared updates:** When calling `remapNode` on a cursor, it iterates over all active subscribers in the stack. This ensures node replacements performed in inner contexts also update outer cursor references.
- **Scoped cleanup:** `restore()` now removes only the corresponding cursor instance from the stack, ensuring proper lifecycle management.
Example:
The key improvement is that outer scopes receive updates performed by inner scopes.
```javascript
// Function A (outer)
function wrapperFunction() {
const cursor = this.preserveSelection();
replaceTextWithSpan();
cursor.restore();
}
// Function B (inner)
function replaceTextWithSpan() {
const innerCursor = this.preserveSelection();
const oldNode = document.querySelector('text');
const newNode = document.createElement('span');
oldNode.replaceWith(newNode);
innerCursor.remapNode(oldNode, newNode);
innerCursor.restore();
}
```
opw-5386862
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThis update resolves an issue preventing vendor bills from being sent to eTIMS. The problem stemmed from incorrect eTIMS configuration in new companies, leading to a skipped process. Now, the system will correctly handle eTIMS sending when the configuration is properly set.
Original PR description
Currently, an error occurs when clicking the `Send to eTIMS` button on vendor bills. Steps to Reproduce: - Install `l10n_ke_edi_oscu` module without demo data. - Create a New company with `Kenya` as…
Currently, an error occurs when clicking the `Send to eTIMS` button on vendor bills.
Steps to Reproduce:
- Install `l10n_ke_edi_oscu` module without demo data.
- Create a New company with `Kenya` as the Country and switch to it.
- Go to Vendors > Bills, create a new bill, and add an invoice line without tax.
- Confirm it, then click `Send to eTIMS`.
Traceback:
```py
File "/home/odoo/src/enterprise/19.0/l10n_ke_edi_oscu/models/account_move.py", line 551, in action_l10n_ke_oscu_confirm_vendor_bill
content = move._l10n_ke_oscu_json_from_move()
File "/home/odoo/src/enterprise/19.0/l10n_ke_edi_oscu/models/account_move.py", line 199, in _l10n_ke_oscu_json_from_move
line_items = self._l10n_ke_oscu_get_json_from_lines(tax_details)
File "/home/odoo/src/enterprise/19.0/l10n_ke_edi_oscu/models/account_move.py", line 250, in _l10n_ke_oscu_get_json_from_lines
tax, line_tax_details = next(
StopIteration: null
```
This error occurs because when a new company is created, the `eTIMS Server Mode` in Settings is empty. As a result, `l10n_ke_oscu_is_active` field becomes `False`, and at [1] the `l10n_ke_validation_message` field will also be `False`, causing the flow to be skipped. Therefore, no error is raised on the frontend side. The field `l10n_ke_oscu_is_active` is set to `True` only when `eTIMS Server Mode` is set to `Demo`.
Here we raise a warning when the `eTIMS` configuration is not set up correctly.
[1]: https://github.com/odoo/enterprise/blob/7fb7b3168039f00b6d815202bc19ac35aa1d9b5e/l10n_ke_edi_oscu/models/account_move.py#L91-L93
sentry-7083978544