Daily updates from Odoo
Wednesday, July 22, 2026
48 changes · saas-19.4
New functionality added to Odoo
Adds the detailed Latvian VAT report attachments needed for domestic, EU, purchase, sales, import, and export transactions. Businesses can now review the supporting transaction breakdowns and export the full tax report package in XML for easier filing and compliance.
Original PR description
This commit adds 4 attachments to the Latvian tax report and an XML export for the tax report (including the attachments). The attachments are the following - PVN 1-I: domestic purchase / import -…
This commit adds 4 attachments to the Latvian tax report
and an XML export for the tax report (including the attachments).
The attachments are the following
- PVN 1-I: domestic purchase / import
- PVN 1-II: EU purchase
- PVN 1-III: domestic sales / export
- PVN 2: EU sale
The attachments give more details for the tax report.
The lines of the attachments are "transactions"
A "transaction" is identified by the move and the transaction type or document type.
The transaction type is given via a tax tag (see community PR).
- PVN 1-I: transaction type, move
- Small transactions (< 150€) are aggregated separately under transaction types 'V' or 'T'
independently of the move
- 'V': All small transactions of a partner in case the total of all their small transactions reaches 150€
- There is max 1 line per partner
- 'T': All small transactions that are not grouped under some 'V' line
- There is max 1 line like this; it has no partner information
- PVN 1-II: transaction type, move
- Small transactions (< 150€) are aggregated separately under transaction types 'V' or 'T'
(like PVN 1-I)
- PVN 1-III: document type, move and line in the main tax report
- All transactions with (document) type 'X' are aggregated on a single line
- Small transactions (< 150€) are aggregated separately under document types 'V' or 'T'
(like PVN 1-I)
- The line in the main tax report is ignored for 'X' and small transactions
- PVN 2: transaction type, move
- No aggregation is performed here
Only account move lines that are tagged with a transaction type (1-I, 1-II, 2)
or a relevant tag for the main report (1-III) are shown in the reports.
The tags `Rep` and `C (car)` only take 40% and 50% respectively of the
base amounts. The tax amount is assumed to be split correctly.
task-4251184
Forward-Port-Of: odoo/enterprise#84135Enhancements to existing features
Shop floor handling for continuous production is tightened to avoid creating backorders for now and to require users to enter a produced quantity before closing a manufacturing order. This helps prevent incorrect production quantities and makes the workflow more predictable while the full continuous production process is refined.
No task ID Forward-Port-Of: odoo/odoo#277308 Forward-Port-Of: odoo/odoo#276936
Original PR description
No task ID Forward-Port-Of: odoo/odoo#277308 Forward-Port-Of: odoo/odoo#276936
#### [IMP] l10n_lv: add tax report attachment tags Add tags for the tax report attachments added in the related enterprise PR and tag all existing taxes. They determine the transaction type. It also adds the special tag `Rep` that is irrelevant for the transaction type. From a base amount line tagged with `Rep` we only put 40% of the amount for the attachments. #### [IMP] l10n_lv: add a car and a representation purchase tax This commit adds 2 new taxes - "car tax": 50% of the VAT
Original PR description
#### [IMP] l10n_lv: add tax report attachment tags Add tags for the tax report attachments added in the related enterprise PR and tag all existing taxes. They determine the transaction type. It also adds the special tag `Rep` that is irrelevant for the transaction type. From a base amount line tagged with `Rep` we only put 40% of the amount for the attachments. #### [IMP] l10n_lv: add a car and a representation purchase tax This commit adds 2 new taxes - "car tax": 50% of the VAT is deductible - "representation tax": 40% of the VAT is deductible #### references task-4251184 Forward-Port-Of: odoo/odoo#272050 Forward-Port-Of: odoo/odoo#212698
In this commit, we continue cleaning and aligning continuous production BoM with normal BoM alongside some UX changes and improvements. In case of a continuous production BoM: - Marking a WO as done, doesn't update qty producing - Interacting with the WO card in shopfloor also will not update qty producing, because it used to mess up component's consumption. Move demand should only be updated when we update MO's quantity producing. In General: - No production state tracking in the
Original PR description
In this commit, we continue cleaning and aligning continuous production BoM with normal BoM alongside some UX changes and improvements. In case of a continuous production BoM: - Marking a WO as done, doesn't update qty producing - Interacting with the WO card in shopfloor also will not update qty producing, because it used to mess up component's consumption. Move demand should only be updated when we update MO's quantity producing. In General: - No production state tracking in the chatter for WO Form - Allow splitting when WO is done - Ensuring that if there are 2 users working on the same time and one of them marks the WO is done, the other won't be able to update the `qty_produced` on accident and will be shown an error to avoid inconsistencies. Task: 6384174 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Resolved issues and error corrections
Spanish VAT book exports now calculate taxes with negative components correctly, instead of showing them as zero. This helps businesses using Spanish accounting reports see accurate tax amounts for applicable EU vendor bills.
Original PR description
Problem: In the Spanish VAT books, taxes with negative component (like 21% EU G) always show their amounts as zero. Steps to reproduce: 1. Install the l10n_es_reports module and select the Spanish company 2. Create a vendor bill with a vendor from another EU country and add a product 3. Make sure the tax applied to the product has a negative component (like 21% EU G) 4. Confirm the bill 5. Go to Accounting > Reporting > Tax Return 6. Generate the VAT books from the action menu and check the tax amounts 7. Notice how the tax amount is zero, even though the tax was applied to the bill Cause: When calculating the tax amounts, the negative component cancels out the positive component, leading to the amount always showing as zero in the VAT books. opw-6169766 Forward-Port-Of: odoo/enterprise#124030 Forward-Port-Of: odoo/enterprise#123738
This update fixes an internal payroll attendance test that was failing because it looked for fields in the wrong place and used outdated options. It helps keep automated checks reliable when validating overtime rule workflows, reducing the risk of payroll attendance issues reaching users.
Original PR description
backward port of this PR https://github.com/odoo/enterprise/pull/122284 merge upto saas-19.4 Issue: The `test_overtime_ruleset_flow` tour test was failing because the `amount_rate` field could not be found. Reason: - Couldn't find the amount_rate field as it was located in the Payroll tab and the tour did not navigate to that tab before interacting with the field. - The tour also used some selectors and values that were no longer valid, causing some steps to fail. Fix: - Open the Payroll tab before interacting with the `amount_rate` field. - Set the overtime leave request duration type to "Custom Hours". - Replace the unavailable "Salary-exempt" employee type with "Employee". - Use the checkbox input selector to interact with the attendance_based field. - Explicitly open the dropdown before clicking on `action_continue` button. - Remove the unnecessary final `action_continue` step.
This fixes Peruvian electronic invoices so detraction withholding amounts are correctly converted to PEN when a company uses USD as its currency. It prevents incorrect XML submissions to SUNAT and ensures PDF reports show the proper Peruvian sol currency symbol.
Original PR description
**Steps to reproduce:** * Install the **l10n_pe_edi** module. * Change the company currency to **USD**. * Configure **Peruvian detraction** settings: * Set a **withholding percentage** on a product.…
**Steps to reproduce:**
* Install the **l10n_pe_edi** module.
* Change the company currency to **USD**.
* Configure **Peruvian detraction** settings:
* Set a **withholding percentage** on a product.
* Set a **withholding code** on the same product.
* Create a customer invoice in **USD**.
* Set the **Operation Type** to **[1001] Operation Subject to Detraction**.
* Add the configured product to the invoice.
* Confirm the invoice, **send it to SUNAT** by *process now**, and generate the ZIP which has XML.
**Observed behavior:**
* The generated XML contains: `<cbc:Amount currencyID="PEN">116.82</cbc:Amount>` The `currencyID` is `PEN` but the amount is the raw USD value instead of being converted to PEN using the exchange rate.
* The PDF report also shows the withholding amount with the wrong currency symbol.
**Cause:**
* `_l10n_pe_edi_get_spot()` computed `spot['amount']` as `amount_total_signed * percent`, where `amount_total_signed` is stored in the **company currency**. When the company currency is PEN this works correctly, but when it is changed to USD the value is in USD while the XML node hardcodes `currencyID="PEN"`.
* `spot['currency']` was also set to `company_id.currency_id`, so the PDF rendered the amount with the wrong currency symbol.
* In `_add_invoice_payment_terms_nodes`, `spot_amount` was selected via `spot['amount'] if invoice.currency_id == invoice.company_id.currency_id` which relied on company currency being PEN as a proxy for the invoice being in PEN, breaking when company currency is USD.
**Fix:**
* In `_l10n_pe_edi_get_spot()`, compute `spot['amount']` by explicitly converting `amount_total` from the invoice currency to PEN using `currency_id._convert(..., env.ref('base.PEN'), ...)`, ensuring the detraction amount is always in PEN regardless of the company currency.
* Set `spot['currency']` to `env.ref('base.PEN')` so the PDF report always displays the withholding amount with the correct PEN symbol.
* In `_add_invoice_payment_terms_nodes`, always use `spot['spot_amount']` (invoice currency amount) for the `FormaPago`/`Cuota` arithmetic, since `spot['amount']` is now exclusively the PEN amount for the detraction XML node.
opw-6327571
Forward-Port-Of: odoo/enterprise#125063
Forward-Port-Of: odoo/enterprise#123782This fix prevents users from creating or editing WhatsApp templates from the event communication flow in a way that can link the wrong template type. This avoids access errors after reloading an event and supports the stricter approval requirements for WhatsApp templates.
Original PR description
Issue: User goes to Event.event Form -> communication tab -> add line Select whatsapp -> type something -> create and edit -> create new template with any model event.registration -> save ( all the way including the event form) reload page -> whatsapp event.mail displays "User does not have access to this record". Fix: add a patch to the js get m2oProps to deactivate edit, and create on the prop. WA Templates need more limitations for creation and edits due to the approval process from META's external API. We cannot block the full creation and edit in the xml becuase other event.mail types rely on that flow to create their types like social posts. This was a fix implemented due to needing to revert the oginal fix odoo/odoo@f58e9f97192ac0ff8d159377494d6c68f871d20b opw-6334168 Forward-Port-Of: odoo/enterprise#124156 Forward-Port-Of: odoo/enterprise#121852
This update registers the WhatsApp Identifiers translation template so it is included in the translation workflow. It helps ensure future text in this module can be translated consistently across supported languages.
Original PR description
pot files must be registered there. See 9966b160972a053e051f2213846acc64d133f2a3 Forward-Port-Of: odoo/enterprise#124076 Forward-Port-Of: odoo/enterprise#124026
Employee appraisals now prioritize the template assigned to the employee's department instead of keeping a generic default template. This ensures the right appraisal form is used automatically while preserving valid user choices for that department.
Original PR description
**Problem:** When a template is restricted to a department, appraisals for employees of that department do not use it — a generic (global) template is used instead. **Steps to reproduce:** 1. Create…
**Problem:** When a template is restricted to a department, appraisals for employees of that department do not use it — a generic (global) template is used instead. **Steps to reproduce:** 1. Create an appraisal template and restrict it to a department. 2. Make sure at least one global (no department) template also exists. 3. Open a new appraisal and select an employee of that department. 4. Observe the appraisal template stays on the global one. **Current behavior:** The global template that was auto-selected before an employee was chosen is kept, ignoring the department-restricted template. **Expected behavior:** The template restricted to the employee's department is selected. **Cause of the issue:** On a new appraisal the template is computed before an employee (and therefore a department) is set, so a global template is pre-selected. When the employee is then chosen, `_compute_appraisal_template` reruns but the `appraisal.appraisal_template_id or ...` clause short-circuits on the already set global template and never falls through to the department's template. **Fix:** Evaluating the department's template before the existing value ensures a department-restricted template takes precedence over a template that was only auto-selected as a default. The existing value is still preserved when the department has no template of its own, so deliberate choices are untouched. opw-6293936 Forward-Port-Of: odoo/enterprise#121377
The Documents app now keeps the Actions menu working when users select multiple documents. This prevents a frustrating dead button and keeps the selected-document count accurate after uploads.
Original PR description
***Issue:*** Since https://github.com/odoo/enterprise/commit/8baaad621a1555680cd77ab514f626137b5b584d the div holding the selection box and the Actions menu carries t-key="targetRecords.length" in…
***Issue:*** Since https://github.com/odoo/enterprise/commit/8baaad621a1555680cd77ab514f626137b5b584d the div holding the selection box and the Actions menu carries t-key="targetRecords.length" in the documents list and kanban views, so every change of the selection count destroys and recreates everything inside it. Ticking a document checkbox updates both the selection and the focused record, and with these two updates the recreation goes wrong: the new ActionMenus component ends up destroyed while its button is still in the page. The dropdown click listeners are removed with the component, so clicking Actions does nothing until the selection changes again. That t-key was added because the selection box shows a stale count after a file upload. The real problem is that SelectionBox caches this.root once in setup. The upload flow reloads the model, which replaces the root record list, and the box keeps counting the selection of the old one. ***Fix:*** Remove the t-key from documents_list_controller.xml and documents_kanban_controller.xml and make DocumentsSelectionBox read the current props.root instead of the value cached by the parent setup. The count follows the new record list after an upload without remounting anything, and the Actions menu is not recreated so its dropdown keeps working. The upload scenario stays covered by the existing multi_view.test.js test, a new test checks that the Actions menu opens with two selected documents. ***Steps to reproduce:*** 1. Open the Documents app 2. Switch to the list view 3. Tick the checkboxes of two documents 4. Click the Actions button next to the "2 selected" box => the Actions dropdown does not open Ticket [link](https://www.odoo.com/odoo/project.task/6365618) opw-6365618 Forward-Port-Of: odoo/enterprise#124238 Forward-Port-Of: odoo/enterprise#123575
The AI module's automated tests were adjusted to focus only on editable email content. This keeps test results reliable after a related editor change created an extra background copy of the content.
Original PR description
This commit updates the tests after https://github.com/odoo/odoo/pull/276332 to query only the editable content, ignoring the DOM clone created by `convert_inline`. opw-3776054
The barcode app now applies a default limit when loading reusable packages for transfers. This prevents very large package lists from causing long delays, improving responsiveness for warehouses with tens of thousands of packages.
Original PR description
# How to reproduce - Have a lot of reusable & locationless packages (e.g. > 10 000) - Go to any transfer via the barcode application # The issue There is a very long loading time, even in local…
# How to reproduce - Have a lot of reusable & locationless packages (e.g. > 10 000) - Go to any transfer via the barcode application # The issue There is a very long loading time, even in local testing. The client of the tickets experiences loadings up to 120 seconds with 50k packages # Cause When opening a transfer, we load barcode data by doing an API call to `_get_stock_barcode_data` : https://github.com/odoo/enterprise/blob/fe058ef501767b7ed9758fc9264f664b32c6bae8/stock_barcode/models/stock_picking.py#L85 During this we preload a lot of records, notably packages : https://github.com/odoo/enterprise/blob/fe058ef501767b7ed9758fc9264f664b32c6bae8/stock_barcode/models/stock_picking.py#L128 The issue is that in the fields we read for the packages, two of them (`location_dest_id` & `contained_quant_ids`) have a `_read_group` in their compute (or in the compute of one of the fields they depend on) : https://github.com/odoo/odoo/blob/625e6bcbd66c45ea2f699df14e2ea12e2e28a893/addons/stock/models/stock_package.py#L65 https://github.com/odoo/odoo/blob/625e6bcbd66c45ea2f699df14e2ea12e2e28a893/addons/stock/models/stock_package.py#L146 Fortunately, this does not mean that we make a query for every records. Instead, in Odoo, we fetch records in batch of 1000. So, for the case of the client, every time he loads the database, the backend does 50 000 / 1000 x 2 = 100 queries, which hinders performance a lot A [PERF] commit was done to limit the number of packages that are fetched base on a config parameter. The problem is that this parameter does not have a default value, so clients still end up with the problem. [PERF]: https://github.com/odoo/enterprise/commit/efe18bc1ea479270e42846986d7ed449b0865617 # Proposed Solution Add a default value for that config parameter. The exact value is up to discussion opw-6200730 Forward-Port-Of: odoo/enterprise#124538 Forward-Port-Of: odoo/enterprise#123696
Creating Australian payroll super accounts could fail because the system used inconsistent employee references when checking contribution proportions. This fix makes that lookup consistent, preventing the error and allowing payroll configuration to continue normally.
Original PR description
Version - 19.0 Steps to reproduce(runbot): - Install `l10n_au_hr_payroll` - Go to Payroll -> Configuration -> Super Accounts - Create a Super Account by filling all the required fields - You will…
Version - 19.0
Steps to reproduce(runbot):
- Install `l10n_au_hr_payroll`
- Go to Payroll -> Configuration -> Super Accounts
- Create a Super Account by filling all the required fields
- You will encounter the issue
**TraceBack:**
```
('hr.menu_hr_employee_payroll', 485, 'Employees > Employees', 756):
Traceback (most recent call last):
File "/tmp/tmpao31_hxw/migrations/base/tests/test_mock_crawl.py", line 346, in crawl_menu
self.mock_action(action_vals)
File "/tmp/tmpao31_hxw/migrations/base/tests/test_mock_crawl.py", line 377, in mock_action
return self.mock_act_window(action)
File "/tmp/tmpao31_hxw/migrations/base/tests/test_mock_crawl.py", line 537, in mock_act_window
mock_method(model, view, fields_list, domain, group_by)
File "/tmp/tmpao31_hxw/migrations/base/tests/test_mock_crawl.py", line 570, in mock_view_form
[data] = record.read(fields_list)
File "/home/odoo/src/odoo/19.0/odoo/orm/models.py", line 3490, in read
return self._read_format(fnames=fields, load=load)
File "/home/odoo/src/odoo/19.0/odoo/orm/models.py", line 3747, in _read_format
vals[name] = convert(record[name], record, use_display_name)
File "/home/odoo/src/odoo/19.0/odoo/orm/models.py", line 6688, in __getitem__
return self._fields[key].__get__(self)
File "/home/odoo/src/odoo/19.0/odoo/orm/fields.py", line 1744, in __get__
self.compute_value(recs)
File "/home/odoo/src/odoo/19.0/odoo/orm/fields.py", line 1915, in compute_value
records._compute_field_value(self)
File "/home/odoo/src/odoo/19.0/addons/mail/models/mail_thread.py", line 484, in _compute_field_value
return super()._compute_field_value(field)
File "/home/odoo/src/odoo/19.0/odoo/orm/models.py", line 4954, in _compute_field_value
determine(field.compute, self)
File "/home/odoo/src/odoo/19.0/odoo/orm/fields.py", line 81, in determine
return needle(*args)
File "/home/odoo/src/enterprise/19.0/l10n_au_hr_payroll/models/hr_employee.py", line 118, in _compute_proportion_warnings
proportions[emp.id] * 100,
KeyError: 4
```
Issue:
During the refactoring from `read_group()` to `_read_group()`, the `proportions` dictionary became keyed by `hr.employee` records instead of employee IDs. While the condition was updated to use `proportions.get(emp)`, the warning message still accessed the dictionary using `proportions[emp.id]`, resulting in a `KeyError`.
Fix:
Use the employee record consistently when accessing the `proportions` dictionary after switching to `_read_group()`.
Task ID - 6390373
Refrence:
https://github.com/odoo/enterprise/pull/72217/changes#diff-8ae3564d54e47eec919ef273d44f6276d8c6df60e21c5c8c8f7292b1c38cf541R460
Forward-Port-Of: odoo/enterprise#124478Emails generated for public appointment and event flows now use the website tied to the appointment or event instead of a generic or recently used website URL. This prevents customers from being sent to the wrong website when confirming, viewing, or managing their booking or registration.
Original PR description
In Multiwebsite settings, when the public user interactions needs email generation (appointment or event flow), the email links are generated with a base url that does not corresponds to the one from…
In Multiwebsite settings, when the public user interactions needs email generation (appointment or event flow), the email links are generated with a base url that does not corresponds to the one from which the request started. Case 1: - Have website A and website B - Create an appointment page website A - Log in via website B - As public user, make an appointment in Website A - Check the generated email Issue: button links in the email will redirect to the wrong website, so users will encounter an issue when managing the appointment. This occurs because when an user log in, the system parameter 'web.base_url' is updated with the current url. This parameter is then used as fallback when we need to retrieve the base url without an active record Case 2: - Have website A and website B - Create an event and assign it to website B - As public user, access the event and register to it - Check the generated email Issue: button links in the email will redirect to the wrong website, so users will encounter an issue when managing the event. This occurs because the record `event.registration` has no website_id field and the base url is taken from the company default website (website A) Backport with improvements of 15bae202d8f1b5bf70bbc63b2d89025e9237e6cf opw-4146760 opw-4336369 Forward-Port-Of: odoo/enterprise#124714 Forward-Port-Of: odoo/enterprise#122669
Clicking a phone number now follows the company’s mobile calling preference when VoIP is unavailable. Users can open the softphone to check connection status, use the native dialer, or choose between options, reducing confusion and accidental duplicate actions.
Original PR description
…ability When the user clicks a phone number in a PhoneField widget but VoIP is not available (canCall = false), the behavior now depends on the how_to_call_on_mobile setting: - "voip": show the softphone so the user can check the connection - "phone": fall back to the base class default (native dialer) - "ask": show a selection dialog for the user to choose We also backport the code to prevent double click from [1]. [1]: https://github.com/odoo/enterprise/commit/fa6c8747d69ffee25a7f308d26baca8500226784
Envia shipping labels for Amazon now send each product's weight, preventing Amazon from applying default weights that can incorrectly exceed the package total. This helps avoid blocked shipments for customers using Envia with Amazon delivery services, especially for orders with many items.
Original PR description
**Issue:** Envia API documentation is very bad. When trying to generate an Amazon Ground shipping with Envia, the API will sometimes reject the payload with the following error: `Total items weight…
**Issue:** Envia API documentation is very bad. When trying to generate an Amazon Ground shipping with Envia, the API will sometimes reject the payload with the following error: `Total items weight exceeds package weight. Please refer to API documentation for allowable limits. (D-703)` Even though the [Envia documentation](https://docs.envia.com/reference/create-shipping-label) doesn't include it, it seems that Amazon requires the weight for each product. If the payload doesn't include the per-item weight, Amazon will set a default weight, which will cause the error to show up if the delivery contains a high quantity. This can be a blocking issue for some customers. **Steps to reproduce on a fresh DB:** - Install Inventory, Sales, and Envia Shipping - Switch company to be based in India (need to provide an address to deliver from, I just used the Odoo India address - InfoCity Gate, Gandhinagar, Gujarat 382007) - Configure an Amazon delivery carrier with Envia (India seems to be the only country that supports Amazon with Envia) - Inventory > Configuration > Delivery Methods > Envia.com method - Must be in a Production environment (because Envia's sandbox server does not work for some reason?) - Add an Envia Production Access Token (will have to use one with some funds) - Change 'Ship From' to India - Configure the `Envia.com Service Name`, set Carrier and Service to AMAZON and AMAZON - Amazon Shipping Standard - Create a demo product, give it an arbitrary weight like 0.1 kg - Create a sales order to an Indian customer, include the demo product with a high quantity (like 20), confirm (might have to create a warehouse and configure the customer's information) - On the generated picking, set the Carrier to Envia.com on the Additional Info tab - When trying to Validate, it should throw the error **Fix:** When generating the payload in _get_shipping_lines() in envia_request, include the item weight in the dictionary. Related ticket: opw-6261682 Forward-Port-Of: odoo/enterprise#125017 Forward-Port-Of: odoo/enterprise#123935
Restores balance receipt printing for Six payment terminals after a previous change caused the receipt template to load incorrectly. Businesses using these terminals will need to upgrade the module so the corrected receipt template is available.
Original PR description
odoo/enterprise#104683 broke the balance receipt for six terminals trying to load an html template in a template name param. We fix this by extracting the template in its own file. Note: clients will have to upgrade the module in order to make the template available. task-6391500 Forward-Port-Of: odoo/enterprise#124521
The spreadsheet editor now stops further loading steps when a spreadsheet model cannot be created. This avoids an additional error screen or traceback after the user has already been notified of the original problem.
Original PR description
Current behavior before PR: - In 4204ceb, model creation errors were caught and a notification was shown to the user. - However, syncSheetFromRouter() was still called afterward. Since it relies on model getters, it raise a traceback when no model existed. Desired behavior after PR is merged: - Call syncSheetFromRouter() only after the model has been created successfully. - This prevents accessing model getters when model creation fails and avoids the resulting traceback. Task: [6355245](https://www.odoo.com/odoo/project/2328/tasks/6355245) Forward-Port-Of: odoo/enterprise#122650
Point of Sale orders linked to planning now create their related sales order lines only once, when the order is paid. This prevents duplicate lines from appearing after repeated backend syncs, improving order accuracy and reducing manual cleanup.
Original PR description
Before this commit, the creation of sale order lines was in sync_from_ui and was executed every time we would enter the method. Since this method is called everytime we sync the order with the backend, it would create duplicated lines on the sale order. The logic is now moved to action_pos_order_paid, which is only called once when the order is paid.
# Problem Cost of production in the inventory valuation report does not respect 'As of' date, and will show current costs of production regardless of the specified date. # Solution `_get_report_data` in `mrp_account` is just missing the date enforcement when calling `_get_location_valuation_vals`, so we will simply pass this in. # Steps to reproduce (runbot v19) - FIFO Perpetual component with non-zero value - Manufactured product that consumes the above component 1. Set a cost of pro
Original PR description
# Problem Cost of production in the inventory valuation report does not respect 'As of' date, and will show current costs of production regardless of the specified date. # Solution `_get_report_data` in `mrp_account` is just missing the date enforcement when calling `_get_location_valuation_vals`, so we will simply pass this in. # Steps to reproduce (runbot v19) - FIFO Perpetual component with non-zero value - Manufactured product that consumes the above component 1. Set a cost of production account on the production location 2. Create and confirm an MO for the manufactured product 3. Go to Accounting > Review > Inventory Valuation, and set the At Date to something far in the past, befroe any move history in the db. Note the Cost of Production accounts have data that does not apply to this period opw-6229088 Forward-Port-Of: odoo/odoo#277025 Forward-Port-Of: odoo/odoo#269911
## Current behavior: Currently, when we go into POS using l10n_tw localization, none of the customers appear on the list. ## Expected behavior: All customers should be shown when using Taiwan localization ## Steps to reproduce: 1. Install l10n_tw and POS modules 2. Use the default US company, observe the customer list in POS. All of them are shown 3. Create and switch to a Taiwan company, go back to POS 4. Observe that no customers are shown ## Cause of the issue: Since 19.0, the
Original PR description
## Current behavior: Currently, when we go into POS using l10n_tw localization, none of the customers appear on the list. ## Expected behavior: All customers should be shown when using Taiwan localization ## Steps to reproduce: 1. Install l10n_tw and POS modules 2. Use the default US company, observe the customer list in POS. All of them are shown 3. Create and switch to a Taiwan company, go back to POS 4. Observe that no customers are shown ## Cause of the issue: Since 19.0, there is a check where if the default payable or receivable account set on the partner is non-trade, those accounts do not appear ## Fix: - Updated AR accounts in COA template file - Added migration script to version 1.1 opw-6298634 Forward-Port-Of: odoo/odoo#274150 Forward-Port-Of: odoo/odoo#270738
Before this commit, two issues affected custom snippet saves. First, the new builder allowed saving the Alternative Products block from product pages as a custom snippet. This block is generated from the current product alternatives, so it is page-specific content. Second, a block saved as a custom snippet could keep `oe_unremovable` or `oe_unmovable` on its root. A saved custom snippet is meant to become a normal reusable block. Once the user drops it on another page, they should be able
Original PR description
Before this commit, two issues affected custom snippet saves. First, the new builder allowed saving the Alternative Products block from product pages as a custom snippet. This block is generated from the current product alternatives, so it is page-specific content. Second, a block saved as a custom snippet could keep `oe_unremovable` or `oe_unmovable` on its root. A saved custom snippet is meant to become a normal reusable block. Once the user drops it on another page, they should be able to remove it or move it like any other block. After this commit, builder plugins can declare selectors that cannot be saved as custom snippets, and `website_sale` uses this to exclude the Alternative Products block. The saved copy also drops `oe_unremovable` and `oe_unmovable` on its root before calling `ir.ui.view.save_snippet`. task-6296872 Forward-Port-Of: odoo/odoo#277092 Forward-Port-Of: odoo/odoo#275303
Steps to reproduce: ================== 1. Add a Donation snippet on a page 2. Click "Donate Now" 3. Switch the website language on the payment page => Configured amounts/descriptions disappear Cause: ====== The donation snippet posts its configuration (prefilled amounts, display options, descriptions) in the request body. If the user switches the website language on the payment page, it triggers a page reload via a GET request which drops the original form body (this also applies to
Original PR description
Steps to reproduce: ================== 1. Add a Donation snippet on a page 2. Click "Donate Now" 3. Switch the website language on the payment page => Configured amounts/descriptions disappear Cause:…
Steps to reproduce: ================== 1. Add a Donation snippet on a page 2. Click "Donate Now" 3. Switch the website language on the payment page => Configured amounts/descriptions disappear Cause: ====== The donation snippet posts its configuration (prefilled amounts, display options, descriptions) in the request body. If the user switches the website language on the payment page, it triggers a page reload via a GET request which drops the original form body (this also applies to a simple page refresh). As a result, the kwargs were empty and the page fell back to the default free-amount input, losing the configured options. Solution: ========= Implement Post/Redirect/Get: on POST, redirect to /donation/pay with the options in the query string so any later GET (language switch, refresh, iframe src reload) re-renders a fully configured page without losing data. Alternative Solution: ===================== We could also store the options in the session, but the current solution is much simpler and avoids session pollution. opw-6282391 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271460
### Steps to reproduce 1. Trigger an error whose browser object has no `stack` property (for example, a `DOMException` such as `AbortError`). 2. Let the web error service format its traceback. ### Current behavior `formatTraceback()` calls `error.stack.split(...)` unconditionally, which raises a second `TypeError` and masks the original error. ### Expected behavior The original error is formatted and reported even when the browser does not provide a stack trace. ### Fix Use the existing t
Original PR description
### Steps to reproduce 1. Trigger an error whose browser object has no `stack` property (for example, a `DOMException` such as `AbortError`). 2. Let the web error service format its traceback. ###…
### Steps to reproduce 1. Trigger an error whose browser object has no `stack` property (for example, a `DOMException` such as `AbortError`). 2. Let the web error service format its traceback. ### Current behavior `formatTraceback()` calls `error.stack.split(...)` unconditionally, which raises a second `TypeError` and masks the original error. ### Expected behavior The original error is formatted and reported even when the browser does not provide a stack trace. ### Fix Use the existing technical name and message as the traceback when `stack` is absent. A focused regression test covers an `AbortError`-like object without `stack`. ### Tests - `git diff --check` - `node --check addons/web/static/src/core/errors/error_utils.js` - `node --check addons/web/static/tests/core/errors/error_service.test.js` - `@web/core/errors` HOOT suite: 24 tests, 107 assertions passed. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr. Forward-Port-Of: odoo/odoo#276864
Invoice dashboard data, specifically DSO, was incorrectly aligned due to a mismatch in the fiscal year structure. Task-6049887 Forward-Port-Of: odoo/odoo#275880 Forward-Port-Of: odoo/odoo#261037
Original PR description
Invoice dashboard data, specifically DSO, was incorrectly aligned due to a mismatch in the fiscal year structure. Task-6049887 Forward-Port-Of: odoo/odoo#275880 Forward-Port-Of: odoo/odoo#261037
Backport the changes from `b9370ea6b70ca3020c73a6940d70ff0cf954f69f` into `mail/convert_inline` to ensure Outlook-compatible image rendering. opw-3776054 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276071 Forward-Port-Of: odoo/odoo#269436
Original PR description
Backport the changes from `b9370ea6b70ca3020c73a6940d70ff0cf954f69f` into `mail/convert_inline` to ensure Outlook-compatible image rendering. opw-3776054 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276071 Forward-Port-Of: odoo/odoo#269436
### Description: When importing a Peppol invoice containing a massive embedded attachment, the `lxml` library throws an `lxml.etree.XMLSyntaxError: huge text node` error. This is a built-in safety check in libxml2 designed to prevent DoS attacks via XML entity expansion or malicious bombs [^1]. Rather than disabling this security protection globally using the `huge_tree` parser flag, we pre-process and trim the raw XML to remove the heavy binary nodes before parsing. ### References:
Original PR description
### Description: When importing a Peppol invoice containing a massive embedded attachment, the `lxml` library throws an `lxml.etree.XMLSyntaxError: huge text node` error. This is a built-in safety check in libxml2 designed to prevent DoS attacks via XML entity expansion or malicious bombs [^1]. Rather than disabling this security protection globally using the `huge_tree` parser flag, we pre-process and trim the raw XML to remove the heavy binary nodes before parsing. ### References: opw-6085893 [^1]: https://lxml.de/6.0/FAQ.html#is-lxml-vulnerable-to-xml-bombs Forward-Port-Of: odoo/odoo#275893 Forward-Port-Of: odoo/odoo#275367
Before this commit When a website user had an active cart, opening the pickup location selector from a backend sale order could use the cart's delivery method instead of the one configured on the sale order. Steps to reproduce: 0. Switch to the debug mode 1. Configure 2 delivery methods (A and B) with pickup locations 2. On eCommerce add storable products to the cart and choose the delivery method A 3. In the backend, create a sale order and set the delivery method B 4. Try to set picku
Original PR description
Before this commit When a website user had an active cart, opening the pickup location selector from a backend sale order could use the cart's delivery method instead of the one configured on the sale order. Steps to reproduce: 0. Switch to the debug mode 1. Configure 2 delivery methods (A and B) with pickup locations 2. On eCommerce add storable products to the cart and choose the delivery method A 3. In the backend, create a sale order and set the delivery method B 4. Try to set pickup location and see the traceback This is caused by wrong location selector props validation and by the wrong locations fetching. This commit fixes the props of location selector to match the given ones and get the correct locations for the given delivery method. opw-6267741 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#267936
Fix a series of service fee defects and add the missing coverage. Discounts: - stop duplicating the service fee line every time a global discount is (re)applied: reconciliation is keyed on tax_ids alone, so the discount line's computation_key is stripped to keep products and discount in one tax group; - recompute a post_discount fee after a 100% discount deletes the now-zero discount line (which emits no event, leaving a stale fee) (pos_discount); - keep a single fee line when a gift card
Original PR description
Fix a series of service fee defects and add the missing coverage. Discounts: - stop duplicating the service fee line every time a global discount is (re)applied: reconciliation is keyed on tax_ids…
Fix a series of service fee defects and add the missing coverage. Discounts: - stop duplicating the service fee line every time a global discount is (re)applied: reconciliation is keyed on tax_ids alone, so the discount line's computation_key is stripped to keep products and discount in one tax group; - recompute a post_discount fee after a 100% discount deletes the now-zero discount line (which emits no event, leaving a stale fee) (pos_discount); - keep a single fee line when a gift card / eWallet program is used (pos_loyalty). Fixed fee: - scale a fixed fee exactly with its quantity (5 x $2 = $10.00, not 9.99 from per-unit tax rounding); - fix the fixed fee being off by one cent on recompute. Refunds: - a refund order has no preset of its own, so recomputeServiceFees falls back to the refunded order's preset and mirrors the fee proportionally: a percentage fee is correctly signed from the (negative) refund basket, a fixed fee is scaled by the refunded fraction; - the fee must not also be refunded as an individual line (which would subtract it twice): it is excluded from auto-selection and a manual click is rejected with a warning. Restaurant: - keep the fee pinned to the bottom of the order (the last course) as courses are added. task-6372687
Multiple fixes needed to be fixed in the configurator: - Wrong static theme images in the previews ✅ - Optimization of the loading time for the static theme images ✅ - On multi language website, first editor opening shouldn't be in translate mode ✅ - Automatic module installation based on selected website type ✅ - Use theme description instead of summary in the AI prompt for the theme recommendation ✅ - Fix test tour errors ✅ - Update images used in the Configurator first Step ✅ - Upda
Original PR description
Multiple fixes needed to be fixed in the configurator: - Wrong static theme images in the previews ✅ - Optimization of the loading time for the static theme images ✅ - On multi language website, first editor opening shouldn't be in translate mode ✅ - Automatic module installation based on selected website type ✅ - Use theme description instead of summary in the AI prompt for the theme recommendation ✅ - Fix test tour errors ✅ - Update images used in the Configurator first Step ✅ - Update Fallback themes selection ✅ - Brutalist theme title doesn't change ✅ - Enforce the text length for generating snippet texts ✅ - Display synonyms instead of label when needed ✅ - highlight unknown industry terms ✅ - open configurator logo picker only once when replacing ✅ task-6325919
## Steps to Reproduce: - Install `stock_picking_batch` with demo data. - Inventory > Operations > Batch Transfers. - Open any record and click on "Print labels". ## Error: `AttributeError: 'stock.move.line' object has no attribute 'action_open_label_layout'` ## Cause: Since commit https://github.com/odoo/odoo/commit/e177fc82faf8ab3577678a587efe51d18e4369f2, the `action_open_label_layout` method is shared by `stock.picking`, `stock.picking.batch`, and `mrp.production` models. However,
Original PR description
## Steps to Reproduce: - Install `stock_picking_batch` with demo data. - Inventory > Operations > Batch Transfers. - Open any record and click on "Print labels". ## Error: `AttributeError: 'stock.move.line' object has no attribute 'action_open_label_layout'` ## Cause: Since commit https://github.com/odoo/odoo/commit/e177fc82faf8ab3577678a587efe51d18e4369f2, the `action_open_label_layout` method is shared by `stock.picking`, `stock.picking.batch`, and `mrp.production` models. However, `stock.picking.batch` mistakenly calls the method on stock move lines instead of stock moves, while the method expects `stock.move` records. ## Fix: This commit calls the method on move ids, ensuring the label layout wizard get the expected records. sentry-7620773909
In Multiwebsite settings, when the public user interactions needs email generation (appointment or event flow), the email links are generated with a base url that does not corresponds to the one from which the request started. - Have website A and website B - Create an event and assign it to website B - As public user, access the event and register to it - Check the generated email Issue: button links in the email will redirect to the wrong website, so users will encounter an issue when
Original PR description
In Multiwebsite settings, when the public user interactions needs email generation (appointment or event flow), the email links are generated with a base url that does not corresponds to the one from which the request started. - Have website A and website B - Create an event and assign it to website B - As public user, access the event and register to it - Check the generated email Issue: button links in the email will redirect to the wrong website, so users will encounter an issue when managing the event. This occurs because the record `event.registration` has no website_id field and the base url is taken from the company default website (website A) opw-4146760 opw-4336369 Forward-Port-Of: odoo/odoo#276984 Forward-Port-Of: odoo/odoo#274051
**Steps to reproduce:** 1. Create a Sales Order. 2. Create a 50% down payment invoice. 3. Create a credit note for the down payment invoice. 4. Reset the credit note to Draft and cancel it. 5. Create the final invoice from the Sales Order. **Issue:** The final invoice is generated for 100% of the order amount, acting as if the down payment invoice does not exist. **Expected behavior:** The final invoice should only include the remaining 50% of the order amount because a valid 50% do
Original PR description
**Steps to reproduce:** 1. Create a Sales Order. 2. Create a 50% down payment invoice. 3. Create a credit note for the down payment invoice. 4. Reset the credit note to Draft and cancel it. 5. Create…
**Steps to reproduce:** 1. Create a Sales Order. 2. Create a 50% down payment invoice. 3. Create a credit note for the down payment invoice. 4. Reset the credit note to Draft and cancel it. 5. Create the final invoice from the Sales Order. **Issue:** The final invoice is generated for 100% of the order amount, acting as if the down payment invoice does not exist. **Expected behavior:** The final invoice should only include the remaining 50% of the order amount because a valid 50% down payment invoice still exists. **Why this happens:** - The `price_unit` on the Sales Order's down payment line is manually updated during `action_post()` based on the sum of posted invoices minus posted credit notes. - When the credit note is posted, `price_unit` drops to 0. However, when that credit note is subsequently reset to draft and cancelled, it triggers `button_cancel()` which only refreshed the line's display name and failed to recalculate `price_unit`. As a result, `price_unit` remained at 0 even though the credit note was no longer active, causing the final invoice to deduct nothing. opw-6373578 Forward-Port-Of: odoo/odoo#277386 Forward-Port-Of: odoo/odoo#275684
Steps to reproduce: - Open the website editor. - Go to the Theme tab. - Inspect the Primary or Secondary color picker title. => The title prop is undefined. - Go to a product page with several product images. - Edit the carousel thumbnail position option. => The Left and Bottom button titles are undefined. Before this commit, some builder option titles were passed as OWL expressions instead of translated string props. After this commit, these titles use translated string props and are
Original PR description
Steps to reproduce: - Open the website editor. - Go to the Theme tab. - Inspect the Primary or Secondary color picker title. => The title prop is undefined. - Go to a product page with several product images. - Edit the carousel thumbnail position option. => The Left and Bottom button titles are undefined. Before this commit, some builder option titles were passed as OWL expressions instead of translated string props. After this commit, these titles use translated string props and are properly available to the builder components. task-6034856 Forward-Port-Of: odoo/odoo#275940 Forward-Port-Of: odoo/odoo#275235
When an attachment is added to an email template and is linked to a journal, and then you try to send an invoice, the attachment is shown in the attachments box but is not sent via peppol, the reason is that we were filtering to send only manually added attachments, and the email attachment was not considered "manual". task-id-6241354 Forward-Port-Of: odoo/odoo#272472
Original PR description
When an attachment is added to an email template and is linked to a journal, and then you try to send an invoice, the attachment is shown in the attachments box but is not sent via peppol, the reason is that we were filtering to send only manually added attachments, and the email attachment was not considered "manual". task-id-6241354 Forward-Port-Of: odoo/odoo#272472
Currently, we only load the XML data from the exported POS order in the field `l10n_jo_edi_pos_computed_xml` when`l10n_jo_edi_pos_error` is False. It should be the opposite. The field `l10n_jo_edi_pos_computed_xml` is only used when we call `download_l10n_jo_edi_pos_computed_xml()` from the anchor "Download XML" , and that anchor is only visible when `l10n_jo_edi_pos_error` is True. If the request succeeds, then the XML file will be stored in the field `l10n_jo_edi_pos_xml_attachment_i
Original PR description
Currently, we only load the XML data from the exported POS order in the field `l10n_jo_edi_pos_computed_xml` when`l10n_jo_edi_pos_error` is False. It should be the opposite. The field `l10n_jo_edi_pos_computed_xml` is only used when we call `download_l10n_jo_edi_pos_computed_xml()` from the anchor "Download XML" , and that anchor is only visible when `l10n_jo_edi_pos_error` is True. If the request succeeds, then the XML file will be stored in the field `l10n_jo_edi_pos_xml_attachment_id` anyway. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276918
Owl 3 refs are signal, not objects with `.el`. Replace `this.content.el` with `this.content()` so preview updates keep targeting the actual element. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Owl 3 refs are signal, not objects with `.el`. Replace `this.content.el` with `this.content()` so preview updates keep targeting the actual element. 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
In this commit [1], the default-9 palette have been modified to dark for a POC, and has not been reverted to it's original color. This PR revert to the original colors. [1]: a26f2cef490408eb7c73623317f1b42050aa0f41 task-6325919
Original PR description
In this commit [1], the default-9 palette have been modified to dark for a POC, and has not been reverted to it's original color. This PR revert to the original colors. [1]: a26f2cef490408eb7c73623317f1b42050aa0f41 task-6325919
**Steps to reproduce:** - Create an attribute of type always, 2 values A and B for it - The two values should have an extra price, like 100 for A and 150 for B - Create an attribute of type dynamic, 2 values C and D for it - C should have an extra price of 100 and 150 for D - Make a product with both of those product, set the price to 100 2 possibilities: - In the PoS, click the product, on the product popup, the price is 100 - This 100 is the product's price and does not change ev
Original PR description
**Steps to reproduce:** - Create an attribute of type always, 2 values A and B for it - The two values should have an extra price, like 100 for A and 150 for B - Create an attribute of type dynamic,…
**Steps to reproduce:** - Create an attribute of type always, 2 values A and B for it - The two values should have an extra price, like 100 for A and 150 for B - Create an attribute of type dynamic, 2 values C and D for it - C should have an extra price of 100 and 150 for D - Make a product with both of those product, set the price to 100 2 possibilities: - In the PoS, click the product, on the product popup, the price is 100 - This 100 is the product's price and does not change even if we change the values - Order that product and buy it with variants A and C - Click on the product again, the price is 300, which is correct - When we click on D, the price is reset to 100, but should be 350 **Why the fix:** When computing the popup's title, we try to get the current product based on the variants choices in the popup. If the product is found, we take that, because it means that it's already in the database. https://github.com/odoo/odoo/blob/0d7f5058664b501779b833609468e535b34356bf/addons/point_of_sale/static/src/app/components/popups/product_configurator_popup/product_configurator_popup.js#L260 If we do not find it, we just take the product template, which does not contain the current extra prices, which is why we got a price of 100 in the exemple. The product is not found because in the case of dynamic variants, the product is only created once it has been ordered at least once. Which means that for this newly created product, it is not yet in the database, so we take the product template instead of the product itself. We now also add the extra price for a product if it is undefined, meaning it has not been found in the database yet. We can't directly update the getter for the priceExtra, as it's also used to build the payload. As the rest of the code works fine with dynamic products with extra price the way it is sent now, we only change the title instead of changing the entire logic and computation. opw-6326125 Forward-Port-Of: odoo/odoo#273411
Before this commit: In some cases, an element may have a invisible `/n` first child from the html. When inserting content to it, the insert function doesn't check if the first child is visible, and then split the element wrongly. After this commit: we now check if the previous sibling of the current node is invisible, if so, we don't split the parent element. task-6352841 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/o
Original PR description
Before this commit: In some cases, an element may have a invisible `/n` first child from the html. When inserting content to it, the insert function doesn't check if the first child is visible, and then split the element wrongly. After this commit: we now check if the previous sibling of the current node is invisible, if so, we don't split the parent element. task-6352841 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277619 Forward-Port-Of: odoo/odoo#273958
In the bubble layout, the `name="company_address"` div was inside an unconstrained `<td>`, causing percentage-based widths set in `company_details` (e.g. `width: 25%` on a image) to resolve against the full table cell width, resulting in oversized content compared to other layouts. **Without fix:** <img width="1127" height="411" alt="withoutfix" src="https://github.com/user-attachments/assets/244c3407-1dbb-4b83-95d9-ebaba2b2b13c" /> For e.g, The folder layout wraps the same block in a `w-
Original PR description
In the bubble layout, the `name="company_address"` div was inside an unconstrained `<td>`, causing percentage-based widths set in `company_details` (e.g. `width: 25%` on a image) to resolve against…
In the bubble layout, the `name="company_address"` div was inside an unconstrained `<td>`, causing percentage-based widths set in `company_details` (e.g. `width: 25%` on a image) to resolve against the full table cell width, resulting in oversized content compared to other layouts. **Without fix:** <img width="1127" height="411" alt="withoutfix" src="https://github.com/user-attachments/assets/244c3407-1dbb-4b83-95d9-ebaba2b2b13c" /> For e.g, The folder layout wraps the same block in a `w-50` div, so percentage widths resolve against ~half the page width. <img width="1111" height="410" alt="folderexp" src="https://github.com/user-attachments/assets/ee72712a-94da-483c-9a8e-cb3a850dac8e" /> Added `w-50 ms-auto` to the `name="company_address"` div in the bubble layout to align its sizing context with the other layouts, ensuring consistent rendering of user-defined styles in `company_details` across both layouts. **With fix:** <img width="1119" height="413" alt="wfix" src="https://github.com/user-attachments/assets/6b1caf24-3a8e-450f-865e-cce2b9788fe9" /> Commit which made the bubble layout in table: https://github.com/odoo/odoo/commit/8eb61a245cd3b650e309fdb55d24654c34d785cd opw-6287230 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275421 Forward-Port-Of: odoo/odoo#270725
The context variable skip_is_manually_modified needs to be passed in order for the autoposting feature to work. The is_manually_modified variable of the move needs to evaluate to true Fixes error in test TestInvoiceExtract.test_autopost_bills_ocr for mc and fr localizations Related pr: https://github.com/odoo/odoo/pull/271865 runbot-6369932 Forward-Port-Of: odoo/odoo#276953
Original PR description
The context variable skip_is_manually_modified needs to be passed in order for the autoposting feature to work. The is_manually_modified variable of the move needs to evaluate to true Fixes error in test TestInvoiceExtract.test_autopost_bills_ocr for mc and fr localizations Related pr: https://github.com/odoo/odoo/pull/271865 runbot-6369932 Forward-Port-Of: odoo/odoo#276953
Miscellaneous changes
_**Description of the issue/feature this PR addresses:**_ SaleOrder._onchange_order_line retrieves the linked lines of each order line by calling SaleOrderLine._get_linked_lines(). That method filters the whole order_line recordset on every call. Since the onchange is triggered by any change to order_line, this noticeably slows down every modification of the lines on large orders even when the order contains no combo product at all. _**Current behavior before PR:**_ For every order line,
Original PR description
_**Description of the issue/feature this PR addresses:**_ SaleOrder._onchange_order_line retrieves the linked lines of each order line by calling SaleOrderLine._get_linked_lines(). That method…
_**Description of the issue/feature this PR addresses:**_
SaleOrder._onchange_order_line retrieves the linked lines of each order line by calling SaleOrderLine._get_linked_lines().
That method filters the whole order_line recordset on every call.
Since the onchange is triggered by any change to order_line, this noticeably slows down every modification of the lines on large orders even when the order contains no combo product at all.
_**Current behavior before PR:**_
For every order line, _onchange_order_line calls line._get_linked_lines(), and each call re-scans the entire order_line recordset with filtered(). The cost therefore grows with the total number of lines (regular lines included), so editing any line on a large order is sluggish.
_**Desired behavior after PR is merged:**_
The {line: linked_lines} mapping is computed in a single pass via the new method SaleOrderLine._get_linked_lines_by_line(), called once per onchange instead of once per line.
The method _get_linked_lines() is kept as a thin single-record wrapper delegating to the batched method, preserving backward compatibility for external callers. Behavior is unchanged and only the performance is improved: the onchange now scales linearly with the number of order lines.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#277620
Forward-Port-Of: odoo/odoo#277185Issue: User goes to Event.event Form -> communication tab -> add line - can no longer create a social post in template communication tab Fix: remove "no_create_edit: True" to the associated field in the xml to unblock creation of new mail.templates Reverted from commit (odoo/odoo@f58e9f97192ac0ff8d159377494d6c68f871d20b) due to not being able to make social media posts on event communication tab. I originanlly suggested this change because WA Templates need more limitations for creation
Original PR description
Issue: User goes to Event.event Form -> communication tab -> add line - can no longer create a social post in template communication tab Fix: remove "no_create_edit: True" to the associated field in the xml to unblock creation of new mail.templates Reverted from commit (odoo/odoo@f58e9f97192ac0ff8d159377494d6c68f871d20b) due to not being able to make social media posts on event communication tab. I originanlly suggested this change because WA Templates need more limitations for creation and edits. This then blocked other creation and edits that rely on this flow. opw-6334168 Forward-Port-Of: odoo/odoo#276031 Forward-Port-Of: odoo/odoo#272262
This reverts commit 787223c. In the point of sale, concurrent sales of the same product can happen, e.g. if several physical points of sales are open at the same time, each with their own session. In the case where the underlying product's valuation is tracked automatically and perpetually, the creation of the pos order leads to the creation of the stock picking, which in turn leads to a search for the next available svl. Because of the flush_all, this can cause lots of retry failures and ass
Original PR description
This reverts commit 787223c. In the point of sale, concurrent sales of the same product can happen, e.g. if several physical points of sales are open at the same time, each with their own session. In the case where the underlying product's valuation is tracked automatically and perpetually, the creation of the pos order leads to the creation of the stock picking, which in turn leads to a search for the next available svl. Because of the flush_all, this can cause lots of retry failures and associated delay/latency/overall perceived slowness for the end user. opw-6206709 Forward-Port-Of: odoo/odoo#276517 Forward-Port-Of: odoo/odoo#275264
all_sm is referenced by two branches of the outer UNION, so PostgreSQL materializes it (a CTE used more than once is an optimization fence). Every query on report_stock_quantity therefore builds the forecast for all products/warehouses first and filters afterwards, so predicates like product_id can't reach the stock_move scan. This hurts single-product lookups such as _read_group() in mrp_report_bom_structure._get_stock_availability(), called repeatedly per component while rendering a BoM rep
Original PR description
all_sm is referenced by two branches of the outer UNION, so PostgreSQL materializes it (a CTE used more than once is an optimization fence). Every query on report_stock_quantity therefore builds the…
all_sm is referenced by two branches of the outer UNION, so PostgreSQL materializes it (a CTE used more than once is an optimization fence). Every query on report_stock_quantity therefore builds the forecast for all products/warehouses first and filters afterwards, so predicates like product_id can't reach the stock_move scan.
This hurts single-product lookups such as _read_group() in mrp_report_bom_structure._get_stock_availability(), called repeatedly per component while rendering a BoM report: each call does a full stock_move scan plus two sorts that spill to disk.
Marking all_sm NOT MATERIALIZED lets the planner inline it and push the product_id/warehouse_id filter down to an index scan, removing the full scan, the GENERATE_SERIES expansion and the on-disk sorts. warehouse_cte stays materialized (small and cheap).
Query generated from the _read_group:
```SQL
SELECT MIN("report_stock_quantity"."date")
FROM "report_stock_quantity"
WHERE (
(
(
(
("report_stock_quantity"."state" = 'forecast')
AND ("report_stock_quantity"."date" >= '2026-07-08')
)
AND ("report_stock_quantity"."product_id" = 15743)
)
AND ("report_stock_quantity"."product_qty" >= 1.0)
)
AND ("report_stock_quantity"."warehouse_id" = 4)
)
AND ("report_stock_quantity"."company_id" IN (1))
```
Before:
800 ms by _read_group in _get_stock_availability().
For opening a BoM overview with hundred of components takes 17 sec.
After:
25 ms by _read_group in _get_stock_availability().
Same BoM overview drops to 3 sec to open.
cc @Aurelienvd
I can send you EXPLAIN ANALYZE, but I prefer to not putting them here to avoid data leakage.
Forward-Port-Of: odoo/odoo#277235
Forward-Port-Of: odoo/odoo#275022