Daily updates from Odoo
Tuesday, August 4, 2026
70 changes
10 changes
Enhancements to existing features
The Timesheet Timeline view now shows assistant suggestions in true chronological order instead of sorting them by title. It also displays each suggestion's start time, making it easier for users to review and enter timesheets accurately.
Original PR description
Forward-Port-Of: odoo/enterprise#125574 Forward-Port-Of: odoo/enterprise#122862
Payroll batch processing has been optimized by removing unnecessary work entry generation and reducing repeated processing during payslip calculations. This should make large payroll runs noticeably faster, especially when computing many payslips at once.
Original PR description
Backport of https://github.com/odoo/enterprise/pull/124776 without the populate blueprint. Forward-Port-Of: odoo/enterprise#126561 Forward-Port-Of: odoo/enterprise#125288
Resolved issues and error corrections
This fix updates Belgian hospitality payroll so CP302 eco-vouchers are prorated according to the correct full-time and part-time rules. It helps ensure employees receive the right voucher amount when they work part of the year, work part-time, or have unpaid absences.
Original PR description
Per the CP302 rules:
- Full-time, incomplete year: 250 × complete_months/12 + 250 × working_days/divisor for any partial month at start/end.
- Part-time: 250 × working_days/divisor. Days are counted as-is ("each daily service = 1 day regardless of duration"), so work_time_rate is not applied to the day count.
- Divisor: 260 (5-day week) or 312 (6-day week).
- Working days use `get_work_duration_data(compute_leaves=False)` so public holidays stay assimilated; only unpaid absences are deducted.
task-6375105
Forward-Port-Of: odoo/enterprise#124297Quotations created from repair orders linked to helpdesk tickets now correctly use the salesperson assigned to the customer. This prevents sales ownership from being left blank, helping teams keep follow-up and reporting accurate.
Original PR description
Currently, when a quotation is created from a repair order generated from a helpdesk ticket, the salesperson is not set on the quotation even if the customer has a salesperson assigned. **Steps to…
Currently, when a quotation is created from a repair order generated from a helpdesk ticket, the salesperson is not set on the quotation even if the customer has a salesperson assigned. **Steps to Reproduce:** - Install `helpdesk_repair`. - Go to `Helpdesk` > `Configuration` > `Helpdesk Teams`. - Open a team recod and enable `Repairs`. - Create a `contact/customer` with a `salesperson` assigned. - Go to `Helpdesk`, create a ticket for that `customer`, and select the `helpdesk team` configured above. - Click `Repair`, then click `Create Quotation`. - Open the quotation and check the `Salesperson` field in the `Other Info` tab. **Current behavior:** The Salesperson field on the quotation remains empty. **Expected behavior:** The Salesperson field on the quotation should inherit the salesperson assigned to the selected customer/contact. **Cause of the issue:** When a repair order is created from a helpdesk ticket, default_user_id [1] is passed in the context . This value is propagated when creating the repair order [2] . Later, when creating the quotation from the repair order [3], the same context is reused. Because default_user_id is already present in the context, it overrides the precomputation of user_id from the customer. As a result, user_id is initialized with an empty value and remains unset. **Fix:** This commit ensures that default_user_id is removed from the context before creating the sale order. Without a default value for user_id, the field is correctly precomputed from the selected customer, and the salesperson is properly assigned. [1]- https://github.com/odoo/enterprise/blob/2662932c7ac8ebf3ed5a05d44d7ebfaff869fcbd/helpdesk_repair/models/helpdesk_ticket.py#L52 [2]- https://github.com/odoo/enterprise/blob/2662932c7ac8ebf3ed5a05d44d7ebfaff869fcbd/helpdesk_repair/models/helpdesk_ticket.py#L36-L40 [3]: https://github.com/odoo/odoo/blob/29328b8fccff833c14de317b51f3b4e5a8c40f75/addons/repair/models/repair.py#L357 opw-6344939 Forward-Port-Of: odoo/enterprise#126310 Forward-Port-Of: odoo/enterprise#122980
Non-admin CRM users can once again create leads from business card pictures when the related feature is available. The change fixes an overly restrictive dropdown permission check while still showing access messages when users lack rights for actions tied to a specific model.
Original PR description
**Steps to reproduce:** - Go to CRM app as an internal user (non-admin) - Click on Generate button - Can't create leads from business card pictures - Only setting the user as admin enables it (was…
**Steps to reproduce:** - Go to CRM app as an internal user (non-admin) - Click on Generate button - Can't create leads from business card pictures - Only setting the user as admin enables it (was working fine in previous versions) **Issue:** Dropdown action is restricted to admin only by default using `hasAccess`. If there is a corresponding model on the `LeadGenerationDropdown` it is later changed according to the current user access rights using `await user.checkAccessRight(model, "create")`. **Fix:** Default `hasAccess` to `True` as there is no related model for the lead generation of business cards. (Note: could also provide the missing model ?) - Installation should be restricted to the admin. - Access message should be shown to the user if he doesn't have enough rights to the related model. - Non-admin users should be able to use the feature if no model is provided and the related app is available. dropdown: https://github.com/odoo/odoo/commit/978019522746ccb971eeb15c5d9530e438b7d2f3 business card: https://github.com/odoo/enterprise/commit/48a9cba24cb51b11a08dd9c0ff1291e15232260f opw-6258689 Forward-Port-Of: odoo/enterprise#121682
The cart now prevents customers from increasing rental product quantities beyond what is available for the selected rental dates. Availability is also rechecked when rental dates are changed, helping avoid overbooking planned service resources.
Original PR description
From the cart, it is possible to increase the amount ordered of a rental product that synchronizes shifts depending on a specific service Steps to reproduce: 1. Install website_sale_renting_planning…
From the cart, it is possible to increase the amount ordered of a rental product that synchronizes shifts depending on a specific service Steps to reproduce: 1. Install website_sale_renting_planning module 2. Go to Rental > Products and create a new product "test" with Sales enabled, Product Type "Service", Plan Services enabled as "Developer", in the Sales tab, enable Is Published and in the Rental prices tab, create a pricing for Daily period 3. In the General Information tab, click on the internal link to "Developer" 4. Enable Sync Shifts and Rental Orders 5. Go to the eCommerce website and search for product "test" 6. Add as much product "test" to the cart as possible (the quantity is limited) 7. Open the cart 8. You can increase the amount of the product regardless of its availability Issue: We don't check the renting availabilities to limit the maximum quantity of the product Solution: Check that the new quantity of the product is available in `_verify_updated_quantity` for the specified dates. We also need to check the availability of the product when we modify the rental dates opw-6274035 Forward-Port-Of: odoo/enterprise#126275 Forward-Port-Of: odoo/enterprise#123056
Preparation ticket printing for Belgian self-order point of sale now uses the OBOX device instead of the point-of-sale terminal. This fixes the printing flow so tickets are handled by the compliant blackbox setup, reducing operational issues for affected restaurants and shops.
Original PR description
Impression of preparation ticket are now handled via the OBOX instead of the PoS terminal. See https://github.com/odoo/enterprise/pull/125348 Forward-Port-Of: odoo/enterprise#126611
Preparation tickets and receipts now load the styling and information they need after the receipt printing refactor. This restores the expected printed layout, brings back missing receipt data such as customer notes, and improves the point-of-sale customer and kitchen workflow.
Original PR description
..., pos_restaurant, pos_self_order, pos_urban_piper --- During the refactor of the receipt printing system, some CSS classes were no longer loaded with preparation tickets. As a result, preparation tickets lost part of their original styling. To restore the expected rendering, ensure all required classes are properly loaded while keeping the loading minimal. Additionally, some receipt data were missing after the refactor and some UI elements could be improved. This commit restores the missing data and improves the overall UI. It also fixes an issue where customer notes were not printed on the receipt. Templates checked: * point_of_sale.pos_order_change_receipt * point_of_sale.pos_order_change_receipt_line --- Task: https://www.odoo.com/odoo/project/1737/tasks/6133403 Refacto: https://github.com/odoo/odoo/pull/244395 Forward-Port-Of: odoo/enterprise#124603 Forward-Port-Of: odoo/enterprise#118782
This fixes how Indian localization reports classify transaction types for POS and other non-purchase entries. Existing databases are updated so prior records use the corrected classification, improving report accuracy.
Original PR description
Description: In #118297 non-sales journal moves were considered purchase moves during l10n_in_transaction_type computation, which is not correct for POS moves as their journal is of type 'general'. Fix: Compare only the purchase journal moves state against the partner state. Other moves treated as sales and their state compared against the company state. Add a migration script to update existing databases. opw-638646 Forward-Port-Of: odoo/enterprise#125697
Restaurant orders using German Fiskaly certification now send the first added item to the Kitchen Display immediately. This prevents kitchen staff from missing new orders until a second item is added, improving order visibility and service flow.
Original PR description
**Step To Reproduce:** 1. Configure a POS with German Fiskaly (l10n_de_pos_cert), Restaurant, and Kitchen Display (pos_preparation_display). 2. Create a new order in the POS and add the first…
**Step To Reproduce:** 1. Configure a POS with German Fiskaly (l10n_de_pos_cert), Restaurant, and Kitchen Display (pos_preparation_display). 2. Create a new order in the POS and add the first product. 3. Observe that the order does not appear on the Kitchen Display. 4. Add a second product to the same order. 5. Observe that the order now appears on the Kitchen Display. **Issue:** The first product of a new restaurant order is not synchronised with the Kitchen Display when the German Fiskaly localisation is enabled. **Reason:** `syncAllOrders()` only processes orders returned by `getPendingOrder()` and ignores orders explicitly passed through `options.orders`. After the initial Fiskaly synchronisation, the order is serialised and removed from the pending queue. Consequently, the Preparation Display synchronisation receives no orders from `getPendingOrder()`, preventing the order from reaching the backend. **Solution:** Update `syncAllOrders()` to prioritize the orders explicitly provided through `options.orders`. When `options.orders` is not available, fall back to the existing behavior by synchronizing the orders from `orderToCreate` and `orderToUpdate`. opw-6321376 Forward-Port-Of: odoo/enterprise#125743
7 changes
Enhancements to existing features
Payroll batch processing has been optimized by avoiding repeated and unnecessary work entry calculations. This should make payroll runs and payslip recomputation noticeably faster, especially for companies processing large employee batches.
Original PR description
Backport of https://github.com/odoo/enterprise/pull/124776 without the populate blueprint. Forward-Port-Of: odoo/enterprise#125288
Resolved issues and error corrections
Quotations created from helpdesk repair orders now correctly use the salesperson assigned to the customer. This prevents sales ownership from being missed when teams create quotes from repair-related helpdesk tickets.
Original PR description
Currently, when a quotation is created from a repair order generated from a helpdesk ticket, the salesperson is not set on the quotation even if the customer has a salesperson assigned. **Steps to…
Currently, when a quotation is created from a repair order generated from a helpdesk ticket, the salesperson is not set on the quotation even if the customer has a salesperson assigned. **Steps to Reproduce:** - Install `helpdesk_repair`. - Go to `Helpdesk` > `Configuration` > `Helpdesk Teams`. - Open a team recod and enable `Repairs`. - Create a `contact/customer` with a `salesperson` assigned. - Go to `Helpdesk`, create a ticket for that `customer`, and select the `helpdesk team` configured above. - Click `Repair`, then click `Create Quotation`. - Open the quotation and check the `Salesperson` field in the `Other Info` tab. **Current behavior:** The Salesperson field on the quotation remains empty. **Expected behavior:** The Salesperson field on the quotation should inherit the salesperson assigned to the selected customer/contact. **Cause of the issue:** When a repair order is created from a helpdesk ticket, default_user_id [1] is passed in the context . This value is propagated when creating the repair order [2] . Later, when creating the quotation from the repair order [3], the same context is reused. Because default_user_id is already present in the context, it overrides the precomputation of user_id from the customer. As a result, user_id is initialized with an empty value and remains unset. **Fix:** This commit ensures that default_user_id is removed from the context before creating the sale order. Without a default value for user_id, the field is correctly precomputed from the selected customer, and the salesperson is properly assigned. [1]- https://github.com/odoo/enterprise/blob/2662932c7ac8ebf3ed5a05d44d7ebfaff869fcbd/helpdesk_repair/models/helpdesk_ticket.py#L52 [2]- https://github.com/odoo/enterprise/blob/2662932c7ac8ebf3ed5a05d44d7ebfaff869fcbd/helpdesk_repair/models/helpdesk_ticket.py#L36-L40 [3]: https://github.com/odoo/odoo/blob/29328b8fccff833c14de317b51f3b4e5a8c40f75/addons/repair/models/repair.py#L357 opw-6344939 Forward-Port-Of: odoo/enterprise#126310 Forward-Port-Of: odoo/enterprise#122980
Non-admin CRM users can again create leads from business card pictures when the related app is available. This fixes an access check that incorrectly hid the option unless the user had administrator rights, restoring the expected workflow for sales teams.
Original PR description
**Steps to reproduce:** - Go to CRM app as an internal user (non-admin) - Click on Generate button - Can't create leads from business card pictures - Only setting the user as admin enables it (was…
**Steps to reproduce:** - Go to CRM app as an internal user (non-admin) - Click on Generate button - Can't create leads from business card pictures - Only setting the user as admin enables it (was working fine in previous versions) **Issue:** Dropdown action is restricted to admin only by default using `hasAccess`. If there is a corresponding model on the `LeadGenerationDropdown` it is later changed according to the current user access rights using `await user.checkAccessRight(model, "create")`. **Fix:** Default `hasAccess` to `True` as there is no related model for the lead generation of business cards. (Note: could also provide the missing model ?) - Installation should be restricted to the admin. - Access message should be shown to the user if he doesn't have enough rights to the related model. - Non-admin users should be able to use the feature if no model is provided and the related app is available. dropdown: https://github.com/odoo/odoo/commit/978019522746ccb971eeb15c5d9530e438b7d2f3 business card: https://github.com/odoo/enterprise/commit/48a9cba24cb51b11a08dd9c0ff1291e15232260f opw-6258689 Forward-Port-Of: odoo/enterprise#121682
Rental orders using custom make-to-order routes now correctly generate the expected return transfer as well as the delivery and purchase. This prevents missing return logistics when businesses rent products that are bought or routed specially for a customer order.
Original PR description
### Steps to reproduce: - In the settings enable: Multi-Steps Routes and rental transfers - Unarchive the MTO route - Create a rental product P with a buy route and a set vendor - Create a rental…
### Steps to reproduce: - In the settings enable: Multi-Steps Routes and rental transfers - Unarchive the MTO route - Create a rental product P with a buy route and a set vendor - Create a rental order for 1 x P and set the the MTO route on the sol - Confirm the order #### > The delivery as well as the purchase for 1 unit of P was generated but the return was not. ### Cause of the issue: The procurement generated to handle both the delivery and the return rental picking are handled by the `_create_procurements`: https://github.com/odoo/enterprise/blob/b0e48baaf99bdc4faefd2ffdd3bd5637fb548593/sale_stock_renting/models/sale_order_line.py#L353-L374 The `route_ids` set and used is the `mto_route` set on the sol: https://github.com/odoo/odoo/blob/0f061503e26ac8c441d62d91947419119e48c47a/addons/sale_stock/models/sale_order_line.py#L415-L422 https://github.com/odoo/odoo/blob/0f061503e26ac8c441d62d91947419119e48c47a/addons/sale_stock/models/sale_order_line.py#L282-L297 However, in the present case, the mto route does not contain any rule with a relevant `location_src_id` in the rental location so that the return will not be generated. opw-6361322 Forward-Port-Of: odoo/enterprise#126078 Forward-Port-Of: odoo/enterprise#124097
This fixes how Indian reporting classifies transaction types so point-of-sale and other non-purchase entries are compared against the correct company state. Existing databases are updated through a migration, helping keep local tax reports accurate without manual correction.
Original PR description
Description: In #118297 non-sales journal moves were considered purchase moves during l10n_in_transaction_type computation, which is not correct for POS moves as their journal is of type 'general'. Fix: Compare only the purchase journal moves state against the partner state. Other moves treated as sales and their state compared against the company state. Add a migration script to update existing databases. opw-638646 Forward-Port-Of: odoo/enterprise#125697
Automatic bank transaction matching now ignores archived bank account records when identifying the related partner. This prevents transactions from being assigned to the wrong partner and makes automated matching behave consistently with manual entry.
Original PR description
Steps to reproduce: - Have a partner with a bank account, then archive the res.partner.bank record (keep the partner active). - Import or create a bank transaction (e.g. via bank sync) whose account number matches that archived bank account, and whose label/payment_ref would otherwise match a reconciliation model for a different partner. - Let the transaction go through automatic partner retrieval. => The archived bank account's partner is assigned, even though a normal manual entry (which skips the account-number match) would have used the label instead. Cause of the issue: `AccountBankStatementLine._retrieve_partner()` matches statement lines to partners in batch using raw SQL joining `res_partner_bank`. The query's WHERE clause filters out archived partners (`AND partner.active`) but never filters `res_partner_bank.active`. opw-6340479 Forward-Port-Of: odoo/enterprise#124748 Forward-Port-Of: odoo/enterprise#124537
This fixes an issue where, with German Fiskaly certification enabled, the first item added to a new restaurant POS order did not appear on the Kitchen Display until another item was added. Kitchen staff now see new orders immediately, helping avoid preparation delays and missed items.
Original PR description
**Step To Reproduce:** 1. Configure a POS with German Fiskaly (l10n_de_pos_cert), Restaurant, and Kitchen Display (pos_preparation_display). 2. Create a new order in the POS and add the first…
**Step To Reproduce:** 1. Configure a POS with German Fiskaly (l10n_de_pos_cert), Restaurant, and Kitchen Display (pos_preparation_display). 2. Create a new order in the POS and add the first product. 3. Observe that the order does not appear on the Kitchen Display. 4. Add a second product to the same order. 5. Observe that the order now appears on the Kitchen Display. **Issue:** The first product of a new restaurant order is not synchronised with the Kitchen Display when the German Fiskaly localisation is enabled. **Reason:** `syncAllOrders()` only processes orders returned by `getPendingOrder()` and ignores orders explicitly passed through `options.orders`. After the initial Fiskaly synchronisation, the order is serialised and removed from the pending queue. Consequently, the Preparation Display synchronisation receives no orders from `getPendingOrder()`, preventing the order from reaching the backend. **Solution:** Update `syncAllOrders()` to prioritize the orders explicitly provided through `options.orders`. When `options.orders` is not available, fall back to the existing behavior by synchronizing the orders from `orderToCreate` and `orderToUpdate`. opw-6321376 Forward-Port-Of: odoo/enterprise#125743
7 changes
Enhancements to existing features
Payment export files now include building number details in structured addresses where required by upcoming ISO 20022 rules. This helps businesses stay compliant ahead of the November 2026 mandate and reduces the risk of rejected bank payment files.
Original PR description
This commit adds the <BldgNb> node in the iso20022 XML files, as it will be mandatory starting November 2026. Linked: https://github.com/odoo/odoo/pull/271855 task-6317758 Forward-Port-Of: odoo/enterprise#126444 Forward-Port-Of: odoo/enterprise#121674
Resolved issues and error corrections
This fix prevents an error when creating a Hong Kong payslip for an employee whose record has no contract start date. Payroll users can now select the employee and continue preparing the payslip without the process being blocked.
Original PR description
Currently, an error occurs when a user sets an employee on a payslip. **Steps to Reproduce:** - Install `l10n_hk_hr_payroll` with demo data. - Switch to the `Hong Kong` company. - Create an…
Currently, an error occurs when a user sets an employee on a payslip. **Steps to Reproduce:** - Install `l10n_hk_hr_payroll` with demo data. - Switch to the `Hong Kong` company. - Create an `employee` and make sure that the employee's version has no `contract start date`. - Go to `Payroll` > `Payslips` > `Payslips`. - Create a `payslip` and set that employee. `TypeError: '<' not supported between instances of 'datetime.date' and 'bool'` When a user sets an employee on a payslip, the system computes the worked day lines [1]. If the salary structure uses worked day lines, it creates the corresponding records [2] and calculates out days and out hours based on the contract dates. During this process, the payslip dates are compared with the version's contract start date. If the version does not have a contract start date, it raises an error [3]. This commit ensures that the payslip dates are compared with the version's contract start date, and that out days and out hours are calculated only when the contract start date exists. Cases where no contract start date is defined are already handled in payslip [4]. [1]: https://github.com/odoo/enterprise/blob/03787659236cbcb46c27acebf410ee3d1e9eb15c/hr_payroll/models/hr_payslip.py#L1964 [2]: https://github.com/odoo/enterprise/blob/03787659236cbcb46c27acebf410ee3d1e9eb15c/hr_payroll/models/hr_payslip.py#L1985-L1988 [3]- https://github.com/odoo/enterprise/blob/03787659236cbcb46c27acebf410ee3d1e9eb15c/l10n_hk_hr_payroll/models/hr_payslip.py#L309 [4]- https://github.com/odoo/enterprise/blob/03787659236cbcb46c27acebf410ee3d1e9eb15c/hr_payroll/models/hr_payslip.py#L1092-L1096 sentry-7632216317
Guatemalan electronic invoices now show the same CF customer status on the PDF as in the official XML file. Placeholder tax ID values are treated as missing, and the legal threshold is checked consistently in the company currency, reducing mismatches and compliance risk.
Original PR description
with this commit:- - Display 'CF' in the invoice PDF whenever the generated XML uses CF. - Treat placeholder VAT values such as '/', 'NA', and 'na' as missing VAT. - Compare the invoice total using the company currency instead of the document currency when evaluating the 2,500 threshold, ensuring the legal limit is applied consistently regardless of the invoice currency task-6305333 Forward-Port-Of: odoo/enterprise#120985
Quotations created from repair orders linked to helpdesk tickets now automatically use the salesperson assigned to the customer. This prevents missed ownership on sales documents and helps teams keep follow-up and reporting accurate.
Original PR description
Currently, when a quotation is created from a repair order generated from a helpdesk ticket, the salesperson is not set on the quotation even if the customer has a salesperson assigned. **Steps to…
Currently, when a quotation is created from a repair order generated from a helpdesk ticket, the salesperson is not set on the quotation even if the customer has a salesperson assigned. **Steps to Reproduce:** - Install `helpdesk_repair`. - Go to `Helpdesk` > `Configuration` > `Helpdesk Teams`. - Open a team recod and enable `Repairs`. - Create a `contact/customer` with a `salesperson` assigned. - Go to `Helpdesk`, create a ticket for that `customer`, and select the `helpdesk team` configured above. - Click `Repair`, then click `Create Quotation`. - Open the quotation and check the `Salesperson` field in the `Other Info` tab. **Current behavior:** The Salesperson field on the quotation remains empty. **Expected behavior:** The Salesperson field on the quotation should inherit the salesperson assigned to the selected customer/contact. **Cause of the issue:** When a repair order is created from a helpdesk ticket, default_user_id [1] is passed in the context . This value is propagated when creating the repair order [2] . Later, when creating the quotation from the repair order [3], the same context is reused. Because default_user_id is already present in the context, it overrides the precomputation of user_id from the customer. As a result, user_id is initialized with an empty value and remains unset. **Fix:** This commit ensures that default_user_id is removed from the context before creating the sale order. Without a default value for user_id, the field is correctly precomputed from the selected customer, and the salesperson is properly assigned. [1]- https://github.com/odoo/enterprise/blob/2662932c7ac8ebf3ed5a05d44d7ebfaff869fcbd/helpdesk_repair/models/helpdesk_ticket.py#L52 [2]- https://github.com/odoo/enterprise/blob/2662932c7ac8ebf3ed5a05d44d7ebfaff869fcbd/helpdesk_repair/models/helpdesk_ticket.py#L36-L40 [3]: https://github.com/odoo/odoo/blob/29328b8fccff833c14de317b51f3b4e5a8c40f75/addons/repair/models/repair.py#L357 opw-6344939 Forward-Port-Of: odoo/enterprise#126310 Forward-Port-Of: odoo/enterprise#122980
Selection field values are now shown in the user's language in messages, warnings, and reports. This makes payroll, accounting, recruitment, IoT, appointments, and localization workflows clearer for multilingual users and reduces confusion from untranslated labels.
Original PR description
The `selection` attribute of `fields.Selection` is not generally translated (unless it is a function instead of a list). For user facing strings, we generally need to translate the value displayed. Forward-Port-Of: odoo/enterprise#126633 Forward-Port-Of: odoo/enterprise#126538
This fixes how Indian localization reports classify transaction types for point-of-sale and other non-purchase journal entries. Existing databases are updated so reports compare the right state information, improving accuracy for compliance reporting.
Original PR description
Description: In #118297 non-sales journal moves were considered purchase moves during l10n_in_transaction_type computation, which is not correct for POS moves as their journal is of type 'general'. Fix: Compare only the purchase journal moves state against the partner state. Other moves treated as sales and their state compared against the company state. Add a migration script to update existing databases. opw-638646 Forward-Port-Of: odoo/enterprise#125697
Restaurant orders using German fiscal certification now appear on the Kitchen Display as soon as the first product is added. This prevents kitchen staff from missing or receiving delayed preparation requests for newly created orders.
Original PR description
**Step To Reproduce:** 1. Configure a POS with German Fiskaly (l10n_de_pos_cert), Restaurant, and Kitchen Display (pos_preparation_display). 2. Create a new order in the POS and add the first…
**Step To Reproduce:** 1. Configure a POS with German Fiskaly (l10n_de_pos_cert), Restaurant, and Kitchen Display (pos_preparation_display). 2. Create a new order in the POS and add the first product. 3. Observe that the order does not appear on the Kitchen Display. 4. Add a second product to the same order. 5. Observe that the order now appears on the Kitchen Display. **Issue:** The first product of a new restaurant order is not synchronised with the Kitchen Display when the German Fiskaly localisation is enabled. **Reason:** `syncAllOrders()` only processes orders returned by `getPendingOrder()` and ignores orders explicitly passed through `options.orders`. After the initial Fiskaly synchronisation, the order is serialised and removed from the pending queue. Consequently, the Preparation Display synchronisation receives no orders from `getPendingOrder()`, preventing the order from reaching the backend. **Solution:** Update `syncAllOrders()` to prioritize the orders explicitly provided through `options.orders`. When `options.orders` is not available, fall back to the existing behavior by synchronizing the orders from `orderToCreate` and `orderToUpdate`. opw-6321376 Forward-Port-Of: odoo/enterprise#125743
6 changes
Resolved issues and error corrections
Users can now confirm multiple Brazilian customer invoices using Avalara tax mapping without the process failing. This prevents validation interruptions and supports smoother batch invoice processing.
Original PR description
**_Steps to reproduce:_** * Install `l10n_br_avatax` and configure Avalara Brazil. * Create at least two customer invoices. * Ensure the fiscal position is set to **Automatic Tax Mapping (Avalara…
**_Steps to reproduce:_** * Install `l10n_br_avatax` and configure Avalara Brazil. * Create at least two customer invoices. * Ensure the fiscal position is set to **Automatic Tax Mapping (Avalara Brazil)**. * Select the invoices and click **Action → Confirm Entries**. **_Observed behavior:_** * A traceback is raised with `ValueError: Expected singleton: account.move(...)` and the invoices cannot be validated. **_Cause:_** * During tax extraction, `_extract_tax_values_from_l10n_br_avatax_detail` accesses `self.invoice_filter_type_domain` while `self` may contain multiple `account.move` records. * Accessing `invoice_filter_type_domain` on a multi-recordset raises an `Expected singleton` error, preventing the validation of multiple invoices. **_Fix:_** * Build the returned tax values by iterating over each invoice in the recordset and using the corresponding `invoice_filter_type_domain`. * This ensures `_extract_tax_values_from_l10n_br_avatax_detail` correctly handles multiple invoices during validation without raising a singleton error. opw-6334761 Forward-Port-Of: odoo/enterprise#124993
Quotations created from repair orders linked to helpdesk tickets now automatically use the salesperson assigned to the customer. This avoids missing salesperson information on sales documents and helps ensure proper sales ownership and follow-up.
Original PR description
Currently, when a quotation is created from a repair order generated from a helpdesk ticket, the salesperson is not set on the quotation even if the customer has a salesperson assigned. **Steps to…
Currently, when a quotation is created from a repair order generated from a helpdesk ticket, the salesperson is not set on the quotation even if the customer has a salesperson assigned. **Steps to Reproduce:** - Install `helpdesk_repair`. - Go to `Helpdesk` > `Configuration` > `Helpdesk Teams`. - Open a team recod and enable `Repairs`. - Create a `contact/customer` with a `salesperson` assigned. - Go to `Helpdesk`, create a ticket for that `customer`, and select the `helpdesk team` configured above. - Click `Repair`, then click `Create Quotation`. - Open the quotation and check the `Salesperson` field in the `Other Info` tab. **Current behavior:** The Salesperson field on the quotation remains empty. **Expected behavior:** The Salesperson field on the quotation should inherit the salesperson assigned to the selected customer/contact. **Cause of the issue:** When a repair order is created from a helpdesk ticket, default_user_id [1] is passed in the context . This value is propagated when creating the repair order [2] . Later, when creating the quotation from the repair order [3], the same context is reused. Because default_user_id is already present in the context, it overrides the precomputation of user_id from the customer. As a result, user_id is initialized with an empty value and remains unset. **Fix:** This commit ensures that default_user_id is removed from the context before creating the sale order. Without a default value for user_id, the field is correctly precomputed from the selected customer, and the salesperson is properly assigned. [1]- https://github.com/odoo/enterprise/blob/2662932c7ac8ebf3ed5a05d44d7ebfaff869fcbd/helpdesk_repair/models/helpdesk_ticket.py#L52 [2]- https://github.com/odoo/enterprise/blob/2662932c7ac8ebf3ed5a05d44d7ebfaff869fcbd/helpdesk_repair/models/helpdesk_ticket.py#L36-L40 [3]: https://github.com/odoo/odoo/blob/29328b8fccff833c14de317b51f3b4e5a8c40f75/addons/repair/models/repair.py#L357 opw-6344939 Forward-Port-Of: odoo/enterprise#126310 Forward-Port-Of: odoo/enterprise#122980
Fixed how Indian reporting classifies POS and other non-purchase transactions. This helps ensure existing and future reports compare the right locations and avoid incorrect transaction type results.
Original PR description
Description: In #118297 non-sales journal moves were considered purchase moves during l10n_in_transaction_type computation, which is not correct for POS moves as their journal is of type 'general'. Fix: Compare only the purchase journal moves state against the partner state. Other moves treated as sales and their state compared against the company state. Add a migration script to update existing databases. opw-638646 Forward-Port-Of: odoo/enterprise#125697
Restaurant orders using the German Fiskaly POS setup now appear on the kitchen display as soon as the first product is added. This prevents kitchen staff from missing newly created orders and avoids delays caused by orders only appearing after a second item is added.
Original PR description
**Step To Reproduce:** 1. Configure a POS with German Fiskaly (l10n_de_pos_cert), Restaurant, and Kitchen Display (pos_preparation_display). 2. Create a new order in the POS and add the first…
**Step To Reproduce:** 1. Configure a POS with German Fiskaly (l10n_de_pos_cert), Restaurant, and Kitchen Display (pos_preparation_display). 2. Create a new order in the POS and add the first product. 3. Observe that the order does not appear on the Kitchen Display. 4. Add a second product to the same order. 5. Observe that the order now appears on the Kitchen Display. **Issue:** The first product of a new restaurant order is not synchronised with the Kitchen Display when the German Fiskaly localisation is enabled. **Reason:** `syncAllOrders()` only processes orders returned by `getPendingOrder()` and ignores orders explicitly passed through `options.orders`. After the initial Fiskaly synchronisation, the order is serialised and removed from the pending queue. Consequently, the Preparation Display synchronisation receives no orders from `getPendingOrder()`, preventing the order from reaching the backend. **Solution:** Update `syncAllOrders()` to prioritize the orders explicitly provided through `options.orders`. When `options.orders` is not available, fall back to the existing behavior by synchronizing the orders from `orderToCreate` and `orderToUpdate`. opw-6321376 Forward-Port-Of: odoo/enterprise#125743
User-facing messages and warnings now show translated selection-field values instead of untranslated internal labels. This improves clarity for users working in different languages across accounting, payroll, recruitment, appointments, IoT, point of sale, and localization workflows.
Original PR description
The `selection` attribute of `fields.Selection` is not generally translated (unless it is a function instead of a list). For user facing strings, we generally need to translate the value displayed. Forward-Port-Of: odoo/enterprise#126538
Click and collect rental orders now check availability against the customer’s selected warehouse instead of all warehouses. This prevents customers from being blocked incorrectly when stock is available at the chosen pickup location.
Original PR description
When using the click & collect option, the available qty for renting was not taking the selected warehouse into account. Steps to reproduce: ------------------- * Create 2 different warehouses with 2…
When using the click & collect option, the available qty for renting was not taking the selected warehouse into account. Steps to reproduce: ------------------- * Create 2 different warehouses with 2 different adresses * Create a product available for renting * Setup the product to use serial numbers * Create 2 serial number, 1 in each warehouse * Activate the click & collect option on the website * Create a first sale order to collect in warehouse 1 * In the backend, confirm the order and pick it up * Go back to the website and make a second order for the second warehouse > Observation: When clicking on the "Add to cart" you get an error saying that there is no quantity available Why the fix: ------------ When computing the `product_rented_quantities` it would look for `sale.order.line` in all the warehouse. So it would find the line from the first order even if it's not linked to the selected warehouse. So we just add a new element to the domain to filter out the incorrect warehouses. opw-6328475 Forward-Port-Of: odoo/enterprise#124969
1 change
Enhancements to existing features
Large SEPA direct debit payment batches now validate and send pre-notification emails more efficiently. This reduces waiting time for accounting teams processing hundreds or thousands of payments, helping avoid slowdowns and timeouts.
Original PR description
- Replace the `id:recordset` aggregation in `_get_expiry_date_per_mandate()` with `date:max` to compute the latest payment date directly in SQL. - Render `email_from` for all payments in batch and cache the computed authors by sender email to avoid repeated partner lookups during SDD pre-notification. This reduces ORM/cache overhead when validating large SEPA batches containing thousands of payments. Measured on a production-sized database: | metric | before | after | factor | |--------|-------:|------:|-------:| | `_get_expiry_date_per_mandate` (500 payments) | 564 ms | 111 ms | ~5x | | `_send_after_validation` notification (500 payments) | 92.9 s | 55.7 s | ~1.7x | | `_get_expiry_date_per_mandate` (1000 payments) | 890 ms | 178 ms | ~5x | | `_send_after_validation` notification (1000 payments) | timed out (>159 s) | 108.9 s | completed | OPW-6377340 Forward-Port-Of: odoo/enterprise#126429 Forward-Port-Of: odoo/enterprise#125439
3 changes
Resolved issues and error corrections
Italian withholding tax returns submitted in quarterly months were incorrectly treated as periodic VAT returns, which could open the wrong export wizard, cause errors, or attach the wrong file. The update ensures the LIPE export is only offered for actual VAT returns, improving reliability for Italian tax filing workflows.
Original PR description
In Italy the periodic VAT return (LIPE) is filed quarterly, so `is_quarter_month` gates the XML export wizard on March, June, September and December. That field only looks at the date, never at the…
In Italy the periodic VAT return (LIPE) is filed quarterly, so `is_quarter_month` gates the XML export wizard on March, June, September and December. That field only looks at the date, never at the kind of return, so every Italian return locked on a quarter month was treated as a LIPE. Submitting the withholding tax return therefore opened the LIPE export wizard. Depending on the record the wizard receives, it either crashes while reading the VP lines missing from the withholding report, or silently generates a LIPE file and attaches it to another return. Add an `is_lipe_return` field telling whether the return actually produces the LIPE. Steps to reproduce: - Install `l10n_it_xml_export` and `l10n_it_edi_withholding_reports` on an Italian company with monthly returns - Open Accounting > Reporting > Tax Return - Review and submit the withholding returns up to February - Review then submit the March withholding return --> The LIPE export wizard opens, and the export fails on the withholding report. opw-6255016
UrbanPiper online orders with tax-included products now calculate the unit price correctly when customers order more than one item. This prevents inflated POS order totals and helps keep sales, tax, and reporting figures accurate.
Original PR description
Steps to reproduce: --- - Configure a Point of Sale with UrbanPiper credentials. - Create a product priced at 100 with a 5% GST (Tax Included). - Sync the product with UrbanPiper. - Place an online order with a quantity greater than 1. Issue: --- - `total_with_tax` was incorrectly treated as the unit price for multi-quantity tax-included orders. Fix: --- - Calculate the unit price by dividing `total_with_tax` by the ordered quantity before creating the POS order line. task-6427634 Forward-Port-Of: odoo/enterprise#125989
This fixes a crash that could happen when approval requests were linked through Studio fields and a form recalculated after a change. The system now avoids trying to send notifications from temporary records, improving reliability when working with approved or refused requests.
Original PR description
**Before this change** We have the potential to attempt to send a notification email from virtual records created by our `BaseModel.new()` method. This can happen during an `onchange` request, given…
**Before this change** We have the potential to attempt to send a notification email from virtual records created by our `BaseModel.new()` method. This can happen during an `onchange` request, given that we'll be working with a virtual "snapshot" record to recompute potentially changed values for our origin record after a change to one or more values. This issue manifests when using Studio to attach a many2many field to a form view, where the related model is "Approval Request". If an approval request record in either the "Approved" or "Refused" state is attached to our record via this new Studio field, any `onchange` requests will trigger this bug. This is because we can't send messages on a virtual record. **After this change** Prevent the creation and sending of a message if we are computing the request status of a virtual `approval.request()` record. The field `request_status` on this model is computed and stored, but the fact that it is a computed field means that it must be recomputed for a virtual record, even if the origin record already has a stored `request_status`. Thus, we may need to compute a `request_status` value for an ephemeral "snapshot" record. Though the issue only manifests for the "Approved" and "Refused" states, this PR expands on a test that covers every approval request state. opw-6390453
18 changes
New functionality added to Odoo
Indian payroll users can now choose ENet as a payment export format and generate the required CSV file from the payroll payment wizard. This makes it easier to prepare salary payment files for banks or payment workflows that use ENet.
Original PR description
This PR adds: - a new `export_format` option as "ENet", and its payment methods - if "ENet" is selected, you can generate ENet CSV using the wizard Task-4585620
Enhancements to existing features
This update makes Odoo's AI assistant more flexible by standardizing how browser-side actions are handled and how results are returned to the AI. It also improves user experience by updating AI thinking messages more dynamically, preserving normal view filters when opening records, and preventing new messages while the assistant is still responding.
Original PR description
Purpose: -------- Instead of handling each AI client tool as a special case when posting a message in the thread, a dedicated registry (ai.client_tools) has been added to make it easy to declare and…
Purpose:
--------
Instead of handling each AI client tool as a special case when posting a message in the thread, a dedicated registry (ai.client_tools) has been added to make it easy to declare and extend client-side tool handlers: `registry.category("ai.client_tools").add(name, (thread, params) => cb);`
On the Python side, AI tools can now trigger client-side behavior by returning a "client_tool" entry with a name and params, keeping the server interface minimal and consistent.
Updating the thinking text is now done using one of this tool, allowing to update the thinking text more dynamically. For example, the thought will now be updated when the web search tool has been executed.
Also, with this commit, the action domains are not overridden anymore: before, if you asked to open your crm pipeline, it would open it without the default hidden domain (type = 'opportunity'). Now, this domain will be applied, so that the view opened is the same as if the user opened it manually.
#### Async JS tools
Client tools can now pause the agent loop, return a result from the
browser and resume the conversation with this result.
By default, client tools wait for a result from the browser. Tools that
do not need to return a result can set `oneway` to true, allowing the
agent loop to continue without creating a pending tool call (for example
to show a notification).
Tool confirmations and client tool results use the same pending tool
response flow. Confirming a tool re-executes it on the Python side,
while returning a client tool result resumes the loop without
re-executing the tool.
To add a tool that allows the agent to get a result from the browser,
one needs to:
- add an AI tool in the backend that returns a dict with a `client_tool`
entry: `'client_tool': {'name': name, 'params': {}}`;
- add an AI tool in the frontend with the same name in the
`ai.client_tools` registry and return the result that needs to be sent
to the LLM.
For a client tool that does not need to return a result, use the `'oneway'`
option on the `client_tool` entry:
`'client_tool': {'name': name, 'params': {}, 'oneway': True}`
To prevent race conditions that could happen when the user sends a new
message while a client tool is being processed, the send button will now
be disabled when the agent is generating a response.
This commit also removes references to `ai_session_identifier` which was
not used anymore.
Task-6352942Improves the process that suggests reconciliation rules when assigning accounts to bank statement lines. The change prevents failures and slowdowns caused by very long payment references, making bank reconciliation setup more reliable for accounting users.
Original PR description
When setting an account to an account.bank.statement there is a step to automatically create a reconciliation rule/model if one does not exist already. To do so, we retrieve 5…
When setting an account to an account.bank.statement there is a step to automatically create a reconciliation rule/model if one does not exist already. To do so, we retrieve 5 account.bank.statement.lines and use them to define the reconciliation model config. A matching is done on the payment_ref of the account.bank.statement.lines by finding the longest common substring in the reference. ### Current Implementation The current algorithm does so by first generating all the possible substrings for all the payment_ref before doing the intersection between these sets and returning the max if `len(substring) >=10`. This is reasonable when the payment_ref follows either a SEPA communication national standard like the Belgian one or the Creditor Reference standard (ISO 11649). For transactions with large, unstructured communication with more than 100 chars, the method `_get_common_substrings` quickly overfill the memory, sometimes raising a MemoryErorr, and takes a significant amount of time. That's because the nested function `_generate_all_substrings` generates n*(n+1)/2 substrings, with n being the lenght of a payment_ref, called `label` in `generate_all_substrings`. ### Proposed Fix This commit introduces another algorithm to find the largest common substring. It starts by taking the two smallest labels to find their substrings intersection. We know that for an arbitrary collection of labels, the intersection of their substrings sets A ∩ B ∩...∩ Z is included in the intersection of any two substrings sets. The underlying assumption of the first step is that for an arbitrary collection of labels the intersection of the substrings sets of the two smallest labels will be the smallest intersection of any given pair of substrings sets. This won't hold true everytime and using a metric such as label similarity instead of shortest string might be better. But on average this should be good enough and it's easier to implement + it removes the need of preprocessing the labels to compute the similarity. The point of the new nested function `common_substrings` is to discard common substrings as we build them. Using the current `generate_all_substsrings` on either the smallest label or both smallest labels would still generate and store a lot of substrings, especially for large labels. By yielding the common substrings as we find them, the memory footprint is vastly reduced. Lastly, the next substring in the common_substrings iterable is only checked against the remaining labels if it's longer than the current match. This speeds up the whole process ### speedup In a customer database with some account.bank.statement.line with payment_ref > 500 chars, setting a specific account (code 4970) on transactions goes from MemoryError to < 1Mb memory consumption. Because of the memory consumption it was not possible to gather timing value on the current version. Testing the new algorithm in a shell and using as labels the 5 longest payment_ref in the customer database (831, 831, 1117, 1178, 1300 chars), averaging to 2000 chars once normalised, the average time to execute `_get_common_substrings` is 900 ms ± 10.3 ms. Forward-Port-Of: odoo/enterprise#121575 Forward-Port-Of: odoo/enterprise#118824
The timesheet ActivityWatch suggestions panel now displays total tracked time by project and an overall total at the bottom. This gives users a clearer view of how much time has been captured before creating or reviewing timesheets.
Original PR description
This commit introduces new time tracking metrics to the ActivityWatch suggestions panel to improve user visibility into their tracked hours. **Enhancements:** - Added the total duration per project in the By Project grouped view. - Added a grand total footer for all suggestions at the bottom of the list. task-6088877 Forward-Port-Of: odoo/enterprise#125515 Forward-Port-Of: odoo/enterprise#114772
This update aligns several country-specific Point of Sale accounting and electronic invoicing flows with recent accounting changes. It helps keep POS receipts, fiscal certification, and tax reporting working correctly across affected localizations after the accounting refactor.
Original PR description
Refector PR: https://github.com/odoo/enterprise/pull/112634
Shop floor users can now manually adjust production time logs when a timer was not started or stopped correctly. This helps keep work order timing accurate by creating or closing time entries based on the corrected time.
Original PR description
The "Update Time Log" dialog inside shopfloor is added to increase the timer's reliability by manually entering the desired time. If someone forgot to start the timer, this option adds a new productivity line ending now. If someone forgot to stop it, this option close the timer and set the end date accordingly. Task-6164336
When an item quantity is set to zero in the certified Point of Sale flow, all removed order lines are now visibly struck through, not just weighted products. This improves receipt and order clarity and prevents newly added items from being incorrectly merged with previously removed lines.
Original PR description
We now strike every orderline instead of only the ones related to weightable products, when quantity is set to 0. We also fix an issue where the PoS kept merging new orderlines with strikedthrough ones. task-6425588
Cashiers can now see each customer's due or deposit amount directly on the mobile customer selection card. This makes it easier to spot outstanding balances or available deposits before choosing a customer, speeding up checkout decisions.
Original PR description
This commit adds the customer's due/deposit amount to the customer card displayed in the mobile customer selection list, allowing cashiers to quickly identify outstanding balances or available deposits when choosing a customer. Task-6329233 Related PR: https://github.com/odoo/odoo/pull/272076 <img width="200" height="431" alt="image" src="https://github.com/user-attachments/assets/d4ad9e0a-34f9-4995-84d3-8c28058cba4f" />
HR users can now complete employee document signature requests themselves when they are the only required signer. This removes the unnecessary step of sending the document to the employee, saving time and simplifying the process.
Original PR description
Before:
- When creating a Signature Request from the employee form:
- If the document had only one signer (HR user), the system still asked to
send it to the employee.
- HR users could not sign the document directly.
After:
- If there is only one signer (the HR user):
- The HR user can now sign the document directly.
- No need to send the document to the employee.
Impact:
- Saves time for HR users.
- Makes the process simpler and faster.
- Reduces unnecessary steps.
Task: 6032364Resolved issues and error corrections
Users can now adjust the start or end time of scheduled work orders directly in the Gantt view without triggering an error. The fix also improves handling of dependent work orders, so related scheduling changes continue smoothly instead of failing when a linked item is being moved.
Original PR description
## Problem When dragging the edge of a scheduled workorder to change the start or end time, _web_gantt_move_candidates would throw a traceback. This is because the web call only supplies the new time…
## Problem When dragging the edge of a scheduled workorder to change the start or end time, _web_gantt_move_candidates would throw a traceback. This is because the web call only supplies the new time chosen by the drag+drop. That is, if date_end was changed, date_start wouldn't be present, so accessing the missing field directly triggers a KeyError. This also revealed a secondary issue involving dependent tasks, where if the parent task is rescheduled with the pills, the child task would fail to find candidate reschedule dates (since its only dependency is being moved), and no boundary date would be supplied when calling _web_gantt_reschedule_compute_dates. This led to another traceback. ## Solution For the first issue, we will get the start date and end date from the supplied values more safely, using get() to default to the original start/end. For the second issue, if the boundary date isn't found by _web_gantt_get_first_and_last_possible_dates, we fall back to the candidate's existing start or end date. ## Steps to replicate (Runbot saas-19.4) 1. Create a product with a BOM with 2 operations on the same workcenter 2. Create an MO for this product, confirm it, and plan it 3. Head to Manufacturing > Planning > Work Orders / Planning 4. Try to change the end date of the first work order by dragging the edge of the pill opw-6378769 Forward-Port-Of: odoo/enterprise#124710
Guatemalan electronic invoice PDFs now match the tax information used in the official XML file. This prevents mismatches when customer tax IDs are missing or placeholder values are used, and applies the legal threshold consistently across currencies.
Original PR description
with this commit:- - Display 'CF' in the invoice PDF whenever the generated XML uses CF. - Treat placeholder VAT values such as '/', 'NA', and 'na' as missing VAT. - Compare the invoice total using the company currency instead of the document currency when evaluating the 2,500 threshold, ensuring the legal limit is applied consistently regardless of the invoice currency task-6305333 Forward-Port-Of: odoo/enterprise#120985
This fix lets regular invoicing users post invoices or reset them to draft when Avalara tax integration is enabled. It removes an access-related blocker so day-to-day invoice processing does not require administrator intervention.
Original PR description
The field `avalara_connection_method` has a restriction to only admins, but needs to be read by normal invoicing users in order to post or reset invoices to draft. Forward-Port-Of: odoo/enterprise#126464
Quotations created from repair orders linked to helpdesk tickets now automatically use the salesperson assigned to the customer. This prevents missing salesperson information, helping sales ownership and follow-up stay accurate.
Original PR description
Currently, when a quotation is created from a repair order generated from a helpdesk ticket, the salesperson is not set on the quotation even if the customer has a salesperson assigned. **Steps to…
Currently, when a quotation is created from a repair order generated from a helpdesk ticket, the salesperson is not set on the quotation even if the customer has a salesperson assigned. **Steps to Reproduce:** - Install `helpdesk_repair`. - Go to `Helpdesk` > `Configuration` > `Helpdesk Teams`. - Open a team recod and enable `Repairs`. - Create a `contact/customer` with a `salesperson` assigned. - Go to `Helpdesk`, create a ticket for that `customer`, and select the `helpdesk team` configured above. - Click `Repair`, then click `Create Quotation`. - Open the quotation and check the `Salesperson` field in the `Other Info` tab. **Current behavior:** The Salesperson field on the quotation remains empty. **Expected behavior:** The Salesperson field on the quotation should inherit the salesperson assigned to the selected customer/contact. **Cause of the issue:** When a repair order is created from a helpdesk ticket, default_user_id [1] is passed in the context . This value is propagated when creating the repair order [2] . Later, when creating the quotation from the repair order [3], the same context is reused. Because default_user_id is already present in the context, it overrides the precomputation of user_id from the customer. As a result, user_id is initialized with an empty value and remains unset. **Fix:** This commit ensures that default_user_id is removed from the context before creating the sale order. Without a default value for user_id, the field is correctly precomputed from the selected customer, and the salesperson is properly assigned. [1]- https://github.com/odoo/enterprise/blob/2662932c7ac8ebf3ed5a05d44d7ebfaff869fcbd/helpdesk_repair/models/helpdesk_ticket.py#L52 [2]- https://github.com/odoo/enterprise/blob/2662932c7ac8ebf3ed5a05d44d7ebfaff869fcbd/helpdesk_repair/models/helpdesk_ticket.py#L36-L40 [3]: https://github.com/odoo/odoo/blob/29328b8fccff833c14de317b51f3b4e5a8c40f75/addons/repair/models/repair.py#L357 opw-6344939 Forward-Port-Of: odoo/enterprise#126310 Forward-Port-Of: odoo/enterprise#122980
Internal CRM users can once again create leads from business card pictures without needing administrator rights. The change keeps access checks for actions tied to specific records while allowing the business card option when the related app is available.
Original PR description
**Steps to reproduce:** - Go to CRM app as an internal user (non-admin) - Click on Generate button - Can't create leads from business card pictures - Only setting the user as admin enables it (was…
**Steps to reproduce:** - Go to CRM app as an internal user (non-admin) - Click on Generate button - Can't create leads from business card pictures - Only setting the user as admin enables it (was working fine in previous versions) **Issue:** Dropdown action is restricted to admin only by default using `hasAccess`. If there is a corresponding model on the `LeadGenerationDropdown` it is later changed according to the current user access rights using `await user.checkAccessRight(model, "create")`. **Fix:** Default `hasAccess` to `True` as there is no related model for the lead generation of business cards. (Note: could also provide the missing model ?) - Installation should be restricted to the admin. - Access message should be shown to the user if he doesn't have enough rights to the related model. - Non-admin users should be able to use the feature if no model is provided and the related app is available. dropdown: https://github.com/odoo/odoo/commit/978019522746ccb971eeb15c5d9530e438b7d2f3 business card: https://github.com/odoo/enterprise/commit/48a9cba24cb51b11a08dd9c0ff1291e15232260f opw-6258689 Forward-Port-Of: odoo/enterprise#121682
Restaurant orders using the German Fiskaly POS certification now show on the Kitchen Display as soon as the first item is added. This prevents kitchen staff from missing or delaying newly created orders in affected German POS setups.
Original PR description
**Step To Reproduce:** 1. Configure a POS with German Fiskaly (l10n_de_pos_cert), Restaurant, and Kitchen Display (pos_preparation_display). 2. Create a new order in the POS and add the first…
**Step To Reproduce:** 1. Configure a POS with German Fiskaly (l10n_de_pos_cert), Restaurant, and Kitchen Display (pos_preparation_display). 2. Create a new order in the POS and add the first product. 3. Observe that the order does not appear on the Kitchen Display. 4. Add a second product to the same order. 5. Observe that the order now appears on the Kitchen Display. **Issue:** The first product of a new restaurant order is not synchronised with the Kitchen Display when the German Fiskaly localisation is enabled. **Reason:** `syncAllOrders()` only processes orders returned by `getPendingOrder()` and ignores orders explicitly passed through `options.orders`. After the initial Fiskaly synchronisation, the order is serialised and removed from the pending queue. Consequently, the Preparation Display synchronisation receives no orders from `getPendingOrder()`, preventing the order from reaching the backend. **Solution:** Update `syncAllOrders()` to prioritize the orders explicitly provided through `options.orders`. When `options.orders` is not available, fall back to the existing behavior by synchronizing the orders from `orderToCreate` and `orderToUpdate`. opw-6321376 Forward-Port-Of: odoo/enterprise#125743
The Belgian payroll rules for CP302 eco-vouchers have been corrected so employees receive prorated voucher amounts based on the proper treatment of full-time, part-time, partial-year work, public holidays, and unpaid absences. This helps payroll teams apply sector rules more accurately and reduces the risk of incorrect employee benefits.
Original PR description
Per the CP302 rules:
- Full-time, incomplete year: 250 × complete_months/12 + 250 × working_days/divisor for any partial month at start/end.
- Part-time: 250 × working_days/divisor. Days are counted as-is ("each daily service = 1 day regardless of duration"), so work_time_rate is not applied to the day count.
- Divisor: 260 (5-day week) or 312 (6-day week).
- Working days use `get_work_duration_data(compute_leaves=False)` so public holidays stay assimilated; only unpaid absences are deducted.
task-6375105
Forward-Port-Of: odoo/enterprise#126198
Forward-Port-Of: odoo/enterprise#124297Customers can no longer complete checkout for planning-based rental services when the required resources are already booked. This avoids taking payment for rentals that cannot be fulfilled and prompts customers to choose another date or quantity.
Original PR description
**Problem:** On a website with rental planning enabled, a customer can book a planning-backed rental product through eCommerce even when no planning resource is free for the requested window. The…
**Problem:** On a website with rental planning enabled, a customer can book a planning-backed rental product through eCommerce even when no planning resource is free for the requested window. The cart lets them increase the quantity past the available capacity and proceed all the way through checkout without any availability gate. **Steps to reproduce:** 1. Install `website_sale_renting_planning`. 2. Create a planning role with `sync_shift_rental` and one resource. 3. Create a service product with `rent_ok=True`, `planning_enabled=True` and the role above. 4. Pre-book the resource for some window via a `planning.slot`. 5. From eCommerce, add the product to the cart for the same window. 6. Proceed to checkout/payment. **Current behavior:** The cart is considered ready, no warning is shown, and payment can proceed even though no planning resource is free for the chosen period. **Expected behavior:** The cart should be flagged as not ready and pre-payment validation should refuse to confirm until the customer picks a different date or quantity. **Cause of the issue:** `sale.order._available_dates_for_renting` in `website_sale_renting` is the documented hook for "stock availability" gating of the cart and pre-payment flow (called from `_is_cart_ready` and from `_check_cart_is_ready_to_be_paid`). `website_sale_stock_renting` overrides it to apply a per-line stock check, but `website_sale_renting_planning` has no such override, so planning-backed rental services reach payment with no availability gate at all. **Fix:** Apply the same gating pattern that `website_sale_stock_renting` already uses: override `_available_dates_for_renting` in `website_sale_renting_planning` so that, for each rental line whose product is a planning-synced rentable service, the cart is only considered valid when at least the requested quantity of planning resources is free during the rental window (mirroring the resource and leave filtering already done by `_planning_slot_vals_list_per_sol` at SO confirmation time). This puts the gate at the same point the stock-renting flow enforces it, keeping the public cart/checkout flow consistent across rentable product types. opw-6247034 Forward-Port-Of: odoo/enterprise#125855 Forward-Port-Of: odoo/enterprise#118943
This fixes how Indian reports classify transaction types for journal entries, especially Point of Sale entries that use general journals. Existing databases are also updated so past entries use the corrected classification logic.
Original PR description
Description: In #118297 non-sales journal moves were considered purchase moves during l10n_in_transaction_type computation, which is not correct for POS moves as their journal is of type 'general'. Fix: Compare only the purchase journal moves state against the partner state. Other moves treated as sales and their state compared against the company state. Add a migration script to update existing databases. opw-638646 Forward-Port-Of: odoo/enterprise#125697
10 changes
Enhancements to existing features
Large SEPA direct debit batches now validate faster by reducing repeated data processing and lookups. This helps businesses process hundreds or thousands of payments more reliably, with shorter waiting times and fewer timeout risks.
Original PR description
- Replace the `id:recordset` aggregation in `_get_expiry_date_per_mandate()` with `date:max` to compute the latest payment date directly in SQL. - Render `email_from` for all payments in batch and cache the computed authors by sender email to avoid repeated partner lookups during SDD pre-notification. This reduces ORM/cache overhead when validating large SEPA batches containing thousands of payments. Measured on a production-sized database: | metric | before | after | factor | |--------|-------:|------:|-------:| | `_get_expiry_date_per_mandate` (500 payments) | 564 ms | 111 ms | ~5x | | `_send_after_validation` notification (500 payments) | 92.9 s | 55.7 s | ~1.7x | | `_get_expiry_date_per_mandate` (1000 payments) | 890 ms | 178 ms | ~5x | | `_send_after_validation` notification (1000 payments) | timed out (>159 s) | 108.9 s | completed | OPW-6377340 Forward-Port-Of: odoo/enterprise#126429 Forward-Port-Of: odoo/enterprise#125439
Resolved issues and error corrections
Fixes an issue where rental returns could fail after items were picked up or returned through stock transfers instead of the rental wizard. The system now keeps the serial number history needed to offer the correct items for return, reducing blocked rental workflows.
Original PR description
**Issue** When rental transfers are enabled and rental pickups/returns are processed through stock pickings, it may become impossible to perform a subsequent rental return through the rental return…
**Issue** When rental transfers are enabled and rental pickups/returns are processed through stock pickings, it may become impossible to perform a subsequent rental return through the rental return wizard. **Steps to reproduce** - Activate "Rental Transfers" in the settings - Create a rental product P, tracked by serial number - Create two serial numbers for P - Create and confirm a rental order for 2 units of P - Validate the pickup transfer - Partially validate the return transfer without creating a backorder - Open the rental order and click on "Return" -> The return wizard opens without any available serial number and validation fails with a serial number-related error. **Cause** When clicking on "Return", if there is no pending pickup/return transfer: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/models/sale_order.py#L62-L68 the rental return wizard is opened directly: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_renting/models/sale_order.py#L316 No serial number is prefilled in the wizard because `returned_lot_ids` is empty: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L122-L124 This is because `returnable_lot_ids` is empty as well. `returnable_lot_ids` is computed while generating the wizard lines: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_renting/wizard/rental_processing.py#L38 https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_renting/wizard/rental_processing.py#L47-L48 https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L99-L106 and `returnable_lots` is empty because both `pickedup_lots` and `returned_lots` are. Those fields are currently only populated through the rental wizard flow: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L42-L43 https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L160-L161 https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L166-L167 Since this flow uses stock pickings instead of the rental wizard, those fields are never updated, preventing the wizard from determining any returnable serial number. opw-6150305
Cancelled Mexican CFDI invoices can now be reprinted with their required fiscal information, including QR codes, digital stamps, and fiscal folio details. This ensures businesses retain compliant proof that an invoice was issued and later cancelled.
Original PR description
### Issue before this commit: When an invoice's CFDI cancellation request is confirmed (state moves from sent to cancel), reprinting the invoice PDF no longer displays the fiscal information (QR…
### Issue before this commit: When an invoice's CFDI cancellation request is confirmed (state moves from sent to cancel), reprinting the invoice PDF no longer displays the fiscal information (QR code, digital stamps, fiscal folio/UUID, etc.), even though the signed CFDI attachment is still present on the invoice. ### Steps to reproduce the issue: 1. Download Accounting and l10n_mx 2. Create an invoice and send it to CFDI 3. Select 'Request for cancel' 4. Wait and click retry button in the CFDI tab until the invoice is marked as cancelled 5. Print the invoice again 6. See PDF does not show fiscal information (QR, fiscal folio, etc.) ### Cause of the issue: https://github.com/odoo/enterprise/blob/f6c94d4ca3ef4211a5ab00bf0b39f6a7675c8f79/l10n_mx_edi/models/account_move.py#L904-L909 Once the CFDI is cancelled, the computed field switches to 'cancel', so the condition fails and the method falls back to the generic account.report_invoice_document template, which has no knowledge of CFDI fiscal fields. ### Reason to introduce the fix: A cancelled CFDI invoice is still a legally relevant fiscal document in Mexico and must be reprintable with its fiscal data intact (to prove it was issued and later cancelled). The fix extends the condition to also cover the 'cancel' state, ensuring the CFDI-specific report template is used whenever a valid attachment exists, regardless of whether the CFDI is currently signed or cancelled. opw-6393656
The pivot field popup now hides date and datetime fields once all available time options have already been added. This prevents duplicate entries and avoids confusing drag-and-drop behavior for spreadsheet pivot users.
Original PR description
Current behavior before PR: - Date and datetime fields remained visible even when all their granularities were already added to the pivot. - Users could add the same field with the same granularity multiple times, creating duplicate IDs and causing unexpected drag and drop behavior. Desired behavior after PR is merged: - Hide date and datetime fields from the popup once all available granularities have already been added to the pivot. - This prevents duplicate field IDs and keeps the popup behavior consistent with spreadsheet pivots during drag-and-drop. Task: [6295794](https://www.odoo.com/odoo/project/2328/tasks/6295794)
User-facing messages and warnings now show translated selection field labels instead of untranslated internal text. This improves clarity for users working in languages other than English across accounting, payroll, recruitment, appointments, IoT, and localization features.
Original PR description
The `selection` attribute of `fields.Selection` is not generally translated (unless it is a function instead of a list). For user facing strings, we generally need to translate the value displayed.
Quotations created from helpdesk repair orders now correctly use the salesperson assigned to the customer. This prevents missing sales ownership on follow-up quotes, helping teams keep accountability and reporting accurate.
Original PR description
Currently, when a quotation is created from a repair order generated from a helpdesk ticket, the salesperson is not set on the quotation even if the customer has a salesperson assigned. **Steps to…
Currently, when a quotation is created from a repair order generated from a helpdesk ticket, the salesperson is not set on the quotation even if the customer has a salesperson assigned. **Steps to Reproduce:** - Install `helpdesk_repair`. - Go to `Helpdesk` > `Configuration` > `Helpdesk Teams`. - Open a team recod and enable `Repairs`. - Create a `contact/customer` with a `salesperson` assigned. - Go to `Helpdesk`, create a ticket for that `customer`, and select the `helpdesk team` configured above. - Click `Repair`, then click `Create Quotation`. - Open the quotation and check the `Salesperson` field in the `Other Info` tab. **Current behavior:** The Salesperson field on the quotation remains empty. **Expected behavior:** The Salesperson field on the quotation should inherit the salesperson assigned to the selected customer/contact. **Cause of the issue:** When a repair order is created from a helpdesk ticket, default_user_id [1] is passed in the context . This value is propagated when creating the repair order [2] . Later, when creating the quotation from the repair order [3], the same context is reused. Because default_user_id is already present in the context, it overrides the precomputation of user_id from the customer. As a result, user_id is initialized with an empty value and remains unset. **Fix:** This commit ensures that default_user_id is removed from the context before creating the sale order. Without a default value for user_id, the field is correctly precomputed from the selected customer, and the salesperson is properly assigned. [1]- https://github.com/odoo/enterprise/blob/2662932c7ac8ebf3ed5a05d44d7ebfaff869fcbd/helpdesk_repair/models/helpdesk_ticket.py#L52 [2]- https://github.com/odoo/enterprise/blob/2662932c7ac8ebf3ed5a05d44d7ebfaff869fcbd/helpdesk_repair/models/helpdesk_ticket.py#L36-L40 [3]: https://github.com/odoo/odoo/blob/29328b8fccff833c14de317b51f3b4e5a8c40f75/addons/repair/models/repair.py#L357 opw-6344939 Forward-Port-Of: odoo/enterprise#126310 Forward-Port-Of: odoo/enterprise#122980
Fixed an issue in the Barcode app where two delivery lines could appear selected at the same time when an operation mixed packaged and unpackaged products. This helps warehouse users avoid confusion and process deliveries more reliably when moving entire packages.
Original PR description
**Steps to reproduce:** - Enable "Move Entire Packages" setting on deliveries - Make a product A, that has a package P1, on hand qty of 1 - Make product B that don't have a package, but on hand qty…
**Steps to reproduce:** - Enable "Move Entire Packages" setting on deliveries - Make a product A, that has a package P1, on hand qty of 1 - Make product B that don't have a package, but on hand qty of 1 - Make a delivery that has both of those products, requested qty of 1 for both - Mark it as todo - Go to the barcode app, select the delivery - Select the line with product B - Select the line with product A --> The line with product B is not unselected **Why the fix:** When we have a mix of packaged products and products without a package on the same operation, they are handled separately. The products without a package are handled in https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L388-L392 that calls https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L1277-L1284 But as you can see, there are no mention of the selected package line, which is stored in **this.lastScanned.packageId**. As we do not touch this variable, the selected package line stays selected. The same is true for the other way around, when we select a package line we call https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L394-L398 This function does not care for the **selectedLineVirtualId** which represents the selected line without a package. To avoid this and make it so that only one line is selected even if they have different package, we now set the corresponding value to false to unselect the other line in all situation. This is basically how it's done in https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L1202-L1208 to unselect every line regardless of packages. opw-6266203 Forward-Port-Of: odoo/enterprise#125356 Forward-Port-Of: odoo/enterprise#122038
Opening bank reconciliation directly from a saved URL now behaves the same as opening it from the Accounting dashboard. Automatic matching runs as expected, and upload options stay hidden for journals connected to online bank synchronization.
Original PR description
### Issue: When accessing the Bank Reconciliation view directly via URL or bookmark, auto-matching with reconciliation models may not trigger and the upload button may be visible on synchronized…
### Issue: When accessing the Bank Reconciliation view directly via URL or bookmark, auto-matching with reconciliation models may not trigger and the upload button may be visible on synchronized journals ### Cause: `_action_open_bank_reconciliation_widget` injects two context keys: - `auto_statement_processing`: triggers auto-reconciliation on statement creation - `bank_statements_source`: hides the upload button for synchronized journals When the view is accessed directly, these keys are not present, causing the UI to ignore them `auto_statement_processing` is now set directly in the user context via `onWillRender`/`onWillDestroy` in `BankRecKanbanController` `bank_statements_source` requires an ORM call to fetch the journal's value and is resolved via `fetchBankStatementsSourceInto` on startup Notes: The fix for `bank_statements_source` was added opportunistically while addressing `auto_statement_processing` Steps to reproduce: - Install `accountant` with demo data - Duplicate the Bank Journal and set Bank Feeds to Online Synchronization - Open the Accounting Dashboard and open the Bank (copy) - Create a transaction (Label: Test, any amount) and click Add & Close - In the 3 dots menu, choose Manage Models - Create a Reconciliation Model (Label contains: Test, Lines: any account, default values) - Click Automate - Go back to the Bank Reconciliation page and verify: -- The transaction is reconciled automatically -- No Upload button is displayed - Create a new transaction, it should be reconciled automatically - Copy the URL and open it in a new tab - Create a new transaction Before the fix, the transaction is not reconciled and the Upload button is present opw-6391107
Employee unavailable time is now calculated consistently across Attendance and Time Off planning views. Days outside an employee contract, including employees without contracts, are clearly shown as unavailable, while flexible schedules are handled more accurately.
Original PR description
…ty of employees purpose: 1- We should have a consistent way to compute `_gantt_unavailability` of employees in time off and attendance. Currently, some cases have inconsistent behavior such as out…
…ty of employees
purpose:
1- We should have a consistent way to compute `_gantt_unavailability` of employees in time off and attendance. Currently, some cases have inconsistent behavior such as out of contract days, flexible and fully flexibe employees. 2- In time off calendar view, if the employee does not have a contract at all, the current working schedule will appear in the calendar and it will not be greyed out. This is inconsistent with the behavior of the attendance application.
Fix:
1:
- implemented `_get_employee_unavailable_intervals` in employee model to be used in both time off and attendance.
- more optimized than the old implementation in time off as it calls `_work_intervals_batch` once per calendar instead of calling it for each contract in `_unavailable_intervals_batch`
- greys out "out of contract" periods
- for flexible and fully flexible employees, the whole period is considered available except leave periods
- made `_get_calendar_periods` use version date start instead of contract date start and corrected a bug in tz conversion 2:
- made `_get_unusual_days` return True for all the days outside of contracts for the employee instead of not returning anything for them or getting values from the working schedule of the employee (means that they will be greyed out in the callendar view) and added a test for it
task-id: 5473055Customer balances in Point of Sale now show the correct Total Due when the company currency differs from the PoS currency. This prevents Pay Later amounts from being converted twice, so staff see the expected customer debt amount.
Original PR description
Steps to reproduce: - set the company currency to XCG - set the PoS sales journal currency and the PoS pricelist currency to USD - configure a XCG <-> USD rate - create a customer without any…
Steps to reproduce: - set the company currency to XCG - set the PoS sales journal currency and the PoS pricelist currency to USD - configure a XCG <-> USD rate - create a customer without any outstanding balance - open the PoS, create an order of USD 100 and validate it with the Customer Account (Pay Later) payment method - open the Customers screen and look at the Total Due of that customer Issue: The Total Due shows about USD 55.56, i.e. the amount converted once too many, instead of the expected USD 100. Cause: get_total_due() sums two amounts that are not expressed in the same currency before converting them. partner.total_due comes from the accounting entries, it is the sum of account.move.line.amount_residual and is therefore in company currency, while total_settled is the sum of pos.payment.amount of the still open sessions, which is in the currency of the order, so the PoS one. The addition is done first and the result is then converted from the company currency to the PoS one, so the pay later payments end up converted a second time. opw-6403320 Forward-Port-Of: odoo/enterprise#126290 Forward-Port-Of: odoo/enterprise#125798
6 changes
Enhancements to existing features
Odoo now checks whether a single or batch payment exceeds the maximum amount allowed by the connected financial institution before attempting to submit it. This helps avoid failed payment attempts and gives businesses clearer control when banks impose transaction limits.
Original PR description
Before trying to initiate payments through Odoo/Odoofin, we should check that the total amount for the (batch) payment does not exceed the maximum payment amount allowed by the institution (some Powens institutions introduced that limit). task-6310729
Bank synchronization now recognizes a new type of recoverable error from Odoo's financial connection service. This helps avoid marking connections as failed when the issue should not block ongoing use, reducing unnecessary disruption for users.
Original PR description
Odoofin now sends a 'non_blocking_error' error response to indicate that the state on account.online.link shouldn't be set to error. In this commit, we start using it. Task ID: 6358809
Resolved issues and error corrections
Restaurant orders now correctly refresh on the kitchen preparation display when items are split from an order and moved to another table. This helps kitchen staff see the latest table and item changes without missing transferred orders.
Original PR description
Step to reproduce: - install pos_restaurant with demo - open restaurant, for a table 1 order 3 items - in second tab, open kitchen display, there should be 1 order for table 1 - in pos, for same order split 1 item and transfer it to table 2 Observation: - splitting and transferring order does not update kitchen display Cause: - we found, doing above actions, never triggered the kitchen display for update Fix: - we know send a flag, if we have to notify the change to preparation display opw-6390979
Planning entries for fully flexible employees are now included in the Timesheet and Planning Analysis report. This fixes missing report data for employees without a set working schedule, giving managers a more complete view of planned work.
Original PR description
Steps to reproduce: ------------------- 1. Install project_timesheet_forecast. 2. Create a fully flexible employee (without a working schedule). 3. Create a planning slot. 4. Open the Timesheet/planning Analysis report. Issue: ------ Planning slots for fully flexible employees are not included in the report. Cause: ------ https://github.com/odoo/enterprise/blob/7d4b43cfa1934856d41992cbe8242eaf62575c2c/project_timesheet_forecast/report/timesheet_forecast_report.py#L142-L161 The report assumes every resource has a working schedule and only considers resources with a resource calendar. As a result, resources without a calendar are excluded from the report. Solution: --------- Handle resources without a working schedule separately so that planning slots for fully flexible employees are also included in the report. opw-6361571
This update prevents report lines from being expanded multiple times when users click quickly or have a slow connection. It keeps financial reports responsive and ensures lines can be folded back correctly without showing duplicate entries.
Original PR description
Steps to reproduce:- - Open any report. - Click on a particular line to unfold more than once very fast(or throttle network to 3G) - Once line is unfolded click again to fold that line. - Line is not folding. Cause:- - When we clicked multiple times to unfold line, duplicate child lines were created(as many times as many times we clicked). - Because when first promise was not resolved so `unfolded = false` and we clicked again so new promise also tries to unfold the same line, resulting in unfolding the same line multiple times. - In version 17.0 these duplicate child lines are created but somehow not visible but it breaks `foldLine`. From version 18.0 onwards these duplicate child lines are visible. Solution: In `unfoldLine` set the flag `unfolding`. So in all clicks other than first, we get `unfolding = true` and don't proceed further, preventing unfolding the same line multiple times. task-6260425 Forward-Port-Of: odoo/enterprise#120392
Fixed an error that could occur when users changed the No Follow-Up setting on invoices with multiple payment installments. This keeps follow-up reporting usable even when some installments have already been paid and reconciled.
Original PR description
Steps to Reproduce: 1. Configure Payment Term (Accounting > Configuration > Payment Terms) containing multiple installments. 2. Create a Customer Invoice with this Payment Term. 3. Post the invoice.…
Steps to Reproduce:
1. Configure Payment Term (Accounting > Configuration > Payment Terms) containing multiple installments.
2. Create a Customer Invoice with this Payment Term.
3. Post the invoice.
4. Register a payment and fully reconcile one of the installments.
5. Navigate to the customer's Follow-Up Report (Accounting > Reporting > Partner Ledger > Report: Follow-Up Report).
6. Navigate to remaining open installment/account move line for that invoice.
7. Turn On or Off the No Follow-Up toggle for the invoice.
An error occurs when enabling or disabling the No Follow-Up toggle.
Issue:
Enabling or disabling the No Follow-Up toggle on a remaining open installment in the Follow-Up Report raises a server error when the invoice contains multiple installments and one or more installments are already fully reconciled.
Root Cause:
The Follow-Up Report only loads and sends non-fully reconciled account move lines from the JavaScript side through all_line_ids. In action_toggle_no_followup(), when the selected line belongs to an invoice, the code retrieves all receivable/payable lines of the invoice, including fully reconciled installments:
```
move.line_ids.filtered(
lambda line: line.account_type in ('asset_receivable', 'liability_payable'),
)
```
The method then attempts to map every receivable/payable line to a report line ID using aml_id_to_line_id. Since fully reconciled installments are not present in all_line_ids, they are missing from the mapping dictionary, causing a KeyError when accessing:
`aml_id_to_line_id[line.id]
`
Fix:
Restricted the impacted lines to those present in the report by adding a check that the account move line exists in aml_id_to_line_id before performing the mapping:
```
lambda line: line.account_type in ('asset_receivable', 'liability_payable')
and line.id in aml_id_to_line_id
```
opw-62454482 changes
Enhancements to existing features
The Amazon sales integration now uses Amazon's newer Orders API ahead of the old version being retired in 2027. This keeps order syncing reliable and improves performance by retrieving order and item details together instead of through repeated follow-up requests.
Original PR description
Amazon has announced the deprecation of the Orders v0 API, with a removal date of March 27, 2027. In this commit, we migrate to the new v2026-01-01 API. This new version restructures how order data is queried and delivered, shifting from a multi-request architecture to a nested consolidated payload. This optimizes our sync performance by eliminating the N+1 query problem when fetching order items. Key changes: - Operation Consolidation: `getOrders` is replaced by `searchOrders`. Because Amazon now embeds orderItems directly inside each order object natively, we remove our secondary item-fetching loops. - Financial aggregation: Item prices, taxes, shipping, and discounts are no longer flat fields on the item but are centralized into a `proceeds` object. - Replacing of deprecated flags. - Reorganization of order-related fields. task-5972714
Resolved issues and error corrections
This fixes an issue in Documents where clicking inside a "Search More" dialog could unexpectedly close the dialog while editing document details. Users can now select related records such as owners or customers without losing their current document selection.
Original PR description
Steps to reproduce: 1. Install Documents 2. In the Documents list view, select a document to display the inspector. 3. Edit a field such as Owner or Customer which uses a Many2one widget. 4. In the…
Steps to reproduce: 1. Install Documents 2. In the Documents list view, select a document to display the inspector. 3. Edit a field such as Owner or Customer which uses a Many2one widget. 4. In the field dropdown, click "Search More..." to open a modal dialog. 5. Click inside the "Search More..." modal (e.g., to sort columns or resize headers). Issue: - The modal dialog immediately closes, and the contact cannot be selected. Root cause: - When an inspector field is edited, the record row is put into edit mode. While in edit mode, the documents list renderer listens for global clicks. Clicking inside the "Search More..." modal dialog targets elements that have `.o_list_renderer` (since the modal dialog renders a list view). Because the click target is within a list renderer but is not a document row, `DocumentsListRenderer.onGlobalClick` executes and clears the selection of the main list view. Clearing the selection unmounts the edited field in the inspector, thereby destroying the modal dialog stack. Solution: - Modify DocumentsListRenderer.onGlobalClick to scope click handling to the current Documents list renderer. Ignore clicks outside this.root.el, so interactions in nested UI such as Search More... do not clear the main selection and destroy the inspector field. opw-6253360