Wednesday, August 27, 2025
25 changes · saas-18.4
Resolved issues and error corrections
Point of Sale now runs the normal post-payment steps even when working offline, so automatic receipt printing is not skipped. This helps stores continue checkout operations smoothly during internet outages when the local receipt printer is still available.
Original PR description
Steps to reproduce: 1. Configure a POS to use a receipt printer with automatic receipt printing. 2. Confirm that the receipt is printed automatically after a order is made as expected. 3. Disconnect from the internet so that POS continues in Offline mode (but ensure you still have access to the receipt printer on the local network). 4. Make an order in offline mode. EXPECTED: The receipt is printed automatically as before ACTUAL: The receipt is not printed. The fix is to still run the `afterOrderValidation` method in offline mode, as previously it was being bypassed and the receipt screen being shown directly. task-4946305 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#224211 Forward-Port-Of: odoo/odoo#224021
Odoo now avoids reusing archived supplier bank accounts when importing vendor bills with embedded bank details. This prevents duplicate bank account errors that could block electronic invoice processing and helps vendor bills import reliably.
Original PR description
### Issue When receiving vendor bills that include bank details, if the partner has archived bank accounts, Odoo may attempt to update them. This leads to a duplicate key violation on…
### Issue
When receiving vendor bills that include bank details, if the partner has archived bank accounts, Odoo may attempt to update them. This leads to a duplicate key violation on `res_partner_bank` when the same account number already exists for the partner.
#### Affected versions
16.0 and later
#### Error example
```bash
2025-07-08 13:36:52,942 204 INFO server-dummy odoo.addons.mail.models.mail_thread: Routing mail from "Client Name" <erp@odoo.com> to "M7- Odoo V17" <purchases@test.odoo.com>,purchases@test.odoo.com with Message-Id <*****.****.*****-****-*****-****.****@******>: direct alias match: ('account.move', 0, {'company_id': 1, 'move_type': 'in_invoice', 'journal_id': 10}, 1, mail.alias(6,))
2025-07-08 13:36:52,946 204 INFO server-dummy odoo.addons.mail.models.mail_thread: Primary email missing on account.move
2025-07-08 13:36:53,576 204 ERROR server-dummy odoo.sql_db: bad query: UPDATE "res_partner_bank" SET "acc_holder_name" = 'M7 GROUP INC.', "company_id" = NULL, "has_iban_warning" = false, "has_money_transfer_warning" = false, "sanitized_acc_number" = '1234567', "write_date" = '2025-07-08T13:36:52.897826'::timestamp, "write_uid" = 1 WHERE id IN (63)
ERROR: duplicate key value violates unique constraint "res_partner_bank_unique_number"
DETAIL: Key (sanitized_acc_number, partner_id)=(1234567, 3524) already exists.
2025-07-08 13:36:53,576 204 ERROR server-dummy odoo.addons.account.models.account_move: Error importing attachment 'factur-x.xml' as invoice (decoder=_import_invoice_ubl_cii)
Traceback (most recent call last):
File "/home/odoo/src/odoo/addons/account/models/account_move.py", line 3219, in _extend_with_attachments
with self.env.cr.savepoint():
File "/home/odoo/src/odoo/odoo/sql_db.py", line 85, in __exit__
self.close(rollback=exc_type is not None)
File "/home/odoo/src/odoo/odoo/sql_db.py", line 89, in close
self._close(rollback)
File "/home/odoo/src/odoo/odoo/sql_db.py", line 113, in _close
self._cr.flush()
File "/home/odoo/src/odoo/odoo/sql_db.py", line 137, in flush
self.transaction.flush()
File "/home/odoo/src/odoo/odoo/api.py", line 879, in flush
env_to_flush.flush_all()
File "/home/odoo/src/odoo/odoo/api.py", line 739, in flush_all
self[model_name].flush_model()
File "/home/odoo/src/odoo/odoo/models.py", line 6362, in flush_model
self._flush(fnames)
File "/home/odoo/src/odoo/odoo/models.py", line 6464, in _flush
model.browse(ids)._write(vals)
File "/home/odoo/src/odoo/odoo/models.py", line 4548, in _write
cr.execute(SQL(
File "/home/odoo/src/odoo/odoo/sql_db.py", line 332, in execute
res = self._obj.execute(query, params)
psycopg2.errors.UniqueViolation: duplicate key value violates unique constraint "res_partner_bank_unique_number"
DETAIL: Key (sanitized_acc_number, partner_id)=(1234567, 3524) already exists.
```
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#224248
Forward-Port-Of: odoo/odoo#223873This fixes a subcontracting receipt issue where changing the received quantity for products using lot-tracked components could leave users unable to validate the receipt. Users are now guided to adjust quantities through the proper component recording flow, and can access related production records when needed.
Original PR description
Issue ----- The problem is when a subcontracted product has a component tracked by lots. Creating a receipt for the subcontractor, marking it as Todo then changing the quantity leads to the reception…
Issue
-----
The problem is when a subcontracted product has a component tracked by lots. Creating a receipt for the subcontractor, marking it as Todo then changing the quantity leads to the reception being impossible to validate because the lots for the components cannot be set from the move.
Steps to reproduce
-----
- Create a product (Comp1)
- Tracked by lots
- Create a product (Prod1)
- Add a BoM - Subcontracted - Flexible consumption - Set Comp1 as consumable
- Create a receipt for 2 Prod1
- Mark as Todo
- Set Quantity to 3
- Save
- Try to validate the receipt
Situation
-----
Before changing the quantity, the user has 2 buttons ("Record components" and the move's hamburger) which open the "Subcontract" wizard. This wizard is where they can set a lot/serial for the products.
When they change the quantity of the move, the inverse method of quantity is called
https://github.com/odoo/odoo/blob/74a8334558bf86c07c0d68090a9126911867ef42/addons/stock/models/stock_move.py#L170-L171
This method is overridden in the mrp_subcontracting module
https://github.com/odoo/odoo/blob/74a8334558bf86c07c0d68090a9126911867ef42/addons/mrp_subcontracting/models/stock_move.py#L75
The part that's important to our use case is
https://github.com/odoo/odoo/blob/74a8334558bf86c07c0d68090a9126911867ef42/addons/mrp_subcontracting/models/stock_move.py#L81-L82
Recording components leads us to create a backorder production
https://github.com/odoo/odoo/blob/74a8334558bf86c07c0d68090a9126911867ef42/addons/mrp_subcontracting/models/mrp_production.py#L90-L91
In our specific use case, this is problematic because the subcontract wizard loads the form of the last production
https://github.com/odoo/odoo/blob/74a8334558bf86c07c0d68090a9126911867ef42/addons/mrp_subcontracting/models/stock_move.py#L245
The user has no way to access the previous production which lacks lot/serial (other than opening the MO itself). Obviously, we don't want to mess with this flow, but there are 2 things we can do:
1. Avoiding weird cases such as this one by forcing the user to change the quantity through the appropriate wizard
2. Providing a link to the mrp.production once some production has been recorded
For the first point, the stock.move model already has a field we can use
https://github.com/odoo/odoo/blob/8c8449f51d5e327ccd2e4bb7c3c4868d51c6d619/addons/stock/models/stock_move.py#L180
We can just override the compute to fit our use case.
For the second point, there is already a button for this. The problem is that its display condition was changed in 9ca1064 to only show once the move is picked. This fix was a bit of an over correction because we also want to show the button for unpicked moves for which a production has been recorded.
-----
Ticket:
opw-4751896
Forward-Port-Of: odoo/odoo#219268Point of Sale now correctly adds sales order lines even when the related order was not confirmed and no stock movements were created. This prevents tracked products from being skipped during settlement, helping staff complete affected PoS sales reliably.
Original PR description
Before this commit, if an order was not confirmed and stock moves were not created, if products are tracked, the order lines would not be added to the PoS. opw-5026892 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#223833 Forward-Port-Of: odoo/odoo#223591
This fix removes extra invoice data that caused Nilvera to reject Turkish E-Archive invoices when no tax office was set. It also corrects the Türkiye label in the electronic invoicing format, improving consistency for Turkish localization users.
Original PR description
### Description of the issue/feature this PR addresses: Nilvera rejects E-Archive invoices if extra fields are present under `PartyTaxScheme` when no tax office is set. In addition, the…
### Description of the issue/feature this PR addresses:
Nilvera rejects E-Archive invoices if extra fields are present under
`PartyTaxScheme` when no tax office is set. In addition, the
`invoice_edi_format` selection name for TR was incorrect.
### Current behavior before PR:
When generating E-Archive invoices, Odoo includes extra nodes such as
`registration_address_vals`, `registration_name`, and `company_id`
under the `PartyTaxScheme` element. Nilvera’s validation fails if
these nodes are present while no tax office is configured. At the same
time, the TR value for `invoice_edi_format` was using the wrong name,
which caused inconsistencies. These issues result in blocking
validation errors on Nilvera’s side and prevent the invoices from
being accepted.
### Desired behavior after PR is merged:
After this fix, the `PartyTaxScheme` is cleaned up only to include the
expected XML structure:
```xml
<cac:PartyTaxScheme>
<cac:TaxScheme>
<cbc:Name>TAX OFFICE NAME</cbc:Name>
</cac:TaxScheme>
</cac:PartyTaxScheme>
```
And the invoice_edi_format selection name for TR will be corrected
to display Türkiye rather than Turkyie.
task-5017223
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#223770Customers using mobile self-ordering will now see their order screen update correctly after payment is completed, even if they close the payment page before confirmation finishes. This prevents confusion after payment and helps staff and customers rely on accurate order status.
Original PR description
Before this commit, if a user closed the payment page on mobile after finalizing the payment but before the payment was confirmed, the self order UI would not update once the payment was confirmed. After this commit, the self-order UI is correctly updated after the payment process, even if the payment page was closed. opw-4911434 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#223813 Forward-Port-Of: odoo/odoo#222954
This fix prevents duplicate zoom windows from opening on product pages when a recently sold products carousel is present. Customers can now use keyboard controls such as arrow keys and Escape normally when viewing enlarged product images, improving the shopping experience.
Original PR description
Versions -------- - saas-18.2+ Steps ----- 1. Have a product with extra eCommerce images; 2. enable zoom-on-click on the product page; 3. add a recently-sold product carousel to the page; 4. click on…
Versions -------- - saas-18.2+ Steps ----- 1. Have a product with extra eCommerce images; 2. enable zoom-on-click on the product page; 3. add a recently-sold product carousel to the page; 4. click on an image to zoom in; 5. attempt to use arrow keys to navigate or using esc to exit zoom. Issue ----- Keys don't appear to do anything. Cause ----- Commit b8d0ab4275b24 set `oe_website_sale` as `snippet_classes` on the `s_dynamic_snippet_products` snippet, in order to enable the `websiteSaleTracking` widget, which uses this class as `selector`. Issue is this class also gets used as the selector by the `WebsiteSale` widget which adds zoom-on-click event listeners. As there are two elements with the `oe_website_sale` class now, this widget gets called twice, and because the query selector selects all image elements on the sale page, images get duplicate event listeners assigned to them. Consequently, clicking on an image opens two lightboxes, and the keys only impact the one hidden behind the other, making it appear as if key presses aren't doing anything. Solution -------- Instead of querying all images on the sale page in each call of the widget, only query for images in `this.el`. opw-4908881 Forward-Port-Of: odoo/odoo#223231
Sales order line prices now update properly when a quantity change triggers a different pricelist rule. This prevents customers from seeing or being charged an outdated unit price on quotes and sales orders, especially for volume-based pricing.
Original PR description
> [!Note] > This PR unreverts fc6b9ed22728 with a minor modification to ensure one `res.currency` record to compare amounts. **Steps to reproduce**: 1. Install the `sale` module. 2. Enable…
> [!Note] > This PR unreverts fc6b9ed22728 with a minor modification to ensure one `res.currency` record to compare amounts. **Steps to reproduce**: 1. Install the `sale` module. 2. Enable `Pricelists` under `Settings > Sales > Pricing > Pricelists`. 3. Create two pricelists: - Pricelist A with two fixed-price rules: - 0.75 for quantity ≥ 0 - 0.50 for quantity ≥ 1000 - Pricelist B with a -10% discount applied to Pricelist A. 4. Create a Sales Order using Pricelist B. 5. Add a product to the order line. 6. Increase the quantity to 1000. **Observed behavior**: - The unit price does not update according to the pricelist rule for quantity ≥ 1000. - If you switch the pricelist to another and then back again, the `Update prices` button appears and correctly updates the price. **Root cause**: - The price is not recomputed when the quantity changes because the `price_unit` is not updated because it does not match the `technical_price_unit`. - Since e1b22257a714, `price_unit` is rounded (2 decimals), but `technical_price_unit` is not. This causes a mismatch in comparison logic due to rounding differences. **Solution**: - Replace direct float comparison with `currency_id.compare_amounts()` to ensure proper comparison with rounding precision. opw-4944644 Forward-Port-Of: odoo/odoo#223548
The list view now shows a plus sign when a selection may include more records than the displayed limit, such as "10,000+". This helps users understand when bulk actions could affect additional records and reduces the risk of applying actions to an unexpected number of items.
Original PR description
Previously, when selection was made in domain mode, the system used the global `web.active_ids_limit` config parameter instead of the actual number of records selected (based on session limit). This caused unintended behavior. For example: - Open a list view of a model with 25,000 records. - The pager limit is initially set to 10,000. - When selecting all 10,000 visible records and performing an action (e.g., archive), the system would incorrectly apply the action to 20,000 records (based on the default value of `web.active_ids_limit`), not the selected 10,000. Forward-Port-Of: odoo/odoo#219639 Forward-Port-Of: odoo/odoo#217094
The New Zealand tax report now counts zero-rated sales only once in the Total Sales and Income section. This prevents overstated sales totals when invoices use a 0% tax rate, improving the accuracy of GST reporting.
Original PR description
**Steps to reproduce:** - Install Accounting and l10n_nz - Switch to a New Zeland company (e.g. NZ Company) - Create an invoice with a 0% tax - Go to "Accounting / Reporting / Statement Reports / Tax Report" - Select "Tax Report (NZ)" and the period of the invoice **Issue:** The amount of the invoice with the 0% tax is included twice in `Total Sales and Income` section. Cause: The formula for `Total Sales and Income` is `BOX5 + BOX6 + BOX9`. However, the value of BOX6 is already included in BOX5 as seen in its description `[BOX 6] Zero-rated supplies in Box 5`. opw-3883198 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#224095 Forward-Port-Of: odoo/odoo#171595
The website blog shortcut for creating a new blog post now loads correctly when the blog app is installed. This prevents users from seeing behavior that incorrectly suggests the blog feature is unavailable.
Original PR description
Sometimes, that button behaves as if the website_blog was not installed. This is because the patch made by the app to enable the button is done too late... as [1] moved the file in a lazy loaded bundle for no reason (unlike all other similar patches for new content buttons whose files it did not touch). This commit restores the file to have a similar name and location as other "new content" patches. [1]: https://github.com/odoo/odoo/commit/9fe45e2b7ddbbfd0445ffe25a859e67a316d02b2 Needed for task-2941442 runbot-226540
Applying an inventory adjustment with an accounting date could fail instead of saving the updated stock quantity. This fix restores the adjustment flow so users can update inventory quantities while keeping the correct accounting date and audit information.
Original PR description
When a user tries to apply an inventory adjustment with an accounting date, the system raises error. **Steps to produce:-** - Install the `Inventory` and `Accounting modules` with demo data. -…
When a user tries to apply an inventory adjustment with an accounting date, the system raises error. **Steps to produce:-** - Install the `Inventory` and `Accounting modules` with demo data. - `Navigate to Inventory > Reporting > Stock`. - Click the pencil icon next to a product that already has an on-hand quantity. - Set an `Accounting Date` (any date)(if not showing accounting date then add from the column dropdown). - `Modify the Quantity` and click `Apply`. **Error:-** `KeyError: 'name'` **Root cause:-** - The `_get_inventory_move_values` method in the `stock_account` module overrides the corresponding method from the base stock module. It attempts to modify the name. - However, the parent method in the stock module was changed in [commit](https://github.com/odoo/enterprise/commit/d0c1e7845feeee1c2e85a21b5d40570d051458d3), and it no longer returns a 'name' key in its result dictionary. **Solution:-** - This fix adjusts the logic in `_get_inventory_move_values` to properly set `inventory_name` with the accounted date and user information. **sentry-6791413899** --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Portal users with edit access now see the shared project's actual name and the expected back navigation in the project sharing view. This fixes a confusing header issue that made the page look generic and harder to navigate.
Original PR description
**Steps to reproduce** - Share a project with a portal user with "Edit" access rights. - With portal user, navigate to the portal project view: back arrow is missing and "Project Sharing" appears instead of project name. <img width="1450" height="894" alt="image" src="https://github.com/user-attachments/assets/05dc16fd-2255-4f90-be3e-b2e870958a6d" /> **1st issue (project name)** Caused by 1b86bd7ecf4d8751015b5056e9d48e49d68d195c removing the `params` key from context. **2nd issue (back arrow)** 939ad768b78d3b705df2589312608e9227604776 introduced a new ProjectTaskControlPanel component. opw-5036315
Credit notes with zero-priced lines and negative quantities now export valid electronic invoice values instead of a negative zero amount. This prevents UBL files, including Romanian CIUS-RO exports, from being rejected by EDI validators.
Original PR description
**Issue description:** When creating a UBL credit note, a line with a zero unit price and a negative quantity would have its gross unit price calculated as `0.0 / <negative_qty>`. This results in a…
**Issue description:** When creating a UBL credit note, a line with a zero unit price and a negative quantity would have its gross unit price calculated as `0.0 / <negative_qty>`. This results in a negative zero `-0.0`, which is considered an invalid negative net price by some EDI validators (e.g., Romanian CIUS-RO), causing the file to be rejected. **Steps to reproduce:** 1. Create a Sales Order with two lines: one product for €100 and a second (e.g., a delivery service) for €0. 2. Create and pay a downpayment invoice for a fixed amount greater than the order total, e.g., €200. 3. Go back to the Sales Order and create a "Regular Invoice". This will generate a credit note with negative quantities on the lines. 4. Ensure the journal is configured for UBL export (e.g., CIUS-RO). 5. Post, then send the credit note and inspect the generated XML file. The zero-priced line will show `cbc:PriceAmount = '-0.0'`. opw-5000314 Forward-Port-Of: odoo/odoo#223643 Forward-Port-Of: odoo/odoo#223074
The Point of Sale app now starts correctly when the default sales preset requires a customer to be selected. This prevents cashiers from being blocked by an initialization error and helps stores open sessions more reliably.
Original PR description
Before this commit, if the POS default preset required a partner, an error would occur during initialization. opw-5023987 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#223355
The website builder's theme settings panel now opens faster by avoiding unnecessary background rendering for collapsed sections. This reduces waiting time for users customizing websites, with an estimated performance gain of about 20%.
Original PR description
The purpose of this commit is to reduce the rendering time of the theme tab. Currently, when we have a BuilderRow that contains a collapse slot, we always render it in order to know whether it contains content or not, so that we can display the collapse arrow. The collapse feature is widely used in the theme tab. This results in a lot of unnecessary calculations, because the only case that requires dynamic calculation of the collapse arrow is the BuilderOption for visibility. So we will therefore add the “observeCollapseContent” props to enable or disable the rendering of the slot in order to dynamically display the collapse arrow. This change saves approximately 20% of time. 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
This fix prevents login failures for databases upgraded from older versions when notification mute settings contain an older date value. It restores the proper handling of that date so user session data can load correctly.
Original PR description
[this]( https://github.com/odoo/odoo/commit/a9532d64c3f9c541f602979225a319ec89af5194#diff-f0beb94587c1e74a64245761f99c97af110a898c0da1b3b9f195b971ee284588L42-L43) commit remove the ``mute_until_dt``…
[this](
https://github.com/odoo/odoo/commit/a9532d64c3f9c541f602979225a319ec89af5194#diff-f0beb94587c1e74a64245761f99c97af110a898c0da1b3b9f195b971ee284588L42-L43) commit remove the ``mute_until_dt`` formatting from from_settings which cause json serialzation issue and not letting login in database while dumping ``session_info`` as value can still exist database are coming from older version. For handling that adding back condtion to solve the issue and handle the ``mute_until_dt`` field formatting
**Note**: This issue won't reproduce on ``18.4`` instance but if database is coming from older version ``mute_until_dt`` will have the value that will break
```py
Traceback (most recent call last):
File "<193>", line 199, in template_web_webclient_bootstrap_193
File "<193>", line 181, in template_web_webclient_bootstrap_193_content
File "<193>", line 149, in template_web_webclient_bootstrap_193_t_call_0
File "<193>", line 24, in template_web_webclient_bootstrap_193_t_set_2
File "/home/odoo/py_env/src/odoo/18.0/odoo/tools/json.py", line 57, in dumps
return _ScriptSafe(json_.dumps(*args, **kwargs))
File "/usr/lib/python3.10/json/__init__.py", line 231, in dumps
return _default_encoder.encode(obj)
File "/usr/lib/python3.10/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python3.10/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
File "/usr/lib/python3.10/json/encoder.py", line 179, in default
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type datetime is not JSON serializable
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/odoo/py_env/src/odoo/18.0/odoo/http.py", line 2666, in __call__
response = request._serve_db()
File "/home/odoo/py_env/src/odoo/18.0/odoo/http.py", line 2169, in _serve_db
return self._transactioning(
File "/home/odoo/py_env/src/odoo/18.0/odoo/http.py", line 2233, in _transactioning
return service_model.retrying(func, env=self.env)
File "/home/odoo/py_env/src/odoo/18.0/odoo/service/model.py", line 176, in retrying
result = func()
File "/home/odoo/py_env/src/odoo/18.0/odoo/http.py", line 2200, in _serve_ir_http
response = self.dispatcher.dispatch(rule.endpoint, args)
File "/home/odoo/py_env/src/odoo/18.0/odoo/http.py", line 2369, in dispatch
return self.request.registry['ir.http']._dispatch(endpoint)
File "/home/odoo/py_env/src/odoo/18.0/odoo/addons/base/models/ir_http.py", line 356, in _dispatch
result.flatten()
File "/home/odoo/py_env/src/odoo/18.0/odoo/tools/facade.py", line 83, in wrap_func
func(self._wrapped__, *args, **kwargs)
File "/home/odoo/py_env/src/odoo/18.0/odoo/http.py", line 1472, in flatten
self.response.append(self.render())
File "/home/odoo/py_env/src/odoo/18.0/odoo/http.py", line 1464, in render
return request.env["ir.ui.view"]._render_template(self.template, self.qcontext)
File "/home/odoo/py_env/src/odoo/18.0/odoo/addons/base/models/ir_ui_view.py", line 2463, in _render_template
return self.env['ir.qweb']._render(template, values)
File "/home/odoo/py_env/src/odoo/18.0/odoo/addons/base/models/ir_qweb.py", line 623, in _render
result = ''.join(rendering)
File "<193>", line 207, in template_web_webclient_bootstrap_193
odoo.addons.base.models.ir_qweb.QWebException: Error while render the template
TypeError: Object of type datetime is not JSON serializable
Template: web.webclient_bootstrap
Path: /t/t/t[1]/script/t
Node: <t t-out="json.dumps(session_info)"/>
```
opw - 5016301
upg - 3095362
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThis update brings Odoo Spreadsheet to the latest 18.4 version and fixes several user-facing issues. Users should see more reliable Excel copy-paste behavior, correct chart exports, and cleaner menu alignment in the spreadsheet interface.
Original PR description
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/746217ad6 [REL] 18.4.8 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0)…
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/746217ad6 [REL] 18.4.8 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/eaa43f6de [FIX] xlsx: correctly export aggregated charts [Task: 4954426](https://www.odoo.com/odoo/2328/tasks/4954426) https://github.com/odoo/o-spreadsheet/commit/dd5bb2738 [FIX] Clipboard: clear useless function argument [](https://www.odoo.com/odoo/2328/tasks/) https://github.com/odoo/o-spreadsheet/commit/5a7c6fbd7 [FIX] clipboard: fix copy-paste from Excel [Task: 4730469](https://www.odoo.com/odoo/2328/tasks/4730469) https://github.com/odoo/o-spreadsheet/commit/157d55c76 [FIX] menu: Fix menu item alignment [Task: 5028721](https://www.odoo.com/odoo/2328/tasks/5028721) https://github.com/odoo/o-spreadsheet/commit/87e875b60 [FIX] Figure: icon of the menu item is not vertically aligned [Task: 4992687](https://www.odoo.com/odoo/2328/tasks/4992687) Co-authored-by: Anthony Hendrickx (anhe) <anhe@odoo.com> Co-authored-by: Alexis Lacroix (laa) <laa@odoo.com> Co-authored-by: Lucas Lefèvre (lul) <lul@odoo.com> Co-authored-by: Dhrutik Patel (dhrp) <dhrp@odoo.com> Co-authored-by: Adrien Minne (adrm) <adrm@odoo.com> Co-authored-by: Ronak Mukeshbhai Bharadiya <rmbh@odoo.com> Co-authored-by: Florian Damhaut (flda) <flda@odoo.com> Co-authored-by: Rémi Rahir (rar) <rar@odoo.com> Co-authored-by: Pierre Rousseau (pro) <pro@odoo.com> Co-authored-by: Vincent Schippefilt (vsc) <vsc@odoo.com>
The Belgian payroll SD Worx export now works with the updated employee version model in saas-18.4. This prevents an error when generating the export file, helping payroll teams complete their reporting workflow reliably.
Original PR description
#### Steps to Reproduce Payroll -> Reporting -> Export Work Entries to SDWorx -> Generate Export File #### Issue In saas-18.4, contracts have been merged into employee versions (`hr.version`) and the contract states (open/close) were removed ([REF] hr_contract: Merge contracts into versioned employee model). The method `_get_versions_with_contract_overlap_with_period` no longer supports the `states` keyword. Passing it caused a traceback when generating the SD Worx export. #### Fix This commit removes the argument to ensure compatibility with the new versioned model. task-5022173
This fix prevents an error when refunding Point of Sale orders that include a global discount line under the Mexican localization. Businesses can now process these refunds from the back end without interruption, improving reliability for store operations.
Original PR description
**Steps to reproduce:** ``` - Install PoS mexican localization - Activate PoS setting Global Discounts - Navigate to PoS and create an order with a discount line - Go to back end and try to refund this order - Notice an error pops-up ``` **Cause:** Bad fw-port In the original commit `json.lines` is an array and accessing index "2" of the array was not a problem (https://github.com/odoo/enterprise/pull/84331/files#diff-63a117ed6751a8aae4fcb11d867177f5d0feb78cc1e2f3461f425babc10b5016R15) From 18.0 we are accessing the record `currentOrder` itself and `currentOrder.lines` is an PosOrderline object which doesn't have a property named "2". **Fix:** Remove index access `[2]` opw-4899501 Forward-Port-Of: odoo/enterprise#93042 Forward-Port-Of: odoo/enterprise#90410
The Belgian POS Blackbox integration now shows clearer messages when the device cable is faulty or the Blackbox sends an invalid response. This helps store staff understand connection problems faster and supports better issue logging for troubleshooting.
Original PR description
This PR adds some explicit messages to invalid responsed from the Blackbox. We will now log and inform the user when the cable is malfunctioning or the blackbox isn't responding with a valid message Forward-Port-Of: odoo/enterprise#90570 Forward-Port-Of: odoo/enterprise#90436
This fixes an issue where changing a product image layout in the website editor could stop the Add to cart button from working for rental and subscription products. The checkout form is now found correctly even when the page layout places the button outside its usual position, helping shoppers complete purchases without interruption.
Original PR description
## Version saas-18.4+ ## Steps to reproduce - Open the shop; - Select any product; - Open the Editor: - Select the product's main image; - Change the image width to either `100 percent` or `None`,…
## Version
saas-18.4+
## Steps to reproduce
- Open the shop;
- Select any product;
- Open the Editor:
- Select the product's main image;
- Change the image width to either `100 percent` or `None`, then save;
- Click on `Add to cart`.
## Issue
Commit eac892a4ad7373d18f954afbbcd2f1213ac5f281 introduced a UI update that reorganizes the layout of the product configurator, placing the `Add to cart` button next to the form rather than below it.
Although the button remains inside the form in the original template, using the Editor to adjust the layout can result in the button being saved outside the `<form>` element in the final DOM.
This breaks the logic that relies on `closest('form')` to locate the surrounding form, since the button is no longer a descendant of the form element.
## Solution
Find the first product form relative to the button, since it may be a sibling rather than an ancestor in the DOM.
opw-4942986
See also:
- https://github.com/odoo/odoo/pull/218902Document link previews now open the correct video when users preview multiple YouTube links. This prevents confusion by ensuring each saved link shows its own preview rather than reusing the most recently added one.
Original PR description
**Steps to reproduce:** 1. Go to Documents > Click ⬇ beside Upload > Add a Link 2. Add two different YouTube video URLs with above steps 3. Preview the first link, then the second **Issue:** Previewing individual YouTube links always displays the preview of the *last* added video, regardless of which one was clicked. **Cause:** When a document has no `attachment_id`, the preview fallback logic defaults incorrectly, causing all documents to share the same preview source. **Solution:** Updated `getRecordAttachment` to prioritize `attachment_id` but gracefully fallback to `rec.resId` and `rec.data.name` when missing. This ensures document preview works even when the record has no linked attachment. opw-4906808 Forward-Port-Of: odoo/enterprise#92491 Forward-Port-Of: odoo/enterprise#90388
This fixes a checkout issue where changing a product image layout in the website editor could make the Add to Cart and wishlist buttons stop working. The storefront now finds the correct product form even when the page layout places the button outside its usual position, helping customers complete purchases reliably.
Original PR description
## Version saas-18.4+ ## Steps to reproduce - Open the shop; - Select any product; - Open the Editor: - Select the product's main image; - Change the image width to either `100 percent` or `None`,…
## Version
saas-18.4+
## Steps to reproduce
- Open the shop;
- Select any product;
- Open the Editor:
- Select the product's main image;
- Change the image width to either `100 percent` or `None`, then save;
- Click on `Add to cart`.
## Issue
Commit bbb2d98d9ab97ce729d59b9858b63daccf5434e2 introduced a UI update that reorganizes the layout of the product configurator, placing the `Add to cart` button next to the form rather than below it.
Although the button remains inside the form in the original template, using the Editor to adjust the layout can result in the button being saved outside the `<form>` element in the final DOM.
This breaks the logic that relies on `closest('form')` to locate the surrounding form, since the button is no longer a descendant of the form element.
## Solution
Find the first product form relative to the button, since it may be a sibling rather than an ancestor in the DOM.
opw-4942986
See also:
- https://github.com/odoo/enterprise/pull/90631This fix prevents certain IoT-connected printers from disappearing when their connection method briefly changes during availability checks. Businesses can keep printing reliably because the system recognizes the printer by its IP address and preserves the existing print queue entry.
Original PR description
Some printers (`lpd...PASSTHRU`s for example) tend to disappear when checking available printers list. They are often switching between one time `lpd...PASSTHRU` and the second time `socket...` protocols. As we get ip addresses for printers, we now check if the new protocol still correspond to the same printer, and if so, we keep the old one. As the printer will still be in the cups queue list, it will still be able to print through it.