Monday, October 13, 2025
76 changes
12 changes
Resolved issues and error corrections
This fix prevents failures when creating Indian GST return records for tax units with multiple companies. The system can now find a valid purchase journal from any company in the tax unit instead of only checking the main company.
Original PR description
Before this PR: - The system searched for a purchase journal only in `company_id`. - In a tax unit with multiple companies, if the main company had no purchase journal configured, record creation failed with a 'NOT NULL constraint violated' error. After this PR: - The journal search now checks all companies in `company_ids` (or falls back to `company_id`), - allowing the system to find a valid purchase journal across the tax unit. OPW: 5159518 Forward-Port-Of: odoo/enterprise#96919 Forward-Port-Of: odoo/enterprise#96838
Changing a coupon reward on a confirmed sales order now updates the coupon's remaining points correctly. This prevents customers from losing or retaining the wrong number of points when a discount reward is switched after order confirmation.
Original PR description
Versions -------- - 17.0+ Steps ----- 1. Have a coupon program; 2. add a 10% discount on order reward for 1 point; 3. add a 50% discount on order reward for 5 points; 4. generate a coupon with 10…
Versions -------- - 17.0+ Steps ----- 1. Have a coupon program; 2. add a 10% discount on order reward for 1 point; 3. add a 50% discount on order reward for 5 points; 4. generate a coupon with 10 points; 5. use coupon code on a confirmed order; 6. select 10% discount reward; 7. change to a 50% discount reward; 8. check coupon point total. Issue ----- Even though the 5 point reward was used, only 4 out of 10 points remain. Cause ----- When updating the reward line of a confirmed order, it keeps track of point cost changes before & after a write. Its purpose is to restore back the point difference on the coupon record. The issue is that while point changes are stored, coupon changes are not. When updating reward lines, `_reset_loyalty` is used, which removes the `coupon_id` from the lines. As a consequence, attempting to restore the point difference on `line.coupon_id` after an update, it writes to an empty record. Solution -------- Store both coupons & their used points before write. After write, restore the previous points to the previous coupon, and subtract the current point cost from the current coupon. This way, any combination of coupon/point changes should have the points updated as expected. opw-4910922 Forward-Port-Of: odoo/odoo#230907 Forward-Port-Of: odoo/odoo#222054
Fixes an issue where confirming a batch transfer could lose barcode scanning settings, causing location barcodes such as WH-Stock to be read incorrectly. This helps warehouse users scan batch deliveries reliably after confirmation without manual workarounds.
Original PR description
### Steps to reproduce: - In the settings enable: "Batch, Wave & Cluster Transfers" - Create 2 deliveries - Barcode > operations > Delivery orders > Batches > New - Add your two deliveries and…
### Steps to reproduce: - In the settings enable: "Batch, Wave & Cluster Transfers" - Create 2 deliveries - Barcode > operations > Delivery orders > Batches > New - Add your two deliveries and confirm - Scan WH-Stock #### > The scan fails considering you scanned each letter independently. ### Cause of the issue: When the barcode is scanned a call of the split barcode will be launched to split the barcode in multiple barcodes according to the `barcode_separator_regex` present in the config: https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/static/src/models/barcode_model.js#L613-L632 The issue lies in the fact that even thought the is `barcode_separator_regex` was conrrectly populated at the onWillStart of the mainComponent: https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/static/src/components/main.js#L209-L213 https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/controllers/stock_barcode.py#L97 https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/static/src/components/main.js#L229 https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/static/src/models/barcode_picking_model.js#L36-L38 It was reset by the batch confirmation here: https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode_picking_batch/static/src/models/barcode_picking_batch_model.js#L123-L135 because this part of the config is not meant to be returned by the private method `_get_barcode_data` but rather by public complete version `get_barcode_data`: https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/controllers/stock_barcode.py#L91-L98 Now, since no `barcode_separator_regex` was provided to our new config, each character will be considered to be considered as an independent barcodes and the `WH-Stock` barcode will not match any location. opw-5062331 Forward-Port-Of: odoo/enterprise#95295 Forward-Port-Of: odoo/enterprise#94056
Appointment video call links now use the correct website domain tied to the appointment type. This prevents customers from receiving links with the wrong company or website address in multi-company, multi-website setups.
Original PR description
**Steps to reproduce:** - Create 2 companies - Create a website for each company - Set a custom website domain on the second one - Create appointement type for each website - Create an appointement on both websites - The link created for the video call has the wrong base for one of them **Issue:** Appointment `get_base_url` finds its base_url without considering the current website. **Fix:** Compute the base_url according to the appointement type to ensure the current website is taken into account. opw-4880715 Forward-Port-Of: odoo/enterprise#96826 Forward-Port-Of: odoo/enterprise#92734
Fixed an issue where lunch orders could be incorrectly archived after repeated Receive actions or when similar orders already existed. This keeps orders visible and ensures quantities are only merged when the target order can actually be updated.
Original PR description
**Issue** The lunch order merge logic was causing orders to be unexpectedly archived when they shouldn't be. Users would see their orders disappear from the list view after certain operations like…
**Issue** The lunch order merge logic was causing orders to be unexpectedly archived when they shouldn't be. Users would see their orders disappear from the list view after certain operations like clicking "Receive" multiple times or when trying to merge orders with existing ones in immutable states. **Steps to Reproduce** 1st problem - Create a lunch order - From the order list view, select the order and click the "Receive" button - Select and click the "Receive" button again on the same order - The order gets archived and disappears from the view 2nd problem - Create a lunch order - From the order list view, select the order and click the "Receive" button - Place another order for the same product as before - From the order list view, once the second order is set to received, it gets archived and the update quantity logic not triggered **Root Cause and Solution** 1st problem: When searching for matching orders to merge, the current order being processed could match itself, leading to self-deactivation. Fixed by adding matching_lines = matching_lines - line to exclude the current record from potential merge targets. 2nd problem: The merge logic was trying to combine new orders with existing "sent" and "confirmed" orders, but the update_quantity method correctly excludes these states since they shouldn't be modified once sent/received. This created a mismatch where orders would be archived but quantities wouldn't update. Fixed by excluding "sent" and "confirmed" states from merge target searches entirely. Task ID: 5123211 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#229084
Invoices now link to the payment that is actually reconciled and confirmed, rather than an older draft payment created during duplicate or reset workflows. This helps users open the right payment from the invoice and avoids confusion in payment follow-up.
Original PR description
[FIX] account: set correct links between invoices and payments The problematic found case was the following: - Create an invoice and register a payment for it, using the wizard, with a journal having…
[FIX] account: set correct links between invoices and payments The problematic found case was the following: - Create an invoice and register a payment for it, using the wizard, with a journal having an outstanding account set - Use the smart button on the invoice form view to open the payment and reset it back to draft - Duplicate the payment, confirm the new one and reconcile it with the invoice => If we go back to the invoice form, the smart button linking payments is now redirecting to the 1st payment, that's in draft state, instead of the second confirmed one. This is because there can be 2 types of links between payments and invoices: - When there's no journal entry for payment, the link is done via the Many2many table 'account_move__account_payment'. - When there's a journal entry, the link is done via the table 'account.partial.reconcile'. Before this commit, the button on the invoice form view was based on account_move__account_payment and wasn't looking at all at account.partial.reconcile as one would expect. To solve that, we now look at reconciled_payment_ids that is computed as the union of account_move__account_payment and account.partial.reconcile. Task-4613193 Runbot: https://runbot.odoo.com/runbot/bundle/18-0-outstanding-double-link-roto-354130 Forward-Port-Of: odoo/enterprise#96926 Forward-Port-Of: odoo/enterprise#89089
Fixed an accounting issue where an invoice could link users to an old draft payment instead of the confirmed payment that actually settled it. This helps finance teams avoid confusion when reviewing paid invoices and their related payments.
Original PR description
[FIX] account: set correct links between invoices and payments The problematic found case was the following: - Create an invoice and register a payment for it, using the wizard, with a journal having…
[FIX] account: set correct links between invoices and payments The problematic found case was the following: - Create an invoice and register a payment for it, using the wizard, with a journal having an outstanding account set - Use the smart button on the invoice form view to open the payment and reset it back to draft - Duplicate the payment, confirm the new one and reconcile it with the invoice => If we go back to the invoice form, the smart button linking payments is now redirecting to the 1st payment, that's in draft state, instead of the second confirmed one. This is because there can be 2 types of links between payments and invoices: - When there's no journal entry for payment, the link is done via the Many2many table 'account_move__account_payment'. - When there's a journal entry, the link is done via the table 'account.partial.reconcile'. Before this commit, the button on the invoice form view was based on account_move__account_payment and wasn't looking at all at account.partial.reconcile as one would expect. To solve that, we now look at reconciled_payment_ids that is computed as the union of account_move__account_payment and account.partial.reconcile. Task-4613193 Runbot: https://runbot.odoo.com/runbot/bundle/18-0-outstanding-double-link-roto-354130 Forward-Port-Of: odoo/odoo#231140 Forward-Port-Of: odoo/odoo#202076
Users could encounter an error when hiding an HTML field that contained newly added images before saving the record. The update makes the editor preserve the field content safely while images finish saving, preventing the crash and improving form reliability.
Original PR description
**PROBLEM** When hiding a HtmlField field from a view with pending images in it, there is a traceback. **STEP TO REPRODUCE** 1. Using studio, create a HtmlField on the view of your choice. 2. Add a…
**PROBLEM** When hiding a HtmlField field from a view with pending images in it, there is a traceback. **STEP TO REPRODUCE** 1. Using studio, create a HtmlField on the view of your choice. 2. Add a checkbox next to it, and link the HtmlField visibility to the button. 3. Add a image to the HtmlField (don't save the record !) 4. Hide the HtmlField using the checkbox, there should be a traceback. (if not, try with a bigger image). **CAUSE** commitChanges() will try to retrieve the field value to commit by looking at the related element in the DOM. Before retrieving this value, we call savePendingImages() to save the new images added to the HtmlField. https://github.com/odoo/odoo/blob/1416aad902a97ce56aaecc2aadc4dd9f7814ee53/addons/html_editor/static/src/fields/html_field.js#L159-L162 This introduces a delay, during which the DOM element could be destroyed. **FIX** We don't call commitChanges() in OnBlur(). Instead, we cache the new value in a property of HtmlField called `newValue` when `OnChanges()` is called. Inside OnBlur(), we save the pending images by directly calling `savePendingImages()` and we commit the new value by calling `updateValue(this.newValue)` opw-5061820 Forward-Port-Of: odoo/odoo#227482
Fixes an issue where Colombian online shoppers could get stuck during checkout when selecting certain tax obligation options. Addresses with double-digit obligation option IDs now save correctly and customers can continue to delivery.
Original PR description
Problem: When there is an obligation type code with id greater than 9, and it is selected in the dropdown of the website sale address form for obligation type, the screen keeps loading forever and…
Problem: When there is an obligation type code with id greater than 9, and it is selected in the dropdown of the website sale address form for obligation type, the screen keeps loading forever and there is an “expected singleton” traceback in the logs. This is because in the method `_parse_form_data` in `l10n_co_website_sale`, the obligation type field on `form_data` is set to be a list of “type ids” which leads to an error when `convert_to_cache` is called as the browse function in this attempts to convert the list to a tuple of single characters. For example, if the list is ["10"], it gets converted to ("1","0") hence leading to the expected singleton traceback.
Purpose: Instead of passing a form list to form_data,we pass the record set which will correctly set the values in the address, much like how `default_obligations_ids` is also currently set. After this correction, the website address screen will save the address properly and redirect to the delivery screen for further actions.
Steps to Reproduce on Runbot:
1. Create a Colombian company, make sure l10n_co is installed
2. Set the company on the website to this company
3. Ensure that there is a record in the table `l10n_co_edi_obligation_type_ids` with id > 9. Create one if it does not exist.
4. Open the /shop page in incognito mode as a public user.
5. Add a product, go to the checkout page, proceed to the address page.
6. Enter all the information including the Identification Number (e.g. 623.456.789-1). Choose “NIT” in identification type and select the type code from step 3 in the dropdown for obligation type. Choose country “Colombia” along with a state and city
7. Click on "Continue checkout". The page gets stuck in a loading state
forever.
opw-4776301
Forward-Port-Of: odoo/enterprise#90862This fixes incorrect Maltese fiscal position mappings that could assign sales taxes where purchase taxes should apply, and vice versa. Businesses using the Malta localization will get more accurate tax handling for EU and non-EU partner transactions.
Original PR description
### Steps to reproduce: - Install "l10n_mt" and switch to a Maltese company - Check the fiscal position "EU Partner", it maps Sales taxes to Purchase ones - "Partner outside the EU" maps Purchase taxes to Sales ones ### Solution: Fix the CSV. We map the taxes respecting Sales/Purchase and with the same percentage. opw-5065298 Forward-Port-Of: odoo/odoo#230638 Forward-Port-Of: odoo/odoo#227423
Products that are missing key setup, such as a bill of materials or vendor, will now appear on the replenishment report much earlier instead of only on the delivery date. This gives teams advance warning to complete product configuration and avoid last-minute delivery or production issues.
Original PR description
Before this commit, RR for unconfigured products (no BoM/ no vendor), was not created until the same day of the delivery date (lead_time=0). Now, RR for unconfigured products is created considering the lead_time is incremented by 365 days. Note that this commit reverts the effect of the commit: https://github.com/odoo/odoo/commit/40d0bc0df0dc09f5138aa747cbbc715ae77f104c It's functionally decided to make the total lead_days for products with no bom to be 365 days without adding the security_lead_days. It's meant just to warn the user on the RR dashboard that the product needing replenishment is not configured, no matter to the security_lead_days in this case. Task-4779057 Forward-Port-Of: odoo/odoo#216293
This fix prevents a module uninstall process from failing when worksheet-related database fields have already been removed. It helps keep uninstall and reinstall operations consistent, avoiding broken data structures that could affect later setup.
Original PR description
Recently pull request https://github.com/odoo/enterprise/pull/86084 introduced an ondelete method on `ir.model` that retrieves some worksheet templates to delete them. However, this method breaks…
Recently pull request https://github.com/odoo/enterprise/pull/86084 introduced an ondelete method on `ir.model` that retrieves some worksheet templates to delete them. However, this method breaks when uninstalling module `worksheet`:
```
ir.model.data._module_data_uninstall():
... records are deleted ...
ir.model.fields.unlink():
drop column of corresponding fields
delete ir.model.field records
ir.model.unlink():
drop table of corresponding models
ir.model._unlink_if_uninstalling():
self.env['worksheet.template'].search([('model_id', ...)]).unlink()
delete ir.model records
```
The call to `ir.model.unlink()` crashes when searching for worksheet templates, since column `model_id` has been dropped already. This makes the transaction fail, and it is rolled back to a savepoint just before the call to `ir.model.unlink()`. In other words, the uninstallation manages to drop most of the columns that must go, but fails to drop all the tables that must go. And the uninstallation proceeds anyway...
Now consider uninstalling module `resource`. That module defines model `resource.calendar` with required field `name`, and also defines a record in that model (a default calendar). When the module is uninstalled, module `worksheet` is also uninstalled (because it depends on `resource`), and so the situation above happens. Consequently, most of the columns of table `resource_calendar` are dropped, but the table is not. If we reinstall module `resource` after that, the ORM re-creates column `name` (which is `NULL` on the default calendar at least), but fails to add the `NOT NULL` constraint on that column.
The fix consists in avoiding the `search()` above in the ondelete method if the column `model_id` does not exist anymore.
Forward-Port-Of: odoo/enterprise#9684519 changes
Resolved issues and error corrections
This fix preserves barcode scanning settings when a warehouse batch transfer is confirmed. It prevents location barcodes such as WH-Stock from being misread character by character, helping warehouse staff continue batch picking without scan failures.
Original PR description
2 changes
Resolved issues and error corrections
UrbanPiper POS orders now apply the correct taxes when a point of sale is set up under a branch company. This prevents undercharging or inaccurate tax reporting in multi-branch businesses, including cases where taxes are split into sub-taxes.
Original PR description
Steps to reproduce: --- - Install `pos_urban_piper`. - Create a branch under *Main Company*. - Switch to the new branch. - Create a POS config in this branch and set up UrbanPiper. - Sync "Apple Pie". - Place an order with "Apple Pie". Issue: --- - The 15% tax defined on Apple Pie is not applied on the orderline. Cause: --- - While creating the order line, the tax company was compared directly with the POS config’s company. In this case, the tax belongs to the parent company, while the POS config belongs to a child company. Fix: --- - Compare the `root_id` of both companies instead of the direct company ID to ensure taxes are applied correctly in multi-branch setups. - Additionally, handled the case where a main tax has sub-taxes (e.g., 5% GST split into 2.5% SGST and 2.5% CGST). In such cases, we now fetch the tax type from the sub-taxes instead of the main tax. Task-5050682 Forward-Port-Of: odoo/enterprise#93467
7 changes
Resolved issues and error corrections
Fixes an issue where confirming a batch transfer could lose barcode scanning settings, causing location barcodes like WH-Stock to be read incorrectly. Warehouse users can now confirm batches and continue scanning locations normally, avoiding blocked or failed batch picking workflows.
Original PR description
25 changes
Resolved issues and error corrections
This update adjusts customer portal templates so invoices, terms, and sales documents display correctly after a recent template engine change. It prevents missing layout details caused by the new way template information is passed behind the scenes.
Original PR description
In this commit(#197296), the behavior of `<t t-call>` has been updated to support parametric template calls. Variables defined inside a nested <t t-set> within a `<t t-call>` block are no longer visible to the called template due to lazy XML evaluation. This commit updates QWeb templates to: Pass parameters directly as attributes on <t t-call> instead of using inner <t t-set> tags. Before fix: <img width="1875" height="985" alt="image" src="https://github.com/user-attachments/assets/c55d42bc-69a5-42d7-9878-e8334b3cebd9" /> After fix: <img width="1869" height="974" alt="image" src="https://github.com/user-attachments/assets/62286ffe-879a-4741-a83f-7fbb8d94bb2c" /> opw-5152781 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
4 changes
Resolved issues and error corrections
This fix prevents GST return setup from failing when a multi-company tax unit's main company has no purchase journal configured. The system now looks across all companies in the tax unit to find a valid purchase journal, improving reliability for Indian GST reporting.
Original PR description
Before this PR: - The system searched for a purchase journal only in `company_id`. - In a tax unit with multiple companies, if the main company had no purchase journal configured, record creation failed with a 'NOT NULL constraint violated' error. After this PR: - The journal search now checks all companies in `company_ids` (or falls back to `company_id`), - allowing the system to find a valid purchase journal across the tax unit. OPW: 5159518 Forward-Port-Of: odoo/enterprise#96838
7 changes
Resolved issues and error corrections
The HR organization chart now avoids an error that could occur when loading employees with many levels of subordinates. This makes the org chart more reliable for companies with deep management structures.
Original PR description
This commit fixes a recursion error that occurs in `_get_subordinates`. An iterative approach is used instead of the current recursive implementation. task-5118697 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
### Steps to reproduce: - In the settings enable: "Batch, Wave & Cluster Transfers" - Create 2 deliveries - Barcode > operations > Delivery orders > Batches > New - Add your two deliveries and…
### Steps to reproduce: - In the settings enable: "Batch, Wave & Cluster Transfers" - Create 2 deliveries - Barcode > operations > Delivery orders > Batches > New - Add your two deliveries and confirm - Scan WH-Stock #### > The scan fails considering you scanned each letter independently. ### Cause of the issue: When the barcode is scanned a call of the split barcode will be launched to split the barcode in multiple barcodes according to the `barcode_separator_regex` present in the config: https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/static/src/models/barcode_model.js#L613-L632 The issue lies in the fact that even thought the is `barcode_separator_regex` was conrrectly populated at the onWillStart of the mainComponent: https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/static/src/components/main.js#L209-L213 https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/controllers/stock_barcode.py#L97 https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/static/src/components/main.js#L229 https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/static/src/models/barcode_picking_model.js#L36-L38 It was reset by the batch confirmation here: https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode_picking_batch/static/src/models/barcode_picking_batch_model.js#L123-L135 because this part of the config is not meant to be returned by the private method `_get_barcode_data` but rather by public complete version `get_barcode_data`: https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/controllers/stock_barcode.py#L91-L98 Now, since no `barcode_separator_regex` was provided to our new config, each character will be considered to be considered as an independent barcodes and the `WH-Stock` barcode will not match any location. opw-5062331 Forward-Port-Of: odoo/enterprise#95295 Forward-Port-Of: odoo/enterprise#94056
Point of Sale payments made through a payment terminal now complete automatically when cash rounding is applied. This prevents staff from having to manually validate fully paid orders, reducing missed validations and checkout mistakes.
Original PR description
Ensure that when a payment is made via a payment terminal and cash rounding is applied, the payment is automatically validated once the response is received. Previously, validation did not always occur because we relied on `get_due` is not exactly what is left to pay, as it does not account for cash rounding rounded amounts. The condition for auto-validation was simplified, since `is_paid` already checks whether there is nothing left to pay. Thus, using `get_due` is redundant. Steps to reproduce: 1. Create a cash rounding and set it on the POS. 2. Sell a product priced at e.g. 1.99 EUR, paid via a terminal (e.g. Worldline). 3. Notice the payment is not auto-validated and requires manual validation, which can lead to mistakes or missed manual validations. opw-4862684 Forward-Port-Of: odoo/odoo#231034 Forward-Port-Of: odoo/odoo#228608
Fixes an issue where lunch orders could be archived by mistake when users clicked Receive more than once or placed another order for the same product. This keeps order lists accurate and prevents confusion around received lunch orders.
Original PR description
**Issue** The lunch order merge logic was causing orders to be unexpectedly archived when they shouldn't be. Users would see their orders disappear from the list view after certain operations like…
**Issue** The lunch order merge logic was causing orders to be unexpectedly archived when they shouldn't be. Users would see their orders disappear from the list view after certain operations like clicking "Receive" multiple times or when trying to merge orders with existing ones in immutable states. **Steps to Reproduce** 1st problem - Create a lunch order - From the order list view, select the order and click the "Receive" button - Select and click the "Receive" button again on the same order - The order gets archived and disappears from the view 2nd problem - Create a lunch order - From the order list view, select the order and click the "Receive" button - Place another order for the same product as before - From the order list view, once the second order is set to received, it gets archived and the update quantity logic not triggered **Root Cause and Solution** 1st problem: When searching for matching orders to merge, the current order being processed could match itself, leading to self-deactivation. Fixed by adding matching_lines = matching_lines - line to exclude the current record from potential merge targets. 2nd problem: The merge logic was trying to combine new orders with existing "sent" and "confirmed" orders, but the update_quantity method correctly excludes these states since they shouldn't be modified once sent/received. This created a mismatch where orders would be archived but quantities wouldn't update. Fixed by excluding "sent" and "confirmed" states from merge target searches entirely. Task ID: 5123211 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#229084
This fix corrects how Maltese fiscal positions map taxes for EU and non-EU partners. It ensures sales taxes map to sales taxes and purchase taxes map to purchase taxes at matching rates, reducing the risk of incorrect tax treatment in Maltese accounting.
Original PR description
### Steps to reproduce: - Install "l10n_mt" and switch to a Maltese company - Check the fiscal position "EU Partner", it maps Sales taxes to Purchase ones - "Partner outside the EU" maps Purchase taxes to Sales ones ### Solution: Fix the CSV. We map the taxes respecting Sales/Purchase and with the same percentage. opw-5065298 Forward-Port-Of: odoo/odoo#230515 Forward-Port-Of: odoo/odoo#227423
This update prevents an error when users hide a rich text field that contains newly added images before saving. It helps keep form editing smooth and avoids interruptions in Studio-configured views.
Original PR description
**PROBLEM** When hiding a HtmlField field from a view with pending images in it, there is a traceback. **STEP TO REPRODUCE** 1. Using studio, create a HtmlField on the view of your choice. 2. Add a…
**PROBLEM** When hiding a HtmlField field from a view with pending images in it, there is a traceback. **STEP TO REPRODUCE** 1. Using studio, create a HtmlField on the view of your choice. 2. Add a checkbox next to it, and link the HtmlField visibility to the button. 3. Add a image to the HtmlField (don't save the record !) 4. Hide the HtmlField using the checkbox, there should be a traceback. (if not, try with a bigger image). **CAUSE** commitChanges() will try to retrieve the field value to commit by looking at the related element in the DOM. Before retrieving this value, we call savePendingImages() to save the new images added to the HtmlField. https://github.com/odoo/odoo/blob/1416aad902a97ce56aaecc2aadc4dd9f7814ee53/addons/html_editor/static/src/fields/html_field.js#L159-L162 This introduces a delay, during which the DOM element could be destroyed. **FIX** We don't call commitChanges() in OnBlur(). Instead, we cache the new value in a property of HtmlField called `newValue` when `OnChanges()` is called. Inside OnBlur(), we save the pending images by directly calling `savePendingImages()` and we commit the new value by calling `updateValue(this.newValue)` opw-5061820 Forward-Port-Of: odoo/odoo#227482
Shipping label printing can now use a selected printer for each delivery operation type instead of automatically using the first compatible printer. This helps businesses route labels to the right printer by workflow or warehouse area, reducing misprints and manual intervention.
Original PR description
Printing shipping labels is performed from the backend, once the shipping info are received in the chatter. The printing command is sent to the frontend via the user bus, then though longpolling to the iot box. This commit adds the possibility to select a printer instead of choosing automatically the first (with the right report associated) on the list. As the change is made on a stable version, we are using system parameters to store the selected printer without adding a new field. We associate a printer with the picking type, in order for to be able to have different printers by default on different picking types. Task: 4792491 Forward-Port-Of: odoo/enterprise#95603 Forward-Port-Of: odoo/enterprise#86818
Invoices eligible for an early payment discount are no longer incorrectly marked as fully paid when only a partial payment is received. The paid amount is applied correctly, keeping the invoice partially paid and avoiding incorrect suspense account entries.
Original PR description
Problem: If partial payment is done for Invoice which is eligible for early payment discount, Invoice is marked as paid and remaining amount is debited in suspense account. Cause: While preparing credit entry for receivable account, only eligibility of Invoice for early payment discount was checked and whole residual amount of Invoice is credited instead of amount which is paid, and this is done for partial payments also(which shouldn't be done). After this commit: If partial payment is done for Invoice which is eligible for early payment discount, Invoice is marked as partially paid and only amount which is paid is credited from receivable account and nothing in suspense account. task-5128802
Fixed an issue where point-of-sale payment shortcut buttons could add the wrong amount for users whose language uses a comma as the decimal separator. This prevents inflated payment totals and helps cashiers process payments accurately in affected locales.
Original PR description
**Steps to reproduce:** - Set your database in a language with a "," as a decimal separator, such as French - Make a purchase, chose a payment method - Before paying, click any +10/20/50 button - The…
**Steps to reproduce:** - Set your database in a language with a "," as a decimal separator, such as French - Make a purchase, chose a payment method - Before paying, click any +10/20/50 button - The price will be multiplied by 100, then add the desired amount **Why the fix:** There were two places where the decimal separator was causing issues. First when we try to get the current price, *currentBufferValue*, we try to get it when it's in float state, but as we have a language with a decimal separator set as "," the "." in this float will be ignored, and we will take the decimal as units as well, explaining the *100 amount, because the decimals become whole numbers. Secondly, when we try to make the addition of the two and convert it to string again, the *toString* method will convert it with a default "." not taking the current decimal separator into account. Once again, the "." will be ignored later on, leading to an even more over the top number. We now convert the numbers and the strings using the correct decimal separator. opw-5126224
Auto-forwarded emails could incorrectly add extra recipients as followers when alias matching was configured to use the email name before the @ sign. This fix restores the expected matching behavior so only the intended recipients are linked, reducing unwanted follower additions and notifications.
Original PR description
Sending an email that was auto-forwarded would lead to the recipient line having two different emails which would cause any emails that were not set up as aliases to be added as followers even if…
Sending an email that was auto-forwarded would lead to the recipient line having two different emails which would cause any emails that were not set up as aliases to be added as followers even if local part detection was enabled in the alias settings. This was due to the fact that partner detection was changed in 18.2 and now looked for exact email to alias matches. Ban emails were passed to the _find_or_create_from_emails and then directly matched to the emails in the list of recipient emails. When a match was not found for emails that did not have an exact matching alias_full_name, we would then look for or create a partner for that email. This caused erroneous followers to be added. Changing the functionality to also look for matching local parts in order to skip partner finding and creation reverts this functionality to how it previously worked where extra recipients with matching local parts when local part detection was enabled would not add those partners as followers. opw-4896074 Forward-Port-Of: odoo/odoo#216737
This update fixes display and filtering issues on website blog pages. Dates now line up correctly in list card layouts, and selected tag filters are preserved when users add, remove, or clear date archive filters.
Original PR description
This PR addresses the following issues: **Issue 1: Date Misalignment** **Steps to Reproduce:** 1. Navigate to website → Blog Page → Edit. 2. Change the layout from Grid to List. 3. Toggle the Cards…
This PR addresses the following issues:
**Issue 1: Date Misalignment**
**Steps to Reproduce:**
1. Navigate to website → Blog Page → Edit.
2. Change the layout from Grid to List.
3. Toggle the Cards button on.
4. The date and tags will appear slightly misaligned.
**Solution:**
Adding `#{` code in the `t-attf-class` attribute will align the date with the blog post content and tags.
**Expected Behavior:**
The date should align with the blog post content and tags preview.
**Issue 2: Some Tag Filters Getting Removed**
**Steps to Reproduce:**
1. Add a date filter from the sidebar of the blog.
2. Remove this filter by clicking the X button.
3. If multiple tags are present in the filter section, only the first tag remains while the rest are removed when the date filter is added or removed.
**Solution:**
Sending a POST request whenever the date filter is selected or removed. To achieve this, we introduced the `post_link` class to the `<select>` and `<a>` elements. When a date option is chosen, the click event triggers the `_onClickPost` handler
function, which extracts the URL from the `value` attribute of the `<option>` tag.
**Expected Behavior:**
All previously added tags should remain after adding or removing the date filter.
**Issue 3: All Tag Filters Getting Removed**
**Steps to Reproduce:**
1. Navigate to website → Blog Page → Turn On the Sidebar.
2. Select any tag from the tags section in the sidebar.
3. Ensure no blog is selected.
4. Select a date from the archives in the sidebar.
5. Change the date to '-- All Dates' in the archives dropdown.
6. All tags in the filter are removed along with the date.
**Solution:**
Removing the condition for navigation based on whether a blog is present or not will ensure tags remain in the filter section after selecting the '-- All Dates' option.
**Expected Behavior:**
Tags present in the filter section should remain after selecting the '-- All Dates' option.
task-3937884
Forward-Port-Of: odoo/odoo#230313
Forward-Port-Of: odoo/odoo#225845UrbanPiper POS orders now apply the right taxes when a point of sale belongs to a branch and the tax is defined on the parent company. This prevents under-taxed orders and also supports split taxes such as GST components.
Original PR description
Steps to reproduce: --- - Install `pos_urban_piper`. - Create a branch under *Main Company*. - Switch to the new branch. - Create a POS config in this branch and set up UrbanPiper. - Sync "Apple Pie". - Place an order with "Apple Pie". Issue: --- - The 15% tax defined on Apple Pie is not applied on the orderline. Cause: --- - While creating the order line, the tax company was compared directly with the POS config’s company. In this case, the tax belongs to the parent company, while the POS config belongs to a child company. Fix: --- - Compare the `root_id` of both companies instead of the direct company ID to ensure taxes are applied correctly in multi-branch setups. - Additionally, handled the case where a main tax has sub-taxes (e.g., 5% GST split into 2.5% SGST and 2.5% CGST). In such cases, we now fetch the tax type from the sub-taxes instead of the main tax. Task-5050682 Forward-Port-Of: odoo/enterprise#93467
Point of Sale loyalty rewards now only grant points when an order meets the program’s item quantity rules. This prevents customers from incorrectly earning points or losing too many points when redeeming a free product.
Original PR description
Loyalty points were not being awarded correctly for some orders. The system granted points even when the minimum required quantity of items was not reached. In some cases, it also added negative…
Loyalty points were not being awarded correctly for some orders. The system granted points even when the minimum required quantity of items was not reached. In some cases, it also added negative loyalty points, which led to an excessive deduction for the customer —sometimes just for claiming a single free product. > Setup of the Loyalty Program (Discount & Loyalty): Program Type : Loyalty Card Rule : minimum 5 items => 10 Loyalty Points per $ Reward : Free product (Simple Pen) => in exchange of 5 Loyalty Points Steps to reproduce: ------------------- * Open the pos Shop * Select a customer with loyalty points * Add a Simple Pen * Click on * Reward > Free Product - Loyalty Program > Observation: Customer shouldn't 'win' points here New Total is mathematically correct but not logic Why the fix: ------------ We need to verify that the order is eligible to generate reward points based on the configured rules, before adding the won points. opw-4914774 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#230166 Forward-Port-Of: odoo/odoo#221570
Website visitors and editors can now keep multiple selected tags when refreshing, opening the editor, or using search on blog and eLearning pages. This prevents filters from unexpectedly resetting and makes browsing tagged content more reliable.
Original PR description
Before the change in the blog/slides pages of a website every tag but one disappears when opening the editor or when the search bar is used. Steps to reproduce: - Log in Odoo with a user that can access the website editor Open the Website - Install the blog app if it is not already present - Open the blog app - Click on two or more tags to add them to the filter Open the Website editor or use the search bar - Every tag but one will be removed After the change all the tags will be kept when opening the editor or using the searchbar. task-4216129 Fixes #164577 Forward-Port-Of: odoo/odoo#226898
This fix prevents an error during module uninstallation that could leave database structures only partially removed. It helps ensure related apps such as Resource and Worksheet can be uninstalled and reinstalled cleanly without causing setup issues.
Original PR description
Recently pull request https://github.com/odoo/enterprise/pull/86084 introduced an ondelete method on `ir.model` that retrieves some worksheet templates to delete them. However, this method breaks…
Recently pull request https://github.com/odoo/enterprise/pull/86084 introduced an ondelete method on `ir.model` that retrieves some worksheet templates to delete them. However, this method breaks when uninstalling module `worksheet`:
```
ir.model.data._module_data_uninstall():
... records are deleted ...
ir.model.fields.unlink():
drop column of corresponding fields
delete ir.model.field records
ir.model.unlink():
drop table of corresponding models
ir.model._unlink_if_uninstalling():
self.env['worksheet.template'].search([('model_id', ...)]).unlink()
delete ir.model records
```
The call to `ir.model.unlink()` crashes when searching for worksheet templates, since column `model_id` has been dropped already. This makes the transaction fail, and it is rolled back to a savepoint just before the call to `ir.model.unlink()`. In other words, the uninstallation manages to drop most of the columns that must go, but fails to drop all the tables that must go. And the uninstallation proceeds anyway...
Now consider uninstalling module `resource`. That module defines model `resource.calendar` with required field `name`, and also defines a record in that model (a default calendar). When the module is uninstalled, module `worksheet` is also uninstalled (because it depends on `resource`), and so the situation above happens. Consequently, most of the columns of table `resource_calendar` are dropped, but the table is not. If we reinstall module `resource` after that, the ORM re-creates column `name` (which is `NULL` on the default calendar at least), but fails to add the `NOT NULL` constraint on that column.
The fix consists in avoiding the `search()` above in the ondelete method if the column `model_id` does not exist anymore.
Forward-Port-Of: odoo/enterprise#96845This fix makes Odoo remember where users were on a page when they return to kanban, pivot, and mobile list views. It improves navigation continuity, especially when switching views or using breadcrumbs, so users do not need to manually find their previous position again.
Original PR description
When coming back to a view using the breadcrumb or with the view switcher, we want to restore the local state of the view as it was when we left it, in particular the scroll position. This is handled…
When coming back to a view using the breadcrumb or with the view switcher, we want to restore the local state of the view as it was when we left it, in particular the scroll position. This is handled by the `useSetupAction` hook, for all views (except for the list as the scrolling container is custom, because of the fixed table header). However, since [1], it was no longer working in kanban, pivot and list (mobile only). This was due to the fact that those views are now "lazy", i.e. they are rendered directly, without the data, such that the control panel is available asap. As a consequence, when `onMounted` is called (i.e. when the hook attempts to restore the scroll position), there's no scrollable content yet. This commit fixes the issue by allowing the controllers to restore the scroll position themselves, when their content is ready. In addition, a custom treatment was necessary for the kanban view, in mobile *and* if grouped, as each column has its own vertical scrollbar. [1] https://github.com/odoo/odoo/pull/205129 task~5086324 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
Products missing key setup, such as a bill of materials or vendor, will now appear on the replenishment report much earlier instead of only on the delivery date. This gives teams more time to notice configuration gaps and fix them before they affect purchasing, manufacturing, or deliveries.
Original PR description
Before this commit, RR for unconfigured products (no BoM/ no vendor), was not created until the same day of the delivery date (lead_time=0). Now, RR for unconfigured products is created considering the lead_time is incremented by 365 days. Note that this commit reverts the effect of the commit: https://github.com/odoo/odoo/commit/40d0bc0df0dc09f5138aa747cbbc715ae77f104c It's functionally decided to make the total lead_days for products with no bom to be 365 days without adding the security_lead_days. It's meant just to warn the user on the RR dashboard that the product needing replenishment is not configured, no matter to the security_lead_days in this case. Task-4779057 Forward-Port-Of: odoo/odoo#216293
Fixes an issue where returning a non-rental item included in a rental order could leave the sale order showing an incorrect delivered quantity. This helps sales and warehouse teams keep delivery status and invoicing information accurate after returns.
Original PR description
**Issue**: Returning a non-rental product in a rental order does not correctly update the delivered quantity. **Steps to reproduce**: - Enable rental transfers via Settings > Rental. - Create a…
**Issue**: Returning a non-rental product in a rental order does not correctly update the delivered quantity. **Steps to reproduce**: - Enable rental transfers via Settings > Rental. - Create a rental order with (in that order!): - A rental product - A non-rental product - Confirm the rental order. - Open the related sale order. - Go to the delivery and validate it. - Return the delivery and validate the return. - Observe that the delivered quantity in the sale order is incorrect. **Cause**: The [_get_outgoing_incoming_moves](https://github.com/odoo/odoo/blob/ea6776f095d556e3429d2b847a66f78f2e866380/addons/sale_stock/models/sale_order_line.py#L200C17-L200C85) method fails to detect incoming moves when the destination location has `usage='internal'` (as in rental flows), instead of `customer` (see [_is_outgoing()](https://github.com/odoo/odoo/blob/ea6776f095d556e3429d2b847a66f78f2e866380/addons/stock/models/stock_location.py#L464)). This causes the delivery quantity not to be decremented on return. **Solution**: Relax `_is_incoming()` logic to consider moves as incoming if they come from a rental and go to an internal location. opw-4894358 Forward-Port-Of: odoo/odoo#222093
Returning non-rental items from a rental order now updates delivered quantities correctly. Rental item returns are also handled so they do not incorrectly reduce delivered quantities, improving order accuracy and reducing manual corrections.
Original PR description
**Issue**: Returning a non-rental product in a rental order does not correctly update the delivered quantity. **Steps to reproduce**: - Enable rental transfers via Settings > Rental. - Create a…
**Issue**: Returning a non-rental product in a rental order does not correctly update the delivered quantity. **Steps to reproduce**: - Enable rental transfers via Settings > Rental. - Create a rental order with (in that order!): - A rental product - A non-rental product - Confirm the rental order. - Open the related sale order. - Go to the delivery and validate it. - Return the delivery and validate the return. - Observe that the delivered quantity in the sale order is incorrect. **Cause**: The [_get_outgoing_incoming_moves](https://github.com/odoo/odoo/blob/ea6776f095d556e3429d2b847a66f78f2e866380/addons/sale_stock/models/sale_order_line.py#L200C17-L200C85) method fails to detect incoming moves when the destination location has `usage='internal'` (as in rental flows), instead of `customer` (see [_is_outgoing()](https://github.com/odoo/odoo/blob/ea6776f095d556e3429d2b847a66f78f2e866380/addons/stock/models/stock_location.py#L464)). This causes the delivery quantity not to be decremented on return. **Solution**: Relax `_is_incoming()` logic to consider moves as incoming if they come from a rental and go to an internal location. **Additional fix**: [This commit](https://github.com/odoo/odoo/commit/886b3ea5d463722413f3cae14d4be1ad5fc88ab9) changed the default of `to_refund` to `True`. Combined with [this change](https://github.com/odoo-dev/odoo/blob/1e7ffa60dc1495243d8d99ac03c1701fbd056fe1/addons/sale_stock/models/sale_order_line.py#L330C13-L330C94), returning a rental product is treated as an incoming move, which incorrectly decreases the delivered quantity. To fix this, rental products are never marked as refundable when the SO is created: we adapt the procurement value to set `to_refund=False` on rental return moves. This ensures the delivered quantity is correctly updated for rental products, while non-rental products in a rental context remain refundable. opw-4894358 Forward-Port-Of: https://github.com/odoo/enterprise/pull/91825
This fix prevents the Colombian online checkout address form from getting stuck when shoppers select certain tax obligation options. Customers can now save their address and continue to delivery as expected, reducing checkout interruptions for Colombian websites.
Original PR description
Problem: When there is an obligation type code with id greater than 9, and it is selected in the dropdown of the website sale address form for obligation type, the screen keeps loading forever and…
Problem: When there is an obligation type code with id greater than 9, and it is selected in the dropdown of the website sale address form for obligation type, the screen keeps loading forever and there is an “expected singleton” traceback in the logs. This is because in the method `_parse_form_data` in `l10n_co_website_sale`, the obligation type field on `form_data` is set to be a list of “type ids” which leads to an error when `convert_to_cache` is called as the browse function in this attempts to convert the list to a tuple of single characters. For example, if the list is ["10"], it gets converted to ("1","0") hence leading to the expected singleton traceback.
Purpose: Instead of passing a form list to form_data,we pass the record set which will correctly set the values in the address, much like how `default_obligations_ids` is also currently set. After this correction, the website address screen will save the address properly and redirect to the delivery screen for further actions.
Steps to Reproduce on Runbot:
1. Create a Colombian company, make sure l10n_co is installed
2. Set the company on the website to this company
3. Ensure that there is a record in the table `l10n_co_edi_obligation_type_ids` with id > 9. Create one if it does not exist.
4. Open the /shop page in incognito mode as a public user.
5. Add a product, go to the checkout page, proceed to the address page.
6. Enter all the information including the Identification Number (e.g. 623.456.789-1). Choose “NIT” in identification type and select the type code from step 3 in the dropdown for obligation type. Choose country “Colombia” along with a state and city
7. Click on "Continue checkout". The page gets stuck in a loading state
forever.
opw-4776301
Forward-Port-Of: odoo/enterprise#90862This fix prevents Field Service report cleanup logic from failing when related worksheet data has already been removed during module uninstallation. It helps avoid incomplete uninstallations that can later cause reinstall problems or database consistency issues.
Original PR description
Recently pull request https://github.com/odoo/enterprise/pull/86084 introduced an ondelete method on `ir.model` that retrieves some worksheet templates to delete them. However, this method breaks…
Recently pull request https://github.com/odoo/enterprise/pull/86084 introduced an ondelete method on `ir.model` that retrieves some worksheet templates to delete them. However, this method breaks when uninstalling module `worksheet`:
```
ir.model.data._module_data_uninstall():
... records are deleted ...
ir.model.fields.unlink():
drop column of corresponding fields
delete ir.model.field records
ir.model.unlink():
drop table of corresponding models
ir.model._unlink_if_uninstalling():
self.env['worksheet.template'].search([('model_id', ...)]).unlink()
delete ir.model records
```
The call to `ir.model.unlink()` crashes when searching for worksheet templates, since column `model_id` has been dropped already. This makes the transaction fail, and it is rolled back to a savepoint just before the call to `ir.model.unlink()`. In other words, the uninstallation manages to drop most of the columns that must go, but fails to drop all the tables that must go. And the uninstallation proceeds anyway...
Now consider uninstalling module `resource`. That module defines model `resource.calendar` with required field `name`, and also defines a record in that model (a default calendar). When the module is uninstalled, module `worksheet` is also uninstalled (because it depends on `resource`), and so the situation above happens. Consequently, most of the columns of table `resource_calendar` are dropped, but the table is not. If we reinstall module `resource` after that, the ORM re-creates column `name` (which is `NULL` on the default calendar at least), but fails to add the `NOT NULL` constraint on that column.
The fix consists in avoiding the `search()` above in the ondelete method if the column `model_id` does not exist anymore.
Forward-Port-Of: odoo/enterprise#96845### Steps to reproduce: - In the settings enable: "Batch, Wave & Cluster Transfers" - Create 2 deliveries - Barcode > operations > Delivery orders > Batches > New - Add your two deliveries and…
### Steps to reproduce: - In the settings enable: "Batch, Wave & Cluster Transfers" - Create 2 deliveries - Barcode > operations > Delivery orders > Batches > New - Add your two deliveries and confirm - Scan WH-Stock #### > The scan fails considering you scanned each letter independently. ### Cause of the issue: When the barcode is scanned a call of the split barcode will be launched to split the barcode in multiple barcodes according to the `barcode_separator_regex` present in the config: https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/static/src/models/barcode_model.js#L613-L632 The issue lies in the fact that even thought the is `barcode_separator_regex` was conrrectly populated at the onWillStart of the mainComponent: https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/static/src/components/main.js#L209-L213 https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/controllers/stock_barcode.py#L97 https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/static/src/components/main.js#L229 https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/static/src/models/barcode_picking_model.js#L36-L38 It was reset by the batch confirmation here: https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode_picking_batch/static/src/models/barcode_picking_batch_model.js#L123-L135 because this part of the config is not meant to be returned by the private method `_get_barcode_data` but rather by public complete version `get_barcode_data`: https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/controllers/stock_barcode.py#L91-L98 Now, since no `barcode_separator_regex` was provided to our new config, each character will be considered to be considered as an independent barcodes and the `WH-Stock` barcode will not match any location. opw-5062331 Forward-Port-Of: odoo/enterprise#95295 Forward-Port-Of: odoo/enterprise#94056
Salary simulation pages opened from recruitment offers now use the correct company context when loading allowed benefits. This ensures candidates and HR teams see up-to-date benefit values for the relevant company instead of defaults from another company.
Original PR description
in this commit, fixes issue when open simulation page through recruitment offer values of benefits not updated. issue: get only default first company while triggering get white list method. task-4929771 Forward-Port-Of: odoo/enterprise#95866
Appointment video call links now use the website tied to the appointment type, so businesses with multiple websites or custom domains get the correct link. This prevents customers from receiving video meeting URLs with the wrong website address.
Original PR description
**Steps to reproduce:** - Create 2 companies - Create a website for each company - Set a custom website domain on the second one - Create appointement type for each website - Create an appointement on both websites - The link created for the video call has the wrong base for one of them **Issue:** Appointment `get_base_url` finds its base_url without considering the current website. **Fix:** Compute the base_url according to the appointement type to ensure the current website is taken into account. opw-4880715 Forward-Port-Of: odoo/enterprise#96826 Forward-Port-Of: odoo/enterprise#92734
This fix prevents completed tax returns from having their deadlines changed when company reminder settings are updated. It also ensures return deadlines are correctly applied for each company in multi-company setups, improving reliability for compliance tracking.
Original PR description
And remove _inverse_deadline_days_delay since _compute_deadline already does everything. To Replicate: - open the returns - mark as completed or complete at least one return - change the deadline_days_delay for that return type - It doesn't change the deadline of completed returns this is working as expected - change the account_return_reminder_day of the company - now it updates the deadline of already existing returns. Forward-Port-Of: odoo/enterprise#95739
Indian GST return processing now looks for a purchase journal across all companies in a tax unit, rather than only the main company. This prevents record creation failures when the main company lacks a purchase journal but another company in the tax unit has one configured.
Original PR description
Before this PR: - The system searched for a purchase journal only in `company_id`. - In a tax unit with multiple companies, if the main company had no purchase journal configured, record creation failed with a 'NOT NULL constraint violated' error. After this PR: - The journal search now checks all companies in `company_ids` (or falls back to `company_id`), - allowing the system to find a valid purchase journal across the tax unit. OPW: 5159518 Forward-Port-Of: odoo/enterprise#96919 Forward-Port-Of: odoo/enterprise#96838
Fixes an issue where Colombian online shoppers could get stuck on the address step when choosing certain tax obligation options. The checkout now saves the address correctly and continues to delivery, reducing failed orders and support friction.
Original PR description
Problem: When there is an obligation type code with id greater than 9, and it is selected in the dropdown of the website sale address form for obligation type, the screen keeps loading forever and…
Problem: When there is an obligation type code with id greater than 9, and it is selected in the dropdown of the website sale address form for obligation type, the screen keeps loading forever and there is an “expected singleton” traceback in the logs. This is because in the method `_parse_form_data` in `l10n_co_website_sale`, the obligation type field on `form_data` is set to be a list of “type ids” which leads to an error when `convert_to_cache` is called as the browse function in this attempts to convert the list to a tuple of single characters. For example, if the list is ["10"], it gets converted to ("1","0") hence leading to the expected singleton traceback.
Purpose: Instead of passing a form list to form_data,we pass the record set which will correctly set the values in the address, much like how `default_obligations_ids` is also currently set. After this correction, the website address screen will save the address properly and redirect to the delivery screen for further actions.
Steps to Reproduce on Runbot:
1. Create a Colombian company, make sure l10n_co is installed
2. Set the company on the website to this company
3. Ensure that there is a record in the table `l10n_co_edi_obligation_type_ids` with id > 9. Create one if it does not exist.
4. Open the /shop page in incognito mode as a public user.
5. Add a product, go to the checkout page, proceed to the address page.
6. Enter all the information including the Identification Number (e.g. 623.456.789-1). Choose “NIT” in identification type and select the type code from step 3 in the dropdown for obligation type. Choose country “Colombia” along with a state and city
7. Click on "Continue checkout". The page gets stuck in a loading state
forever.
opw-4776301
Forward-Port-Of: odoo/enterprise#90862This change prevents an uninstall process from failing when worksheet-related database fields have already been removed. It helps avoid incomplete uninstalls that could cause problems when reinstalling dependent modules later.
Original PR description
Recently pull request https://github.com/odoo/enterprise/pull/86084 introduced an ondelete method on `ir.model` that retrieves some worksheet templates to delete them. However, this method breaks…
Recently pull request https://github.com/odoo/enterprise/pull/86084 introduced an ondelete method on `ir.model` that retrieves some worksheet templates to delete them. However, this method breaks when uninstalling module `worksheet`:
```
ir.model.data._module_data_uninstall():
... records are deleted ...
ir.model.fields.unlink():
drop column of corresponding fields
delete ir.model.field records
ir.model.unlink():
drop table of corresponding models
ir.model._unlink_if_uninstalling():
self.env['worksheet.template'].search([('model_id', ...)]).unlink()
delete ir.model records
```
The call to `ir.model.unlink()` crashes when searching for worksheet templates, since column `model_id` has been dropped already. This makes the transaction fail, and it is rolled back to a savepoint just before the call to `ir.model.unlink()`. In other words, the uninstallation manages to drop most of the columns that must go, but fails to drop all the tables that must go. And the uninstallation proceeds anyway...
Now consider uninstalling module `resource`. That module defines model `resource.calendar` with required field `name`, and also defines a record in that model (a default calendar). When the module is uninstalled, module `worksheet` is also uninstalled (because it depends on `resource`), and so the situation above happens. Consequently, most of the columns of table `resource_calendar` are dropped, but the table is not. If we reinstall module `resource` after that, the ORM re-creates column `name` (which is `NULL` on the default calendar at least), but fails to add the `NOT NULL` constraint on that column.
The fix consists in avoiding the `search()` above in the ondelete method if the column `model_id` does not exist anymore.
Forward-Port-Of: odoo/enterprise#96845This fixes an issue where a document selected for a draft chatter note could become linked to the underlying record before the note was posted. Attachments now stay tied to the draft composer until the user posts the message, preventing unintended document links and disruptive preview behavior.
Original PR description
When adding attachment from documents in the composer, link the attachment to the composer and not to the thread as it must be linked to the thread only once the message is posted. How to reproduce: - Install the app documents and crm - Open a lead - In the chatter click on "Log a note" - Then click on "Add from Documents" - Select a document and click on "Add from Documents" - Reload the page without posting the message The attachment selected in document is now linked to the lead which shouldn't be the case. Note that if you do the same for an expense, as the attachment is linked to the expense right away when added, the preview panel open immediately, and you have to reopen "Log a note". That was the original bug detected. Task-5075835
Fixed an issue where changing a coupon reward on a confirmed sales order could deduct the wrong number of points. Coupon balances now stay accurate when customers switch rewards, reducing billing and loyalty program discrepancies.
Original PR description
Versions -------- - 17.0+ Steps ----- 1. Have a coupon program; 2. add a 10% discount on order reward for 1 point; 3. add a 50% discount on order reward for 5 points; 4. generate a coupon with 10…
Versions -------- - 17.0+ Steps ----- 1. Have a coupon program; 2. add a 10% discount on order reward for 1 point; 3. add a 50% discount on order reward for 5 points; 4. generate a coupon with 10 points; 5. use coupon code on a confirmed order; 6. select 10% discount reward; 7. change to a 50% discount reward; 8. check coupon point total. Issue ----- Even though the 5 point reward was used, only 4 out of 10 points remain. Cause ----- When updating the reward line of a confirmed order, it keeps track of point cost changes before & after a write. Its purpose is to restore back the point difference on the coupon record. The issue is that while point changes are stored, coupon changes are not. When updating reward lines, `_reset_loyalty` is used, which removes the `coupon_id` from the lines. As a consequence, attempting to restore the point difference on `line.coupon_id` after an update, it writes to an empty record. Solution -------- Store both coupons & their used points before write. After write, restore the previous points to the previous coupon, and subtract the current point cost from the current coupon. This way, any combination of coupon/point changes should have the points updated as expected. opw-4910922 Forward-Port-Of: odoo/odoo#230907 Forward-Port-Of: odoo/odoo#222054
This fix makes all fields and action buttons in the appraisal skills list accessible again on mobile devices. Employees and managers can now scroll horizontally to view justification details and add or remove skill entries as intended.
Original PR description
Horizontal scrolling has been disabled on the appraisal skills list. An unwanted side effect of that is that the justification field along with the add and remove buttons are not visible on mobile. This PR re-enables the scrolling and removes some dead css. task-5001344 Forward-Port-Of: odoo/enterprise#96579 Forward-Port-Of: odoo/enterprise#91882
Location barcode images are now hidden when the stored barcode contains characters that cannot be displayed in the required format. This prevents upgrade failures for customers with unsupported barcode values while keeping valid barcodes visible as before.
Original PR description
A new field `barcode_img` was added odoo/enterprise@53d008e9ce11bbf870e5d2f248fd591fa679be0e to display location barcodes in the form view. It uses the `barcode` field of the location, but some clients have values with unsupported characters (e.g., `Ž`, `بيع`) that cannot be encoded in Code128. This caused upgrade failures as such barcodes could not be rendered. Now, Don't show barcode in the form view if it fails to render. opw-5129150
Video call links for appointments now use the correct website address when multiple company websites are configured. This prevents customers from receiving links with the wrong domain, improving reliability for businesses running appointments across different websites.
Original PR description
**Steps to reproduce:** - Create 2 companies - Create a website for each company - Set a custom website domain on the second one - Create appointement type for each website - Create an appointement on both websites - The link created for the video call has the wrong base for one of them **Issue:** Appointment `get_base_url` finds its base_url without considering the current website. **Fix:** Compute the base_url according to the appointement type to ensure the current website is taken into account. opw-4880715 Forward-Port-Of: odoo/enterprise#96826 Forward-Port-Of: odoo/enterprise#92734
Batch transfer confirmation now preserves the barcode settings needed to read location barcodes correctly. This prevents scans such as WH-Stock from being split into individual characters, allowing warehouse staff to continue batch picking without scan failures.
Original PR description
### Steps to reproduce: - In the settings enable: "Batch, Wave & Cluster Transfers" - Create 2 deliveries - Barcode > operations > Delivery orders > Batches > New - Add your two deliveries and…
### Steps to reproduce: - In the settings enable: "Batch, Wave & Cluster Transfers" - Create 2 deliveries - Barcode > operations > Delivery orders > Batches > New - Add your two deliveries and confirm - Scan WH-Stock #### > The scan fails considering you scanned each letter independently. ### Cause of the issue: When the barcode is scanned a call of the split barcode will be launched to split the barcode in multiple barcodes according to the `barcode_separator_regex` present in the config: https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/static/src/models/barcode_model.js#L613-L632 The issue lies in the fact that even thought the is `barcode_separator_regex` was conrrectly populated at the onWillStart of the mainComponent: https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/static/src/components/main.js#L209-L213 https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/controllers/stock_barcode.py#L97 https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/static/src/components/main.js#L229 https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/static/src/models/barcode_picking_model.js#L36-L38 It was reset by the batch confirmation here: https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode_picking_batch/static/src/models/barcode_picking_batch_model.js#L123-L135 because this part of the config is not meant to be returned by the private method `_get_barcode_data` but rather by public complete version `get_barcode_data`: https://github.com/odoo/enterprise/blob/aeb9343f4b7dfab0fbc04bca4623ae85b3ea6030/stock_barcode/controllers/stock_barcode.py#L91-L98 Now, since no `barcode_separator_regex` was provided to our new config, each character will be considered to be considered as an independent barcodes and the `WH-Stock` barcode will not match any location. opw-5062331 Forward-Port-Of: odoo/enterprise#95295 Forward-Port-Of: odoo/enterprise#94056
This fix ensures purchase stock valuations based on vendor bills correctly account for differences in units of measure and currency. Businesses get more accurate inventory values and financial reporting when bills use different units or currencies than the related stock move.
Original PR description
Currently the move valuation base on BILL use the value define on the BILL without checking the currency nor the UoM. 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 payroll work entries from crashing or staying in the wrong status when no work entry type is selected. Entries without a type are now handled consistently as conflicts, helping users spot and correct incomplete records instead of encountering errors.
Original PR description
If the user creates a work entry without a work entry type, it will fetch "false" id work entry type. It raises a traceback task-5078885
This fix ensures that status indicators show the latest value after a record is moved or updated elsewhere. Users will no longer see outdated stages when returning to a form view, improving confidence in pipeline and workflow data.
Original PR description
Before this commit, there was a race condition with the statusbar field because of which the current status wasn't correctly updated when the rpc returned. For instance, in CRM pipeline, open the records in form view (to put them in cache). Then, go back in kanban and drag a record from a column to another. Re-open a record in form view, and use to pager to browse to the updated record. It still displayed the former value. This was due to an optimization attempt to prevent from re-computing too often the items of the statusbar. 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 ensures time off entries in the French HR localization use the employee's own working schedule, even when it starts earlier or ends later than the company's schedule. This prevents incorrect leave hour totals in timesheets and payroll-related records.
Original PR description
This bug is in France localization. In some cases employee schedule seems ignored in timesheet entry (`account.analytic.line`) creation, and the duration field is created using the company schedule.…
This bug is in France localization. In some cases employee schedule seems ignored in timesheet entry (`account.analytic.line`) creation, and the duration field is created using the company schedule. The reason is the case which the employee schedule starts before company scheudle or ends after it. To reproduce the bug: 1- Make a db with fr company (install l10n_fr) 2- Make two working schedule: - Company schedule with working day on Monday from 8:00-12:00 13:00-17:00 - Employee schedule with working day on Monday from 8:30-12:25 13:30-17:15 3- Assign company schedule to company in `Company Working Hours` in Setting and apply employee schedule to an employee from `Payroll` tab of employee 4- Allocate some time off to the employee and take a time off on Monday 5- Check the work entries for the day you took the day off on timesheet app 6- 7:24 `Worked Hour` is shown instead of 7:40 The bug occurs because in calling `adjust_date_range`, the case which employee's schedule ends after company schedule is not considered. opw-4868643 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#230621 Forward-Port-Of: odoo/odoo#222262
This change rolls back earlier accounting changes for manufacturing unbuild operations because they caused inconsistent stock valuation and errors in some cost scenarios. The team is returning to the previous behavior while a cleaner long-term solution is prepared.
Original PR description
This commit reverts [1], [2], [3], and [4]. (It actually results in minimal changes since those commits were already removing parts of each other.) Issue before those commits: 1. Setup a auto-fifo…
This commit reverts [1], [2], [3], and [4]. (It actually results in minimal changes since those commits were already removing parts of each other.) Issue before those commits: 1. Setup a auto-fifo category and two storable products (a component and a finished product) 2. Receive one compo at 10, then one at 25 3. Produce two MO with one finished product 4. Unbuild the second one Error: - For the component, we just use the value of the consumed components: IN 1 @ 25 - For the finished product, we process it as a classic out. Reminder, we are in FIFO: OUT 1 @ 10 As a result, thanks to the unbuild, we have created - A over-valuation of the stock (+15) - An outstanding balance of the "Cost of Production" This is why [1] has been merged. However, it brought some other issues, cf [2], [3] and [4]. Unfortunately, it still has some issues - After the above use case, the difference between the debit and the credit of the stock valuation account is no longer the sum of the remaining values of the layers - Adding some landed costs on MOs will lead to a traceback when undbuilding - The over-valuation of the stock (that was already present before [1], cf above) is still present Following some discussions with R&D and the product owners, we have decided to start over from scratch, which means: - Revert all commits - Try another approach (if so, the new PR will be linked to the PR related with this commit) [2], [3], and [4] are partially reverted: the tests can remain, as they were only failing due to a sequence of changes. [1] https://github.com/odoo/odoo/commit/84dda968146d2f3743ab7fc516300e50780725e3 [2] https://github.com/odoo/odoo/commit/49565cdd9007ac66a3b835dc073777e2e6c48f2c [3] https://github.com/odoo/odoo/commit/3a69456a291da593748475c86e7efc6234019e47 [4] https://github.com/odoo/odoo/commit/fb30cde9a320c245cf1321c9dc2ea2e67a53d0a0 OPW-5036574 Forward-Port-Of: odoo/odoo#226380 Forward-Port-Of: odoo/odoo#225728
Belgian Group S payroll reports can now be generated without triggering an error. This ensures payroll teams can complete the report export process reliably, with test coverage added to help prevent the issue from returning.
Original PR description
Generating a Group S report caused a traceback. Fixed by replacing 'date_start' with 'date' in the 'l10n.be.hr.payroll.export.group.s' model. Added a test to validate the change is working with the whole flow from creating a work entry till exporting the file. task-5005925
Spanish point-of-sale orders now keep the cashier’s selected fiscal position during payment validation instead of reverting to the default. This prevents incorrect tax amounts from appearing as change on receipts when taxes were intentionally removed or changed before payment.
Original PR description
Currently, when you use a default fiscal position in the pos, if you switch to no fiscal position, upon order validation the tax amount is counted as change. Steps to reproduce: ------------------- *…
Currently, when you use a default fiscal position in the pos, if you switch to no fiscal position, upon order validation the tax amount is counted as change. Steps to reproduce: ------------------- * Install l10n_es_pos, switch to es company * In the config of a shop, use fiscal position, set some as available, one as default * Open shop session * Add a product that has taxes * Switch fiscal position to one that has 0% taxes * There should not be taxes in the cart at this point * Go to pay the order (cash or bank) > Observation: On the receipt the previous tax value is counted as change Why the fix: ------------ The issue happens because of the simplified invoice mechanism present in the ES localization. When you validate an order and that order can apply for simplified invoice, if there is no customer on the order the partner is set with the simplified partner. When setting a partner on the order we update the fiscal position and pricelist. https://github.com/odoo/odoo/blob/1358f93a4c73de5a28cda72ec78769625c863efd/addons/point_of_sale/static/src/app/models/pos_order.js#L929 The fiscal position is updated with the partner's fiscal position or the default one if none on the partner. https://github.com/odoo/odoo/blob/1358f93a4c73de5a28cda72ec78769625c863efd/addons/point_of_sale/static/src/app/models/pos_order.js#L986-L995 Instead of the fallback on the default fiscal position in the case it is not set on a partner we fallback on the order current fiscal position. If it is different than the default one is means that it was changed intentionally and there's a high chance we want to keep it, otherwise it will already be the default fp. opw-5051231 Forward-Port-Of: odoo/odoo#229237
Restaurant point-of-sale bill splitting now correctly closes once the last split item has been paid. This prevents staff from seeing an empty bill-splitting screen after the bill is fully settled, reducing confusion during payment workflows.
Original PR description
When splitting a bill, a specific flow would leave the bill splitting screen open event when everything was paid. Steps to reproduce: ------------------- * In pos restaurant add 2 product to the order * Select Action > Split * Select a product * Click Pay(ment) and validate the payment * Continue * Select the last product * Click Pay(ment) and validate the payment * Continue > Observation: The Bill splitting screen is still open at 0$ Why the fix: ------------ When one or more products are selected a new order is created with those products. If the quantities match, it's the last payement for that bill, we can directly pay. The original order will then be closed. opw-5006042 Forward-Port-Of: odoo/odoo#230536 Forward-Port-Of: odoo/odoo#228991
Product category images in the website Catalog dynamic block now use the correct category URL when a custom website domain is configured. This prevents broken images and keeps storefront catalog sections looking complete for visitors.
Original PR description
Steps to reproduce: ==================== - Add a Catalog dynamic block. - Set a custom domain for the website. → Product category images do not display. Why? ==== Image URLs were generated using the website base domain, not the category's base url. As a result, links pointed to non-existent resources. Fix: ==== Generate image URLs using the category URL instead of the website's base URL. opw-5143162 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix prevents failures when creating GST return records for tax units that include multiple companies. The system can now use a valid purchase journal from any company in the tax unit, reducing setup-related errors for multi-company configurations.
Original PR description
Before this PR: - The system searched for a purchase journal only in `company_id`. - In a tax unit with multiple companies, if the main company had no purchase journal configured, record creation failed with a 'NOT NULL constraint violated' error. After this PR: - The journal search now checks all companies in `company_ids` (or falls back to `company_id`), - allowing the system to find a valid purchase journal across the tax unit. OPW: 5159518 Forward-Port-Of: odoo/enterprise#96919 Forward-Port-Of: odoo/enterprise#96838
This fixes an issue where Safari users could not select a website type or objective in the website setup wizard because the dropdown closed too early. The change ensures mouse selections are recognized properly, helping users complete website creation without browser-specific disruption.
Original PR description
Problem Using Safari, in the website configuration wizard, when selecting a website type or an objective by mouse clicking, nothing would get selected, and the dropdown would close prematurely. Steps - Using Safari - In Odoo with the Website addon installed - Create a new website in the website settings - Try to select any type of website by mouse clicking - Nothing would get selected, and the dropdown closes before pointerUp Cause On Safari, buttons are not focusable by default. So if we want good accessibility on these dropdowns, a workaround is needed. Fix Delay focusout actions until a pointerUp event is triggered on the dropdown, if the Safari user uses its mouse to choose an option. task-5139708 Closes https://github.com/odoo/odoo/pull/226637
Colombian website checkout now correctly saves customer addresses when a selected tax obligation type has a double-digit identifier. This prevents the checkout page from getting stuck and allows shoppers to continue to delivery.
Original PR description
Problem: When there is an obligation type code with id greater than 9, and it is selected in the dropdown of the website sale address form for obligation type, the screen keeps loading forever and…
Problem: When there is an obligation type code with id greater than 9, and it is selected in the dropdown of the website sale address form for obligation type, the screen keeps loading forever and there is an “expected singleton” traceback in the logs. This is because in the method `_parse_form_data` in `l10n_co_website_sale`, the obligation type field on `form_data` is set to be a list of “type ids” which leads to an error when `convert_to_cache` is called as the browse function in this attempts to convert the list to a tuple of single characters. For example, if the list is ["10"], it gets converted to ("1","0") hence leading to the expected singleton traceback.
Purpose: Instead of passing a form list to form_data,we pass the record set which will correctly set the values in the address, much like how `default_obligations_ids` is also currently set. After this correction, the website address screen will save the address properly and redirect to the delivery screen for further actions.
Steps to Reproduce on Runbot:
1. Create a Colombian company, make sure l10n_co is installed
2. Set the company on the website to this company
3. Ensure that there is a record in the table `l10n_co_edi_obligation_type_ids` with id > 9. Create one if it does not exist.
4. Open the /shop page in incognito mode as a public user.
5. Add a product, go to the checkout page, proceed to the address page.
6. Enter all the information including the Identification Number (e.g. 623.456.789-1). Choose “NIT” in identification type and select the type code from step 3 in the dropdown for obligation type. Choose country “Colombia” along with a state and city
7. Click on "Continue checkout". The page gets stuck in a loading state
forever.
opw-4776301
Forward-Port-Of: odoo/enterprise#90862Purchase orders now keep the same unit of measure shown in the product catalog when products are added, avoiding accidental ordering by vendor packs instead of individual units. This helps buyers create accurate orders and prevents quantity or pricing surprises, with related tests updated for purchasing and stock workflows.
Original PR description
Steps to reproduce the bug:
- Create a storable product “P1”:
- UoM: unit
- Purchase tab:
- Vendor: Azure interior
- UoM: Pack of 6
- Create a purchase order:
- Vendor: Azure interior
- Click the Catalog button:
- Select 1 unit of P1 (note: UoM cannot be changed in the catalog)
Problem:
The purchase order line is created, but with 1 pack of 6 instead of 1 unit
Fix:
Ensure the selected product quantity and UoM from the catalog are correctly applied to the PO line.
Opw-4794362
Forward-Port-Of: odoo/odoo#227212
Forward-Port-Of: odoo/odoo#224231This fixes an issue where applying multiple global discounts to a sales order could create extra discount lines. Businesses will see cleaner, more accurate order and tax calculations when using cumulative discounts.
Original PR description
Because of the grouping on the computation_key in the taxes engine, when a second global discount was applied on a SO, it was creating two additional lines instead of one. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#230494
This fix keeps all selected tags visible when users refresh, search, or open the website editor on blog and eLearning pages. It prevents filters from being unexpectedly lost, making content browsing and editing more reliable.
Original PR description
Before the change in the blog/slides pages of a website every tag but one disappears when opening the editor or when the search bar is used. Steps to reproduce: - Log in Odoo with a user that can access the website editor Open the Website - Install the blog app if it is not already present - Open the blog app - Click on two or more tags to add them to the filter Open the Website editor or use the search bar - Every tag but one will be removed After the change all the tags will be kept when opening the editor or using the searchbar. task-4216129 Fixes #164577 Forward-Port-Of: odoo/odoo#226898
Products without a bill of materials or vendor will now appear on the replenishment report much earlier instead of only on the delivery day. This helps teams spot missing product configuration in time and avoid last-minute supply issues.
Original PR description
Before this commit, RR for unconfigured products (no BoM/ no vendor), was not created until the same day of the delivery date (lead_time=0). Now, RR for unconfigured products is created considering the lead_time is incremented by 365 days. Note that this commit reverts the effect of the commit: https://github.com/odoo/odoo/commit/40d0bc0df0dc09f5138aa747cbbc715ae77f104c It's functionally decided to make the total lead_days for products with no bom to be 365 days without adding the security_lead_days. It's meant just to warn the user on the RR dashboard that the product needing replenishment is not configured, no matter to the security_lead_days in this case. Task-4779057 Forward-Port-Of: odoo/odoo#216293
Restores the blue banner shown when staff preview sales orders and invoices in the customer portal. This makes it easy to return from portal preview back to backend edit mode, avoiding confusion and extra navigation.
Original PR description
## Versions
19.0+
## Issue
The blue banner ("This is a preview of the customer portal. → Back to edit mode") does not appear when previewing a Sale Order or Invoice from the backend.
## Steps to reproduce
Open a SO:
- Click the "Preview" button;
- The portal preview page opens, but the top blue banner to return to the backend is missing.
## Cause
This regression appeared after the QWeb refactor (https://github.com/odoo/odoo/commit/eb6e88a25050fff2bd09317739dd51ba451450df) which changed how template variables propagate:
- `t-call` is now parametric, variables defined inside a `t-call` no longer affect the outer scope;
- The inner content of a `t-call` only sees variables defined before the call;
- Lazy XML evaluation means `t-set` values defined after the layout call are not yet in scope during rendering.
Previously, `o_portal_fullwidth_alert` was set **after** the layout was called, so the variable was invisible when the alert banner was rendered.
opw-5096001This change prevents uninstalling worksheet-related modules from failing after database fields have already been removed. It helps avoid broken uninstall/reinstall flows that could leave business data tables in an inconsistent state.
Original PR description
Recently pull request https://github.com/odoo/enterprise/pull/86084 introduced an ondelete method on `ir.model` that retrieves some worksheet templates to delete them. However, this method breaks…
Recently pull request https://github.com/odoo/enterprise/pull/86084 introduced an ondelete method on `ir.model` that retrieves some worksheet templates to delete them. However, this method breaks when uninstalling module `worksheet`:
```
ir.model.data._module_data_uninstall():
... records are deleted ...
ir.model.fields.unlink():
drop column of corresponding fields
delete ir.model.field records
ir.model.unlink():
drop table of corresponding models
ir.model._unlink_if_uninstalling():
self.env['worksheet.template'].search([('model_id', ...)]).unlink()
delete ir.model records
```
The call to `ir.model.unlink()` crashes when searching for worksheet templates, since column `model_id` has been dropped already. This makes the transaction fail, and it is rolled back to a savepoint just before the call to `ir.model.unlink()`. In other words, the uninstallation manages to drop most of the columns that must go, but fails to drop all the tables that must go. And the uninstallation proceeds anyway...
Now consider uninstalling module `resource`. That module defines model `resource.calendar` with required field `name`, and also defines a record in that model (a default calendar). When the module is uninstalled, module `worksheet` is also uninstalled (because it depends on `resource`), and so the situation above happens. Consequently, most of the columns of table `resource_calendar` are dropped, but the table is not. If we reinstall module `resource` after that, the ORM re-creates column `name` (which is `NULL` on the default calendar at least), but fails to add the `NOT NULL` constraint on that column.
The fix consists in avoiding the `search()` above in the ondelete method if the column `model_id` does not exist anymore.
Forward-Port-Of: odoo/enterprise#96845This change prevents an uninstall process from failing when worksheet-related database fields have already been removed. It helps avoid incomplete module removals that could cause problems when reinstalling related apps later.
Original PR description
Recently pull request https://github.com/odoo/enterprise/pull/86084 introduced an ondelete method on `ir.model` that retrieves some worksheet templates to delete them. However, this method breaks…
Recently pull request https://github.com/odoo/enterprise/pull/86084 introduced an ondelete method on `ir.model` that retrieves some worksheet templates to delete them. However, this method breaks when uninstalling module `worksheet`:
```
ir.model.data._module_data_uninstall():
... records are deleted ...
ir.model.fields.unlink():
drop column of corresponding fields
delete ir.model.field records
ir.model.unlink():
drop table of corresponding models
ir.model._unlink_if_uninstalling():
self.env['worksheet.template'].search([('model_id', ...)]).unlink()
delete ir.model records
```
The call to `ir.model.unlink()` crashes when searching for worksheet templates, since column `model_id` has been dropped already. This makes the transaction fail, and it is rolled back to a savepoint just before the call to `ir.model.unlink()`. In other words, the uninstallation manages to drop most of the columns that must go, but fails to drop all the tables that must go. And the uninstallation proceeds anyway...
Now consider uninstalling module `resource`. That module defines model `resource.calendar` with required field `name`, and also defines a record in that model (a default calendar). When the module is uninstalled, module `worksheet` is also uninstalled (because it depends on `resource`), and so the situation above happens. Consequently, most of the columns of table `resource_calendar` are dropped, but the table is not. If we reinstall module `resource` after that, the ORM re-creates column `name` (which is `NULL` on the default calendar at least), but fails to add the `NOT NULL` constraint on that column.
The fix consists in avoiding the `search()` above in the ondelete method if the column `model_id` does not exist anymore.Spanish Veri*Factu invoices for customers outside Spain now select the correct export regime key instead of the general regime. This helps businesses submit more accurate e-invoicing data and avoid manual corrections for export invoices.
Original PR description
### Steps to reproduce: - Install l10n_es_edi_verifactu and switch too Spanish company - Create an invoice for a partner outside Spain (or with the tax "0% EX G") - Check the "Veri*Factu Regime Key" under the page "Veri*Factu" - It should be "Export" (02) but it's "General Regime Operation" (01) ### Cause: `_l10n_es_edi_verifactu_get_suggested_clave_regimen()` is called on the tax "0% EX G". The line ```taxes.filtered(lambda tax: (tax.l10n_es_type not in main_tax_types or tax._l10n_es_edi_verifactu_get_applicability() != forced_tax_applicability))``` doesn't do what the comment says: remove the main taxes with a different applicability. ### Solution: Change the `!=` to `==` so that the line does the same thing as the comment. opw-5071665 Forward-Port-Of: odoo/odoo#230823
Purchase requests created from approvals now use the currency configured for the selected vendor instead of defaulting to the company currency. This keeps RFQ pricing consistent with other purchasing flows and helps avoid currency mismatches.
Original PR description
### Issue: When creating an RFQ from an approval, the created purchase order does not use the currency set on the vendor of the product. Rather, it uses the currency of the company, with the value converted based on the vendor's currency to get the price. This is not consistent with other ways we create RFQs, which all respect the vendor currency. ### Solution: Pass the vendor's currency into the values sent when creating the purchase order. opw-4549937
The Subscriptions MRR Breakdown report now ignores archived companies when preparing report data. This prevents access errors for users working in databases where the original company was archived and another active company is in use.
Original PR description
Step to reproduce: - Start database without demo data and install Subscriptions - Create a new Company and archive the first Company in the Database - Set a currency rate on a currency (i.e. Euro),…
Step to reproduce: - Start database without demo data and install Subscriptions - Create a new Company and archive the first Company in the Database - Set a currency rate on a currency (i.e. Euro), then set that currency as the Main Currency of the new Company. - Then, set a currency rate on the previous Main Currency i.e USD. - Create a Subscription Sales Order and confirm it. - Open the MRR Breakdown report. - Click into the data of the report. Observation: An error message will occur appear (Access Error) Issue: - when building the query, it also fetches the archived company, due to `active_test` context applied from [fetch()](https://github.com/odoo/odoo/blob/754599a7720ee179fc5304b9613df9c177e4b231/odoo/models.py#L3858), and hence wrong query is build which fetches no data, leading to sort of access error as this [condition](https://github.com/odoo/odoo/blob/754599a7720ee179fc5304b9613df9c177e4b231/odoo/models.py#L3876) matches. Fix: - we explicitly search for active companies opw-5090463
Swiss payroll users can now access all required backend configuration fields directly from the salary rule screen. This helps payroll teams configure wage types more completely and reduces the need for technical backend access.
Original PR description
task-4954650
Restricted website editors can now update pages even after an administrator adds an embedded video. The change keeps videos visible to visitors while storing them in a way that remains compatible with content safety rules, reducing editing interruptions for business teams.
Original PR description
Steps to reproduce the current behaviour: - Update the DEMO user to be a website "restricted editor" and sales "admin" who cannot bypass HTML field sanitization. - As ADMIN, add a YouTube video to a…
Steps to reproduce the current behaviour: - Update the DEMO user to be a website "restricted editor" and sales "admin" who cannot bypass HTML field sanitization. - As ADMIN, add a YouTube video to a product page > Save. - As DEMO, try to update the content on the product page > You cannot (a dialog informs you that you cannot edit the content because an admin edited it previously). Explanation: Starting from [1], an HTML field can be flagged as `sanitize_overridable` which allowed users with the `base.group_sanitize_override` group to skip the HTML field sanitize process. If such users added some content that is not considered "sanitize friendly" (e.g. YouTube iframe), a restricted user won't be allowed to add content in the fields, since the sanitizer will remove the original content from the DOM. For this case, the code from [2] added an implementation to consider the field as none editable and warn the user once he tries to update it. Implementation: The goal of this commit it to fix the current limitation for video upload that currently prevents non admin users to edit a website record once an admin adds a video on it... The idea of the fix is the following: - We already have a technical fallback when uploading a video to save the iframe `src` to an attribute: `data-oe-expression`. - The public widget is now destroying the video iframes so they are never saved in the DOM. - A non-lazy code will build the iframes immediately on page load. - The public widget can always create the iframes if they are not already created (for compatibility). [1]: https://github.com/odoo/odoo/commit/cf844e34dd0ce4830eb99fd0fa5b6b9cb58c867c [2]: https://github.com/odoo/odoo/commit/cb80c15d3db49ede3c93171abcaa9064b88822c6 task-3757205
Project profitability now reflects only the portion of an expense assigned to a project through analytic distribution. This prevents expenses that are partially allocated to a project from being counted in full, giving managers more accurate profitability figures.
Original PR description
…nse profitability #### Issue: While looking at project profitability, expenses analytic distribution are treated as being set to 100%. #### Step to reproduce: - With modules: project_{hr,…
…nse profitability
#### Issue:
While looking at project profitability, expenses analytic distribution are treated as being set to 100%.
#### Step to reproduce:
- With modules: project_{hr, sale}_expense, accountant
- enable "Analytic accounting"
- enable project > Timesheet
- Create a project "A"
- Set it as billable
- Create a Meal expense for an amount of 115$
- Set an analytic account of 50% for the project "A"
- Validate
- Approve
- Post journal entries
- Go to the project "A" > settings > Set Status
#### Current behavior:
- profitability display '-100'. It took the whole expense.
#### Expected behavior:
- profitability should display '-50'. Only 50% of the untaxed amount.
#### Cause of the issue:
- While querying `hr_expense`, the full untaxed amount of all expenses having the right `analytic_account` in their `analytic_distribution` were added together with no regard to the percent they were set to.
#### Solution:
- weight the expenses depending of their analytical distribution
opw-4949634
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prSpanish Facturae e-invoices now use the invoice’s recorded accounting lines to calculate tax totals, preventing small rounding differences in the XML when global tax rounding is enabled. This helps ensure the electronic invoice matches the tax amounts shown in Odoo and reduces validation or reconciliation issues.
Original PR description
If the tax rounding is set to round_globally, the XML generated for an invoice might have a different TotalTaxOutputs than the tax computation shown in the invoice. This is due to an extra rounding occuring during the XML generation. In this commit, we base the computed values of the InvoiceTotals segment of the facturae document on the move's line_ids, avoiding unnecessary and error-prone re-computation. task-4650439 As the file changed in 18.0, another PR is necessary from 18 on : https://github.com/odoo/odoo/pull/229236
Dashboard charts on mobile now behave like desktop charts: tapping a chart opens the linked Odoo menu. This makes mobile dashboards more useful and consistent for users who rely on charts to navigate to related business information.
Original PR description
Current behavior before PR: - Clicking on a chart in mobile did nothing, unlike on desktop where it redirects to the linked Odoo menu. Desired behavior after PR is merged: - Clicking on a chart in mobile also redirects to the corresponding Odoo menu. - The test has been refactored to remove duplication and improve readability. Task: [4884509](https://www.odoo.com/odoo/2328/tasks/4884509)