Daily updates from Odoo
Thursday, July 2, 2026
31 changes · saas-19.2
Resolved issues and error corrections
This fix ensures grouped customer payments are correctly marked back to “In Process” when a bank statement match is undone. It prevents inconsistent payment states that could otherwise cause problems when reconciling the same batch again.
Original PR description
**Steps to reproduce:** - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A *…
**Steps to reproduce:** - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A * Total; 10.00 - Confirm the invoice - From the invoice list, select both invoice - Create payment: * Journal: Bank * Group Payments: [checked] * Group Payments: [checked] * Amount: 40.00 - Create a third invoice for another customer: * Customer: Partner B * Total: 25.00 - Confirm the invoice - Register payment from the invoice - Create a fourth invoice for another customer: * Customer: Partner C * Total; 40.00 - Confirm the invoice - Register payment from the invoice - From the payment list, select all 3 payments and create batch payment - Validate the batch payment - From Accounting dashboard, open Bank journal - Create a new bank statement line of 105.00 - Match it with the batch payment At that point, the statement line is reconciled with the 4 invoices and the 3 payments are marked as paid. - Go to the fourth invoice - Reset it to draft - Change the price - Save When the amount of the invoice is changed, the statement line is unreconciled and all the payments should change state from "Paid" to "In Process". **Issue:** All the single payments have their state correctly changed to "In Process", except for the group payment for the 2 first invoices, which leads to undesired values when trying to reconcile the statement line with the batch payment again. **Cause:** When the statement is unreconciled, all the partial reconcile records are deleted and the state of the linked payments are updated to "In Process". The payments are retrieved by checking if there are linked to an account move present in the partial reconcile record and if the amount of the payment matches the amount of the partial reconcile record. In case of a group payment, there are 2 partial reconcile records for each invoice linked to the payment. Therefore, in that case, the amount doesn't match the amount of the payment because it matches the amount of one of the invoice. opw-6141089 Forward-Port-Of: odoo/enterprise#122195 Forward-Port-Of: odoo/enterprise#120210
When Point of Sale fails to create a database transaction, the system now shows the real underlying error instead of a generic message. This makes it much easier for support teams and developers to understand what went wrong and resolve issues faster.
Original PR description
Before this commit the error "Transaction could not be created" was thrown when the transaction could not be created. This commit changes the behavior to throw the actual error that caused the transaction creation to fail, providing more context for debugging. Forward-Port-Of: odoo/odoo#273116
This change prevents invoice notifications from crashing when they are sent in a different language than the one used during invoice entry. It ensures Quick Edit invoices can still be confirmed and emailed successfully, improving reliability for multilingual teams.
Original PR description
**Steps to Reproduce:** - Install the Accounting and Contacts modules. - Enable Quick Encoding for Customer Invoices and Vendor Bills in the company settings. - Create a new customer: Assign a…
**Steps to Reproduce:**
- Install the Accounting and Contacts modules.
- Enable Quick Encoding for Customer Invoices and Vendor Bills in the company
settings.
- Create a new customer: Assign a salesperson.
- Ensure:
- The salesperson is not a login user.
- The customer language, salesperson's language, and Login user's language
are different. Example:
- Customer language: English
- Salesperson language: French
- Login user language: French
- Create a customer invoice using the Upload Document functionality.
- Select the customer created above.
- Use Quick Edit mode and enter an amount and Click Confirm.
**Issue:**
- When the invoice notification is rendered in a language different from the one
used during the write operation, the notification rendering flow calls
_notify_by_email_prepare_rendering_context().
- During rendering, the code executes:
```
self.tax_totals.get('total_amount_currency', 0)
```
- Since tax_totals is protected, the ORM returns False instead of the expected
dictionary, leading to:
```
AttributeError: 'bool' object has no attribute 'get'
```
**Root Cause:**
- This issue occurs in Quick Edit mode because tax_totals is [not read-only](https://github.com/odoo/odoo/blob/1f7a62d38303a992f501b4ecdb1bee437f7279b8/addons/account/views/account_move_views.xml#L1359)
in Quick Edit mode and is included in [the values](https://github.com/odoo/odoo/blob/1f7a62d38303a992f501b4ecdb1bee437f7279b8/addons/web/static/src/model/relational_model/record.js#L708) sent by the web client during write().
- During create()/write(), _get_protected_vals() marks tax_totals as protected.
- Since tax_totals is a [@api.depends_context('lang')](https://github.com/odoo/odoo/blob/1f7a62d38303a992f501b4ecdb1bee437f7279b8/addons/account/models/account_move.py#L975) computed field, it
maintains a separate cache per language. [During write()](https://github.com/odoo/odoo/blob/1f7a62d38303a992f501b4ecdb1bee437f7279b8/addons/account/models/account_move.py#L3955), the [field becomes
protected](https://github.com/odoo/odoo/blob/1f7a62d38303a992f501b4ecdb1bee437f7279b8/addons/account/models/account_move.py#L3863) by [env.protecting()](https://github.com/odoo/odoo/blob/1f7a62d38303a992f501b4ecdb1bee437f7279b8/odoo/orm/fields.py#L1738). While the protection is still active, the mail
notification flow renders the email using the recipient's language. If the
corresponding language-specific cache entry for tax_totals is not available,
the ORM cannot recompute the protected field and returns False instead
of the expected dictionary.
- The rendering code assumes tax_totals is always a dictionary and directly
calls .get(), leading to the crash.
**Solution:**
- Exclude tax_totals from _get_protected_vals().
- tax_totals is already handled explicitly after create()/write(), so protecting
it is unnecessary. This allows the field to be recomputed during notification
rendering when required.
**Result:**
- Invoice notifications render correctly in all languages.
- No RPC crash occurs when rendering notifications after Quick Edit.
**Runbot reproduction: [video](https://github.com/user-attachments/assets/5f045efb-37de-40aa-b135-1368b1601d61)**
**opw-6209647**
Forward-Port-Of: odoo/odoo#266335This update makes an automated discussion test more reliable by ensuring the activity counter starts from a clean state before it runs. It prevents leftover background updates from being counted twice, which helps avoid flaky test failures and improves confidence in the results.
Original PR description
The avatar card tour asserts the systray activity counter, which the browser maintains from "mail.activity/updated" bus notifications. The counter is seeded at page load with a snapshot (activityCounter) and a baseline bus id (activity_counter_bus_id), and only notifications newer than that baseline are applied. The activity unlink/create done while preparing the test emit such notifications whose bus.bus rows are only materialized at precommit, so their ids could land after the baseline and be double-counted, leaving the counter wrong. Reset the bus right before the tour so those setup notifications are dropped and the baseline starts clean, and clear only the user's own pre-existing activities so the snapshot counts just this test's activities. https://runbot.odoo.com/odoo/error/237779 Forward-Port-Of: odoo/odoo#273103
This update corrects how grouped customer payments are handled when a bank reconciliation is undone. It ensures those payments are moved back to "In Process" like other payments, so the statement can be matched again without errors or inconsistent payment states.
Original PR description
**Steps to reproduce:** - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A *…
**Steps to reproduce:** - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A * Total; 10.00 - Confirm the invoice - From the invoice list, select both invoice - Create payment: * Journal: Bank * Group Payments: [checked] * Amount: 40.00 - Create a third invoice for another customer: * Customer: Partner B * Total: 25.00 - Confirm the invoice - Register payment from the invoice - Create a fourth invoice for another customer: * Customer: Partner C * Total; 40.00 - Confirm the invoice - Register payment from the invoice - From the payment list, select all 3 payments and create batch payment - Validate the batch payment - From Accounting dashboard, open Bank journal - Create a new bank statement line of 105.00 - Match it with the batch payment At that point, the statement line is reconciled with the 4 invoices and the 3 payments are marked as paid. - Go to the fourth invoice - Reset it to draft - Change the price - Save When the amount of the invoice is changed, the statement line is unreconciled and all the payments should change state from "Paid" to "In Process". **Issue:** All the single payments have their state correctly changed to "In Process", except for the group payment for the 2 first invoices, which leads to undesired values when trying to reconcile the statement line with the batch payment again. **Cause:** When the statement is unreconciled, all the partial reconcile records are deleted and the state of the linked payments are updated to "In Process". The payments are retrieved by checking if there are linked to an account move present in the partial reconcile record and if the amount of the payment matches the amount of the partial reconcile record. In case of a group payment, there are 2 partial reconcile records for each invoice linked to the payment. Therefore, in that case, the amount doesn't match the amount of the payment because it matches the amount of one of the invoice. opw-6141089 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272954 Forward-Port-Of: odoo/odoo#269510
This fix prevents an error when downloading the PDF of certain Guatemalan vendor bills, specifically those marked as FESP. It also corrects a template reference so the invoice can be generated and downloaded successfully without interruption.
Original PR description
**Steps to reproduce:** - Install the `l10n_gt_edi` module and switch to a `GT Company`. - Create a new vendor bill with: - Vendor: GT Company - GT Document Type: `FESP` - Add taxes `VAT Withholding…
**Steps to reproduce:** - Install the `l10n_gt_edi` module and switch to a `GT Company`. - Create a new vendor bill with: - Vendor: GT Company - GT Document Type: `FESP` - Add taxes `VAT Withholding 12%` and `ISR Withholding 5%` in Invoice lines. - `Confirm` the bill and `Send to SAT`. - From the gear icon, click `Download` > `PDF`. **Error1:** `KeyError: 'gran_total'` **Error2:** `KeyError: 'retencion_grand_total'` **Root Cause:** In commit [1], the code at [2] missed calling `_l10n_gt_edi_add_base_values()` before `_l10n_gt_edi_add_withholding_values()`. However, `_l10n_gt_edi_add_withholding_values()` uses the `gran_total` value, which is initialized by `_l10n_gt_edi_add_base_values()`, resulting in a `KeyError`. Additionally, the report template at [3] references `retencion_grand_total` instead of the correct key `retencion_gran_total`, causing another `KeyError`. **Fix:** This commit prevents errors and ensures users can successfully download the PDF by applying a fix similar to [4], [1]: https://github.com/odoo/enterprise/commit/44afd19e4ed0827e343af0e584c81e579935c9e8 [2]: https://github.com/odoo/enterprise/blob/9846b337cfe1876017c7c2ce3041569d7a2ac03f/l10n_gt_edi/models/account_move.py#L305-L328 [3]: https://github.com/odoo/enterprise/blob/9846b337cfe1876017c7c2ce3041569d7a2ac03f/l10n_gt_edi/views/report_invoice.xml#L72 [4]: https://github.com/odoo/enterprise/blob/9846b337cfe1876017c7c2ce3041569d7a2ac03f/l10n_gt_edi/models/account_move.py#L790-L800 opw-6323049 Forward-Port-Of: odoo/enterprise#122398 Forward-Port-Of: odoo/enterprise#122030
This update prevents an error that could occur when scrapping components from a subcontractor replenishment order. It also ensures forecast stock availability stays accurate in this subcontracting flow, avoiding interruptions for users working with purchase and inventory operations.
Original PR description
[FIX] stock,*: properly compute forecast availability after PO resupply scrap * : mrp_subcontracting_purchase # How to reproduce - Enable Subcontracting in the settings - Create Product A with : -…
[FIX] stock,*: properly compute forecast availability after PO resupply scrap * : mrp_subcontracting_purchase # How to reproduce - Enable Subcontracting in the settings - Create Product A with : - Quantity : > 0 - Routes : Buy & Resupply Subcontractor on Order - Create Product B - Create BOM for that Product with - BOM Type : Subcontracting - Subcontractors : any - Component : Product A - Create a PO for Product B - Confirm the PO Order - Use the Resupply smart button - Click on the gear icons > Scrap - Scrap Product A # The problem A traceback will appear. # Cause There are two main ways to get the picking type's code of a move. Either : - `product_code` which is a related field to `picking_id.picking_type_id.code` : https://github.com/odoo/odoo/blob/0442c66d26b0c23313f17c566b16e34e7b22c2b6/addons/stock/models/stock_move.py#L174 - `picking_type_id.code` where `picking_type_id` is a computed field : https://github.com/odoo/odoo/blob/0442c66d26b0c23313f17c566b16e34e7b22c2b6/addons/stock/models/stock_move.py#L283-L287 When we scrap the products, we call the `do_scrap()` function that creates a new scrap move : https://github.com/odoo/odoo/blob/0442c66d26b0c23313f17c566b16e34e7b22c2b6/addons/stock/models/stock_scrap.py#L158 When we do so, the create move's `picking_code` wil be the code of the picking type of the current picking (The subcontractor resupply) : https://github.com/odoo/odoo/blob/0442c66d26b0c23313f17c566b16e34e7b22c2b6/addons/stock/models/stock_scrap.py#L151 But `picking_type_id.code` will be different because there is a `default_picking_type_id` value set in the context by : https://github.com/odoo/odoo/blob/0442c66d26b0c23313f17c566b16e34e7b22c2b6/addons/purchase_stock/models/purchase_order.py#L223 In our case, theses values end up not being the same. Later, when we compute the forecast information of the move, we prefetch virtual available keys and put the moves in a dict based on those keys. The computation of the virtual available key is based on the `picking_code` of the move : https://github.com/odoo/odoo/blob/0442c66d26b0c23313f17c566b16e34e7b22c2b6/addons/stock/models/stock_move.py#L488-L490 https://github.com/odoo/odoo/blob/0442c66d26b0c23313f17c566b16e34e7b22c2b6/addons/stock/models/stock_move.py#L496-L499 When later we try to fetch back the move, we compute the virtual available key based on `picking_type_id.code` : https://github.com/odoo/odoo/blob/0442c66d26b0c23313f17c566b16e34e7b22c2b6/addons/stock/models/stock_move.py#L529-L536 But since `picking_code` and `picking_type_id.code` are different, the output `key_virtual_available` is also different. Essentially, we add the move in the dict with key A and then try to fetch it back using key B, which gives us a KeyError. opw-6145887 Forward-Port-Of: odoo/odoo#272171 Forward-Port-Of: odoo/odoo#263799
This fix prevents a crash that could happen when a user removes the currency from the payment register in the Argentine withholding flow. It makes the payment screen handle an empty currency safely, so users can continue working without interruption.
Original PR description
When the user removes the currency from the payment register, a traceback is raised. Steps to reproduce the error: - Install ``l10n_ar_withholding`` module - Switch to ``(AR) Exento`` company - Create a new invoice > Confirm > Pay > Unset the currency Traceback: ```py ValueError: Expected singleton: res.currency() ``` https://github.com/odoo/odoo/blob/d98afdc08b46bf458eaa287ea882cc7663286a59/addons/l10n_ar_withholding/wizards/account_payment_register.py#L27 This line causes a traceback with an empty currency when the user removes the currency from the payment register. sentry-7362499567 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272891 Forward-Port-Of: odoo/odoo#255825
This change prevents an access error that could block delivery validation for users with limited Sales access when the related sales order belongs to another salesperson. The system now safely reads only the needed subscription status, so deliveries can be confirmed without exposing additional order details.
Original PR description
## **Issue:** When validating a delivery, users with Sales: Own Documents Only and Inventory Administrator access rights can encounter an access error if the delivery belongs to a sale order owned by…
## **Issue:** When validating a delivery, users with Sales: Own Documents Only and Inventory Administrator access rights can encounter an access error if the delivery belongs to a sale order owned by another salesperson. ## **Steps to reproduce:** - Install sale_subscription_stock. - Create a user with Sales: Own Documents Only and Inventory Administrator access rights. - Create a sale order as another user. - Validate the delivery with the restricted user. ## **Solution:** During _action_done(), [This line](https://github.com/odoo/enterprise/blob/19.0/sale_subscription_stock/models/stock_picking.py#L45) is checking subscription_state. Since the user does not have read access to the sale order, reading this field raises an access error and prevents the delivery from being validated. As the method only needs to read the subscription state, access the field with sudo() to avoid the unnecessary access error while preserving the existing business logic. Runbot Video : [Video](https://drive.google.com/file/d/1d7U2jTCxaaVk2YJcy3bi2SlYuT-yXMsu/view?usp=drive_link) OPW - 6295712 Forward-Port-Of: odoo/enterprise#122420
When a new company is created, its main employee folder will now be placed in the company root area instead of appearing in a personal drive. This keeps employee documents organized in the expected shared location and avoids confusion for administrators.
Original PR description
Steps to reproduce =================== - Install documents_hr. - Log in with admin. - Create a new company `Test`. - Go to Document and choose the new company (top right). - Go to `My Drive`: a folder named `Employees - Test` has been created. This new folder should be created in the `Company` root instead of the `My Drive,` which will hold all the employee folders. Technical =========== When the main employee folder is created via `_generate_employee_documents_main_folders` `owner_id` falls back to the current user, which leads to computing the `user_folder_id` as `My drive,` and so that's why the newly created folder starts appearing there instead of the `Company` root. This PR addresses the issue and sets the `owner_id` to False, which leads to show the main employee folder in the company root. Task-6267352 Forward-Port-Of: odoo/enterprise#120677
Uninstalling Manufacturing could leave behind a filter used by the Stock report, which caused an error when opening that report. This update restores the original behavior during removal, so users can access Stock reporting normally after removing MRP.
Original PR description
Currently an error occurs when user opens stock report after uninstalling mrp. Steps to replicate: - Install mrp. - Uninstall mrp and open `Stock > Reporting > Stock`. Error: ``` ValueError: Invalid…
Currently an error occurs when user opens stock report after uninstalling mrp.
Steps to replicate:
- Install mrp.
- Uninstall mrp and open `Stock > Reporting > Stock`.
Error:
```
ValueError: Invalid field product.product.is_kits in condition ('is_kits', '=', False)
```
Cause:
- The `mrp` module overrides the `stock.action_product_stock_view` window action domain with `is_kits` field referenced inside [1].
- When mrp is uninstalled, the `is_kits` field is removed from `product.product` but the overridden action domain remains stored in the database. Opening the action then tries to evaluate a domain referencing a non-existent field, resulting in this error.
Solution:
- Restore the original `stock.action_product_stock_view` domain during mrp uninstallation to remove the `is_kits` condition.
[1]: https://github.com/odoo/odoo/blob/c8390638cae4b4dafb805bc0d3a4149fb5194934/addons/mrp/views/product_views.xml#L164-L166
sentry-7332688253
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#269512This update prevents an error that could stop users from generating the GSTR-1 Excel file when data from multiple company branches is involved. It makes the export more reliable in common multi-company Indian localization setups, so users can complete report generation without interruption.
Original PR description
Steps to reproduce: - Install `l10n_in_reports` module(Indian Localisation) - Create a branch in `IN Company` > Select both - Create separate invoices for each company - Created the GSTR-1 report for…
Steps to reproduce:
- Install `l10n_in_reports` module(Indian Localisation)
- Create a branch in `IN Company` > Select both
- Create separate invoices for each company
- Created the GSTR-1 report for both company
- While generating Excel, select only main company
Traceback:
```py
File "/home/odoo/src/enterprise/19.0/l10n_in_reports/models/account_return.py", line 2537, in action_generate_gstr1_xlsx
gstr1_json = self._get_l10n_in_gstr1_json()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/19.0/l10n_in_reports/models/account_return.py", line 1071, in _get_l10n_in_gstr1_json
'b2cs': _get_b2cs_json(AccountMoveLine.search(self._get_section_domain('b2cs'))),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/19.0/l10n_in_reports/models/account_return.py", line 672, in _get_b2cs_json
for line, line_tax_details in tax_details.items():
^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'items'
```
Cause:
This issue occurs because, while generating the GSTR-1 Excel report for a particular month, [journal_items] contains account moves from both companies. This happens because the [domain] fetches records for both companies, resulting in move [lines] from both companies being included.
However, while generating the Excel report, only one company is selected. As a result, [tax_details_by_move] does not contain the move data for the branch company, which returns None, causing the error to be raised.
Solution:
Pass an empty `{}` for `tax_details` when only a single company is selected.
[journal_items]: https://github.com/odoo/enterprise/blob/3c3641d9f0753c1ca62285667c4a2786c15e2444/l10n_in_reports/models/account_return.py#L877
[domain]: https://github.com/odoo/enterprise/blob/770ffaac14bfcd2c54a7ce6aca27e0010e7884d4/l10n_in_reports/models/account_return.py#L1387-L1393
[lines]:
https://github.com/odoo/enterprise/blob/3c3641d9f0753c1ca62285667c4a2786c15e2444/l10n_in_reports/models/account_return.py#L1074
[tax_details_by_move]:
https://github.com/odoo/enterprise/blob/3c3641d9f0753c1ca62285667c4a2786c15e2444/l10n_in_reports/models/account_return.py#L880
opw-6242824
Forward-Port-Of: odoo/enterprise#118614When a restaurant order is split, the new order now keeps the original fiscal position and pricelist. This ensures the correct taxes and prices continue to apply after splitting, instead of falling back to default values.
Original PR description
When splitting an order, the new order was created without the original's fiscal position and pricelist, so its lines fell back to the default taxes Steps to reproduce: 1. Create a fiscal position with some tax mapping 2. Create a pricelist with some price rules 3. Add the fiscal position and pricelist to the delivery preset 4. Create a restaurant order as delivery 5. Split the order 6. Pay both of them 7. First order will have the default taxes and prices list instead of preset's ones Part of: https://github.com/odoo/odoo/pull/268862 -opw-6246434 Forward-Port-Of: odoo/odoo#273174 Forward-Port-Of: odoo/odoo#272837
The product classification code 10171500, for Organic fertilizers and plant nutrients, is now visible again in the UNSPSC list. This ensures users can select the correct code when setting up product accounting, avoiding missing classification options.
Original PR description
The code 10171500 - Organic fertilizers and plant nutrients wasn't appearing. In the file that has the unspsc product codes this one was set to False. Steps to reproduce: - Activate module product_unspsc. - Go to product > accounting. - Verify that this code is not listed. Ticket [link](https://www.odoo.com/odoo/project.task/4461974) opw-4461974 Forward-Port-Of: odoo/enterprise#121914
When a planned work order’s start time is changed, Odoo now keeps the original duration and recalculates the end time from it. This prevents unexpected duration changes and avoids cases where dependent work orders could end up with a zero duration.
Original PR description
**Problem:** On a planned work order, changing only the start date (e.g. in the planning gantt edit dialog) corrupts the expected duration instead of just shifting the end date. The duration drifts…
**Problem:** On a planned work order, changing only the start date (e.g. in the planning gantt edit dialog) corrupts the expected duration instead of just shifting the end date. The duration drifts to a wrong value, and in some cases (e.g. dependent work orders) collapses to 0. **Steps to reproduce:** 1. Plan a work order on a workcenter (start, end, expected duration). 2. Open it and change only the start date to a time that is not on a working-hours boundary. 3. The end date updates, but the expected duration is now wrong. **Expected behavior:** Changing the start date replans the work order: the duration is kept and the end date is recomputed from it. This is how 19.0 behaves and how dragging the pill in the gantt already behaves. **Cause of the issue:** Changing date_start triggers _onchange_date_start, which recomputes date_finished from start + duration via plan_hours. That cascades into _onchange_date_finished, which recomputes duration_expected from the dates via get_work_duration_data. Since the resource calendar refactor in 19.2, plan_hours and get_work_duration_data are no longer exact inverses around the work order's own planned slot, so the round trip drifts the duration. **Fix:** Only recompute the duration when the end date was edited on its own. When date_finished already matches the planned end for the current duration, it was merely derived from the start change, so the duration is kept. This keeps the duration authoritative when moving the work order while still recomputing it on a genuine end-date resize. opw-6231569
This change moves a few test checks to the correct module so builds run consistently in both full and single-app setups. It prevents false failures during validation and helps keep deployment checks reliable.
Original PR description
Oversight of: https://github.com/odoo/enterprise/pull/98569 Some assertions were put in the wrong module, making the builds work in "all apps" mode but fail in "single app" mode. This commit moves assertions where they belong. Task-6353709
This change makes Odoo better at processing email attachments from external systems that send an incomplete Content-Type value. Instead of risking file corruption, attachments are now stored correctly even when the email header is non-standard.
Original PR description
[[REF] mail: consolidate attachment Content-Type normalization](https://github.com/odoo/odoo/pull/273097/changes/ad4e34c5c79450b1e976d9ba7047487218690585) Two separate spots handled malformed…
[[REF] mail: consolidate attachment Content-Type normalization](https://github.com/odoo/odoo/pull/273097/changes/ad4e34c5c79450b1e976d9ba7047487218690585)
Two separate spots handled malformed Content-Type headers. Merge them
into one block, read the raw header once with partition(';') to have
both the type and its parameters available without re-fetching the
header for each case.
No behavior change.
[[FIX] mail: handle attachment Content-Type with no subtype](https://github.com/odoo/odoo/pull/273097/changes/7b410fbe606b7e476f0005485e42783834983b75)
Some mailers send attachments with a bare token as Content-Type instead
of a valid 'type/subtype' pair, e.g.:
Content-Type: base64; name="foo.pdf"
Content-Transfer-Encoding: base64
Python's email library normalises any MIME type without a '/' to
'text/plain'. get_content() then decodes the base64 payload as UTF-8
text, replacing invalid byte sequences with U+FFFD. The subsequent
encode('utf-8') bakes those replacements in, permanently corrupting
the stored file.
Per Postel's law [RFC 761], be liberal in what we accept: detect these
non-standard types via `not all(mimetype.partition('/'))` and fall back
to application/octet-stream, keeping the original parameters (filename,
charset, etc.) so the attachment is stored intact.
opw-6227526Gift receipts will no longer include the self-service invoicing QR code. This helps preserve the purpose of gift receipts by keeping pricing information hidden from the recipient.
Original PR description
Gift receipts are intended to be given to the gift recipient and are designed to hide product prices. The self-service invoicing QR code could expose pricing information through the generated invoice, defeating the purpose of the gift receipt. Therefore, remove the self-invoicing QR code from gift receipts. task-6299597 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This change restores a missing update when a phone call activity is marked as done. It ensures the related message is properly updated afterward, preventing inconsistencies in follow-up activity tracking.
Original PR description
In [1], we removed `action_call_done` for call activity, and to use `action_feedback` to mark a call activity done like other activities. However, we forgot to assign `activity_mail_message_id` for later mail message update. Add this in `action_feedback`. [1]: 70ba1812812596e00509415cedcc8f4bdf6c6e37 COMPR: https://github.com/odoo/odoo/pull/267663
When exporting an invoice to PDF, the VAT/TIN label will now appear in the customer’s chosen language instead of the employee’s language. This makes invoices clearer and more consistent for customers who receive documents in their preferred language.
Original PR description
Issue: While exporting an invoice as PDF, Customer VAT is translated according to user language instead of customer chosen language. Steps to reproduce: - In a Belgian company - Install Greek language, but keep English as user language - Create a Customer and select Greek as their language - Create an invoice - Export as PDF Current behavior: - VAT is displayed in user language Expected behavior: - VAT is displayed in customer language (ΦΠΑ) opw-6264065
This change removes the ability to create new journals directly from the journal search popup in places like Point of Sale payment methods. It helps keep journal setup controlled inside the Accounting app, avoiding accidental creation in the wrong context.
Original PR description
Currently on the pos payment method form, if you click "Select more" on the journal field, you will see two buttons 'New' & 'Create New'. Steps to reproduce: ------------------- * Open any pos…
Currently on the pos payment method form, if you click "Select more" on the journal field, you will see two buttons 'New' & 'Create New'. Steps to reproduce: ------------------- * Open any pos payment method * Select the journal field * Select "Search more" > See two creation buttons Why the fix: ------------ One button is the standard "On search more" button which can be hidden using options such as no_create, no_create_edit, ... The second button is defined on the list view for journals and since the search more uses the list view it shows the button as well. Currently we can do that with a context key to ensure that on the "real" list view it's still visible. Why do we want to hide those buttons? Asked the R&D accounting team, it should not be allowed to create journals on the fly. You should only be able to create them inside accounting app. This behavior is not limited to this view but will only be applied locally. The fix can however be applied everywhere where needed. Before the fix: ------------------- <img width="700" height="417" alt="image" src="https://github.com/user-attachments/assets/ca11ea13-c38e-40a1-9848-cbc5edc6226e" /> <img width="1507" height="887" alt="image" src="https://github.com/user-attachments/assets/1cde5d3b-3372-4aca-b5d0-2319bd82c1de" /> After the fix: ---------------- <img width="707" height="474" alt="image" src="https://github.com/user-attachments/assets/01dc7b42-43d6-4b18-a12d-54330d51b92b" /> <img width="1457" height="870" alt="image" src="https://github.com/user-attachments/assets/ff387d3f-f59c-47ad-abfe-a2003669db1a" /> opw-6131231
The Point of Sale payment method screen no longer offers one-click creation of accounting journals from the search dialog. This ensures journals are only created through the Accounting app, reducing accidental setup changes and keeping accounting controls consistent.
Original PR description
Currently on the pos payment method form, if you click "Select more" on the journal field, you will see two buttons 'New' & 'Create New'. Steps to reproduce: ------------------- * Open any pos…
Currently on the pos payment method form, if you click "Select more" on the journal field, you will see two buttons 'New' & 'Create New'. Steps to reproduce: ------------------- * Open any pos payment method * Select the journal field * Select "Search more" > See two creation buttons Why the fix: ------------ One button is the standard "On search more" button which can be hidden using options such as no_create, no_create_edit, ... The second button is defined on the list view for journals and since the search more uses the list view it shows the button as well. Currently we can do that with a context key to ensure that on the "real" list view it's still visible. Why do we want to hide those buttons? Asked the R&D accounting team, it should not be allowed to create journals on the fly. You should only be able to create them inside accounting app. Before the fix: ------------------- <img width="700" height="417" alt="image" src="https://github.com/user-attachments/assets/6b67a45b-6e52-4e02-a827-1aca5d8417ec" /> <img width="1507" height="887" alt="image" src="https://github.com/user-attachments/assets/077bc3ab-bc6e-42a1-85e6-adf778000b92" /> After the fix: ----------------- <img width="707" height="474" alt="image" src="https://github.com/user-attachments/assets/da2a43e3-01c0-44c5-b529-e73f21825150" /> <img width="1457" height="870" alt="image" src="https://github.com/user-attachments/assets/b658b95f-5bc3-4b7a-9e7c-8b182cab48a0" /> opw-6131231
This update fixes a potential issue where cron jobs in the accounting module could incorrectly report progress even when errors occurred. Now, progress is only recorded when a job completes successfully or when a specific error is handled. This enhances the reliability and accuracy of accounting processes.
Original PR description
The previous fix commits progress even when an unexpected exception escaped the loop iteration when _autopost_draft_entries. Now progress is only committed on success or when a UserError is explicitly handled. Reference: https://github.com/odoo/odoo/pull/271509 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273115
This update resolves a bug in the l10n_eg token setup process for IoT devices. A recent change simplified the process by storing the actual token instead of a hash, but this caused validation errors. The fix ensures the system correctly handles both token and hash formats, preventing errors and maintaining a smooth setup experience.
Original PR description
In odoo/odoo#255121, the l10n_eg token flow was simplified to store the token automatically in the IoT config when running the installer, instead of showing a popup requiring the user to save the token manually. However, this broke the flow because previously, a *hash* of the token was being stored in the IoT config, but now the actual token is stored in the config (which allows it to be sent to the DB). The token validation logic was not updated accordingly, so it would try to use the token itself as a hash which would result in an `UnknownHashError`. To fix this, we first check if the provided token matches the stored token exactly. If it doesn't, we assume it is a hash and continue with the old flow as before. Logging statements are added in every failure case to ease debugging in the future. opw-6049363 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273033
This update resolves an issue preventing POS managers without administrative rights from modifying POS configurations, specifically background images. The fix removes a restriction that blocked edits to images uploaded by other users, ensuring all POS managers have the necessary access to manage their POS settings. This improves usability and operational efficiency.
Original PR description
When editing a POS config, `_ensure_public_attachments` wrote `public=True` on the self-ordering background/home images on every write. These images are Many2many attachments created with a `res_model` but no `res_id`, so the attachment access check denies write to any non-system user who is not their creator.
As a result, a POS manager without Settings/Admin rights could not edit a config whose images were uploaded by another user (e.g. an admin during setup), getting:
AccessError: Sorry, you are not allowed to access this document.
(Operation: write) - Records: ir.attachment(...), User: ...
Steps to reproduce:
1. Enable self-ordering on a POS and select a background image
2. Set self-ordering back to disabled
3. Log in as a POS admin without Admin/Settings rights
4. Try to edit the POS -> error
opw-6331261
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#273299This update prevents minimal rights employees from accidentally entering negative quantities when using the point-of-sale system. Previously, pressing the '-' key could lead to incorrect order totals. This fix ensures data accuracy and prevents potential errors when using the system with restricted user permissions.
Original PR description
Currently minimal rights employee cannot select the "+/-" button to have a negative quantity line. However if they have a keyboard and press the "-" key they can modify the quantity to negative. Steps to reproduce: ------------------- * Modify the shop settings, give some employee minimal rights * Open shop and use the minimal employee as cashier * Add a product to the order * Press the "-" key on the keyboard > The line quantity becomes -1 Why the fix: ------------ The button on the product screen is disabled for the employee with minimal rights https://github.com/odoo/odoo/blob/4a2aa33ded628200935b22c501a5f94c21dffb1f/addons/point_of_sale/static/src/app/screens/product_screen/product_screen.js#L154 We extend that to the input key "-". opw-6248098 Forward-Port-Of: odoo/odoo#267748
A test was failing due to a user account lacking the necessary permissions to access timesheets. This update grants the required group access, ensuring the test now passes and the timesheet functionality remains accessible for the testing user. This resolves a technical issue preventing proper test execution.
Original PR description
A few weeks after this test was introduced, some changes were made to the `get_calendar_events()` function on `account.analytic.line`, which caused this test to fail due to insufficient access rights. The reasoning is because the user we run this test as does not have the "User: own timesheets only" group, so they aren't able to access timesheets at all. Here, we grant this group to the user to prevent this error, as they should be able to access their own timesheets. [runbot-940437](https://runbot.odoo.com/odoo/error/940437) Forward-Port-Of: odoo/enterprise#122545
This update fixes a website accessibility issue where language selector flags lacked alternative text descriptions. This ensures the website is usable by screen readers and search engines, improving inclusivity and SEO. The change adds necessary alt text to the flag images when both inline and flag options are enabled.
Original PR description
Steps to reproduce: 1. Enable the language selector in the website header. 2. Enable the "Inline" and "Flag" options. 3. Inspect the flag images rendered in the inline variant. Issue: Flag images in the list items have an empty `alt=""` attribute in "Flag only" mode, where the flag is the sole visual indicator of the language, making the selector inaccessible to screen readers and providing no context for search crawlers. Expected behavior: Inline + Flag should have a descriptive ALT tag since there is no adjacent text or code to identify the language, the flag is not decorative. opw-6246464 Forward-Port-Of: odoo/odoo#273025 Forward-Port-Of: odoo/odoo#271362
This update fixes an issue where the cookie bar buttons were too close together, creating a cluttered appearance. The change utilizes Bootstrap spacing classes to ensure consistent and professional spacing across different layouts. This improves the user experience and visual consistency of the website.
Original PR description
[FIX] website: preserve cookie bar button spacing Steps to reproduce: - Enable the cookies bar in the website settings. - Go to the website and enter edit mode. - Open the cookies bar from the invisible elements panel. - Select the "Discrete" layout in the options. => The buttons and link are rendered without the expected spacing. Before this commit, the client-side cookie bar template relied on whitespace-only text nodes to separate inline elements. Those nodes are not kept in the same way when the template is rendered by Owl, so selecting the layout could make adjacent buttons touch each other. After this commit, the spacing is carried by explicit Bootstrap spacing classes, so the rendered layout no longer depends on text nodes preserved by the XML formatting. task-6251151 Forward-Port-Of: odoo/odoo#272641 Forward-Port-Of: odoo/odoo#267488
This update resolves a technical issue where Chrome browsers were unable to properly display audio previews within the Documents app. The fix blocks audio file previews by default, aligning with our strategy to avoid using Odoo Enterprise as a media streaming platform. This ensures consistent functionality across browsers.
Original PR description
**Steps to reproduce:** - Install Documents app - Upload a sound file (mp3 for example, but the behavior is the same for other formats) - Share the document and copy the link - Log out - Paste the…
**Steps to reproduce:**
- Install Documents app
- Upload a sound file (mp3 for example, but the
behavior is the same for other formats)
- Share the document and copy the link
- Log out
- Paste the link
- Click on preview button
- Media is working fine on Firefox
- Media won't read on Chrome
```
Loading media from '' violates the following Content Security Policy directive: "default-src 'none'".
Note that 'media-src' was not explicitly set, so 'default-src' is used as a fallback.
The action has been blocked.
```
**Issue:**
Since [1] default CSP Headers are too strict for Chrome default media rendering, which breaks the file preview (and force user download).
This only impacts Chrome as they seem to render generate `<video><source>` elements to render the file which triggers a secondary request and fails due to the CSP constraint.
**Fix:**
Could re-apply the header fix of 17.4 (see [2]), but it seems better to block the preview of audio files as well by default (to match how we manage videos).
(Note: we don't want to be used as a media streaming platform)
[1] (set csp to none by default) https://github.com/odoo/odoo/commit/64beb80205dffe4b432c8b5813a3271b073fa85e
[2] (similar issue which was not fixed in 18.0+) https://github.com/odoo/enterprise/commit/a7af78eeb2b9763045a5bda8714172f5e7402df8
[3] (mp4 preview removed) https://github.com/odoo/enterprise/commit/ea88cf7c6d5f077b60fb59347659507fded0e2fe
opw-6235043
Forward-Port-Of: odoo/enterprise#119644This update fixes an issue where the Auto Plan feature incorrectly assigned resources to slots based solely on project membership, ignoring the role assigned to the slot. Now, the system ensures resources are assigned based on the specified role, preventing misallocation and improving planning accuracy. This ensures resources are assigned to the correct roles when using the Auto Plan feature.
Original PR description
## Issue When using the *Auto Plan* feature on a planning slot with a Role and a Project set, a resource which operated on the same project will be chosen if available, without taking into account…
## Issue
When using the *Auto Plan* feature on a planning slot with a Role and a Project set, a resource which operated on the same project will be chosen if available, without taking into account the Role set on the slot.
## Steps to reproduce
1. Install Project Planning (`project_forecast`)
2. In Planning > Configuration > Roles, create two planning roles A and B
- Role A: Assign a resource R
- Role B: No resource
3. Open Planning (Schedule by Resource), and go back a few weeks (to prevent overlaps with potential demo data)
4. Create two new slots:
1. Set Role B and a random Project P, then click Auto Plan: there should be no available resource (because we didn't set any resource for Role B)
2. Set Role A and the same Project P, then click Auto Plan: it should assign the resource R assigned to Role A
5. After assigning a resource to the slot for Role A, edit the Open Shift for Role B again and click Auto Plan: **it assigns the same resource R, even though that resource is not assigned to Role B.**
## Cause
The `_get_open_shifts_resources` override in `project_forecast` looks for resources that were assigned to slots related to the same project. It does not filter resources based on the requested role.
https://github.com/odoo/enterprise/blob/885edbc270a86ab76e0a6eff4acb5767c0fe29d1/project_forecast/models/planning_slot.py#L104-L116
This means that resources that are not part of the requested role can be assigned to the slot, as long as the resource operated on another slot for the same project.
opw-6325744
Forward-Port-Of: odoo/enterprise#122035