Daily updates from Odoo
Monday, June 29, 2026
49 changes · saas-19.1
New functionality added to Odoo
This update adds two new delivery provider options for online orders: Food Zapp for the UAE and Enqueue for Saudi Arabia. It gives businesses in these markets more delivery integration choices and helps expand local delivery support.
Original PR description
In this commit: - We are introducing two new providers, FoodZapp and Enqueue, for the UAE and KSA, respectively. Task-6263190,6263310 Forward-Port-Of: odoo/enterprise#121461
Enhancements to existing features
This change lets administrators adjust how long idle database connections are kept open. It helps reduce memory usage in environments where keeping too many unused connections alive can strain system resources.
Original PR description
In memory-scarce environments, the default 10-minute idle timeout may keep too many backend connections alive. Allow operators to override it via the ODOO_DB_MAX_IDLE_TIMEOUT environment variable to evict idle connections more aggressively. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271785
The leave validation message now includes more useful context when an employee’s time off request cannot be processed. This makes it much easier for users and support teams to identify which employee and leave record caused the problem, especially when many records are updated at once.
Original PR description
The current message is pretty useless as of now when a lot of leaves are being written to, notably when creating a public holiday, which sets the state of all the leaves overlapping the public holiday's day to be reevaluated, and if an error occurs, you have to go through every employee's leave allocation and leaves taken to hopefully find one who might have to many days taken/not enough allocated. This extra information will be a huge QOL improvement, for the customer who will be able to troubleshoot his issue himself more easily, but also for our support team as the only way to debug those kind of issues now is to put a breakpoint there and see what employee has an issue. opw-4411999 Forward-Port-Of: odoo/odoo#270888 Forward-Port-Of: odoo/odoo#200376
The Point of Sale receipt now shows the tax base amount for every tax group again, matching the 19.0 receipt layout. This makes the tax breakdown easier to read and avoids receipts looking like a flat list when multiple tax groups share the same base amount.
Original PR description
Revert the receipt tax summary design back to the 19.0 format, ensuring that the base amount is always displayed for each tax group. Before this commit, when all tax groups shared the same tax base, the base amount was hidden, leading to a flat tax listing. Now, the template always renders the tax groups in the format: "Tax [Name] on [Base Amount] [Tax Amount]" task-id: 6296906 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The action for sending a PDP response is no longer shown as a prominent button. It has been moved into the cog wheel menu, since users can achieve the same result through the existing cancel and post workflow for invoices and bills.
Original PR description
No real need to show a big button for sending a response in PDP as cancelling and posting an invoice/bill would do the same, so we move it to the cog wheel menu task-6274220 Forward-Port-Of: odoo/odoo#268846
Resolved issues and error corrections
This update restores the company address on Colombian invoices when using the Folder or Wave layouts. It also preserves the invoice title layout so PDF exports remain readable and complete.
Original PR description
Issue: On Wave and Folder layout, the address of the company doesn't appear on invoices. Steps to reproduce: - In a Colombian company, - Set company layout to Folder - Add a long tag line, - Create an invoice, - Send it to DIAN - Export to PDF Current behavior: - Company address is missing in the header Cause: Tag line + logo and address take 100% of the display width. However, loca add a QR code on the left, so it takes QR Code + 100% width. Therefore, address was out of the PDF. Moreover, for Folder layout, some resizing was done and as soon as there was a tag_line, the `rem` was downsized, allowing the invoice title: "Factura Electrónica de Venta SETP/*\*\*/\*\*\*\*" to be displayed entirely. The fix of the previous issue stopped the resizing, then the invoice title got overridden by the QR Code (same as without tag_line before this fix). opw-6239030
Imported bill quantities are now kept at the correct precision when matching them to purchase orders. This prevents small rounding differences that could make invoiced quantities off by a cent in some cases.
Original PR description
When importing an XML bill and linkin git to a purcahse order, the invoiced quantity may be computed incorrectly, due to a decimal precision mismatch. Steps to reproduce: - Import an XML bill having a line with quantity 1800.0 - Link to a purchase order with the same line Issue: The invoiced quantity will be computed with 1 cent difference (1800.01) Analysis: Because the system forced a decimal precision of 13 for 'Product Unit of Measure', quantity is imported as 1800.0000000000016. Later, when computing the invoiced quantity, the system round the quantity using 'UP' strategy, rounding the amount to 1800.01 opw-6194824 Forward-Port-Of: odoo/odoo#270916 Forward-Port-Of: odoo/odoo#266283
This fix makes the text editor toolbar disappear at the right time when a snippet is removed from a page. It prevents the toolbar from staying visible after deleting content, improving the editing experience in the website builder.
Original PR description
Commit 8df8b4f41809de75f9ca220d47274cc3166f1cd5 moved the check for selection inside `[data-prevent-closing-overlay]` to the `closeToolbar` plugin. But when this function is called from `selection_leave_handlers` it should not do that check, as it was done for the focus or click. This commit skips the check based on the selection when `closeToolbar` is called by `selection_leave_handlers`. Steps to reproduce: - Open website builder - Drop "Text Image" snippet - Select some text in the snippet - Click on the trash icon in the sidebar to remove the snippet - Bug: the toolbar is still shown task-6308364 Forward-Port-Of: odoo/odoo#270516
This update corrects the validation message shown on public forum profiles so it uses the signed-in user’s information instead of the profile being viewed. It prevents another user's private email address from appearing in the green email verification banner.
Original PR description
**Steps to reproduce:**
- Install website_forum module
- Create a new portal user and log in with it
- Go to the website forum to see that the account requires email verification
- Send the verification email to see the green banner ('an email was sent to XX')
- Add XP (karma) points to this user as admin (User > Smart actions > Karma)
- Switch back to the portal account
- Check any public user profile on the forum (`/profile/user/2?forum_id=2`)
- Green banner now displays the private email of the user you're checking
**Issue:**
On the `email_validation_banner` the user field is used for the validation
data, but it is overridden by `_prepare_user_profile_values` which is
setting the current page user.
**Fix:**
Properly set `user` to `env.user` in the template.
opw-6276809
Forward-Port-Of: odoo/odoo#269249This update fixes several issues in the website rental and planning tests so they run more reliably. It ensures payment setup only happens when the required demo data is available, allows weekend rentals in the test setup, and makes the product search more targeted so the correct item is found on the shop page.
Original PR description
## [FIX] website_sale_renting_planning: prepare payment if demo is installed Before this commit, the demo `payment.provider` for the tests was being created in `setUpClass` this caused an issue…
## [FIX] website_sale_renting_planning: prepare payment if demo is installed Before this commit, the demo `payment.provider` for the tests was being created in `setUpClass` this caused an issue because `payment_demo` is not a dependency of this module, therefore it may not be installed while these tests are running and cause the tests to error at setup. After this commit, the `payment.provider` creation was moved into the tests after the check for `payment_demo` installation, ensuring that `payment_demo` would exist when a `payment.provider` is prepared. https://runbot.odoo.com/odoo/runbot.build.error/940273 ## [FIX] website_sale_renting_planning: unforbid weekend in tests Before this commit, the company had `renting_forbidden_sat` and `renting_forbidden_sun` enabled which made it not possible to rent products from website if the rental date included a saturday or sunday. This commit fixes that but setting `renting_forbidden_sat` and `renting_forbidden_sun` to False and allowing rental on all days of the week. https://runbot.odoo.com/odoo/runbot.build.error/940312 ## [FIX] website_sale_renting_planning: search for product in shop page Before this commit, the website `/shop` page would display all published products in the db, this could cause the `website_sale_renting_planning_buy_product` tour to fail if the setup product is not in the first page. After this commit, the `/shop` page is now access with a search on the product to ensure there won't be other products in the first page. https://runbot.odoo.com/odoo/runbot.build.error/940275 Forward-Port-Of: odoo/enterprise#121342
The website editor sidebar was adjusted so it no longer becomes one pixel wider than intended at certain browser zoom levels. This prevents the page preview from switching to mobile view when users click Edit at 150% zoom, keeping the editing experience consistent.
Original PR description
Steps to reproduce: - Open a website page on Chrome/Firefox. - Set the browser zoom to 150%. - Click Edit. => The website preview switches to mobile view. Before this commit, [1] changed the sidebar to `content-box`, so the `border-start` class added one pixel to `$o-we-sidebar-width`. The sidebar then reached 289px instead of 288px, which made the preview fall below the desktop breakpoint at 150% zoom. After this commit, the sidebar width subtracts the Bootstrap border width so its total width stays at 288px and edit mode keeps the desktop view. [1]: https://github.com/odoo/odoo/commit/181b870c3c6cf28c3eac59a16c36b94ae11ae927 task-6251151 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272074
This change prevents the text selection from being reset unexpectedly when a user closes the color picker by clicking elsewhere in the editor. It makes text editing behave more reliably and consistently across browsers, especially when applying text colors in website content.
Original PR description
When a popover is used on top of an iframe, when clicking outside the popover but inside the iframe to close the popover, the click away is detected through a blur event. The close during the click…
When a popover is used on top of an iframe, when clicking outside the popover but inside the iframe to close the popover, the click away is detected through a blur event. The close during the click away is used by some features to apply the change. Setting the text color in the editor might modify the DOM structure and therefore needs to readjust the selection to match the new DOM nodes. When confirming a color, or when applying intermediary changes this behavior is required. But when the color confirmation happens because of a click away, this selection gets on the way of the selection made by clicking away. The sequence of events is as follows: - pointerdown in iframe: sets the selection based on the click - main window blur: color gets applied, and selection gets reset - pointermove in iframe: expands selection to new position This commit avoids this unwanted reset by detecting the click away through a pointerdown on the iframe - thus making the selection adjustment before the default browser handling of the event actually sets the selection on the clicked position. Steps to reproduce: - Edit a website page - Drop a text snippet - Select a word - Set a custom color using the color area - so that the color picker remains open - Click (and hold) in the empty area after the text paragraph - Move pointer by a few pixels => The text anchor remained the one of the former selection, but the focus was set according to the pointer position Note that Firefox did not blur the main window, therefore this change actually also unifies the behavior of Chrome and Firefox. The discrepancy between Chrome and Firefox's handling of the blur event in this situation seems to be related to either prioritizing the DOM specifications or the HTML specifications - and the way the are interpreted. The DOM Standard [1] relies on UIEvents [2] which states: "A user agent MUST dispatch this event when an event target loses focus." The HTML Standard defines how to compute the focus [3] and relies on nested browsing contexts [4]. Typically, the simpler readable description for developers says: "document.hasFocus() Returns true if key events are being routed through or to document; otherwise, returns false. Roughly speaking, this corresponds to document, or a document nested inside document, being focused." [1]: https://dom.spec.whatwg.org/#biblio-uievents [2]: https://w3c.github.io/uievents/#event-type-blur [3]: https://html.spec.whatwg.org/multipage/interaction.html#focus-processing-model [4]: https://html.spec.whatwg.org/multipage/document-sequences.html#nested-browsing-contexts task-6268573 Forward-Port-Of: odoo/odoo#269742
This fix ensures that Point of Sale receipts show the customer’s change as a positive amount when they pay more than the order total. It removes a misleading negative sign so receipts are clearer and more accurate for customers and staff.
Original PR description
**Issue:** The printed receipt in Point of Sale displayed a negative change amount when the customer paid more than the order total. **Before:** The receipt showed the change as a negative value…
**Issue:** The printed receipt in Point of Sale displayed a negative change amount when the customer paid more than the order total. **Before:** The receipt showed the change as a negative value (e.g., `-$5,504.00`), which was misleading for customers. **After:** The receipt now correctly displays the change as a positive value (e.g., `$5,504.00`). **Steps to Reproduce:** 1. Open a Point of Sale session 2. Add products to the cart (example total: `$49,496.00`) 3. Select the **Cash** payment method 4. Enter an amount greater than the order total (example: `$55,000.00`) 5. Observe that the **Change** field displays a negative value 6. Confirm the payment 7. Print the receipt and observe that the change amount is also negative **Root Cause:** The issue was caused by an unnecessary negation in the `export_for_printing()` method in `pos_order.js`. The `get_change()` method already returns the correct positive change amount. However, the code applied an extra negation (`-this.get_change()`), which converted the value into a negative amount before rendering it on the receipt. **Fix:** Removed the unnecessary negation in `export_for_printing()` so the receipt now displays the correct positive change amount. Video reproducing the issue: [[Click here to view the video](https://drive.google.com/file/d/1QnQ47qlTFvv98K0J_NzreBVeIh-J2XcF/view?usp=sharing)] opw-6211988 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#269978 Forward-Port-Of: odoo/odoo#264681
This change fixes a test in the salary configurator so it correctly includes an employee’s private address. It helps ensure the salary setup process is validated properly and avoids false test failures during development.
Original PR description
Task-6329628 Forward-Port-Of: odoo/enterprise#121626
Fixed an issue where the delivery and billing addresses chosen during checkout could be replaced later if the cart was refreshed in the background. This makes sure customers keep the address they selected, preventing incorrect order details when they finish buying quickly.
Original PR description
Steps to reproduce: =================== 1. Add several delivery addresses & billing addresses 2. Add a product to the cart and go to checkout. 3. Select a specific delivery address and a different…
Steps to reproduce: =================== 1. Add several delivery addresses & billing addresses 2. Add a product to the cart and go to checkout. 3. Select a specific delivery address and a different invoice address. 4. Pay and click "Skip" immediately on that page. 5. Open the resulting sales order. => The delivery address is reset to the company's first delivery child instead of the one selected during checkout. Root cause: =========== `partner_shipping_id` and `partner_invoice_id` are stored computed fields (compute + store + readonly=False) that depend on `partner_id`. Any write that includes `partner_id`, even writing the same value, retriggers the compute and overwrites a manually selected address with the result of `partner_id.address_get()`. `_get_and_cache_current_cart` resurrects the customer's draft cart when it is no longer referenced in the session and re-runs `_update_address(partner, ['partner_id'])` on it to refresh the pricelist and fiscal position. Clicking "Skip" runs `sale_reset()`, which clears the session cart key while the order is still draft, so the next cart access takes that abandoned-cart branch and the redundant `partner_id` write discards the selected delivery/invoice address. Waiting a few seconds lets the order reach the 'sale' state first, so the draft search no longer matches and the address is kept, which is why the issue is timing dependent. Fix: ==== In `_update_address`, when partner_id is written, keep the delivery and invoice addresses already set on the cart if they still belong to the new partner's company (same `commercial_partner_id`) by writing them in the same `write()` so the recompute does not override them. Addresses that do not belong to the new partner are still recomputed to the partner's defaults. opw-6267188 Forward-Port-Of: odoo/odoo#270300
This change stops a repetitive warning from appearing when automatic OCR is turned off. It makes uploads cleaner and reduces noise for users, without changing how documents are processed.
Original PR description
The warning "Automatic OCR does not apply to this document" was logged for every upload when automatic OCR isn't enabled, it isn't very useful. opw-[6232122](https://www.odoo.com/odoo/unassigned-tasks/6232122) Forward-Port-Of: odoo/enterprise#120741
This update corrects how one Luxembourg equity account is classified and simplifies the calculation used for the “Profit or loss brought forward” line in the balance sheet. It helps ensure the report shows the right figures more reliably for year-end accounting.
Original PR description
This commit addresses the account type for the current year earnings and simplifies the calculation for the "Result brought forward" line in the Luxembourg balance sheet reports.
Modifications:
* Changed the account type of account 142 ("Result for the financial year") from `equity_unaffected` to standard `equity`.
* Simplified the formula for the Balance Sheet line "Profit or loss brought forward" (codes `LU_BS_319` and `LU_BSABR_319`).
* The new formula simply targets the `14` accounts while explicitly excluding `142`.
Enterprise PR: odoo/enterprise#121891
Ticket [link](https://www.odoo.com/odoo/project.task/6059571)
opw-6059571
Forward-Port-Of: odoo/odoo#272362This fixes an issue where changing lot numbers on tracked products could unexpectedly alter quantities or drop reservations in stock operations. The update ensures lots stay linked correctly, quantities remain consistent, and reservations are adjusted in a predictable way when users edit delivery or receipt lines.
Original PR description
### Issue: Editing the `lot_ids` of a move of a `lot` tracked product from the picking form view leads to wildly unexpected results. This happens only with tracking by `lot` not by serial. ###…
### Issue:
Editing the `lot_ids` of a move of a `lot` tracked product from the picking form view leads to wildly unexpected results. This happens only with tracking by `lot` not by serial.
### Concrete Issue 1:
1. In the settings Enable "Lots and serial numbers", "Storage Locations"
2. Create a storable product P tracked by lots
3. Create and confirm a delivery for 5 units of P
4. Set the quantity of the move to 5 from the Form picking view > save
5. Create and set 2 lots: LOT1, LOT2 on the serial numbers field
6. Save
#### > The quantity of the move has been updated to 2, only the first lot is set and it has been for this quantity of 2
### Concrete Issues 2 and 3:
1. In the settings Enable "Lots and serial numbers", "Storage Locations"
2. Create a storable product P tracked by lots
3. Update the onhand quantity of P:
- 1 units of LOT001 in Shelf1
- 2 units of LOT001 in Shelf2
- 2 units of LOT002 in Stock
4. Create and confirm a delivery for 5 units of P
5. Remove LOT002 from the Serial numbers in the Form picking view > save
#### > The quantity of the move is updated to 1 (only the 1 unit of LOT001 from Shelf2 is kept)
5'. Remove LOT002 and put it back
#### > The quantity is updated from 5 to 2 if you save, only LOT001 is kept.
### Cause of the issue:
The `_onchange_lot_ids` and `_set_lot_ids` methods have been tailored to work appropriately only with `serial` tracking, updating the quantities considering a 1 to 1 quantity, lot matching:
https://github.com/odoo/odoo/blob/c9715982134220aa8fa525d0cf6a8d47eaeb6ed6/addons/stock/models/stock_move.py#L623-L645
However, for lot tracked product the situation is much more subtle to handle.
### Behavior after the fix:
Editing the `lot_ids` on tracked products should adapt the reservation following these rules:
- Existing move lines with a valid lot or lot name should be kept unchanged.
- Removing a lot should delete its related move lines and adjust the move quantity accordingly.
- Each newly assigned lot must be linked to at least one move line of the move.
If the move is expected to bypass reservation (e.g. receipts, final move of a production,...):
- Assignment should be performed, in priority, on an existing free move line.
- If no suitable free move line exists, a new move line should be created with the largest possible quantity that does not cause the total assigned quantity to exceed the move demand.
- If such a quantity cannot be assigned, the new move line should be created with a quantity of 1 in the product.uom_id.
If the move is expected to be reserved (e.g. internal transfer, deliveries,...):
- Each new lot should be assigned from an existing quants with the maximum available quantity to satisfy at best the remaining demand.
- If no available quantity can be assigned from existing quants, the lot should be assigned a minimum quantity of 1 in product.uom_id.
### Additional note on the fix:
Since move that do bypass reservation use a different detailed operation view relying on lot_names form move line rather than lot_id from existing quants it is important to set both the `lot_name` as well as the `lot_id` on move lines for the changes to be visible in the detailed operations view.
### Note:
The current fix populated records on which the `label_production_view_pdf` report was tested (by the test_report) highlighting a template error:
https://github.com/odoo/odoo/blob/a73428187112b3948a11810abae2a3c82c9c7bcd/addons/mrp/report/mrp_production_templates.xml#L187
The value provided to the t-field being something else than a field but rather an or close between two fields.
opw-6173914
opw-5881661
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#263037This change prevents text styling from being applied outside the editable area in the website editor. As a result, formatting changes such as font size are now saved correctly in website builder and translation views.
Original PR description
Commit e0cf601ab6fc1d7cb007fcb16ee4bb6097ba6fdd added a condition to apply format on the parent of fully selected unsplittable nodes. But this could lead to format applied outside of `contenteditable=true` nodes in some cases of website builder. This commit adds a condition to only apply format outside the unsplittable if it is not the node with `contenteditable`. Steps to reproduce: - In event page, open website builder - Double click on "Starts" in the sidebar inside the event page - Change font size - Save - Bug: the changed font size is not save (a span with the font class was created outside the savable element) ### - In translate mode - Select a whole translation span - Change font size - Save - Bug: the changed font size is not save (the font class was added on the translation span) task-6308352 Forward-Port-Of: odoo/odoo#271888 Forward-Port-Of: odoo/odoo#270401
This update fixes how a year-end earnings account is classified in Luxembourg accounting, so it is treated like a standard equity account. It also simplifies the balance sheet formula for carried-forward profit or loss, which helps ensure the report shows the correct amount more reliably.
Original PR description
This commit addresses the account type for the current year earnings and simplifies the calculation for the "Result brought forward" line in the Luxembourg balance sheet reports.
Modifications:
* Changed the account type of account 142 ("Result for the financial year") from `equity_unaffected` to standard `equity`.
* Simplified the formula for the Balance Sheet line "Profit or loss brought forward" (codes `LU_BS_319` and `LU_BSABR_319`).
* The new formula simply targets the `14` accounts while explicitly excluding `142`.
Community PR: odoo/odoo#272362
Ticket [link](https://www.odoo.com/odoo/project.task/6059571)
opw-6059571
Forward-Port-Of: odoo/enterprise#121891Scheduling a document activity from several records at once could fail with an error. The system now correctly checks each selected record, so users can schedule activities in bulk without interruption.
Original PR description
### Steps to reproduce: - Install 'Accounting' - From 'Accounting' > 'Journal Entries', Select multiple records from the list view. - Try to schedule a 'Document' activity. > Traceback: `KeyError:…
### Steps to reproduce:
- Install 'Accounting'
- From 'Accounting' > 'Journal Entries', Select multiple records from the list view.
- Try to schedule a 'Document' activity.
> Traceback: `KeyError: account.move(X, X)`
### Cause of Issue:
When scheduling an activity for multiple records, `_onchange_activity_user_id` calls `_mail_get_operation_for_mail_message_operation('create')` on the entire batch of records. This method returns a dictionary mapping *individual* records to their required operations. However, then it was attempted to retrieve the operation values using the whole thread (which now contains 2 records) as a key causing a `KeyError` since only individual records existed as keys. https://github.com/odoo/odoo/blob/337efb069f6cf2cb9478a970f075fd139c1e8e0a/addons/mail/wizard/mail_activity_schedule.py#L463
### Fix:
For each required operation type, filter the records requiring it from the `thread` recordset and evaluate `check_access` on those specific records, making access checking efficient.
opw-6290303
Forward-Port-Of: odoo/odoo#270277This update removes a receipt customization that pointed to an element no longer used in the standard point of sale receipt. It ensures the Belgian black box receipt continues to work correctly after the receipt layout change, avoiding display or rendering issues.
Original PR description
In the community point_of_sale module, the `<t id="tax_base">` element was removed from the order receipt template in order to restore the 19.0 tax summary design (always displaying the tax base). Remove the xpath in pos_blackbox_be that was targeting this deleted element. task-id: 6296906
This update makes reset (neutralized) databases use the test VAT validation service instead of the live production one. It helps avoid sending unnecessary checks to the real external service, while leaving any custom setup unchanged.
Original PR description
Neutralized databases don't always have demo data, so they talk to production VIES endpoint. With this change, the production endpoint is replaced with the test one. If some database has a custom endpoint, nothing is done. @moduon MT-15142 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272036
When an email from a mass mailing campaign bounces, the contact’s bounce count is now updated reliably. This fixes cases where bounce notifications came from a different sender address, which previously caused some bounces to be missed.
Original PR description
Previously, when a mailing campaign sent out an email to a mailing.contact, and that email bounced, the bounce would not increment the contact's bounce count. This commit makes it so that the bounce count is correctly updated when a mailing campaign sends an email that bounces. task-4893615 Forward-Port-Of: odoo/odoo#226362
This change stops private tasks from being used as parent tasks in projects. It helps avoid accidental exposure or linking of tasks that should remain restricted, keeping task hierarchies more consistent and secure.
Original PR description
In this commit, we ensure that private tasks can never be selected as parent tasks. task-5119141 Forward-Port-Of: odoo/odoo#272263 Forward-Port-Of: odoo/odoo#270795
Swiss sales invoices now generate a payment reference even when the customer is outside Switzerland or Liechtenstein, as long as a QR-IBAN is configured. This ensures the invoice PDF continues to display payment communication and bank details, making it easier for customers to pay correctly.
Original PR description
Issue: When an invoice (sales journal) uses "Switzerland" localization and the invoice is issued to a customer outside Switzerland/Liechtenstein, no payment reference is generated. This causes the…
Issue: When an invoice (sales journal) uses "Switzerland" localization and the invoice is issued to a customer outside Switzerland/Liechtenstein, no payment reference is generated. This causes the invoice PDF to hide payment communication and bank account details. Other localizations like Belgian companies, uses Belgian references, the reference is always generated regardless of customer country. Steps to reproduce: - Configure a Swiss company with a QR IBAN bank account - Set the sales journal Communication Standard to Switzerland - Create and confirm an invoice for a non swiss customer (US, BE) - Observe in the pdf and in the other info tab -> no payment reference or payment details Cause: `get_l10n_ch_qrr_number()` was using on `l10n_ch_is_qr_valid()`, which conflicts QR-bill printability (partner country, currency) with payment reference generation. When the customer is outside CH/LI, `l10n_ch_is_qr_valid()` is False and no QRR reference is generated. Solution: Decouple QRR reference generation from QR bill printability. The Swiss communication standard now generates a QRR format reference when a QR-IBAN is configured, regardless of customer's country or currency. opw-6222417 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#266861
This fix stops the Belgian POS restaurant setup from creating the same “Take out” tax and fiscal position more than once when a branch is created. It allows branches to reuse the existing settings instead of failing during setup, making restaurant rollout smoother for companies with multiple locations.
Original PR description
When creating a restaurant with the POS scenario on a company with the Belgian accounting package, we automatically create a new 'Take out' fiscal position and a 'Take out' 6% tax. But when creating a branch for the company and using the same scenario, it will duplicate the 'Take out' fiscal position, and then fail to create because it will try to create a duplicate Tax with the same name and then odoo will complain. After the fix the scenario checks whether the fiscal position and tax already exist on the company, and if they do, it doesn't recreate them. This should let branches use the scenario and then they can use the already existing taxes and FPs. Task [link](https://www.odoo.com/odoo/project.task/5502948) Task-5502948 Forward-Port-Of: odoo/odoo#245848
The page builder now correctly hides the column count option again when the related style is used. This restores the expected editing behavior after a refactoring broke it, helping keep layout settings consistent for content editors.
Original PR description
The class 's_nb_column_fixed' was used to hide the column count option, but it got lost during the refactoring and doesn't work since 18.4. This commit restores it. task-6234267 Forward-Port-Of: odoo/odoo#268005
This change makes the public discussion tour more reliable by ensuring the attachment menu closes before a message is sent. It also corrects a test setup issue so the right conversation is updated between test runs, helping prevent flaky failures and improving confidence in messaging features.
Original PR description
Attempt at fixing the following race condition. It's not clear what causes it, but these changes make the test more robust and might help future investigations. discuss_channel_public_tour opens the composer "More Actions" menu to attach files but feeds the hidden file input directly, so the menu is never closed and is still open when Send is clicked. Close it and wait for it to disappear before sending, to avoid clicking Send while the dropdown is dismissing. Also fix _open_group_page_as_user, which updated the last message body of self.channel instead of self.group between the two tour runs. https://runbot.odoo.com/odoo/error/243436 Forward-Port-Of: odoo/odoo#272425
Images placed into device-shaped frames now keep the frame’s proportions instead of being forced into a square crop first. This makes tall or wide images fit more naturally and avoids unnecessary trimming, improving the final visual result for users.
Original PR description
Scenario: - insert image with ~ 1:2 ratio (height bigger than width) - set shape "iPhone `#2`" to that image Result: the image should fit without much cropping the 0.46:1 aspect ratio of the shape, but it is cropped 1:1 before being applied to it. Cause: when the image has a set aspect ratio, we are always cropping it to 1:1 aspect ratio in postProcessCroppedCanvas but it should be cropped to the shape aspect ratio as it was done in previous version. Fix: go back to what was done in saas-18.3 and apply the shape aspect ratio and not just square (1:1) aspect ratio. opw-5415137 Forward-Port-Of: odoo/odoo#250922
This fix prevents records created by Marketing Automation templates, such as the “Confirmed contacts” list and related actions, from being deleted during module upgrades. As a result, users who set up a template can upgrade the app without losing these campaign components.
Original PR description
When a user chooses the "Double Opt-in" template (or others using `_create_records_with_xml_ids`), the system creates records like the "Confirmed contacts" list and a server action. It also adds an…
When a user chooses the "Double Opt-in" template (or others using `_create_records_with_xml_ids`), the system creates records like the "Confirmed contacts" list and a server action. It also adds an `ir.model.data` entry for them under the module, but sets `noupdate=False`. The problem is that during a module upgrade, Odoo's cleanup process (`_process_end`) deletes any record marked `noupdate=False` if it wasn't "reloaded" from a file. Since these records are created manually in the code and aren't in any XML file, they never get reloaded, so Odoo just deletes them and the records they point to. By setting `noupdate=True` when these rows are created, we tell the system to leave them alone during upgrades. Since these only exist at runtime and don't have a data file, we don't need to worry about them being updated later anyway. The helper was added in https://github.com/odoo/enterprise/commit/fd98660e352512e0b74d91958707687978154833. Steps to reproduce: 1. Install Marketing Automation 2. Go to Campaigns > New and pick the "Double Opt-in" template, then save 3. Confirm the "Confirmed contacts" mailing list and server action exist 4. Go to Apps and Upgrade Marketing Automation 5. Try to find the mailing list and server action again => They disappear after the upgrade. Ticket [link](https://www.odoo.com/odoo/project.task/6140191) opw-6140191 Forward-Port-Of: odoo/enterprise#115444
The GIF integration in chat now uses Klipy instead of Tenor for its API key. This change is needed to keep GIF search working, since the old Tenor key will no longer be valid for the new service and Tenor itself is being phased out.
Original PR description
Tenor API will be terminated on June 30, 2026: https://developers.google.com/tenor/guides/quickstart This commit makes the Tenor API key input settings use a Klipy GIF API key instead of a Tenor GIF API key. To keep GIF working after this commit, the API key must necessarily be changed to a Klipy GIF API key, as the old Tenor API key would be considered as an invalid Klipy API key. Task-5491965 Upgrade: https://github.com/odoo/upgrade/pull/10516 Forward-Port-Of: odoo/odoo#272493 Forward-Port-Of: odoo/odoo#250113
The Planning app now calculates weekly hours using the actual first day of the week set in the system, instead of always relying on the locale default. This prevents employees with flexible schedules from showing more hours than their calendar allows when the week starts on a different day.
Original PR description
**Steps to reproduce** - Install planning - Switch to English (UK) and change the "First day of the week" to Sunday in the technical settings - Have an employee with a flexible schedule with a total of 40h/week, average 8h/day - In the planning app, after creating a shift to display the employee in the gantt view, notice that when hovering over the progress bar on the left, 48 worked hours are expected for the current week, which is more than what is defined in the employee's calendar **Cause** The displayed week, starting on Sunday, could accumulate more hours than the weekly cap due to the Sunday being part of another week with the locale default first day (Monday). opw-6110395 Forward-Port-Of: odoo/odoo#259600
This update extends the automated test mock so it also covers the new Odoo Fin v2 favorites institutions endpoint. It helps keep tests fully isolated from production services, reducing the risk of unwanted external requests during dashboard testing.
Original PR description
This commit follows up on [1] by extending the Odoo Fin request mock to cover the new version 2 (v2) favorite institutions endpoint. Previously, a mock was introduced to prevent the Clickall tool from making real external HTTP requests to `production.odoofin.com` when displaying the accounting dashboard. This update ensures that the newly introduced v2 URL is also safely intercepted, keeping the automated tests fully isolated from production servers. runbot-234936 [1] : https://github.com/odoo/odoo/commit/c6451015f1b01c3e1defe4a576989fd4bfdf2cdb Forward-Port-Of: odoo/odoo#272339
This fix ensures subcontracted receipt quantities stay as manually adjusted, even after the inventory scheduler runs. It prevents the system from overwriting user changes and helps keep purchase and receipt quantities aligned with what was intended.
Original PR description
**Issue** Quantity on subcontracted receipts could be overridden after running the scheduler. **Steps to reproduce** - Create a subcontracting product - Create a PO for 10 units of that product - Go…
**Issue** Quantity on subcontracted receipts could be overridden after running the scheduler. **Steps to reproduce** - Create a subcontracting product - Create a PO for 10 units of that product - Go to receipt and open Subcontracting Productions' - Change the quantity to 5 - Enable debug mode. - Run Inventory/Operations/Procurement: run scheduler - Return to the receipt -> The receipt quantity is reset to 10 instead of remaining at 5. **Cause** Since the refactor introduced in commit: https://github.com/odoo/odoo/commit/fc66e2d4eb638f1486e69cd5920f02c787055da1, subcontracting receipt moves are no longer automatically picked when the production quantity is modified. In particular, this test case protects that behavior: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/mrp_subcontracting/tests/test_subcontracting.py#L1629-L1631 When the scheduler runs: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/stock/models/stock_rule.py#L731 it computes the moves to assign: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/stock/models/stock_rule.py#L706-L710 However, subcontracting moves are still included in the assignment domain: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/stock/models/stock_rule.py#L680-L688 https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/mrp/models/stock_rule.py#L127-L129 As a result, they are reassigned if they are not already picked: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/stock/models/stock_move.py#L1931-L1937 opw-6229668 Forward-Port-Of: odoo/odoo#270837
Opening the full message composer could fail when a recipient was identified only by email and not linked to a contact. This fix ignores those incomplete recipients so the composer opens normally and users can continue sending messages without errors.
Original PR description
The full composer builds default_partner_ids by doing recipient.persona.id over allRecipients. When a recipient is not linked to a partner, the chatter input inserts it with persona: false here:…
The full composer builds default_partner_ids by doing recipient.persona.id over allRecipients. When a recipient is not linked to a partner, the chatter input inserts it with persona: false here: https://github.com/odoo/odoo/blob/28c11a068b2ecf521f8ba1da271ebee24f5345ae/addons/mail/static/src/core/web/recipients_input.js#L151 false.id is undefined, so the wizard gets a bad id and clicking the recipient tag crashes with `Invalid ids list: false`. The persona is false because /mail/partner/from_email returns no partner for unresolved emails when the user does not have base.group_partner_manager. That matches the gate _prepare_post_data already uses for the simple post flow: https://github.com/odoo/odoo/blob/28c11a068b2ecf521f8ba1da271ebee24f5345ae/addons/mail/controllers/thread.py#L153,L155 The full composer just was not handling that case. Filter out persona-less recipients from default_partner_ids so the wizard only sees real partner ids. The full composer now drops them the same way the simple post path already does. Steps to reproduce: 1. As Administrator, create a user with the Sales group only (no Contact Creation). 2. Log in as that user. 3. Open a CRM lead whose Email is set but Customer is empty. 4. Click Send message. 5. Click the expand icon to open the full composer. 6. Click the recipient tag in the To field. => Recipient shows as Unnamed and clicking it raises an RPC error. Ticket [link](https://www.odoo.com/odoo/project.task/5974081) opw-5974081 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271422 Forward-Port-Of: odoo/odoo#251780
This fix ensures users see the right manufacturing orders when opening them from the statistics button. It prevents confusion by making the displayed records match the actual manufactured orders linked to the product.
Original PR description
* Following https://github.com/odoo/odoo/pull/261438 (forward-ported to 19.0 in #265323) we also need to show correct MOs when view from statsbutton Forward-Port-Of: odoo/odoo#265195 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#269201
This change prevents the point of sale from crashing when Adyen sends the same payment notification more than once. It makes the payment flow more resilient, so customers can complete card payments without unexpected errors caused by duplicate messages.
Original PR description
The following error is raised in the POS when paying with an Adyen terminal: ``` TypeError: Cannot read properties of undefined (reading 'uuid') at Proxy.handleAdyenStatusResponse ``` Adyen delivers…
The following error is raised in the POS when paying with an Adyen terminal: ``` TypeError: Cannot read properties of undefined (reading 'uuid') at Proxy.handleAdyenStatusResponse ``` Adyen delivers webhook notifications at-least-once, so the ADYEN_LATEST_RESPONSE event can fire several times for a single payment, running handleAdyenStatusResponse concurrently. After the await on get_latest_adyen_status, a previous (duplicate) notification may already have resolved the payment line, so getPendingPaymentLine no longer returns it and the subsequent line.uuid dereference crashes. opw-6237987 patched the same root cause on a single line by adding an optional chaining operator in isPaymentSuccessful, which only moved the crash to the next dereference. Fetch the pending line once at the start of handleAdyenStatusResponse and bail out when it is gone, so every dereference below is safe. The same guard is added to the remaining branches of _adyen_handle_response for consistency with the existing Reject branch. opw-6237987 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270880 Forward-Port-Of: odoo/odoo#269720
Shop Floor now correctly places manufacturing orders without a planned start date after those that are already scheduled. This makes the order shown in Shop Floor match the usual work order prioritization and avoids confusing list behavior for operators.
Original PR description
## Problem In shop floor, MOs with unplanned work orders get sorted before MOs that have planned operations, which contradicts the normal nulls last sorting for work orders. ## Solution We will…
## Problem In shop floor, MOs with unplanned work orders get sorted before MOs that have planned operations, which contradicts the normal nulls last sorting for work orders. ## Solution We will update the sorting logic in the MrpDisplay component to more gracefully handle falsy date_start values, sorting them to the end. ## Steps to reproduce (runbot 19) 1. Create 2 MOs with an operation (work order) involving a work center, we'll call them A and B. 2. Open Shop Floor and open the work center that the MOs' work orders belong to, and note they are ordered A, B (this is fine, neither are planned so the precedence falls back to id 3. Go back to MO B and plan it. This should give it precedence in Shop Floor 4. Under the work center in Shop Floor, note that the MOs are still ordered A, B, despite B's work order having a start date and A's work order not having one To further motivate this being unintended, you can go to Manufacturing > Operations > Work Orders, and you'll see MO B's work order sitting at the top of the list. opw-6303323 Forward-Port-Of: odoo/enterprise#121693
This update corrects a timing issue in planning where shifts on 24/7 schedules could be shown as one minute longer than they really were. As a result, allocated time in reports now matches the planned shift length, improving accuracy for customers relying on planning data.
Original PR description
**Problem:** On a round-the-clock (0h-24h) working schedule, shifts created from a shift template that spans more than one day get one extra minute added to their allocated time: an 8-hour shift…
**Problem:** On a round-the-clock (0h-24h) working schedule, shifts created from a shift template that spans more than one day get one extra minute added to their allocated time: an 8-hour shift shows 08:01. **Steps to reproduce:** 1. Create a working schedule with a 00:00 -> 24:00 attendance for every day (24h/day, "Full Day"). 2. Assign an employee to that schedule. 3. Create a multi-day-span shift template (e.g. 16:00 -> 00:00, 2 days). 4. Plan a shift for that employee using the template. 5. Observe the Allocated Time shows one minute more than expected (08:01). **Current behavior:** Allocated Time is one minute too long (e.g. 08:01 instead of 08:00), which throws off the customer's planning reports. **Expected behavior:** Allocated Time matches the template duration exactly (08:00). **Cause of the issue:** In `_calculate_start_end_dates`, the end of a multi-day-span shift is computed with `resource.calendar_id.plan_days(...)`. On a 0h-24h calendar each day ends at `time.max` (23:59:59.999999), so `plan_days` returns an end datetime carrying those stale seconds. The following `end.replace(hour=..., minute=...)` overwrites only the hour and minute, leaving `second=59, microsecond=999999`. The slot is therefore ~1 minute longer than intended, and `allocated_hours` rounds that up to 08:01. **Fix:** Resetting seconds and microseconds when rebuilding the end datetime keeps the slot aligned to the template's whole-minute boundary, regardless of how the underlying calendar represents the end of day. The hour/minute already come from the template, so the leftover sub-minute precision from `plan_days` is never meaningful and is what produces the drift. opw-6265238 Forward-Port-Of: odoo/enterprise#120219
### Steps to reproduce: - Download Calendar and Contacts app - Go to the Setting -> Companies -> Manage companies; make sure there are at least two companies - Go to the Setting -> Users -> Manage users; make sure the current logged-in user has access to both companies - Create a another user who also have access to both companies - Search for the new user in contacts -> Assign the current company to the contact -> Through the internal link of the company, go to sales and purchase tab -> as
Original PR description
### Steps to reproduce: - Download Calendar and Contacts app - Go to the Setting -> Companies -> Manage companies; make sure there are at least two companies - Go to the Setting -> Users -> Manage…
### Steps to reproduce: - Download Calendar and Contacts app - Go to the Setting -> Companies -> Manage companies; make sure there are at least two companies - Go to the Setting -> Users -> Manage users; make sure the current logged-in user has access to both companies - Create a another user who also have access to both companies - Search for the new user in contacts -> Assign the current company to the contact -> Through the internal link of the company, go to sales and purchase tab -> assign the same company in the company field - Switch the company of the logged in user to the other company - Open the test contact form, use the meeting smart button and create a new meeting - Open the kanban contact view **> Access Error: Uh-oh! Looks like you have stumbled upon some top-secret records.** ### Cause of Issue: When trying to view the search results in kanban view, the `meeting_count` is calculated for each contact. Hence,`_compute_meeting_count()` is called which calls `_compute_meeting()`. https://github.com/odoo/odoo/blob/f39785bcddd1eb5b7fb503d053c9bb66e2a0f15c/addons/calendar/models/res_partner.py#L49-L54 Since the above section tries to access `partner.parent_id` each loop, it reaches a `parent_id` that's not accessible for the current user. ### Fix: Since we need to access `parent_id` to be able to calculate meeting count for the full tree of partners, `sudo()` is used to get all partners, but meetings are computed for ancestors who are in `self_ids` only so that we still remain within scope. Same old logic is used to propagate meetings for every ancestor, but dictionary lookups are used to enhance performance. opw-5874204 Forward-Port-Of: odoo/odoo#248985
Remove useless assignation of state from frontend in `_check_pos_order` because its overrided just after in the process. Forward-Port-Of: odoo/odoo#272176
Original PR description
Remove useless assignation of state from frontend in `_check_pos_order` because its overrided just after in the process. Forward-Port-Of: odoo/odoo#272176
This change fixes an unstable automated test in the messaging area that could fail because of timing, not because of a real product issue. It makes the test wait for the load action to be properly in progress before retrying, so it better reflects how a real user behaves and prevents false failures in quality checks.
Original PR description
The "Retry loading more messages on failed load more messages" test drove load-more by scrolling (real IntersectionObserver) and failed the fetch synchronously, then clicked retry immediately. The observer could fire the older-fetch twice and leave a second fetch in flight at the retry click, which then no-op'd (fetchMoreMessages bails while a fetch is loading), leaving 30 messages instead of 60. This is a test-timing artifact: a real user retries long after any fetch has settled. Fail the load-more through a Deferred rejected only once the fetch is in flight, like jump_to_present.test.js. While it is pending, duplicate observer fires no-op, so no orphan fetch can race the retry. https://runbot.odoo.com/odoo/error/242113 Forward-Port-Of: odoo/odoo#272430
This change prevents stock-related actions from breaking when a product template has dynamic attributes but no variant has been created yet. It hides or blocks actions that depend on a variant, avoiding errors and unexpected behavior for users managing inventory.
Original PR description
Issue: --- Not having at least one variant created for a product template with dynamic attributes can cause issues as it's expected a product template to have at least one variant. To reproduce: 1-…
Issue: --- Not having at least one variant created for a product template with dynamic attributes can cause issues as it's expected a product template to have at least one variant. To reproduce: 1- Create a dynamic attribute with values. 2- Create a product and without saving: - Enable track inventory. - Add the dynamic attributes and values. 3- Save the product. 4- Click on forecasted quantity smart button: - There is a traceback. 5- Click on Replenish: - Unexpected behavior. 6- Click on `Product On Hand Quantity`: - No product will be shown if you try to add quantity. Cause: --- This is caused because there is no variant created. In the steps, if you save the template once before adding dynamic attributes, a single variant will be created which allows it to work without issue. Fix: --- we can fix the TB by hiding the forecasted qty smart button, when there is no variant. However, there will be still issue with `Replenish` flow, which requires a variant. We could do the prevent the issue by ensuring there is at least one variant. opw-6260253 Forward-Port-Of: odoo/odoo#268879
This update prevents a browser security error that could appear when opening the top-right menu in Knowledge. It improves reliability so users can access the menu without the page failing in Chrome.
Original PR description
Steps to reproduce ================== - Install knowledge - Go to knowledge - Click on the three dots at the top right => SecurityError Cause of the issue ================== Since https://github.com/odoo/odoo/commit/8719c81744431d9fb862821430ce4558e2317b71 , We try to intercept clicks on iframes. In Chrome, accessing iframes from a different origin throws a SecurityError opw-6344024 Forward-Port-Of: odoo/odoo#272872
This update prevents the text cursor from jumping to the edge of a template block when editing and deleting text inside email content. It makes editing in mail templates smoother and more predictable, especially in purchase order templates.
Original PR description
## Problem:
`<t>` elements are classified as self-closing, even if they aren't used that way in a mail template. If you press backspace in the editor on some plain text that happens to be inside a `<t></t>` block, the editor would prevent the cursor from being placed back inside the block after merging because of `normalizeSelfClosingElement`. The result is the cursor being left on the outside edge of the block.
## Solution:
We will remove "T" from the list of self-closing tags.
## Steps to replicate (runbot v18):
1. Open an email template (Purchase: Purchase Order)
2. Place your cursor in some text inside a t-if element ('The receipt is expected for...'). Press backspace. Your cursor will snap to the end of the t-if block.
opw-6124284
Forward-Port-Of: odoo/odoo#266816Documentation and clarification updates
This change adds a signed Odoo Individual Contributor License Agreement for David Sonnet. It is an administrative/legal update that allows the contributor’s work to be accepted under Odoo’s contribution process, with no functional impact on the product.
Original PR description
Signing the Odoo Individual Contributor License Agreement v1.0. Adds `doc/cla/individual/dsonnet.md`. --- I confirm I have read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270526
Miscellaneous changes
Pulling latest translations from Weblate, since the sync failed to merge them.
Original PR description
Pulling latest translations from Weblate, since the sync failed to merge them.
Pulling latest translations from Weblate, since the sync failed to merge them.
Original PR description
Pulling latest translations from Weblate, since the sync failed to merge them.