Daily updates from Odoo
Tuesday, August 4, 2026
36 changes · saas-19.1
Enhancements to existing features
Currently, Peppol product detection relies strictly on barcode or default_code matching, which fails when vendors use their own codes. Accurate product identification is essential before running the predictive model (for taxes/accounts) and is a strict prerequisite for Purchase Orders matching to function correctly. This PR makes the product matching relies on the Vendor Product Code as the first priority ( SellersItemIdentification or StandardItemIdentification or BuyersItemIdentification
Original PR description
Currently, Peppol product detection relies strictly on barcode or default_code matching, which fails when vendors use their own codes. Accurate product identification is essential before running the predictive model (for taxes/accounts) and is a strict prerequisite for Purchase Orders matching to function correctly. This PR makes the product matching relies on the Vendor Product Code as the first priority ( SellersItemIdentification or StandardItemIdentification or BuyersItemIdentification ) task-6171251 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262801
Currently all of our iot boxes are updated on mondays. This PR adds the dynamic selection of the update day of the week based on the rpi serial number. This allows our iot boxes not to be updated all at the same time, reducing the risk of introducing bugs for our clients all at the same time. Related: https://github.com/odoo/odoo/pull/278914
Original PR description
Currently all of our iot boxes are updated on mondays. This PR adds the dynamic selection of the update day of the week based on the rpi serial number. This allows our iot boxes not to be updated all at the same time, reducing the risk of introducing bugs for our clients all at the same time. Related: https://github.com/odoo/odoo/pull/278914
Forward-Port-Of: odoo/odoo#278655
Original PR description
Forward-Port-Of: odoo/odoo#278655
Motivation ---------- Each database served keeps a full registry in a process-wide LRU. The LRU is bounded by a count, so on a server hosting thousands of databases the number of retained registries follows traffic rather than memory pressure. Their combined footprint can push a worker past its virtual-memory soft limit, at which point it is killed and restarted. On a server with ~2500 databases, the soft limit is reached at ~180 resident databases while the LRU could still hold ~210, so HT
Original PR description
Motivation ---------- Each database served keeps a full registry in a process-wide LRU. The LRU is bounded by a count, so on a server hosting thousands of databases the number of retained registries…
Motivation ---------- Each database served keeps a full registry in a process-wide LRU. The LRU is bounded by a count, so on a server hosting thousands of databases the number of retained registries follows traffic rather than memory pressure. Their combined footprint can push a worker past its virtual-memory soft limit, at which point it is killed and restarted. On a server with ~2500 databases, the soft limit is reached at ~180 resident databases while the LRU could still hold ~210, so HTTP workers were being recycled under normal load. Tracking usage -------------- Every request for a registry goes through the single lookup in the registry constructor, which stamps it with a monotonic timestamp; the stamp is also set when a registry is first built. Collecting idle registries -------------------------- A collection pass drops every registry whose last use is older than the configured idle timeout. It runs at the end of registry loading, so it fires periodically as databases come and go. Registries that are still loading are skipped, so a concurrent build is never collected. Dropping a registry only detaches it from the LRU: a request still holding a reference keeps working, and the next lookup rebuilds it. The timeout is read from ODOO_REGISTRY_MAX_IDLE_TIMEOUT, in seconds; a value of zero, the default, disables the mechanism so behaviour is unchanged unless it is opted into. Results ------- With a five-minute timeout on the same ~2500-database server, the HTTP workers settle at around 40 resident registries instead of saturating memory on the long run. The gevent worker, which sees every web client reconnect at startup and briefly fills the LRU with ~150 databases, releases most of them on the first pass, reclaiming the memory. On a real-life SaaS server with 64GB of RAM, that frees up to ~10GB which were previously taken by unused registries in the LRU. It comes at the expense of extra registry recomputes, but on the other hand workers do not reach their virtual memory limit anymore. closes odoo/odoo#276581 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#278236
Resolved issues and error corrections
Payroll reports now calculate default dates consistently using the user's timezone. This prevents late-night automated checks and payroll payment workflows from failing around midnight due to mismatched payment and value dates.
Original PR description
### Steps to reproduce: - Set the environment timezone (`env.tz`) to a timezone ahead of UTC (e.g., Europe/Brussels) - Run the enterprise tests (L10n standalone, Single app, or Multi l10n) during the…
### Steps to reproduce: - Set the environment timezone (`env.tz`) to a timezone ahead of UTC (e.g., Europe/Brussels) - Run the enterprise tests (L10n standalone, Single app, or Multi l10n) during the late evening in UTC (e.g., 23:00 UTC) > UserError: The Payment Date cannot be later than the Value Date, please make sure that the correct dates are set ### Cause of Issue: In the payroll payment report wizards, a race condition occurs around midnight due to mismatched timezone context evaluations between different date fields. The `effective_date` field (defined in the base hr_payroll module) derives its default value using `fields.Date.context_today`, which correctly applies the client's timezone offset to the current server time. https://github.com/odoo/enterprise/blob/54b7035b4cb6b9427092a3eebe73f2bee7f2ae09/hr_payroll/wizard/hr_payroll_payment_report_wizard.py#L23-L26 However, `l10n_sa_wps_value_date` (and similar date fields in other localizations like AU, HK, AE) derives its default value using `fields.Date.today()`, which strictly relies on the server's UTC time. https://github.com/odoo/enterprise/blob/54b7035b4cb6b9427092a3eebe73f2bee7f2ae09/l10n_sa_hr_payroll/wizard/hr_payroll_payment_report_wizard.py#L13-L14 When the nightly Runbot builds execute late at night UTC time, the environment timezone frequently crosses midnight into "tomorrow" while the server time is still on "today". Because of this offset, `effective_date` rolls over to tomorrow, but `l10n_sa_wps_value_date` evaluates as today + 1 day (which is also tomorrow). The validation check `effective_date >= l10n_sa_wps_value_date` evaluates to True. https://github.com/odoo/enterprise/blob/54b7035b4cb6b9427092a3eebe73f2bee7f2ae09/l10n_sa_hr_payroll/wizard/hr_payroll_payment_report_wizard.py#L93-L94 ### Fix: Standardize the default date computations to ensure they are all evaluated within the same timezone context and prevent the midnight timezone rollover discrepancy. runbot-937793
A small typo in the journal report line actions was corrected, and unused date fields were cleaned up. This helps prevent confusing or broken actions when users interact with journal report lines, with no expected change to normal workflows.
Original PR description
Forward-Port-Of: odoo/enterprise#125266
Users can now confirm multiple Brazilian customer invoices using Avalara tax mapping without the process failing. This prevents validation interruptions and supports smoother batch invoice processing.
Original PR description
**_Steps to reproduce:_** * Install `l10n_br_avatax` and configure Avalara Brazil. * Create at least two customer invoices. * Ensure the fiscal position is set to **Automatic Tax Mapping (Avalara…
**_Steps to reproduce:_** * Install `l10n_br_avatax` and configure Avalara Brazil. * Create at least two customer invoices. * Ensure the fiscal position is set to **Automatic Tax Mapping (Avalara Brazil)**. * Select the invoices and click **Action → Confirm Entries**. **_Observed behavior:_** * A traceback is raised with `ValueError: Expected singleton: account.move(...)` and the invoices cannot be validated. **_Cause:_** * During tax extraction, `_extract_tax_values_from_l10n_br_avatax_detail` accesses `self.invoice_filter_type_domain` while `self` may contain multiple `account.move` records. * Accessing `invoice_filter_type_domain` on a multi-recordset raises an `Expected singleton` error, preventing the validation of multiple invoices. **_Fix:_** * Build the returned tax values by iterating over each invoice in the recordset and using the corresponding `invoice_filter_type_domain`. * This ensures `_extract_tax_values_from_l10n_br_avatax_detail` correctly handles multiple invoices during validation without raising a singleton error. opw-6334761 Forward-Port-Of: odoo/enterprise#124993
The Malaysian Statement of Account option now appears only for companies based in Malaysia. This prevents users in other countries from seeing or running a country-specific report that does not apply to them.
Original PR description
### Current behavior: After installing `l10n_my_reports`, the Malaysian's Statement of Account button appears on Aged Receivable for every company, and the partner Action "Print Statement of Account" can be run from non-MY companies ### Expected behavior: To avoid user confusion, it is advised to restrict its visibility so that it is only accessible to Malaysia-specific companies ### Steps to reproduce: 1. Install `l10n_my_reports` 2. Switch to a non-Malaysian company 3. Open Invoicing > Reporting > Aged Receivable 4. Observe the "Statement of Account" button on partner lines ### Cause of the issue: Missing checks for 'MY' company country code in UI and print report action ### Fix: - show the Aged Receivable SoA button only when `company_country_code === 'MY'` - guard `action_print_report_statement_account` for non-MY companies opw-6340854 Forward-Port-Of: odoo/enterprise#126172
Quotations created from repair orders linked to helpdesk tickets now automatically use the salesperson assigned to the customer. This avoids missing salesperson information on sales documents and helps ensure proper sales ownership and follow-up.
Original PR description
Currently, when a quotation is created from a repair order generated from a helpdesk ticket, the salesperson is not set on the quotation even if the customer has a salesperson assigned. **Steps to…
Currently, when a quotation is created from a repair order generated from a helpdesk ticket, the salesperson is not set on the quotation even if the customer has a salesperson assigned. **Steps to Reproduce:** - Install `helpdesk_repair`. - Go to `Helpdesk` > `Configuration` > `Helpdesk Teams`. - Open a team recod and enable `Repairs`. - Create a `contact/customer` with a `salesperson` assigned. - Go to `Helpdesk`, create a ticket for that `customer`, and select the `helpdesk team` configured above. - Click `Repair`, then click `Create Quotation`. - Open the quotation and check the `Salesperson` field in the `Other Info` tab. **Current behavior:** The Salesperson field on the quotation remains empty. **Expected behavior:** The Salesperson field on the quotation should inherit the salesperson assigned to the selected customer/contact. **Cause of the issue:** When a repair order is created from a helpdesk ticket, default_user_id [1] is passed in the context . This value is propagated when creating the repair order [2] . Later, when creating the quotation from the repair order [3], the same context is reused. Because default_user_id is already present in the context, it overrides the precomputation of user_id from the customer. As a result, user_id is initialized with an empty value and remains unset. **Fix:** This commit ensures that default_user_id is removed from the context before creating the sale order. Without a default value for user_id, the field is correctly precomputed from the selected customer, and the salesperson is properly assigned. [1]- https://github.com/odoo/enterprise/blob/2662932c7ac8ebf3ed5a05d44d7ebfaff869fcbd/helpdesk_repair/models/helpdesk_ticket.py#L52 [2]- https://github.com/odoo/enterprise/blob/2662932c7ac8ebf3ed5a05d44d7ebfaff869fcbd/helpdesk_repair/models/helpdesk_ticket.py#L36-L40 [3]: https://github.com/odoo/odoo/blob/29328b8fccff833c14de317b51f3b4e5a8c40f75/addons/repair/models/repair.py#L357 opw-6344939 Forward-Port-Of: odoo/enterprise#126310 Forward-Port-Of: odoo/enterprise#122980
The Planning app now applies employee and material filtering correctly for open shifts only. This prevents assigned shifts from being incorrectly included or excluded, helping planners find the right shifts and resources more reliably.
Original PR description
Before this commit, the domain wrongly assumes that we always search on shifts having no role or a role containing resources of types 'user' or 'material' (1). Additionally to the basic domain which searches on the shifts having resources of types 'user' or 'material' (2). After this commit, we add a condition on domain (1) to only apply it for open shifts (shifts having no resource_id). no-task Forward-Port-Of: odoo/enterprise#126247
The Helpdesk unanswered ticket filter no longer treats automatic acknowledgement emails as customer replies needing a response. This helps support teams focus on genuinely unanswered customer messages and avoid misleading ticket queues.
Original PR description
Steps to reproduce: --------- - install website_helpdesk - set an email address on the company partner if it is empty ( it is empty in a database without demo data). - generate a ticket from the website. - apply the Unanswered filter. Issue: ------ system generated acknowledgement message is considered an unanswered customer reply. Fix: -------- system generated acknowledgement messages are now considered answered. task-5138678
Users who open a bank statement line from an in-app notification will now see the related discussion panel. This ensures tagged users can immediately view and respond to comments in the expected place, improving collaboration during bank reconciliation.
Original PR description
Problem: When navigating to a bank statement line through a notification, the chatter doesn't appear. Steps to reproduce: 1. Set in app notifications for one of the users 2. Open Accounting > Bank > To Reconcile 3. Select any bank statement line 4. Tag the user from step 1 in a comment 5. Log in as that user 6. Check notifications and click the new notification 7. Notice how the chatter does not appear on the bank statement line after navigating there Cause: The chatter was not enabled on the bank statement line form view. opw-6410186
Fixed how Indian reporting classifies POS and other non-purchase transactions. This helps ensure existing and future reports compare the right locations and avoid incorrect transaction type results.
Original PR description
Description: In #118297 non-sales journal moves were considered purchase moves during l10n_in_transaction_type computation, which is not correct for POS moves as their journal is of type 'general'. Fix: Compare only the purchase journal moves state against the partner state. Other moves treated as sales and their state compared against the company state. Add a migration script to update existing databases. opw-638646 Forward-Port-Of: odoo/enterprise#125697
Restaurant orders using the German Fiskaly POS setup now appear on the kitchen display as soon as the first product is added. This prevents kitchen staff from missing newly created orders and avoids delays caused by orders only appearing after a second item is added.
Original PR description
**Step To Reproduce:** 1. Configure a POS with German Fiskaly (l10n_de_pos_cert), Restaurant, and Kitchen Display (pos_preparation_display). 2. Create a new order in the POS and add the first…
**Step To Reproduce:** 1. Configure a POS with German Fiskaly (l10n_de_pos_cert), Restaurant, and Kitchen Display (pos_preparation_display). 2. Create a new order in the POS and add the first product. 3. Observe that the order does not appear on the Kitchen Display. 4. Add a second product to the same order. 5. Observe that the order now appears on the Kitchen Display. **Issue:** The first product of a new restaurant order is not synchronised with the Kitchen Display when the German Fiskaly localisation is enabled. **Reason:** `syncAllOrders()` only processes orders returned by `getPendingOrder()` and ignores orders explicitly passed through `options.orders`. After the initial Fiskaly synchronisation, the order is serialised and removed from the pending queue. Consequently, the Preparation Display synchronisation receives no orders from `getPendingOrder()`, preventing the order from reaching the backend. **Solution:** Update `syncAllOrders()` to prioritize the orders explicitly provided through `options.orders`. When `options.orders` is not available, fall back to the existing behavior by synchronizing the orders from `orderToCreate` and `orderToUpdate`. opw-6321376 Forward-Port-Of: odoo/enterprise#125743
User-facing messages and warnings now show translated selection-field values instead of untranslated internal labels. This improves clarity for users working in different languages across accounting, payroll, recruitment, appointments, IoT, point of sale, and localization workflows.
Original PR description
The `selection` attribute of `fields.Selection` is not generally translated (unless it is a function instead of a list). For user facing strings, we generally need to translate the value displayed. Forward-Port-Of: odoo/enterprise#126538
Click and collect rental orders now check availability against the customer’s selected warehouse instead of all warehouses. This prevents customers from being blocked incorrectly when stock is available at the chosen pickup location.
Original PR description
When using the click & collect option, the available qty for renting was not taking the selected warehouse into account. Steps to reproduce: ------------------- * Create 2 different warehouses with 2…
When using the click & collect option, the available qty for renting was not taking the selected warehouse into account. Steps to reproduce: ------------------- * Create 2 different warehouses with 2 different adresses * Create a product available for renting * Setup the product to use serial numbers * Create 2 serial number, 1 in each warehouse * Activate the click & collect option on the website * Create a first sale order to collect in warehouse 1 * In the backend, confirm the order and pick it up * Go back to the website and make a second order for the second warehouse > Observation: When clicking on the "Add to cart" you get an error saying that there is no quantity available Why the fix: ------------ When computing the `product_rented_quantities` it would look for `sale.order.line` in all the warehouse. So it would find the line from the first order even if it's not linked to the selected warehouse. So we just add a new element to the domain to filter out the incorrect warehouses. opw-6328475 Forward-Port-Of: odoo/enterprise#124969
Problem: When testing the import of contacts with a user without accounting access rights, the test fails and leads to an error. Steps to reproduce: 1- Remove accounting access rights from your user (Set Accounting to No) 2- Open Contacts app 3- Try importing contacts (you can download the available template and use it as the file you are asked to upload) 4- Test the import 5- Notice the error you receive Cause: When importing contacts, the commercial fields (fields related to the co
Original PR description
Problem: When testing the import of contacts with a user without accounting access rights, the test fails and leads to an error. Steps to reproduce: 1- Remove accounting access rights from your user…
Problem: When testing the import of contacts with a user without accounting access rights, the test fails and leads to an error. Steps to reproduce: 1- Remove accounting access rights from your user (Set Accounting to No) 2- Open Contacts app 3- Try importing contacts (you can download the available template and use it as the file you are asked to upload) 4- Test the import 5- Notice the error you receive Cause: When importing contacts, the commercial fields (fields related to the contact's parent) are loaded and then written. Some of these fields may have access rights that the user trying to import doesn't have. As a result, when trying to load/write them, the user may get an error. Solution: Use sudo() when loading them. This shouldn't be an issue since they are only copied from the parent. Also, sudo() is already being used when writing the values, https://github.com/odoo/odoo/blob/bb94f13b38f0bf1ce8886f4630ad42caf6c56325/odoo/addons/base/models/res_partner.py#L996 so sudo() should also be used when loading them. opw-6396086 Forward-Port-Of: odoo/odoo#278638
PoS loads product categories from both the PoS configuration and the preparation printers. Before this commit, if a child category was included in the PoS configuration, but its parent was only included in a preparation printer, the parent category was loaded in the frontend without being visible. As a result, the child category was also hidden, even though its products were still available. How to reproduce: - Create a parent category. - Create a child category containing a product. -
Original PR description
PoS loads product categories from both the PoS configuration and the preparation printers. Before this commit, if a child category was included in the PoS configuration, but its parent was only included in a preparation printer, the parent category was loaded in the frontend without being visible. As a result, the child category was also hidden, even though its products were still available. How to reproduce: - Create a parent category. - Create a child category containing a product. - Limit the PoS categories to the child category. - Create a preparation printer and assign the parent category to it. - Open the PoS. - The products are available, but the child category is not visible. opw-6381119 Forward-Port-Of: odoo/odoo#276782
### Steps to reproduce the issue: 1. Download Accounting and l10n_de 2. Set VAT number for DE company and another company you will use for the invoice 3. Switch to german language 4. Create an invoice and send it 5. Download the PDF and upload it on www.portinvoice.com 6. See the following error: the PDF metadata incorrectly states the conformance level as "ERWEITERT" (German), which directly clashes with the correct "EXTENDED" (English) profile declared inside the embedded XML file. ##
Original PR description
### Steps to reproduce the issue: 1. Download Accounting and l10n_de 2. Set VAT number for DE company and another company you will use for the invoice 3. Switch to german language 4. Create an invoice and send it 5. Download the PDF and upload it on www.portinvoice.com 6. See the following error: the PDF metadata incorrectly states the conformance level as "ERWEITERT" (German), which directly clashes with the correct "EXTENDED" (English) profile declared inside the embedded XML file. ### Cause of the issue: Issue comes from this commit 9396790e9cc1ce1c6e5c29b71b5629b31fb16458 where it has been forgotten to disable the translation. ### Reason to introduce the fix: Meet the requirements of the electronic invoice. opw-6023971 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273042
Use "VAT" instead of "TAX" for the default UK tax groups. Also set "Subtotal" as their preceding subtotal label so that it replaces "Untaxed Amount". task-[6413495](https://www.odoo.com/odoo/project/967/tasks/6413495) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279865 Forward-Port-Of: odoo/odoo#278351
Original PR description
Use "VAT" instead of "TAX" for the default UK tax groups. Also set "Subtotal" as their preceding subtotal label so that it replaces "Untaxed Amount". task-[6413495](https://www.odoo.com/odoo/project/967/tasks/6413495) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279865 Forward-Port-Of: odoo/odoo#278351
…F fetch Nilvera PDF retrieval (the manual "Get PDF" action and the scheduled "retrieve sale PDFs" cron) hardcoded the "Sale" document category. That is correct for e-invoices (/einvoice/Sale/{uuid}/pdf) but wrong for e-archive documents, whose resource is "Invoices". For e-archive invoices it produced GET /earchive/Sale/{uuid}/pdf, which Nilvera answers with 404, surfacing to the user as "Odoo could not perform this action at the moment... Not Found - 404" and making the cron raise on every
Original PR description
…F fetch
Nilvera PDF retrieval (the manual "Get PDF" action and the scheduled "retrieve sale PDFs" cron) hardcoded the "Sale" document category. That is correct for e-invoices (/einvoice/Sale/{uuid}/pdf) but wrong for e-archive documents, whose resource is "Invoices". For e-archive invoices it produced GET /earchive/Sale/{uuid}/pdf, which Nilvera answers with 404, surfacing to the user as "Odoo could not perform this action at the moment... Not Found - 404" and making the cron raise on every run.
Derive the document category from the invoice channel so e-archive resolves to /earchive/invoices/{uuid}/pdf while e-invoice keeps using /einvoice/sale/{uuid}/pdf.
OPW-6311661
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#278796**Description of the issue/feature this PR addresses:** When adding a product with an analytic distribution to a Sales Order that is already linked to a project, the product's analytic distribution is not automatically applied to the order line. This occurs due to a previous commit that attempted to protect manually entered analytic distributions from being overwritten when an SO is confirmed and a project is generated. To do this, the old code filtered out any non-empty project lines and
Original PR description
**Description of the issue/feature this PR addresses:** When adding a product with an analytic distribution to a Sales Order that is already linked to a project, the product's analytic distribution…
**Description of the issue/feature this PR addresses:** When adding a product with an analytic distribution to a Sales Order that is already linked to a project, the product's analytic distribution is not automatically applied to the order line. This occurs due to a previous commit that attempted to protect manually entered analytic distributions from being overwritten when an SO is confirmed and a project is generated. To do this, the old code filtered out any non-empty project lines and bypassed calling `super()` on them. Consequently, if a line already had an analytic distribution (such as inheriting the project's), the system would skip computing the product's specific distribution rules entirely. This commit resolves the issue by reverting that change, ensuring the base compute method is always called so product-based rules execute correctly. While this means manual analytic entries added before the compute trigger might be overwritten, there is no perfect solution to prevent losing both manual and product distributions. As concluded with the Product Owner in a similar PR for Purchase Orders, we prioritize keeping the product's automated distribution, as it is much harder to manually reconstruct after its removal. The corresponding test is also reverted to its original state to reflect this expected behavior. A small test is added to ensure that the analytic distribution results are unchanged when adding a project to the SO. opw-6279406 **Steps to Reproduce:** - Accounting > Configuration > Settings > Analytics > enable Analytic Accounting - Accounting > Configuration > Analytic Accounting > Analytic Distribution Models - Create a new model with any product (e.g. “Bolt”) and any Analytic Distribution (e.g. “Production”) - Create SO, enable “Analytic Distribution” in filters - Add any customer, add the above product (e.g. “Bolt”), save - Observe that the “Production” Analytic Distribution is automatically populated - On the same SO > Other Info> Project > add (e.g. “Home Construction”) - Then go back to Order Lines and remove the previous SOL and create a new one with the same product > save - Observe that the “Production” Analytic Distribution is not added (although “Home Construction” is) **Current behavior before PR:** - Product analytic distributions are not automatically applied when the Sales Order is already linked to a project **Desired behavior after PR is merged:** - Product analytic distributions are automatically applied even when the Sales Order is linked to a project **Note:** This commit basically ports a fix/revert (https://github.com/odoo/odoo/commit/54852978617cfb2d8c5afdcf80adbf6c0605093c) introduced to the project_purchase module for the same issue. Their commit message is quite detailed in explaining the issue. To quote: >However, due to the agency of the code, we cannot prevent losing *both* manually added analytic distributions and product analytic distribution. After consulting the product owner, we concluded that there was no perfect solution in this case, but we'd rather keep the product analytic distribution, as it is much harder to add it again after its removal. Therefore, this commit reverts the previously mentioned commit, while keeping the refactor it introduced. The referenced initial commit is here: https://github.com/odoo/odoo/commit/3dfa98bd3b9d5ababe3a7548d604e22350023799 Forward-Port-Of: odoo/odoo#274893
When running `ŧest_free_reservation`, it could happen on very rare occasions that both moves would be created at a different second. In such cases, the test would fail. Since we want to test the case with *exact* same dates, we can't use `assertAlmostEqual` which is usually better for dates. Instead, we freeze the time for the duration of the creation / assignation. runbot-944453 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of:
Original PR description
When running `ŧest_free_reservation`, it could happen on very rare occasions that both moves would be created at a different second. In such cases, the test would fail. Since we want to test the case with *exact* same dates, we can't use `assertAlmostEqual` which is usually better for dates. Instead, we freeze the time for the duration of the creation / assignation. runbot-944453 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279565 Forward-Port-Of: odoo/odoo#278103
Before this commit, the down payments line of the project profitability panel had no drill down action for salespersons and billing users without accounting access, because the group references were written with a trailing comma inside the XML id, making the two checks silently fail for everyone. Only the accounting read group check, written correctly, was effective. Steps to reproduce: - create a service product with "Create on Order: Project & Task", sell it on a sale order and confirm it
Original PR description
Before this commit, the down payments line of the project profitability panel had no drill down action for salespersons and billing users without accounting access, because the group references were…
Before this commit, the down payments line of the project profitability panel had no drill down action for salespersons and billing users without accounting access, because the group references were written with a trailing comma inside the XML id, making the two checks silently fail for everyone. Only the accounting read group check, written correctly, was effective. Steps to reproduce: - create a service product with "Create on Order: Project & Task", sell it on a sale order and confirm it - create a down payment invoice from the sale order and post it - create a user with Sales "User: All Documents" access, Project "User" access and no accounting access - as that user, open the dashboard of the generated project and look at the Down Payments line of the profitability panel The Down Payments amount is displayed as plain text, while a user with accounting access can click it to open the related invoices, as intended for the salesperson too. Solution: Move the commas out of the group references. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278521
The test for `hr_leave_attendance_report` failed Runbot's faketime tests for two reasons: * The report's view use SQL's reserved syntax `CURRENT_DATE` which always resolves to real system clock, and ignores Odoo's faketime mechanism. * The three tests used hardcoded dates. Since the report is exclusively concerned with the window of last 13 months. Faking the time in a future date further than this led to wrong results. This commit fixes both issues by: 1. Using `now()::date`
Original PR description
The test for `hr_leave_attendance_report` failed Runbot's faketime tests for two reasons: * The report's view use SQL's reserved syntax `CURRENT_DATE` which always resolves to real system clock, and ignores Odoo's faketime mechanism. * The three tests used hardcoded dates. Since the report is exclusively concerned with the window of last 13 months. Faking the time in a future date further than this led to wrong results. This commit fixes both issues by: 1. Using `now()::date` in the view instead of `CURRENT_DATE`. 2. Replacing the hardcoded dates in the tests by dates computed relative to `fields.Date.today()`. Runbot Errors: [1](https://runbot.odoo.com/odoo/runbot.build.error/944585), [2](https://runbot.odoo.com/odoo/runbot.build.error/944585/runbot.build.error/runbot.build.error/944584) Forward-Port-Of: odoo/odoo#279337
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#279843 Forward-Port-Of: odoo/odoo#257823
**Description of the issue/feature this PR addresses:** `test_search_date_category` is failing across runbot builds Remove the blanket deletion of all repair orders at the start of test_search_date_category and replace the exact count assertion with assertIn. This avoids interfering with other test data and makes the test resilient to pre-existing records in the database. **Current behavior before PR:** ``` ERROR: TestRepair.test_search_date_category Traceback (most recent call last):
Original PR description
**Description of the issue/feature this PR addresses:** `test_search_date_category` is failing across runbot builds Remove the blanket deletion of all repair orders at the start of…
**Description of the issue/feature this PR addresses:**
`test_search_date_category` is failing across runbot builds
Remove the blanket deletion of all repair orders at the start of test_search_date_category and replace the exact count assertion with assertIn. This avoids interfering with other test data and makes the test resilient to pre-existing records in the database.
**Current behavior before PR:**
```
ERROR: TestRepair.test_search_date_category
Traceback (most recent call last):
File "/data/build/odoo/addons/repair/tests/test_repair.py", line 915, in test_search_date_category
self.env['repair.order'].search([]).unlink()
File "/data/build/odoo/addons/rating/models/mail_thread.py", line 21, in unlink
result = super().unlink()
^^^^^^^^^^^^^^^^
File "/data/build/odoo/addons/mail/models/mail_thread.py", line 391, in unlink
res = super(MailThread, self).unlink()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/build/odoo/addons/mail/models/models.py", line 46, in unlink
result = super().unlink()
^^^^^^^^^^^^^^^^
File "/data/build/odoo/odoo/orm/models.py", line 4131, in unlink
func(self)
File "/data/build/odoo/addons/repair/models/repair.py", line 421, in _unlink_except_confirmed
repairs_to_cancel.action_repair_cancel()
File "/data/build/enterprise/quality_repair/models/repair.py", line 114, in action_repair_cancel
res = super().action_repair_cancel()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/build/odoo/addons/repair/models/repair.py", line 475, in action_repair_cancel
raise UserError(_("You cannot cancel a Repair Order that's already been completed"))
odoo.exceptions.UserError: You cannot cancel a Repair Order that's already been completed
```
**Desired behavior after PR is merged:**
`test_search_date_category` passes
opw-[4998413](https://www.odoo.com/odoo/my-tasks/4998413)
runbot.build.error-[231146](https://runbot.odoo.com/odoo/runbot.build.error/231146)
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#267852**Steps to reproduce:** 1. Install Sales app and open any sale order 2. In the "Terms and conditions" text area at the bottom, apply the "/Switch direction" command for an empty block **Issue:** The feature doesn't work when you apply it on an empty line **Why this happens:** Before the fix, the switch-direction logic depended on selected text nodes, and effectively ignored empty content nodes. **Fix:** The problem has been fixed in 19.4 as an [IMP] in this commit 9c97fc464ffba5088
Original PR description
**Steps to reproduce:** 1. Install Sales app and open any sale order 2. In the "Terms and conditions" text area at the bottom, apply the "/Switch direction" command for an empty block **Issue:** The feature doesn't work when you apply it on an empty line **Why this happens:** Before the fix, the switch-direction logic depended on selected text nodes, and effectively ignored empty content nodes. **Fix:** The problem has been fixed in 19.4 as an [IMP] in this commit 9c97fc464ffba5088642d7699b3e033c1fcc2564, so this is essentially a backport for that fix. opw-6344750 Forward-Port-Of: odoo/odoo#279887 Forward-Port-Of: odoo/odoo#276536
Ensure combo prices are computed in the backend. Forward-Port-Of: odoo/odoo#279652
Original PR description
Ensure combo prices are computed in the backend. Forward-Port-Of: odoo/odoo#279652
Purpose of this PR: - On double click, opening the toolbar is delayed by 300ms to prevent flickering before a potential triple click. - However, mouseup was re-enabling selection tracking (onSelectionChangeActive = true) before the 300ms delay finished. Because browser selectionchange events are dispatched asynchronously after mouseup, they triggered updateToolbar() immediately, bypassing the 300ms delay. - This fix re-enables selection tracking only after the 300ms debounced update actuall
Original PR description
Purpose of this PR: - On double click, opening the toolbar is delayed by 300ms to prevent flickering before a potential triple click. - However, mouseup was re-enabling selection tracking (onSelectionChangeActive = true) before the 300ms delay finished. Because browser selectionchange events are dispatched asynchronously after mouseup, they triggered updateToolbar() immediately, bypassing the 300ms delay. - This fix re-enables selection tracking only after the 300ms debounced update actually finishes. runbot-941543 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279826 Forward-Port-Of: odoo/odoo#278025
Steps to reproduce: 1. Install Calendar 2. Create a meeting in Calendar in form view 3. Set the video link on it 4. Turn on the debug mode 5. Now, clear the video link Issue: - Traceback ``` Uncaught Promise > Invalid props for component 'CopyButton': 'content' is not a string or object or function ``` Cause: - The 'CopyButton' component expect content to be a string, object or function but receives false. It does not happen in previous versions because in the refector https:/
Original PR description
Steps to reproduce: 1. Install Calendar 2. Create a meeting in Calendar in form view 3. Set the video link on it 4. Turn on the debug mode 5. Now, clear the video link Issue: - Traceback ``` Uncaught…
Steps to reproduce: 1. Install Calendar 2. Create a meeting in Calendar in form view 3. Set the video link on it 4. Turn on the debug mode 5. Now, clear the video link Issue: - Traceback ``` Uncaught Promise > Invalid props for component 'CopyButton': 'content' is not a string or object or function ``` Cause: - The 'CopyButton' component expect content to be a string, object or function but receives false. It does not happen in previous versions because in the refector https://github.com/odoo/odoo/commit/c2f34517b2f9832a498981d0fa17ec39b9739cb6 set the `videocall_location` to false instead of empty string like before https://github.com/odoo/odoo/blob/499420f7062ab467ff6f50b30c547e54c35ae1e9/addons/web/static/src/core/copy_button/copy_button.js#L14 - but any field using the `CopyClipboardChar/CopyClipboardURL` widget passes its raw field value straight through as content. An empty char/text field is represented as false, so whenever such a field becomes empty, CopyClipboardField hands `false` to CopyButton, which fails prop validation (debug mode). Solution: - Fix it at the source: CopyClipboardField's template now falls back to an empty string when the field value is falsy, so CopyButton never receives false but a valid string. opw-6360936 Forward-Port-Of: odoo/odoo#275236
The `selection` attribute of `fields.Selection` is not generally translated (unless it is a function instead of a list). For user facing strings, we generally need to translate the value displayed. 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#280094
Original PR description
The `selection` attribute of `fields.Selection` is not generally translated (unless it is a function instead of a list). For user facing strings, we generally need to translate the value displayed. 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#280094
Before this commit, test_01_invite_by_email_flow could fail right after a tour that succeeded, on a loaded runbot: ``` AssertionError: res.partner(2417,) not found in res.partner(2416,) ``` This happens because the tour ends on the click on "Invite to Group Chat", which only starts the add_members and invite_by_email calls. The test closes the browser and reads the channel members right after, so under load the calls never reach the server. Note that the tour did wait for the invite p
Original PR description
Before this commit, test_01_invite_by_email_flow could fail right after a tour that succeeded, on a loaded runbot: ``` AssertionError: res.partner(2417,) not found in res.partner(2416,) ``` This happens because the tour ends on the click on "Invite to Group Chat", which only starts the add_members and invite_by_email calls. The test closes the browser and reads the channel members right after, so under load the calls never reach the server. Note that the tour did wait for the invite panel to close, until that panel became a dialog: the step waited for any panel to be gone, and the member list stays open. This commit waits for the invited member in the member list and for the dialog to close, which only happens once both calls are done. https://runbot.odoo.com/odoo/error/944291
The fw-ports of https://github.com/odoo/odoo/pull/269465 incorrectly use _get_peppol_error_message, which is depreciated from 19.0 and even removed in subsequent versions (at least 19.4 and master). It now uses the correct get_peppol_error_message static method. Forward-Port-Of: odoo/odoo#278057
Original PR description
The fw-ports of https://github.com/odoo/odoo/pull/269465 incorrectly use _get_peppol_error_message, which is depreciated from 19.0 and even removed in subsequent versions (at least 19.4 and master). It now uses the correct get_peppol_error_message static method. Forward-Port-Of: odoo/odoo#278057
Miscellaneous changes
This is in preparation for forcefully recommending the use of `execute_query` and `SQL` as early as 19.0. While `execute_query` is the primary recommendation, `execute(SQL(...))` is an OK alternative, but static checking limitations mean queries constructed in function calls, or callers (that includes the implementation of `execute_query` itself), or using conditionals, will be flagged. In that case the easiest pattern is execute(SQL("%s", query)) which we do not want to penalize overl
Original PR description
This is in preparation for forcefully recommending the use of `execute_query` and `SQL` as early as 19.0. While `execute_query` is the primary recommendation, `execute(SQL(...))` is an OK alternative, but static checking limitations mean queries constructed in function calls, or callers (that includes the implementation of `execute_query` itself), or using conditionals, will be flagged. In that case the easiest pattern is
execute(SQL("%s", query))
which we do not want to penalize overly.
- Add fast path for `SQL("%s", arg: SQL)`.
- Improve fast-path for `SQL(SQL())` to do ~nothing when possible.
- Allow overriding `to_flush` in both case, fix site which needs that
- Update type dispatches to check for `Iterable` instead of `__iter__`. this both helps type checkers and is actually correct.
Forward-Port-Of: odoo/odoo#258930**Steps to reproduce:** - Install Survey app - Create a survey - Share as e-mail - Add some text in the body/subject - Modify recipients - The added text is automatically reset **Issue:** Behavior was previously introduced to match the content of the composer body/subject to the recipient language. If there was only one language among the recipients it automatically adapted the template and changed the rendered language (which also refreshed the content). This logic was trigge
Original PR description
**Steps to reproduce:** - Install Survey app - Create a survey - Share as e-mail - Add some text in the body/subject - Modify recipients - The added text is automatically reset **Issue:** Behavior…
**Steps to reproduce:** - Install Survey app - Create a survey - Share as e-mail - Add some text in the body/subject - Modify recipients - The added text is automatically reset **Issue:** Behavior was previously introduced to match the content of the composer body/subject to the recipient language. If there was only one language among the recipients it automatically adapted the template and changed the rendered language (which also refreshed the content). This logic was triggered by a depends on `partner_ids` and triggered the compute on every recipient changes which led to the subject/body reset. **Fix:** Revert commit: https://github.com/odoo/odoo/commit/b7bbb7b21f4848323666230b518cad9459726f67 in 18.0+ Also adapt commit: https://github.com/odoo/odoo/commit/c6f19e89cb6019e7dbaadbc7427fbb6ddd5661ed to avoid mixed language in resulting mail when the composer was modified We could also try to prevent the compute when the subject or body is already modified instead of removing its logic. opw-6020245 Forward-Port-Of: odoo/odoo#279669 Forward-Port-Of: odoo/odoo#254090