Daily updates from Odoo
Monday, June 29, 2026
241 changes
7 changes
Resolved issues and error corrections
This change ensures translation terms are only applied to website-specific editors, so Studio’s XML editor no longer picks up the default language from the first website in the database. It prevents confusing translation mismatches and keeps the special website behavior limited to the HTML/CSS editor where it belongs.
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 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/odoo/pull/237000 Forward-Port-Of: odoo/odoo#263592
This change updates automated tests for the map view so they complete more reliably even when execution is slower than expected. It helps prevent test timeouts and reduces false failures in the development and deployment pipeline.
Original PR description
This commit replaces the waitFor timeout in map view tests with runAllTimers to cope with potential execution slowdowns and avoid waiting for too long while executing the tests. runbot-error-939600 Forward-Port-Of: odoo/enterprise#119654
This update prevents errors when importing Shopee customers whose identifiers are larger than the system’s standard number range. If an ID is too large to store in the usual field, Odoo now uses an alternative customer reference so contact creation and matching can still work correctly.
Original PR description
When the Shopee connector was introduced, Shopee documented `buyer_user_id` as an int32. We therefore store it in an `Integer` field, which maps to a PostgreSQL int32 column. However, feedback showed that Shopee can send ids exceeding the int32 bounds, leading to a traceback when creating new contacts. Shopee has since updated their documentation to confirm the field is actually an int64. Since we are in stable and cannot change the column type, this commit falls back to the `ref` field of the `res.partner` model to store and match Shopee contacts whose identifier doesn't fit within an int32. opw-6325948 See also: - master: https://github.com/odoo/enterprise/pull/121507 - upgrade: https://github.com/odoo/upgrade/pull/10578 Forward-Port-Of: odoo/enterprise#121707 Forward-Port-Of: odoo/enterprise#121498
This update standardizes the spacing used on card-based kanban screens so they follow the same layout rules across affected areas. It helps the interface look more consistent and reduces the risk of spacing differences between views.
Original PR description
Rename and reuse the new generic card padding variables. Follow-up of https://github.com/odoo/odoo/pull/272083
The website profile page now uses the currently logged-in user when displaying the email verification banner. This prevents another person's private email address from appearing on a public profile page, protecting user privacy.
Original PR description
**Steps to reproduce:**
- Install website_forum module
- Create a new portal user and log in with it
- Go to the website forum to see that the account requires email verification
- Send the verification email to see the green banner ('an email was sent to XX')
- Add XP (karma) points to this user as admin (User > Smart actions > Karma)
- Switch back to the portal account
- Check any public user profile on the forum (`/profile/user/2?forum_id=2`)
- Green banner now displays the private email of the user you're checking
**Issue:**
On the `email_validation_banner` the user field is used for the validation
data, but it is overridden by `_prepare_user_profile_values` which is
setting the current page user.
**Fix:**
Properly set `user` to `env.user` in the template.
opw-6276809
Forward-Port-Of: odoo/odoo#269249When a Google Calendar account is disconnected with event deletion enabled, the system now removes all related recurring schedule rules as well as the individual events. This prevents leftover recurrence data from blocking future resynchronization of the same account.
Original PR description
When we disconnect a google account with the delete events option enabled, we should also delete `calendar.recurrence` records, not just the base events. Broken flow: 1. Sync google calendar with some recurrent event on google 2. Reset account via the wizard 3. -> The events are removed, but the recurrent rule remains in the db 4. Resync with the same account 5. -> The recurrence is not created because it already exists on the database Follow-up for odoo/odoo@ae52126522e3570e11845c3c04d0eb6b198b3848
This update restores a Planning tour that was failing after changes to the popover interface. It ensures the automated test matches the new behavior so Planning can be validated reliably again.
Original PR description
PR [1] refactored the gantt popover API, and classname `.popover-footer` has been replaced by `.o_popover_footer` (i.e. we no longer use the bootstrap class for popovers). Tours that fail due to this change have been adapted accordingly. However, there was a planning tour that was temporarily deactivated and that we thus didn't spot. This commit fixes it. [1] odoo/enterprise#114328 runbot error~940279
32 changes
Enhancements to existing features
This update records device details when a login session appears to come from a different device than the one currently in use. It helps teams spot unusual access patterns and investigate potential account misuse more quickly.
Original PR description
Log device information if fingerprint doesn't match the one currently being used for the current session. Task-6340963 Forward-Port-Of: odoo/odoo#272413
This update adds two new delivery providers to the point-of-sale Urban Piper integration: Food Zapp for the UAE and Enqueue for Saudi Arabia. It broadens local delivery support, helping businesses connect with more region-specific delivery options.
Original PR description
In this commit: - We are introducing two new providers, FoodZapp and Enqueue, for the UAE and KSA, respectively. Task-6263190,6263310 Forward-Port-Of: odoo/enterprise#121461
The option to send a PDP response is no longer shown as a prominent button on the invoice or bill screen. It has been moved into the settings/menu area, since cancelling and reposting the document achieves the same result and keeps the interface cleaner.
Original PR description
No real need to show a big button for sending a response in PDP as cancelling and posting an invoice/bill would do the same, so we move it to the cog wheel menu task-6274220 Forward-Port-Of: odoo/odoo#268846
Resolved issues and error corrections
This fix makes website popups reliably open and close even when users click the visibility toggle very quickly. It prevents the popup state from getting out of sync with the editor icon and avoids follow-up errors when adding nested popups.
Original PR description
__To reproduce__ 1. Drop a popup on the website. 2. Click twice rapidly on the popup show/hide toggle in the sidebar. => The popup visibility will be in an inconsistent state compared to the toggle's…
__To reproduce__ 1. Drop a popup on the website. 2. Click twice rapidly on the popup show/hide toggle in the sidebar. => The popup visibility will be in an inconsistent state compared to the toggle's eye icon. __Reason__ Bootstrap ignores any call to show/hide if the popup is still transitioning. __Fix__ - Set `_isTransitioning` to `false` to trick Bootstrap into firing the event regardless of its current state. - When hide/show are triggered in quick succession, the modal can enter an inconsistent state with `.show` class but `display: none` style (hide removes `.show` immediately, show restores it with `display: block`, then hide applies `display: none` after animation). Dispatching `transitionend` event before resetting `_isTransitioning` ensures Bootstrap completes its state transitions. __Note__ This commit also fixes `custom_popup_snippet`, which fails non-deterministically with the following error: `TypeError: Cannot read properties of undefined (reading 'after')` This error occurs when trying to add a popup inside another popup that never closes due to this bug. runbot-939039 Forward-Port-Of: odoo/odoo#269782
The forum’s email verification banner now shows the correct email tied to the current logged-in user, instead of accidentally exposing the private email of the profile being viewed. This prevents confusing and potentially sensitive information from appearing on public profile pages.
Original PR description
**Steps to reproduce:**
- Install website_forum module
- Create a new portal user and log in with it
- Go to the website forum to see that the account requires email verification
- Send the verification email to see the green banner ('an email was sent to XX')
- Add XP (karma) points to this user as admin (User > Smart actions > Karma)
- Switch back to the portal account
- Check any public user profile on the forum (`/profile/user/2?forum_id=2`)
- Green banner now displays the private email of the user you're checking
**Issue:**
On the `email_validation_banner` the user field is used for the validation
data, but it is overridden by `_prepare_user_profile_values` which is
setting the current page user.
**Fix:**
Properly set `user` to `env.user` in the template.
opw-6276809
Forward-Port-Of: odoo/odoo#269249This change prevents a website error that could happen when adding a dynamic product block to a page. It makes the system skip a date check for placeholder products that do not have a publish date, so page editing works smoothly without interruption.
Original PR description
Currently, an error occurs when a user insert a dynamic product snippet onto website. **Steps to Reproduce:** - Install `website_sale` without demo data. - Go to `Website` > `eCommerce` > `Products`…
Currently, an error occurs when a user insert a dynamic product snippet onto website. **Steps to Reproduce:** - Install `website_sale` without demo data. - Go to `Website` > `eCommerce` > `Products` > `Ribbons`. - Open any ribbon and set `Assign` to `When New`. - Go to the `Website` > `Edit` > drag and drop the `Catalog` block, and select a `Dynamic Product` block (`Generic Product Template (customizable)` [ref](https://drive.google.com/file/d/1ZYeQA8DhfYAf_jbPwL-tZXaVi1YAyFbd/view?usp=drive_link)). `TypeError: unsupported operand type(s) for -: 'datetime.datetime' and 'bool'` After this [recent commit], when a user drops a dynamic product snippet, the system attempts to set the ribbon value [1]. If no product records are available, it falls back to using sample products [2]. These sample products are virtual records created with model.new() [3] [4] and are not stored in the database, so they do not have a publish date. When auto-assigned ribbon with the When New option assign, the system compares the ribbon's new period with the product's publish date. Since the sample products do not have a publish date, this comparison raises an error [5]. This commit ensures that the comparison between new period and publish date is only performed when the product has a valid publish date. [recent commit]: https://github.com/odoo/odoo/commit/f427f795c24ee37ee02302642b77bfc314a9ea43 [1]- https://github.com/odoo/odoo/blob/b70330df7dc2017ab592b075c8ad8e048f671d90/addons/website_sale/templates/snippets/product_snippet_template_data.xml#L52-L58 [2]: https://github.com/odoo/odoo/blob/b70330df7dc2017ab592b075c8ad8e048f671d90/addons/website/models/website_snippet_filter.py#L75-L78 [3]- https://github.com/odoo/odoo/blob/b70330df7dc2017ab592b075c8ad8e048f671d90/addons/website/models/website_snippet_filter.py#L210-L215 [4]: https://github.com/odoo/odoo/blob/b70330df7dc2017ab592b075c8ad8e048f671d90/addons/website_sale/models/website_snippet_filter.py#L62-L95 [5]: https://github.com/odoo/odoo/blob/b70330df7dc2017ab592b075c8ad8e048f671d90/addons/website_sale/models/product_ribbon.py#L121-L124 sentry-7528296918 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update prevents command shortcuts and markdown auto-formatting from triggering inside code blocks. It avoids errors when users type commands in code content and keeps code formatting from being changed unexpectedly.
Original PR description
### Steps to reproduce: - Go to ToDo. - Create a code block using `/code`. - Place the cursor inside the code block. - Type `/table` and select the table command. - A traceback occurs. ### Purpose of this PR: - Commands and markdown shorthands should not be available inside code blocks. However, typing `/` inside a `<pre>` opened the command palette, allowing structural commands such as `/table` to be executed and causing a traceback. Similarly, markdown shorthands such as `* ` and `1.` were still active, unexpectedly transforming code content into lists. ### This PR fixes the issue by: - Disabling the command palette when the cursor is inside a `<pre>` element. - Disabling markdown shorthands inside `<pre>` elements by registering an `are_shorthand_available_predicates` predicate. task-6292231 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271796 Forward-Port-Of: odoo/odoo#269430
This change prevents a warning from being logged on every document upload when automatic OCR is not enabled. It reduces noisy logs and makes it easier for teams to spot messages that actually need attention.
Original PR description
The warning "Automatic OCR does not apply to this document" was logged for every upload when automatic OCR isn't enabled, it isn't very useful. opw-[6232122](https://www.odoo.com/odoo/unassigned-tasks/6232122) Forward-Port-Of: odoo/enterprise#120741
The website editor now hides the editing toolbar when a content block is removed, even if text was previously selected. This fixes a confusing issue where the toolbar could remain visible after deleting a snippet, improving the editing experience for users.
Original PR description
Commit 8df8b4f41809de75f9ca220d47274cc3166f1cd5 moved the check for selection inside `[data-prevent-closing-overlay]` to the `closeToolbar` plugin. But when this function is called from `selection_leave_handlers` it should not do that check, as it was done for the focus or click. This commit skips the check based on the selection when `closeToolbar` is called by `selection_leave_handlers`. Steps to reproduce: - Open website builder - Drop "Text Image" snippet - Select some text in the snippet - Click on the trash icon in the sidebar to remove the snippet - Bug: the toolbar is still shown task-6308364 Forward-Port-Of: odoo/odoo#270516
This fix prevents a traceback in Planning when the system tries to auto-plan or send schedules without start or end dates. It makes the workflow safer and avoids interruptions for users working with incomplete planning data.
Original PR description
Add a guarding condition to the auto-plan or send behavior to avoid doing those operations when no start/end dates are defined --- Task: 6312650 Forward-Port-Of: odoo/enterprise#121808
The text editor now keeps the correct text selection when a popover is closed by clicking back into the page. This prevents the editor from unexpectedly resetting the selection, which could otherwise affect formatting actions like text color changes.
Original PR description
When a popover is used on top of an iframe, when clicking outside the popover but inside the iframe to close the popover, the click away is detected through a blur event. The close during the click…
When a popover is used on top of an iframe, when clicking outside the popover but inside the iframe to close the popover, the click away is detected through a blur event. The close during the click away is used by some features to apply the change. Setting the text color in the editor might modify the DOM structure and therefore needs to readjust the selection to match the new DOM nodes. When confirming a color, or when applying intermediary changes this behavior is required. But when the color confirmation happens because of a click away, this selection gets on the way of the selection made by clicking away. The sequence of events is as follows: - pointerdown in iframe: sets the selection based on the click - main window blur: color gets applied, and selection gets reset - pointermove in iframe: expands selection to new position This commit avoids this unwanted reset by detecting the click away through a pointerdown on the iframe - thus making the selection adjustment before the default browser handling of the event actually sets the selection on the clicked position. Steps to reproduce: - Edit a website page - Drop a text snippet - Select a word - Set a custom color using the color area - so that the color picker remains open - Click (and hold) in the empty area after the text paragraph - Move pointer by a few pixels => The text anchor remained the one of the former selection, but the focus was set according to the pointer position Note that Firefox did not blur the main window, therefore this change actually also unifies the behavior of Chrome and Firefox. The discrepancy between Chrome and Firefox's handling of the blur event in this situation seems to be related to either prioritizing the DOM specifications or the HTML specifications - and the way the are interpreted. The DOM Standard [1] relies on UIEvents [2] which states: "A user agent MUST dispatch this event when an event target loses focus." The HTML Standard defines how to compute the focus [3] and relies on nested browsing contexts [4]. Typically, the simpler readable description for developers says: "document.hasFocus() Returns true if key events are being routed through or to document; otherwise, returns false. Roughly speaking, this corresponds to document, or a document nested inside document, being focused." [1]: https://dom.spec.whatwg.org/#biblio-uievents [2]: https://w3c.github.io/uievents/#event-type-blur [3]: https://html.spec.whatwg.org/multipage/interaction.html#focus-processing-model [4]: https://html.spec.whatwg.org/multipage/document-sequences.html#nested-browsing-contexts task-6268573 Forward-Port-Of: odoo/odoo#269742
This fix stops public holiday work entries from being counted twice when they overlap with worked-time leave, such as sandwich leave rules. It ensures the holiday is handled first so payroll work entries stay accurate and employees are not overcounted on the same day.
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#121542 Forward-Port-Of: odoo/enterprise#119530
Reports will no longer show ledgers that do not contain any journals for the active companies. This reduces confusion by removing entries that are not meaningful for the current business context.
Original PR description
When a ledger does not include any journal of the active companies, do not display it because it does not make sence for these companies. task-6280033 Forward-Port-Of: odoo/enterprise#119546
This change prevents public holidays and worked-time leave from being counted twice on the same day when work entries are generated from attendances. It ensures the public holiday is taken into account first, so payroll data stays correct and employees do not get duplicate time entries.
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/odoo#271637 Forward-Port-Of: odoo/odoo#268527
This update fixes an issue in the website builder where elements with a custom inline shadow could be shown with the wrong shadow state. It also ensures that removing a custom shadow clears any standard shadow styling too, keeping the visual result consistent.
Original PR description
Before this PR, , since [1], elements with an inline `box-shadow` and no custom shadow class were not detected as custom shadows by the builder option. This could make existing snippets show the wrong shadow state. After this PR, elements with an inline `box-shadow` are treated as custom shadows by the builder option, and cleaning the custom shadow also removes Bootstrap shadow classes. [1]: https://github.com/odoo/odoo/commit/55890082db7879bef3a976c84ab336bdacf76818 task-6251151 Forward-Port-Of: odoo/odoo#267175
This fix restores the standalone Timesheet icon when Attendance from the backend is turned off. Users can once again log hours directly from the toolbar instead of losing access to the timesheet action.
Original PR description
Steps to reproduce: - Install Attendance + Timesheets - Disable "Attendances from Backend" - Timesheet icon disappears from toolbar Current behavior: Bridge module permanently removes the `timesheet…
Steps to reproduce: - Install Attendance + Timesheets - Disable "Attendances from Backend" - Timesheet icon disappears from toolbar Current behavior: Bridge module permanently removes the `timesheet systray` from the `registry` and merges it inside the attendance dropdown. When `attendance_from_systray` is off, the dropdown hides itself and takes the timesheet icon with it, leaving no way to log hours from the toolbar. Expected behavior: Timesheet icon should remain accessible when attendance from systray is disabled. Issue: `registry.remove()` at module load made the timesheet icon impossible to restore. Fix: Keep the timesheet systray registered. Patch TimesheetSystray to read `display_systray from lazy_session` on startup and show itself standalone when attendance from systray is off. The template no longer replaces nodes. Header and total_hours are toggled via `position="attributes"` (`t-if="!props.signInOut"`, a prop only passed by the attendance dropdown), and a self-contained dropdown-only footer with the Check out button is added after total_hours. Ref: odoo/enterprise#104347 task-6285068 Forward-Port-Of: odoo/enterprise#119840
This fix prevents text formatting from being applied outside the editable area in the website builder and translation editor. As a result, changes like font size now save correctly instead of being lost after saving the page.
Original PR description
Commit e0cf601ab6fc1d7cb007fcb16ee4bb6097ba6fdd added a condition to apply format on the parent of fully selected unsplittable nodes. But this could lead to format applied outside of `contenteditable=true` nodes in some cases of website builder. This commit adds a condition to only apply format outside the unsplittable if it is not the node with `contenteditable`. Steps to reproduce: - In event page, open website builder - Double click on "Starts" in the sidebar inside the event page - Change font size - Save - Bug: the changed font size is not save (a span with the font class was created outside the savable element) ### - In translate mode - Select a whole translation span - Change font size - Save - Bug: the changed font size is not save (the font class was added on the translation span) task-6308352 Forward-Port-Of: odoo/odoo#271888 Forward-Port-Of: odoo/odoo#270401
GSTR-2B matching now correctly handles vendor bills issued in foreign currencies. This prevents bills from being incorrectly flagged as partially matched when the GST portal reports amounts in INR, improving the accuracy of GST reconciliation.
Original PR description
**Steps to reproduce:** * Install the **l10n_in_reports** module. * Go to **Accounting → Configuration → Settings**, and enable **Multi-Currencies**. * Activate a foreign currency (e.g., USD) and set…
**Steps to reproduce:** * Install the **l10n_in_reports** module. * Go to **Accounting → Configuration → Settings**, and enable **Multi-Currencies**. * Activate a foreign currency (e.g., USD) and set an exchange rate. * Create a new vendor bill for an Indian vendor, setting the currency to USD. * Add lines to the bill and apply IGST/GST taxes, then confirm the bill. * Go to **Accounting → Reporting → GST Return Period** and initiate GSTR-2B matching for the period corresponding to the bill (using a valid JSON payload where the amounts are correctly reported in INR). **Observed behavior:** * The vendor bill is incorrectly marked as "Partially matched" instead of "Fully matched", accompanied by an exception stating that the total amount as per GSTR-2B does not match. **Cause:** * The GSTR-2B data fetched from the GST portal always reports values in the company's base currency (INR). * The `match_bills` method was directly comparing the GSTR-2B INR amounts ( `bill_total` and `bill_taxable_value`) against the bill's `amount_total` and `amount_untaxed` fields. * Because these fields return values in the document's foreign currency (e.g., USD), the mismatch triggers an exception and flags the bill as partially matched. **Fix:** * Modified the matching logic to compare GSTR-2B values against `abs(amount_total_signed)` and `abs(amount_untaxed_signed)`. * This ensures that the amounts evaluated during reconciliation are always correctly converted and compared in the company's base currency (INR). opw-6311097 Forward-Port-Of: odoo/enterprise#121677 Forward-Port-Of: odoo/enterprise#120967
Neutralized databases will now use the test VIES VAT validation service instead of accidentally contacting the live production service. This reduces the risk of unintended external requests while keeping custom endpoint settings unchanged.
Original PR description
Neutralized databases don't always have demo data, so they talk to production VIES endpoint. With this change, the production endpoint is replaced with the test one. If some database has a custom endpoint, nothing is done. @moduon MT-15142 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272036
This update makes automated checks for chat window titles more precise and less likely to fail at random. It improves the reliability of tests, helping keep messaging features stable in development and on runbot.
Original PR description
The hoot `:text('X')` pseudo-class matches an element only when its whole inline text equals "X". `.o-mail-ChatWindow:text('slytherins')` therefore matched the chat window only during the brief frame where it showed nothing but its title, before the thread body (start message, composer) was rendered. Catching that frame is a race, so the assertion times out intermittently on runbot.
Assert against the title element itself: add a dedicated `o-mail-ChatWindow-name` class on it and match it with `.o-mail-ChatWindow-name:text('X')`. This is exact and no longer depends on the rest of the window being empty.
https://runbot.odoo.com/odoo/error/939914
Forward-Port-Of: odoo/odoo#272454
Forward-Port-Of: odoo/odoo#272380This fix prevents key Marketing Automation items created from templates, such as the confirmed contacts list and related server action, from disappearing during a module upgrade. It matters because users can now upgrade the app without losing template-based setup they already created.
Original PR description
When a user chooses the "Double Opt-in" template (or others using `_create_records_with_xml_ids`), the system creates records like the "Confirmed contacts" list and a server action. It also adds an…
When a user chooses the "Double Opt-in" template (or others using `_create_records_with_xml_ids`), the system creates records like the "Confirmed contacts" list and a server action. It also adds an `ir.model.data` entry for them under the module, but sets `noupdate=False`. The problem is that during a module upgrade, Odoo's cleanup process (`_process_end`) deletes any record marked `noupdate=False` if it wasn't "reloaded" from a file. Since these records are created manually in the code and aren't in any XML file, they never get reloaded, so Odoo just deletes them and the records they point to. By setting `noupdate=True` when these rows are created, we tell the system to leave them alone during upgrades. Since these only exist at runtime and don't have a data file, we don't need to worry about them being updated later anyway. The helper was added in https://github.com/odoo/enterprise/commit/fd98660e352512e0b74d91958707687978154833. Steps to reproduce: 1. Install Marketing Automation 2. Go to Campaigns > New and pick the "Double Opt-in" template, then save 3. Confirm the "Confirmed contacts" mailing list and server action exist 4. Go to Apps and Upgrade Marketing Automation 5. Try to find the mailing list and server action again => They disappear after the upgrade. Ticket [link](https://www.odoo.com/odoo/project.task/6140191) opw-6140191 Forward-Port-Of: odoo/enterprise#115444
Opening the full message composer no longer crashes when a recipient is only known by email and not linked to a contact. The system now ignores those unresolved recipients in the expanded composer, keeping the messaging flow stable and consistent with the simpler send-message flow.
Original PR description
The full composer builds default_partner_ids by doing recipient.persona.id over allRecipients. When a recipient is not linked to a partner, the chatter input inserts it with persona: false here:…
The full composer builds default_partner_ids by doing recipient.persona.id over allRecipients. When a recipient is not linked to a partner, the chatter input inserts it with persona: false here: https://github.com/odoo/odoo/blob/28c11a068b2ecf521f8ba1da271ebee24f5345ae/addons/mail/static/src/core/web/recipients_input.js#L151 false.id is undefined, so the wizard gets a bad id and clicking the recipient tag crashes with `Invalid ids list: false`. The persona is false because /mail/partner/from_email returns no partner for unresolved emails when the user does not have base.group_partner_manager. That matches the gate _prepare_post_data already uses for the simple post flow: https://github.com/odoo/odoo/blob/28c11a068b2ecf521f8ba1da271ebee24f5345ae/addons/mail/controllers/thread.py#L153,L155 The full composer just was not handling that case. Filter out persona-less recipients from default_partner_ids so the wizard only sees real partner ids. The full composer now drops them the same way the simple post path already does. Steps to reproduce: 1. As Administrator, create a user with the Sales group only (no Contact Creation). 2. Log in as that user. 3. Open a CRM lead whose Email is set but Customer is empty. 4. Click Send message. 5. Click the expand icon to open the full composer. 6. Click the recipient tag in the To field. => Recipient shows as Unnamed and clicking it raises an RPC error. Ticket [link](https://www.odoo.com/odoo/project.task/5974081) opw-5974081 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271422 Forward-Port-Of: odoo/odoo#251780
This update extends the test mock used by Clickall so it also covers the newer Odoo Fin favorite institutions endpoint. It keeps automated accounting dashboard tests fully isolated from the live production service, reducing the risk of unintended external requests during testing.
Original PR description
This commit follows up on [1] by extending the Odoo Fin request mock to cover the new version 2 (v2) favorite institutions endpoint. Previously, a mock was introduced to prevent the Clickall tool from making real external HTTP requests to `production.odoofin.com` when displaying the accounting dashboard. This update ensures that the newly introduced v2 URL is also safely intercepted, keeping the automated tests fully isolated from production servers. runbot-234936 [1] : https://github.com/odoo/odoo/commit/c6451015f1b01c3e1defe4a576989fd4bfdf2cdb Forward-Port-Of: odoo/odoo#272339
This fix prevents subcontracted receipt quantities from being overwritten when the scheduler runs. It ensures manual adjustments on these receipts are preserved, avoiding unexpected changes to incoming quantities.
Original PR description
**Issue** Quantity on subcontracted receipts could be overridden after running the scheduler. **Steps to reproduce** - Create a subcontracting product - Create a PO for 10 units of that product - Go…
**Issue** Quantity on subcontracted receipts could be overridden after running the scheduler. **Steps to reproduce** - Create a subcontracting product - Create a PO for 10 units of that product - Go to receipt and open Subcontracting Productions' - Change the quantity to 5 - Enable debug mode. - Run Inventory/Operations/Procurement: run scheduler - Return to the receipt -> The receipt quantity is reset to 10 instead of remaining at 5. **Cause** Since the refactor introduced in commit: https://github.com/odoo/odoo/commit/fc66e2d4eb638f1486e69cd5920f02c787055da1, subcontracting receipt moves are no longer automatically picked when the production quantity is modified. In particular, this test case protects that behavior: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/mrp_subcontracting/tests/test_subcontracting.py#L1629-L1631 When the scheduler runs: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/stock/models/stock_rule.py#L731 it computes the moves to assign: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/stock/models/stock_rule.py#L706-L710 However, subcontracting moves are still included in the assignment domain: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/stock/models/stock_rule.py#L680-L688 https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/mrp/models/stock_rule.py#L127-L129 As a result, they are reassigned if they are not already picked: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/stock/models/stock_move.py#L1931-L1937 opw-6229668 Forward-Port-Of: odoo/odoo#270837
This change prevents an automated test from failing when the ISO 20022 payment module is not installed. It makes the test suite more reliable across different setups without affecting normal business operations.
Original PR description
The test_batch_payment_deletion test is currently failing when `account_iso20022` is not installed because the sepa_ct payment method doesn't exists. Add a skipTest in case the module is not installed. runbot-940257
This change fixes an error that could prevent the appraisal email template from being parsed correctly. As a result, appraisal-related emails should work reliably again and avoid disruptions in sending notifications.
Original PR description
Task#6309699
This update fixes an issue where the text cursor could jump to the edge of a template block when deleting text inside an email editor. It makes editing template content feel more natural and prevents unexpected cursor movement while working on messages.
Original PR description
## Problem:
`<t>` elements are classified as self-closing, even if they aren't used that way in a mail template. If you press backspace in the editor on some plain text that happens to be inside a `<t></t>` block, the editor would prevent the cursor from being placed back inside the block after merging because of `normalizeSelfClosingElement`. The result is the cursor being left on the outside edge of the block.
## Solution:
We will remove "T" from the list of self-closing tags.
## Steps to replicate (runbot v18):
1. Open an email template (Purchase: Purchase Order)
2. Place your cursor in some text inside a t-if element ('The receipt is expected for...'). Press backspace. Your cursor will snap to the end of the t-if block.
opw-6124284
Forward-Port-Of: odoo/odoo#272285
Forward-Port-Of: odoo/odoo#266816The POS restaurant interface will now only show the Split button when bill splitting is actually enabled in the settings. This avoids confusing staff with an option that should not be available and keeps the checkout screen consistent with the configured behavior.
Original PR description
The Split button in the POS control panel was rendered whenever the restaurant module was active, without checking the `iface_splitbill` config flag. opw-6248177 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#267359 Forward-Port-Of: odoo/odoo#266654
This change ensures that when users open manufacturing orders from the statistics button, they see the correct orders. It fixes a mismatch that could otherwise show the wrong production records and confuse follow-up work.
Original PR description
* Following https://github.com/odoo/odoo/pull/261438 (forward-ported to 19.0 in #265323) we also need to show correct MOs when view from statsbutton Forward-Port-Of: odoo/odoo#265195 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#269201
This update fixes an issue where chat and thread messages could sometimes fail to appear after a reload. It improves reliability so users see the correct conversation content instead of an empty placeholder.
Original PR description
The Thread component mirrors `thread.isLoaded` into the `state.mountedAndLoaded` flag that gates whether the real messages (as opposed to the empty phantom placeholder) are rendered. The mirroring…
The Thread component mirrors `thread.isLoaded` into the `state.mountedAndLoaded` flag that gates whether the real messages (as opposed to the empty phantom placeholder) are rendered. The mirroring effect both read `mountedAndLoaded` as a dependency and wrote it. `useEffect` records its dependency array before running the body, so right after the effect sets `mountedAndLoaded` to true the recorded dependencies still hold the pre-write pair `[isLoaded=true, mountedAndLoaded=false]`; that update only settles on a later, microtask-deferred patch. When a second reload runs `reset()` in that window, it drives `mountedAndLoaded` back to false while `isLoaded` stays true. The settling patch then computes the very `[true, false]` pair that was already recorded, so the effect never re-runs: `mountedAndLoaded` is stranded at false and no message is ever rendered. Depend on a monotonic `resetCount` bumped by `reset()` instead of on `mountedAndLoaded` itself. It is never written by the effect, so the recorded dependencies can no longer match the current ones after a reset and the effect always re-runs to re-sync `mountedAndLoaded` with `isLoaded`. `reset()` keeps clearing `mountedAndLoaded` as before (the false dip is needed for the reload scroll handshake), so the behaviour is otherwise unchanged. https://runbot.odoo.com/odoo/error/940032 Forward-Port-Of: odoo/odoo#272504 Forward-Port-Of: odoo/odoo#272281
When a fixed price is set by a pricelist, the extra price badge for product variants will now be hidden in both Sales and Website. This prevents customers and sales users from seeing a price adjustment that does not actually affect the final price.
Original PR description
Issue: --- If pricelist.compute_price is fixed, extra price of variant is not taken into calculation, but it's shown in extra price badge. Steps to reproduce: --- 1- Create a product template with two variants. 2- Apply extra price for each attribute values. 3- Apply a pricing with a fixed price for the product on a pricelist. 4- Create a SO and apply the pricelist. Add the product to SOL. 5- Open product configurator on SOL. - As you see, the extra price is shown but it's not effective. 6- Open the product in website with the pricelist. - Here also the extra price is shown but it's not effective. Cause: --- This is caused because there is no mechanism to hide extra price having pricelist.compute_price == fixed. Fix: --- We need to fix the issue both in sale and website_sale separately by having a flag to ensure extra price badge is hidden if compute_price is fixed. opw-6276208 Forward-Port-Of: odoo/odoo#271572 Forward-Port-Of: odoo/odoo#270140
Documentation and clarification updates
This change adds a signed Individual Contributor License Agreement for David Sonnet. It is an administrative/legal update that confirms the contribution can be accepted into the project.
Original PR description
Signing the Odoo Individual Contributor License Agreement v1.0. Adds `doc/cla/individual/dsonnet.md`. --- I confirm I have read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270526
14 changes
Enhancements to existing features
The option to send a PDP response is no longer shown as a large on-screen button. It has been moved into the cog wheel menu, since cancelling and then posting an invoice or bill already provides the same result.
Original PR description
No real need to show a big button for sending a response in PDP as cancelling and posting an invoice/bill would do the same, so we move it to the cog wheel menu task-6274220 Forward-Port-Of: odoo/odoo#268846
Resolved issues and error corrections
This update fixes a timing issue in WhatsApp channel tests where seen-status indicators could fail to appear reliably. By waiting for the conversation to fully load before simulating the seen event, the indicators now display correctly and the test no longer times out.
Original PR description
The "Allow SeenIndicators in WhatsApp Channels" test awaited the bus subscription so the simulated seen notification is no longer dropped, but that exposed a second race between the init RPC and the bus return. openDiscuss does not await the channel data fetch (channels_as_member), whose response carries each member seen_message_id=false. When it is applied after the _sendone seen notification, it clobbers the member back to unseen, the indicators never render, and the assertion times out. Wait for the message to render before simulating the seen notification: the thread message comes from the message fetch, which only runs once the channel (with its members) is loaded, so the seen data is guaranteed applied. This mirrors the message seen indicator tests in mail. https://runbot.odoo.com/odoo/error/242021
The message composer now ignores email-only recipients that are not linked to a contact record when opening the full composer. This prevents a crash when users click those recipient tags and ensures the message form behaves consistently with the simpler send flow.
Original PR description
The full composer builds default_partner_ids by doing recipient.persona.id over allRecipients. When a recipient is not linked to a partner, the chatter input inserts it with persona: false here:…
The full composer builds default_partner_ids by doing recipient.persona.id over allRecipients. When a recipient is not linked to a partner, the chatter input inserts it with persona: false here: https://github.com/odoo/odoo/blob/28c11a068b2ecf521f8ba1da271ebee24f5345ae/addons/mail/static/src/core/web/recipients_input.js#L151 false.id is undefined, so the wizard gets a bad id and clicking the recipient tag crashes with `Invalid ids list: false`. The persona is false because /mail/partner/from_email returns no partner for unresolved emails when the user does not have base.group_partner_manager. That matches the gate _prepare_post_data already uses for the simple post flow: https://github.com/odoo/odoo/blob/28c11a068b2ecf521f8ba1da271ebee24f5345ae/addons/mail/controllers/thread.py#L153,L155 The full composer just was not handling that case. Filter out persona-less recipients from default_partner_ids so the wizard only sees real partner ids. The full composer now drops them the same way the simple post path already does. Steps to reproduce: 1. As Administrator, create a user with the Sales group only (no Contact Creation). 2. Log in as that user. 3. Open a CRM lead whose Email is set but Customer is empty. 4. Click Send message. 5. Click the expand icon to open the full composer. 6. Click the recipient tag in the To field. => Recipient shows as Unnamed and clicking it raises an RPC error. Ticket [link](https://www.odoo.com/odoo/project.task/5974081) opw-5974081 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271422 Forward-Port-Of: odoo/odoo#251780
This fix ensures that Marketing Automation templates such as Double Opt-in keep their linked records, like the confirmed contacts list and server action, after an app upgrade. It prevents these important template-generated items from disappearing, so campaigns continue to work as expected.
Original PR description
When a user chooses the "Double Opt-in" template (or others using `_create_records_with_xml_ids`), the system creates records like the "Confirmed contacts" list and a server action. It also adds an…
When a user chooses the "Double Opt-in" template (or others using `_create_records_with_xml_ids`), the system creates records like the "Confirmed contacts" list and a server action. It also adds an `ir.model.data` entry for them under the module, but sets `noupdate=False`. The problem is that during a module upgrade, Odoo's cleanup process (`_process_end`) deletes any record marked `noupdate=False` if it wasn't "reloaded" from a file. Since these records are created manually in the code and aren't in any XML file, they never get reloaded, so Odoo just deletes them and the records they point to. By setting `noupdate=True` when these rows are created, we tell the system to leave them alone during upgrades. Since these only exist at runtime and don't have a data file, we don't need to worry about them being updated later anyway. The helper was added in https://github.com/odoo/enterprise/commit/fd98660e352512e0b74d91958707687978154833. Steps to reproduce: 1. Install Marketing Automation 2. Go to Campaigns > New and pick the "Double Opt-in" template, then save 3. Confirm the "Confirmed contacts" mailing list and server action exist 4. Go to Apps and Upgrade Marketing Automation 5. Try to find the mailing list and server action again => They disappear after the upgrade. Ticket [link](https://www.odoo.com/odoo/project.task/6140191) opw-6140191 Forward-Port-Of: odoo/enterprise#115444
This fix prevents the restaurant setup from creating the same Belgian “Take out” tax and fiscal position more than once when a branch uses the POS scenario. As a result, branches can be created successfully and reuse the existing tax settings instead of failing during setup.
Original PR description
When creating a restaurant with the POS scenario on a company with the Belgian accounting package, we automatically create a new 'Take out' fiscal position and a 'Take out' 6% tax. But when creating a branch for the company and using the same scenario, it will duplicate the 'Take out' fiscal position, and then fail to create because it will try to create a duplicate Tax with the same name and then odoo will complain. After the fix the scenario checks whether the fiscal position and tax already exist on the company, and if they do, it doesn't recreate them. This should let branches use the scenario and then they can use the already existing taxes and FPs. Task [link](https://www.odoo.com/odoo/project.task/5502948) Task-5502948 Forward-Port-Of: odoo/odoo#245848
This update corrects how discounts are calculated in the point of sale sales details report when refunded items are included. It ensures refunded discounted lines no longer distort the reported discount total, making the figures more accurate for business review.
Original PR description
The sales details report computes a line discount as `original_price - price_subtotal_incl`. On a refund line the quantity is negative, so `original_price` is negative, while `price_subtotal_incl` is stored positive. Subtracting the two then inflates the discount instead of cancelling it, understating "discount_amount" by `2 * price_subtotal_incl` for every refunded discounted line. opw-6281752 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270592
We fixed an issue in Planning where searching by skill could hide employees who had the skill but no scheduled slots in the selected time period. Now those employees appear correctly in search results, making skill-based staffing searches more reliable.
Original PR description
Issue: ---------------------------------------- Doing a search on skills, the employees with the skill but no slot in the time frame aren't shown. Steps to reproduce:…
Issue:
----------------------------------------
Doing a search on skills, the employees with the skill but no slot in the time frame aren't shown.
Steps to reproduce:
----------------------------------------
- Install `planning_hr_skills`
- Make sure an employee has the skill "English" and no slots
- Open Planning and type "English" in the search bar, click to search on Skills
- The employee does not show up
Cause:
----------------------------------------
Using the search view on skills, a filter on `resource_ids` is in the domain with a `OR`:
https://github.com/odoo/enterprise/blob/5d6d16aae43ffda1532cfa4b06fdcddd7e5b0fcc/planning_hr_skills/views/planning_slot_views.xml#L9
Then a new filter on `resource_ids` is added [here](https://github.com/odoo/enterprise/blob/5d6d16aae43ffda1532cfa4b06fdcddd7e5b0fcc/planning_hr_skills/models/planning_slot.py#L14-L43) to do the search on the skill names: `[('resource_ids', 'in', matching_resource_ids)]`.
The domain is then something like this:
`['&', ('resource_ids', 'in', matching_resource_ids), '|', ('resource_ids', '=', False), ('employee_skill_ids', 'ilike', 'English')]`.
Since fbf8b2ac67c71ca0abfc75df543069696bd2d29b the resulting domain passes through `filter_map_domain()`. `filter_map_domain()` will only keep the leaves on `resource_ids` and the default `AND` will be used between them resulting in:
`['&', ('resource_ids', 'in', matching_resource_ids), ('resource_ids', '=', False)]`
which fetches no resources.
So `_group_expand_resource_ids()` doesn't expand.
Solution:
----------------------------------------
Instead of adding the new leaf to retrieve the resources with the right skills, we replace the leaf on `employee_skill_ids`. This ensures the `OR` operations are kept by `filter_map_domain()`.
opw-6296755This fix preserves more precision when calculating overtime durations, so very small time differences are not lost before pay is computed. It helps ensure overtime amounts are calculated more accurately and consistently.
Original PR description
Overtime duration computed as fractional hours was rounded to 3 decimal places before being stored on the overtime line. Since 1 decimal hour = 3600 seconds, this gives only 3.6 seconds of precision and the rounding can go in the wrong direction due to floating-point representation. The fix consists in replacing the duration rounding to 4 decimals when building overtime work entries so stored durations keep sub-second precision needed for money computation. task-6212231 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#268889
The Planning / Timesheets Analysis report now correctly counts planning slots tied to duration-based calendars. This fixes missing entries in reports, so managers get more accurate workload and timesheet analysis.
Original PR description
Issue: ---------------------------------------- The Planning / Timesheets Analysis report doesn't include most of the planning slots if they have a calendar based on duration. Steps to reproduce:…
Issue: ---------------------------------------- The Planning / Timesheets Analysis report doesn't include most of the planning slots if they have a calendar based on duration. Steps to reproduce: ---------------------------------------- - Have a 1 day planning slot (8h-17h) for an employee with a calendar based on duration. - Planning > Reporting > Planning / Timesheets Analysis - The slot is not included in the report Cause: ---------------------------------------- The update of how calendars work in saas-19.2 included the `duration_based` option but the query was not adapted. It still checks if the slot start time is lower than the calendar end time on that day: ```sql F.start_datetime < (d.date::date + (A.hour_to || ' hour')::interval) AND F.end_datetime > (d.date::date + (A.hour_from || ' hour')::interval) ``` But for duration-based calendars `hour_from` and `hour_to` are stored as `0.0`. So `F.start_datetime < (d.date::date + (A.hour_to || ' hour')::interval)` evaluates to False. Solution: ---------------------------------------- If the calendar has `duration_based` to True we only check the date. opw-6217643
The automated Clickall test now also blocks requests to the newer Odoo Fin v2 favorite institutions endpoint. This keeps test runs fully isolated from production services and reduces the risk of unwanted external calls during accounting dashboard testing.
Original PR description
This commit follows up on [1] by extending the Odoo Fin request mock to cover the new version 2 (v2) favorite institutions endpoint. Previously, a mock was introduced to prevent the Clickall tool from making real external HTTP requests to `production.odoofin.com` when displaying the accounting dashboard. This update ensures that the newly introduced v2 URL is also safely intercepted, keeping the automated tests fully isolated from production servers. runbot-234936 [1] : https://github.com/odoo/odoo/commit/c6451015f1b01c3e1defe4a576989fd4bfdf2cdb Forward-Port-Of: odoo/odoo#272339
This change improves how overtime hours are stored so they keep enough precision for payroll calculations. It prevents small rounding errors from affecting the amount paid to employees.
Original PR description
Overtime duration computed as fractional hours was rounded to 3 decimal places before being stored on the overtime line. Since 1 decimal hour = 3600 seconds, this gives only 3.6 seconds of precision and the rounding can go in the wrong direction due to floating-point representation. The fix consists in replacing the duration rounding to 4 decimals when building overtime work entries so stored durations keep sub-second precision needed for money computation. task-6212231 Forward-Port-Of: odoo/enterprise#119721
This fix prevents the system scheduler from automatically reassigning subcontracting receipt moves. As a result, when users manually adjust the receipt quantity, it will stay as entered instead of being reset later, avoiding incorrect receipt quantities in subcontracting workflows.
Original PR description
**Issue** Quantity on subcontracted receipts could be overridden after running the scheduler. **Steps to reproduce** - Create a subcontracting product - Create a PO for 10 units of that product - Go…
**Issue** Quantity on subcontracted receipts could be overridden after running the scheduler. **Steps to reproduce** - Create a subcontracting product - Create a PO for 10 units of that product - Go to receipt and open Subcontracting Productions' - Change the quantity to 5 - Enable debug mode. - Run Inventory/Operations/Procurement: run scheduler - Return to the receipt -> The receipt quantity is reset to 10 instead of remaining at 5. **Cause** Since the refactor introduced in commit: https://github.com/odoo/odoo/commit/fc66e2d4eb638f1486e69cd5920f02c787055da1, subcontracting receipt moves are no longer automatically picked when the production quantity is modified. In particular, this test case protects that behavior: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/mrp_subcontracting/tests/test_subcontracting.py#L1629-L1631 When the scheduler runs: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/stock/models/stock_rule.py#L731 it computes the moves to assign: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/stock/models/stock_rule.py#L706-L710 However, subcontracting moves are still included in the assignment domain: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/stock/models/stock_rule.py#L680-L688 https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/mrp/models/stock_rule.py#L127-L129 As a result, they are reassigned if they are not already picked: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/stock/models/stock_move.py#L1931-L1937 opw-6229668 Forward-Port-Of: odoo/odoo#270837
This update stops command shortcuts and auto-formatting from working inside code blocks. It helps users keep code text unchanged and avoids errors when editing code content.
Original PR description
### Steps to reproduce: - Go to ToDo. - Create a code block using `/code`. - Place the cursor inside the code block. - Type `/table` and select the table command. - A traceback occurs. ### Purpose of this PR: - Commands and markdown shorthands should not be available inside code blocks. However, typing `/` inside a `<pre>` opened the command palette, allowing structural commands such as `/table` to be executed and causing a traceback. Similarly, markdown shorthands such as `* ` and `1.` were still active, unexpectedly transforming code content into lists. ### This PR fixes the issue by: - Disabling the command palette when the cursor is inside a `<pre>` element. - Disabling markdown shorthands inside `<pre>` elements by registering an `are_shorthand_available_predicates` predicate. task-6292231 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271796 Forward-Port-Of: odoo/odoo#269430
This fix ensures that when users open manufacturing order statistics, they are shown the correct set of manufacturing orders. It prevents confusion caused by seeing the wrong records, making it easier to review production activity accurately.
Original PR description
* Following https://github.com/odoo/odoo/pull/261438 (forward-ported to 19.0 in #265323) we also need to show correct MOs when view from statsbutton Forward-Port-Of: odoo/odoo#265195 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#269201
17 changes
Enhancements to existing features
The action for sending a PDP response is no longer shown as a prominent button. It has been moved into the cog wheel menu, since users can achieve the same result through the existing cancel and post workflow for invoices and bills.
Original PR description
No real need to show a big button for sending a response in PDP as cancelling and posting an invoice/bill would do the same, so we move it to the cog wheel menu task-6274220 Forward-Port-Of: odoo/odoo#268846
Resolved issues and error corrections
This fix stops the Belgian POS restaurant setup from creating the same “Take out” tax and fiscal position more than once when a branch is created. It allows branches to reuse the existing settings instead of failing during setup, making restaurant rollout smoother for companies with multiple locations.
Original PR description
When creating a restaurant with the POS scenario on a company with the Belgian accounting package, we automatically create a new 'Take out' fiscal position and a 'Take out' 6% tax. But when creating a branch for the company and using the same scenario, it will duplicate the 'Take out' fiscal position, and then fail to create because it will try to create a duplicate Tax with the same name and then odoo will complain. After the fix the scenario checks whether the fiscal position and tax already exist on the company, and if they do, it doesn't recreate them. This should let branches use the scenario and then they can use the already existing taxes and FPs. Task [link](https://www.odoo.com/odoo/project.task/5502948) Task-5502948 Forward-Port-Of: odoo/odoo#245848
The page builder now correctly hides the column count option again when the related style is used. This restores the expected editing behavior after a refactoring broke it, helping keep layout settings consistent for content editors.
Original PR description
The class 's_nb_column_fixed' was used to hide the column count option, but it got lost during the refactoring and doesn't work since 18.4. This commit restores it. task-6234267 Forward-Port-Of: odoo/odoo#268005
This change makes the public discussion tour more reliable by ensuring the attachment menu closes before a message is sent. It also corrects a test setup issue so the right conversation is updated between test runs, helping prevent flaky failures and improving confidence in messaging features.
Original PR description
Attempt at fixing the following race condition. It's not clear what causes it, but these changes make the test more robust and might help future investigations. discuss_channel_public_tour opens the composer "More Actions" menu to attach files but feeds the hidden file input directly, so the menu is never closed and is still open when Send is clicked. Close it and wait for it to disappear before sending, to avoid clicking Send while the dropdown is dismissing. Also fix _open_group_page_as_user, which updated the last message body of self.channel instead of self.group between the two tour runs. https://runbot.odoo.com/odoo/error/243436 Forward-Port-Of: odoo/odoo#272425
Images placed into device-shaped frames now keep the frame’s proportions instead of being forced into a square crop first. This makes tall or wide images fit more naturally and avoids unnecessary trimming, improving the final visual result for users.
Original PR description
Scenario: - insert image with ~ 1:2 ratio (height bigger than width) - set shape "iPhone `#2`" to that image Result: the image should fit without much cropping the 0.46:1 aspect ratio of the shape, but it is cropped 1:1 before being applied to it. Cause: when the image has a set aspect ratio, we are always cropping it to 1:1 aspect ratio in postProcessCroppedCanvas but it should be cropped to the shape aspect ratio as it was done in previous version. Fix: go back to what was done in saas-18.3 and apply the shape aspect ratio and not just square (1:1) aspect ratio. opw-5415137 Forward-Port-Of: odoo/odoo#250922
This fix prevents records created by Marketing Automation templates, such as the “Confirmed contacts” list and related actions, from being deleted during module upgrades. As a result, users who set up a template can upgrade the app without losing these campaign components.
Original PR description
When a user chooses the "Double Opt-in" template (or others using `_create_records_with_xml_ids`), the system creates records like the "Confirmed contacts" list and a server action. It also adds an…
When a user chooses the "Double Opt-in" template (or others using `_create_records_with_xml_ids`), the system creates records like the "Confirmed contacts" list and a server action. It also adds an `ir.model.data` entry for them under the module, but sets `noupdate=False`. The problem is that during a module upgrade, Odoo's cleanup process (`_process_end`) deletes any record marked `noupdate=False` if it wasn't "reloaded" from a file. Since these records are created manually in the code and aren't in any XML file, they never get reloaded, so Odoo just deletes them and the records they point to. By setting `noupdate=True` when these rows are created, we tell the system to leave them alone during upgrades. Since these only exist at runtime and don't have a data file, we don't need to worry about them being updated later anyway. The helper was added in https://github.com/odoo/enterprise/commit/fd98660e352512e0b74d91958707687978154833. Steps to reproduce: 1. Install Marketing Automation 2. Go to Campaigns > New and pick the "Double Opt-in" template, then save 3. Confirm the "Confirmed contacts" mailing list and server action exist 4. Go to Apps and Upgrade Marketing Automation 5. Try to find the mailing list and server action again => They disappear after the upgrade. Ticket [link](https://www.odoo.com/odoo/project.task/6140191) opw-6140191 Forward-Port-Of: odoo/enterprise#115444
The GIF integration in chat now uses Klipy instead of Tenor for its API key. This change is needed to keep GIF search working, since the old Tenor key will no longer be valid for the new service and Tenor itself is being phased out.
Original PR description
Tenor API will be terminated on June 30, 2026: https://developers.google.com/tenor/guides/quickstart This commit makes the Tenor API key input settings use a Klipy GIF API key instead of a Tenor GIF API key. To keep GIF working after this commit, the API key must necessarily be changed to a Klipy GIF API key, as the old Tenor API key would be considered as an invalid Klipy API key. Task-5491965 Upgrade: https://github.com/odoo/upgrade/pull/10516 Forward-Port-Of: odoo/odoo#272493 Forward-Port-Of: odoo/odoo#250113
The Planning app now calculates weekly hours using the actual first day of the week set in the system, instead of always relying on the locale default. This prevents employees with flexible schedules from showing more hours than their calendar allows when the week starts on a different day.
Original PR description
**Steps to reproduce** - Install planning - Switch to English (UK) and change the "First day of the week" to Sunday in the technical settings - Have an employee with a flexible schedule with a total of 40h/week, average 8h/day - In the planning app, after creating a shift to display the employee in the gantt view, notice that when hovering over the progress bar on the left, 48 worked hours are expected for the current week, which is more than what is defined in the employee's calendar **Cause** The displayed week, starting on Sunday, could accumulate more hours than the weekly cap due to the Sunday being part of another week with the locale default first day (Monday). opw-6110395 Forward-Port-Of: odoo/odoo#259600
This update extends the automated test mock so it also covers the new Odoo Fin v2 favorites institutions endpoint. It helps keep tests fully isolated from production services, reducing the risk of unwanted external requests during dashboard testing.
Original PR description
This commit follows up on [1] by extending the Odoo Fin request mock to cover the new version 2 (v2) favorite institutions endpoint. Previously, a mock was introduced to prevent the Clickall tool from making real external HTTP requests to `production.odoofin.com` when displaying the accounting dashboard. This update ensures that the newly introduced v2 URL is also safely intercepted, keeping the automated tests fully isolated from production servers. runbot-234936 [1] : https://github.com/odoo/odoo/commit/c6451015f1b01c3e1defe4a576989fd4bfdf2cdb Forward-Port-Of: odoo/odoo#272339
This fix ensures subcontracted receipt quantities stay as manually adjusted, even after the inventory scheduler runs. It prevents the system from overwriting user changes and helps keep purchase and receipt quantities aligned with what was intended.
Original PR description
**Issue** Quantity on subcontracted receipts could be overridden after running the scheduler. **Steps to reproduce** - Create a subcontracting product - Create a PO for 10 units of that product - Go…
**Issue** Quantity on subcontracted receipts could be overridden after running the scheduler. **Steps to reproduce** - Create a subcontracting product - Create a PO for 10 units of that product - Go to receipt and open Subcontracting Productions' - Change the quantity to 5 - Enable debug mode. - Run Inventory/Operations/Procurement: run scheduler - Return to the receipt -> The receipt quantity is reset to 10 instead of remaining at 5. **Cause** Since the refactor introduced in commit: https://github.com/odoo/odoo/commit/fc66e2d4eb638f1486e69cd5920f02c787055da1, subcontracting receipt moves are no longer automatically picked when the production quantity is modified. In particular, this test case protects that behavior: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/mrp_subcontracting/tests/test_subcontracting.py#L1629-L1631 When the scheduler runs: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/stock/models/stock_rule.py#L731 it computes the moves to assign: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/stock/models/stock_rule.py#L706-L710 However, subcontracting moves are still included in the assignment domain: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/stock/models/stock_rule.py#L680-L688 https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/mrp/models/stock_rule.py#L127-L129 As a result, they are reassigned if they are not already picked: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/stock/models/stock_move.py#L1931-L1937 opw-6229668 Forward-Port-Of: odoo/odoo#270837
Opening the full message composer could fail when a recipient was identified only by email and not linked to a contact. This fix ignores those incomplete recipients so the composer opens normally and users can continue sending messages without errors.
Original PR description
The full composer builds default_partner_ids by doing recipient.persona.id over allRecipients. When a recipient is not linked to a partner, the chatter input inserts it with persona: false here:…
The full composer builds default_partner_ids by doing recipient.persona.id over allRecipients. When a recipient is not linked to a partner, the chatter input inserts it with persona: false here: https://github.com/odoo/odoo/blob/28c11a068b2ecf521f8ba1da271ebee24f5345ae/addons/mail/static/src/core/web/recipients_input.js#L151 false.id is undefined, so the wizard gets a bad id and clicking the recipient tag crashes with `Invalid ids list: false`. The persona is false because /mail/partner/from_email returns no partner for unresolved emails when the user does not have base.group_partner_manager. That matches the gate _prepare_post_data already uses for the simple post flow: https://github.com/odoo/odoo/blob/28c11a068b2ecf521f8ba1da271ebee24f5345ae/addons/mail/controllers/thread.py#L153,L155 The full composer just was not handling that case. Filter out persona-less recipients from default_partner_ids so the wizard only sees real partner ids. The full composer now drops them the same way the simple post path already does. Steps to reproduce: 1. As Administrator, create a user with the Sales group only (no Contact Creation). 2. Log in as that user. 3. Open a CRM lead whose Email is set but Customer is empty. 4. Click Send message. 5. Click the expand icon to open the full composer. 6. Click the recipient tag in the To field. => Recipient shows as Unnamed and clicking it raises an RPC error. Ticket [link](https://www.odoo.com/odoo/project.task/5974081) opw-5974081 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271422 Forward-Port-Of: odoo/odoo#251780
This fix ensures users see the right manufacturing orders when opening them from the statistics button. It prevents confusion by making the displayed records match the actual manufactured orders linked to the product.
Original PR description
* Following https://github.com/odoo/odoo/pull/261438 (forward-ported to 19.0 in #265323) we also need to show correct MOs when view from statsbutton Forward-Port-Of: odoo/odoo#265195 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#269201
This change prevents the point of sale from crashing when Adyen sends the same payment notification more than once. It makes the payment flow more resilient, so customers can complete card payments without unexpected errors caused by duplicate messages.
Original PR description
The following error is raised in the POS when paying with an Adyen terminal: ``` TypeError: Cannot read properties of undefined (reading 'uuid') at Proxy.handleAdyenStatusResponse ``` Adyen delivers…
The following error is raised in the POS when paying with an Adyen terminal: ``` TypeError: Cannot read properties of undefined (reading 'uuid') at Proxy.handleAdyenStatusResponse ``` Adyen delivers webhook notifications at-least-once, so the ADYEN_LATEST_RESPONSE event can fire several times for a single payment, running handleAdyenStatusResponse concurrently. After the await on get_latest_adyen_status, a previous (duplicate) notification may already have resolved the payment line, so getPendingPaymentLine no longer returns it and the subsequent line.uuid dereference crashes. opw-6237987 patched the same root cause on a single line by adding an optional chaining operator in isPaymentSuccessful, which only moved the crash to the next dereference. Fetch the pending line once at the start of handleAdyenStatusResponse and bail out when it is gone, so every dereference below is safe. The same guard is added to the remaining branches of _adyen_handle_response for consistency with the existing Reject branch. opw-6237987 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270880 Forward-Port-Of: odoo/odoo#269720
Shop Floor now correctly places manufacturing orders without a planned start date after those that are already scheduled. This makes the order shown in Shop Floor match the usual work order prioritization and avoids confusing list behavior for operators.
Original PR description
## Problem In shop floor, MOs with unplanned work orders get sorted before MOs that have planned operations, which contradicts the normal nulls last sorting for work orders. ## Solution We will…
## Problem In shop floor, MOs with unplanned work orders get sorted before MOs that have planned operations, which contradicts the normal nulls last sorting for work orders. ## Solution We will update the sorting logic in the MrpDisplay component to more gracefully handle falsy date_start values, sorting them to the end. ## Steps to reproduce (runbot 19) 1. Create 2 MOs with an operation (work order) involving a work center, we'll call them A and B. 2. Open Shop Floor and open the work center that the MOs' work orders belong to, and note they are ordered A, B (this is fine, neither are planned so the precedence falls back to id 3. Go back to MO B and plan it. This should give it precedence in Shop Floor 4. Under the work center in Shop Floor, note that the MOs are still ordered A, B, despite B's work order having a start date and A's work order not having one To further motivate this being unintended, you can go to Manufacturing > Operations > Work Orders, and you'll see MO B's work order sitting at the top of the list. opw-6303323 Forward-Port-Of: odoo/enterprise#121693
This update corrects a timing issue in planning where shifts on 24/7 schedules could be shown as one minute longer than they really were. As a result, allocated time in reports now matches the planned shift length, improving accuracy for customers relying on planning data.
Original PR description
**Problem:** On a round-the-clock (0h-24h) working schedule, shifts created from a shift template that spans more than one day get one extra minute added to their allocated time: an 8-hour shift…
**Problem:** On a round-the-clock (0h-24h) working schedule, shifts created from a shift template that spans more than one day get one extra minute added to their allocated time: an 8-hour shift shows 08:01. **Steps to reproduce:** 1. Create a working schedule with a 00:00 -> 24:00 attendance for every day (24h/day, "Full Day"). 2. Assign an employee to that schedule. 3. Create a multi-day-span shift template (e.g. 16:00 -> 00:00, 2 days). 4. Plan a shift for that employee using the template. 5. Observe the Allocated Time shows one minute more than expected (08:01). **Current behavior:** Allocated Time is one minute too long (e.g. 08:01 instead of 08:00), which throws off the customer's planning reports. **Expected behavior:** Allocated Time matches the template duration exactly (08:00). **Cause of the issue:** In `_calculate_start_end_dates`, the end of a multi-day-span shift is computed with `resource.calendar_id.plan_days(...)`. On a 0h-24h calendar each day ends at `time.max` (23:59:59.999999), so `plan_days` returns an end datetime carrying those stale seconds. The following `end.replace(hour=..., minute=...)` overwrites only the hour and minute, leaving `second=59, microsecond=999999`. The slot is therefore ~1 minute longer than intended, and `allocated_hours` rounds that up to 08:01. **Fix:** Resetting seconds and microseconds when rebuilding the end datetime keeps the slot aligned to the template's whole-minute boundary, regardless of how the underlying calendar represents the end of day. The hour/minute already come from the template, so the leftover sub-minute precision from `plan_days` is never meaningful and is what produces the drift. opw-6265238 Forward-Port-Of: odoo/enterprise#120219
### Steps to reproduce: - Download Calendar and Contacts app - Go to the Setting -> Companies -> Manage companies; make sure there are at least two companies - Go to the Setting -> Users -> Manage users; make sure the current logged-in user has access to both companies - Create a another user who also have access to both companies - Search for the new user in contacts -> Assign the current company to the contact -> Through the internal link of the company, go to sales and purchase tab -> as
Original PR description
### Steps to reproduce: - Download Calendar and Contacts app - Go to the Setting -> Companies -> Manage companies; make sure there are at least two companies - Go to the Setting -> Users -> Manage…
### Steps to reproduce: - Download Calendar and Contacts app - Go to the Setting -> Companies -> Manage companies; make sure there are at least two companies - Go to the Setting -> Users -> Manage users; make sure the current logged-in user has access to both companies - Create a another user who also have access to both companies - Search for the new user in contacts -> Assign the current company to the contact -> Through the internal link of the company, go to sales and purchase tab -> assign the same company in the company field - Switch the company of the logged in user to the other company - Open the test contact form, use the meeting smart button and create a new meeting - Open the kanban contact view **> Access Error: Uh-oh! Looks like you have stumbled upon some top-secret records.** ### Cause of Issue: When trying to view the search results in kanban view, the `meeting_count` is calculated for each contact. Hence,`_compute_meeting_count()` is called which calls `_compute_meeting()`. https://github.com/odoo/odoo/blob/f39785bcddd1eb5b7fb503d053c9bb66e2a0f15c/addons/calendar/models/res_partner.py#L49-L54 Since the above section tries to access `partner.parent_id` each loop, it reaches a `parent_id` that's not accessible for the current user. ### Fix: Since we need to access `parent_id` to be able to calculate meeting count for the full tree of partners, `sudo()` is used to get all partners, but meetings are computed for ancestors who are in `self_ids` only so that we still remain within scope. Same old logic is used to propagate meetings for every ancestor, but dictionary lookups are used to enhance performance. opw-5874204 Forward-Port-Of: odoo/odoo#248985
Remove useless assignation of state from frontend in `_check_pos_order` because its overrided just after in the process. Forward-Port-Of: odoo/odoo#272176
Original PR description
Remove useless assignation of state from frontend in `_check_pos_order` because its overrided just after in the process. Forward-Port-Of: odoo/odoo#272176
4 changes
Resolved issues and error corrections
This fix prevents Kenya PoS combo products from being treated as items that must be registered with eTIMS. As a result, customers can sell combos normally without validation warnings or blocked payments, while only the actual products inside the combo are sent for compliance.
Original PR description
Steps to reproduce ------------------ 1. Install l10n_ke_edi_oscu_pos. 2. Select the Kenyan company. 3. Enable eTIMS on the PoS. 4. Register the products inside a combo, but not the combo itself. 5.…
Steps to reproduce ------------------ 1. Install l10n_ke_edi_oscu_pos. 2. Select the Kenyan company. 3. Enable eTIMS on the PoS. 4. Register the products inside a combo, but not the combo itself. 5. Sell the combo in the PoS. Observation ----------- We see a warning that the combo must be registered to eTIMS, and the order can't be validated. What's happening ---------------- In the PoS a combo adds a 0 price parent line for the combo product, but the combo is not a real item to send to eTIMS, only the products inside it are, and (as per step 4) the combo is not registered. `checkEtimsFields` sees the combo as not registered, so it raises the warning in `showUnregisteredProductsWarning` and blocks the payment in `validateOrder`. Fix --- In the backend, we skip sending the parent combo line to eTIMS, and on the frontend, we make the combo parent line not need eTIMS registration, so the warning and the block don't apply to it. Note ---- Pushing onto `tax_ids` in the order widget makes the Kenyan receipt crash with "The 'tax_ids' array cannot be modified. Use the update method instead.", so we assign the taxes instead of pushing them. opw-6253306 Forward-Port-Of: odoo/enterprise#121831 Forward-Port-Of: odoo/enterprise#119362
Fixed an issue where records created by marketing automation templates, such as the confirmed contacts list and related server action, could disappear after upgrading the module. This ensures campaigns keep working normally after upgrades and prevents users from losing important automation setup.
Original PR description
When a user chooses the "Double Opt-in" template (or others using `_create_records_with_xml_ids`), the system creates records like the "Confirmed contacts" list and a server action. It also adds an…
When a user chooses the "Double Opt-in" template (or others using `_create_records_with_xml_ids`), the system creates records like the "Confirmed contacts" list and a server action. It also adds an `ir.model.data` entry for them under the module, but sets `noupdate=False`. The problem is that during a module upgrade, Odoo's cleanup process (`_process_end`) deletes any record marked `noupdate=False` if it wasn't "reloaded" from a file. Since these records are created manually in the code and aren't in any XML file, they never get reloaded, so Odoo just deletes them and the records they point to. By setting `noupdate=True` when these rows are created, we tell the system to leave them alone during upgrades. Since these only exist at runtime and don't have a data file, we don't need to worry about them being updated later anyway. The helper was added in https://github.com/odoo/enterprise/commit/fd98660e352512e0b74d91958707687978154833. Steps to reproduce: 1. Install Marketing Automation 2. Go to Campaigns > New and pick the "Double Opt-in" template, then save 3. Confirm the "Confirmed contacts" mailing list and server action exist 4. Go to Apps and Upgrade Marketing Automation 5. Try to find the mailing list and server action again => They disappear after the upgrade. Ticket [link](https://www.odoo.com/odoo/project.task/6140191) opw-6140191 Forward-Port-Of: odoo/enterprise#115444
This fix prevents a permissions error that could appear when a user with limited sales access updates a manufacturing order linked to a rental sale. It ensures the system can complete the update without trying to read sales data the user is not allowed to access, avoiding a blocked workflow.
Original PR description
### Steps to reproduce: - Ensure `sale_stock_renting` is installed - Enable Multi-Steps Routes > Unarchive MTO - Create a product P with a BoM and the routes MTO + manufacture - Create anc confirm a…
### Steps to reproduce: - Ensure `sale_stock_renting` is installed - Enable Multi-Steps Routes > Unarchive MTO - Create a product P with a BoM and the routes MTO + manufacture - Create anc confirm a sale order for A unit of P - Log in with an other user with with mrp User rights and sales User: Own Documents Only (he should not have access to the SO) - Open the MO, add a component line and save #### > Access Error: Blame the following rule: - Personal Order ### Cause of the issue: Writing on the `move_raw_ids` will trigger a call of the `_autoconfirm_production` in order to confirm the newly created move: https://github.com/odoo/odoo/blob/e447f4849056a0aab35966fb6ba595ebaadb79ab/addons/mrp/models/mrp_production.py#L990-L991 https://github.com/odoo/odoo/blob/e447f4849056a0aab35966fb6ba595ebaadb79ab/addons/mrp/models/mrp_production.py#L1422-L1423 During this confirmation process, one calls the `_merge_moves` method in order to merge this new move (if relevant) to any already existing one. https://github.com/odoo/odoo/blob/e447f4849056a0aab35966fb6ba595ebaadb79ab/addons/stock/models/stock_move.py#L1575-L1576 Now, the issue is that, `sale_stock_renting` module overrides the method `_prepare_merge_moves_distinct_fields` determining the fields relevant to the merge by requiring a read access to the `is_rental_order` compute field of the `sale_order` linked to the MO: https://github.com/odoo/enterprise/blob/b66097122ba3a758734ac6fb2b26579c35cb72c2/sale_stock_renting/models/stock_move.py#L34-L40 However, due to the 'Personal Orders' ir.rule, the user does not have a read access to this record: https://github.com/odoo/odoo/blob/e447f4849056a0aab35966fb6ba595ebaadb79ab/addons/sale/security/ir_rules.xml#L44-L49 Community: https://github.com/odoo/odoo/pull/271017 opw-6275658 Forward-Port-Of: odoo/enterprise#121510 Forward-Port-Of: odoo/enterprise#121135
The GSTR-1 export now uses the company currency (INR) for the Invoice Value of SEZ invoices, even when the invoice was originally issued in a foreign currency. This avoids confusing mismatches in the tax return spreadsheet and helps ensure the report matches the required filing currency.
Original PR description
Currently, when generatign GSTR-1 return spreadshee, SEZ invoices issued in a foreign currency are exported with their totals in the foreign currency rather than the company currency (INR) Steps to reproduce: - Create a B2B SEZ invoice in foreign currency - Go to Accounting > Reporting > [India] GST Return periods - Generate the GSTR-1 report for the period Issue: In the resulting spreadsheet, the "Invoice Value" column takes the invoice total in USD rather then INR opw-6292913 Forward-Port-Of: odoo/enterprise#121864 Forward-Port-Of: odoo/enterprise#121157
5 changes
Resolved issues and error corrections
Swiss invoices now generate a payment reference even when the customer is outside Switzerland or Liechtenstein. This ensures the invoice PDF and payment details stay visible, making it easier for customers to pay correctly.
Original PR description
Issue: When an invoice (sales journal) uses "Switzerland" localization and the invoice is issued to a customer outside Switzerland/Liechtenstein, no payment reference is generated. This causes the…
Issue: When an invoice (sales journal) uses "Switzerland" localization and the invoice is issued to a customer outside Switzerland/Liechtenstein, no payment reference is generated. This causes the invoice PDF to hide payment communication and bank account details. Other localizations like Belgian companies, uses Belgian references, the reference is always generated regardless of customer country. Steps to reproduce: - Configure a Swiss company with a QR IBAN bank account - Set the sales journal Communication Standard to Switzerland - Create and confirm an invoice for a non swiss customer (US, BE) - Observe in the pdf and in the other info tab -> no payment reference or payment details Cause: `get_l10n_ch_qrr_number()` was using on `l10n_ch_is_qr_valid()`, which conflicts QR-bill printability (partner country, currency) with payment reference generation. When the customer is outside CH/LI, `l10n_ch_is_qr_valid()` is False and no QRR reference is generated. Solution: Decouple QRR reference generation from QR bill printability. The Swiss communication standard now generates a QRR format reference when a QR-IBAN is configured, regardless of customer's country or currency. opw-6222417 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#266861
This update corrects how Odoo updates payment statuses when a reconciled bank statement is reversed. Grouped payments are now properly moved back to "In Process" along with other payments, so users can reconcile the statement again without inconsistent values or errors.
Original PR description
**Steps to reproduce:** - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A *…
**Steps to reproduce:** - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A * Total; 10.00 - Confirm the invoice - From the invoice list, select both invoice - Create payment: * Journal: Bank * Group Payments: [checked] * Amount: 40.00 - Create a third invoice for another customer: * Customer: Partner B * Total: 25.00 - Confirm the invoice - Register payment from the invoice - Create a fourth invoice for another customer: * Customer: Partner C * Total; 40.00 - Confirm the invoice - Register payment from the invoice - From the payment list, select all 3 payments and create batch payment - Validate the batch payment - From Accounting dashboard, open Bank journal - Create a new bank statement line of 105.00 - Match it with the batch payment At that point, the statement line is reconciled with the 4 invoices and the 3 payments are marked as paid. - Go to the fourth invoice - Reset it to draft - Change the price - Save When the amount of the invoice is changed, the statement line is unreconciled and all the payments should change state from "Paid" to "In Process". **Issue:** All the single payments have their state correctly changed to "In Process", except for the group payment for the 2 first invoices, which leads to undesired values when trying to reconcile the statement line with the batch payment again. **Cause:** When the statement is unreconciled, all the partial reconcile records are deleted and the state of the linked payments are updated to "In Process". The payments are retrieved by checking if there are linked to an account move present in the partial reconcile record and if the amount of the payment matches the amount of the partial reconcile record. In case of a group payment, there are 2 partial reconcile records for each invoice linked to the payment. Therefore, in that case, the amount doesn't match the amount of the payment because it matches the amount of one of the invoice. opw-6141089 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#269510
This change corrects how grouped customer payments are handled when a bank statement is later unreconciled. It ensures all related payments move back to the proper intermediate status, so the statement can be reconciled again without errors or inconsistent payment values.
Original PR description
**Steps to reproduce:** - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A *…
**Steps to reproduce:** - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A * Total; 10.00 - Confirm the invoice - From the invoice list, select both invoice - Create payment: * Journal: Bank * Group Payments: [checked] * Group Payments: [checked] * Amount: 40.00 - Create a third invoice for another customer: * Customer: Partner B * Total: 25.00 - Confirm the invoice - Register payment from the invoice - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A * Total; 10.00 - Confirm the invoice - From the invoice list, select both invoice - Create payment: * Journal: Bank * Group Payments: [checked] * Amount: 40.00 - Create a third invoice for another customer: * Customer: Partner B * Total: 25.00 - Confirm the invoice - Register payment from the invoice - Create a fourth invoice for another customer: * Customer: Partner C * Total; 40.00 - Confirm the invoice - Register payment from the invoice - From the payment list, select all 3 payments and create batch payment - Validate the batch payment - From Accounting dashboard, open Bank journal - Create a new bank statement line of 105.00 - Match it with the batch payment At that point, the statement line is reconciled with the 4 invoices and the 3 payments are marked as paid. - Go to the fourth invoice - Reset it to draft - Change the price - Save When the amount of the invoice is changed, the statement line is unreconciled and all the payments should change state from "Paid" to "In Process". **Issue:** All the single payments have their state correctly changed to "In Process", except for the group payment for the 2 first invoices, which leads to undesired values when trying to reconcile the statement line with the batch payment again. **Cause:** When the statement is unreconciled, all the partial reconcile records are deleted and the state of the linked payments are updated to "In Process". The payments are retrieved by checking if there are linked to an account move present in the partial reconcile record and if the amount of the payment matches the amount of the partial reconcile record. In case of a group payment, there are 2 partial reconcile records for each invoice linked to the payment. Therefore, in that case, the amount doesn't match the amount of the payment because it matches the amount of one of the invoice. opw-6141089 Forward-Port-Of: odoo/enterprise#120210
Neutralized databases will now use Odoo’s test VIES service instead of the live production endpoint by default. This helps prevent unintended requests to the real VAT validation service while keeping databases with custom settings unchanged.
Original PR description
Neutralized databases don't always have demo data, so they talk to production VIES endpoint. With this change, the production endpoint is replaced with the test one. If some database has a custom endpoint, nothing is done. @moduon MT-15142 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272036
Mailing campaign emails that bounce will now correctly increase the contact’s bounce count. This fixes cases where bounce notifications came from a different sender address, which previously caused the system to miss the bounce and undercount it.
Original PR description
Previously, when a mailing campaign sent out an email to a mailing.contact, and that email bounced, the bounce would not increment the contact's bounce count. This commit makes it so that the bounce count is correctly updated when a mailing campaign sends an email that bounces. task-4893615 Forward-Port-Of: odoo/odoo#226362
1 change
Resolved issues and error corrections
Records created when using Marketing Automation templates, such as the Double Opt-in mailing list and server action, will now remain available after a module upgrade. This prevents users from losing important campaign setup items during routine updates.
Original PR description
When a user chooses the "Double Opt-in" template (or others using `_create_records_with_xml_ids`), the system creates records like the "Confirmed contacts" list and a server action. It also adds an…
When a user chooses the "Double Opt-in" template (or others using `_create_records_with_xml_ids`), the system creates records like the "Confirmed contacts" list and a server action. It also adds an `ir.model.data` entry for them under the module, but sets `noupdate=False`. The problem is that during a module upgrade, Odoo's cleanup process (`_process_end`) deletes any record marked `noupdate=False` if it wasn't "reloaded" from a file. Since these records are created manually in the code and aren't in any XML file, they never get reloaded, so Odoo just deletes them and the records they point to. By setting `noupdate=True` when these rows are created, we tell the system to leave them alone during upgrades. Since these only exist at runtime and don't have a data file, we don't need to worry about them being updated later anyway. The helper was added in https://github.com/odoo/enterprise/commit/fd98660e352512e0b74d91958707687978154833. Steps to reproduce: 1. Install Marketing Automation 2. Go to Campaigns > New and pick the "Double Opt-in" template, then save 3. Confirm the "Confirmed contacts" mailing list and server action exist 4. Go to Apps and Upgrade Marketing Automation 5. Try to find the mailing list and server action again => They disappear after the upgrade. Ticket [link](https://www.odoo.com/odoo/project.task/6140191) opw-6140191 Forward-Port-Of: odoo/enterprise#115444
8 changes
New functionality added to Odoo
This update adds the 281.18 and 274.18 payroll reports for Belgium. It helps correctly handle withholding tax reporting linked to specific special leave situations, improving compliance and payroll accuracy.
Enhancements to existing features
The website generator now links categories to products using unique IDs instead of category names. This avoids mistakes when different categories share the same name, making product assignment more accurate and dependable.
Original PR description
Before we matched categories with products but names but this was less reliable in the case that we had multiple categories with the same name. e.g. Accessories (for men) and Accessories (for women). This new method allows for this and makes the matching more reliable.
This update makes payroll setup easier for new Indonesian companies by automatically assigning the correct accounting accounts to salary rules. It also combines two duplicate BPJS Kesehatan rules into one set of rules without changing the calculated amounts, which helps keep payroll configuration simpler and more consistent.
Original PR description
Configure the default debit/credit accounts for the Indonesian salary rules so new ID companies get correct payroll journal entries out of the box. We also merge the BPJS Kesehatan allowance and deduction rules that were split by payroll type despite identical logic. The kept rules now apply to both gross and gross_up, leaving amounts unchanged. Community PR: https://github.com/odoo/odoo/pull/271991 Upgrade PR: https://github.com/odoo/upgrade/pull/10620 task-6316791
The Belgian payroll payslip now shows additional employee information, including Pay Category and Joint Committee, except for company executives. It also hides the Working Schedule for company executives, making payslip details more relevant and easier to read for each employee type.
Original PR description
This PR expected to update payslip information, such as: - Add Pay Category and Joint Comitte on Payslip in the employee information, except for company executive - Hide Working Schedule if employee_type is company executive task: 6330973
Resolved issues and error corrections
The page limit note shown in the website generator has been updated to be less specific about the maximum number of pages. This gives the system more flexibility to adjust limits later without changing the user-facing message again.
Original PR description
Page limit note fixed by being more general instead of stating a blatant 200. This gives us more leeway to control the nbr of pages IAP side. Forward-Port-Of: odoo/enterprise#121941 Forward-Port-Of: odoo/enterprise#121671
Debit notes for Colombian DIAN now send correctly without triggering an XML template error. The system no longer includes an unnecessary buyer reference on debit notes, which prevents the document from failing during submission.
Original PR description
Issue: Sending Debit Notes to a tax authority can cause the following error: "ValueError: The following child node is not defined in the template: DebitNote/cbc:BuyerReference" Steps to reproduce on…
Issue: Sending Debit Notes to a tax authority can cause the following error: "ValueError: The following child node is not defined in the template: DebitNote/cbc:BuyerReference" Steps to reproduce on any database with DIAN and Colombian localization: 1. Create a new "Sales" type journal. Then, check the checkbox “Nota de Debito”. 2. Find a res.partner with a ref field, or add a ref field to any partner. 3. Make an invoice using the partner found in step 2. Ensure it uses a tax. Confirm it. 4. Send that invoice to DIAN. 5. Create a Debit Note for that invoice. Use the journal created in step 1. 6. Add a product, price, and tax to the debit note. Confirm it. 7. Send the debit note to DIAN. Explanation: The `_add_invoice_header_nodes` method on the AccountEdiXmlUbl_21 model adds a BuyerReference node unconditionally. (See account_edi_xml_ubl_21.py.) But the DebitNote XML template does not include a BuyerReference element (see ubl_21_debit_note.py). This caused a ValueError when assembling the XML for debit note documents. Solution: The fix overrides this in the Colombian localization by clearing the BuyerReference value when the document type is "debit_note". That way, the node is omitted from the output. opw-6181039 Forward-Port-Of: odoo/enterprise#121458 Forward-Port-Of: odoo/enterprise#121422
This change corrects the rules for CP302 temporary workers so they are no longer blocked by the seniority limit that does not apply to them. It also improves when the 13th-month amount is shown, ensuring end-of-contract dates at year end are taken into account, which helps employees receive the correct benefit at the right time.
Original PR description
Temporary workers (dimona "ext") are unable to have more than 2 days of seniority, since they cannot work more than two consecutive days (see [task 6128098](https://www.odoo.com/odoo/project/1251/tasks/6128098)) Partena's CP302 sectorial documentation says that no employee can get their 13th month if they have less than 2 months of seniority. But in fact, temporary workers are exempt of that rule. Instead, they just need to work at least 44 days during the year to be eligible. This PR changes the condition, adapts the tests, and fixes one thing on when to display the 13th month: - Now, the last contract date end of the year is also considered the last work day of the year (which makes sense). Thus temporary workers may have their remaining 13th month displayed at each end of contract they get. task-6314432
Code cleanup and technical improvements
This change removes an old website selection helper and replaces it with more explicit ways to identify the active website. It reduces ambiguity and lowers the risk of the wrong website being used in requests, tests, and backend flows.
Original PR description
Finalized the deprecation roadmap by completely removing the
`get_current_website()` method. All remaining call sites have been
migrated to use explicit, precise syntax.
Migration strategy applied:
* Standard calls now use `self.env.website`, relying on the safely
injected context.
* Complex locations requiring explicit domain-based routing fallbacks
have been replaced with `self.env.website` or `self.env['website'].browse(self.env.context.get('host_id'))`.
* This brings total clarity to the codebase, ensuring that website
resolution is explicit, predictable, and fully traceable.2 changes
Enhancements to existing features
The Australian payroll tax tables and formulas have been updated for the 2026-27 financial year. It also corrects how the Medicare exemption is applied from 2024 onward, while keeping older data available for historical payroll corrections.
Original PR description
Update tax rates and formulas for the 2026-27 financial year in the Australian payroll module. This commit also amends the tax rates and formulas from 2024 onwards. The Medicare exemption is now properly factored into the tax rates from the 2024-25 fiscal year forward, with the revised formula applied accordingly. Data for pre-2024 remains supported to facilitate importing historical payslips for corrections, aligning with the ATO rule allowing amendments for up to 5 years after the original payslip date. 6252689
Resolved issues and error corrections
Audio files shared through Documents will no longer open in public preview. This avoids broken playback in Chrome and keeps shared files consistent with the existing handling of video files, where preview is also disabled by default.
Original PR description
**Steps to reproduce:** - Install Documents app - Upload a sound file (mp3 for example, but the behavior is the same for other formats) - Share the document and copy the link - Log out - Paste the…
**Steps to reproduce:**
- Install Documents app
- Upload a sound file (mp3 for example, but the
behavior is the same for other formats)
- Share the document and copy the link
- Log out
- Paste the link
- Click on preview button
- Media is working fine on Firefox
- Media won't read on Chrome
```
Loading media from '' violates the following Content Security Policy directive: "default-src 'none'".
Note that 'media-src' was not explicitly set, so 'default-src' is used as a fallback.
The action has been blocked.
```
**Issue:**
Since [1] default CSP Headers are too strict for Chrome default media rendering, which breaks the file preview (and force user download).
This only impacts Chrome as they seem to render generate `<video><source>` elements to render the file which triggers a secondary request and fails due to the CSP constraint.
**Fix:**
Could re-apply the header fix of 17.4 (see [2]), but it seems better to block the preview of audio files as well by default (to match how we manage videos).
(Note: we don't want to be used as a media streaming platform)
[1] (set csp to none by default) https://github.com/odoo/odoo/commit/64beb80205dffe4b432c8b5813a3271b073fa85e
[2] (similar issue which was not fixed in 18.0+) https://github.com/odoo/enterprise/commit/a7af78eeb2b9763045a5bda8714172f5e7402df8
[3] (mp4 preview removed) https://github.com/odoo/enterprise/commit/ea88cf7c6d5f077b60fb59347659507fded0e2fe
opw-62350437 changes
Resolved issues and error corrections
This update adjusts an automated test for subtasks so it matches the current project behavior. When a project is removed from a child task, the task now follows its parent’s project and is hidden, rather than being treated as an invalid change.
Original PR description
Since 2d22b5c, removing the project on a child task sets the project as the parent's and hides the task. The test was not adapted for this behaviour and still expected the write on the child's project_id to raise a CheckValidation error. opw-6253263 runbot-937760
This update adjusts a failing test for project subtasks so it matches the current behavior of the system. When a project is removed from a child task, the task now follows its parent task’s project instead of triggering an error, which keeps the test suite accurate and stable.
Original PR description
Since 2d22b5c, removing the project on a child task sets the project as the parent's and hides the task. The test was not adapted for this behaviour and still expected the write on the child's project_id to raise a CheckValidation error. opw-6253263 runbot-937760
The Czech VIES report XML now includes the taxpayer city and missing representative name fields when needed, and no longer includes the email address. This helps the report pass official validation and reduces the risk of filing errors with the tax authority.
Original PR description
**PROBLEM** For VIES report, the xml should not contains the email. The city of the tax payer is missing, and while it's not strictly require, it can modify the tax regime of the payer, so we need to include it in the xml. There is missing fields in the case the company is an individual (zast_jmeno, zast_prijmeni). **STEP TO REPRODUCE** 1. Create an invoice to a EU partner, don't forget to set the transaction code on the invoice line (unhide the field). 2. Go to the VIES reports, and generate the xml. 3. Upload it to https://mojedane.gov.cz/pmd/epo to validate and see the errors. documentation: https://mojedane.gov.cz/dpr/adis/idpr_pub/epo2_info/popis_struktury_detail.faces?zkratka=DPHSHV opw-6190983
The website language selector now includes descriptive alternative text for flag images when the flag is the only visual cue. This makes the selector easier to use with screen readers and gives search engines better context.
Original PR description
Steps to reproduce: 1. Enable the language selector in the website header. 2. Enable the "Inline" and "Flag" options. 3. Inspect the flag images rendered in the inline variant. Issue: Flag images in the list items have an empty `alt=""` attribute in "Flag only" mode, where the flag is the sole visual indicator of the language, making the selector inaccessible to screen readers and providing no context for search crawlers. Expected behavior: Inline + Flag should have a descriptive ALT tag since there is no adjacent text or code to identify the language, the flag is not decorative. opw-6246464
This fix makes the revenue shown in Timesheets > Reporting calculate correctly for prepaid service orders billed by days. It prevents revenue figures from jumping to incorrect values when time entries are added, and keeps discounts reflected properly in the report.
Original PR description
Steps to reproduce 1. Create a service product: Invoicing Policy = Prepaid/Fixed Price, Track Service = Timesheets, Unit of Measure = Days 2. Confirm a Sales Order with 2 days of that product at…
Steps to reproduce 1. Create a service product: Invoicing Policy = Prepaid/Fixed Price, Track Service = Timesheets, Unit of Measure = Days 2. Confirm a Sales Order with 2 days of that product at 800/day 3. Register 1 hour on the generated task 4. Open Timesheets > Reporting, add the "Timesheet Revenues" measure Issue `timesheet_revenues` in `timesheets.analysis.report` was computed per analytic line as `(SOL.price_subtotal / SOL.qty_delivered) * (unit_amount * sol_uom.factor / ts_uom.factor)` (https://github.com/odoo/odoo/blob/16f170619d9cc5fd86529a3f17e349da37607f73/addons/sale_timesheet/report/timesheets_analysis_report.py#L42-L44). `SOL.qty_delivered` is a stored float rounded to the day UoM precision (0.01d). For 1 hour timesheeted, qty_delivered = 1/8 = 0.125d rounds to 0.13d, so the formula yields (1600 / 0.13) × (1/8) = 1538.46 instead of the correct 100. Because `qty_delivered` is recomputed each time a timesheet is added, all existing rows shift their revenue figure with every new entry. Additionally, using `price_subtotal / qty_delivered` as the per-unit rate ignores any line discount: the rate derived from a discounted subtotal divided by a delivered quantity that differs from the ordered quantity is not the effective price per day. For prepaid lines, the effective per-unit rate is `price_subtotal / product_uom_qty` — the ordered quantity is stable and the subtotal already reflects any discount — multiplied by the timesheet hours converted to the SO line UoM. opw-6150555
Deleting a field could incorrectly trigger an access error for unrelated website-form settings, even when the field being removed was not connected to them. This fix ensures the check runs with the right access level so field deletion works normally for users.
Original PR description
# How to reproduce - Install the Website module - Install another module that has atleast one model with one html field, sanitize=Flase or sanitize_form=False and groups - Remove the field's group…
# How to reproduce - Install the Website module - Install another module that has atleast one model with one html field, sanitize=Flase or sanitize_form=False and groups - Remove the field's group from the current user - Enable dev mode - Go to Settings > Technical > Database Structure > Models - Pick any model (e.g. sale.order.line) - Add a field to that model & Save - Delete the added field & Save > Note : Significantly harder to reproduce since : https://github.com/odoo/odoo/commit/9a336bbb94b0a4266d84f7554c024c3abd2d1e7c I am not sure a field as mentionned in the steps exists # The problem An access error is raised for the module wich access rights were removed, even if the module is not linked in any way with the picked model # Cause of the issue Deleting the field will endup calling the `unlink()` method of `BaseModel` on the `ir.model.fields` record. This function triggers all `@api.delete` methods defined on the model : https://github.com/odoo/odoo/blob/5538132d9d14c4cc5031fc50ac0388ad2ab0fc92/odoo/models.py#L4548-L4552 This will call the this method : https://github.com/odoo/odoo/blob/5538132d9d14c4cc5031fc50ac0388ad2ab0fc92/addons/website/models/website_form.py#L153-L154 That was introduced by : https://github.com/odoo/odoo/commit/c0a827519844ec43537e4487f6abe358bb82ba9a Which prevents a field from being deleted if it is actively used in any website form. But this method does a search on every model return by `_get_html_fields` which may contains models that are not accessible by the user, so we get an access error. # Proposed solution Since `_check_if_used_in_website_form` should perform the same independently from the user, we can do the search in sudo opw-6231951 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Currently, an error occurs on an invoice when user selects a payment term and removes the currency. Steps to replicate: - Install account - Turn on multiple currencies - Open invoices. - Create a new invoice - Add a line - Add a customer - Save - Select payment term as `30% Now, Balance 60 Days` - Remove the currency. Error: ``` ValueError: Expected singleton: res.currency() ``` Cause: - This error only occurs when the selected payment term contains at least two due term l
Original PR description
Currently, an error occurs on an invoice when user selects a payment term and removes the currency. Steps to replicate: - Install account - Turn on multiple currencies - Open invoices. - Create a new…
Currently, an error occurs on an invoice when user selects a payment term and removes the currency. Steps to replicate: - Install account - Turn on multiple currencies - Open invoices. - Create a new invoice - Add a line - Add a customer - Save - Select payment term as `30% Now, Balance 60 Days` - Remove the currency. Error: ``` ValueError: Expected singleton: res.currency() ``` Cause: - This error only occurs when the selected payment term contains at least two due term lines [1]. - When the selected payment term has atleast two lines the check [1] assigns `on_balance_line` as false and the `else` block is evaluated where currency being an empty recordset (as the user removed it) causes the error from [line] when trying to perform `round()` on an empty res.currency recordset. Solution: - As the currency is a required field, user will not be able to save the record until a currency is assigned. - Used journal's currency or company's currency as a fallback when computing payment terms if the current currency is empty. [1]: https://github.com/odoo/odoo/blob/177002c0aca95de2de6458bb65bedf5c74541ac0/addons/account/models/account_payment_term.py#L229 [line]: https://github.com/odoo/odoo/blob/177002c0aca95de2de6458bb65bedf5c74541ac0/addons/account/models/account_payment_term.py#L240 sentry-7569922293 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
3 changes
Resolved issues and error corrections
This change removes an incorrect validation that blocked invoices when more than one pension fund tax was applied to the same line. It now matches the Italian electronic invoicing rules, so affected invoices can be sent without error.
Original PR description
### Steps to reproduce the issue: 1. Download Accounting and l10n_it_edi_withholding 2. Switch to IT company 3. Create 2 taxes with a Pension fund type set (in Advanced Options) 4. Create an invoice…
### Steps to reproduce the issue: 1. Download Accounting and l10n_it_edi_withholding 2. Switch to IT company 3. Create 2 taxes with a Pension fund type set (in Advanced Options) 4. Create an invoice and set on the same line the 2 taxes created 5. Click on send and print and see the error: Invoices must have at most one Pension Fund tax set per line. (even if it's not true) ### Cause of the issue: The following function check how many taxes we have per line but this limit is incorrect because it is accepted by the Italian electronic invoicing specifications to have also more than 1 tax. https://github.com/odoo/odoo/blob/bd095fe286930acc54d85bdf7f92af15569f5b82/addons/l10n_it_edi/models/account_move.py#L1268-L1273 ### Reference documentation: 1. [Art. 10 della Legge n. 183_2011, successivamente integrato dal D.L. n. 1_2012 (art. 9-bis)..pdf](https://github.com/user-attachments/files/29056003/Art.10.della.Legge.n.183_2011.successivamente.integrato.dal.D.L.n.1_2012.art.9-bis.pdf) 2. Following image: <img width="823" height="580" alt="estrattoEppi" src="https://github.com/user-attachments/assets/e79be16f-651e-467a-84f4-8400185ceea4" /> opw-6264685 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Helpdesk quick-create forms now only show customers that belong to the relevant company. This prevents users working across multiple companies from accidentally choosing a customer from the wrong one.
Original PR description
Steps to reproduce: - Create two companies (Company A and Company B) - Create one partner in each company - Enable both companies for the user - Open Helpdesk and go to the tickets Kanban view for a Company A team. - In the quick create form, the customer dropdown shows customers from Company B Issue: - Customers from other companies are visible in the customer field, Cause: - The partner_id field in the quick create view had no domain, so it displayed partners from all allowed companies. Solution: - Added a domain on partner_id in the ticket quick create form view. task-4971466
This fix prevents an error when users open the forecasted quantity view for a product template that does not yet have a variant. Instead of showing a traceback, the forecast button is hidden in this case, which keeps the product screen working normally.
Original PR description
This is a partial backport of 9d2bd55f4833171878972e043a831621f98653b0 Issue: --- Not having at least one variant created for a product template with dynamic attributes can cause issues as it's expected a product template to have at least one variant. To reproduce: 1- Create a dynamic attribute with values. 2- Create a product and without saving: - Enable track inventory. - Add the dynamic attributes and values. 3- Save the product. 4- Click on forecasted quantity smart button: - There is a traceback. Cause: --- This is caused because there is no variant created. In the steps, if you save the template once before adding dynamic attributes, a single variant will be created which allows it to work without issue. Fix: --- we can fix the TB by hiding the forecasted qty smart button, when there is no variant. opw-6300837