Daily updates from Odoo
Tuesday, July 7, 2026
305 changes
20 changes
Enhancements to existing features
The timesheet assistant now gives clearer guidance when setup issues prevent activity tracking, including distinguishing connection problems from CORS configuration issues and warning when the browser extension is missing or inactive. It also improves suggestion quality by showing real record names, preserving deleted Odoo events properly, and selecting more relevant projects for calendar-based timesheets.
Original PR description
Forward-Port-Of: odoo/enterprise#121939 Forward-Port-Of: odoo/enterprise#115859
This update adds automated checks to ensure emails can be properly traced when a new coupon is generated from a helpdesk ticket. It helps protect customer service workflows by reducing the risk of unnoticed regressions in coupon-related communication tracking.
Original PR description
Added tests for email traceability when generating a new coupon in a ticket --- task-6341030
Resolved issues and error corrections
Fixed an issue where the dialog for adding snippets to a mailing could appear behind the full-screen editor when the AI chatbox was active. This restores normal editing behavior and prevents save or discard actions from becoming blocked.
Original PR description
When an AI chatbox is active, all non-error dialog modals are set to be behind the chatbox through their z-index. This causes an issue where the dialog modal to add new snippets to a mailing is set behind the fullscreen edit window, preventing its use and freezing the use of some commands (save & discard). This commit restores the snippet dialog's z-index to its original value. task-6321624
EC Sales List returns are now generated separately for each company in a tax unit using that company's own VAT number. This prevents multiple entities from being incorrectly combined into one declaration under the tax unit VAT number, improving compliance accuracy.
Original PR description
Issue: The EC Sales List return is currently generated under the tax unit VAT number, consolidating all member entities into a single declaration. Expected: The EC Sales List return must be generated individually per member entity, each under their own VAT number, even when those entities belong to a tax Unit. Fix: Apply tax unit only if report's multi company filter is `tax_units`. Ref: https://github.com/odoo/enterprise/blob/07e8aba8604319747a5925c83576095ce9a63f9e/account_reports/models/account_return.py#L316-L317 task-6069402 Forward-Port-Of: odoo/enterprise#115974
The planning test flow now closes a side panel that could hide split shift items and cause unreliable results. This keeps the weekly planning checks stable, including when they run on Sundays, helping prevent false failures during quality checks.
Cancelled UrbanPiper delivery orders are now ignored when calculating active delivery counts. This prevents affected point-of-sale sessions from failing to reopen after a delivery provider cancels an order, helping staff continue service without interruption.
Original PR description
### Steps to reproduce 1. Configure UrbanPiper and start a POS session. 2. Receive an order from the delivery provider. 3. Accept the order and mark it as **Ready**. 4. Cancel the order from the…
### Steps to reproduce 1. Configure UrbanPiper and start a POS session. 2. Receive an order from the delivery provider. 3. Accept the order and mark it as **Ready**. 4. Cancel the order from the delivery provider. 5. Reopen the running POS session. ### Current behavior When a delivery provider cancels an order, the `delivery_status` is updated to `cancelled`, while the POS order state remains (`draft`, `paid`, or `done`). As a result: * Cancelled deliveries are still included in the active delivery order count. * `_get_urbanpiper_order_count()` attempts to map the `cancelled` status, which is not present in `status_map`, raising a `KeyError`. * The POS UI fails to load, preventing users from reopening the running session. ### Expected behavior Cancelled delivery orders should not be considered active delivery orders and should not be included in the delivery status count, allowing the POS session to open normally. ### Solution Exclude orders with `delivery_status = 'cancelled'` from the active delivery order count computation. This prevents the `KeyError` and ensures cancelled delivery orders are ignored when computing active delivery statistics. [Video reproducing the issue](https://drive.google.com/file/d/1XdiylekWV-q6LTbvhCgbyd_KDKlG2imz/view?usp=sharing) --- **opw-6353861** Forward-Port-Of: odoo/enterprise#122798
Studio's XML editor no longer applies website default-language translations when editing non-website views. This prevents business documents and other views from unexpectedly showing translated XML content just because Website is installed.
Original PR description
Problem: When opening the Studio XML editor when Website is installed, the translation terms corresponding to the Default Language of the first website in the database are used. This behavior should…
Problem: When opening the Studio XML editor when Website is installed, the translation terms corresponding to the Default Language of the first website in the database are used. This behavior should only be applied to the HTML/CSS Editor in Website. Purpose: Modify Website's override of get_related_views to only return translated views when called with a specific website in context. This is done here by adding a context flag, as to not interfere with customizations made in stable versions. This will be changed for master. Steps to Reproduce in Runbot: 1. Activate a non-English (US) language. 2. Add this language to the Website with the lowest ID in the database, then set it to the Default Language of the Website. 3. While in debug mode, enter Studio and navigate to a view that has translation terms (ex. Sale Order Form view), then open the XML editor. opw-5136124 Foward Port of https://github.com/odoo/enterprise/pull/110418 Forward-Port-Of: odoo/enterprise#116771
Shipment insurance configured on Envia delivery methods is now sent in the format expected by Envia. This helps ensure insured shipments, such as those using Mexican FedEx ground services, correctly generate the related insurance documents.
Original PR description
Issue ----- Insurance set on the delivery method is not correctly being communicated to Envia. Steps to reproduce ----- - Create a MX company - Set up Envia - Fedex Nacional Economico (ground) - 10% insurance - Create a MX client - Create a product (with some weight) - Create a SO using the delivery method & confirm - Validate the picking > No insurance pdf is being printed Cause ----- We are passing the insurance value as a `insurance` field on the shipment, which is not what the API expects. We should instead pass it in `additionalServices` as shown in the example of https://docs.envia.com/docs/additional-services#how-to-add-services-to-a-shipment ----- Ticket: opw-5254952 Forward-Port-Of: odoo/enterprise#121691 Forward-Port-Of: odoo/enterprise#118966
Fixed an error that appeared when users clicked the AI button while sending a signature request. The AI helper now uses the right interaction mode for Sign templates, so users can continue preparing and sending documents without interruption.
Original PR description
Version: saas-19.3 Steps to Reproduce: 1. Open a sign template and click "Send" 2. Click the AI button in the wizard Issue: Clicking the AI button raises ValueError: "The record must inherit from 'mail.thread'". Cause: `sign.template` does not inherit `mail.thread`, but interfaceKey `mail_composer` requires it. Fix: Added `get interfaceKey()` to `MailComposerChatGPT` so subclasses can override it. `SignAIButton` in `sign_ai` overrides interfaceKey to `html_field_record`. Taskid: 6303226 Forward-Port-Of: odoo/enterprise#120659
The outstanding payments widget on invoices now lists payments consistently by the most recent date and related record first. This reduces confusion for accounting users when reviewing open invoices and matching payments.
Original PR description
Before this commit: The invoice outstanding payments widget was not sorted by date globally, which could lead to confusion for users when viewing the widget. After this commit: This commit adds a sorting mechanism to ensure that the payments are displayed in descending order based on their date and ID. opw-6254080 Forward-Port-Of: odoo/enterprise#122964 Forward-Port-Of: odoo/enterprise#121642
Audit reports exported to PDF now include images inserted with the file command. This prevents missing visual evidence or supporting materials in generated reports, making exported documents more complete and reliable.
Original PR description
Currently, when a user uses the `/file` command to insert an image into an audit report and exports the report to PDF, the image is omitted from the generated PDF. To improve the support of those blocks, we will pre-process the document and replace the embedded files that correspond to images with standard image elements before PDF generation. This will ensure that images are correctly rendered and displayed within the document's text flow in the exported PDF. Task [link](https://www.odoo.com/odoo/project.task/5115280) task-5115280 Forward-Port-Of: odoo/enterprise#122699 Forward-Port-Of: odoo/enterprise#121673
Payroll work entries now avoid counting the same public holiday twice when attendance-based employees also have worked-time leave from sandwich rules. This helps keep generated payroll hours accurate and prevents inflated work entry totals on affected holidays.
Original PR description
Issue: When work entries are generated from Attendances, a worked-time time off created by the Indian sandwich rule can overlap a public holiday and generate duplicate work entries for the same day.…
Issue: When work entries are generated from Attendances, a worked-time time off created by the Indian sandwich rule can overlap a public holiday and generate duplicate work entries for the same day. Steps to reproduce: - Create an employee with Work Entry Source set to Attendances - Use a flexible working schedule on the employee - Configure a public holiday on a scheduled day with work entry type (Paid time off) - Create a time off type with Count as set to Worked Time - Generate time off for the period so the public holiday entry exists (maybe a day before and a the public holiday and the day after) - Open Payroll > Work Entries (Observe the date of the public holiday will have more than 8h entry) Cause: In `_get_version_work_entries_values()`, calendar leaves are split by `hr_holidays` `time_type` into: - leaves: absences and public holidays - worked_leaves: worked-time time off For attendance-based contracts, both sets were turned into work entries without removing overlap between a public holiday and a worked-time leave on the same period. https://github.com/odoo/odoo/blob/3a088e23d3e563c39cdcb252edc8c7cc74981de4/addons/hr_work_entry/models/hr_version.py#L222-L226 For non-flexible calendar: Public holidays and worked-time leaves are both clipped to the static working schedule (e.g. 8h per working day). overlap was kept in both result sets. https://github.com/odoo/odoo/blob/3a088e23d3e563c39cdcb252edc8c7cc74981de4/addons/hr_work_entry/models/hr_version.py#L260 For flexible calendar: The one-day intervals are kept as the actual interval (often 00:00-23:59 for a public holiday). The worked-time on that day is schedule-shaped (e.g. 8h). Subtracting intervals on a full-day public holiday left a 16h fragment instead of removing the public holiday entry. https://github.com/odoo/odoo/blob/3a088e23d3e563c39cdcb252edc8c7cc74981de4/addons/hr_work_entry/models/hr_version.py#L242-L249 Solution: We need to make regular leaves take priority over worked-time leaves, compute the real regular leave intervals first, then remove those intervals from the worked-time leave intervals before work entries are created: - for fully flexible employees, subtract regular leaves from worked leaves; - for flexible calendars, keep one-day regular leaves as is and subtract them from worked-time leaves - for non-flexible attendance-based calendars, clip regular leaves on the static schedule, then subtract them from worked-time leaves clipped on the same schedule. This means that when a sandwich worked-time leave overlaps a public holiday, the public holiday consumes that period first. The overlapping part is then removed from `real_worked_leaves`, so no second worked-time entry is generated for the same public holiday period. opw-6237163 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/enterprise#121940 Forward-Port-Of: odoo/enterprise#119530
Users without payroll access can now open employee working schedules without seeing an error linked to Belgian payroll data. The change prevents restricted payroll-related information from being read when the user does not have the required permissions, improving reliability for HR configuration screens.
Original PR description
**Steps to Reproduce:** 1)Create a database in v19.2. 2)Install the l10n_be_hr_payroll module. 3)Open the login user's profile and set the Payroll access rights to No (null). 4)Navigate to Employees…
**Steps to Reproduce:** 1)Create a database in v19.2. 2)Install the l10n_be_hr_payroll module. 3)Open the login user's profile and set the Payroll access rights to No (null). 4)Navigate to Employees → Configuration → Working Schedules. **Actual Result:** A traceback is triggered after opening the record. ```python Failed to read field resource.calendar.l10n_be_reorganisation_measure_ids You are not allowed to access 'BE: Reorganisation Measure.' (l10n.be.reorganisation.measure) records. This operation is allowed for the following groups: - Payroll/Assistant Contact your administrator to request access if necessary. ``` **Issue:-** The traceback is caused by the following commit introduced in v19.2 [here](https://github.com/odoo/enterprise/commit/e1092393ff99e9dad84ea8b9d6066e0bc61d6312) In this commit, a new computed field `l10n_be_reorganisation_measure_ids` was added on `resource.calendar`. The field is computed and store=true when the read function is called, and reads the data from the database at that time; The payroll doesn't have any access rights due to the error **Solution:** To fix this issue, a group access check is added inside the field Ticket:- 6245936 Forward-Port-Of: odoo/enterprise#119518
Stripe expense authorizations are now matched correctly when merchant category codes fall within configured ranges, reducing incorrect authorization errors. Declined Stripe expenses also avoid duplicate refusal messages, keeping expense records clearer for users.
Original PR description
# [FIX] hr_expense_stripe: Fix MCC ranges Context: Since 3e52d875 when receiving an authorization whose MCC fits in a range we would not find it in the search. This is logical yet we return an error before checking properly mcc codes with range included After this commit: This will also check that the authorization MCC exist if we don't directly find the range. We move the "not found" error after that check too The forgotten tests have been added into the overrides opw-6185961 opw-6288399 # [FIX] hr_expense_stripe: Fix double refusal of expenses Context: When an expense is created through a declined stripe authorization, the expense is refused twice, resulting in a duplicated refusal message After this commit: Do not refuse already refused expenses Forward-Port-Of: odoo/enterprise#122923 Forward-Port-Of: odoo/enterprise#121474
IoT device logs sent to the server are now recorded at a lower severity level. This reduces unnecessary alerts and Sentry usage from noisy device connection issues, helping teams focus on meaningful problems.
Original PR description
Each time IoT box sends its logs to the server (route `/iot/log`), we then print them with the same log level. However, IoT box logs can be quite noisy (for instance when there are some connection issues), which affects the logs. Sentry side, it also implies a huge wave of useless events that reach the limits of our subscription. The logs management have been improved on next versions. In the meantime, we should at least decrease the logger level so we can keep working on Sentry Forward-Port-Of: odoo/enterprise#122426
The Planning Analysis report no longer crashes when the Field Service planning module is installed. The Priority filter is now placed correctly, keeping the report accessible for users reviewing planning data.
Original PR description
Steps to reproduce: - 1. Install `planning_field_service`. 2. Open Planning > Reporting > Planning Analysis. Issue: - The view crashes with `UncaughtPromiseError > Error: Attribute "domain"` is missing, and the Planning Analysis report cannot be opened. Cause: - The xpath adding the "Priority" filter anchors on `//filter[@name='unpublished_shifts']`, which is a child of the "Status" filter. As a result, "Priority" is inserted inside "Status", and it requires a `domain` on any filter nested inside another filter. "Priority" has none. Fix: - Anchor the xpath on `//filter[@name='status']` instead. task-6358804
The Journal Audit PDF report no longer adds an empty final page when the global tax summary section is not included. This prevents confusing or unprofessional-looking report output for accounting users.
Original PR description
Steps to reproduce: 1. Set the active company as My Company (san francisco) 2. Navigate to Accounting > Review > Journal Audit 3. Remove all journals from the report except Bank and Misc. 4. Use the PDF action button to print the report. 5. The last page of the report is completely empty. https://drive.google.com/file/d/1otpniJgt1UNCe2hrUBwqIK58dGuXpu8T/view?usp=sharing This commit ensures that the Journal Audit report does not have blank pages when the global tax summary section is not present. It uses some features of QWeb outlined in the following docs article: https://www.odoo.com/documentation/19.0/developer/reference/frontend/qweb.html#loops opw-6224670 Forward-Port-Of: odoo/enterprise#122704 Forward-Port-Of: odoo/enterprise#121068
The webhook URL field is now constrained so it no longer stretches beyond its container in the form view. This prevents the nearby renew button from being covered or difficult to click, improving the usability of the page.
Original PR description
Before this commit, the webhook URL field could overflow in the form view, causing the adjacent renew button to become partially or fully unclickable. This commit fixes the issue by allowing the copy clipboard URL field container to shrink properly within layout, so the URL is truncated as intended and the renew button remains accessible. task:6317827 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272019
This change prevents a server error that could occur while WebSockets are being opened, improving stability for users. It also ensures cleanup happens correctly even if something goes wrong after the connection has been created.
Original PR description
Currently, when a `PoolError` from `psycopg2.pool` is raised (code ref [1]) during the execution of `retrying()` inside `acquire_cursor()`, Python's contextlib generates the following server error: ``` RuntimeError: generator didn't stop after throw() ``` This occurs because the exception is suppressed within the generator-based context manager, causing the generator to continue execution after throw(). This commit fixes the issue by limiting the `suppression/retry` logic to the cursor acquisition step. It also uses `ExitStack()` to ensure proper management of the exit callback stack across the `yield`, guaranteeing that resources are cleaned up correctly even if an exception is raised after the cursor is yielded. [1]: https://github.com/odoo/odoo/blob/1956c5e3e14086f699e4582a7332577bc2fbf557/odoo/sql_db.py#L648 Sentry-7567409750,7401155298 Forward-Port-Of: odoo/odoo#271527
The Timesheets kanban cards now keep the year in the date display on a single line, even when the card contains a long project, task, or description. This improves readability and prevents the date from breaking awkwardly on crowded cards.
Original PR description
Steps to reproduce:
-
1. Open the Timesheets app and display "All Timesheets" in kanban view.
2. Use a record whose project, task, or description is long enough to take up most of the card's width.
3. Look at the date shown on the left side of the kanban card.
Issue:
-
The year is split over two lines (e.g. "202" / "6") instead of staying on a single line.
Cause:
-
On the kanban card, the date is rendered in a small left-hand column split into two lines ("MMM d" and "yyyy"). That column has no `flex-shrink-0`, so when the description and the hours/avatar footer compete for space, the flex layout shrinks the date column until the year no longer fits and wraps.
Fix:
-
Add `flex-shrink-0` to the date column so it keeps its natural width.
task-6330852
Forward-Port-Of: odoo/odoo#27199216 changes
Resolved issues and error corrections
This update ensures invoices still reduce the declaration-of-intent plafond even when the DoI tax is used together with another tax on the same line. It prevents incorrect remaining amounts and keeps the customer’s tax limit accurate.
Original PR description
- Create a declaration of intent in the customer's contact - Issue an invoice that includes both the 0% E (DoI tax) and any other tax - You will see how the plafond is not updated and the amount of this invoice is not deducted from it The method _compute_l10n_it_edi_doi_amount specifically exclude from the doi amount lines with the doi tax and another tax. However it should be possible to use both on a single line. We can use the amount subtotal because the doi is always 0%. opw-6253475 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#267669
This fix ensures that hours already fully invoiced or refunded are not counted again when creating a new invoice from a sales order. It prevents customers from being charged twice for the same timesheeted work after a partial refund.
Original PR description
### Steps to reproduce: - Download 'Sales' and 'Timesheets' apps - Create a service product invoiced on delivered quantities with timesheet tracking - Create and confirm a SO for quantity 1 - Log 20h…
### Steps to reproduce: - Download 'Sales' and 'Timesheets' apps - Create a service product invoiced on delivered quantities with timesheet tracking - Create and confirm a SO for quantity 1 - Log 20h on timesheets - Invoice the SO - Create a credit note for 11 hours => only 9 hours are invoiced - Log 5h more on timesheets - Back to the SO > create invoice again > All the 25hrs are to invoiced, although 9 of them were invoiced before ### Cause of Issue: When generating the new invoice, `_recompute_qty_to_invoice` calls `_get_delivered_quantity_by_analytic` which retrieves the analytic values for the SO line. The values retrieved are later used to determine the delivered quantity, which is later assigned to be `line.qty_to_invoice` without taking into account the already invoiced hours. https://github.com/odoo/odoo/blob/7a6518e39d34575a3977e7c4a0053a45223e203c/addons/sale_timesheet/models/sale_order_line.py#L176-L186 ### Fix: Ensures that hours that have already been completely invoiced are deducted from the quantity to invoice. opw-6253650 Forward-Port-Of: odoo/odoo#274035 Forward-Port-Of: odoo/odoo#268025
This change fixes a test in the Italian e-invoicing withholding area after a previously merged update. It does not change business behavior, but it helps ensure the related functionality is checked correctly and future updates remain stable.
Original PR description
This commit just want to correct a test of a PR already merged. Original commit: 78ffb5a2e63401123e4506056493e52cf3e69953 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274262 Forward-Port-Of: odoo/odoo#274062
Mass mailing unsubscribe links now use the recipient’s own website address instead of the global database address. This prevents recipients in multi-company setups from being sent to a login page when they try to opt out, and keeps the unsubscribe flow working as expected.
Original PR description
In a multi-company setup with a website per company, the unsubscribe link in mass mailing emails could send recipients to the login page instead of the unsubscribe confirmation page. ### Steps to…
In a multi-company setup with a website per company, the unsubscribe link in mass mailing emails could send recipients to the login page instead of the unsubscribe confirmation page.
### Steps to reproduce
1. Enable multi-company and create a second company `Company B`.
2. Create two websites with different domains, one per company:
- `Website A` on the main company, domain `http://website-a.test`
- `Website B` on `Company B`, domain `http://website-b.test`
3. Set the system parameter `web.base.url` to `http://website-a.test`. System parameters are global, so this value applies to the whole database regardless of the company you switch to.
4. Create a contact and set its `Company` field to `Company B`.
5. In Email Marketing, create a mailing with recipient model `Contact`, target the contact above, pick any template with an unsubscribe link, and send it.
6. Open the email in an incognito window and click the unsubscribe link: you land on the login page instead of the unsubscribe page.
### Cause
Mass mailing builds the unsubscribe link in two steps.
First, each email body is rendered for its recipient. While rendering, relative URLs like `/unsubscribe_from_list` are turned into absolute URLs by prepending a base URL. That base URL comes from the recipient record itself: `recipient.get_base_url()`. The `website` module overrides this so that, when the record has a company, it returns that company's website domain. For a contact in `Company B`, the body ends up with `http://website-b.test/unsubscribe_from_list`.
Second, right before sending, `mail_mail._prepare_outgoing_list` replaces that placeholder URL with a per-recipient signed URL pointing to `/confirm_unsubscribe`. It does this by plain string replacement: it looks for `{base_url}/unsubscribe_from_list` in the body and swaps it. The `base_url` used here came from `self.mailing_id.get_base_url()`. A mailing has no company, so its base URL falls back to the global `web.base.url`, which in our setup is `http://website-a.test`.
The two base URLs no longer match. The body contains the website B URL, but the replacement code searches for the website A URL. The search fails, the placeholder stays in the email, and the recipient clicks a link to `/unsubscribe_from_list`. That route only redirects to `/mailing/my`, which requires being logged in, so the user lands on the login page.
### Fix
Compute the base URL from the recipient record (the same record used when rendering the body) instead of the mailing. The two URLs then agree and the replacement works. Fall back to the mailing's base URL if there is no recipient model on the mail.
opw-4914203
Forward-Port-Of: odoo/odoo#274191
Forward-Port-Of: odoo/odoo#264055This fix restores missing payment method information in self-order order responses. As a result, customers can again download their receipts correctly after an order is paid in the backend.
Original PR description
Steps to reproduce: - Set up a kiosk with pay at counter - Order a product - Settle the order in backend - Go to my order on the self, try donwload the receipt - TB Issue: This commit https://github.com/odoo/odoo/pull/237553 removed the pos_payment_method from the _generate_return_values method. The fornt-end didn't had the necessary data to generate the receipt. Fix: Restore payment method in the _generate_return_values method. Task-6191379 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#273831 Forward-Port-Of: odoo/odoo#263515
WebP images uploaded to Odoo now follow the same maximum size checks as other image formats. This prevents very large images from being accepted on upload, helping keep attachments consistent and avoiding oversized files in the system.
Original PR description
Since 17.0, `webp` images can be uploaded at any resolution, whereas every other format is refused above IMAGE_MAX_RESOLUTION (50 Mpx) when the attachment is created on the server. Root cause…
Since 17.0, `webp` images can be uploaded at any resolution, whereas every other format is refused above IMAGE_MAX_RESOLUTION (50 Mpx) when the attachment is created on the server. Root cause =========== `ImageProcess` grouped webp together with empty sources and SVG and set `self.image = False`, returning before the `verify_resolution` check. As a result the resolution limit enforced for `png/jpeg/...` was never applied to `webp`. Fix === Split `webp` out of the skip branch: it is still not processed as before, but its resolution is now read from the RIFF header with `get_webp_size()` and checked against `IMAGE_MAX_RESOLUTION`, so oversized webp images are refused on upload like any other format. Steps to reproduce =================== 1. Edit any page with the website editor 2. Upload a `webp` image larger than 50 Mpx (e.g. 8000x8000) => The image is accepted, while a `png/jpeg` of the same size is refused task-4134430 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273570 Forward-Port-Of: odoo/odoo#273010
The receipt deadline is now calculated without considering cancelled stock moves. This ensures that when a purchase line is reduced to zero and later dates are updated, the receipt shows the correct deadline instead of keeping an outdated one.
Original PR description
Steps to reproduce the bug:
- Create a Purchase Order with 2 products and confirm it
- Note the receipt's deadline (= date_planned of both lines)
- Set the quantity of one PO line to 0
- Update the scheduled date (date_planned) of the purchase order
Problem:
the receipt deadline does not update.
The receipt kept the old deadline from the cancelled move. When a PO line qty is set to 0, `_merge_moves` cancels the corresponding stock move via `_action_cancel`. Then `_update_move_date_deadline` correctly skips cancelled moves (filtered by `state not in ('done', 'cancel')`), so the cancelled move retains its original `date_deadline`. However, `_compute_date_deadline` on `stock.picking` used
`move_ids.filtered('date_deadline')`, which not checks move state, so the stale deadline of the cancelled move was included in the min/max computation.
opw-6292600
Forward-Port-Of: odoo/odoo#271890
Forward-Port-Of: odoo/odoo#270985This change prevents an error that could happen when searching paid POS orders after an employee has been archived. It ensures the POS can still load order data correctly, so users can keep working without interruption.
Original PR description
Steps to reproduce on runbot:
- Enable "Log in with Employees"
- Connect to the POS with an employee
- Process an order
- Go to the backend
- Archive the employee
- Connect to the POS with another employee
- Go to the "Order" tab and search for "Paid" orders
Error:
Odoo Server Error: {archived_employee_id}
[opw-6223243](https://www.odoo.com/odoo/project/49/tasks/6223243)
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#273889
Forward-Port-Of: odoo/odoo#266364This update prevents an error that could appear when opening the Time Off report by employee for French companies. It ensures the report opens correctly even when an employee has no working hours calendar set, improving reliability for HR users.
Original PR description
A singleton error appears when opening the "By Employee" report under Time Off. Steps to reproduce: 1)Install the l10n_fr_hr_holidays module. 2)Switch to the French company. 3)Open any employee record. 4)Set Working Hours (resource_calendar_id) to empty. 5)Set Hours Per Week. 6)Create a time off request for any past date. 7)Go to Reporting → By Employee. Task:-6043142 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#264585
This fixes a problem that prevented PDF generation for Polish e-invoices when QR codes were included. As a result, customers can again create and print the affected PDFs without errors.
Original PR description
Due to this (https://github.com/odoo/odoo/pull/244421/changes/546a4425884e61080a7a7e8d2b2a97c8a2e3f38e), PDF generation was broken. Removing the manual encoding of the data. Runbot [link](https://runbot.odoo.com/odoo/error/941292) runbot-941292
Customers paying with DPO were sometimes sent to an error page instead of the payment page because the transaction details were being sent in a way DPO did not preserve during a redirect. This update makes the payment details travel correctly so customers can complete their payment as expected.
Original PR description
When a customer paid through DPO, they landed on the DPO error page ("Not Valid - this transaction is no longer valid") instead of the payment page, even though the transaction token was created…
When a customer paid through DPO, they landed on the DPO error page ("Not Valid - this transaction is no longer valid") instead of the payment page, even though the transaction token was created correctly.
The customer is redirected to `https://secure.3gdirectpay.com/payv2.php` with the transaction token passed as the `ID` parameter. `payv2.php` answers with a 302 redirect to `payv3.php`. Per HTTP semantics, a 302 turns the request into a GET and drops the body, so when `ID` is sent in the body of a POST it never reaches `payv3.php`: the customer arrives at `payv3.php?` with no token and DPO rejects it as invalid.
This regressed with 97ec8a3e72d9d48a0a9620c53feea533421b9d67, which moved redirect providers to the generic redirect form. Before that commit, the token was part of the action URL itself (`payv2.php?ID=<token>`), so it stayed in the query string across the redirect. The refactor moved `ID` into `url_params` rendered as a hidden input, and since `http_method` was left unset the generic form defaults to POST, putting `ID` in the body.
Set `http_method` to "get" so the token is serialized back into the query string and survives the `payv2.php` -> `payv3.php` redirect, restoring the pre-refactor behavior. This also matches DPO's documented convention of passing the token in the URL query string.
opw-6312732
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThis change corrects a small typo that was preventing a responsive design class from being applied properly in the chat meeting interface. It helps the page adapt more reliably on different screen sizes, improving the user experience on mobile and smaller displays.
Original PR description
--- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274435 Forward-Port-Of: odoo/odoo#274343
All-day events imported from Google are now stored in a way that keeps them on the correct calendar day for users in any timezone. This prevents events from appearing one day earlier in list views for users west of UTC, while keeping calendar views unchanged.
Original PR description
When Google sends an all-day event, the payload only contains a date (no time), so the inbound sync stores start and stop at 00:00 UTC. The list view renders those Datetime fields in the viewing…
When Google sends an all-day event, the payload only contains a date (no time), so the inbound sync stores start and stop at 00:00 UTC. The list view renders those Datetime fields in the viewing user's timezone, so any user west of UTC sees the previous day. The calendar view stays correct because it reads the date part directly. The rest of Odoo stores all-day events at 08:00 and 18:00 UTC, which keeps the stored datetime inside the same calendar day: https://github.com/odoo/odoo/blob/327ad9b737b0f1d4c547c71a52c45d8433f2b3f4/addons/calendar/models/calendar_event.py#L408-L414 Apply the same 08:00 / 18:00 normalization when building values from a Google all-day payload, so events created on Google match events created in Odoo. Steps to reproduce: 1. Set your user timezone to America/Winnipeg. 2. Connect a Google account and run the calendar sync. 3. In Google Calendar, create an all-day event on January 31. 4. Sync, then open Calendar in list view in Odoo. => Start Date and End Date columns show January 30. Ticket [link](https://www.odoo.com/odoo/project.task/6145880) opw-6145880 Forward-Port-Of: odoo/odoo#271573 Forward-Port-Of: odoo/odoo#262282
The Point of Sale screen now shows the change due to the customer with the correct sign and value. This avoids confusion during payments and refunds, especially when the customer is owed money back.
Original PR description
Steps to Reproduce ------------------------ - Install point of sale. - Do a order and pay more than the amount. Issue ------ - The change amount is displayed as a positive value on the UI. - Typically, amounts going out of the shop (like change given to the customer) should be shown as negative. Cause ------- - The change amount was not correctly represented in the UI. - Since the change flows in the opposite direction of the payment, it should be displayed as the negation of the original amount. FIX ----- - Updated the frontend to display the change amount with the correct (negative) sign. - No backend changes were required, as the correct value was already being handled during order synchronization Enterprise PR: https://github.com/odoo/enterprise/pull/112560 task: 6074620 Forward-Port-Of: odoo/odoo#274534 Forward-Port-Of: odoo/odoo#256776
This change makes employee data refresh more reliably after updates, preventing outdated information from being shown because of cache issues. It helps ensure changes are reflected consistently when employee records are modified.
Original PR description
There was yet another issue with the cache but related to the contract_date_start field. To prevent any issues like this to arise again, the version_revision will have the write_date to invalidate cache everytime the model has been written to. task-6326052 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#273516 Forward-Port-Of: odoo/odoo#272855
Paymob no longer operates in Pakistan, so payments routed through that country are no longer available in Odoo. This change removes the unsupported option to avoid failed payment setups and confusion for users.
Original PR description
Paymob stopped their operations in Pakistan unexpectedly. Domain was dropped so none of the APIs work for Pakistan. Therefore we are removing the support of Pakistan in the Paymob provider. See Also: https://github.com/odoo/documentation/pull/18768 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273935
6 changes
Enhancements to existing features
This change speeds up forum pages by reducing the work needed to display popular tags and match similar posts. For odoo.com, it cuts the time and database load of forum page requests roughly in half, which helps the site stay faster under heavy traffic.
Original PR description
This PR improves the cost of `/forum/my-forum-1/my-slug-1234` by ~48%. This has a huge impact on odoo.com The `/forum/...` routes are the `#1` on odoo.com in terms of absolute count and in terms of…
This PR improves the cost of `/forum/my-forum-1/my-slug-1234` by ~48%. This has a huge impact on odoo.com The `/forum/...` routes are the `#1` on odoo.com in terms of absolute count and in terms of CPU and SQL cost. They are called several million times a day. The average total time for `/forum/my-forum-1/my-slug-1234` goes from ~358ms to ~187ms (sql: 107ms -> 52ms - cpu 250ms -> 135ms) This has been tested by extracting 30k real forum post urls from odoo.com logs and replaying them on a staging server. That day `/forum/...` routes were called 2.8M times ## before <img width="1343" height="122" alt="image" src="https://github.com/user-attachments/assets/2b8264b7-4f26-40a7-a20a-20d478f5a93a" /> ## after <img width="1339" height="124" alt="image" src="https://github.com/user-attachments/assets/7c73aeb0-a4b4-45b8-ae98-093ac70c438e" /> ### First commit before <img width="1857" height="946" alt="image" src="https://github.com/user-attachments/assets/63b9d966-f5fd-4047-b4cb-533b7e9491bc" /> after <img width="1844" height="867" alt="image" src="https://github.com/user-attachments/assets/9494efe0-0b7c-419d-b918-dcfe5e942e63" /> query plan for most used tags as public user: - with the index https://explain.dalibo.com/plan/gbf9fbd358687f3e - without the index https://explain.dalibo.com/plan/da5gg6cd27f67496 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Resolved issues and error corrections
A small typo in a user interface class was fixed so the meeting/call screen adapts correctly on smaller displays. This helps keep the layout consistent and improves the experience for users on different screen sizes.
Original PR description
--- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274435 Forward-Port-Of: odoo/odoo#274343
This fix prevents an error that could appear when opening the Time Off “By Employee” report for employees in the French company setup. It ensures the report works correctly even when an employee has no working hours calendar configured, avoiding a disruption for users reviewing leave information.
Original PR description
A singleton error appears when opening the "By Employee" report under Time Off. Steps to reproduce: 1)Install the l10n_fr_hr_holidays module. 2)Switch to the French company. 3)Open any employee record. 4)Set Working Hours (resource_calendar_id) to empty. 5)Set Hours Per Week. 6)Create a time off request for any past date. 7)Go to Reporting → By Employee. Task:-6043142 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#264585
This change prevents an error that could occur when searching paid POS orders after one of the employees involved had been archived. It ensures the Point of Sale order loading still works correctly, so users can continue reviewing past orders without interruption.
Original PR description
Steps to reproduce on runbot:
- Enable "Log in with Employees"
- Connect to the POS with an employee
- Process an order
- Go to the backend
- Archive the employee
- Connect to the POS with another employee
- Go to the "Order" tab and search for "Paid" orders
Error:
Odoo Server Error: {archived_employee_id}
[opw-6223243](https://www.odoo.com/odoo/project/49/tasks/6223243)
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#273889
Forward-Port-Of: odoo/odoo#266364We fixed an issue where the buttons for microphone, camera, and hang up could be hidden when joining a call in a mobile browser. The call screen now fits the visible area more accurately, making it easier to control calls on phones and tablets.
Original PR description
Before this commit, joining a call in a mobile browser (Chrome, Safari, ...) would crop the bottom call controls (mic, camera, hang-up, ...) behind the browser's chrome (URL bar / bottom nav). On…
Before this commit, joining a call in a mobile browser (Chrome, Safari, ...) would crop the bottom call controls (mic, camera, hang-up, ...) behind the browser's chrome (URL bar / bottom nav). On mobile, entering the meeting uses the fullscreen overlay with `keepBrowserHeader: true`, so no native fullscreen is requested and the browser UI stays visible. The overlay was sized with the Bootstrap `vh-100` class (`height: 100vh`), and `100vh` resolves to the *large* viewport (as if the URL bar were hidden). Combined with `fixed-top`, the overlay extended past the visible area and pushed the control row off screen. This commit sizes the overlay with `100dvh` (dynamic viewport height) instead, which tracks the currently visible viewport and shrinks while the URL bar is shown, keeping the controls on screen. This is a no-op in native/desktop fullscreen where `dvh == vh`, and matches the `dvh` usage already present in the codebase (welcome page, bottom sheet). task-6353266 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273949
Point of Sale receipts now correctly show line discounts when a product is sold with a percentage reduction. This helps customers and staff clearly see the discounted amount on the printed receipt, matching what was shown during the sale.
Original PR description
Currently, when adding a line discount it does not reflect on the receipt. Steps to reproduce: ------------------- * Add items to the order * For one of them use a line discount (% button) * Pay the order * Generate the receipt > The mention x% discount off on y is not displayed Why the fix: ------------ On the product screen the mention is shown and the value is computed here: https://github.com/odoo/odoo/blob/fc2230fb44dc421fe280d49da9b2d8134e1a0702/addons/point_of_sale/static/src/app/models/accounting/pos_order_line_accounting.js#L54-L66 We can reuse this fonction for the frontend, in the backend we translate it. We don't show this mention for the chosen products of a combo product. opw-6290821
2 changes
Enhancements to existing features
The VAT field now shows a cleaner placeholder and, when possible, the expected VAT format for the selected country. The help text was also simplified to make it easier for users to understand how to mark a customer without a Tax ID.
Original PR description
In this commit: - Remove 'or not applicable' and '/ if not applicable' from VAT placeholders. - Display the expected VAT format when available (e.g. BE0477472701). - Leave the placeholder empty when no format is known. - Simplify the tooltip to: 'You can use / to indicate that the customer has no Tax ID.' task-[5005896](https://www.odoo.com/odoo/project/967/tasks/5005896) Forward-Port-Of: odoo/odoo#273344
Resolved issues and error corrections
Uploaded WebP images are now checked against the same maximum resolution limit as other image formats. This prevents very large images from being accepted by mistake, helping keep uploads consistent and avoiding oversized files on the platform.
Original PR description
Since 17.0, `webp` images can be uploaded at any resolution, whereas every other format is refused above IMAGE_MAX_RESOLUTION (50 Mpx) when the attachment is created on the server. Root cause…
Since 17.0, `webp` images can be uploaded at any resolution, whereas every other format is refused above IMAGE_MAX_RESOLUTION (50 Mpx) when the attachment is created on the server. Root cause =========== `ImageProcess` grouped webp together with empty sources and SVG and set `self.image = False`, returning before the `verify_resolution` check. As a result the resolution limit enforced for `png/jpeg/...` was never applied to `webp`. Fix === Split `webp` out of the skip branch: it is still not processed as before, but its resolution is now read from the RIFF header with `get_webp_size()` and checked against `IMAGE_MAX_RESOLUTION`, so oversized webp images are refused on upload like any other format. Steps to reproduce =================== 1. Edit any page with the website editor 2. Upload a `webp` image larger than 50 Mpx (e.g. 8000x8000) => The image is accepted, while a `png/jpeg` of the same size is refused task-4134430 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273570 Forward-Port-Of: odoo/odoo#273010
2 changes
Resolved issues and error corrections
This change updates an automated test for the Italian e-invoicing withholding feature. It does not change business behavior, but it helps ensure the previously merged fix is validated correctly and reduces the risk of future regressions.
Original PR description
This commit just want to correct a test of a PR already merged. Original commit: 78ffb5a2e63401123e4506056493e52cf3e69953 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274062
This change prevents an extra calendar event from being created when a recurring series ends on a boundary day, especially for users in time zones behind UTC. It keeps Google Calendar sync aligned with the original series so users do not see duplicate meetings after updates.
Original PR description
When Google sends a recurrence with UNTIL in UTC (UNTIL=...Z), users in timezones behind UTC can get one extra occurrence on the boundary day. Google's UNTIL represents the last allowed start in UTC,…
When Google sends a recurrence with UNTIL in UTC (UNTIL=...Z), users in timezones behind UTC can get one extra occurrence on the boundary day. Google's UNTIL represents the last allowed start in UTC, but that UTC date fell into the previous local day. Because Odoo was comparing event start times as naive local datetimes against a cutoff derived from the wrong date, the boundary occurrence passed the check and was created. Steps to reproduce: 1. Set the user's timezone to a UTC-negative offset (e.g. America/Argentina/Buenos_Aires, UTC-3). 2. In Google Calendar, create a weekly recurring event (e.g. every Thursday at 12:00 local). 3. Edit the series with "This and following events" so the old series ends with UNTIL set to 02:59:59 UTC of the next day (= 23:59:59 local of the last valid occurrence day). 4. Sync with Odoo -> an extra event is created on the day after the last valid Thursday, which does not exist in Google Calendar. opw-6024835 Forward-Port-Of: odoo/odoo#273915 Forward-Port-Of: odoo/odoo#265297
32 changes
Security fixes and vulnerability patches
Appraisal permissions are now enforced in the underlying business logic, not only in the web interface. This helps prevent employees from using APIs to change restricted appraisal information or perform manager-only actions.
Original PR description
A lot of the access restrictions within the appraisal app, such as field visibility, editability and certain actions, were enforce only at the view layer through invisible/read-only. This works great for the usual case when uses the web-ui. However, when using the JSON2 API to interact with the appraisal app, the user could bypass these "security rules" as the usual invisible/read-only restrictions don't apply to the API. So a normal user could for example, modify the private note or mark an appraisal as done through the API which was impossible for them to do through the web-ui. This PR introduces the same security rules and validations to the model layer itself which makes it harder to perform unauthorized actions regardless of the interfaces. Task-5926306
New functionality added to Odoo
Malaysia companies can now use Balance Sheet and Profit & Loss report templates aligned with MPERS standards. This helps businesses produce locally compliant financial statements more easily and consistently in Odoo.
Original PR description
Add Balance Sheet and Profit & Loss reports according to MPERS standards. Community PR: https://github.com/odoo/odoo/pull/271714 task-6159106
Enhancements to existing features
The payroll dashboard now shows a dedicated cancel button when a user starts deleting a to-do item. This makes the choice to back out of deletion more obvious and reduces confusion for users.
Original PR description
Small UX improvement adding a cancel button when deleting todos on the dashboard. While you can simply press the x to cancel, showing a button for it makes it clearer at no extra cost.
Field service users can now see product availability forecasts and expected arrival timing directly in the stock moves list. This saves time by reducing the need to open each record individually when checking supplementary products for planned sales orders.
Original PR description
Previously, when a sales order for a field service product was planned, adding supplementary products only displayed the basic delivery status in the stock moves list view. To view the replenishment forecast or expected arrival date, users had to navigate into the form view. This commit exposes the `forecast_widget` in the list view. Users can now check product availability and arrival timelines at a glance without opening individual records. task-5929015
Printer setup now only shows the OBox IP address setting when it is relevant for ePOS printers. Less useful OBox service details are hidden from the regular view, reducing clutter and making configuration easier for users.
Original PR description
This PR adapts the view to only allow the user to set obox ip if the type of printer used is epos as it doesnt matter otherwise It also moves services installed on the obox to debug view only task-6330864
Project task users can now dismiss time off warning banners once they have been seen or addressed. Dismissed employees are skipped in future time off checks, reducing unnecessary processing and improving performance on tasks with multiple assignees.
Original PR description
Previously, leave warnings were always computed and displayed for all assigned employees, even if the warning was already known or addressed. For tasks with multiple assignees, this led to unnecessary processing. - Add a dismissal mechanism to the leave warning banner on the task form view. - Exclude dismissed users from the time-off calculation pool to avoid redundant fetching and performance degradation. task-5025297
Cell hover tooltips were removed from selected list views because they were hard to discover and often duplicated visible content. This makes day-to-day navigation less intrusive, while still allowing helpful tooltips on clearer elements like buttons or icons when needed.
Original PR description
In this commit, we decided to remove tooltips from the `cell` in the `listview`. The reasons are: - It’s hard to discover that a tooltip exists on a cell. - Default tooltips are annoying because they appear whenever the user parks the mouse over a cell. - Most tooltips are useless because they simply display the cell content If the content is truncated, you should resize/enlarge the cell instead. Note: Tooltip isn't ban but if a tooltip is really needed, it should be attached to a button or an icon rather than appearing on hover with a delay. task-4504910
Belgian payroll now better supports flexi-job contracts, including the required Dimona notifications, shift-hour capture, and payroll calculations. The update helps employers stay compliant by preventing invalid automatic declarations and adjusting wage handling when official notifications are refused.
Original PR description
Modifications include: - Updated the dimona workflow to support flexi-jobs, including capturing shift hours for same-day contracts. - Added restrictions to prevent automatic dimonas beyond 31 days and block contracts overlapping multiple quarters. - Added support for a new "Flexi Wage" and specific payroll computations. - Implemented anomaly code handling (460/510) to fall back to regular wage computations when a dimona is refused. - Updated the DMfA XML templates and schemas to include the `FlexiNotion` tag for relevant employees. Task Id : 6033394
The preparation display used by kitchen and order teams has been refreshed with a cleaner layout and improved visual styling. A new dark mode makes the screen easier to use in low-light environments and gives restaurants more flexibility for their setup.
Original PR description
*: pos_restaurant_preparation_display, pos_self_order_preparation_display, pos_urban_piper In this commit: ----------------------- - Implemented dark mode for the kitchen display. - Updated styling and layout for improved visuals. Task: 6112459 | Brfore | |--------| | <img width="1919" height="896" alt="image" src="https://github.com/user-attachments/assets/082924e6-f442-429f-afb0-6b5c16b7d761" /> | AFTER | Light | Dark | |--------|--------| | <img width="1919" height="898" alt="image" src="https://github.com/user-attachments/assets/225ce5c1-fee2-4ea7-ac80-5ee9c9232d1b" /> | <img width="1920" height="895" alt="image" src="https://github.com/user-attachments/assets/bee6c761-49ea-49b0-b20e-bd7d96904e6d" /> |
AI chats now behave more like standard Discuss conversations, with message search, editable conversation titles, and a visible favorite button in the header. Tools and Skills setup options were moved under Configuration so administrators can find setup-related settings in a more intuitive place.
Original PR description
AI chats were missing several behaviors users expect from any other Discuss conversation: searching within messages, renaming the conversation, and displaying the favorite button in the header (the action was already available but not visible there). The Tools and Skills configuration entries were also moved from the Agent menu to the Configuration menu, as they are setup-time settings rather than something a user interacts with during day-to-day agent use, and grouping them under Configuration is more consistent with where users expect to find them. task-6326376 Related: https://github.com/odoo/odoo/pull/273973
After a user signs a document, the thank you dialog now only suggests documents that are ready for that user to sign. This prevents users from opening or signing documents before their turn, making the signing flow clearer and more reliable.
Original PR description
Before this fix: After signing a document, the thank you dialog would show pending documents regardless of signing order. This allowed users to navigate to and sign documents even when it was not yet their turn. After this fix: The thank you dialog now only shows documents where it is the user's turn to sign, respecting the signing order set on the request. Impact: Improves user experience by ensuring the signing order is respected when navigating to the next document from the thank you dialog. Task ID: 6306061
The subscription sales module has been adjusted to stay aligned with recent platform changes. This helps keep subscription pricing behavior consistent and reduces the risk of disruption after upgrades.
Subscription product pages now show discount badges only when a plan is truly cheaper than the one-time purchase option or the relevant comparison price. Goods product pages also avoid showing misleading recurring price information, helping customers compare options more clearly before buying.
Original PR description
Before: - When "Accept One-Time Sale" was enabled, plans priced higher than the Buy Once price still showed a discount badge incorrectly. - For goods products, the "per period" price column was shown, which is misleading since goods are not sold on a recurring price basis. After: - When "Accept One-Time Sale" is enabled, each plan is compared against the Buy Once price; only cheaper plans show a discount badge. - For consumable products, discount is calculated against the most expensive delivery option so cheaper plans show the saving correctly. - For non-consumable products, plan prices are normalized to the shortest billing period for a fair comparison across all plans. - The "per period" price column is now shown only for service products. Impact: - Customers always see accurate discount badges. - Goods product pages no longer show a misleading per-period price, reducing confusion for customers during purchase. Taskid- 6230474
Rental orders now update key dates and prices automatically, reducing manual work and the risk of pricing mistakes. The sales form is also cleaner by showing subscription and rental fields only when they are relevant.
Original PR description
Before this change: - A delivery date field was manually editable and used to control the rental delivery date. - Changing the rental start or end date showed an 'Update Rental Prices' button to update rental pricing. - The rental period field was displayed below the delivery date. - The recurring plan field was visible even when no subscription product was present. After this change: - The delivery date field is hidden and automatically computed from rental_start_date. - Rental prices are automatically recomputed when the rental start or end date changes, removing the 'Update Rental Prices' button. - The rental period field is moved before the pricelist field for better UI flow. -The recurring plan field is now hidden when the order does not contain any subscription product. task-6031439 Community PR:https://github.com/odoo/odoo/pull/255832 Upgrade PR:https://github.com/odoo/upgrade/pull/9693
Project document workspaces now update their company when all linked projects belong to the same company. This removes an inconsistency where projects created in different ways could leave shared documents without the right company assignment.
Original PR description
Before this PR --- - Projects created from the kanban quick create have no company at creation time, so their workspace is born without one. Changing the company later from the form view was silently…
Before this PR
---
- Projects created from the kanban quick create have no company at creation
time, so their workspace is born without one. Changing the company later
from the form view was silently ignored for the workspace, causing the
workspace and its documents to remain without a company.
- Projects created from the list view had their company set at creation, so
their workspace already had a company, and changes were correctly propagated.
This inconsistency made the behavior depend on how the project was created.
After this PR
---
- When a project's company changes, all projects linked to the same workspace
are checked:
- If all linked projects are now in the same company, the workspace company
is updated accordingly.
- If linked projects are in different companies and the workspace has no
company, the workspace is left untouched (accessible to all companies).
- If linked projects are in different companies and the workspace already has
a company, an error is raised (existing behavior, unchanged).
- This makes the behavior consistent regardless of how the project was created
(kanban quick create or list view).
task-4988098Salary offers based on an existing employee version can now use a different PDF template. This gives HR teams more flexibility to tailor offer documents without changing the underlying employee version.
Original PR description
When the offer is based on an employee version (template is the version of the employee), allow to modify `sign_template_id`. Task-6094733
Route planning now checks the number of locations before contacting the map service, avoiding predictable failed requests. Users receive a clearer warning when too many stops are selected, making route planning feedback faster and easier to understand.
Original PR description
This commit adapts the geolocation `fetchRoutes` code to cancel requests with more than 25 coordinates (12 with optimized routing) instead of waiting for an error response from Mapbox. It also adapts the notification warning message in that usecase. task-6358624
Companies can now explicitly choose whether Stripe Issuing for expense cards runs in demo or production mode. This helps teams test cards safely without creating unnecessary fake Stripe accounts in a live setup.
Original PR description
In this PR: - Added a selection field "Mode" for users to explicitly select demo or production mode. - This avoids unnecessary creation of fake Stripe accounts in production. task-5952661
Resolved issues and error corrections
This fixes a payroll issue that could affect generating payslips from pay runs after recent changes to work entry dates. The update helps ensure payroll batches select the correct work entries, reducing the risk of incomplete or incorrect payslip generation.
Original PR description
Fixes a small issue with the generation to adapt a domain to the new date system on work entries.
The HSBC autopay configuration option is now shown correctly under the Hong Kong payroll settings. This helps Hong Kong payroll administrators access the bank payment setup without workarounds.
Original PR description
A recent change in the parent view made the HSBC setting invisible in most cases. We update the view to add it under HK localization and make sure it is visible.
The AI helpdesk help page now uses the correct main page heading. This improves accessibility for screen reader users and helps search engines better understand the page content.
Original PR description
Problem: On every page, we should have one and only one \<h1>. On /help, the title is set as a heading 2. Having one h1 establishes a clear document hierarchy, allowing search engine crawlers to understand your primary topic and ensuring screen readers can accurately navigate the content. Solution: Change the title's heading of the AI helpdesk page Task-6284703
Code cleanup and technical improvements
Odoo Studio’s form editor now uses the current rendering approach so selected fields and labels are decorated at the right moment. This keeps sidebar updates and drag-and-drop editing behavior reliable while removing an outdated compatibility method.
Original PR description
Replaced `useLayoutEffect` in `InnerGroupItemComponent` with `onMounted` + `onPatched` because `useLayoutEffect` is deprecated in OWL3. The single effect decorated label/field DOM elements with…
Replaced `useLayoutEffect` in `InnerGroupItemComponent` with `onMounted` + `onPatched` because `useLayoutEffect` is deprecated in OWL3. The single effect decorated label/field DOM elements with studio CSS classes immediately after each render. A reactive `useEffect` (OWL3's signal-based scheduler) re-runs asynchronously, so `studio_view.updateActiveNode` — which reads `.o-web-studio-editor--element-clickable` via `el.closest()` right after the view re-renders — found the label without the class, and the `o-web-studio-editor--element-clicked` decoration was never applied. `onMounted` + `onPatched` run synchronously within the patch commit, matching the timing the compat `useLayoutEffect` provided (which is itself implemented via `onMounted`/`onPatched`). `labelRef` and `fieldRef` were converted from OWL2 compat `useRef` wrappers to plain `signal(null)` class fields so the template uses `t-ref="this.labelRef"` / `t-ref="this.fieldRef"` and the refs are read with `this.labelRef()` / `this.fieldRef()` inside `applyStudioClasses`. The unrelated `rootRef` in `OuterGroup`/`InnerGroup` is kept as `useRef` since those classes have not been migrated. The useLayoutEffect refactored in this PR had test coverage — below are some tests that failed when the effect was commented out, and are now passing: - @web_studio/view_editors/form_editor/move a field in form - @web_studio/view_editors/form_editor/correctly display hook below group title - @web_studio/view_editors/interactive_editor_sidebar/update sidebar after edition see commented-out runbot build: https://runbot.odoo.com/runbot/batch/2602198/build/115250548
The VoIP test environment now handles country data requests the same way the live application does. This prevents unnecessary warnings and missing mock responses during softphone testing, making automated tests more reliable without changing user-facing behavior.
Original PR description
The mock server now dispatches /mail/store requests through a store handler registry, mirroring the python controllers. Register voip's res.country store handler in the mock so it matches voip/controllers/webclient.py; otherwise the registry warns (and serves nothing) every time the softphone fetches res.country during tests. https://github.com/odoo/odoo/pull/273720
This update modernizes internal test setup across several enterprise apps to match the newer application-based testing approach. It helps keep automated tests aligned with the current platform architecture without changing end-user functionality.
Original PR description
* documents,iot,obox,pos_enterprise,room,spreadsheet_edition,timer, web_grid,web_studio This commit replaces every occurence of `makeMockEnv` by `makeTestApp`. An app is the minimum test unit since owl3 compared to owl2 where it was the env. The commit also changes a little bit some helpers the multi tab tests (bus, imlivechat, mail) to depend less on the env and more on the helpers.
The spreadsheet-related apps were updated to support Odoo's newer interface framework. This is an internal modernization that helps keep document spreadsheets and spreadsheet dialogs reliable as the platform evolves.
Original PR description
* = [spreadsheet_edition] As part of the migration from `owl 2` to `owl 3`, this commit replaces uses of `t-custom-model` with `t-model` or `t-model.proxy`.
The VoIP softphone was updated to use newer platform mechanisms while preserving the same user experience. This helps ensure the softphone opens correctly, keeps the right tab selected, and focuses the search bar when users reopen it.
Original PR description
Replaced `useLayoutEffect` with `onWillRender` + `onMounted` + `onPatched` because `useLayoutEffect` is deprecated in OWL3. `useEffect` was tried first but its microtask-deferred re-runs are…
Replaced `useLayoutEffect` with `onWillRender` + `onMounted` + `onPatched` because `useLayoutEffect` is deprecated in OWL3. `useEffect` was tried first but its microtask-deferred re-runs are decoupled from the render/patch cycle. On softphone reopen (hide → systray click), the batched re-run arrived after the click already set `isDisplayed = true`, so the effect read the already-true flag and called `hide()` a second time — leaving the softphone closed and the search-bar input unfocused. The fix reproduces the original render-coupled timing with three native hooks: `onWillRender` subscribes the component to the reactive proxy so state changes trigger re-renders; `onMounted` applies the initial show/hide/promote logic; `onPatched` applies it on every subsequent render — matching the behaviour of the original `useLayoutEffect` exactly. The useLayoutEffect refactored in this PR had test coverage — below are some tests that failed when the effect was commented out, and are now passing: - @voip/softphone/softphone/Opening the softphone selects the Recent tab. - @voip/softphone/softphone/Search bar is focused after reopen the softphone. - @voip/softphone/activity_tab/Call activities are displayed in the "Activities" tab. see commented-out runbot build: https://runbot.odoo.com/runbot/batch/2596849/build/114857981
The payroll resource logic was simplified by replacing an older helper with direct working-period checks. This is an internal cleanup that should make future maintenance easier without changing day-to-day payroll behavior.
The Knowledge app was updated to keep its editor commands working correctly after a framework change. This preserves expected Knowledge and Helpdesk interactions, such as using articles, files, and templates, while reducing reliance on deprecated code.
Original PR description
Replaced `useLayoutEffect` in `FormControllerPatch.setup()` with `onMounted`/`onPatched` because `useLayoutEffect` is deprecated in OWL3. `useLayoutEffect` ran post-mount, after the chatter had…
Replaced `useLayoutEffect` in `FormControllerPatch.setup()` with `onMounted`/`onPatched` because `useLayoutEffect` is deprecated in OWL3. `useLayoutEffect` ran post-mount, after the chatter had registered its `__knowledgeUpdateCommandsRecordInfo__` callback. `useEffect` ran during `setup`, before the chatter was ready, so chatter access rights were never recorded. `onMounted`/`onPatched` with a `lastResId` guard restores the original post-mount timing and only re-evaluates on record navigation. The `useLayoutEffect` refactored in this PR has test coverage — below are some tests that failed when the effect was commented out, and are now passing: - TestKnowledgeEditorCommands.test_knowledge_article_commands_tour - TestHelpdeskKnowledgeCrossModuleFeatures.test_helpdesk_pick_file_as_attachment_from_knowledge - TestHelpdeskKnowledgeCrossModuleFeatures.test_helpdesk_pick_template_as_description_from_knowledge see commented-out runbot build: https://runbot.odoo.com/runbot/batch/2604778/build/115379873
Several accounting-related screens were updated to use the newer interface framework required by the Owl 3 migration. This is an internal modernization that helps keep bank reconciliation, import guidance, and reporting views compatible and maintainable without changing business workflows.
Original PR description
*account_reports As part of the Owl 3 migration, replace deprecated onWillRender hooks with the appropriate Owl 3 alternatives.
The report editor was updated to use newer supported framework behavior, keeping breadcrumb updates working as before. This reduces technical debt and helps ensure the feature remains compatible with upcoming platform changes without changing the user experience.
Original PR description
Replaced `useLayoutEffect` with `onMounted` + `useEffect` because `useLayoutEffect` is deprecated in OWL3. The original effect had an empty dep array (run-once). Its body did two things: (1) pushed the crumb onto the editor breadcrumbs — a one-time side-effect that maps to `onMounted`, matching how `useEditorBreadcrumbs` pushes its own `initialCrumb`; (2) started a reactive `effect()` keeping `crumb.name` in sync with `rem.reportData?.name`, returning the dispose fn as cleanup — this was replaced by `useEffect`, which auto-tracks the reactive read and is auto-disposed on unmount. The use layoutEffect refactored in this PR had test coverage — below are some tests that failed when the effect was commented out, and are now passing: - TestReportEditorUIUnit.test_basic_report_edition - TestReportEditorUIUnit.test_basic_report_edition_discard - TestReportEditorUIUnit.test_xml_and_form_diff see commented-out runbot build: https://runbot.odoo.com/runbot/batch/2624594/build/116553758
This update replaces an outdated internal mechanism in the grid view with the newer supported approach. It helps keep the grid reliable and ready for the next version of the underlying interface framework, without changing how users work with it.
Original PR description
Replaced `useLayoutEffect` with `onMounted` + `onPatched` because `useLayoutEffect` is deprecated in OWL3. The single tracked dependency was `component.props.reactive.cell` — a reactive property…
Replaced `useLayoutEffect` with `onMounted` + `onPatched` because `useLayoutEffect` is deprecated in OWL3. The single tracked dependency was `component.props.reactive.cell` — a reactive property holding the cell's HTMLElement (or null). The effect body wrote `component.state.cell` and immediately re-read it (via `state.cell.row.isSection` and `component.isEditable()`). A native OWL3 `useEffect` subscription was tried first but failed: the signal effect runs eagerly during `setup()`, before mount, so `rootRef.el` is null on the first run when `props.reactive.cell` is truthy, crashing with `Cannot read properties of null (reading 'style')`. Since the component already re-renders whenever `reactive.cell` changes (the overlay root is `<div t-if="props.reactive.cell">`), plain `onMounted` + `onPatched` running the same body is sufficient: `rootRef.el` is guaranteed present whenever `cellEl` is truthy, no `untrack` is needed, and the lifecycle callbacks reproduce the original post-render timing exactly. The use of `useLayoutEffect` refactored in this PR had test coverage — below are some tests that failed when the effect was commented out, and are now passing: - @web_grid/grid_view/grid_view_desktop/editing a value - @web_grid/grid_cells/float_toggle_grid_cell/FloatToggleGridCell: click to focus - @web_grid/grid_view/grid_view_desktop/Edition navigate with tab/shift+tab and enter key see commented-out runbot build: https://runbot.odoo.com/runbot/batch/2624597/build/116553714
This updates the Sign app’s internal upload handling to stay compatible with the next version of Odoo’s web framework. Drag-and-drop document uploads keep working as before, with tests confirming the behavior.
Original PR description
Replaced `useLayoutEffect` with `onMounted`/`onWillUnmount` because `useLayoutEffect` is deprecated in OWL3. `useListener` was considered first but cannot be used here: `.o_content` is an ancestor element owned by the layout component, not by `DocumentUploadMixin` itself, so there is no reactive signal or ref to give it. `onMounted` resolves `.o_content` once the component is in the DOM (guaranteed present), stores it, and attaches the three drag event listeners (dragover, dragleave, drop); `onWillUnmount` removes them — exactly reproducing the original post-mount timing and cleanup semantics. The useLayoutEffect refactored in this PR had test coverage — below are some tests that failed when the effect was commented out, and are now passing: - @sign/sign_kanban/Drop to upload file in kanban see commented-out runbot build: https://runbot.odoo.com/runbot/batch/2596830/build/114857573
11 changes
Enhancements to existing features
Database KPI reporting now supports showing the status of the Know Your Client procedure. This helps business users quickly monitor customer verification progress directly from database information.
Original PR description
Add a new type kyc_status to display the status of the Know Your Client procedure in the databases. Task-id: [6348952](https://www.odoo.com/odoo/project.task/6348952)
This update adds the new 13.5% Finnish tax rate and its related reporting group to support an upcoming VAT change from 14%. Businesses using Finnish localization can apply and report the new rate correctly when it becomes relevant.
Original PR description
backport of 5324615 As in Finland the tax rate will change from 14 to 13.5 on certain goods and services those taxes and the corresponding tax group were added to the l10n task-6332565
Resolved issues and error corrections
Fixed an issue where scanning a component product barcode on the shopfloor did nothing when that component was tied to a manufacturing operation. Operators can now scan these products as expected, reducing interruptions and manual follow-up during production.
Original PR description
When scanning a product barcode in the shopfloor, it would not simulate a click on the product if the corresponding BoM line was linked to an operation. Steps to reproduce: ------------------- * Create a BoM for product A with a BoM line for product B and link it to any operation. * Create a WO for product A and confirm it * Open the shopfloor with the WO and scan the barcode of product B > Observation: Nothing happens Why the fix: ------------ We simulate the onClick for the product even if the move is not marked manual_consumption. opw-6268665
Knowledge articles with embedded kanban, calendar, or map views now print and export to PDF correctly. This prevents blank PDFs and ensures users can share complete article content as expected.
Original PR description
When a Knowledge article embeds a kanban, calendar or map view and the user prints it or exports it to PDF, the view is missing and the printed page is blank. The Knowledge print stylesheet hides…
When a Knowledge article embeds a kanban, calendar or map view and the user prints it or exports it to PDF, the view is missing and the printed page is blank. The Knowledge print stylesheet hides those embedded views in print mode. The rule was introduced with the print feature under the selector `.o_knowledge_embedded_view > .o_kanban_view`, but `.o_knowledge_embedded_view` is emitted nowhere in the templates or components, so the rule matched nothing and the embedded views were always printed. Commit https://github.com/odoo/enterprise/commit/69612c80ea0aec5ccf2c2857449da03e61273457 rescoped the print rules and retargeted the selector to the real wrapper as `[data-embedded="view"] .o_kanban_view`. That selector matches, so the views are now hidden and the printed article is blank. Remove the rule from `knowledge_print.scss` so embedded views render again in print mode, restoring the behavior that held since the print feature was introduced. Steps to reproduce: 1. Open Knowledge and create a new article. 2. Click Build an Item Kanban, type a name and click Insert. 3. Add an item with Quick add so a card appears in the kanban. 4. Open the article options menu and click Download PDF. => The embedded kanban view is missing and the PDF is blank. Ticket [link](https://www.odoo.com/odoo/project/49/tasks/6299703) opw-6299703
This update lowers the severity of recurring IoT device log messages that were incorrectly treated as errors. It helps reduce unnecessary Sentry alerts so teams can focus on real issues without changing business workflows.
Original PR description
This PR adapts the necessary log levels to avoid spamming Sentry in a loop. Currently there is a lot of logs which can be avoided to be logged in error/exception level. see https://github.com/odoo/odoo/pull/273277
Shopfloor operators can now see their own and other operators' profile photos instead of generic placeholder images. This makes it easier to identify the right operator when using or editing the shopfloor operator view.
Original PR description
Currently when a shopfloor operator modifies the operator, operator images are not visible and only place holder images are visible. ## Steps to produce: - Install Manufacturing with demo data -…
Currently when a shopfloor operator modifies the operator, operator images are not visible and only place holder images are visible. ## Steps to produce: - Install Manufacturing with demo data - Login as Marc Demo - Open shopfloor ## Observed Behavior: Operator is unable to see their own profile picture and when you press the Edit Operator the operator is not able to see their as well as other operators images as well. ## Root cause: This issue occurs because by default an operator's user does not have access right for `Employees` in Human Resources section as they are not an HR officer nor an administrator. So when the user tries to access the image url that is meant for users with those access rights (HR officer / Administrator) at [1] and at [2]. The system returns a placeholder image instead of the employee image since the operator does not have access to hr employee model but does have access to hr employee public as per this [commit](https://github.com/odoo/odoo/commit/c9ca3761464413327d2beb697553a3ccd7eef4d1) [1]- https://github.com/odoo/enterprise/blob/5fe2fb44f4c8a938390343f7cdc90674cbf09391/mrp_workorder/static/src/mrp_display/dialog/mrp_employee_dialog.js#L16 [2]- https://github.com/odoo/enterprise/blob/5fe2fb44f4c8a938390343f7cdc90674cbf09391/mrp_workorder/static/src/mrp_display/employees_panel.xml#L9-L10 ## Solution: Allowing operators to see images can be done by modifying the links to use the public model instead of the private model. This will allow operators see other operators based on images and should improve user experience. | Before | |--------| | <img width="1865" height="844" alt="image" src="https://github.com/user-attachments/assets/c28f4209-0a60-486a-bfec-2a4db39cd946" /> | | <img width="995" height="899" alt="image" src="https://github.com/user-attachments/assets/7541edd9-6cc9-42d1-b5c5-39e0740d9a93" /> | | After | |--------| | <img width="1881" height="903" alt="image" src="https://github.com/user-attachments/assets/df3f8357-5cc2-4688-83dd-9a009fd56957" /> | | <img width="1221" height="862" alt="image" src="https://github.com/user-attachments/assets/c9d72b07-e1ad-43e4-85f5-00d8f1db9095" /> | opw-6321989
Correct a translation to australian English to better fit the expectations.
Original PR description
Correct a translation to australian English to better fit the expectations.
Lazada order imports no longer adjust individual item quantities based on item-level cancellation statuses. This prevents delivered orders from failing to sync when Lazada reports an exceptional item status after delivery.
Original PR description
Lazada stores order statuses at the item level. When an item is canceled, we mirrored this by decreasing the ordered quantity on the sale order line. But if the item was already delivered, decreasing the quantity below the delivered amount is forbidden and raises a `UserError`, which aborts the whole order sync:
```python
File ".../sale_stock/models/sale_order_line.py", line 420, in _update_line_quantity
raise UserError(_('The ordered quantity of a sale order line cannot be decreased below the amount already delivered. [...]'))
```
In practice, item-level statuses only differ from the order status in exceptional cases. Stop syncing statuses at the item level and assume the entire order shares a single status, which avoids the quantity decrease and the resulting traceback.
opw-6267730This fixes Hong Kong payroll calculations for payment in lieu of notice when an employee has not worked a full 12 months. The calculation now uses the contract start date to determine the relevant days and months, helping produce more accurate final payroll amounts and adding tests for special cases.
Original PR description
Currently, the calculation of the payment in lieu of notice is assuming the employee worked a whole 12 months prior to it being paid. This is of course not always going the be case, and when it happens our calculation is often incorrect. We update the salary rule to calculate a more accurate total days (which is no longer based on a fixed 12-month period but takes into account the contract's start date). We also now calculate the number of months more accurately by taking, once again, the contract's start date into account. Also adding a few test cases to test a bit more some special case we didn't yet test correctly. task-6348903 Forward-Port-Of: odoo/enterprise#122580
This fixes an error that could occur when changing quantities on confirmed field service sales orders while automated email/message rules are active. The update keeps internal message suppression working while returning the expected system object, preventing interruptions for users managing field service orders.
Original PR description
Steps to reproduce: ---------------------------------------- 1. Install `industry_fsm_sale` and `base_automation` modules 2. Create a product with: * Type: Service * Create on order: Task * Project:…
Steps to reproduce:
----------------------------------------
1. Install `industry_fsm_sale` and `base_automation` modules
2. Create a product with:
* Type: Service
* Create on order: Task
* Project: Field Service
3. Create an automation rule with:
* Model: Sales order
* Trigger: Incoming message
4. Create and confirm a sale order with this product
5. Add another product to the SO via the catalog view:
* Change the quantity to 2 or more
Observation:
----------------------------------------
Traceback occurs:
```
File '/home/odoo/src/odoo/addons/base_automation/models/base_automation.py', line 871, in _message_post
message_sudo = message.sudo().with_context(active_test=False)
AttributeError: 'bool' object has no attribute 'sudo'
```
Root Cause:
----------------------------------------
* Catalog qty change calls `set_fsm_quantity()` method
* Setting `fsm_quantity` triggers its inverse `_inverse_fsm_quantity()`, which writes the new qty to the SOL, but passes `fsm_no_message_post=True` in context to suppress chatter noise
https://github.com/odoo/enterprise/blob/ac5d670832a5e0db714c0bd056e1406b50bb4c17/industry_fsm_sale/models/product_product.py#L72-L83
* `sale.order.line.write()` detects a qty change on a confirmed order and calls `_update_line_quantity()`, which posts a message on the parent sale order
* FSM's `message_post` override sees the context flag and returns `False`
* When `base_automation` has an `on_message_received` rule on `sale.order`, it wraps `message_post` at registry load time. That wrapper calls `sudo()` on whatever `message_post` returns, Which was `False`
Solution:
----------------------------------------
Return `self.env['mail.message']` (empty recordset) instead of False, it's still falsy, but it's a proper ORM object that `sudo()` can be called on
opw-6276916
Forward-Port-Of: odoo/enterprise#119542Task progress shading in the Gantt view now correctly reflects hours worked against allocated hours. This fixes cases where a half-complete task appeared almost empty, helping users quickly understand task status at a glance.
Original PR description
Steps to reproduce: ------------------------------------------- 1. Install the Timesheet module with demo data 2. Go to any FSM task > set allocated hours to 20h 3. Fill the timesheet for the same…
Steps to reproduce: ------------------------------------------- 1. Install the Timesheet module with demo data 2. Go to any FSM task > set allocated hours to 20h 3. Fill the timesheet for the same task for 10h 4. Navigate to FSM > My Tasks > Gantt view Observation: ------------------------------------------- Look at the task on the Gantt chart. The shading is barely visible because it covers only 0.5% of the bar, not 50% Issue: ------------------------------------------- In the commit https://github.com/odoo/odoo/pull/137570/changes/4a93d9aee957dd3feb3db0cb69eb3b8f0f4a4683 The progress field computation was changed from storing percentage values (0-100) to storing decimal values (0-1). Specifically, the `_compute_progress_hours` method was modified. This change was made to standardize the progress field storage format, with the understanding that the UI layer would multiply by 100 when displaying the value. While most views (form, list, kanban, etc.) were updated to multiply the progress by 100 for display purposes, the Gantt view's pill progress bar was missed. Solution: ------------------------------------------- Overrides the `enrichPill` method to multiply the `_progress` value by 100 before it's passed to the template. This ensures the Gantt pill progress bars display correctly without modifying the core web_gantt module. Before --------------------------- <img width="268" height="368" alt="image" src="https://github.com/user-attachments/assets/6d35927f-bd3f-47fc-9101-e2e188d419b8" /> After: -------------------------- <img width="250" height="371" alt="image" src="https://github.com/user-attachments/assets/fe7133e0-26d1-4c5f-b903-48826fda9488" /> opw-6038983 Forward-Port-Of: odoo/enterprise#122899 Forward-Port-Of: odoo/enterprise#111270
6 changes
New functionality added to Odoo
This change adds new file formats needed for the French PDP implementation. It helps Odoo generate and handle the required electronic invoice documents for France, supporting compliance with local e-invoicing needs.
Original PR description
For the implementation of pdp, we are adding some files formats. task-4603737 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Enhancements to existing features
Xendit payments now support PayNow for Singapore, along with SGD and USD currencies. It also adds more accepted card brands, helping businesses offer a wider range of payment options to more customers.
Original PR description
This commit expands Xendit support to include the Singaporean market and additional card brands. The following changes were made: - Added support for the PayNow (SGQR) payment method. - Added SGD and USD to the list of supported currencies. - Added JCB and AMEX to the supported card brands (available for some markets). - Updated the base payment provider data for Xendit to include PayNow. Task-5964309 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update prepares the French e-invoicing setup to enforce two-factor authentication when the new PDP integration is enabled. It helps ensure the connection meets compliance requirements before users can send invoices through the approved platform.
Original PR description
WIP: waiting for the pdp pr To be compliant with pdp, a 2FA process needs to be setup on the login. task-5486860 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Resolved issues and error corrections
This change corrects the way a hidden field is written in a view so Odoo no longer shows a warning about a missing "true" field. The behavior for users stays the same, but the edit experience is cleaner and less confusing.
Original PR description
There is a warning saying that there is no "true" field when editing the view. But in reality this is currently working as expected and the field is hidden. related to opw-5947987
This fix makes attendance reports calculate expected hours using the employee’s weekly contract limit, not just the average hours per day. As a result, flexible schedules no longer show more expected hours than the employee’s contract allows when they work extra days in a week.
Original PR description
Issue: - When the attendance is flexible, the weekly expected hours shown in reports are incorrect. - This happens because the calculation is based only on the `Average Hour per Day` and doesn't take…
Issue:
- When the attendance is flexible, the weekly expected hours shown in reports are incorrect.
- This happens because the calculation is based only on the `Average Hour per Day` and doesn't take into account the `Hours per Week` set on the employee resource. It ignores the weekly limit defined in the employee's working schedule. -As a result, if an employee works more days than expected, the report may show more than the allowed weekly hours.
Example:
- An employee has a 32h/week contract and 8h/day.
- If they work 5 days, the system still counts 8h as expected for each day — totaling 40h instead of 32h.
Steps To reporduce:
- Set up a flexible contract with 32 hours/week (8 hours/day) for an employee.
- Log 5 attendances in one week with 8 worked hours each.
- Go to report and filter by employee by week, notice the current behavior yields 5 x 8 = 40 hours in expected_hours.
Solution:
- Check the weekly hours cap defined in `resource_calendar_id.full_time_required_hours`.
- If total `expected_hours` from earlier attendances this week exceeds that limit, set expected_hours = 0 for any excess.
OPW-4583064
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThis update fixes how long numbers are grouped for Portuguese (pt_PT) and Hindi (hi_IN), making them easier to read in the expected local format. It improves number display consistency for users in these languages, especially when viewing large values.
Original PR description
Currently the number grouping for Portuguese and Hindi is missing. Number grouping is used to separate long numbers in logical groups to make then easier to read. In Western countries, the grouping is usually done in groups of three digits (e.g. `1,000,000` instead of `1000000`), while in India, the grouping is done in groups of two digits after the first three digits (e.g. `10,00,000` instead of `1000000`). Source: https://www.unicode.org/cldr/charts/48/by_type/numbers.number_formatting_patterns.html#24a93b3d14ba17b2 All languages will be revised in a follow-up `master` PR. [task-6320391](https://www.odoo.com/odoo/project.task/6320391) Forward-Port-Of: odoo/odoo#274443
5 changes
Enhancements to existing features
The Azerbaijani Manat (AZN) now uses its official currency symbol, ₼, instead of the previous symbol. This improves accuracy and consistency in currency display for users who work with Azerbaijani currency.
Original PR description
This commit updates the base currency symbol for the Azerbaijani Manat (AZN) to its official Unicode character '₼'. Related Upgrade PR: https://github.com/odoo/upgrade/pull/10107 Backport of: https://github.com/odoo/odoo/pull/262471 task-6112867
Resolved issues and error corrections
This fix makes Microsoft calendar connections renew correctly by saving the new refresh token each time access is refreshed. As a result, users are less likely to be asked to log in again every 90 days when their original token expires.
Original PR description
Microsoft issues a new refresh token on every access token refresh (rolling 90-day sliding window). The previous code discarded it, causing users to be forced to re-authenticate every 90 days once the original token expired. Closes #253543
When records are grouped by hour, the labels now use a 24-hour format instead of a 12-hour format without AM/PM. This removes ambiguity in grouped lists and ensures users can clearly distinguish afternoon and evening records.
Original PR description
Description of the issue/feature this PR addresses: When grouping datetime fields by hour, `read_group` formats the group display label using `hh:00 dd MMM`. In Babel/LDML formatting, `hh` represents…
Description of the issue/feature this PR addresses:
When grouping datetime fields by hour, `read_group` formats the group display label using `hh:00 dd MMM`.
In Babel/LDML formatting, `hh` represents a 12-hour clock. Since the format does not include an AM/PM marker, afternoon/evening hours are displayed ambiguously in grouped views.
Current behavior before PR:
A datetime value in the afternoon is grouped under a 12-hour label without AM/PM.
For example, records around `13:50` are displayed under:
01:00 20 Mar
Similarly, a datetime value around `16:20` may be grouped under:
04:00 26 Mar
This is ambiguous because the group header does not indicate whether the hour is AM or PM.
Example screenshot showing records around 13:xx grouped under `01:00`:
<img width="251" height="195" alt="image" src="https://github.com/user-attachments/assets/9c394063-f679-4faa-a045-2456cc452fb9" />
Desired behavior after PR is merged:
Hour-based datetime group labels should be unambiguous.
The hour grouping format now uses `HH:00 dd MMM`, so grouped datetime labels render using a 24-hour clock.
For example:
13:00 20 Mar
16:00 26 Mar
This fixes the datetime hour grouping label shown in grouped list views and other `read_group` consumers.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThis change avoids a rare timing issue where the same online payment could be processed twice if both the scheduled background job and the customer’s return flow tried to handle it at the same time. It helps ensure each successful payment is finalized only once, reducing the risk of duplicate post-processing and related accounting or order handling issues.
Original PR description
The following use case has been observed: 0. Customer start a payment from /shop/payment. 1. We received the webhook that notifies that the payment succeeded. 2. The payment post-processing cron…
The following use case has been observed: 0. Customer start a payment from /shop/payment. 1. We received the webhook that notifies that the payment succeeded. 2. The payment post-processing cron start (it gather all the transactions that need to be processed, including the customer new transaction) 3. Meanwhile, the customer is redirected back by the payment provider to Odoo, which then redirect to /payment/status and start the payment post-processing for that specific transaction 4. The customer initiated payment processing finishes, he is redirected back to /my/orders/... page. 5. The payment post-processing cron finally start processing the same customer transaction and process it (a second time). In that case, as the transactions to be post-processed backlog was quite high, there is consequent time between the time we gather all the TXs to post-process and actually process the customer transaction. Also we don't end up with a `SerializationError` as the cron do commit after each transaction post-processing. This commit force invalidate individual transaction cache values and recheck if it effectively still need to be post-processed before doing it. opw-6332192 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update fixes a connection issue in the Spanish e-invoicing flow when a company uses a seal certificate instead of a personal one. The system now selects the correct AEAT endpoint based on the certificate type, which helps prevent authentication failures and improves reliability.
Original PR description
The AEAT provides different endpoints depending on the type of digital certificate you use. A personal certificate or a seal certificate. The module used always the standard endpoint regardless of the certificate type. Causing authentication failures when a sello certificate was configured. This fix detects the certificate type by checking for the presence of a GIVEN_NAME attribute. task-6169935 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr