Daily updates from Odoo
Monday, August 10, 2026
245 changes
13 changes
Enhancements to existing features
Before this commit, the empty space between audio recordings in the CallDebrief timeline had no DOM elements representing them because the media elements are styled with absolute positioning In this commit we generate silence gap elements to enable designers to transition the timeline layout to a linear flexgrid. task-6321723
Original PR description
Before this commit, the empty space between audio recordings in the CallDebrief timeline had no DOM elements representing them because the media elements are styled with absolute positioning In this commit we generate silence gap elements to enable designers to transition the timeline layout to a linear flexgrid. task-6321723
Resolved issues and error corrections
Rejection notification emails now show the name of the person who declined to sign, rather than the email recipient's name. This makes signing status updates clearer and prevents confusion among people involved in the document process.
Original PR description
**Description of the issue/feature this PR addresses:** When a document is rejected by a signer, the notification email sent to other involved parties incorrectly displays the recipient's name in the…
**Description of the issue/feature this PR addresses:** When a document is rejected by a signer, the notification email sent to other involved parties incorrectly displays the recipient's name in the subject line instead of the person who actually refused to sign. This occurs because the subject string was using `partner.name` (the current email recipient) instead of `refuser.name`. This commit updates the string to reference the refuser, ensuring the subject accurately identifies the individual who rejected the document. **Steps to reproduce:** - Sign > upload any PDF > add signature request for 2 different signers > Send > choose signers, e.g. Abigail Carter and Marc Demo > Send - Settings > Technical > Emails > Emails - Select one of the sent emails > Sign document > sign > Validate & Send Completed Document - Select the other email > Sign document > top-right dropdown arrow > Decline to sign > Decline - Settings > Technical > Emails > Emails - Observe that all emails sent state that the recipient of the email rejected the signing **Current behavior before PR:** - Rejection email subject states that the recipient refused to sign **Desired behavior after PR is merged:** - Rejection email subject states that the refuser refused to sign opw-6421188 Forward-Port-Of: odoo/enterprise#126412
This fix clears a cached internal route so test overrides are correctly applied when larger test suites run. It helps prevent false test failures in barcode inventory workflows, improving confidence in release validation without changing user-facing behavior.
Original PR description
test_barcode_create_serials_in_batch_with_single_scan keeps failing on master and 19.4 as call_count !=2, but instead = 0 This does not happen when running only the tests in stock_barcode but instead when you run a larger suite of tests such as the following: https://runbot.odoo.com/runbot/build/119533820 Once a route is hit it is stored in the cache, causing the later override to be missed. [Runbot-238760](https://runbot.odoo.com/odoo/error/238760)
Belgian payroll now automatically applies the legal minimum employee contribution for meal vouchers when the configured amount is too low. HR managers receive a non-blocking payslip warning so they know the value was adjusted while payroll processing can continue.
Original PR description
**What:** - Refactored the meal voucher salary rule computation to take the maximum between the configured employee share and the parameter-defined minimum threshold (€1.09). - Added a non-blocking warning message on the payslip to notify HR managers when an employee's configured share is below the legal minimum and has been automatically adjusted. task-6428585 Forward-Port-Of: odoo/enterprise#126194
MyInvois expects the CountrySubentityCode to be fixed as '17' for customers located outside Malaysia, since Malaysian state codes don't apply to them. Set it to '17' instead of the raw state name for non-Malaysian customers. task-6388521 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281095 Forward-Port-Of: odoo/odoo#280550
Original PR description
MyInvois expects the CountrySubentityCode to be fixed as '17' for customers located outside Malaysia, since Malaysian state codes don't apply to them. Set it to '17' instead of the raw state name for non-Malaysian customers. task-6388521 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281095 Forward-Port-Of: odoo/odoo#280550
### Issue: In the tax report, lines `E5`, `F3`, `F4`, `F7`, `F8` and `F9` show 0 when using a tax with the corresponding tax grid ### Cause: In 19.0, the +/- tax grids were replaced by a single unsigned tax grid The E and F formulas were not updated accordingly, causing their values to be negative instead of positive ### Fix: The formulas have been updated based on the official documentation to correctly separate Sales and Purchases lines: https://www.impots.gouv.fr/sites/default/file
Original PR description
### Issue: In the tax report, lines `E5`, `F3`, `F4`, `F7`, `F8` and `F9` show 0 when using a tax with the corresponding tax grid ### Cause: In 19.0, the +/- tax grids were replaced by a single unsigned tax grid The E and F formulas were not updated accordingly, causing their values to be negative instead of positive ### Fix: The formulas have been updated based on the official documentation to correctly separate Sales and Purchases lines: https://www.impots.gouv.fr/sites/default/files/formulaires/3310-ca3-sd/2026/3310-ca3-sd_5426.pdf ### Steps to reproduce: - Install `l10n_fr_account` - Create a Tax (Amount: 1.75%, Base Tax Grids: E5 and F3) - Create an invoice (any amount, Tax: created tax) - Open the Tax Report for this month Before the fix, E5 and F3 lines are empty opw-6357703 Forward-Port-Of: odoo/odoo#278635
Changing options for the Contact Us button in the navbar makes the button lose current selection.
Original PR description
Changing options for the Contact Us button in the navbar makes the button lose current selection.
On python 3.10.12 `test_export_translatable_resources` fails. This is fixed in this commit build-944659 I only tested it on 17.0 since we do not seem to have the build error on higher versions. But the minimum python version is 3.10 until [excluding saas-19.1](https://github.com/odoo/odoo/blob/11ee42b4bf70a1008b06d13a48263e42c381aeed/odoo/release.py#L39) Forward-Port-Of: odoo/odoo#281294 Forward-Port-Of: odoo/odoo#280927
Original PR description
On python 3.10.12 `test_export_translatable_resources` fails. This is fixed in this commit build-944659 I only tested it on 17.0 since we do not seem to have the build error on higher versions. But the minimum python version is 3.10 until [excluding saas-19.1](https://github.com/odoo/odoo/blob/11ee42b4bf70a1008b06d13a48263e42c381aeed/odoo/release.py#L39) Forward-Port-Of: odoo/odoo#281294 Forward-Port-Of: odoo/odoo#280927
_track_finalize() can browse records into self that get dropped from trackings when _mail_track() raises MissingError (e.g. deleted mid-transaction), so indexing trackings[move.id] could KeyError. Iterate trackings.items() instead, since it's the authoritative set of records with tracking data. runbot-944656 Forward-Port-Of: odoo/odoo#281110
Original PR description
_track_finalize() can browse records into self that get dropped from trackings when _mail_track() raises MissingError (e.g. deleted mid-transaction), so indexing trackings[move.id] could KeyError. Iterate trackings.items() instead, since it's the authoritative set of records with tracking data. runbot-944656 Forward-Port-Of: odoo/odoo#281110
In ubuntu 26.04 the time zone database contents changed. A couple of timezone names are not available anymore, causing runtime exceptions. This mapping links old with new time zone naming conventions to prevent future (test) breakdown. The mapping WET to Europe/Lisbon is imperfect, and the localizations for the fixed date inside the test did not match. There exists no better nor correct mapping for WET. The mapping to Europe/Lisbon comes from the IANA tzdb-2026c and is official, so it
Original PR description
In ubuntu 26.04 the time zone database contents changed. A couple of timezone names are not available anymore, causing runtime exceptions. This mapping links old with new time zone naming conventions to prevent future (test) breakdown. The mapping WET to Europe/Lisbon is imperfect, and the localizations for the fixed date inside the test did not match. There exists no better nor correct mapping for WET. The mapping to Europe/Lisbon comes from the IANA tzdb-2026c and is official, so it is kept unchanged. The fixed date inside the test is changed to a recent one that aligns the test outcome with expectations: - Offsets match for recent history and future time - Match daylight savings time (DST) observation --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280691
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the corresponding Purchase Orders, then confirm the merged PO 4. Validate the dropship transfer Issue stock.picking.sale_id is a Many2one (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/sale_stock/models/stock.py#L99) computed from procurement.group.sale_id, an
Original PR description
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the…
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the corresponding Purchase Orders, then confirm the merged PO 4. Validate the dropship transfer Issue stock.picking.sale_id is a Many2one (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/sale_stock/models/stock.py#L99) computed from procurement.group.sale_id, and stock.picking.group_id is a stored related on move_ids.group_id (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/stock/models/stock_picking.py#L186). A single picking can therefore only resolve to one SO. _create_picking (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/purchase_stock/models/purchase_order.py#L290) builds one picking per PO and _prepare_stock_moves assigns every move the merged PO's group_id (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/purchase_stock/models/purchase_order_line.py#L307), so when a merged dropship PO carries lines from multiple SOs every move lands in one picking under the PO group. Only one SO gets linked and the others stay "not fully delivered" even after validation. Solution Override PurchaseOrderLine._prepare_stock_moves to set group_id to the SO's procurement_group_id when sale_line_id is set, so each dropship move is created in its originating SO's procurement group. Override PurchaseOrder._create_picking to detect dropship POs whose order lines span more than one SO and create one picking per SO group by calling _prepare_picking and _create_stock_moves per group. picking.group_id then resolves to the SO group via the stored related field, picking.sale_id points to the right SO, and delivery_status updates correctly on validation. opw-6094608 Forward-Port-Of: odoo/odoo#280166 Forward-Port-Of: odoo/odoo#257823
This commit will remove the condition about the review state to place the move in to review. We want to place the move in the state "to_review" as soon as a user with not enough access right modify the move. task-6409437 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278078
Original PR description
This commit will remove the condition about the review state to place the move in to review. We want to place the move in the state "to_review" as soon as a user with not enough access right modify the move. task-6409437 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278078
When importing a UBL bill, if a price-included tax is used, we need to adjust the unit price by adding the tax amount per unit. When a discount is added to the line, the unit price doesn't reflect it, but the raw_tax_amount_currency does. As a result, we add the reduced tax amount to the original unit price. We propose to compute the raw tax amount before the discount to adjust the unit price. opw-6242701 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.
Original PR description
When importing a UBL bill, if a price-included tax is used, we need to adjust the unit price by adding the tax amount per unit. When a discount is added to the line, the unit price doesn't reflect it, but the raw_tax_amount_currency does. As a result, we add the reduced tax amount to the original unit price. We propose to compute the raw tax amount before the discount to adjust the unit price. opw-6242701 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278659
11 changes
Enhancements to existing features
Don't generate a task every time the payroll officer assigns a new driver to the car. task-6425360
Original PR description
Don't generate a task every time the payroll officer assigns a new driver to the car. task-6425360
Resolved issues and error corrections
MyInvois expects the CountrySubentityCode to be fixed as '17' for customers located outside Malaysia, since Malaysian state codes don't apply to them. Set it to '17' instead of the raw state name for non-Malaysian customers. task-6388521 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281095 Forward-Port-Of: odoo/odoo#280550
Original PR description
MyInvois expects the CountrySubentityCode to be fixed as '17' for customers located outside Malaysia, since Malaysian state codes don't apply to them. Set it to '17' instead of the raw state name for non-Malaysian customers. task-6388521 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281095 Forward-Port-Of: odoo/odoo#280550
In this commit: - When only one preset remains available after filtering table identifier in self-order mode, automatically select it and skip the preset selection page. - This avoids showing a location selection page when there is no actual choice available to the customer. Task:6217791 Enterprise PR : https://github.com/odoo/enterprise/pull/122979 Forward-Port-Of: odoo/odoo#280579 Forward-Port-Of: odoo/odoo#274301
Original PR description
In this commit: - When only one preset remains available after filtering table identifier in self-order mode, automatically select it and skip the preset selection page. - This avoids showing a location selection page when there is no actual choice available to the customer. Task:6217791 Enterprise PR : https://github.com/odoo/enterprise/pull/122979 Forward-Port-Of: odoo/odoo#280579 Forward-Port-Of: odoo/odoo#274301
### Issue: In the tax report, lines `E5`, `F3`, `F4`, `F7`, `F8` and `F9` show 0 when using a tax with the corresponding tax grid ### Cause: In 19.0, the +/- tax grids were replaced by a single unsigned tax grid The E and F formulas were not updated accordingly, causing their values to be negative instead of positive ### Fix: The formulas have been updated based on the official documentation to correctly separate Sales and Purchases lines: https://www.impots.gouv.fr/sites/default/file
Original PR description
### Issue: In the tax report, lines `E5`, `F3`, `F4`, `F7`, `F8` and `F9` show 0 when using a tax with the corresponding tax grid ### Cause: In 19.0, the +/- tax grids were replaced by a single unsigned tax grid The E and F formulas were not updated accordingly, causing their values to be negative instead of positive ### Fix: The formulas have been updated based on the official documentation to correctly separate Sales and Purchases lines: https://www.impots.gouv.fr/sites/default/files/formulaires/3310-ca3-sd/2026/3310-ca3-sd_5426.pdf ### Steps to reproduce: - Install `l10n_fr_account` - Create a Tax (Amount: 1.75%, Base Tax Grids: E5 and F3) - Create an invoice (any amount, Tax: created tax) - Open the Tax Report for this month Before the fix, E5 and F3 lines are empty opw-6357703 Forward-Port-Of: odoo/odoo#278635
## Steps to reproduce: ## Why the fix: opw-6428369
Original PR description
## Steps to reproduce: ## Why the fix: opw-6428369
On python 3.10.12 `test_export_translatable_resources` fails. This is fixed in this commit build-944659 I only tested it on 17.0 since we do not seem to have the build error on higher versions. But the minimum python version is 3.10 until [excluding saas-19.1](https://github.com/odoo/odoo/blob/11ee42b4bf70a1008b06d13a48263e42c381aeed/odoo/release.py#L39) Forward-Port-Of: odoo/odoo#281294 Forward-Port-Of: odoo/odoo#280927
Original PR description
On python 3.10.12 `test_export_translatable_resources` fails. This is fixed in this commit build-944659 I only tested it on 17.0 since we do not seem to have the build error on higher versions. But the minimum python version is 3.10 until [excluding saas-19.1](https://github.com/odoo/odoo/blob/11ee42b4bf70a1008b06d13a48263e42c381aeed/odoo/release.py#L39) Forward-Port-Of: odoo/odoo#281294 Forward-Port-Of: odoo/odoo#280927
Currently, l10n_vn_edi_unit_price and unit_price have the same label, triggering a warning. This commit changes the field name of l10n_vn_edi_price_unit to avoid the conflict. Backport of https://github.com/odoo/odoo/pull/260550 task-260550
Original PR description
Currently, l10n_vn_edi_unit_price and unit_price have the same label, triggering a warning. This commit changes the field name of l10n_vn_edi_price_unit to avoid the conflict. Backport of https://github.com/odoo/odoo/pull/260550 task-260550
In ubuntu 26.04 the time zone database contents changed. A couple of timezone names are not available anymore, causing runtime exceptions. This mapping links old with new time zone naming conventions to prevent future (test) breakdown. The mapping WET to Europe/Lisbon is imperfect, and the localizations for the fixed date inside the test did not match. There exists no better nor correct mapping for WET. The mapping to Europe/Lisbon comes from the IANA tzdb-2026c and is official, so it
Original PR description
In ubuntu 26.04 the time zone database contents changed. A couple of timezone names are not available anymore, causing runtime exceptions. This mapping links old with new time zone naming conventions to prevent future (test) breakdown. The mapping WET to Europe/Lisbon is imperfect, and the localizations for the fixed date inside the test did not match. There exists no better nor correct mapping for WET. The mapping to Europe/Lisbon comes from the IANA tzdb-2026c and is official, so it is kept unchanged. The fixed date inside the test is changed to a recent one that aligns the test outcome with expectations: - Offsets match for recent history and future time - Match daylight savings time (DST) observation --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280691
When importing a UBL bill, if a price-included tax is used, we need to adjust the unit price by adding the tax amount per unit. When a discount is added to the line, the unit price doesn't reflect it, but the raw_tax_amount_currency does. As a result, we add the reduced tax amount to the original unit price. We propose to compute the raw tax amount before the discount to adjust the unit price. opw-6242701 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.
Original PR description
When importing a UBL bill, if a price-included tax is used, we need to adjust the unit price by adding the tax amount per unit. When a discount is added to the line, the unit price doesn't reflect it, but the raw_tax_amount_currency does. As a result, we add the reduced tax amount to the original unit price. We propose to compute the raw tax amount before the discount to adjust the unit price. opw-6242701 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278659
**Steps to reproduce:** 1. Install eCommerce, l10n_be, payment_stripe and switch to belgian company 2. Switch the admin user's company to the belgian one, and update their contact address to be in Belgium 3. Create a website for the belgian company and enable stripe payment provider 4. Add SEPA payment method in stripe configuration 5. Open the website, add any product to cart, go to checkout and make a payment using SEPA **Issue:** - Check the transaction in Stripe dashboard: the order
Original PR description
**Steps to reproduce:** 1. Install eCommerce, l10n_be, payment_stripe and switch to belgian company 2. Switch the admin user's company to the belgian one, and update their contact address to be in…
**Steps to reproduce:** 1. Install eCommerce, l10n_be, payment_stripe and switch to belgian company 2. Switch the admin user's company to the belgian one, and update their contact address to be in Belgium 3. Create a website for the belgian company and enable stripe payment provider 4. Add SEPA payment method in stripe configuration 5. Open the website, add any product to cart, go to checkout and make a payment using SEPA **Issue:** - Check the transaction in Stripe dashboard: the order reference is currently sent only in the `Description` field which is for internal information and is not shown to customers on their bank statements. Customers only see "MACKNET", so they cannot identify which order the payment relates to. **Expected behavior:** - Should also send the order reference to Stripe's `statement_descriptor` field, which is the field used for the customer-facing bank statement reference. - The `statement_descriptor` value must comply with Stripe's requirements: Must not contain <, >, \, ', ", or * Must contain at least one letter Maximum 22 characters **Fix:** - Pass the order reference, which should already satisfy the first two requirements based on Odoo order/invoice naming conventions opw-6424994 Forward-Port-Of: odoo/odoo#280985
Steps: - Install l10n_co module. - Set `CO company` on user. - Go to address page on portal address. - Set `Company Name`, `ID Type` and `ID Number` on the address page. Issue: - Not able to save address without any error message on the address page and in logger it raise validation error. Cause: - In address we actually do vat validation before creation/updation and if there is any issue with vat number then add it into invalid_fields instead raising any validation error, so here wh
Original PR description
Steps: - Install l10n_co module. - Set `CO company` on user. - Go to address page on portal address. - Set `Company Name`, `ID Type` and `ID Number` on the address page. Issue: - Not able to save…
Steps: - Install l10n_co module. - Set `CO company` on user. - Go to address page on portal address. - Set `Company Name`, `ID Type` and `ID Number` on the address page. Issue: - Not able to save address without any error message on the address page and in logger it raise validation error. Cause: - In address we actually do vat validation before creation/updation and if there is any issue with vat number then add it into invalid_fields instead raising any validation error, so here when user set `Company name` on address it try to create parent company and again do vat validation and it raise validation error because `ID Type` on customer is not propagated to parent when creating parent company from portal. Fix: - Skip vat validation on parent company creation from address. To-do: We also need to pass `ID type` and other accounting related values when creating parent company from customer or make them dependent like `Vat`. Issued PR: https://github.com/odoo/odoo/pull/264356 opw-6434127 Forward-Port-Of: odoo/odoo#280859
12 changes
Enhancements to existing features
The checks the Tax Agency performs are always based on the latest version of their XSD (no API versioning), but the XSD URI changes with each new version of the checks. Since it's not functionally used, it's not so important to keep it always updated and yet now: - we now update the export templates to have the latest `schemalocation` URI for once. - we start ignoring namespaces in l10n_it_* XML tests - we start ignoring the root FatturaElettronica tag's namespace attributes so there
Original PR description
The checks the Tax Agency performs are always based on the latest version of their XSD (no API versioning), but the XSD URI changes with each new version of the checks. Since it's not functionally used, it's not so important to keep it always updated and yet now: - we now update the export templates to have the latest `schemalocation` URI for once. - we start ignoring namespaces in l10n_it_* XML tests - we start ignoring the root FatturaElettronica tag's namespace attributes so there won't be a problem in case we change the `schemalocation` again. Forward-Port-Of: odoo/odoo#280795 Forward-Port-Of: odoo/odoo#275345
Resolved issues and error corrections
MyInvois expects the CountrySubentityCode to be fixed as '17' for customers located outside Malaysia, since Malaysian state codes don't apply to them. Set it to '17' instead of the raw state name for non-Malaysian customers. task-6388521 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281095 Forward-Port-Of: odoo/odoo#280550
Original PR description
MyInvois expects the CountrySubentityCode to be fixed as '17' for customers located outside Malaysia, since Malaysian state codes don't apply to them. Set it to '17' instead of the raw state name for non-Malaysian customers. task-6388521 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281095 Forward-Port-Of: odoo/odoo#280550
After this commit: = - LNA is only intended for kiosk mode where local hardware access is expected. Initializing it in mobile mode unnecessarily triggers permission checks. task-6412414
Original PR description
After this commit: = - LNA is only intended for kiosk mode where local hardware access is expected. Initializing it in mobile mode unnecessarily triggers permission checks. task-6412414
**Issue:** Flexible employees in French companies cannot request the reference paid time off type, even when they have a sufficient allocation. **Steps to reproduce:** - Install the l10n_fr_hr_holidays module. - Create a French company and set it as the active company. - Log in as a user whose working schedule is Flexible (i.e., the employee's Working Hours field is left blank). - Ensure the company's Time Off Type matches the leave type that the employee is requesting. - Set a Resource
Original PR description
**Issue:** Flexible employees in French companies cannot request the reference paid time off type, even when they have a sufficient allocation. **Steps to reproduce:** - Install the…
**Issue:** Flexible employees in French companies cannot request the reference paid time off type, even when they have a sufficient allocation. **Steps to reproduce:** - Install the l10n_fr_hr_holidays module. - Create a French company and set it as the active company. - Log in as a user whose working schedule is Flexible (i.e., the employee's Working Hours field is left blank). - Ensure the company's Time Off Type matches the leave type that the employee is requesting. - Set a Resource Calendar on the company (this is required and must differ from the employee's flexible working schedule). - Attempt to create a Time Off request for the employee. **Cause:** https://github.com/odoo/odoo/blob/5e865aeec854ca012dc5537f36b2e626ee39cf0b/addons/l10n_fr_hr_holidays/models/hr_leave.py#L17-L27 `_l10n_fr_leave_applies()` considers an empty employee calendar different from the company calendar. This sends flexible leaves to `_get_fr_date_from_to()`, which requires attendance rows and rejects the request. **Solution:** We need to require a concrete employee calendar before applying the French part-time calendar adjustment, leaving flexible employees to the core flexible-duration computation. opw-6417220 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
How to reproduce: - In a Fiscal Position, map the Downpayment account set in the settings to anything else - Put that Fiscal Position on a SO. - On that SO, create a Downpayment invoice -> The regular Downpayment account is used on the Downpayment invoice, but it should have been mapped because of the Fiscal Position account mapping Solution: Pre-map the company's default down payment account using the Sales Order's Fiscal Position before passing it to the invoice line creation
Original PR description
How to reproduce: - In a Fiscal Position, map the Downpayment account set in the settings to anything else - Put that Fiscal Position on a SO. - On that SO, create a Downpayment invoice -> The regular Downpayment account is used on the Downpayment invoice, but it should have been mapped because of the Fiscal Position account mapping Solution: Pre-map the company's default down payment account using the Sales Order's Fiscal Position before passing it to the invoice line creation. This ensures the correct account mapping is always respected for advance payment invoices. Task-6212218 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279464
On python 3.10.12 `test_export_translatable_resources` fails. This is fixed in this commit build-944659 I only tested it on 17.0 since we do not seem to have the build error on higher versions. But the minimum python version is 3.10 until [excluding saas-19.1](https://github.com/odoo/odoo/blob/11ee42b4bf70a1008b06d13a48263e42c381aeed/odoo/release.py#L39) Forward-Port-Of: odoo/odoo#281294 Forward-Port-Of: odoo/odoo#280927
Original PR description
On python 3.10.12 `test_export_translatable_resources` fails. This is fixed in this commit build-944659 I only tested it on 17.0 since we do not seem to have the build error on higher versions. But the minimum python version is 3.10 until [excluding saas-19.1](https://github.com/odoo/odoo/blob/11ee42b4bf70a1008b06d13a48263e42c381aeed/odoo/release.py#L39) Forward-Port-Of: odoo/odoo#281294 Forward-Port-Of: odoo/odoo#280927
Steps to reproduce: - Enable presets and set a preset carrying a tax-replacing fiscal position (e.g. "Takeout") as the default preset of the POS config - Take an order with another preset that has no fiscal position (e.g. "Dine In") - Refund that order from the ticket screen Issue: The refund is taxed with the fiscal position of the default preset instead of the one of the refunded order. The ticket screen displays the refund lines with the taxes of the original order, but the refund that
Original PR description
Steps to reproduce: - Enable presets and set a preset carrying a tax-replacing fiscal position (e.g. "Takeout") as the default preset of the POS config - Take an order with another preset that has no…
Steps to reproduce: - Enable presets and set a preset carrying a tax-replacing fiscal position (e.g. "Takeout") as the default preset of the POS config - Take an order with another preset that has no fiscal position (e.g. "Dine In") - Refund that order from the ticket screen Issue: The refund is taxed with the fiscal position of the default preset instead of the one of the refunded order. The ticket screen displays the refund lines with the taxes of the original order, but the refund that is actually created maps them through the wrong fiscal position. With tax-included prices the totals still match on screen, so the operator only sees the discrepancy after going back. Cause: The destination order of a refund is an empty order, created with the default preset and therefore with that preset's fiscal position. In TicketScreen.onDoRefund, the fiscal position of the refunded order was only copied onto it when the refunded order had one, so an order taken without a fiscal position kept the default preset's one. When an already existing empty order is reused as destination, whatever fiscal position was last set on it survives for the same reason. Fix: Always assign the fiscal position of the refunded order to the destination order, an empty one included, so a refund is taxed exactly like the order it refunds instead of silently switching. The preset itself is left untouched: it drives the ordering workflow (timing slot, customer identification) which must not be imposed on a refund. opw-6442664 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280672
In ubuntu 26.04 the time zone database contents changed. A couple of timezone names are not available anymore, causing runtime exceptions. This mapping links old with new time zone naming conventions to prevent future (test) breakdown. The mapping WET to Europe/Lisbon is imperfect, and the localizations for the fixed date inside the test did not match. There exists no better nor correct mapping for WET. The mapping to Europe/Lisbon comes from the IANA tzdb-2026c and is official, so it
Original PR description
In ubuntu 26.04 the time zone database contents changed. A couple of timezone names are not available anymore, causing runtime exceptions. This mapping links old with new time zone naming conventions to prevent future (test) breakdown. The mapping WET to Europe/Lisbon is imperfect, and the localizations for the fixed date inside the test did not match. There exists no better nor correct mapping for WET. The mapping to Europe/Lisbon comes from the IANA tzdb-2026c and is official, so it is kept unchanged. The fixed date inside the test is changed to a recent one that aligns the test outcome with expectations: - Offsets match for recent history and future time - Match daylight savings time (DST) observation --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280691
Description of the issue/feature this PR addresses: A user without accounting rights cannot open an invoice form when l10n_es_edi_verifactu is installed. The module adds a VeriFactu page and three warning banners to the standard invoice form without any groups restriction, so every user able to open an invoice reads three fields (l10n_es_edi_verifactu_document_ids, l10n_es_edi_verifactu_warning, l10n_es_edi_verifactu_warning_level) pointing at l10n_es_edi_verifactu.document. That model
Original PR description
Description of the issue/feature this PR addresses: A user without accounting rights cannot open an invoice form when l10n_es_edi_verifactu is installed. The module adds a VeriFactu page and three…
Description of the issue/feature this PR addresses: A user without accounting rights cannot open an invoice form when l10n_es_edi_verifactu is installed. The module adds a VeriFactu page and three warning banners to the standard invoice form without any groups restriction, so every user able to open an invoice reads three fields (l10n_es_edi_verifactu_document_ids, l10n_es_edi_verifactu_warning, l10n_es_edi_verifactu_warning_level) pointing at l10n_es_edi_verifactu.document. That model only grants read access to account.group_account_invoice and account.group_account_readonly. Steps to reproduce: - install `l10n_es_edi_verifactu` - create a salesman user with sales rights but no accounting right (*Own Documents Only* is enough) - create an ES company and an ES customer - give the salesman access to the ES company - activate Peppol in the general settings - log in as the salesman - create a sale order in the ES company for the ES customer - confirm it - click **Create Invoice** - click **Create Draft** Current behavior before PR: An error access is raised: Failed to read field account.move.l10n_es_edi_verifactu_document_ids You are not allowed to access 'Veri*Factu Document' (l10n_es_edi_verifactu.document) records. This operation is allowed for the following groups: - Invoicing/Billing - Technical/Show Accounting Features - Readonly Contact your administrator to request access if necessary. In Odoo sh (for databases 19.0), the standard test sale_management / TestSaleFlowTourPostInstall.test_basic_sale_flow_with_minimal_access_rights fails for the same reason as soon as l10n_es_edi_verifactu is installed alongside sale_management. Desired behavior after PR is merged: On a database with l10n_es_edi_verifactu installed, a non-accountant user having the possibility to create invoices should not have the error message displayed. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280879
When importing a UBL bill, if a price-included tax is used, we need to adjust the unit price by adding the tax amount per unit. When a discount is added to the line, the unit price doesn't reflect it, but the raw_tax_amount_currency does. As a result, we add the reduced tax amount to the original unit price. We propose to compute the raw tax amount before the discount to adjust the unit price. opw-6242701 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.
Original PR description
When importing a UBL bill, if a price-included tax is used, we need to adjust the unit price by adding the tax amount per unit. When a discount is added to the line, the unit price doesn't reflect it, but the raw_tax_amount_currency does. As a result, we add the reduced tax amount to the original unit price. We propose to compute the raw tax amount before the discount to adjust the unit price. opw-6242701 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278659
**Steps to reproduce:** 1. Install eCommerce, l10n_be, payment_stripe and switch to belgian company 2. Switch the admin user's company to the belgian one, and update their contact address to be in Belgium 3. Create a website for the belgian company and enable stripe payment provider 4. Add SEPA payment method in stripe configuration 5. Open the website, add any product to cart, go to checkout and make a payment using SEPA **Issue:** - Check the transaction in Stripe dashboard: the order
Original PR description
**Steps to reproduce:** 1. Install eCommerce, l10n_be, payment_stripe and switch to belgian company 2. Switch the admin user's company to the belgian one, and update their contact address to be in…
**Steps to reproduce:** 1. Install eCommerce, l10n_be, payment_stripe and switch to belgian company 2. Switch the admin user's company to the belgian one, and update their contact address to be in Belgium 3. Create a website for the belgian company and enable stripe payment provider 4. Add SEPA payment method in stripe configuration 5. Open the website, add any product to cart, go to checkout and make a payment using SEPA **Issue:** - Check the transaction in Stripe dashboard: the order reference is currently sent only in the `Description` field which is for internal information and is not shown to customers on their bank statements. Customers only see "MACKNET", so they cannot identify which order the payment relates to. **Expected behavior:** - Should also send the order reference to Stripe's `statement_descriptor` field, which is the field used for the customer-facing bank statement reference. - The `statement_descriptor` value must comply with Stripe's requirements: Must not contain <, >, \, ', ", or * Must contain at least one letter Maximum 22 characters **Fix:** - Pass the order reference, which should already satisfy the first two requirements based on Odoo order/invoice naming conventions opw-6424994 Forward-Port-Of: odoo/odoo#280985
Before this commit, when the project user tries to create a task with a sale_order_id computed, he cannot because the user cannot read the comodel. This commit changes the condition to not block project user to create task if they can. The sale_order_id is actually filled by the compute method, so there is no reason to block the user. Forward-Port-Of: odoo/odoo#281380
Original PR description
Before this commit, when the project user tries to create a task with a sale_order_id computed, he cannot because the user cannot read the comodel. This commit changes the condition to not block project user to create task if they can. The sale_order_id is actually filled by the compute method, so there is no reason to block the user. Forward-Port-Of: odoo/odoo#281380
7 changes
Resolved issues and error corrections
MyInvois expects the CountrySubentityCode to be fixed as '17' for customers located outside Malaysia, since Malaysian state codes don't apply to them. Set it to '17' instead of the raw state name for non-Malaysian customers. task-6388521 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281095 Forward-Port-Of: odoo/odoo#280550
Original PR description
MyInvois expects the CountrySubentityCode to be fixed as '17' for customers located outside Malaysia, since Malaysian state codes don't apply to them. Set it to '17' instead of the raw state name for non-Malaysian customers. task-6388521 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281095 Forward-Port-Of: odoo/odoo#280550
### Issue: In the tax report, lines `E5`, `F3`, `F4`, `F7`, `F8` and `F9` show 0 when using a tax with the corresponding tax grid ### Cause: In 19.0, the +/- tax grids were replaced by a single unsigned tax grid The E and F formulas were not updated accordingly, causing their values to be negative instead of positive ### Fix: The formulas have been updated based on the official documentation to correctly separate Sales and Purchases lines: https://www.impots.gouv.fr/sites/default/file
Original PR description
### Issue: In the tax report, lines `E5`, `F3`, `F4`, `F7`, `F8` and `F9` show 0 when using a tax with the corresponding tax grid ### Cause: In 19.0, the +/- tax grids were replaced by a single unsigned tax grid The E and F formulas were not updated accordingly, causing their values to be negative instead of positive ### Fix: The formulas have been updated based on the official documentation to correctly separate Sales and Purchases lines: https://www.impots.gouv.fr/sites/default/files/formulaires/3310-ca3-sd/2026/3310-ca3-sd_5426.pdf ### Steps to reproduce: - Install `l10n_fr_account` - Create a Tax (Amount: 1.75%, Base Tax Grids: E5 and F3) - Create an invoice (any amount, Tax: created tax) - Open the Tax Report for this month Before the fix, E5 and F3 lines are empty opw-6357703 Forward-Port-Of: odoo/odoo#278635
When importing a UBL bill, if a price-included tax is used, we need to adjust the unit price by adding the tax amount per unit. When a discount is added to the line, the unit price doesn't reflect it, but the raw_tax_amount_currency does. As a result, we add the reduced tax amount to the original unit price. We propose to compute the raw tax amount before the discount to adjust the unit price. opw-6242701 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.
Original PR description
When importing a UBL bill, if a price-included tax is used, we need to adjust the unit price by adding the tax amount per unit. When a discount is added to the line, the unit price doesn't reflect it, but the raw_tax_amount_currency does. As a result, we add the reduced tax amount to the original unit price. We propose to compute the raw tax amount before the discount to adjust the unit price. opw-6242701 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278659
On python 3.10.12 `test_export_translatable_resources` fails. This is fixed in this commit build-944659 I only tested it on 17.0 since we do not seem to have the build error on higher versions. But the minimum python version is 3.10 until [excluding saas-19.1](https://github.com/odoo/odoo/blob/11ee42b4bf70a1008b06d13a48263e42c381aeed/odoo/release.py#L39) Forward-Port-Of: odoo/odoo#281294 Forward-Port-Of: odoo/odoo#280927
Original PR description
On python 3.10.12 `test_export_translatable_resources` fails. This is fixed in this commit build-944659 I only tested it on 17.0 since we do not seem to have the build error on higher versions. But the minimum python version is 3.10 until [excluding saas-19.1](https://github.com/odoo/odoo/blob/11ee42b4bf70a1008b06d13a48263e42c381aeed/odoo/release.py#L39) Forward-Port-Of: odoo/odoo#281294 Forward-Port-Of: odoo/odoo#280927
Steps to reproduce: ------------------------------------------------- 1. Install the `sale_project` module 2. Create a test user with Project User rights 3. Create a Project Role with the Created User as a Team Member 4. Create a Template Project as follows: * Add one task to the template project * Add the created Project role to the Task 5. Create a Service Type Product with: * Create on order: Project * Project Template: Created Template 6. Archive the Created User
Original PR description
Steps to reproduce: ------------------------------------------------- 1. Install the `sale_project` module 2. Create a test user with Project User rights 3. Create a Project Role with the Created…
Steps to reproduce:
-------------------------------------------------
1. Install the `sale_project` module
2. Create a test user with Project User rights
3. Create a Project Role with the Created User as a Team Member
4. Create a Template Project as follows:
* Add one task to the template project
* Add the created Project role to the Task
5. Create a Service Type Product with:
* Create on order: Project
* Project Template: Created Template
6. Archive the Created User
7. Create and Confirm the Sale Order with the Created Product
Observation:
-------------------------------------------------
The generated task is assigned to the archived user, although the archived user is no longer part of the Project Role.
Issue:
-------------------------------------------------
While creating Project and Tasks from template, the context disable active record filtering (e.g., `active_test=False`), causing the assignment logic to fetch both active and inactive/archived users linked to the role. https://github.com/odoo/odoo/blob/8ec646e51497b38d34ea59296e0fc8644a50ee3a/odoo/orm/models.py#L4868
After that, during the `copy_data` method, It takes all the users from the roles without checking weather user is active or not
https://github.com/odoo/odoo/blob/8ec646e51497b38d34ea59296e0fc8644a50ee3a/addons/project/models/project_task.py#L890-L904
And even if we pass only Active users from this method, on moving further, it reassigns the users from roles without checking the Active field of the user
https://github.com/odoo/enterprise/blob/5abb147f9bf725daafc202d8259a5bb8a9b78d94/project_enterprise/models/project_task.py#L501-L503
https://github.com/odoo/enterprise/blob/5abb147f9bf725daafc202d8259a5bb8a9b78d94/project_enterprise/models/project_task.py#L544-L553
Due to this, the Archived User is also assigned to the tasks from the project roles
Solution:
-------------------------------------------------
Apply a `filtered('active')` check directly on the project role's users
`(role.user_ids)` within the core task-copying logic in both `project` and
`project_enterprise` modules. This ensures archived users are universally
excluded from task assignments during template copying, regardless of what
triggers the template instantiation.
Related Enterprise PR: https://github.com/odoo/enterprise/pull/125637
opw-6350841In ubuntu 26.04 the time zone database contents changed. A couple of timezone names are not available anymore, causing runtime exceptions. This mapping links old with new time zone naming conventions to prevent future (test) breakdown. The mapping WET to Europe/Lisbon is imperfect, and the localizations for the fixed date inside the test did not match. There exists no better nor correct mapping for WET. The mapping to Europe/Lisbon comes from the IANA tzdb-2026c and is official, so it
Original PR description
In ubuntu 26.04 the time zone database contents changed. A couple of timezone names are not available anymore, causing runtime exceptions. This mapping links old with new time zone naming conventions to prevent future (test) breakdown. The mapping WET to Europe/Lisbon is imperfect, and the localizations for the fixed date inside the test did not match. There exists no better nor correct mapping for WET. The mapping to Europe/Lisbon comes from the IANA tzdb-2026c and is official, so it is kept unchanged. The fixed date inside the test is changed to a recent one that aligns the test outcome with expectations: - Offsets match for recent history and future time - Match daylight savings time (DST) observation --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280691
Description of the issue/feature this PR addresses: A user without accounting rights cannot open an invoice form when l10n_es_edi_verifactu is installed. The module adds a VeriFactu page and three warning banners to the standard invoice form without any groups restriction, so every user able to open an invoice reads three fields (l10n_es_edi_verifactu_document_ids, l10n_es_edi_verifactu_warning, l10n_es_edi_verifactu_warning_level) pointing at l10n_es_edi_verifactu.document. That model
Original PR description
Description of the issue/feature this PR addresses: A user without accounting rights cannot open an invoice form when l10n_es_edi_verifactu is installed. The module adds a VeriFactu page and three…
Description of the issue/feature this PR addresses: A user without accounting rights cannot open an invoice form when l10n_es_edi_verifactu is installed. The module adds a VeriFactu page and three warning banners to the standard invoice form without any groups restriction, so every user able to open an invoice reads three fields (l10n_es_edi_verifactu_document_ids, l10n_es_edi_verifactu_warning, l10n_es_edi_verifactu_warning_level) pointing at l10n_es_edi_verifactu.document. That model only grants read access to account.group_account_invoice and account.group_account_readonly. Steps to reproduce: - install `l10n_es_edi_verifactu` - create a salesman user with sales rights but no accounting right (*Own Documents Only* is enough) - create an ES company and an ES customer - give the salesman access to the ES company - activate Peppol in the general settings - log in as the salesman - create a sale order in the ES company for the ES customer - confirm it - click **Create Invoice** - click **Create Draft** Current behavior before PR: An error access is raised: Failed to read field account.move.l10n_es_edi_verifactu_document_ids You are not allowed to access 'Veri*Factu Document' (l10n_es_edi_verifactu.document) records. This operation is allowed for the following groups: - Invoicing/Billing - Technical/Show Accounting Features - Readonly Contact your administrator to request access if necessary. In Odoo sh (for databases 19.0), the standard test sale_management / TestSaleFlowTourPostInstall.test_basic_sale_flow_with_minimal_access_rights fails for the same reason as soon as l10n_es_edi_verifactu is installed alongside sale_management. Desired behavior after PR is merged: On a database with l10n_es_edi_verifactu installed, a non-accountant user having the possibility to create invoices should not have the error message displayed. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280879
9 changes
Enhancements to existing features
Before this commit, when importing and invoice/bill, we predicted the invoice line account based on previous invoices/bills. If the predicted account had default tax, it was ignored during tax matching. With this commit, first checks whether the predicted account has a default tax. If it finds one that matches the tax percentage from the imported XML, that tax is applied. Otherwise, or if the account has no default tax, the existing tax matching logic is used. task-6345661 Forward-Po
Original PR description
Before this commit, when importing and invoice/bill, we predicted the invoice line account based on previous invoices/bills. If the predicted account had default tax, it was ignored during tax matching. With this commit, first checks whether the predicted account has a default tax. If it finds one that matches the tax percentage from the imported XML, that tax is applied. Otherwise, or if the account has no default tax, the existing tax matching logic is used. task-6345661 Forward-Port-Of: odoo/odoo#279940
Resolved issues and error corrections
When importing a UBL bill, if a price-included tax is used, we need to adjust the unit price by adding the tax amount per unit. When a discount is added to the line, the unit price doesn't reflect it, but the raw_tax_amount_currency does. As a result, we add the reduced tax amount to the original unit price. We propose to compute the raw tax amount before the discount to adjust the unit price. opw-6242701 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.
Original PR description
When importing a UBL bill, if a price-included tax is used, we need to adjust the unit price by adding the tax amount per unit. When a discount is added to the line, the unit price doesn't reflect it, but the raw_tax_amount_currency does. As a result, we add the reduced tax amount to the original unit price. We propose to compute the raw tax amount before the discount to adjust the unit price. opw-6242701 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278659
Steps to reproduce: - Set a Saudi company with a long legal name (e.g. "Golden Oasis Trading and Contracting Company Limited") - Make a POS order and look at the receipt QR code Issue: The QR code is drawn visibly smaller and denser than for a company with a short name, even though the image it sits in is the same 150px box: 90px of code at a 2px module pitch, against 111px at 3px. Cause: The ZATCA payload embeds the seller name, so a longer name needs a higher QR version, i.e. more mo
Original PR description
Steps to reproduce: - Set a Saudi company with a long legal name (e.g. "Golden Oasis Trading and Contracting Company Limited") - Make a POS order and look at the receipt QR code Issue: The QR code is drawn visibly smaller and denser than for a company with a short name, even though the image it sits in is the same 150px box: 90px of code at a 2px module pitch, against 111px at 3px. Cause: The ZATCA payload embeds the seller name, so a longer name needs a higher QR version, i.e. more modules. ZXing's BrowserQRCodeSvgWriter draws each module at a whole number of pixels of the canvas it is given (multiple = floor(canvas / (modules + 8))), so asking it for a fixed 150x150 or 200x200 canvas leaves a leftover margin that varies with the module count. The code shrinks as soon as the module count crosses a multiple of the canvas size. opw-6399878 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280000
The `qr_code` field on res.config.settings was labeled "Display SEPA QR-code", even though the underlying feature generates QR codes for any supported country scheme, not just SEPA. Align the label with the already-generic string used on res.company and the setting's help text. opw-6452422 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
The `qr_code` field on res.config.settings was labeled "Display SEPA QR-code", even though the underlying feature generates QR codes for any supported country scheme, not just SEPA. Align the label with the already-generic string used on res.company and the setting's help text. opw-6452422 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
In ubuntu 26.04 the time zone database contents changed. A couple of timezone names are not available anymore, causing runtime exceptions. This mapping links old with new time zone naming conventions to prevent future (test) breakdown. The mapping WET to Europe/Lisbon is imperfect, and the localizations for the fixed date inside the test did not match. There exists no better nor correct mapping for WET. The mapping to Europe/Lisbon comes from the IANA tzdb-2026c and is official, so it
Original PR description
In ubuntu 26.04 the time zone database contents changed. A couple of timezone names are not available anymore, causing runtime exceptions. This mapping links old with new time zone naming conventions to prevent future (test) breakdown. The mapping WET to Europe/Lisbon is imperfect, and the localizations for the fixed date inside the test did not match. There exists no better nor correct mapping for WET. The mapping to Europe/Lisbon comes from the IANA tzdb-2026c and is official, so it is kept unchanged. The fixed date inside the test is changed to a recent one that aligns the test outcome with expectations: - Offsets match for recent history and future time - Match daylight savings time (DST) observation --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280691
Description of the issue/feature this PR addresses: A user without accounting rights cannot open an invoice form when l10n_es_edi_verifactu is installed. The module adds a VeriFactu page and three warning banners to the standard invoice form without any groups restriction, so every user able to open an invoice reads three fields (l10n_es_edi_verifactu_document_ids, l10n_es_edi_verifactu_warning, l10n_es_edi_verifactu_warning_level) pointing at l10n_es_edi_verifactu.document. That model
Original PR description
Description of the issue/feature this PR addresses: A user without accounting rights cannot open an invoice form when l10n_es_edi_verifactu is installed. The module adds a VeriFactu page and three…
Description of the issue/feature this PR addresses: A user without accounting rights cannot open an invoice form when l10n_es_edi_verifactu is installed. The module adds a VeriFactu page and three warning banners to the standard invoice form without any groups restriction, so every user able to open an invoice reads three fields (l10n_es_edi_verifactu_document_ids, l10n_es_edi_verifactu_warning, l10n_es_edi_verifactu_warning_level) pointing at l10n_es_edi_verifactu.document. That model only grants read access to account.group_account_invoice and account.group_account_readonly. Steps to reproduce: - install `l10n_es_edi_verifactu` - create a salesman user with sales rights but no accounting right (*Own Documents Only* is enough) - create an ES company and an ES customer - give the salesman access to the ES company - activate Peppol in the general settings - log in as the salesman - create a sale order in the ES company for the ES customer - confirm it - click **Create Invoice** - click **Create Draft** Current behavior before PR: An error access is raised: Failed to read field account.move.l10n_es_edi_verifactu_document_ids You are not allowed to access 'Veri*Factu Document' (l10n_es_edi_verifactu.document) records. This operation is allowed for the following groups: - Invoicing/Billing - Technical/Show Accounting Features - Readonly Contact your administrator to request access if necessary. In Odoo sh (for databases 19.0), the standard test sale_management / TestSaleFlowTourPostInstall.test_basic_sale_flow_with_minimal_access_rights fails for the same reason as soon as l10n_es_edi_verifactu is installed alongside sale_management. Desired behavior after PR is merged: On a database with l10n_es_edi_verifactu installed, a non-accountant user having the possibility to create invoices should not have the error message displayed. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280879
Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions 3. Create invoice with ar_001 partner 4. Confirm the invoice 5. Try to create credit note → Error: KeyError: 'en_US' Root Cause: The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB di
Original PR description
Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings >…
Steps to Reproduce the Error (Odoo SaaS 19.2):
1. Install l10n_gcc_invoice localization & Accounting
2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions
3. Create invoice with ar_001 partner
4. Confirm the invoice
5. Try to create credit note → Error: KeyError: 'en_US'
Root Cause:
The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB dict directly into cache, bypassing ORM field conversion. When Odoo 19.2's improved ORM conversion runs, it creates nested JSON in narration instead of a flat structure.
Timeline:
- bedf1cb66fbb: Workaround added to prevent T&C duplication in preview
- 75f050b9650d: Root cause fixed in report template (conditional display) → Made _load_narration_translation() redundant
- 4e4156536bc9: Odoo 19.2 improved ORM conversion → Now conflicts with the redundant workaround, causing nested JSON
How It Breaks:
1. Invoice creation: _load_narration_translation() injects raw dict into cache
2. ORM writes: nested JSON stored: {ar_001: {en_US: ., ar_001: Arabic}}
3. Credit note creation: copy_translations() expects flat structure → Crashes: KeyError: 'en_US'
Why It's Safe to Remove:
Report template already prevents T&C duplication (commit 75f050b9650d). Removing the workaround restores proper credit note creation without breaking T&C display.
Changes:
- Remove moves._load_narration_translation() in create()
- Remove out self.filtered('id')._load_narration_translation() in _compute_narration()
opw : 6284943
Forward-Port-Of: odoo/odoo#271037**Steps to reproduce:** This issue is hard to reproduce because it requires a live ZATCA connection: - As a user with read-only permission on journals, send an invoice to ZATCA. - You get an access error on the journal, and the invoice is unchanged (You can try sending it again to ZATCA). **Issue:** What happens is: - A user with read-only permission on journals sends an invoice to ZATCA. - If ZATCA responds with a 200 (successfully submitted), we try to write on the field `journal.l10n
Original PR description
**Steps to reproduce:** This issue is hard to reproduce because it requires a live ZATCA connection: - As a user with read-only permission on journals, send an invoice to ZATCA. - You get an access error on the journal, and the invoice is unchanged (You can try sending it again to ZATCA). **Issue:** What happens is: - A user with read-only permission on journals sends an invoice to ZATCA. - If ZATCA responds with a 200 (successfully submitted), we try to write on the field `journal.l10n_sa_latest_submission_hash` - With no write permissions, the write fails and all changes are rolled back (on odoo, not on ZATCA) - We can send the invoice again to ZATCA, resulting in duplicates. **Solution:** - Added a sudo when writing on the field: `journal.l10n_sa_latest_submission_hash` opw-6320179 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278728
### Steps to reproduce 1. Install *Sales* and *Timesheets* 2. Create a service product: Invoicing Policy = *Based on Timesheets*, Create on Order = *Task* 3. Create a sale order for it (quantity 1) and confirm it 4. On the generated task, log **4.5 h on 15/06** and **3.5 h on 23/07** 5. *Create Invoice* with no timesheet period → 8 h, and post it 6. On that invoice: *Reverse* → *Partial Refund*, set the quantity to **3.5 h** and post it → 4.5 h invoiced 7. Log **1 h on 31/07** → 9 h delivered 8
Original PR description
### Steps to reproduce 1. Install *Sales* and *Timesheets* 2. Create a service product: Invoicing Policy = *Based on Timesheets*, Create on Order = *Task* 3. Create a sale order for it (quantity 1)…
### Steps to reproduce 1. Install *Sales* and *Timesheets* 2. Create a service product: Invoicing Policy = *Based on Timesheets*, Create on Order = *Task* 3. Create a sale order for it (quantity 1) and confirm it 4. On the generated task, log **4.5 h on 15/06** and **3.5 h on 23/07** 5. *Create Invoice* with no timesheet period → 8 h, and post it 6. On that invoice: *Reverse* → *Partial Refund*, set the quantity to **3.5 h** and post it → 4.5 h invoiced 7. Log **1 h on 31/07** → 9 h delivered 8. *Create Invoice* again, with a **Timesheets Period of 01/06 → 31/07** ### Current behavior The invoice bills **9 h**: the 4.5 h that were invoiced and not credited are billed a second time. ### Expected behavior The invoice bills **4.5 h** — the quantity delivered minus the quantity invoiced. ### Cause of the issue Posting a partial credit note clears `timesheet_invoice_id` on every timesheet the reversed invoice had linked (`sale_timesheet/models/account_move.py`, `action_post`), because a credit note carries a quantity and never a set of timesheets, so there is no way to tell which hours it credited. All of those hours therefore become candidates again in `_recompute_qty_to_invoice`, which assigns their sum to `qty_to_invoice` without comparing it to what is still due on the line. ### Fix Timesheet links cannot express a partially invoiced timesheet, so they are used only to select the hours a period concerns, while the quantity that may still be billed is `qty_delivered - qty_invoiced`. The period lookup is capped by that remainder, and kept at zero or above so that an over-invoiced line is corrected by a deliberate credit note rather than as a side effect of invoicing a period. ### Tests Five tests are added to `addons/sale_timesheet/tests/test_sale_timesheet.py`. Three of them fail without the fix: | test | without the fix | | --- | --- | | `test_period_invoice_does_not_rebill_refunded_invoice_hours` | `9.0 != 4.5` | | `test_period_invoice_after_refund_is_computed_per_line` | `4.0 != 1.5` | | `test_period_invoice_after_refund_of_an_over_invoiced_line` | `8.0 != 1.0` | The other two cover behaviour that is not exercised today and that the fix must not break: an over-invoiced line (which must be left out rather than credited, and must not prevent the other lines of the order from being invoiced) and the reversed invoice's own `invoice_date`, which must not influence the quantity billed for a period. The full `sale_timesheet` suite passes (86 tests). Forward-Port-Of: odoo/odoo#280721 Forward-Port-Of: odoo/odoo#280536
29 changes
Enhancements to existing features
Shared document links now keep the user's current context, including the active spreadsheet sheet, even when redirects occur. This helps recipients land directly on the intended sheet instead of needing to navigate there manually.
Original PR description
## Description of the issue/feature this PR addresses: Current behavior before PR: - Fragment parameters in document URLs (such as the active sheet) were lost during redirects, causing the client to lose its current state. Changes introduced: - Redirects now preserve fragment parameters generically, so URL state is maintained without needing feature-specific controller logic. - Shareable document links now include the current `sheet_id` as a URL parameter. Desired behavior after PR is merged: - When a shared document link is opened, the correct sheet is restored automatically, preserving the user’s context. Task: [4760176](https://www.odoo.com/odoo/project/2328/tasks/4760176)
Spreadsheet dashboard definitions were updated so key values and baselines use the latest formula format. This keeps dashboards working consistently across accounting, CRM, helpdesk, payroll, recruitment, marketing, manufacturing, purchasing, rentals, and documents reporting.
Original PR description
…formula syntax "keyValue" and "baseline" are now formulas and need an "=" symbol Task: 6343843
Document sorting with AI is now available without requiring a Studio subscription. This makes the AI sorting capability easier to access for document workflows and removes an unnecessary paid dependency.
Original PR description
Purpose ======= We changed our mind, and we should be able to sort documents with AI without having to pay for studio. Revert of bc15543b5ce563bdddb54198eaaf00a5c8d01e54 Task-6383816 Forward-Port-Of: odoo/enterprise#126796
Website users can now use the ALT+H keyboard shortcut on frontend pages to jump directly to the backend homepage. This makes navigation faster for users who move between the public website and administrative areas.
Original PR description
This PR adds an "ALT+H" shortcut on the frontend pages to jump straight to the backend homepage. task-5347435
US payroll calculations now use the date employees are paid, rather than the pay period end date, for year-to-date totals and tax reporting. This helps ensure year-end payslips paid in January are reported in the correct tax year, improving W-2 accuracy.
Original PR description
*: l10n_us_ Purpose: For the US official tax reporting (e.g. W-2), the totals are computed based on the date when the payslip was paid out to the employees, not the pay period in which the wages were earned. It is necessary because a very likely occurrence of a December payslip being paid out in January of the following year must count towards the W-2 of the following year. Current Behavior: The US salary rules and related year-to-date calculations are computed based on the closing date of the pay period. Expected Behavior: The US salary rules and related year-to-date calculations are computed based on the paid_date of the payslip. task-5450399
The employee list shown when creating a Pay Run is now less cluttered because the Termination column is hidden by default. Users can still access it from the Options menu when needed, keeping important payroll details available without crowding the main view.
Original PR description
Before, when creating a Pay Run, the Termination column was always visible. Since it is not frequently used, we moved it to the Options menu to reduce clutter. Task-6449701
Existing spreadsheet dashboards across several business apps have been refreshed to use the newer carousel data view experience. This makes dashboard navigation and presentation more modern while keeping the underlying dashboard content unchanged.
Original PR description
This task aims to update existing dashboards to use new carousel data views. Task: 6412458
Belgian payroll users can now see the replacement amount directly in the worked days section of a payslip. This makes absence valuations clearer and reduces the need to rely on generated reports to understand how amounts were calculated.
Original PR description
Period valuations for absences were only computed when generating reports, making it unclear for users how amounts were determined. This adds a "Replacement Amount" column to the worked days tab of the payslip to display the period valuation. Task-6377538
Australian payroll pay runs now show superannuation contributions and tax withholding directly in the payslip list, along with totals at the top of the pay run. This helps payroll teams review key employer contribution and withholding amounts faster without opening individual payslips.
Original PR description
super contribution column (SUPER + SUPER.CONTRIBUTION lines) is shown in the payrun's view
. in the list view of payslips
tax withholding column is shown in the payrun's view
. in the list view of payslips
Total of super contributions and tax withholding is shown in the top of the payrun view
task-6423860Odoo now creates tracking log messages in batches when many records are updated at once, instead of processing each record separately. This improves performance for large updates while preserving attachments and tracking details for each document.
Original PR description
When tracked fields change on many records without a subtype change, each record's tracking message was logged individually through `_message_log`, resulting in one `_message_create` call per record. Grouping the logs by author and going through `_message_log_batch` creates all the messages of a batch in a single `_message_create` call. To allow this, `_message_log_batch` now takes `attachment_ids` and `tracking_values` as dicts keyed by record id instead of flat values, lifting the previous limitation that batch logs could not carry attachments or tracking values for more than one document. task-6354178
When logging a VoIP call, Odoo now automatically suggests the business record the user already has open, reducing manual selection and helping calls get linked to the right customer, ticket, project, or document. The update also prevents access errors for non-HR users when call logging touches HR-related options.
Original PR description
When log a call, if the user has a opened form of a record, we will try select this record in the log call wizard. Task-[6204862](https://www.odoo.com/odoo/5778/tasks/6204862)
Belgian payroll users can now correct previously submitted 281.10 and 281.45 forms using the Belcotax reference number. The system also warns teams when payroll changes make submitted forms inconsistent, helping them identify and handle corrections on time.
Original PR description
Task: 5470512
Belgian payroll dashboards now warn when an employee has Dimona declarations that are not yet covered by a payslip, even though a pay run exists without that employee. This helps payroll teams spot missing payslips sooner and reduce compliance or processing oversights.
Original PR description
This commit adds a dashboard warning for employees that have dimonas not covered by any payslip yet a payrun exists in which they are not included. task- 6201337
Resolved issues and error corrections
TikTok Shop orders that arrive without a payment timestamp, such as Cash On Delivery orders, can now be created and synchronized instead of failing. The system temporarily uses the order creation time and marks payment as pending, then updates the order once TikTok provides the payment confirmation time.
Original PR description
**Issue**
- TikTok Shop orders may be received without any `paid_time` value in the returned API data, particularly for _Cash On Delivery ([COD](https://seller-ph.tiktok.com/university/essay?knowledge_id=10004482&lang=en)) payments.
- When creating the order, `_create_order_from_data` accessed `order_data[‘paid_time’]` directly, which triggered a `KeyError` and prevented all orders from being fully synchronised.
**Changes**
- When creating an order, if `paid_time` is missing from the data provided by TikTok:
-> `date_order` is initialised with `create_time` as a fallback
-> The new field `tiktok_payment_pending` is set to `True` to mark the order as awaiting payment confirmation.
- During subsequent synchronisations, if `paid_time` is now provided by TikTok for a pending order,
-> `date_order` is updated with the new provided timestamp and the `tiktok_payment_pending` flag is reset.
opw-6440127
Forward-Port-Of: odoo/enterprise#126797The UAE payroll employee profile now restricts the MOHRE skill level field to HR users only. This prevents non-HR employees from seeing HR-specific information on public employee profiles and resolves the reported access issue.
Original PR description
add group `hr.group_hr_user` to `l10n_ae_mohre_skill_level` to make sure it's hidden for non-hr users in the public employee profile fixes https://runbot.odoo.com/odoo/error/242024 opw-242024 Forward-Port-Of: odoo/enterprise#125452
Tax return deadline dates in account report emails are now shown using the recipient's locale settings. This prevents confusion caused by unfamiliar date formats and makes deadline communications clearer for international users.
Original PR description
The date was not formatted according to the user's locale. Forward-Port-Of: odoo/enterprise#127317
Belgian payroll now calculates employment bonuses correctly for both full-time and part-time employees. This improves payroll accuracy and helps align payslips and social security reporting with official Belgian guidance.
Original PR description
[IMP] l10n_be: fix the calculation of employement bonus A According to the document: https://www.socialsecurity.be/employer/instructions/dmfa/fr/latest/instructions/deductions/workers_reductions/workbonus.html We were calculating the employement bonus A according to S = (W/H) x U calculation in the document. But it is only for part-time workers. Now, we consider full time cases as well and the final result is accurate. task - 6334065
The EPF Summary report now calculates EPS contributions based on basic salary, in line with Indian payroll rules. This helps payroll teams avoid incorrect statutory contribution amounts in reporting.
Original PR description
**Steps to Reproduce** - Create an Indian employee. - Create a payslip for this employee. - Go to **Payroll > Reporting > EPF-ECR Report**. - Create a new report with the report type **EPF Summary**. **Before This Commit** - For the EPS contribution, we were calculating `min(15,000, EPF)` and then applying **8.33%** to the resulting amount. - This resulted in an incorrect EPS contribution amount. **After This Commit** - According to Indian payroll rules, the EPS contribution is calculated as 8.33% of `min(15,000, Basic Salary)`, rather than `8.33% of the EPF amount`. - This commit corrects the EPS contribution calculation accordingly. Task: [6442399](https://www.odoo.com/odoo/project/1251/tasks/6442399) Forward-Port-Of: odoo/enterprise#126608
Activity Watch can now use a task ID captured directly from a configured rule pattern, such as one found in a page URL or window title. This makes timesheet suggestions more accurate when the task is already visible in the activity name, reducing reliance on less precise guessing from past activity.
Original PR description
Before this commit, when the task_id to link to activity watch can be found in the URL or window/tab name but it is not possible for the user to create a regex to be able to automatically say to the system the task_id is found in the event name recorded by activity watch. This commit adds the possibility to define `task_id` group name inside the regex to be able to take that information instead of searching which task is linked to that event based on previous key event or the frequency of the current user. task-[6384029](https://www.odoo.com/odoo/project.task/6384029) Forward-Port-Of: odoo/enterprise#126588 Forward-Port-Of: odoo/enterprise#124113
This update makes a small correction in the referenced module to improve reliability. The pull request details do not provide enough information to identify the specific business process affected, so the expected impact appears limited.
Automatic values inserted into salary contract and signature documents now keep valid zero values instead of turning them into blanks. Decimal values are also rounded properly, helping business documents show accurate amounts.
Original PR description
Before this commit, falsy values were always set to '' even when they corresponded to numbers. Moreover, floats values were not rounded. Forward-Port-Of: odoo/enterprise#127064 Forward-Port-Of: odoo/enterprise#121640
This fix makes cash basis report tests use the configured outstanding receipts account instead of assuming a fixed account code. It helps prevent false test failures when account codes differ between database setups, improving reliability without changing business functionality.
Original PR description
Description of the issue this commit addresses: Commit 63f5646cfd75 made the tests use the default outstanding account but hard-coded code 101403. In an all-module database, generated account codes depend on existing accounts, so Outstanding Receipts may use code 101404 and make otherwise correct report assertions fail. --- Desired behavior after this commit is merged: This commit derives the expected report line name from the configured outstanding receipts account, making the assertions independent of its generated code. --- runbot-[231581](https://runbot.odoo.com/odoo/error/231581) Forward-Port-Of: odoo/enterprise#126743 Forward-Port-Of: odoo/enterprise#125652
This update improves how the Belgian payroll module calculates DMFA reported days, especially for employees working 40-hour weeks. It helps prevent overstated day totals in payroll declarations, improving reporting accuracy and reducing correction work.
Original PR description
Currently, there is problem with DMFA Number of days Computation, If we have case where the employee working hour is 40h/week, the calculations mentioned in report 67.5 days, which is too many, In this PR, expected to update the number of days on DMFA computations task-6432418
The tax return view now adjusts its status bar layout to match the number of states shown. This prevents broken or misaligned cards for country-specific tax returns, such as Indian reports with four states.
Original PR description
…te counts Steps to reproduce: - Install l10n_in_reports and select an Indian company - Go to the tax return and set a date in the past --> The state bar layout breaks because there are 4 states, but the CSS grid was previously hardcoded to a maximum of 3 columns. Cause: The CSS `--columns` rule assumed a maximum of 3 states across return cards. When 4 states are present, the grid columns shift or break. Fix: Calculate the maximum state count across all visible records in the kanban renderer (`maxStateCount`) and set it as a CSS variable on the parent container. This ensures all cards in the view align consistently to the maximum number of states present without hardcoding column counts.
The Point of Sale appointment booking Gantt view now loads capacity information when it first opens. This prevents attendee labels from showing confusing placeholder text like "undefinedp" and makes booking details clearer for staff.
Original PR description
Steps to reproduce : - Open PoS and navigate to the Booking view (Gantt View). - Create a booking or view existing bookings / time-off leaves on the Gantt chart. - Observe 'undefinedp' appended to attendee names on Gantt pills (e.g. 'Billy Fox undefinedp'). Issue : 'undefinedp' is displayed on Gantt view pills instead of the correct capacity. Cause : Capacity information was not being fetched during the initial Gantt view rendering. Fix : Ensured capacity data is fetched during initial Gantt view loading so guest capacity displays properly on Gantt pills. Task ID: 6405279
This fixes an issue in the Timesheet timer form where clicking Save or Reset could trigger an error instead of completing the action. The change helps users record or adjust time entries without interruption.
Original PR description
469a7d200ce ([FIX] timesheet_grid: focus on description input, odoo/enterprise#125993) was forward-ported from saas-19.4 onto master a day after 6d3c12624e4 had turned `descriptionFieldRef` into a `signal.ref()`, which has no `.el`: clicking Save or Reset in the timesheet timer form throws on `undefined.querySelector` in onPatched -- the very refocus the original fix was adding. The read is correct on the back branches, where the ref is still a `useRef()`; call the ref on master.
Website Studio now ignores automatic cleanup edits when deciding whether a user has made changes. This helps prevent the system from treating background formatting updates as user edits, reducing false change prompts or unnecessary save behavior.
Original PR description
Automatic mutations done by `normalize` are now marked with `isAutomatic`. This commit ignore those in `on_pending_mutations_staged_handlers`.
Code cleanup and technical improvements
This change updates how report filters are built internally, aligning enterprise reporting modules with a shared query-handling improvement. It should not change day-to-day workflows, but helps keep reporting code more consistent and maintainable.
Original PR description
https://github.com/odoo/odoo/pull/281077
German Elster tax submission features have been moved into the main German reports module instead of staying in a separate add-on. This simplifies setup and maintenance while keeping the same reporting capability available in one place.
Original PR description
After introducing the module l10n_de_reports_elster in 19.0 ( PR: https://github.com/odoo/enterprise/pull/121805 ), we need to merge it in l10n_de_reports in master as it doesn't make sense to keep this module as a standalone module. l10n_de_reports_elster is now part of l10n_de_reports. task-6396219
8 changes
Enhancements to existing features
Budget report loading has been optimized by changing how budget lines are matched to related records, avoiding very slow comparisons on larger datasets. This makes budget reporting usable again for customers with many analytic lines and purchase order lines, with benchmarked load time dropping from nearly a minute to about a second in the tested case.
Original PR description
**Description:** While loading the budget report, the bad queries are created by ```def _get_aal_query()``` and ```def _get_pol_query()``` function, makes the budget report unusable. **Root cause:**…
**Description:**
While loading the budget report, the bad queries are created by
```def _get_aal_query()``` and ```def _get_pol_query()``` function, makes
the budget report unusable.
**Root cause:**
Instead of doing a hash join while searching the record,
the OR statement in the Left Join in the condition
```(%(bl)s IS NULL OR %(a)s = %(bl)s)```
creates a nested for loop that compares everything single aal to bl,
this causes a significant performance issue as the number of the
number of check will be the the number aal * bl,
if a database has a 70k aal and 20k bl, both numbers are not large
but it will cause a 70k * 20k search which is more than a billion.
**Fix**:
There are some refactors made in this PR.
_First_, separate out the Q1.
In order to find the aal that has no bl connects to it.
Doing a search to find the aals that have bl and then subtract them from all aals.
_Second_, Instead of doing a nested loop for by using
```(%(bl)s IS NULL OR %(a)s = %(bl)s)```,
originally we will have do something like
```
JOIN budget_line bl
ON (bl.x_plan2_id IS NULL OR aal.x_plan2_id = bl.x_plan2_id)
AND (bl.x_plan3_id IS NULL OR aal.x_plan3_id = bl.x_plan3_id)
AND (bl.x_plan4_id IS NULL OR aal.x_plan4_id = bl.x_plan4_id)
```
Assuming each bl has three plans ```x_plan2_id```, ```x_plan3_id```, ```x_plan4_id```
Grouping the bl base on whether a specific plan is set, (i.e. shapes)
we can skip the ```IS NULL OR``` because we already know which plan
is null and do the hash join directly.
For example, the shapes will be a dictionary with a key of a tuple of booleans
based on whether a plan is set or not and the value is a list of bl_id.
```
{
(True, False, False): [1, 2],
(False, True, True): [3, 4],
(False, False, False): [5],
}
```
we can end up doing something like
```
JOIN budget_line bl
ON bl.id = ANY(ARRAY[3,4])
AND aal.x_plan3_id = bl.x_plan3_id AND aal.x_plan4_id = bl.x_plan4_id
```
which is way more faster.
---
The benchmark is made locally from this client's database which contains
69k aal, 23k bl, 6829 pol and 3 plans for aal and bl.
|Record count |Time before|Time after|
|--------------------------------------------------|-----------------|---------------|
|69k aal, 23k bl, 6829 pol, 3 plans |70.04s |4.6s |
Dalibo:
Before:
Month-over-month grand total by company:
https://explain.dalibo.com/plan/8h3d4e89aaf9f3d4
Overall grand total by company:
https://explain.dalibo.com/plan/445g1f9caf4923e2
Month-over-month grand total by plan:
https://explain.dalibo.com/plan/53a138ca50b2a7c4
Overall grand total by plan:
https://explain.dalibo.com/plan/hdbe169ddc7g5785
After:
Month-over-month grand total by company:
https://explain.dalibo.com/plan/hcc86c801e6872bf
Overall grand total by company:
https://explain.dalibo.com/plan/69b2421a3581f98h
Month-over-month grand total by plan:
https://explain.dalibo.com/plan/a88f398bbbch3148
Overall grand total by plan:
https://explain.dalibo.com/plan/1gg749ae7ab1553c
opw-6345552
Forward-Port-Of: odoo/enterprise#127297
Forward-Port-Of: odoo/enterprise#124161Belgian payroll now includes the upcoming fiscal employment bonus rate changes starting in August 2026 and 2028. This helps ensure payslip calculations stay aligned with new rules for low-wage workers and the general fiscal rate.
Original PR description
Starting from August 2026: - The increased fiscal rate for low-wage workers (Volet B) rises from 52.54% to 63% (and to 72% in 2028). - The general fiscal rate (Volet A) rises from 33.14% to 35% starting in 2028. This adds new rule parameters for the fiscal rates and updates computation logic to apply these rates Task-6438319 Forward-Port-Of: odoo/enterprise#126713
Resolved issues and error corrections
Portal users now see their pending signature count decrease after they sign a document. This prevents confusion by ensuring the portal dashboard only counts documents still awaiting action from that specific user.
Original PR description
Version: 18.0 Steps to reproduce: - Create a sign request with two signers. - Assign the first signature to a portal user. - Log in as the portal user and sign the document. Issue: After signing, the to-sign count in the portal does not decrease. This is because the query only checks the overall sign request state instead of the individual signer's item state, so the count remains unchanged Fix: Added an item level state check to the count query so it only counts items that are still pending for that specific user. Task ID: 6412976 Forward-Port-Of: odoo/enterprise#125632
Fixes an error that could occur when users turned the No Follow-Up setting on or off for invoices paid in multiple installments. This keeps the Follow-Up Report usable when some installments are already settled and others remain open.
Original PR description
Steps to Reproduce: 1. Configure Payment Term (Accounting > Configuration > Payment Terms) containing multiple installments. 2. Create a Customer Invoice with this Payment Term. 3. Post the invoice.…
Steps to Reproduce:
1. Configure Payment Term (Accounting > Configuration > Payment Terms) containing multiple installments.
2. Create a Customer Invoice with this Payment Term.
3. Post the invoice.
4. Register a payment and fully reconcile one of the installments.
5. Navigate to the customer's Follow-Up Report (Accounting > Reporting > Partner Ledger > Report: Follow-Up Report).
6. Navigate to remaining open installment/account move line for that invoice.
7. Turn On or Off the No Follow-Up toggle for the invoice.
An error occurs when enabling or disabling the No Follow-Up toggle.
Issue:
Enabling or disabling the No Follow-Up toggle on a remaining open installment in the Follow-Up Report raises a server error when the invoice contains multiple installments and one or more installments are already fully reconciled.
Root Cause:
The Follow-Up Report only loads and sends non-fully reconciled account move lines from the JavaScript side through all_line_ids. In action_toggle_no_followup(), when the selected line belongs to an invoice, the code retrieves all receivable/payable lines of the invoice, including fully reconciled installments:
```
move.line_ids.filtered(
lambda line: line.account_type in ('asset_receivable', 'liability_payable'),
)
```
The method then attempts to map every receivable/payable line to a report line ID using aml_id_to_line_id. Since fully reconciled installments are not present in all_line_ids, they are missing from the mapping dictionary, causing a KeyError when accessing:
`aml_id_to_line_id[line.id]
`
Fix:
Restricted the impacted lines to those present in the report by adding a check that the account move line exists in aml_id_to_line_id before performing the mapping:
```
lambda line: line.account_type in ('asset_receivable', 'liability_payable')
and line.id in aml_id_to_line_id
```
opw-6245448
Forward-Port-Of: odoo/enterprise#126156Timesheets now use each employee's scheduled weekly hours when checking weekly totals, rather than comparing part-time schedules against a full-time reference. This prevents correct timesheets from being incorrectly marked as under target for employees on flexible or reduced schedules.
Original PR description
Root cause: For an employee on a flexible working schedule, the weekly overtime shown in the timesheet grid compares the entered total against the full time equivalent of the schedule instead of its…
Root cause: For an employee on a flexible working schedule, the weekly overtime shown in the timesheet grid compares the entered total against the full time equivalent of the schedule instead of its own weekly hours. The target is sent by _count_daily_working_hours: https://github.com/odoo/enterprise/blob/27f3a05ca8a5ad6e8d4537dac4f613e60931f0cd/timesheet_grid/models/hr_employee.py#L117-L119 It reads full_time_required_hours, but since https://github.com/odoo/odoo/commit/5cb102546ea4370b4fe5e4a4f37cccdc90c263fd this field holds the company full time reference used to compute the work time rate, and the hours the schedule actually expects per week are on hours_per_week. So for a part time schedule at 80% of a 42 hours full time, the grid expects 42 hours instead of 33h36 and the weekly total shows in red with a wrong negative overtime. Fix: In _count_daily_working_hours, send the hours_per_week of the calendar as the weekly target and keep full_time_required_hours as a fallback when it is not set. For a full time schedule both fields hold the same value so nothing changes there. The result key stays the same so the grid renderers need no change. Steps to reproduce: 1. Go to Employees > Configuration > Working Schedules and create a schedule with Schedule Type Flexible, Full Time Equivalent 42:00 and Total 33:36 hours per week 2. Assign this schedule to an employee linked to a user 3. As that user, go to Timesheets > My Timesheets 4. On a past week, log 6:44 on Monday and 6:43 from Tuesday to Friday on a project 5. Check the Time Spent weekly total => the weekly total 33:36 shows in red with a -8:24 overtime while the employee worked exactly the 33h36 expected by the schedule Ticket [link](https://www.odoo.com/odoo/project.task/6352965) opw-6352965
This fixes an issue where Indian payroll fields were calculated and shown in employee change logs even when Belgium was the active localization. The change ensures Indian payroll calculations only apply to Indian employee records, keeping payroll tracking relevant and avoiding confusing chatter entries.
Original PR description
[FIX] l10n_in: fix some l10n_in fields computed for other localizations
Bug reproduction:
1 - in localhost install below modules:
→ l10n_in_hr_payroll,l10n_be_hr_payroll,l10n_be_hr_contract_salary
2 - Select BE, IN localizations, but as active one select Belgium. 3 - Go to employee, Laura.
4 - Change her wage to 8000
5 - In the chatter, you will see some indian fields are tracked.
→ Shouldn't be, Laura is Belgium, only BE fields should be tracked
Bug cause:
1 - In the hr.version of l10n_in_hr_payroll:
→ there isn't enough caution in compute methods for other l18ns.
→ e.g., _l10n_in_get_montly_wage returns self.wage
→ self.wage is 8000 and that function leads to positive computations
Bug solution:
1 - Non-indian versions are carefully handled in compute methods
task-6411960This fix helps Odoo use an existing database shortcut when looking for unreconciled accounting entries tied to known accounts. As a result, bank statement matching and reconciliation-related searches can run more efficiently without changing user workflows.
Original PR description
We have a very efficient index for searching unreconciled lines on known accounts. Let's use it.
```python
_unreconciled_index = models.Index("(account_id, partner_id) WHERE reconciled IS NOT TRUE")
```
Before this change, the query planner didn't recognize the index because of its definition being slightly different wrt the null values.The Shop Floor view now preserves the intended order of work orders after refreshes or filter changes. This prevents confusing reshuffling and keeps production teams seeing work orders ordered by status and scheduled start date.
Original PR description
Records already in cache are intended to be sorted by their position in `recordCacheIds` to preserve the previously computed display order. However, `recordCacheIds` stores database record ids (`resId`), and currently the cache lookup incorrectly uses `id` instead. As a result, every lookup returns `-1`, and could lead to inconsistent ordering. Steps to reproduce: 1. Create several manufacturing orders with work orders assigned to the same work center. 2. Give the work orders different states and scheduled start dates. 3. Open Shop Floor and display that work center. 4. Refresh the view or change a filter so the records are recomputed. It should use `resId` so the previously computed display order remains, which is based on state and scheduled start date. Related: odoo/enterprise#74421 opw-6402233 Forward-Port-Of: odoo/enterprise#125928
7 changes
Resolved issues and error corrections
In ubuntu 26.04 the time zone database contents changed. A couple of timezone names are not available anymore, causing runtime exceptions. This mapping links old with new time zone naming conventions to prevent future (test) breakdown. The mapping WET to Europe/Lisbon is imperfect, and the localizations for the fixed date inside the test did not match. There exists no better nor correct mapping for WET. The mapping to Europe/Lisbon comes from the IANA tzdb-2026c and is official, so it
Original PR description
In ubuntu 26.04 the time zone database contents changed. A couple of timezone names are not available anymore, causing runtime exceptions. This mapping links old with new time zone naming conventions to prevent future (test) breakdown. The mapping WET to Europe/Lisbon is imperfect, and the localizations for the fixed date inside the test did not match. There exists no better nor correct mapping for WET. The mapping to Europe/Lisbon comes from the IANA tzdb-2026c and is official, so it is kept unchanged. The fixed date inside the test is changed to a recent one that aligns the test outcome with expectations: - Offsets match for recent history and future time - Match daylight savings time (DST) observation --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280691
Before this commit, duplicating several projects at once from the list view gave every copy the milestones of all the duplicated projects, because the copy loop assigned the milestones of the whole recordset instead of the ones of the project being copied. Duplicating a single project behaves correctly, which hid the issue. Steps to reproduce: - create two projects with milestones enabled, add a milestone to the first one and two others to the second one - select both projects in the list v
Original PR description
Before this commit, duplicating several projects at once from the list view gave every copy the milestones of all the duplicated projects, because the copy loop assigned the milestones of the whole recordset instead of the ones of the project being copied. Duplicating a single project behaves correctly, which hid the issue. Steps to reproduce: - create two projects with milestones enabled, add a milestone to the first one and two others to the second one - select both projects in the list view and duplicate them Each copy contains the three milestones instead of only the milestones of its original project. Solution: Copy the milestones of the project being duplicated. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
l10n_vn_pos_symbol carries groups='base.group_system,point_of_sale.group_pos_manager', but _prepare_invoice_vals reads it while an ORDINARY salesperson closes an order: _process_saved_order calls _generate_pos_order_invoice as the acting user, with no sudo anywhere on the way. So on a Vietnamese POS with auto-send to SInvoice enabled, a user in point_of_sale.group_pos_user alone hit Access Denied by ACLs for operation: read, model: pos.config, fields: l10n_vn_pos_symbol and the order nev
Original PR description
l10n_vn_pos_symbol carries groups='base.group_system,point_of_sale.group_pos_manager', but _prepare_invoice_vals reads it while an ORDINARY salesperson closes an order: _process_saved_order calls…
l10n_vn_pos_symbol carries groups='base.group_system,point_of_sale.group_pos_manager', but _prepare_invoice_vals reads it while an ORDINARY salesperson closes an order: _process_saved_order calls _generate_pos_order_invoice as the acting user, with no sudo anywhere on the way. So on a Vietnamese POS with auto-send to SInvoice enabled, a user in point_of_sale.group_pos_user alone hit
Access Denied by ACLs for operation: read, model: pos.config, fields: l10n_vn_pos_symbol
and the order never finished syncing - the receipt screen's Done button stayed disabled and the checkout dead-ended.
This is reachable from the module's own test suite, which is what makes it more than theoretical: point_of_sale's start_pos_tour logs in as `pos_user` (group_pos_user, NOT group_pos_manager - that is `pos_admin`), so test_l10n_vn_edi_pos_refund_reason_tour exercises exactly the unprivileged path.
Reading the config as sudo is the right resolution rather than widening the field's groups: the salesperson is never shown the symbol or allowed to change it, it is only stamped onto the invoice their own sale produces, which is what a per-POS configuration field is for. Both symbols are read through the same sudo recordset so the company-level fallback keeps working identically.
Reproduced and verified on v18_full (5-repo addons path):
before - FAILED: [13/36] Tour L10nVnEdiPosRefundReasonTour -> "go to next screen from
receipt"; 1 failed, 0 error(s) of 1 tests
after - tour succeeded for both tours in the class; 0 failed, 0 error(s) of 2 tests,
and no ACL line left in the log
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prSteps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions 3. Create invoice with ar_001 partner 4. Confirm the invoice 5. Try to create credit note → Error: KeyError: 'en_US' Root Cause: The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB di
Original PR description
Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings >…
Steps to Reproduce the Error (Odoo SaaS 19.2):
1. Install l10n_gcc_invoice localization & Accounting
2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions
3. Create invoice with ar_001 partner
4. Confirm the invoice
5. Try to create credit note → Error: KeyError: 'en_US'
Root Cause:
The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB dict directly into cache, bypassing ORM field conversion. When Odoo 19.2's improved ORM conversion runs, it creates nested JSON in narration instead of a flat structure.
Timeline:
- bedf1cb66fbb: Workaround added to prevent T&C duplication in preview
- 75f050b9650d: Root cause fixed in report template (conditional display) → Made _load_narration_translation() redundant
- 4e4156536bc9: Odoo 19.2 improved ORM conversion → Now conflicts with the redundant workaround, causing nested JSON
How It Breaks:
1. Invoice creation: _load_narration_translation() injects raw dict into cache
2. ORM writes: nested JSON stored: {ar_001: {en_US: ., ar_001: Arabic}}
3. Credit note creation: copy_translations() expects flat structure → Crashes: KeyError: 'en_US'
Why It's Safe to Remove:
Report template already prevents T&C duplication (commit 75f050b9650d). Removing the workaround restores proper credit note creation without breaking T&C display.
Changes:
- Remove moves._load_narration_translation() in create()
- Remove out self.filtered('id')._load_narration_translation() in _compute_narration()
opw : 6284943
Forward-Port-Of: odoo/odoo#271037### Steps to reproduce: - Download 'Sales' and 'Timesheets' apps - Create a service product: - Invoicing policy = Based on Delivered Quantity - Track service =Timesheets on tasks - Create and confirm a sale order for quantity 1 - Log 20h on the task. Create Invoice → 20.00. Then, post - On the invoice: Reverse → Partial Refund, set the credit-note quantity to 11.00 - Post credit note → qty_invoiced = 9.00 - Log 5h. Create Invoice → 16.00. Post. (this part was already fixed, see
Original PR description
### Steps to reproduce: - Download 'Sales' and 'Timesheets' apps - Create a service product: - Invoicing policy = Based on Delivered Quantity - Track service =Timesheets on tasks - Create and confirm…
### Steps to reproduce:
- Download 'Sales' and 'Timesheets' apps
- Create a service product:
- Invoicing policy = Based on Delivered Quantity
- Track service =Timesheets on tasks
- Create and confirm a sale order for quantity 1
- Log 20h on the task. Create Invoice → 20.00. Then, post
- On the invoice: Reverse → Partial Refund, set the credit-note quantity to 11.00
- Post credit note → qty_invoiced = 9.00
- Log 5h. Create Invoice → 16.00. Post. (this part was already fixed, see below)
- Log 3h. Create Invoice
> Expected: an invoice for 3.00h — qty_delivered (28) - qty_invoiced (25)
> Actual: a credit note (out_refund) for 6.00h
### Cause of Issue:
A previous [PR](https://github.com/odoo/odoo/pull/268025) fixed a related issue where `_recompute_qty_to_invoice` failed to account for hours already invoiced/refunded when a credit note had been posted against a prior invoice, causing already-invoiced hours to be re-invoiced.
However, that approach relies on invoice *lineage* (which invoice was reversed) rather than on the actual net amount already invoiced.
https://github.com/odoo/odoo/blob/427d398880c381981e088f7001f855a10d1cd581/addons/sale_timesheet/models/sale_order_line.py#L183 This caused the already-resolved refund to be subtracted a second time (3-(20-11) = -6), producing a negative `qty_to_invoice` and, consequently, a credit note instead of an invoice for the newly logged hours.
### Fix:
Replace the lineage-based tracking with a simpler and more efficient way that holds across any number of refund/re-invoice cycles.
In case there are refund moves:
`qty_to_invoice = total_delivered_quantity − net_posted_invoiced_quantity`
`net_posted_invoiced_quantity` is computed directly from all **posted** invoice lines linked to the
SO line, without needing to determine which invoice a given credit note was reversing or whether
its timesheets have since moved to a newer invoice.
And in case of no refunds (less complex flow), we only include the relevant timesheets.
opw-6253650When modifying project_id on a timesheet through mass edit/rpc or anything that is not triggering `onChange`. The task_id would not be reset if it doesnt' belong to the new project set on the timesheet. Steps to reproduce: ------------------- * Install studio for easier reproducing of the issue * Open the timesheet list view * Open studio and activate the mass edit on the view * Modify the project_id on multiple records > Observation: The task_id stays the same even if they do not belon
Original PR description
When modifying project_id on a timesheet through mass edit/rpc or anything that is not triggering `onChange`. The task_id would not be reset if it doesnt' belong to the new project set on the timesheet. Steps to reproduce: ------------------- * Install studio for easier reproducing of the issue * Open the timesheet list view * Open studio and activate the mass edit on the view * Modify the project_id on multiple records > Observation: The task_id stays the same even if they do not belong to the new set project Why the fix: ------------ Instead of relying only on the onChange we add an inverse to the project_id that will reset the task when needed. opw-6259149
Deleting a draft customer invoice linked to timesheets resets their timesheet_invoice_id so the hours become invoiceable again. This write also marks the timesheets' so_line for recompute, and the re-derivation runs while the lines are no longer protected by the invoice link. When the task or project no longer resolves to a sale order item (e.g. it was unlinked after invoicing), the timesheets lose their sale order item or get reassigned to another one, so the delivered hours silently disappear
Original PR description
Deleting a draft customer invoice linked to timesheets resets their timesheet_invoice_id so the hours become invoiceable again. This write also marks the timesheets' so_line for recompute, and the…
Deleting a draft customer invoice linked to timesheets resets their timesheet_invoice_id so the hours become invoiceable again. This write also marks the timesheets' so_line for recompute, and the re-derivation runs while the lines are no longer protected by the invoice link. When the task or project no longer resolves to a sale order item (e.g. it was unlinked after invoicing), the timesheets lose their sale order item or get reassigned to another one, so the delivered hours silently disappear from the original order line. Protect so_line during the write and drop the pending recompute: deleting an invoice must only make the hours invoiceable again, not change their allocation. Steps to reproduce: - Install Sales and Timesheets - Create a service product with invoice policy "Based on Timesheets" and "Create a task in a new project" - Create and confirm a sale order with this product - Log a timesheet on the generated task - Create the invoice (keep it in draft) - Remove the Sales Order Item from the task and from the project settings (or point them to a sale order item of another order) - Delete the draft invoice - Open the timesheet: its Sales Order Item is emptied (or replaced by the other order's item, whose delivered quantity now includes the hours sold on the original order), and the original line's delivered quantity is reset --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279552
4 changes
Resolved issues and error corrections
The selection options for l10n_id_coretax_add_info_07/08 and l10n_id_coretax_facility_info_07 were swapped: the "additional information" fields showed facility stamp text and vice versa. Also add the UoM codes and new kode faktur 07 additional info/facility stamp options published by DJP on 2026-01-26. task-6434742
Original PR description
The selection options for l10n_id_coretax_add_info_07/08 and l10n_id_coretax_facility_info_07 were swapped: the "additional information" fields showed facility stamp text and vice versa. Also add the UoM codes and new kode faktur 07 additional info/facility stamp options published by DJP on 2026-01-26. task-6434742
Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions 3. Create invoice with ar_001 partner 4. Confirm the invoice 5. Try to create credit note → Error: KeyError: 'en_US' Root Cause: The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB di
Original PR description
Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings >…
Steps to Reproduce the Error (Odoo SaaS 19.2):
1. Install l10n_gcc_invoice localization & Accounting
2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions
3. Create invoice with ar_001 partner
4. Confirm the invoice
5. Try to create credit note → Error: KeyError: 'en_US'
Root Cause:
The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB dict directly into cache, bypassing ORM field conversion. When Odoo 19.2's improved ORM conversion runs, it creates nested JSON in narration instead of a flat structure.
Timeline:
- bedf1cb66fbb: Workaround added to prevent T&C duplication in preview
- 75f050b9650d: Root cause fixed in report template (conditional display) → Made _load_narration_translation() redundant
- 4e4156536bc9: Odoo 19.2 improved ORM conversion → Now conflicts with the redundant workaround, causing nested JSON
How It Breaks:
1. Invoice creation: _load_narration_translation() injects raw dict into cache
2. ORM writes: nested JSON stored: {ar_001: {en_US: ., ar_001: Arabic}}
3. Credit note creation: copy_translations() expects flat structure → Crashes: KeyError: 'en_US'
Why It's Safe to Remove:
Report template already prevents T&C duplication (commit 75f050b9650d). Removing the workaround restores proper credit note creation without breaking T&C display.
Changes:
- Remove moves._load_narration_translation() in create()
- Remove out self.filtered('id')._load_narration_translation() in _compute_narration()
opw : 6284943
Forward-Port-Of: odoo/odoo#271037#### Description of the issue: Activity filters using context_today() bucket against the UTC date instead of the user's local date, off by one for part of the day. Partial revert of #265250 (e048bb5), scoped to PyDate: UTC getters are right for PyDateTime, wrong for a calendar day. #### Current behavior before PR: A Perth (UTC+8) user finds an activity due today under "Future Activities" from 00:00 to 08:00 local, while the chatter labels the same activity "Today". #### Desired behavior
Original PR description
#### Description of the issue: Activity filters using context_today() bucket against the UTC date instead of the user's local date, off by one for part of the day. Partial revert of #265250 (e048bb5), scoped to PyDate: UTC getters are right for PyDateTime, wrong for a calendar day. #### Current behavior before PR: A Perth (UTC+8) user finds an activity due today under "Future Activities" from 00:00 to 08:00 local, while the chatter labels the same activity "Today". #### Desired behavior after PR is merged: context_today(), today and current_date return the user's local calendar day, so filters agree with the chatter. PyDateTime and PyTime keep the UTC getters; now and time.strftime() are unchanged. opw-6415985 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Miscellaneous changes
**Problem** Opening a location applies the default filter `qty_available > 0 | virtual_available < 0`. Both fields are computed and non-stored, so each leaf goes through `_search_product_quantity`, which ran `search([])` and evaluated the operator in Python over the whole catalog: - `_compute_quantities_dict` `_read_group`s quants **and** incoming/outgoing moves, even when the searched field only needs quants, each scoped with `product_id IN (all_ids)`. - `_compute_quantities` th
Original PR description
**Problem** Opening a location applies the default filter `qty_available > 0 | virtual_available < 0`. Both fields are computed and non-stored, so each leaf goes through `_search_product_quantity`,…
**Problem**
Opening a location applies the default filter `qty_available > 0 | virtual_available < 0`.
Both fields are computed and non-stored, so each leaf goes through
`_search_product_quantity`, which ran `search([])` and evaluated the operator in
Python over the whole catalog:
- `_compute_quantities_dict` `_read_group`s quants **and** incoming/outgoing moves,
even when the searched field only needs quants, each scoped with
`product_id IN (all_ids)`.
- `_compute_quantities` then materialises every product through the ORM: it zeroes
five fields on each one and loops calling `.update` per product.
- `filtered_domain` iterates the full recordset to evaluate the operator.
Nothing is queried per record, but every step scales with the *total* number of
products, so runtime and (batched prefetch) queries grow with the catalog instead of
with the number of products that actually have stock.
**Solution**
Aggregate the underlying quants/moves once and evaluate the operator per product on
plain dicts:
- Only query what the field needs (`need_quant`/`need_in`/`need_out`); a search on
`qty_available` no longer touches moves.
- No `product_id IN (...)`: the `GROUP BY` only returns products that actually have
quants/moves, bounding the work by stock rather than by catalog size.
- Products with neither quant nor move have an implicit value of 0 and are never
loaded: when 0 satisfies the operator the result is returned as
`id not in <aggregated products that failed>`, otherwise as `id in <matches>`.
- `_compute_quantities` is never called, so no full-catalog ORM materialisation.
The context keys that scope or time-shift the quantity (`lot_id`, `owner_id`,
`package_id`, `from_date`, `to_date`) are applied to the aggregation domains exactly
as `_compute_quantities_dict` does. Like that method's raw aggregates, per-UoM
rounding is ignored, and — as the search already did — kit BoMs are not expanded.
Pre-fix:
| Unique products in location | Search Domain | (Moves=Quants) / Product | Run time | Queries |
|---|---|---|---|---|
| 1,000 | [("virtual_available", ">", 0)] | 1 | 0.15 Seconds | 125 |
| 10,000 | [("virtual_available", ">", 0)] | 1 | 1 Second | 420 |
| 100,000 | [("virtual_available", ">", 0)] | 1 | 10.6 Seconds | 3,400 |
| 100,000 | [("virtual_available", ">", 0)] | 10 | 12.0 Seconds | 3,550 |
| 100,000 | [("virtual_available", ">", 0)] | 50 | 14.5 | 3,700 |
| 500,000 | [("virtual_available", ">", 0)] | 1 | 60.4 Seconds | 17,000 |
| 500,000 | [("incoming_qty", ">", 0)] | 1 | 60.5 Seconds | 17,000 |
| 500,000 | ['or', ("incoming_qty", ">", 0), ("virtual_available", ">", 0)] | 1 | 63 Seconds | 17,170 |
Post-fix:
| Unique products in location | Search Domain | (Moves=Quants) / Product | Run time | Queries |
|---|---|---|---|---|
| 1,000 | [("virtual_available", ">", 0)] | 1 | 0.07 Seconds | 100 |
| 10,000 | [("virtual_available", ">", 0)] | 1 | 0.3 Seconds | 110 |
| 100,000 | [("virtual_available", ">", 0)] | 1 | 2.5 Seconds | 150 |
| 100,000 | [("virtual_available", ">", 0)] | 10 | 3.5 Seconds | 150 |
| 100,000 | [("virtual_available", ">", 0)] | 50 | 4.9 Seconds | 150 |
| 500,000 | [("virtual_available", ">", 0)] | 1 | 6.8 Seconds | 250 |
| 500,000 | [("incoming_qty", ">", 0)] | 1 | 3.2 Seconds | 130 |
| 500,000 | ['or', ("incoming_qty", ">", 0), ("virtual_available", ">", 0)] | 1 | 10.3 Seconds | 315 |
opw-6379459