Daily updates from Odoo
Wednesday, August 12, 2026
28 changes · saas-19.1
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#281424 Forward-Port-Of: odoo/odoo#279940
This commit adds a "Reload Data" button to the traceback dialog for PWA applications. When clicked, the user is asked to confirm the action. Once confirmed, all locally stored browser data is cleared, allowing the POS to recover from errors caused by corrupted or outdated local data. task-6388234 Forward-Port-Of: odoo/odoo#276559
Original PR description
This commit adds a "Reload Data" button to the traceback dialog for PWA applications. When clicked, the user is asked to confirm the action. Once confirmed, all locally stored browser data is cleared, allowing the POS to recover from errors caused by corrupted or outdated local data. task-6388234 Forward-Port-Of: odoo/odoo#276559
Resolved issues and error corrections
This fix prevents an error during delivery processing when a product is changed into a kit after a transfer has already been confirmed. It ensures the Kenya OSCU stock integration uses the correct updated delivery records, helping deliveries complete reliably without unexpected interruptions.
Original PR description
When a stock move's product is turned into a kit after the transfer was confirmed, it explodes it into its component moves and unlinks the original one: https://github.com/odoo/odoo/blob/f59783d43f891fea14d03f67d7c017d7ffbbe5a7/addons/mrp/models/stock_move.py#L358-L363 https://github.com/odoo/odoo/blob/f59783d43f891fea14d03f67d7c017d7ffbbe5a7/addons/mrp/models/stock_move.py#L400 The `_action_done()` override of `l10n_ke_edi_oscu` localisation called `super()` first and then used `self.filtered(...)` on the pre-explosion recordset, which could still reference the now-deleted move, raising a `MissingError`: https://github.com/odoo/enterprise/blob/ee7e6894ed313db844aeff5ba5e19de3ad94898e/l10n_ke_edi_oscu_stock/models/stock_move.py#L96-L99 Use the `super()` return value instead, which reflects the moves that were actually processed. runbot-243291 Forward-Port-Of: odoo/enterprise#127027
Refunding Ecuador POS orders made with the “Consumidor Final” customer now shows the intended warning instead of crashing. This helps cashiers understand why the refund cannot be validated and avoids an unexpected interruption at checkout.
Original PR description
When attempting to refund orders that were created with the "Consumidor Final" customer. The refund validation would crash with a TypeError instead of showing the proper error message. Steps to…
When attempting to refund orders that were created with the "Consumidor Final" customer. The refund validation would crash with a TypeError instead of showing the proper error message. Steps to reproduce: ------------------- In POS with l10n_ec_edi module activated: * Create a new order with "Consumidor Final" as customer * Add products and pay the order * Validate the order * Attempt to refund this order > Observation: The refund validation would crash with: TypeError: Cannot read properties of undefined (reading 'add') at OrderPaymentValidation.isOrderValid Why the fix: ------------ The code was trying to access `this.dialog` which is undefined in the OrderPaymentValidation class context. The dialog service should be accessed via `this.pos.dialog`, which is the correct pattern used throughout the base OrderPaymentValidation class. This fix ensures the error dialog is properly displayed when attempting to refund orders for the anonymous final consumer, instead of crashing with a TypeError. opw-6427113 Forward-Port-Of: odoo/enterprise#126308
This fix corrects how leave intervals are adjusted in the Gantt view for employees using duration-based work schedules. It helps ensure planned absences display with the right timing, reducing confusion for HR teams and managers.
Original PR description
task-id: 6460078 Forward-Port-Of: odoo/enterprise#127487
Swiss payroll no longer assigns a Swiss-specific contract type to employees when the company context is not Switzerland. This prevents automated workflow failures and helps keep employee contract information aligned with the correct country settings.
Original PR description
[FIX] l10n_ch: fix default contract type This task is runbot error fix that occured from 19.0 to 19.2 Bug reproduction: 1 - Go to version 19.0, install l10n_ch_hr_payroll_account 2 - Execute…
[FIX] l10n_ch: fix default contract type
This task is runbot error fix that occured from 19.0 to 19.2
Bug reproduction:
1 - Go to version 19.0, install l10n_ch_hr_payroll_account 2 - Execute test_version_timeline_auto_save_tour tour test 3 - It fails in .o_arrow_button_wrapper[data-tooltip^='Contract:'] step
Bug cause:
1 - When l10n_ch_hr_payroll_account is installed:
1.1 - contract type becomes "Permanent contract with monthly salary"
1.2 - the employee is not swiss but it has this CH contract type
2 - data-tooltip starts with Permanent contract instead of contract
2.1 - Tour fails
3 - contract_type_id is overwritten in swiss modules
3.1 - Default is assigned without looking to the country of self.env
Bug solution:
1 - If the country is not swiss, the default is assigned as False
1.1 -> fixed in l10n_ch_hr_payroll/hr_version
1.2 instead of assigning swiss contract type to the non-swiss emp.
Note: This is fix from saas-18.4 to master.
task-6392040
runbot error: https://runbot.odoo.com/odoo/runbot.build.error/941358
Forward-Port-Of: odoo/enterprise#126520This fix corrects an internal module dependency for the Belgian point of sale black box setup with HR features. It helps ensure the right related module is installed and avoids configuration or automated test failures caused by the previous dependency mismatch.
Original PR description
Before this commit, the dependency of the module l10n_be_pos_blackbox_hr_pos_blackbox_be was set to pos_hr, which is not totally correct. The correct dependency should be l10n_be_pos_blackbox_hr. runbot-error: 941561 Forward-Port-Of: odoo/enterprise#124814
This fixes an issue where unused leave could be missed when processing payslips for multiple employees at once. Each payslip now uses the correct employee’s leave allocations, helping ensure Australian payroll amounts are calculated accurately.
Original PR description
`_l10n_au_get_unused_leave_by_type` compared leave allocations to `self.employee_id` while looping payslips. On a multi-recordset that is the whole employee set, so the match never holds and unused leave is skipped. Use `payslip.employee_id` so each payslip keeps its own allocations. task-6458480 Forward-Port-Of: odoo/enterprise#127330
Fixes an issue where using AI to update website SEO could fail when the AI agent relied on certain document-generated files, such as invoice PDFs. The AI feature can now correctly use those document sources, reducing interruptions for users optimizing website content.
Original PR description
### Problem When an AI agent includes a document source whose underlying `ir.attachment` has `res_field` set (e.g., an invoice PDF generated from a Sale Order), triggering **Update With AI** from…
### Problem
When an AI agent includes a document source whose underlying `ir.attachment`
has `res_field` set (e.g., an invoice PDF generated from a Sale Order),
triggering **Update With AI** from **Website → Site → Optimize SEO**
raises a `KeyError` in `_build_rag_context`.
### Steps to Reproduce
1. Open the **AI** app.
2. Configure the **Odoo Agent**.
3. Add a source → **Add From Documents**.
4. Select a document whose underlying `ir.attachment` has `res_field` set
(e.g., an invoice PDF generated from a Sale Order).
5. Go to **Website → Site → Optimize SEO**.
6. Click **Update With AI**.
7. Observe the following error:
```
KeyError: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
```
[Video](https://drive.google.com/file/d/1AAg0AvC3TRQzMLhI9hWFuSarOTHzQE-b/view?usp=sharing)
### Root Cause
In `ai/models/ai_agent.py`, `_build_rag_context()` retrieves the
`ai.agent.source` records corresponding to the embeddings by searching on the
attachment checksum:
```python
agent_sources = self.env["ai.agent.source"].search([
("attachment_id.checksum", "in", embeddings_attachment_checksums),
("agent_id", "=", self.id),
])
```
This domain traverses `attachment_id.checksum`, which internally calls
`ir.attachment._search()`.
As part of the standard attachment search behavior,
`ir.attachment._search()` automatically injects a
`('res_field', '=', False)` filter unless:
- `skip_res_field_check=True` is set in the context,
- the domain explicitly references `id` or `res_field`, or
- `bypass_access` is enabled.
```python
domain = Domain(domain)
if (
not self.env.context.get("skip_res_field_check")
and not any(d.field_expr in ("id", "res_field") for d in domain.iter_conditions())
and not bypass_access
):
disable_binary_fields_attachments = True
domain &= Domain("res_field", "=", False)
```
[Reference](https://github.com/odoo/odoo/blob/19.0/odoo/addons/base/models/ir_attachment.py#L630)
Because of this implicit filter, attachments with `res_field` set are excluded
from the search. Consequently, `agent_sources` does not contain all the sources
corresponding to the retrieved embeddings.
Later, `_build_rag_context()` builds a checksum-to-source mapping:
```python
source_map = {
source.attachment_id.checksum: source
for source in agent_sources
}
for embedding in similar_embeddings:
checksum = embedding.attachment_id.checksum
agent_source = source_map[checksum]
```
Since `source_map` is built from the incomplete `agent_sources` recordset, it is
missing entries for attachments filtered by `ir.attachment._search()`.
However, `similar_embeddings` still contains embeddings for those attachments.
As a result, the lookup:
```python
agent_source = source_map[checksum]
```
raises a `KeyError`.
### Solution
Bypass the implicit `res_field` filter when searching `ai.agent.source`:
```python
agent_sources = (
self.env["ai.agent.source"]
.with_context(skip_res_field_check=True)
.search([
("attachment_id.checksum", "in", embeddings_attachment_checksums),
("agent_id", "=", self.id),
])
)
```
This ensures that all `ai.agent.source` records matching the requested
attachment checksums are returned, including those referencing attachments with
`res_field` set. As a result, `source_map` contains all expected entries and
`_build_rag_context()` no longer raises a `KeyError`.
opw-6379816French VAT reimbursement declaration 3519 now includes the bank account holder name in the account details section. This helps meet declaration requirements and reduces the risk of rejected or incomplete reimbursement submissions.
Original PR description
For reimbursement declarations, the name of the holder of the account is required This commits adds holder's name to the account data zone no-task-id Forward-Port-Of: odoo/enterprise#127631 Forward-Port-Of: odoo/enterprise#127554
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 Forward-Port-Of: odoo/odoo#281096
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 Forward-Port-Of: odoo/odoo#281096
task-id: 6460078 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281502
Original PR description
task-id: 6460078 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281502
**Setup** * Increase the debounce time of `debouncedSynchronizeLocalDataInIndexedDB` to **5 seconds** to reproduce the issue deterministically. * Configure a restaurant with **Self Ordering** enabled (`QR Menu + Ordering`). * Configure **Mollie** as the **only** online payment method. **Reproduction** 1. Place a **takeout** order through the mobile menu. 2. Select a pickup time, enter the required customer information (including a mobile number), and proceed to the payment page. 3.
Original PR description
**Setup** * Increase the debounce time of `debouncedSynchronizeLocalDataInIndexedDB` to **5 seconds** to reproduce the issue deterministically. * Configure a restaurant with **Self Ordering** enabled…
**Setup** * Increase the debounce time of `debouncedSynchronizeLocalDataInIndexedDB` to **5 seconds** to reproduce the issue deterministically. * Configure a restaurant with **Self Ordering** enabled (`QR Menu + Ordering`). * Configure **Mollie** as the **only** online payment method. **Reproduction** 1. Place a **takeout** order through the mobile menu. 2. Select a pickup time, enter the required customer information (including a mobile number), and proceed to the payment page. 3. Verify from the backend that the draft order contains the expected data (customer/partner and `preset_time`). 4. Press the browser **Back** button to return from the payment page. 5. Check the draft order in the backend again. [video](https://drive.google.com/file/d/1kNWpYuo79mYMV3eMelwJ5IDFeWUc7zsD/view) **Observed result** * The draft order loses its previously synced information. In particular, the **partner/customer** data (and other synced fields such as `preset_time`) are removed. **Expected result** * Returning from the payment page should not modify the draft order. All previously synced data should remain intact. **Cause** - When there's only a single payment method, it's [auto-selected](https://github.com/odoo/odoo/blob/161715c850496d3683baa5d1600380470d0b5ff5/addons/pos_self_order/static/src/app/pages/payment_page/payment_page.js#L21-L22) and `checkAndOpenPaymentPage` immediately opens the payment page via[ window.open()](https://github.com/odoo/odoo/blob/161715c850496d3683baa5d1600380470d0b5ff5/addons/pos_online_payment_self_order/static/src/app/pages/payment_page/payment_page.js#L35). - The order's local data is saved to IndexedDB on a 300ms debounce. If the redirect fires before that debounce completes, the save is cancelled, leaving IndexedDB out of sync with the in-memory order **Fix** - Before opening the payment URL, explicitly flush the order to IndexedDB using the `synchronizeLocalDataInIndexedDB`, ensuring the local data is persisted before the page navigates away. opw-6231478 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272724
An old refactor left some data around that are in conflict with other records for the same model. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281276
Original PR description
An old refactor left some data around that are in conflict with other records for the same model. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281276
Before this commit, the default einvoice format was changed only when the partner was french and had a vat number, but we want to ease that condition and do it only if the partner is french. task-6303174 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278158 Forward-Port-Of: odoo/odoo#270720
Original PR description
Before this commit, the default einvoice format was changed only when the partner was french and had a vat number, but we want to ease that condition and do it only if the partner is french. task-6303174 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278158 Forward-Port-Of: odoo/odoo#270720
Before this commit, some layouts had the customer address on the right (light, boxed, bold, striped) and some had it on the left (bubble, wave, folder). For the latter, when an information_block with the address existed, it would be inserted before the address pushing it further right. This was inconsistent since the address position should not depend on whether an information_block is present or not. The customer address must stay in a fixed place to match the transparent window of the
Original PR description
Before this commit, some layouts had the customer address on the right (light, boxed, bold, striped) and some had it on the left (bubble, wave, folder). For the latter, when an information_block with…
Before this commit, some layouts had the customer address on the right (light, boxed, bold, striped) and some had it on the left (bubble, wave, folder). For the latter, when an information_block with the address existed, it would be inserted before the address pushing it further right. This was inconsistent since the address position should not depend on whether an information_block is present or not. The customer address must stay in a fixed place to match the transparent window of the envelope when sending a physical letter by snailmail. This commit fixes this issue by ensuring that in all cases the customer address position stays fixed regardless of the presence or absence of the information_block and regardless of the layout used for the letter. It also fixes the addresses displayed on the sale order report: 1) If invoicing address = partner address != shipping address or invoicing address != partner address = shipping address then the three addresses would be printed, even though 2 addresses are identical. 2) The shipping address and the invoicing address are now printed horizontally rather than vertically to get rid of the resulting large blank block under the partner address in that case. backport of: https://github.com/odoo/odoo/pull/276622 task-6340467 Forward-Port-Of: odoo/odoo#273640
Making sure that during the race condition between the save triggered by closing the widget and the one triggered by the ’ NEED_LOCAL_CHANGES’ bus doesn’t lead to the re-opening of the widget itself and subsequently the list mass edit pop up.
Original PR description
Making sure that during the race condition between the save triggered by closing the widget and the one triggered by the ’ NEED_LOCAL_CHANGES’ bus doesn’t lead to the re-opening of the widget itself and subsequently the list mass edit pop up.
In saas-19.1, `purchase_cdnur_regular` was renamed to `purchase_cdnur_overseas`. However, commit https://github.com/odoo/odoo/commit/c4b0911e061ff0619bd3d6a411701fc898dad258 still used the old section name. This commit updates `purchase_cdnur_regular` to `purchase_cdnur_overseas`.
Original PR description
In saas-19.1, `purchase_cdnur_regular` was renamed to `purchase_cdnur_overseas`. However, commit https://github.com/odoo/odoo/commit/c4b0911e061ff0619bd3d6a411701fc898dad258 still used the old section name. This commit updates `purchase_cdnur_regular` to `purchase_cdnur_overseas`.
### Issue before this commit: Before commit f2965048f60fe6c815b3e50fa714c97a93dfb5d3, company_type allowed manually selecting whether a contact was an individual or a company. After the commit, is_company became a stored computed field derived from the VAT number, with no manual override available in the standard UI, and no exception was added for Spanish DNI/NIE formats. ### Steps to reproduce the issue: 1. Download Accounting and l10n_es 2. Set as VAT of ES company 47857909S (or similar
Original PR description
### Issue before this commit: Before commit f2965048f60fe6c815b3e50fa714c97a93dfb5d3, company_type allowed manually selecting whether a contact was an individual or a company. After the commit,…
### Issue before this commit: Before commit f2965048f60fe6c815b3e50fa714c97a93dfb5d3, company_type allowed manually selecting whether a contact was an individual or a company. After the commit, is_company became a stored computed field derived from the VAT number, with no manual override available in the standard UI, and no exception was added for Spanish DNI/NIE formats. ### Steps to reproduce the issue: 1. Download Accounting and l10n_es 2. Set as VAT of ES company 47857909S (or similar but must be a DNI or NIE format) 3. Create an invoice for a Spanish customer 4. Send the invoice with Facturae 5. Check the XML created and see that the tag <PersonTypeCode> of <SellerParty> has a J (legal entity) rather than an F (individual) ### Cause of the issue: The Spanish localization's _compute_is_company override only adds the check for CIF-formatted VAT numbers (for [legal entities](https://sede.agenciatributaria.gob.es/Sede/ayuda/manuales-videos-folletos/manuales-practicos/guia-practica-cumplimentacion-modelo-censal-036/anexos/anexo-01-solicitud-nif-documentacion-aportar/informacion-sobre-numero-identificacion-fiscal/composicion-nif/personas-juridicas-entidades.html)) but it has no corresponding negative check for DNI or NIE formats (for [standalone individuals](https://sede.agenciatributaria.gob.es/Sede/ayuda/manuales-videos-folletos/manuales-practicos/guia-practica-cumplimentacion-modelo-censal-036/anexos/anexo-01-solicitud-nif-documentacion-aportar/informacion-sobre-numero-identificacion-fiscal/composicion-nif/personas-fisicas.html)). Here the [rules](https://factuo.es/herramientas/verificador-nif) for regex. https://github.com/odoo/odoo/blob/f014e0b7bc3ce56a9931e81339a4f8327a400422/addons/l10n_es/models/res_partner.py#L39-L51 As a result, any standalone partner with a valid non-void VAT inherits is_company = True from the base computation. https://github.com/odoo/odoo/blob/f014e0b7bc3ce56a9931e81339a4f8327a400422/odoo/addons/base/models/res_partner.py#L824-L833 ### Reason to introduce the fix: The Facturae 3.2.2 export directly derives PersonTypeCode (F/J) and the LegalEntity/Individual XML structure from partner.is_company. Since a self-employed individual (autónomo) is required to use their personal DNI/NIE as NIF and is their own commercial partner, the current logic misclassifies them as a legal entity (J), producing a Facturae invoice with an incorrect PersonTypeCode and structure. Explicitly setting is_company = False for DNI/NIE-formatted Spanish VAT numbers restores the ability to correctly represent individual entrepreneurs in Facturae exports. opw-6396314 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Automatically update the ruff config to the latest version generated on runbot
Original PR description
Automatically update the ruff config to the latest version generated on runbot
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-pr
Forward-Port-Of: odoo/odoo#281621
Forward-Port-Of: odoo/odoo#281119Before this commit, a call test where a participant card appears while in a call fails with: Unimplemented server route: /mail/rtc/channel/upgrade_connection The client sends that request a few seconds later, so only a test still running by then fails, as `Adjust view: switching between Tiled and Spotlight` does on master under load. This happens because the other participants of a test call are only records, so their peer connection negotiates no transceiver, and asking it to downl
Original PR description
Before this commit, a call test where a participant card appears while in a call fails with:
Unimplemented server route: /mail/rtc/channel/upgrade_connection
The client sends that request a few seconds later, so only a test still running by then fails, as `Adjust view: switching between Tiled and Spotlight` does on master under load.
This happens because the other participants of a test call are only records, so their peer connection negotiates no transceiver, and asking it to download the video of the card schedules a connection recovery instead. Recovering without a TURN server, which a test never has, asks the server to move the call to an SFU with that route, and the mock server implements join_call and leave_call only.
This commit registers the route with an empty handler, as no test has an SFU server to join.
Forward-Port-Of: odoo/odoo#281736Steps to reproduce the bug: - Install a localization that overrides invoice_policy defaults for storable products without an explicit company_id (e.g. l10n_ke_edi_oscu_stock, which forces 'delivery' in that case) - Run TestSaleMRPAngloSaxonValuation.test_sale_mrp_kit_bom_cogs (sale_mrp) or TestAngloSaxonValuation.test_anglo_saxon_cogs_partial_down_payment_credit_note (sale_stock) Problem: These tests create their products without setting invoice_policy explicitly, relying on the field's im
Original PR description
Steps to reproduce the bug: - Install a localization that overrides invoice_policy defaults for storable products without an explicit company_id (e.g. l10n_ke_edi_oscu_stock, which forces 'delivery'…
Steps to reproduce the bug: - Install a localization that overrides invoice_policy defaults for storable products without an explicit company_id (e.g. l10n_ke_edi_oscu_stock, which forces 'delivery' in that case) - Run TestSaleMRPAngloSaxonValuation.test_sale_mrp_kit_bom_cogs (sale_mrp) or TestAngloSaxonValuation.test_anglo_saxon_cogs_partial_down_payment_credit_note (sale_stock) Problem: These tests create their products without setting invoice_policy explicitly, relying on the field's implicit default. l10n_ke_edi_oscu_stock's _compute_invoice_policy (https://github.com/odoo/enterprise/blob/4e459417dac809caafea34aa2e487fc3c1f0ce1a/l10n_ke_edi_oscu_stock/models/product.py#L16-L21) forces invoice_policy to 'delivery' for any storable product whose company_id is not set, which is the case for products created in these test fixtures. Once invoice_policy becomes 'delivery', invoiced quantities are driven by qty_delivered instead of the ordered quantity, which the affected tests never account for (some deliver an arbitrary quantity instead of the exact BoM demand, others never validate a delivery at all), causing wrong COGS amounts or wrongly invoiced quantities as soon as such a localization is installed alongside these modules. Solution: Pin invoice_policy to 'order' explicitly wherever these test fixtures create their products, so the test outcome no longer depends on which other modules happen to be installed. runbot-243633 Forward-Port-Of: odoo/odoo#279277 Forward-Port-Of: odoo/odoo#278346
Before this commit, the Chat action of the meeting view could keep its unread dot instead of showing "1" after "Mark as Unread": FAILED: [14/21] Tour discuss.meeting_view_tour Step .o-mail-Meeting [title='Chat']:has(.badge:contains(1)). Element (.o-mail-Meeting [title='Chat']:has(.badge:contains(1))) has not been found. TIMEOUT step failed to complete within 10000 ms. This happens because a mark as read carries the id of the newest message the client knew when it re
Original PR description
Before this commit, the Chat action of the meeting view could keep its unread dot instead of showing "1" after "Mark as Unread": FAILED: [14/21] Tour discuss.meeting_view_tour Step .o-mail-Meeting…
Before this commit, the Chat action of the meeting view could keep its unread dot instead of showing "1" after "Mark as Unread":
FAILED: [14/21] Tour discuss.meeting_view_tour
Step .o-mail-Meeting [title='Chat']:has(.badge:contains(1)).
Element (.o-mail-Meeting [title='Chat']:has(.badge:contains(1)))
has not been found.
TIMEOUT step failed to complete within 10000 ms.
This happens because a mark as read carries the id of the newest message the client knew when it requested it, and under load it can reach the server after a newer message was posted. The new message separator then moves back before that message, which makes it unread before the user even asks for it. The click on "Mark as Unread" writes the separator the counter is already computed from, so the counter does not change, and the client, which holds the counter it displays while the user reads the thread, never refreshes it.
This commit moves the new message separator forward only, so reading messages never makes another one unread.
https://runbot.odoo.com/odoo/error/945958During the backport we discovered a programming error in `_get_peppol_document_params`. The super function can return `None` values for both `edi_user` and `document`. This can lead to a traceback when the variables are used. We do not have any known issues in 18.0 or higher versions. (Probably because the move send was heavily refactored.) But better safe than sorry. It could maybe happen with the batch sending or in case the "surrounding" logic is refactored in the future. task-None
Original PR description
During the backport we discovered a programming error in `_get_peppol_document_params`. The super function can return `None` values for both `edi_user` and `document`. This can lead to a traceback when the variables are used. We do not have any known issues in 18.0 or higher versions. (Probably because the move send was heavily refactored.) But better safe than sorry. It could maybe happen with the batch sending or in case the "surrounding" logic is refactored in the future. task-None Forward-Port-Of: odoo/odoo#279317
Before this commit, the html composer variant of "Opening thread with needaction messages should mark all messages of thread as read" failed at random on runbot: 11. [verifySteps] expected the following steps > Expected: [ "mark-all-messages-as-read", ] > Received: [] This happens because the channel of that variant holds no message, so the test goes to the inbox before the channel is loaded and it keeps scrollUnread set. Opening the channel again then loads its m
Original PR description
Before this commit, the html composer variant of "Opening thread with needaction messages should mark all messages of thread as read" failed at random on runbot: 11. [verifySteps] expected the…
Before this commit, the html composer variant of "Opening thread with needaction messages should mark all messages of thread as read" failed at random on runbot:
11. [verifySteps] expected the following steps
> Expected: [
"mark-all-messages-as-read",
]
> Received: []
This happens because the channel of that variant holds no message, so the test goes to the inbox before the channel is loaded and it keeps scrollUnread set. Opening the channel again then loads its messages around the 0 separator, and that fetch calls set_message_done, which marks the needaction message as read and leaves nothing for mark_all_as_read to mark.
This commit fixes the issue by giving the channel two messages, pointing the separator at the first one and waiting for their display: loading messages around the separator is skipped when that message is already loaded, so opening the channel again fetches nothing, which the closing assertion checks as well.
The text composer variant gets the same fixture, so that both variants read as master does, from commit 8cd330e3e2d5b1d857d3effb80aa8176d60b38f9. It does not fail: it already waits for a message of its own, and a fetch around its non-zero separator leaves the messages alone in the mock.
https://runbot.odoo.com/odoo/error/945744
Forward-Port-Of: odoo/odoo#281714**ISSUE** When running` _cron_migrate_local_to_cloud_storage` manually,` cron._trigger` is called, which schedules the cron to be triggered later by a worker. To check whether the cron is being run manually or not, we check if there is a request. In SaaS, staging, and duplicate databases, the request is only truthy when the cron is run manually and falsy when run by a worker. In a SH production database, however, the request is truthy both when run manually and when run by a worker due to a spe
Original PR description
**ISSUE** When running` _cron_migrate_local_to_cloud_storage` manually,` cron._trigger` is called, which schedules the cron to be triggered later by a worker. To check whether the cron is being run manually or not, we check if there is a request. In SaaS, staging, and duplicate databases, the request is only truthy when the cron is run manually and falsy when run by a worker. In a SH production database, however, the request is truthy both when run manually and when run by a worker due to a specific cron worker configuration in that environment. As a result,` cron._trigger `is called infinitely and nothing gets uploaded to the cloud. **FIX** Instead of calling `cron._trigger()` to reschedule the job, `limit_time_real` is used when `request` is truthy, and `limit_time_real_cron` otherwise. opw-6330674 Forward-Port-Of: odoo/odoo#279581
Miscellaneous changes
- Compute the standard durations for all French leaves in a single `_get_durations()` call instead of recomputing them for each leave. - Reuse the precomputed duration mapping while calculating the French legal duration for each leave. - Keep the existing French-specific duration calculation unchanged, including public holidays, company calendar, date extension, and half-day handling. This avoids repeated ORM computations when processing multiple French leaves in a batch an
Original PR description
- Compute the standard durations for all French leaves in a single `_get_durations()` call instead of recomputing them for each leave. - Reuse the precomputed duration mapping while calculating the…
- Compute the standard durations for all French leaves in a single `_get_durations()` call instead of recomputing them for each leave. - Reuse the precomputed duration mapping while calculating the French legal duration for each leave. - Keep the existing French-specific duration calculation unchanged, including public holidays, company calendar, date extension, and half-day handling. This avoids repeated ORM computations when processing multiple French leaves in a batch and significantly improves the performance of leave duration computation. Performance testing was performed using the `hr.leave.employee.report` introduced in 19.1, which calls `_get_durations()` on a large batch of virtual leaves. Performance testing on a database containing 677 leaves, including 298 French leaves: | Metric | Before | After | |------------------------------------|-----------------|-------------| | Standard duration computations | 298 | 1 | | Total `_get_durations()` | >169s (timeout) | ~24s | not specific to the employee report and benefits any caller that invokes _get_durations() on a larger batch. **opw-6421323** --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281165