Daily updates from Odoo
Friday, August 1, 2025
18 changes · saas-18.3
Enhancements to existing features
Restaurant self-ordering users can now access a "Get QR Codes" button directly from the floor plan view. The button opens a prefilled Odoo.com form, making it easier to order engraved QR codes for tables and speed up self-order setup.
Original PR description
Add a `Get QR Codes` button on the floor plan view TaskID: 4814164 Forward-Port-Of: odoo/odoo#221489 Forward-Port-Of: odoo/odoo#218164
Kiosk and self-order screens now automatically refresh when product availability changes, so customers see current stock status without a manual reload. This prevents unavailable items from being selected or paid for, reducing failed orders and improving the customer experience.
Original PR description
Before this commit: --------------------------- - Product availability changes were not reflected in the kiosk or self-order screens. - Users could select and proceed to payment for products that were already out of stock. - No automatic UI update; a manual page reload was required to reflect stock changes. After this commit: ------------------------------------ - Product availability changes now automatically refresh the kiosk and self-order interfaces. - Unavailable products are blocked from being selected or paid for. - The UI reflects real-time stock status, ensuring a consistent and reliable experience. Task-4830424
The point-of-sale settlement flow no longer loads all accounting move records upfront when they are not immediately needed. This reduces memory use and speeds up loading, especially for businesses with large accounting histories.
Original PR description
Before this commit, all account.move records were loaded into the PoS interface, even though they were not used immediately. This caused significant performance issues, increasing memory usage and loading times. opw-4986727
Resolved issues and error corrections
Corrects how future time off balances are calculated when unused days can carry over for a limited period. Employees and HR teams will now see the correct available leave after carryover days expire, avoiding misleading zero or partial balances in future balance checks.
Original PR description
### Steps to reproduce: - Create an accrual plan with the following rule: — The employee has 20 days off in the first year. Total 20. — The employee has 21 days off in the second year and an…
### Steps to reproduce: - Create an accrual plan with the following rule: — The employee has 20 days off in the first year. Total 20. — The employee has 21 days off in the second year and an additional 5 days off if available from the previous year, which can be taken until 6 months. Total 21 + 5 = 26 — The employee has 22 days off in the third year and an additional 5 days off if available from the previous year, which can be taken until 6 months. Total 22 + 5 = 27 — The employee has 23 days off in the fourth year and an additional 5 days off if available from the previous year, which can be taken until 6 months. Total 23 + 5 = 28 - Create an accrual allocation with the created plan - Check future allocation data using 'Balance at the' - Notice the following behaviour: — until 31/12/2025 it CORRECTLY shows 20 days available. — from 01/01/2026 to 30/06/2026 it CORRECTLY shows 26 days (21 days for renewal and 5 days not used in 2025) — from 01/07/2026 it INCORRECTLY shows no days available. — from 01/01/2027 to 30/06/2027 it CORRECTLY shows 27 days (22 days for renewal and 5 days not used in 2026) — from 01/07/2027 it INCORRECTLY shows 5 days. — from 01/01/2028 to 30/06/2028 it CORRECTLY shows 28 days (23 days for renewal and 5 days not used in 2027) — from 01/07/2028 it INCORRECTLY shows no days available. — from 01/01/2029 it CORRECTLY shows 28 days again. — In the following years, after 6 months, one year shows 5 days and the next shows nothing. ### Cause: The first cause here is that when we have validity for the carryover then we will have two calls in each year one at the start of the year and another at the expiration date of the carryover. So, when we add the days to the allocation we don't consider the second call in the condition and we only check if the allocation.actual_lastcall is equal to one of the start dates for each year https://github.com/odoo/odoo/blob/3fb37cbc59adc2caace8efcdae418d2466a9b750/addons/hr_holidays/models/hr_leave_allocation.py#L588 The second cause where each two years one of them shows the number of carryover days from the previous year, this is happening because when we remove the expiring days for the first year we set the number of days to 0 https://github.com/odoo/odoo/blob/3fb37cbc59adc2caace8efcdae418d2466a9b750/addons/hr_holidays/models/hr_leave_allocation.py#L516-L517 And it will be 0 until we loop again and add the days to allocation https://github.com/odoo/odoo/blob/3fb37cbc59adc2caace8efcdae418d2466a9b750/addons/hr_holidays/models/hr_leave_allocation.py#L521-L522 and since this is happening after we already set the expiring days which in this year will be 0 we won't remove those expiring days from the year's allocation data ### Fix: We add a condition to check if the actual_lastcall is either a date in the start of the allocation or one of the expiration dates for the carryover. Also, before we set the value of the expiring_carryover_days we call _add_days_to_allocation to calculate on the correct number of days for the plan level we are checking. opw-4606886 Forward-Port-Of: odoo/odoo#221248 Forward-Port-Of: odoo/odoo#209669
Invoice line rounding differences are now spread evenly across lines instead of being applied to one large line. This helps electronic invoices meet PEPPOL/BIS3 validation rules and reduces the risk of rejected invoices due to rounding discrepancies.
Original PR description
Before this commit, the behaviour of `_round_base_lines_tax_details` was to assign all the base line delta to the largest base line. However, when generating the UBL, the delta would then get included in the LineExtensionAmount, but BIS3 rule PEPPOL-EN16931-R120 enforces that the LineExtensionAmount must be at most 2 cents away from `(quantity * net price) + sum(charges) - sum(allowances)`. Effectively this means that we can put at most 2 cents base delta on each invoice line. After this commit, `_round_base_lines_tax_details` redistributes the base delta evenly over all the base lines. task-none Forward-Port-Of: odoo/odoo#220701 Forward-Port-Of: odoo/odoo#219244
Confirming a sales order for a service that creates a project now correctly assigns the customer's company when the project template has no company set. This prevents an unexpected error and lets businesses create project-based work from sales orders without manual data cleanup.
Original PR description
Currently, a user error occurs when confirming a Sales Order (SO). **Steps to reproduce:** 1) Install sale_project 2) Create a service product that generates a project and a task. 3) Add a project…
Currently, a user error occurs when confirming a Sales Order (SO). **Steps to reproduce:** 1) Install sale_project 2) Create a service product that generates a project and a task. 3) Add a project template by creating one from the product form view. 4) Create an SO by creating a customer with a company 5) Add the above-created service product and confirm the SO. **Error:** A user exception will be triggered ``` The project and the associated partner must be linked to the same company. ``` **Cause:** - When a project template is created from the product view, both the customer and the company_id default to empty. - Later, when confirming a SO with a customer that belongs to a company, the new project's company_id is taken from the project template, which is empty. https://github.com/odoo/odoo/blob/876e9d5e9ba87fa69188b2da098eec78f77040f5/addons/sale_project/models/sale_order.py#L140-L141 - However, the project’s partner_id (the customer) does have a company_id, (since the customer value for the project will be set through SO's customer). - This leads to a mismatch between the project’s company_id(which is empty) and its partner’s company_id. So a user exception will be triggered from the below lines https://github.com/odoo/odoo/blob/876e9d5e9ba87fa69188b2da098eec78f77040f5/addons/project/models/project_project.py#L257-L258 **Solution:** - If the project template has no company_id, and the customer of the project has one, set the project’s company_id to match that of the customer. opw-4900741,4880495 Forward-Port-Of: odoo/odoo#216582
This fixes a Spanish accounting setup issue where two domestic fiscal positions existed after an upgrade. The duplicate Mainland Spain entry is merged into ES Domestic, reducing confusion and helping ensure taxes are applied consistently.
Original PR description
Before this commit: - In version 18.3, due to changes and migrations in fiscal positions, the domestic fiscal position for Spain was duplicated (ES Domestic and Mainland Spain). After this commit: - Merged the duplicated fiscal position 'Mainland Spain' into 'ES Domestic'. task-4972464
Opening an invoice could fail when related credit notes and statement lines existed for the same partner. The accounting calculation was adjusted so the outstanding credits and debits information is computed independently, preventing the error and keeping invoice payment information available.
Original PR description
To reproduce: - Install account_accountant (not reproducible on runbot with all modules installed) - Create an invoice for partner_a - Create a credit note for same partner - Create a statement line for same partner - Open the invoice => Traceback The issue is that invoice_outstanding_credits_debits_widget is first put to False, then protected. So the real value is not put, while invoice_has_outstanding is changed. So in the override of the compute, it does not contain 'content' (=False), and so fails. The issue is not easy to solve. Problem of cache protection etc,... The situation does not seem problematic per se. We separate the 2 fields in 2 compute, so invoice_outstanding_credits_debits_widget is not protected by the computation of invoice_has_outstanding --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Timesheet administrators who do not have Project app access can now open timesheet lists and related forms without being blocked by access errors. This keeps timesheet review workflows working while preserving normal project record permissions.
Original PR description
Steps to Reproduce: - Ensure the `sale_timesheet` module is installed. - Log in as a user with Timesheet Administrator permissions but without access to the Project module. - Attempt to open the…
Steps to Reproduce: - Ensure the `sale_timesheet` module is installed. - Log in as a user with Timesheet Administrator permissions but without access to the Project module. - Attempt to open the Timesheets list view results in an `AccessError` due to missing read rights on `project.task`. - Create a task in a private project linked to a timesheet and open its form view results in an `AccessError` due to missing read rights on `project.project`. Cause: - When a user has Timesheet Administrator access but lacks project access, they can view all timesheets, including those linked to tasks with private privacy visibility. However, these users do not have read access to the private tasks themselves. - The `_compute_commercial_partner` method reads `task_id.partner_id.commercial_partner_id` and `project_id.partner_id.commercial_partner_id`. When a user without read access to `project.task` or `project.project` tries to compute this field, an `AccessError` occurs because the code tries to access these related records without bypassing access rights. Solution: - Use `sudo()` on `task_id` and `project_id` when accessing their `partner_id` fields inside the compute method to bypass access rights checks, preventing ` AccessError` for users lacking read permissions. task-4798066 Forward-Port-Of: odoo/odoo#221247 Forward-Port-Of: odoo/odoo#210826
Point of Sale now correctly accepts multiple existing serial numbers on the same order line when creating new serial numbers is disabled. This prevents valid sales from being blocked when cashiers add several serialized units of the same product.
Original PR description
**Steps to reproduce:** - Install `point_of_sale`. - Go to POS -> configuration -> settings - Search 'Operation type' -> open picking type -> Disable `Create new` - Create a storable product 'test'…
**Steps to reproduce:** - Install `point_of_sale`. - Go to POS -> configuration -> settings - Search 'Operation type' -> open picking type -> Disable `Create new` - Create a storable product 'test' with serial tracking. - Add on-hand quantity with serial numbers. - In POS, select the product and choose one SN, - Select it again and choose another SN. **Observation:** - The order line should have 2 quantities with a list of Serial numbers chosen by the user. For one quantity, it's working fine, but for multiple quantities, an issue occurs. **Issue:** - While confirming edit serial numbers popup for multiple quantities, it checks whether each selected SN is valid or not. - The condition is that the entered SN is in the existing available SNs option. But the already chosen SN is not in the existing SN option, - Also, creating a new SN is disabled, so it's considered an invalid input. https://github.com/odoo/odoo/blob/876b7337eb689e0682ab48e9e833f9f0dc6bb8d2/addons/point_of_sale/static/src/app/store/select_lot_popup/select_lot_popup.js#L190-L193 **Solution:** - Added a condition to allow SNs that are already selected (matched by name and ID) to be considered valid inputs. opw-4865902 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#220932 Forward-Port-Of: odoo/odoo#219205
This fix helps Point of Sale recover correctly after a temporary internet outage. When the connection comes back, the system now waits briefly before checking connectivity and then triggers order synchronization, reducing the risk of sales data staying unsent.
Original PR description
Steps to reproduce: - open a pos on a runbot from saas-18.2 - turn off the wifi on your device until you see the disconnected sign - turn back on the wifi - the pos stays in "offline" mode Issue: The ping rpc call is made before the connection is really reestablished. The rpc call fails and the network.offline attribute stays true. This prevent the data from being sent to the backend. Fix: Set a timeout to perform the ping rpc call and sent an envent to notify the pos_store to syncAllOrders when back online. Task-id: 4978122 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#220954
This change restores correct backorder handling when a delivery includes both regular and subcontracted products. It avoids blocking barcode users in a situation where they had no practical workaround, while keeping test coverage for the barcode flow.
Original PR description
This commit reverts db8b33e (and the wrong follow-up fix of 2755c09) because it breaks backorders for pickings that mix regular and subcontrcted products. We'd rather the flow has problems in back end where the user can manually uncheck the picked box rather than in barcode where there is no work around. We keep the enterprise test introduced in [792c968](https://github.com/odoo/enterprise/commit/792c968) to protect the barcode flow. Forward-Port-Of: odoo/odoo#220318
This fix prevents PDF print jobs on Android devices from being stopped too early while the print preview is still loading. It improves reliability for users printing documents from mobile browsers, reducing failed or incomplete print attempts.
Original PR description
Currently, pdf.js does not support printing from mobile browsers, and the pdf.js team will not fix this issue [1]. I investigated and found that sometimes `window.print()` is asynchronous [2]. On Android, the print preview dialog re-renders the entire PDF within the preview, which can obviously take some time and the abort method is call before the preview rendering is complete. opw-4190135 [1]: https://github.com/mozilla/pdf.js/issues/12020 [2]: https://github.com/mozilla/pdf.js/blob/2d0ba7db08fb6bb597ba718635314d8e8998a7d0/web/pdf_print_service.js#L226 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#221172 Forward-Port-Of: odoo/odoo#217526
Users can now change dates for recurring shifts in Sale Planning without hitting a missing record error. The fix ensures Sale Planning only updates shifts that still exist after Planning processes the recurrence change, preventing disruptions when editing all shifts.
Original PR description
Version: 17.0 Steps to reproduce: - Install sale_planning - Create a recurrence shift. - Change the date of second shift which is created by recurrence. - Give the edit value as All shifts. - save record, missing error occured. Issue: When a user changes the date of a shift created by recurrence, the system crash with the message, "Record does not exist or has been deleted." Cause: There was an issue between "Planning" and "Sale Planning". When a user moves a shift, "Planning" removes the old shift from the system except the first one, But 'sale planning' was still trying to work with that removed shift. Fix: Now, after 'Planning' does its work, 'Sale Planning' checks again to see that shifts are still there. It only works with shifts that actually exist. So crash no longer happens. Users can now safely change the date of recurring shifts without errors. task-4859892 Forward-Port-Of: odoo/enterprise#91236 Forward-Port-Of: odoo/enterprise#88234
Timesheet administrators who do not have Project access can now open the Timesheets list and kanban views without hitting an access error. This prevents a blocking issue for managers who need to review timesheets but should not have broader project permissions.
Original PR description
Steps to Reproduce: - Ensure the `timesheet_grid_holidays` module is installed. - Log in as a user with Timesheets Administrator access but no access to the Project module. - Navigate to the Timesheets > List or Kanban view. - An `AccessError` occurs due to missing read rights on the `project.task` model. Cause: - In the `timesheet_grid_holidays` module, the `_should_not_display_timer` method accesses `self.task_id.is_timeoff_task` without checking access rights, causing an `AccessError` when users who can view timesheets but lack read access to `project.task` try to access tasks linked to projects with private privacy visibility. Solution: - Use `sudo()` when accessing `self.task_id` in `_should_not_display_timer()` to avoid access errors. task-4798066 Forward-Port-Of: odoo/enterprise#91361 Forward-Port-Of: odoo/enterprise#86302
Manufacturing users who are not HR users can now open the Shop Floor app without an access rights error. Employee barcode lookup is handled only when needed, avoiding restricted HR data access while preserving barcode identification on the shop floor.
Original PR description
**PROBLEM** If a user is in the mrp.group_mrp_user group, but does not belong to hr.group_hr_user, he can't access the shop floor app. **STEP TO REPRODUCE** 1. connect with a user which is a user of manufactring, but not a user of hr. 2. try to go on the shop floor app and notice there is an access right error. **CAUSE** When connecting to the shop floor app, we are trying to get the barcode field on all employee (because we need them if we want to identify an employee on the shop floor app using their barcode). This was added in this commit: https://github.com/odoo/enterprise/commit/b3fb0073a15adcc799a5681284f0cfd2308764b8 The barcode field is only accessible to member of hr.group_hr_user. **FIX** Instead of getting the barcode of all employee using `get_all_employee()`, we do a rpc call to query the employee the barcode belong to. opw-4905206
This fixes how absence-related days are calculated in Swiss payroll reporting. It helps ensure payroll and statutory declarations use accurate day counts, reducing the risk of incorrect employee records or reporting adjustments.
Original PR description
Forward-Port-Of: odoo/enterprise#91391 Forward-Port-Of: odoo/enterprise#91358
Payslip PDFs now correctly follow the salary structure setting that hides the basic wage. This prevents confidential wage details from appearing when the option is enabled, matching the expected payroll configuration.
Original PR description
After this commit: odoo/enterprise@9dceed0896ce5089bccbc9cc2ce1e8c4b13f0048…
After this commit: odoo/enterprise@9dceed0896ce5089bccbc9cc2ce1e8c4b13f0048 [diff](https://github.com/odoo/enterprise/commit/9dceed0896ce5089bccbc9cc2ce1e8c4b13f0048#diff-de4a628e7837c273b67d71f93efab85b6a9ee957ea702f502066ebcc632a76cbL64) The condition that handles hiding the basic wage on the payslip was not added —possibly it was missed. That’s why the "Hide basic on PDF" feature doesn’t work, regardless of whether it’s enabled, as the necessary condition is missing in the template. Steps to reproduce (on runbot): - In a v18 runbot, open any payslip and go to the salary structure. Enable the "Hide basic on PDF" option. - Return to the payslip and print it. - You’ll see that the basic wage is still printed on the payslip. **Before Fix:** <img width="669" height="238" alt="payslipbefore" src="https://github.com/user-attachments/assets/2fce67a2-19d8-45d8-88fa-4fc6a1767e68" /> **After Fix:** <img width="683" height="289" alt="payslipafter" src="https://github.com/user-attachments/assets/adcb0104-9c4e-4a35-ba78-b3f278f6bfda" /> opw-4953831 Forward-Port-Of: odoo/enterprise#90798