Saturday, September 12, 2026
15 changes · master
Resolved issues and error corrections
Card payments no longer fail when a previous expense created from the same card is missing a date. Undated expenses are now only included in all-time checks, helping employees continue using their cards while keeping spending limits accurate.
Original PR description
Fix a traceback preventing card users to make any payment with their card if at least one expense created by said card has no date Steps to reproduce: - Install hr_expense_stripe_demo (to access the test wizards) - Setup the stripe (demo) account with a valid card and funds - Create one transaction with the card - Remove the date of the generated expense -> Any further transaction with that card will fail After this commit: An expense with no date is considered only in the 'all time' Ticket [link](https://www.odoo.com/odoo/project.task/6326124) opw-6326124 Forward-Port-Of: odoo/enterprise#130337
German point-of-sale sessions using Fiskaly can now close successfully when an order customer is an address contact without its own name. The system uses the displayed contact name as a fallback for required compliance export data, preventing session-closing crashes.
Original PR description
Steps to reproduce: - German PoS with Fiskaly TSS configured - Set a customer that is an address contact (type invoice/delivery/other) on an order; such a contact has no name of its own, it is…
Steps to reproduce: - German PoS with Fiskaly TSS configured - Set a customer that is an address contact (type invoice/delivery/other) on an order; such a contact has no name of its own, it is displayed with its parent's - Close the session Issue: Closing crashes with "TypeError: 'bool' object is not subscriptable" and the session cannot be closed at all. Cause: _get_dsfinvk_cash_point_closing_data builds the DSFinV-K buyer block from partner.name, which is only guarded by "if partner := o.partner_id". res.partner.name is not required: the res_partner_check_name constraint only enforces it for type='contact', so an address contact stores NULL there and partner.name reads as False, which cannot be sliced. Fix: Fall back on complete_name - what the UI displays for those contacts, "Parent Company, Delivery" - and on a literal when even that is empty, since the buyer name is mandatory in the export. Reading name first leaves the exported value untouched for every partner that has one. opw-6518336 Forward-Port-Of: odoo/enterprise#131212 Forward-Port-Of: odoo/enterprise#129709
Odoo now processes official Flow 10 response messages for French PDP reporting instead of only storing them as files. Rejected reports are marked correctly, users can see the rejection details, and corrected reports can be resent with a new transmission reference.
Original PR description
Flow 10 PPF responses were stored as attachments without being processed. Consequently, rejected reports remained marked as sent, the rejection reason was not shown to users, and corrected reports could not be submitted again. Process the PPF response codes, update the flow state, and log the returned details in the chatter. Keep response attachments separate from the outgoing payload and allow rejected reports to be manually resent with their original moves and a new transmission identifier. no task id Forward-Port-Of: odoo/odoo#287737 Forward-Port-Of: odoo/odoo#287338
This fix prevents scheduled Chilean electronic invoicing status checks from failing when the tax authority returns an empty response. It helps keep automated invoice processing running reliably without manual intervention.
Original PR description
When checking the status of a DTE, sometimes the response will have no `text`. This causes a traceback error that halts execution of the cron `cron_run_sii_workflow`. opw-6322106 Forward-Port-Of: odoo/enterprise#130873 Forward-Port-Of: odoo/enterprise#129582
This fixes SEPA credit transfer export files so they no longer include an address field that some European banks reject. Businesses using Austrian, German, or similarly strict banks should be able to submit batch payment files successfully again.
Original PR description
### Issue before this commit: Generating a SEPA Credit Transfer XML for certain European banks (e.g., Austrian and German banks) fails because the generated XML contains an unexpected `<CtrySubDvsn>`…
### Issue before this commit: Generating a SEPA Credit Transfer XML for certain European banks (e.g., Austrian and German banks) fails because the generated XML contains an unexpected `<CtrySubDvsn>` tag inside the `<PstlAdr>` node, leading to the rejection of the batch payment file. ### Steps to reproduce the issue: 1. Download Accounting and l10n_at 2. Go to settings and activate SEPA Credit Transfer / ISO20022 3. Go to Journals > Bank > set an account number 4. Create an austrian contact (ex. FK Austria Wien AG) and set in the invoicing tab a bank (ex. AT526000071856851733) and set it trusted 5. Go to Bills, create a new one with the contact created and confirm it 6. Then click 'PAY' and select SEPA Credit Transfer 7. Go to Vendors > Batch Payments 8. Create a new one with: 1. Bank as bank 2. SEPA Credit Transfer as Payment Method 3. Add the bill just created 9. Validate and download the XML 10. See that a wrong tag <CtrySubDvsn> is added. This makes some banks refuse it ### Cause of the issue: External commit 30b023d394a5e4de64873188aa1d5961fecccb10 introduced the `<CtrySubDvsn>` tag to support US and CA requirements. However, the change was incorrectly applied to the common `account_iso20022` file, making it leak into standard European SEPA exports where the tag is not compliant with certain strict banking validation rules. ### Reason to introduce the fix: Revert the generic addition of the `<CtrySubDvsn>` tag in the common ISO20022 XML generation and restrict it only to the specific localizations (US/CA) that require it. This brings the `<PstlAdr>` node back to compliance, allowing Austrian, German, and other European banks to successfully process the files. opw-6523035 Forward-Port-Of: odoo/enterprise#131156 Forward-Port-Of: odoo/enterprise#131090
Payslips now only include public holidays for the employee version's own company, even when multiple companies are selected. This prevents holidays from one country or company appearing incorrectly in another company's payroll calculations.
Original PR description
Issue: - Create a public holiday in France, and generate a payslip in Belgium, with both companies selected. - French public holidays will appear in the belgian worked day lines. Fix: replace `self.env.companies.ids` -which returns all selected companies- in `_get_leave_domain` with `self.company_id.ids` to match the company of the current version in the payslip. task-id: 6425963 Forward-Port-Of: odoo/odoo#287638
User role changes now correctly update the related access groups, even when the role is not tied to a specific functional access. This prevents mismatches between what administrators see in the user form and the permissions actually applied after saving or reloading.
Original PR description
It is a functional request to add him to the groups even if he is not involved by a functional access. [FIX] base: prevent group desync in user onchange When editing a user in the web client, the…
It is a functional request to add him to the groups even if he is not involved by a functional access. [FIX] base: prevent group desync in user onchange When editing a user in the web client, the onchange mechanism creates a virtual record using `new(values, origin=record)` to build the baseline snapshot used for field diff tracking. In `res.users.new()`, logic automatically adjusts `group_ids` (adding or removing `base.group_multi_company` depending on the number of companies on the user) as a side effect. When `new()` was called with an `origin`, this side effect corrupted the reference snapshot. Consequently, the onchange return value failed to detect or report the real delta to the web client, leaving the UI in an incorrect or desynchronized state (e.g. `role` radio buttons or access right checkboxes out of sync with actual groups). Fix this by skipping the automatic group adjustment in `new()` when `origin` is present, keeping the reference snapshot clean. Add tour tests to ensure `role` and group checkboxes stay synchronized across saves and page reloads in the web client.
Fixed an issue where reusing the calendar multi-create popover could incorrectly limit available Time Type options after creating and deleting working-time entries. Users can now continue adding schedule entries without needing to refresh the page to restore the full list of allowed choices.
Original PR description
Issue: The calendar multi-create popover retains its form values so they can be reused when adding entries to another selection. In a variable working schedule, this retained state incorrectly…
Issue: The calendar multi-create popover retains its form values so they can be reused when adding entries to another selection. In a variable working schedule, this retained state incorrectly restricted Time Type to the first allowed value after mass creating entries and deleting one occurrence. Refreshing the page restored all Time Type options because the form was then rebuilt from the complete backend value of `allowed_work_entry_type_ids`. Steps to reproduce: - Open a working schedule and switch it from Fixed to Variable. - Select multiple days and mass add working-time entries. - Select one of the created days and delete its entry. - Select that day again and open the Add popover. - Open Time Type and observe that only the first allowed type is available. - Refresh the page and observe that all allowed types are available again. Cause: `work_entry_type_id` is filtered by the computed `allowed_work_entry_type_ids` relation. The relational model keeps every relation ID in `StaticList.currentIds`, but only materializes the loaded page in `StaticList.records`. Since this invisible domain dependency has no related display fields, its loaded page is limited to one record. When the multi-create popover was submitted or closed, https://github.com/odoo-dev/odoo/blob/23266b3a3bf0856dc147e3780e5ac54469bbcc53/addons/web/static/src/views/view_components/multi_selection_buttons.js#L169-L180 serialized x2many values from `StaticList.records`. This reduced `allowed_work_entry_type_ids` to its first loaded ID in the retained `multiCreateValues`. Reopening the popover reused that incomplete relation, so the Time Type domain correctly evaluated against only one ID. Solution: Serialize x2many values from `StaticList.currentIds` so every related ID is preserved. For loaded records, merge the cached record data to retain edited or display values, for unloaded records, retain an ID-only value. This keeps the complete domain dependency across calendar multi-create popovers without changing the backend Time Type computation. opw-6398706 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280391
Employee availability is now shown consistently across Time Off and Attendance, including days outside contracts and flexible schedules. This prevents misleading calendar views by greying out unavailable periods and improves reliability for workforce planning.
Original PR description
purpose: 1- We should have a consistent way to compute `_gantt_unavailability` of employees in time off and attendance. Currently, some cases have inconsistent behavior such as out of contract days,…
purpose:
1- We should have a consistent way to compute `_gantt_unavailability` of employees in time off and attendance. Currently, some cases have inconsistent behavior such as out of contract days, flexible and fully flexibe employees. 2- In time off calendar view, if the employee does not have a contract at all, the current working schedule will appear in the calendar and it will not be greyed out. This is inconsistent with the behavior of the attendance application.
Fix:
1:
- implemented `_get_employee_unavailable_intervals` in employee model to be used in both time off and attendance.
- more optimized than the old implementation in time off as it calls `_work_intervals_batch` once per calendar instead of calling it for each contract in `_unavailable_intervals_batch`
- greys out "out of contract" periods
- for flexible and fully flexible employees, the whole period is considered available except leave periods
- for duration based calendars, morning and afternoon map to 12 hours of availability and full day maps to 24 hours of availability
- made `_get_calendar_periods` use version date start instead of contract date start and corrected a bug in tz conversion 2:
- made `_get_unusual_days` return True for all the days outside of contracts for the employee instead of not returning anything for them or getting values from the working schedule of the employee (means that they will be greyed out in the callendar view) and added a test for it
task-id: 5473055
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#287019
Forward-Port-Of: odoo/odoo#258604This fixes a problem where the HTML editor could stay stuck with outdated content after a newer save happened elsewhere. The editor now uses the latest version stored on the record, helping users see the correct server-saved document and avoid stale edits.
Original PR description
Before this commit, an editor recovering from a stale document could stop on this error and keep the stale content:
```
Error: Concurency detected while recovering from a stale document. The
last history id of the server is different from the history id received
by the html_field_write event.
at CollaborationOdooPlugin.resetFromServerAndResyncWithPeers
```
This happens because the recovery compares the history id of the record with the one the html_field_write event carried. A write keeps only the last step id in the field, so an event handled after a later write names an id the record no longer holds. As a result, the recovery stops there and the document stays stale.
This commit fixes the issue by taking the history id read from the record as the new server reference, so the editor converges on the document the server holds.
https://runbot.odoo.com/odoo/error/944595
Forward-Port-Of: odoo/odoo#287523
Forward-Port-Of: odoo/odoo#287408This fix ensures automatic period-change entries are properly balanced and reconciled. It prevents leftover accounting lines from cluttering records and helps keep financial data accurate.
Original PR description
The previous code wasn't reconciling the destination and accrual moves, leaving potentially non-neutral journal items and their counterpart polluting the DB. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#287524 Forward-Port-Of: odoo/odoo#279766
This fix stops the system from creating exchange difference entries when users reconcile journal items on accounts where reconciliation is not allowed. It ensures accounting records stay cleaner and avoids unexpected extra entries in this specific workflow.
Original PR description
Repro steps: 1) Create two misc entries with different foreign currency amount and different company currency amounts, on an account with "Allow Reconciliation" disabled (one debit, one credit). 2) Go to Journal Items, select both lines and click Reconcile. Issue: An exchange difference entry is generated. Fix: Move the control of the exchange difference moves creation to the account.reconcile.wizard instead of controling it inside action_reconcile of account.move Related PRs: https://github.com/odoo/enterprise/pull/130541 https://github.com/odoo/enterprise/pull/108362 Forward-Port-Of: odoo/enterprise#131145
Employee availability is now shown consistently across Attendance and Time Off planning views. Days outside an employee contract are clearly greyed out, while flexible schedules and leave periods are handled more accurately, helping managers plan with fewer misleading calendar gaps.
Original PR description
purpose: 1- We should have a consistent way to compute `_gantt_unavailability` of employees in time off and attendance. Currently, some cases have inconsistent behavior such as out of contract days,…
purpose:
1- We should have a consistent way to compute `_gantt_unavailability` of employees in time off and attendance. Currently, some cases have inconsistent behavior such as out of contract days, flexible and fully flexibe employees. 2- In time off calendar view, if the employee does not have a contract at all, the current working schedule will appear in the calendar and it will not be greyed out. This is inconsistent with the behavior of the attendance application.
Fix:
1:
- implemented `_get_employee_unavailable_intervals` in employee model to be used in both time off and attendance.
- more optimized than the old implementation in time off as it calls `_work_intervals_batch` once per calendar instead of calling it for each contract in `_unavailable_intervals_batch`
- greys out "out of contract" periods
- for flexible and fully flexible employees, the whole period is considered available except leave periods
- for duration based calendars, morning and afternoon map to 12 hours of availability and full day maps to 24 hours of availability
- made `_get_calendar_periods` use version date start instead of contract date start and corrected a bug in tz conversion 2:
- made `_get_unusual_days` return True for all the days outside of contracts for the employee instead of not returning anything for them or getting values from the working schedule of the employee (means that they will be greyed out in the callendar view) and added a test for it
task-id: 5473055
Forward-Port-Of: odoo/enterprise#130714
Forward-Port-Of: odoo/enterprise#113498Colombian child contacts linked to a company with a NIT are no longer incorrectly treated as separate companies. This restores the expected company-and-contact display and makes those contacts show up when users search by the parent company name.
Original PR description
Issue: Colombian child contacts linked to a NIT company are displayed with their standalone name instead of "Company, Contact". Searching Contacts by the company name consequently returns the company…
Issue: Colombian child contacts linked to a NIT company are displayed with their standalone name instead of "Company, Contact". Searching Contacts by the company name consequently returns the company but not its child contacts. Steps to reproduce: - Create a Colombian company with NIT - Add a child contact or address to that company - Filter Contacts by the company name - Observe that the child is displayed separately and is not returned Cause: The Colombian `is_company` computation classifies every partner with a Colombian NIT and qualifying obligations as a company: https://github.com/odoo/enterprise/blob/911686a31d5d3c1539d0dff7d16edf1ce9b101ca/l10n_co_edi/models/res_partner.py#L43-L53 Those fiscal values are commercial fields and are propagated to child contacts. Without checking that the partner is its own commercial entity, children are therefore classified as companies, preventing the standard display name logic from prefixing their parent name. Solution: We need to restrict the Colombian company classification to partners that are their own commercial partner. This preserves the NIT and obligation rules for actual companies while keeping their inherited child records as contacts, restoring both the combined display name and parent name search behavior. opw-6470958 Forward-Port-Of: odoo/enterprise#130373 Forward-Port-Of: odoo/enterprise#128986
This fixes an issue where some product variant images could be treated as general product images during installation or upgrades. Online stores will show and organize variant-specific images more accurately, reducing confusion for shoppers and staff.
Original PR description
Issue: when installing or upgrading `website_sale` (version 20.0), some variant images were incorrectly interpreted as template images. Fix: before interpreting an image as a template image, check whether it's used in one or more variants, and if so, interpret the image as a variant image instead (and assign in to the union of the variants' PTAVs). This PR also fixes a few cosmetic issues.