Daily updates from Odoo
Thursday, August 6, 2026
61 changes · saas-19.3
Enhancements to existing features
Bank synchronization now recognizes a new type of temporary error from Odoofin without marking the bank connection as failed. This helps avoid unnecessary disruption for users when an issue does not require stopping the connection.
Original PR description
Odoofin now sends a 'non_blocking_error' error response to indicate that the state on account.online.link shouldn't be set to error. In this commit, we start using it. Task ID: 6358809 Forward-Port-Of: odoo/enterprise#126737 Forward-Port-Of: odoo/enterprise#123287
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
Comply with new provincial fiscal transparency regulations (CABA, Entre Ríos, Chubut, and other provinces still not defined) that mandate detailing Perception IIBB taxes on B2C invoices (Factura/Invoice B): - Some jurisdictions mandate a new description for IIBB perception taxes on the invoice, - We need to put the IIBB perception taxes in the special "Fiscal Transparency Regime" table, and exclude them from the standard tax table, task-6367087 Forward-Port-Of: odoo/odoo#278729 Forwar
Original PR description
Comply with new provincial fiscal transparency regulations (CABA, Entre Ríos, Chubut, and other provinces still not defined) that mandate detailing Perception IIBB taxes on B2C invoices (Factura/Invoice B): - Some jurisdictions mandate a new description for IIBB perception taxes on the invoice, - We need to put the IIBB perception taxes in the special "Fiscal Transparency Regime" table, and exclude them from the standard tax table, task-6367087 Forward-Port-Of: odoo/odoo#278729 Forward-Port-Of: odoo/odoo#277673
The decorator `no_retry` can be used on any objects and just sets a flag. When checking if we should retry a test, let's also check the value on the class. This was broken by 2423b460526e9e7dd9ea8a7b3f7e40c93ab708f5. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280641
Original PR description
The decorator `no_retry` can be used on any objects and just sets a flag. When checking if we should retry a test, let's also check the value on the class. This was broken by 2423b460526e9e7dd9ea8a7b3f7e40c93ab708f5. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280641
The feature was never merged on IAP/Internal's side and we now have a new task to move the setting up of the auto-refill from the local db to the IAP server, so the feature is no longer relevant on the client side. Task-6397951 Forward-Port-Of: odoo/odoo#277512
Original PR description
The feature was never merged on IAP/Internal's side and we now have a new task to move the setting up of the auto-refill from the local db to the IAP server, so the feature is no longer relevant on the client side. Task-6397951 Forward-Port-Of: odoo/odoo#277512
This commit adds 3 new `Tax Exemption Reason Code`: - VATEX-FR-F - VATEX-FR-I - VATEX-FR-J task-6333649 Forward-Port-Of: odoo/odoo#280537 Forward-Port-Of: odoo/odoo#278086
Original PR description
This commit adds 3 new `Tax Exemption Reason Code`: - VATEX-FR-F - VATEX-FR-I - VATEX-FR-J task-6333649 Forward-Port-Of: odoo/odoo#280537 Forward-Port-Of: odoo/odoo#278086
Resolved issues and error corrections
The Barcode app welcome screen now correctly shows the instruction to scan a package when package tracking is enabled. This helps warehouse users find transfers by package without missing expected guidance on the landing page.
Original PR description
When packages are enabled, the barcode scanner welcome screen does not display the instructions for scanning a package. ## Steps to reproduce - Enable `Packages` in Inventory settings. - Open the Barcode application. - Observe the instructions listed on the welcome/landing page. - Notice that the instruction `Scan a package to find a transfer` is missing, even though packages are enabled. ## Issue The MainMenu component has a getter barcodeHomeHelper that checks this.packageEnabled to construct the barcode scanner helper bullet points. However, during setup, the configuration value was incorrectly assigned to this.packagesEnabled. ## Fix Correct the variable name typo in the main menu setup so that the package related instructions are correctly displayed when packaging is enabled. [^1] [^1]:  Forward-Port-Of: odoo/enterprise#124658
Replacing a Sign document now keeps multiple signature fields assigned to the same signer instead of splitting them into separate signers. This prevents confusion and extra manual cleanup when updating documents that are already configured for signing.
Original PR description
### Description of the issue/feature this PR addresses: This PR fixes an issue in the Sign module where replacing a document breaks the link between a signer and their multiple signature fields,…
### Description of the issue/feature this PR addresses: This PR fixes an issue in the Sign module where replacing a document breaks the link between a signer and their multiple signature fields, causing Odoo to erroneously generate separate signers for each individual field. ### Current behavior before PR: When a document with multiple signature fields assigned to the same person is replaced, the _copy_sign_items_to function duplicates the sign.item records. During this duplication process, Odoo duplicates the old responsible_ids, creating copies with new ids. These new copies overwrite the old responsible_ids, ensuring that the newly created sign_items have entirely new responsible_ids. Because a shared responsible_id is the primary key Odoo uses to group multiple signature items under a single signer, this change in ID causes the system to lose the grouping. As a result, Odoo treats each copied field as belonging to a completely new, separate signer. _Note_: Because of the limitation mentioned before, any responsible_id that is passed through the copy function, and thereby the copy_data function, is overwritten with new ids. The only work-around then is to update the responsible_id value attached to the new_sign_item after the copy_data function has completed and the new_sign_item has been created. ### Desired behavior after PR is merged: The original responsible_id is explicitly carried over and assigned to the newly copied sign.item immediately after the copy operation completes. This ensures the copied signature fields retain their original role IDs and grouping, keeping them correctly assigned to the single original signer. opw-6354334 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/enterprise#123628
This fixes a payroll ADP test setup issue that could fail when optional attendance-related apps were not installed. The change keeps the test compatible across different installation setups, improving reliability of automated validation without changing user-facing payroll behavior.
Original PR description
Steps to reproduce the bug: - Install l10n_us_hr_payroll_adp without hr_attendance/hr_holidays_attendance - Run the test suite (runbot build 941182) - TestL10nUsHrPayrollADPExport.setUpClass fails…
Steps to reproduce the bug: - Install l10n_us_hr_payroll_adp without hr_attendance/hr_holidays_attendance - Run the test suite (runbot build 941182) - TestL10nUsHrPayrollADPExport.setUpClass fails Problem: setUpClass raised `ValueError: Invalid field 'overtime_deductible' in 'hr.work.entry.type'` when writing on the overtime work entry type. The field overtime_deductible is only defined by hr_holidays_attendance https://github.com/odoo/odoo/blob/saas-19.2/addons/hr_holidays_attendance/models/hr_work_entry_type.py#L10-L12 which depends on hr_attendance and auto-installs only when hr_attendance is present. l10n_us_hr_payroll_adp's dependency chain (l10n_us_hr_payroll -> hr_payroll) never pulls in hr_attendance, so the field doesn't always exist in the test's registry. However, when hr_holidays_attendance IS installed (e.g. on the full runbot build), the field must still be set to False: leaving it at its default causes hr.leave.create() to run hr_holidays_attendance's _check_overtime_deductible(), which raises "The employee does not have enough extra hours to request this leave." for the overtime leaves created further down in setUpClass, since the test employees have no recorded attendance/overtime hours. Solution: Only include overtime_deductible in the write() vals when the field exists on hr.work.entry.type, keeping it disabled either way. runbot-941182 Forward-Port-Of: odoo/enterprise#126491
Commission reports now use simpler internal row identifiers instead of more complex text-based IDs. This reduces unnecessary complexity in the sales commission reporting logic without changing what users see in the report.
Original PR description
Unlike achievement report ids, commission report ids do not need to identify source records. ROW_NUMBER() is enough to identify the grouped rows and avoids using string ids.
Peruvian electronic invoices now calculate down payment amounts consistently when withholding tax is involved. This prevents mismatched XML totals and avoids referencing cancelled down payment invoices, reducing the risk of rejected or incorrect electronic documents.
Original PR description
### Issue: When an invoice has a down payment on a line with a withholding tax, the `PrepaidPayment/PaidAmount` in the UBL XML included the withholding tax amount, causing a mismatch with…
### Issue: When an invoice has a down payment on a line with a withholding tax, the `PrepaidPayment/PaidAmount` in the UBL XML included the withholding tax amount, causing a mismatch with `LegalMonetaryTotal/PrepaidAmount` which correctly excludes it ### Cause: `PrepaidPayment/PaidAmount` was set directly from `prepayment_move.amount_total`, which includes all taxes `LegalMonetaryTotal/PrepaidAmount` uses `_aggregate_base_line_tax_details` to exclude withholding taxes, but this was not applied to the `PrepaidPayment` node ### Fix: Using `prepayment_move.amount_total` directly includes all taxes and does not match the rounding logic of `LegalMonetaryTotal` Instead, `_aggregate_base_line_tax_details` is used with the same `total_grouping_function` as `LegalMonetaryTotal`, ensuring both nodes use the same rounding logic and exclude withholding taxes Reversed down payment moves are also excluded from `AdditionalDocumentReference` to avoid referencing cancelled invoices ### Steps to reproduce: - Install `l10n_pe_edi` and `sale_management` with demo data - Switch to the PE company - Create and confirm a Sale Order (Customer: PE Company, Product: Any, Unit Price: 200, Taxes: VAT 18% and 3% IGV Withholding) - Create, confirm and pay a Down Payment Invoice (Fixed: 28.92) - Go back to the SO and create the Regular Invoice - Confirm it and click Process Now - Open the EDI Document tab and download the XML Before the fix, the sum of `PrepaidPayment/PaidAmount` did not match `LegalMonetaryTotal/PrepaidAmount` opw-6273903 Forward-Port-Of: odoo/enterprise#126776 Forward-Port-Of: odoo/enterprise#121733
Click and collect rental orders now check availability only in the warehouse selected by the customer. This prevents items stored in one pickup location from incorrectly blocking rentals from another location, reducing false out-of-stock errors.
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#126545 Forward-Port-Of: odoo/enterprise#124969
Appointment cancellation emails are now sent in the language of the customer who booked the appointment, instead of defaulting to the staff member's language. This makes cancellation messages consistent with booking confirmations and reduces customer confusion for multilingual businesses.
Original PR description
**Problem:** When an appointment is cancelled, the cancellation email is always sent in the organizer's (staff member's) language, ignoring the booking customer's language. The booking confirmation,…
**Problem:**
When an appointment is cancelled, the cancellation email is always sent in the organizer's (staff member's) language, ignoring the booking customer's language. The booking confirmation, by contrast, is correctly localized.
**Steps to reproduce:**
1. Set a contact's language to a non-default one (e.g. Romanian).
2. Book an appointment for that contact (they are the booker/attendee).
3. Cancel the appointment.
4. The customer received the confirmation in Romanian but the cancellation email arrives in English.
**Current behavior:**
The cancellation email is rendered in the organizer's language.
**Expected behavior:**
The cancellation email is rendered in the booking customer's language, like the confirmation/invitation email.
**Cause of the issue:**
The cancellation uses `appointment_canceled_mail_template`, whose `lang` is `{{ object.partner_id.lang }}`. On `calendar.event`, `partner_id` is `related='user_id.partner_id'`, i.e. the organizer, not the customer. The template is posted once per event (via `_track_template`), so its single rendering language applies to every recipient, including attendees whose own language differs. The confirmation email is unaffected because it is the per-attendee `attendee_invitation_mail_template` (model `calendar.attendee`), rendered once per attendee in that attendee's language.
**Fix:**
Deriving the language from `appointment_booker_id` makes the cancellation consistent with the other appointment mails, which are meant for the person who booked the meeting. It falls back to `partner_id` when there is no booker (e.g. an event not created through the appointment flow), preserving the previous behavior in that case.
opw-6323179
Forward-Port-Of: odoo/enterprise#125927
Forward-Port-Of: odoo/enterprise#124116Opening bank reconciliation from a direct link or bookmark now keeps the same automation behavior as opening it from the Accounting dashboard. Matching rules are applied automatically, and upload options stay hidden for journals connected to online bank feeds, reducing manual cleanup and confusion.
Original PR description
### Issue: When accessing the Bank Reconciliation view directly via URL or bookmark, auto-matching with reconciliation models may not trigger and the upload button may be visible on synchronized…
### Issue: When accessing the Bank Reconciliation view directly via URL or bookmark, auto-matching with reconciliation models may not trigger and the upload button may be visible on synchronized journals ### Cause: `_action_open_bank_reconciliation_widget` injects two context keys: - `auto_statement_processing`: triggers auto-reconciliation on statement creation - `bank_statements_source`: hides the upload button for synchronized journals When the view is accessed directly, these keys are not present, causing the UI to ignore them `auto_statement_processing` is now set directly in the user context via `onWillRender`/`onWillDestroy` in `BankRecKanbanController` `bank_statements_source` requires an ORM call to fetch the journal's value and is resolved via `fetchBankStatementsSourceInto` on startup Notes: The fix for `bank_statements_source` was added opportunistically while addressing `auto_statement_processing` Steps to reproduce: - Install `accountant` with demo data - Duplicate the Bank Journal and set Bank Feeds to Online Synchronization - Open the Accounting Dashboard and open the Bank (copy) - Create a transaction (Label: Test, any amount) and click Add & Close - In the 3 dots menu, choose Manage Models - Create a Reconciliation Model (Label contains: Test, Lines: any account, default values) - Click Automate - Go back to the Bank Reconciliation page and verify: -- The transaction is reconciled automatically -- No Upload button is displayed - Create a new transaction, it should be reconciled automatically - Copy the URL and open it in a new tab - Create a new transaction Before the fix, the transaction is not reconciled and the Upload button is present opw-6391107 Forward-Port-Of: odoo/enterprise#126706 Forward-Port-Of: odoo/enterprise#126359
A bug in accounting reports allowed users to trigger the same line expansion multiple times by clicking quickly or using a slow connection. The fix blocks repeat expansion requests while the first one is still loading, so report lines fold and unfold reliably.
Original PR description
Steps to reproduce:- - Open any report. - Click on a particular line to unfold more than once very fast(or throttle network to 3G) - Once line is unfolded click again to fold that line. - Line is not…
Steps to reproduce:- - Open any report. - Click on a particular line to unfold more than once very fast(or throttle network to 3G) - Once line is unfolded click again to fold that line. - Line is not folding. Cause:- - When we clicked multiple times to unfold line, duplicate child lines were created(as many times as many times we clicked). - Because when first promise was not resolved so `unfolded = false` and we clicked again so new promise also tries to unfold the same line, resulting in unfolding the same line multiple times. - In version 17.0 these duplicate child lines are created but somehow not visible but it breaks `foldLine`. From version 18.0 onwards these duplicate child lines are visible. Solution: In `unfoldLine` set the flag `unfolding`. So in all clicks other than first, we get `unfolding = true` and don't proceed further, preventing unfolding the same line multiple times. task-6260425 Forward-Port-Of: odoo/enterprise#126765 Forward-Port-Of: odoo/enterprise#120392
Automatic bank reconciliation rules now use more reliable text matching and consider transaction amounts and direction when creating or reusing rules. Users should see more relevant reconciliation suggestions for the selected journal and fewer incorrect or stale automatic rules.
Original PR description
Reconcile models automatically created now use contains instead of match regex and take the amount into consideration when creating the rule as well as checking for existing rules, it's checked whether all of the lines are positive or negative. Added an extra filter on the reconcile models so that it only shows rules that would be applied on the journal, and did some optimizations in the substring matching. task-6140372 Forward-Port-Of: odoo/enterprise#126187 Forward-Port-Of: odoo/enterprise#117256
The Vietnam reporting module now places short-term loan balances under held-to-maturity investments, aligning the balance sheet with Circular 99/2025. This helps businesses produce compliant Vietnamese financial reports without manual reclassification.
Original PR description
### Expected behavior: As per circular 99/2025, short-term loan (12831) balance is required to fall under Held to Maturity Investment (Code 123) instead of 112, translated: ``` Short-term held-to-maturity investments (Code 123): includes held-to-maturity investments with a remaining term of 12 months or less from the end of the accounting period, such as term deposits, bonds, commercial paper, loans, and other debt securities. This item does not include held-to-maturity investments that have been presented in the item “Cash equivalents” ``` ### Steps to reproduce: Install `l10n_vn_reports` module ### Fix: PO validated: Update the Balance Sheet code formula for the 12381 account opw-6413120 Forward-Port-Of: odoo/enterprise#126763
Portal users editing Knowledge articles can now view and edit existing voice transcription text without seeing the voice recording controls reserved for internal users. This keeps collaboration safe while preserving access to existing article content.
Original PR description
Portal users can edit Knowledge articles but should not have access to the voice recording feature, which is reserved for internal users. The readonly component is already used in read-only views, so reusing it in the editor for portal users is safe, it still renders the existing transcription content correctly without exposing any recording controls. Portal users can still edit the text content inside the component thanks to the editable descendants concept, which allows the editor to manage specific editable areas even within a readonly component. Task-6320461 Forward-Port-Of: odoo/enterprise#126606
The Australian payroll update process now includes salary rule category data when refreshing payroll rules. This prevents update failures when new payroll rule categories are introduced, helping payroll maintenance run more reliably.
Original PR description
ir_cron_update_payroll_data updates the payroll data including rules but fails if a new rule category is introduced. This commit adds the hr_salary_rule_category_data file to the list of data files to update. task-6351929 Forward-Port-Of: odoo/enterprise#122392
Cohort reports now calculate average retention based on the size of each cohort rather than treating every cohort equally. This gives business users a more representative view of overall retention, especially when comparing groups of very different sizes.
Original PR description
Steps to reproduce: - Open a retention cohort with cohorts of different sizes - Compare the average row with the overall retained population Issues: The average row gives every cohort the same weight. A cohort of one record at 0% retention and a cohort of nine records at 100% retention therefore displays 50% instead of 90%. Solution: Weight each cohort percentage by its initial cohort value.
Payslip reports now better detect when a note is effectively empty, even if it contains only hidden formatting tags. This prevents blank note sections from appearing on payroll documents, keeping payslips cleaner for employees and payroll teams.
Original PR description
The condition was only checking if the note field was truthy. Actually, this can be a problem if the field is with only empty tags. Instead, we should use is_html_empty.
The barcode app now correctly keeps only one delivery line selected when an operation includes both packaged and unpackaged products. This prevents confusion for warehouse users and reduces the risk of processing the wrong line during barcode-based deliveries.
Original PR description
**Steps to reproduce:** - Enable "Move Entire Packages" setting on deliveries - Make a product A, that has a package P1, on hand qty of 1 - Make product B that don't have a package, but on hand qty…
**Steps to reproduce:** - Enable "Move Entire Packages" setting on deliveries - Make a product A, that has a package P1, on hand qty of 1 - Make product B that don't have a package, but on hand qty of 1 - Make a delivery that has both of those products, requested qty of 1 for both - Mark it as todo - Go to the barcode app, select the delivery - Select the line with product B - Select the line with product A --> The line with product B is not unselected **Why the fix:** When we have a mix of packaged products and products without a package on the same operation, they are handled separately. The products without a package are handled in https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L388-L392 that calls https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L1277-L1284 But as you can see, there are no mention of the selected package line, which is stored in **this.lastScanned.packageId**. As we do not touch this variable, the selected package line stays selected. The same is true for the other way around, when we select a package line we call https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L394-L398 This function does not care for the **selectedLineVirtualId** which represents the selected line without a package. To avoid this and make it so that only one line is selected even if they have different package, we now set the corresponding value to false to unselect the other line in all situation. This is basically how it's done in https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L1202-L1208 to unselect every line regardless of packages. opw-6266203 Forward-Port-Of: odoo/enterprise#126790 Forward-Port-Of: odoo/enterprise#122038
This fixes an issue where Tyro card payments with a surcharge could sometimes validate before the surcharge was added to the point-of-sale order. Businesses using Tyro payments should now see more reliable order totals and surcharge recording at checkout.
Original PR description
Currently when completing a Tyro payment with a surcharge fee in some cases there is a race condition preventing the surcharge line to be added to the pos order before its validation This PR fixes that issue opw-6402191 Forward-Port-Of: odoo/enterprise#126035 Forward-Port-Of: odoo/enterprise#125852
Fixed an issue where uploading a document from a contact could place it in the last folder used in Documents, such as Finance, instead of the intended My Drive/All workspace location. This prevents files from being misfiled and helps users find contact-related uploads where they expect them.
Original PR description
Steps to reproduce ================== 1. Open Documents. 2. Select Finance. 3. Return to the home page and open the Contacts app. 4. Open any contact. 5. Click the Documents stat button. 6. Upload a document. Issue ===== The document is uploaded to the Finance folder instead of My Drive. Reason ====== When uploading a document using the upload button, we use `currentFolderAccessToken` to determine the destination folder. When opening the Documents view from a contact, `searchpanel_default_folder_id` is set to `False` so that documents are uploaded to the `All` workspace. However, when the search model is loaded, we do not reset `currentFolderAccessToken` when `folder_id` is `False`, causing the previously selected folder (Finance) to be reused. Task-6352242 Forward-Port-Of: odoo/enterprise#123285
Fixed an issue that could prevent event badges from printing when the badge layout included an image. This ensures staff can print badges reliably without encountering an error during event check-in or preparation.
Original PR description
Before this commit, some faulty logic in the `load_image` function caused a traceback when the ESC/LABEL badge template tried to use an image field. This bug only surfaced recently due to changes in how binary fields are accessed. After this commit, the logic is fixed and the traceback no longer occurs. task-6452486
Users can now disconnect a Belgian CodaBox connection using either the fiduciary password or a valid IAP token. This fixes a client-side gap so the revocation process works as already supported by the server.
Original PR description
The user should be able to revoke the CodaBox connection by either entering the fidu password or by using a valid iap_token. This was implemented in the iap server but not in the client side, after this commit the user should be able to either revoke by using the fidu password or by using the iap_token. task-6348433 Forward-Port-Of: odoo/enterprise#126698
This fix stops approval requests from trying to send notifications while temporary form data is being recalculated. It prevents crashes when users edit forms that include approval request links, especially for approved or refused requests, making Studio-customized workflows more reliable.
Original PR description
**Before this change** We have the potential to attempt to send a notification email from virtual records created by our `BaseModel.new()` method. This can happen during an `onchange` request, given…
**Before this change** We have the potential to attempt to send a notification email from virtual records created by our `BaseModel.new()` method. This can happen during an `onchange` request, given that we'll be working with a virtual "snapshot" record to recompute potentially changed values for our origin record after a change to one or more values. This issue manifests when using Studio to attach a many2many field to a form view, where the related model is "Approval Request". If an approval request record in either the "Approved" or "Refused" state is attached to our record via this new Studio field, any `onchange` requests will trigger this bug. This is because we can't send messages on a virtual record. **After this change** Prevent the creation and sending of a message if we are computing the request status of a virtual `approval.request()` record. The field `request_status` on this model is computed and stored, but the fact that it is a computed field means that it must be recomputed for a virtual record, even if the origin record already has a stored `request_status`. Thus, we may need to compute a `request_status` value for an ephemeral "snapshot" record. Though the issue only manifests for the "Approved" and "Refused" states, this PR expands on a test that covers every approval request state. opw-6390453 Forward-Port-Of: odoo/enterprise#125374
The cash basis reporting tests now use the outstanding receipts account configured in the system instead of relying on a fixed account code. This prevents false test failures when account codes differ between databases, 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 fixes a timing issue in the batch picking barcode flow test by waiting for the first scanned product quantity to update before selecting the next product. It helps prevent incorrect quantity splits during automated validation, reducing false failures and improving confidence in barcode picking behavior.
Original PR description
Problem: When scanning the first product, the second move line is clicked immediately after.…
Problem: When scanning the first product, the second move line is clicked immediately after. https://github.com/odoo/enterprise/blob/bfb8bab7636a84c829f16087771e00bf31ad2cce/stock_barcode_picking_batch/static/tests/tours/tour_test_barcode_batch_flows.js#L1529-L1541 If this happens before the first scan has finished, its quantity is incorrectly applied to the second move line that is clicked. This causes a 0 - 3 split instead of a 1 - 2 split, which results in there only being 6 move lines instead of 7. We updated our quantity on the `currentLine` https://github.com/odoo/enterprise/blob/bfb8bab7636a84c829f16087771e00bf31ad2cce/stock_barcode/static/src/models/barcode_model.js#L1478 When finding `currentLine`, we go through `_findLine` and use `this.selectedLineVirtualId`, which is the one that is currently selected in the UI https://github.com/odoo/enterprise/blob/bfb8bab7636a84c829f16087771e00bf31ad2cce/stock_barcode/static/src/models/barcode_model.js#L1705-L1712 Purpose: By adding this step, we wait until the first line’s quantity to be updated before it moves on and clicks on the second product. runbot-941211 Forward-Port-Of: odoo/enterprise#126847 Forward-Port-Of: odoo/enterprise#124162
The Timesheet Assistant now includes very small calendar events by adding their time to a matching larger event instead of ignoring them. This helps suggested timesheets reflect the full time spent, improving accuracy for users who rely on automated suggestions.
Original PR description
## Previous Behavior Before this PR: When events were to small to suggestion Timesheet Assistant would completely discard these events. This lead to a suggestion haveing a lower total time than it should. ## New Expected Behavior After this PR: When an event is too small to suggest and shares its name and group with one or more larger event, the duration of the smaller event is added to the last event with the same name and groupe. task-[6452987](https://www.odoo.com/odoo/project/4105/tasks/6452987)
Preparation tickets in self-order point of sale now use the language configured for the default self-order user. This helps kitchen or preparation staff receive tickets in the expected language, reducing confusion and order handling mistakes.
Original PR description
Before this commit the preparation ticket wasn't using the lang of the default pos_self_order user. Now it will use it.
UrbanPiper point-of-sale orders with tax-included prices now calculate the per-item price correctly when customers order more than one of the same product. This prevents overcharging or incorrect order totals for affected online orders.
Original PR description
Steps to reproduce: --- - Configure a Point of Sale with UrbanPiper credentials. - Create a product priced at 100 with a 5% GST (Tax Included). - Sync the product with UrbanPiper. - Place an online order with a quantity greater than 1. Issue: --- - `total_with_tax` was incorrectly treated as the unit price for multi-quantity tax-included orders. Fix: --- - Calculate the unit price by dividing `total_with_tax` by the ordered quantity before creating the POS order line. task-6427634 Forward-Port-Of: odoo/enterprise#126723 Forward-Port-Of: odoo/enterprise#125989
Steps to reproduce: 1) Install hr_holidays & hr_attendance. 2) Enable "Display Extra Hours" & "Absence Management" in the Attendance app settings. 3) Make a new employee, in the form view click the "+" button to make a new hr version record for this employee. 4) Set the date to be the first of the last month. 5) In the Attendance app -> New -> Select the new employee. 6) Select the check in and out dates to be from last month, edit the times such that the time worked is between 7 and 8 h
Original PR description
Steps to reproduce: 1) Install hr_holidays & hr_attendance. 2) Enable "Display Extra Hours" & "Absence Management" in the Attendance app settings. 3) Make a new employee, in the form view click the…
Steps to reproduce: 1) Install hr_holidays & hr_attendance. 2) Enable "Display Extra Hours" & "Absence Management" in the Attendance app settings. 3) Make a new employee, in the form view click the "+" button to make a new hr version record for this employee. 4) Set the date to be the first of the last month. 5) In the Attendance app -> New -> Select the new employee. 6) Select the check in and out dates to be from last month, edit the times such that the time worked is between 7 and 8 hours (ex 9:00am to 4:55pm). 7) In the Attendance app -> Reporting -> Attendances -> the test employee should have a negative value for "Worked Extra Hours" 8) Create a new time off type, enable "Deduct Extra Hours" & disable "Requires Allocation" use hours as the Unit of measure. 9) Open the time off smart button menu from the test employee's form view. Issue) The value seen in the report from step 7 is not the same as what the user sees in the dashboard. Notes) This issue can occur when an employee scheduled to work for 8 hours a day only clocks in for 7:55 hours leading to a negative extra time. The back-end has the correct value stored and sends it to the browser. The issue occurs because the JavaScript function that converts the decimal number of hours into a string (9.5 -> "9:30") does not work with negative input. This PR resolves that issue. opw-6417543 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280491
Before this commit: Deleting a record that uses a filterable selection field with `whitelist_fname` raises a traceback because the record field data becomes undefined during deletion. Steps to reproduce: 1. Install Belgium Accounting (l10n_be). 2. Create a contact and set a Peppol scheme and endpoint. 3. Delete the contact -> a traceback is raised. After this commit: The selection field safely handles undefined record field data during record deletion without causing an error. no-t
Original PR description
Before this commit: Deleting a record that uses a filterable selection field with `whitelist_fname` raises a traceback because the record field data becomes undefined during deletion. Steps to reproduce: 1. Install Belgium Accounting (l10n_be). 2. Create a contact and set a Peppol scheme and endpoint. 3. Delete the contact -> a traceback is raised. After this commit: The selection field safely handles undefined record field data during record deletion without causing an error. no-task Forward-Port-Of: odoo/odoo#280153 Forward-Port-Of: odoo/odoo#278808
### Issue: A user who can modify `tax_exigibility` but does not have `account.group_account_readonly` is blocked from switching to `on_payment` There is no way to complete the operation as the account field is not visible and cannot be filled before saving ### Cause: When `tax_exigibility` is set to `on_payment`, the view expects `cash_basis_transition_account_id` to be filled before saving`_constrains_cash_basis_transition_account` then validates that the account is reconcilable `cas
Original PR description
### Issue: A user who can modify `tax_exigibility` but does not have `account.group_account_readonly` is blocked from switching to `on_payment` There is no way to complete the operation as the…
### Issue: A user who can modify `tax_exigibility` but does not have `account.group_account_readonly` is blocked from switching to `on_payment` There is no way to complete the operation as the account field is not visible and cannot be filled before saving ### Cause: When `tax_exigibility` is set to `on_payment`, the view expects `cash_basis_transition_account_id` to be filled before saving`_constrains_cash_basis_transition_account` then validates that the account is reconcilable `cash_basis_transition_account_id` was restricted to `account.group_account_readonly`, hiding it from other users The field is never rendered, so it cannot be filled The `required` constraint is never evaluated client-side and `_constrains_cash_basis_transition_account` raises a `ValidationError` on save because the account is empty There is no reason to restrict `cash_basis_transition_account_id` independently — if a user can modify `tax_exigibility`, they must also be able to set the linked account ### Steps to reproduce: - Install `account` - Enable Cash Basis in Settings (On RunBot ensure no default account is set) - Enable Developer Mode in Settings - Go to Settings > Users & Companies > Users - Open the current user and disable both: `Show Accounting Features - Readonly` and `Show Full Accounting Features` (if set) - Go to Invoicing > Configuration > Taxes - Open any tax and go to Advanced Options - Change Tax Exigibility to Based on Payment Before the fix, the account selector is not displayed and saving raises an error opw-6359173 Forward-Port-Of: odoo/odoo#274728
Before this commit, the `empty a many2one field in list view` test sometimes failed, because the many2one value wasn't correctly unset (`first record` was selected). This happened because we cleared the input and automatically validated (typically with tab). However, it could happen that the validation occurred after the dropdown was opened, so the first value of the dropdown was selected. As a matter of fact, adding `await runAllTimers()` after clearing the input is a way to make the test fail
Original PR description
Before this commit, the `empty a many2one field in list view` test sometimes failed, because the many2one value wasn't correctly unset (`first record` was selected). This happened because we cleared…
Before this commit, the `empty a many2one field in list view` test sometimes failed, because the many2one value wasn't correctly unset (`first record` was selected). This happened because we cleared the input and automatically validated (typically with tab). However, it could happen that the validation occurred after the dropdown was opened, so the first value of the dropdown was selected. As a matter of fact, adding `await runAllTimers()` after clearing the input is a way to make the test fail deterministically. This commit avoids the issue by emptying the many2one without validation, so it basically only set the input value to the empty string, but doesn't tab/enter or anything else, hence it never selects an unwanted value. runbot error-941430 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#280351
This is rather an attempt of fix, as we couldn't reproduce the error locally or in a multi build., so we have no guarantee that this strenghtens the test. The test sometimes fails as `.o_crop_icon` can't be found within 200ms. Before that, we wait for the video element to be ready (we rely on a patch of the `isVideoReady` method of the component to know that the video is ready). Once it is, the isReady flag in the state is set to true and the CropOverlay component renders its `o_crop_icon` el
Original PR description
This is rather an attempt of fix, as we couldn't reproduce the error locally or in a multi build., so we have no guarantee that this strenghtens the test. The test sometimes fails as `.o_crop_icon`…
This is rather an attempt of fix, as we couldn't reproduce the error locally or in a multi build., so we have no guarantee that this strenghtens the test. The test sometimes fails as `.o_crop_icon` can't be found within 200ms. Before that, we wait for the video element to be ready (we rely on a patch of the `isVideoReady` method of the component to know that the video is ready). Once it is, the isReady flag in the state is set to true and the CropOverlay component renders its `o_crop_icon` element. Our guess is that we may sometimes early return in `isVideoReady`, because the component has been destroyed (a new rendering might be on the way). To ensure that we don't take that as the ready signal in the test, we now only consider that we're ready if isVideoReady returned true (i.e. no early return). runbot error-241798 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#280329
When a customer invoice is digitized through OCR, the salesperson may be set to the "Public User" instead of the internal user who uploaded the document. Steps to reproduce: - Upload a PDF invoice of an existing customer - Send the PDF to OCR - Reload the page Issue: Observe the Salesperson field: it is set to the Public User. Analysis: This occurs because when the partner is filled in, the compute of the salesperson will trigger. On SaaS this happens through the extraction c
Original PR description
When a customer invoice is digitized through OCR, the salesperson may be set to the "Public User" instead of the internal user who uploaded the document. Steps to reproduce: - Upload a PDF invoice of an existing customer - Send the PDF to OCR - Reload the page Issue: Observe the Salesperson field: it is set to the Public User. Analysis: This occurs because when the partner is filled in, the compute of the salesperson will trigger. On SaaS this happens through the extraction completion webhook a public route processed in sudo. that does not change the current user (public user). As self.env.user is the fallback of the compute, it may be set as salesperson. opw-6296330 Forward-Port-Of: odoo/odoo#279724
### Steps to reproduce: - In the settings enable: Multi-Steps Routes - Inventory > Configuration > Warehouse Management > Warehouses - Set your warehouse deliveries in two steps - Inventory > Operations > Tranfers > Internal > New - Set the operation type as Pick, set a partner and add Partner: Bob - In the sales & Purchase tab of the partner form set a customer location to be a child of the Customers location: Customers/Bob'Stock - Confirm and validate the Pick for 1 unit of a product
Original PR description
### Steps to reproduce: - In the settings enable: Multi-Steps Routes - Inventory > Configuration > Warehouse Management > Warehouses - Set your warehouse deliveries in two steps - Inventory >…
### Steps to reproduce: - In the settings enable: Multi-Steps Routes - Inventory > Configuration > Warehouse Management > Warehouses - Set your warehouse deliveries in two steps - Inventory > Operations > Tranfers > Internal > New - Set the operation type as Pick, set a partner and add Partner: Bob - In the sales & Purchase tab of the partner form set a customer location to be a child of the Customers location: Customers/Bob'Stock - Confirm and validate the Pick for 1 unit of a product P #### > A ship picking is created but the destination of the related move is still set to the default customer location. ### Note: If the flow is performed by a sale order, the `property_stock_customer` location will appropriately be used as `location_final_id`: https://github.com/odoo/odoo/blob/7609b5805c3704034b4d7813e2f356381ed18771/addons/sale_stock/models/sale_order_line.py#L297 https://github.com/odoo/odoo/blob/7609b5805c3704034b4d7813e2f356381ed18771/addons/sale_stock/models/sale_order_line.py#L306-L309 https://github.com/odoo/odoo/blob/720598d0315dbb91628441078febfd43ffefb431/addons/stock/models/stock_rule.py#L263-L264 So that the bug does not occur in that case. By contrast if the pick move is created manually, we do not set its `location_final_id` and hence do not propagate the info. Even though it looks expected to be set set as location_dest_id of the ship move sas suggested by the `stock.picking.location_dest_id` compute method : https://github.com/odoo/odoo/blob/fe3aea07a1964cd24f4c8ebf2bc93e483eca6b0b/addons/stock/models/stock_picking.py#L990-L1002 opw-6402483 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279616 Forward-Port-Of: odoo/odoo#278838
**PROBLEM** Before this PR, there was no way to handle invoices sent to clients depending from a JST/LGU (local government unit). This PR add support for it. opw-6095581 Forward-Port-Of: odoo/odoo#280377 Forward-Port-Of: odoo/odoo#260367
Original PR description
**PROBLEM** Before this PR, there was no way to handle invoices sent to clients depending from a JST/LGU (local government unit). This PR add support for it. opw-6095581 Forward-Port-Of: odoo/odoo#280377 Forward-Port-Of: odoo/odoo#260367
Steps to reproduce 1. Go to Manufacturing > Configuration > Settings and enable By-Products 2. Go to Inventory > Configuration > Locations, find the location with type Production and set the Cost of Production account 3. Go to Inventory > Configuration > Product Categories and set the costing method to Standard Price and Inventory Valuation to Perpetual (at invoicing) 4. Set the finished product and byproduct as Storable with a non-zero Cost 5. Create a BoM with a component and a by
Original PR description
Steps to reproduce 1. Go to Manufacturing > Configuration > Settings and enable By-Products 2. Go to Inventory > Configuration > Locations, find the location with type Production and set the Cost of…
Steps to reproduce 1. Go to Manufacturing > Configuration > Settings and enable By-Products 2. Go to Inventory > Configuration > Locations, find the location with type Production and set the Cost of Production account 3. Go to Inventory > Configuration > Product Categories and set the costing method to Standard Price and Inventory Valuation to Perpetual (at invoicing) 4. Set the finished product and byproduct as Storable with a non-zero Cost 5. Create a BoM with a component and a byproduct with a Cost Share % assigned 6. Create and complete a manufacturing order 7. Check the journal entries of the MO: the byproduct entry shows $0 Issue Standard-cost byproduct moves have no price_unit set in either code path of _cal_price, so their journal entries always show $0. When the finished product is standard cost, _cal_price returns early at https://github.com/odoo/odoo/blob/55221db559cda1c61229eecf8493f5fbaee5cd50/addons/mrp_account/models/mrp_production.py#L66-L68 without iterating byproducts at all, so no price_unit is ever set on them. When the finished product is FIFO/AVCO, the byproduct loop at https://github.com/odoo/odoo/blob/55221db559cda1c61229eecf8493f5fbaee5cd50/addons/mrp_account/models/mrp_production.py#L83-L84 only sets price_unit for FIFO/AVCO byproducts. Standard byproducts are skipped, giving them $0 even though their cost_share was already deducted from the finished product, making value disappear from inventory entirely. For standard-cost products the MO has no influence on their value — they always use the standard_price from the product form, regardless of cost_share. Solution In the early-return branch, iterate byproducts: standard ones get standard_price, FIFO/AVCO ones get total_cost * cost_share. In the FIFO/AVCO branch, add the same standard_price fallback so standard byproducts are no longer left at $0 when their cost_share is set. opw-6020065 Forward-Port-Of: odoo/odoo#280614 Forward-Port-Of: odoo/odoo#257472
**Issue** Confirming a SO that generates a batch of MOs from a BoM with a batch size could lead to creating an invalid number of pickings: all the MOs end up sharing a single picking instead of getting one each. **Steps to reproduce** - Use 2-step manufacturing - Create a storable product with the MTO + Manufacture routes - Add a BOM that has a batch size of 10 that consumes one component - Create and confirm a SO of 100 units of that product -> 10 MOs are created, but each one points
Original PR description
**Issue** Confirming a SO that generates a batch of MOs from a BoM with a batch size could lead to creating an invalid number of pickings: all the MOs end up sharing a single picking instead of…
**Issue** Confirming a SO that generates a batch of MOs from a BoM with a batch size could lead to creating an invalid number of pickings: all the MOs end up sharing a single picking instead of getting one each. **Steps to reproduce** - Use 2-step manufacturing - Create a storable product with the MTO + Manufacture routes - Add a BOM that has a batch size of 10 that consumes one component - Create and confirm a SO of 100 units of that product -> 10 MOs are created, but each one points to the same "Pick Components" transfer instead of getting its own. **Cause** This commit dd6ee071f949752d31497d9f975ba7fc41ebcd98 batches the confirm of productions: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/mrp/models/stock_rule.py#L120 thus `assign_picking` is called in batches: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/mrp/models/mrp_production.py#L1653 https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1736-L1737 https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1550-L1556 since, the `reference_ids` are the same for each MO/stock.move (they all come from the same procurement): https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1712-L1713 Consequently, all the moves end up in the same recordset `moves`: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1527 Creating only one picking: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1577 opw-6403427 Forward-Port-Of: odoo/odoo#279179
Issue ----- Branch companies can have quants of a product limited to their parent company, but they don't show in the per location report. Steps to reproduce ----- - Create a branch company - Create a WH for the branch - Create a tracked product - Company set to parent only - Switch to the branch company - Add a quant of the product in branch stock - Open Inventory > Reporting > Locations > The product is not shown although there is a quant in the branch Cause ----- The m
Original PR description
Issue ----- Branch companies can have quants of a product limited to their parent company, but they don't show in the per location report. Steps to reproduce ----- - Create a branch company - Create…
Issue ----- Branch companies can have quants of a product limited to their parent company, but they don't show in the per location report. Steps to reproduce ----- - Create a branch company - Create a WH for the branch - Create a tracked product - Company set to parent only - Switch to the branch company - Add a quant of the product in branch stock - Open Inventory > Reporting > Locations > The product is not shown although there is a quant in the branch Cause ----- The menu button triggers `action_view_quants` https://github.com/odoo/odoo/blob/03a3662212f094158f885ae6545009fd0a74d3cb/addons/stock/views/stock_quant_views.xml#L493-L495 https://github.com/odoo/odoo/blob/03a3662212f094158f885ae6545009fd0a74d3cb/addons/stock/models/stock_quant.py#L399-L402 The problem here comes from the fact that in `_get_quants_action`, we limit the products to those of only the active companies, instead of allowing to view those of parent companies aswell. https://github.com/odoo/odoo/blob/03a3662212f094158f885ae6545009fd0a74d3cb/addons/stock/models/stock_quant.py#L1330 Such a change works because the domain is specifically for the product's (`product_id.company_id`) and not the location's. ----- Ticket: opw-6131525 Forward-Port-Of: odoo/odoo#280083 Forward-Port-Of: odoo/odoo#277531
A user with role Inventory/User cannot validate the dropship of a product with an Average Cost (AVCO) Costing Method Steps to reproduce: 1. Install sale_management, stock_dropshipping and stock_landed_costs module 2. Go to Sales > Configuration > Categories and change Furniture / Office's Costing Method to Average Cost (AVCO) 3. Go to Settings > Users and set Marc Demo's role on Purchase to User 3. Log in as Marc Demo 4. Create and confirm a quotation for customer Acme Corporation with p
Original PR description
A user with role Inventory/User cannot validate the dropship of a product with an Average Cost (AVCO) Costing Method Steps to reproduce: 1. Install sale_management, stock_dropshipping and…
A user with role Inventory/User cannot validate the dropship of a product with an Average Cost (AVCO) Costing Method Steps to reproduce: 1. Install sale_management, stock_dropshipping and stock_landed_costs module 2. Go to Sales > Configuration > Categories and change Furniture / Office's Costing Method to Average Cost (AVCO) 3. Go to Settings > Users and set Marc Demo's role on Purchase to User 3. Log in as Marc Demo 4. Create and confirm a quotation for customer Acme Corporation with product Large Cabinet (Dropship route and AVCO costing method) 5. Go to the related purchase order and confirm it 6. Go to the related dropship and validate it 7. An access error is raised Issue: Validating a dropship recomputes the cost of the product and reads `stock.valuation.adjustment.lines` https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/stock_landed_costs/models/stock_move.py#L11 But only Inventory/Administrator have read access to these records https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/stock_landed_costs/security/ir.model.access.csv#L4 Solution: Call `_get_landed_cost` with `.sudo()` in order to update the cost even though the user has no landed costs access opw-6366844 Forward-Port-Of: odoo/odoo#280521 Forward-Port-Of: odoo/odoo#276285
**Steps to reproduce:** - Go to any view where you can send mails (eg sale orders) - Send a first mail to multiple recipients so they are added automatically on the next mail. - Open a new mail, confirm that the recipients are present, add a selectable attachment (eg a PDF), then click on it. - Remove any amount of recipients then send the mail. - You will see that the recipients are added back and the mail is sent to them. **Behavior:** Currently whenever a user clicks on an attachment
Original PR description
**Steps to reproduce:** - Go to any view where you can send mails (eg sale orders) - Send a first mail to multiple recipients so they are added automatically on the next mail. - Open a new mail,…
**Steps to reproduce:**
- Go to any view where you can send mails (eg sale orders)
- Send a first mail to multiple recipients so they are added automatically on the next mail.
- Open a new mail, confirm that the recipients are present, add a selectable attachment (eg a PDF), then click on it.
- Remove any amount of recipients then send the mail.
- You will see that the recipients are added back and the mail is sent to them.
**Behavior:**
Currently whenever a user clicks on an attachment in a mail composer, the systems considers that the user might be trying
to leave the page and will trigger an `urgentSave()`, and further down the line a `web_save()`.
The behavior when a web_save() is triggered is to create a record if there isnt currently one, and otherwise to write the modified values onto the record, using commands.
The recipients for the mail are added by default, which is represented by a list of `[4, id]`add commands, that will be written on the record created in the first `web_save`, however this list is not correctly emptied after the first `_save()`.
If the list is present within `this._changes` then it is correctly cleared, but in the case where no changes were made, the within `this._values['partner_ids']` still contains the commands.
So when we later assign `this.data = { ...this._values };`, `this.data['partner_ids']` now contains our uncleared list of commands.
https://github.com/odoo/odoo/blob/f3e407c6a58abd2ddba42f26fcbd1928da63cb63/addons/web/static/src/model/relational_model/record.js#L1222-L1230
And when we compute changes['partner_ids'] in our next iteration, we find ourselves with our command list again.
https://github.com/odoo/odoo/blob/f3e407c6a58abd2ddba42f26fcbd1928da63cb63/addons/web/static/src/model/relational_model/record.js#L1317-L1322
So when we then try to remove a recipient tag, the new delete command `[3, id]`
just gets canceled out with the already present add command.
And the `write()` in `web_save()` only writes add commands of already present partners, which doesn't do anything.
----
This commit adds a line to ensure commands inside `_values` are cleared
opw-6304713
Forward-Port-Of: odoo/odoo#280533
Forward-Port-Of: odoo/odoo#278876Steps 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
Steps to reproduce the error: (Python Version: 3.14.X) - Install ``accounting_firm`` industry with demo data Code for server action to generate the error: ```py for i in [1]: try: pass except Exception: pass if i: pass ``` Traceback: ```py ValueError: forbidden opcode(s) in'...': JUMP_BACKWARD_NO_INTERRUPT ``` https://github.com/odoo/industry/blob/701f7595453772e42ce72aa75df346a504e5bd82/accounting_firm/demo/ir_actions_server.xml#L105-L10
Original PR description
Steps to reproduce the error: (Python Version: 3.14.X) - Install ``accounting_firm`` industry with demo data Code for server action to generate the error: ```py for i in [1]: try: pass except…
Steps to reproduce the error: (Python Version: 3.14.X)
- Install ``accounting_firm`` industry with demo data
Code for server action to generate the error:
```py
for i in [1]:
try:
pass
except Exception:
pass
if i:
pass
```
Traceback:
```py
ValueError: forbidden opcode(s) in'...': JUMP_BACKWARD_NO_INTERRUPT
```
https://github.com/odoo/industry/blob/701f7595453772e42ce72aa75df346a504e5bd82/accounting_firm/demo/ir_actions_server.xml#L105-L108
The server action contains a ``for`` loop with a ``try/except`` block followed by additional statements in the loop body,
this combination generates the ``JUMP_BACKWARD_NO_INTERRUPT`` opcode, which is not included in ``_SAFE_OPCODES`` at [1].
When the server action is evaluated by ``safe_eval``, it calls the ``assert_valid_codeobj`` method, which validates the compiled bytecode against ``_SAFE_OPCODES``. Since ``JUMP_BACKWARD_NO_INTERRUPT`` is not present in the allowed opcodes, ``assert_valid_codeobj()`` raises a ``ValueError`` at [2] before the server action is executed .
Solution:
``JUMP_BACKWARD_NO_INTERRUPT`` opcode is added in the ``_SAFE_OPCODES`` and it is also added in the ``_SAFE_QWEB_OPCODES``.
It was added in Python 3.11: https://docs.python.org/3/whatsnew/3.11.html#new-opcodes
``JUMP_BACKWARD_NO_INTERRUPT`` is a control-flow opcode that only changes
the interpreter's execution flow by jumping back to a previous instruction.
It is the equivalent to ``JUMP_BACKWARD`` opcode. Its only semantic difference is
that the interpreter does not perform an interrupt check at that instruction.
It does not introduce any new capabilities or perform operations such as
attribute access, imports, function calls, or object creation.
Ref: https://docs.python.org/3.12/library/dis.html#opcode-JUMP_BACKWARD_NO_INTERRUPT
Similar commit that adds some necessary opcodes:
https://github.com/odoo/odoo/commit/86498d24946e510025add5d24ef0d4bcce8ad05f
[1]: https://github.com/odoo/odoo/blob/2ccbc4660077bd48529e9de43d4309fbfafc75ca/odoo/tools/safe_eval.py#L135
[2]: https://github.com/odoo/odoo/blob/2ccbc4660077bd48529e9de43d4309fbfafc75ca/odoo/tools/safe_eval.py#L244-L246
sentry-7614026125
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#277192### Issue: A partner with VAT set to '/' incorrectly matches a fiscal position with `VAT required`, instead of one without The '/' value is the placeholder suggested by the UI to indicate that the partner is known to have no VAT, but it was treated as a valid VAT by the fiscal position matching logic ### Cause: `_get_fpos_ranking_functions` uses `_get_vat_valid` to rank fiscal positions based on VAT presence `_get_vat_valid` returned `True` for any non-empty VAT value, including '/' Th
Original PR description
### Issue: A partner with VAT set to '/' incorrectly matches a fiscal position with `VAT required`, instead of one without The '/' value is the placeholder suggested by the UI to indicate that the…
### Issue: A partner with VAT set to '/' incorrectly matches a fiscal position with `VAT required`, instead of one without The '/' value is the placeholder suggested by the UI to indicate that the partner is known to have no VAT, but it was treated as a valid VAT by the fiscal position matching logic ### Cause: `_get_fpos_ranking_functions` uses `_get_vat_valid` to rank fiscal positions based on VAT presence `_get_vat_valid` returned `True` for any non-empty VAT value, including '/' The '/' case was not excluded, causing it to be treated as a valid VAT number ### Steps to reproduce: - Install `account` - Create two fiscal positions with auto-apply: -- Name: FP VAT, VAT required: True, sequence: 1 -- Name: FP no VAT, VAT required: False, sequence: 2 - Create a partner with VAT: '/' - Create an Invoice for that partner and check the Fiscal Position Before the fix, `FP VAT` is selected instead of `FP no VAT` opw-6204531 Forward-Port-Of: odoo/odoo#280494 Forward-Port-Of: odoo/odoo#280065
## Issue When logging timesheet from the *Recorded* smart button on a Sale Order containing multiple service items, the recorded hours will be added to the first sale order line, regardless of the task ID set on the timesheet entries. ## Steps to reproduce 1. Install *Sales Timesheet* (`sale_timesheet`) 2. Create a Product P: - *Product Type*: Service - *Create on Order*: Task - *Project*: Any 3. Create a SO: - *Customer*: Any - Add the product P on two different
Original PR description
## Issue When logging timesheet from the *Recorded* smart button on a Sale Order containing multiple service items, the recorded hours will be added to the first sale order line, regardless of the…
## Issue
When logging timesheet from the *Recorded* smart button on a Sale Order containing multiple service items, the recorded hours will be added to the first sale order line, regardless of the task ID set on the timesheet entries.
## Steps to reproduce
1. Install *Sales Timesheet* (`sale_timesheet`)
2. Create a Product P:
- *Product Type*: Service
- *Create on Order*: Task
- *Project*: Any
3. Create a SO:
- *Customer*: Any
- Add the product P on two different lines and give them two different descriptions D1 and D2
- Confirm the SO, this will create two tasks with the names D1 and D2
4. On the SO, click the *Recorded* smart button and create two entries:
1. Task D1, 2 hours spent
2. Tsk D2, 3 hours spent
5. **Back on the SO, there are 5 hours registered for the first SOL (with the description D1), which does not match the entries we created from the smart button.**
It is worth noting that when we create the Timesheets entries from the project itself (instead of the SO's smart button), the hours are correctly distributed among the different SOLs.
## Cause
The SOL linked to the timesheet entry (`account.analytic.line`) is computed by `_compute_so_line`:
https://github.com/odoo/odoo/blob/8b102f500f5a122e99b07a08cc43814e7c6f0f75/addons/sale_timesheet/models/hr_timesheet.py#L79-L82
This method sets the correct SOL under the condition that `is_so_line_edited` is False and `_is_no_billed()` returns True.
When opening the *Recorded* smart button from a SO, the `is_so_line_edited` is set to True by default, even if no SOL was modified.
https://github.com/odoo/odoo/blob/8b102f500f5a122e99b07a08cc43814e7c6f0f75/addons/sale_timesheet/models/sale_order.py#L113-L117
As that value is never set to False, when trying to compute the SOL for the timesheet entry, the entry is skipped and the default SOL (which is the first one) is used instead.
opw-6133473
Forward-Port-Of: odoo/odoo#274759Before this commit, in some cases, the order created for printing cash move was saved to the IndexedDB and then later loaded from IndexedDB, which caused the order gets synced to the backend but missing some required fields, like preset or pricelist. opw-5969602 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262248
Original PR description
Before this commit, in some cases, the order created for printing cash move was saved to the IndexedDB and then later loaded from IndexedDB, which caused the order gets synced to the backend but missing some required fields, like preset or pricelist. opw-5969602 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262248
When we create a database with `-i web --skip-auto-install`, we run into CSS compilation errors due to undefined variables `$black` and `$gray-200`. This commit adds these two definitions. opw-6398398 Forward-Port-Of: odoo/odoo#279753 Forward-Port-Of: odoo/odoo#279287
Original PR description
When we create a database with `-i web --skip-auto-install`, we run into CSS compilation errors due to undefined variables `$black` and `$gray-200`. This commit adds these two definitions. opw-6398398 Forward-Port-Of: odoo/odoo#279753 Forward-Port-Of: odoo/odoo#279287
Before this commit, this test sometimes failed because it couldn't find a dialog containing "camera" within 200ms. In the test scenario, we click to open the BarcodeDialog, which uses the BarcodeVideoScanner. The latter, in its `onMounted`, checks whether it has the necessary permission, which isn't the case as the `getUserMedia` function is mocked in the test to return a rejected promise. As a consequence, the `onError` callback given in props is called, which changes the state of the parent
Original PR description
Before this commit, this test sometimes failed because it couldn't find a dialog containing "camera" within 200ms. In the test scenario, we click to open the BarcodeDialog, which uses the…
Before this commit, this test sometimes failed because it couldn't find a dialog containing "camera" within 200ms. In the test scenario, we click to open the BarcodeDialog, which uses the BarcodeVideoScanner. The latter, in its `onMounted`, checks whether it has the necessary permission, which isn't the case as the `getUserMedia` function is mocked in the test to return a rejected promise. As a consequence, the `onError` callback given in props is called, which changes the state of the parent component, which re-renders itself so display "Unable to access camera" instead of the BarcodeVideoScanner. To make this test more robust, we do 2 things: 1) load the zxing library before running the test, which avoids the BarcodeVideoScanner component to load it in onWillStart. 2) explicitly wait for the 2 animationFrames, as in the scenario, we must wait for the BarcodeDialog to be rendered twice, and those renderings are now synchronous. runbot error-237933 Forward-Port-Of: odoo/odoo#280613
Steps to reproduce ------------------ 1. Set the company document layout to DIN5008 2. Open a delivery and print the delivery slip The title is missing on the DIN5008 layout, we only have the reference `WH/OUT/00001`. What happens ------------ The DIN5008 layout hides the body title with css and prints its own `h2` instead, from the `din5008_document_title` variable, and uses `o.name` (the picking number) when this variable is not set. The commit 0058d1cf7655 added the title on the
Original PR description
Steps to reproduce ------------------ 1. Set the company document layout to DIN5008 2. Open a delivery and print the delivery slip The title is missing on the DIN5008 layout, we only have the reference `WH/OUT/00001`. What happens ------------ The DIN5008 layout hides the body title with css and prints its own `h2` instead, from the `din5008_document_title` variable, and uses `o.name` (the picking number) when this variable is not set. The commit 0058d1cf7655 added the title on the standard delivery report with `picking_type_id._get_code_report_name()`, but `l10n_din5008_stock` was not updated to set `din5008_document_title`, so on DIN5008 we only get the number. The fix ------- We set it the same way as the other layouts, hence we get back the full title `Delivery Note WH/OUT/00001`. opw-6299248 Forward-Port-Of: odoo/odoo#277444
The compute method should not depend whether or not the employee is active or not. 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
Original PR description
The compute method should not depend whether or not the employee is active or not. 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
Bug === Since a4efb745e9f4ba24dfa01f1e17e65f1a7cac90a5 , we cannot insert properties. The reason is that we try to get the field definition from the inserted QWeb expression (eg `object.properties.get('property_product', env['product']).name`) which crash. Task-6311655 Forward-Port-Of: odoo/odoo#279373
Original PR description
Bug
===
Since a4efb745e9f4ba24dfa01f1e17e65f1a7cac90a5 , we cannot insert properties. The reason is that we try to get the field definition from the inserted QWeb expression (eg `object.properties.get('property_product', env['product']).name`) which crash.
Task-6311655
Forward-Port-Of: odoo/odoo#279373# Issue The test `test_absence_management_with_timeoff` fails if demo data is enabled. It was introduced by : https://github.com/odoo/odoo/pull/272089 # Cause `self.env.user` has an 'Europe/Brussels' tz when demo data is enabled. This changes the date used in the `search_count` at then end of the test : 2026-01-14 00:00 => 2026-01-13 23:00 So we check at the wrong date runbot-941523 Forward-Port-Of: odoo/odoo#279764
Original PR description
# Issue The test `test_absence_management_with_timeoff` fails if demo data is enabled. It was introduced by : https://github.com/odoo/odoo/pull/272089 # Cause `self.env.user` has an 'Europe/Brussels' tz when demo data is enabled. This changes the date used in the `search_count` at then end of the test : 2026-01-14 00:00 => 2026-01-13 23:00 So we check at the wrong date runbot-941523 Forward-Port-Of: odoo/odoo#279764
See commit messages for details. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
See commit messages for details. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Before this commit, an internal user opening the public page of a channel they are not a member of could see Discuss move to another conversation while composing, so the message was sent without its text and the tour timed out on it: FAILED: [15/37] Tour discuss_channel_public_tour.js -> Step .o-mail-Message:has(...:contains('cheese'))[data-persistent]. Element has not been found. TIMEOUT step failed to complete within 10000 ms. This happens because every member of a cha
Original PR description
Before this commit, an internal user opening the public page of a channel they are not a member of could see Discuss move to another conversation while composing, so the message was sent without its…
Before this commit, an internal user opening the public page of a channel they are not a member of could see Discuss move to another conversation while composing, so the message was sent without its text and the tour timed out on it:
FAILED: [15/37] Tour discuss_channel_public_tour.js -> Step
.o-mail-Message:has(...:contains('cheese'))[data-persistent].
Element has not been found.
TIMEOUT step failed to complete within 10000 ms.
This happens because every member of a channel notifies it that its pin state changed, self member or not. The member panel loads the members of the displayed channel right after the page, and as the user has no member there, the channel then concludes it is not pinned and Discuss opens the first pinned channel of the sidebar. The text typed before that stays on the composer of the channel it was typed in, while the attachments and the send go to the new one.
This commit fixes the issue by notifying the channel only when the pin state of self member changes. The tour also checks the name of the displayed conversation is unchanged before sending, as it succeeds in whichever conversation is displayed.
https://runbot.odoo.com/odoo/error/944617After removing sale_order_many2one widget https://github.com/odoo/odoo/commit/0ecaa6e4c359681daf90c1757bcf71ba5e4d305c , there's no need for multiple sale_order_id definitions in the form view. In this commit, cleaning the redundant field definitions and restrict visibility of Sale Order smart button. task-4661781 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280740 Forward-Port-Of: odoo/odoo#255367
Original PR description
After removing sale_order_many2one widget https://github.com/odoo/odoo/commit/0ecaa6e4c359681daf90c1757bcf71ba5e4d305c , there's no need for multiple sale_order_id definitions in the form view. In this commit, cleaning the redundant field definitions and restrict visibility of Sale Order smart button. task-4661781 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280740 Forward-Port-Of: odoo/odoo#255367
Miscellaneous changes
**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#280162 Forward-Port-Of: odoo/odoo#254090
load_data() reads product.pricelist.item_ids as a field, which applies _base_domain_item_ids()'s dotted active conditions. Since this runs as the cashier, never sudo, the ORM injects ir.rules into those conditions, forcing a non-hashable subquery that Postgres re-scans once per pricelist item. Cost scales with items times catalog size, freezing session opening on large catalogs. product.pricelist.item is already loaded separately via a plain, indexed pricelist_id domain. Reuse it to build ite
Original PR description
load_data() reads product.pricelist.item_ids as a field, which applies _base_domain_item_ids()'s dotted active conditions. Since this runs as the cashier, never sudo, the ORM injects ir.rules into those conditions, forcing a non-hashable subquery that Postgres re-scans once per pricelist item. Cost scales with items times catalog size, freezing session opening on large catalogs.
product.pricelist.item is already loaded separately via a plain, indexed pricelist_id domain. Reuse it to build item_ids instead of reading the field, avoiding the join/subquery entirely.
before after speedup
item_ids read 475.8s 2.44s ~195x
load_data() (full) unbounded 8.7s hang -> ok
opw-6391847
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#277254