Monday, September 28, 2026
17 changes · master
Resolved issues and error corrections
Unreconciling one partial match on an invoice now removes only the selected match instead of also removing other related credit note or payment matches. This helps accounting users correct individual reconciliations without accidentally undoing valid payments or credits.
Original PR description
Repro steps: 1) Create an invoice I 2) Partially reconcile I with a credit note CN 3) Partially reconcile I with a payment P 4) Unreconcile one of the 2 partials Problem: If you unreconcile one partial, both partials are removed (an exception is when account_accountant is installed, not just account, in that case, unreconciling P works fine, but unreconciling CN, also unreconcilies P still) Root cause: account.move.line.remove_move_reconcile used to unreconcile on move level instead of line level because of this PR https://github.com/odoo/odoo/pull/249536 Solution: The logic in remove_move_reconcile is kept simple, and it only unreconciles on account.move.line level. A new method is also introduced account.move._remove_reconciliation_between_moves to unreconcile on the move level, and this one is used with the account payment field to solve the aforementioned issue. task-6574942 Forward-Port-Of: odoo/odoo#288562
Indian e-waybill generation now correctly accounts for global discounts on invoices. This helps ensure submitted e-waybill values match the discounted transaction totals, reducing reporting errors and manual corrections.
Original PR description
Before this commit- We didn't consider, global discount for ewaybill After this commit- We consider the global discount for ewaybill opw-6592878 task-[6596257](https://www.odoo.com/odoo/project/967/tasks/6596257) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#290718 Forward-Port-Of: odoo/odoo#290217
Users can now click Helpdesk ticket analysis graph bars or pivot cells grouped by employee, manager, or department without triggering a server error. The report now correctly opens the related tickets, improving reliability for teams reviewing timesheet and support performance data.
Original PR description
Currently, an error occurs on clicking on the graph or the pivot cell if the data is grouped by Employee/Manager/Department. ### **Steps to reproduce** 1) Install helpdesk_timesheet with demo data 2)…
Currently, an error occurs on clicking on the graph or the pivot cell if the data is grouped by Employee/Manager/Department.
### **Steps to reproduce**
1) Install helpdesk_timesheet with demo data
2) Go to Timesheet > Reporting > Ticket Analysis
3) Set group by to Employee
4) Click on any graph bar or pivot cell
### **Error:**
`ValueError: Invalid field helpdesk.ticket.employee_id in condition ('employee_id', '=', 1)`
Root Cause:
The `helpdesk.ticket.report.analysis` model includes specific fields such as `employee_id`, `department_id`, and `employee_parent_id` (see [1]) that are defined for reporting purposes but do not exist on the `helpdesk.ticket` model. When a user clicks a data point to view related tickets, the reporting view passes the current domain directly to the ticket list view. Because `helpdesk.ticket` lacks these fields, the ORM fails to validate the domain, resulting in a server error.
[1]- https://github.com/odoo/enterprise/blob/8d16b647431985dd7c216ae39eea6ca050e04b46/helpdesk_timesheet/report/helpdesk_ticket_report_analysis.py#L15-L17
### **Fix:**
This commit introduces a mixin to intercept the openView call. The mixin maps reporting-specific fields to valid relational paths on the ticket model `(for example, employee_id is transformed into user_id.employee_id)`. This ensures that the domain generated from the report model is compatible with the target ticket model.
**opw-5931273**
Forward-Port-Of: odoo/enterprise#113088
Forward-Port-Of: odoo/enterprise#108503Duplicate expense submissions now correctly show a warning when the expense extraction feature is installed. This helps prevent employees and accounting teams from accidentally processing the same expense more than once.
Original PR description
Steps to reproduce: - install hr_expense_extract - create an expense and submit it - duplicate that expense, and submit it - no warning dialog showed up when one should. Forward-Port-Of: odoo/enterprise#132357
The scheduled payroll warning email process was failing because it still referenced an outdated internal function. This fix removes that obsolete reference so payroll warning emails can run as expected when company payroll dates are configured.
Original PR description
An error occurs when running the `Payroll: Warning Email Alert` cron job. ### Steps to Reproduce: 1. Install the `hr_payroll` module. 2. Set the "First Pay Run Date" and "Payroll Closing Date" in the company settings. 3. Run the `Payroll: Warning Email Alert` cron job manually. ### Error: `AttributeError: 'hr.payroll.warning' object has no attribute '_get_next_payrun_warnings'` ### Cause: The `_get_next_payrun_warnings()` method was removed in commit [1]. The payrun warnings are now handled by `_get_applicable_payroll_warnings()`, but the old call was still left in `_cron_payroll_warning_email_alert()`. ### Fix: Remove the old `_get_next_payrun_warnings()` call from `_cron_payroll_warning_email_alert()`. [1]:https://github.com/odoo/enterprise/commit/330b2c227a6f32b0eb97a42241b3e098d0a21c74#diff-46a2ba727ac741e996e25eb87db9baf48d6162c82b3124f22036a1972043b06cL498 sentry-**7753641229** Forward-Port-Of: odoo/enterprise#132955
The Swiss financial reports now use corrected balance sheet formulas. This helps businesses in Switzerland see more accurate accounting report totals for compliance and decision-making.
Original PR description
Change some formulas in the Swiss balance sheet task-6379692 Forward-Port-Of: odoo/enterprise#132976 Forward-Port-Of: odoo/enterprise#123895
Payments in Mexican electronic invoices now keep the official stored currency rate when the difference from recalculation is within the accepted rounding range. This prevents invoice and payment XML files from showing different exchange rates for the same date, reducing validation issues and reconciliation confusion.
Original PR description
Issue: Currency rate for payment is recomputed up to 6 digit. However, it may differ from the official one stored in db up to 4 digits. Which creates differencies between invoice and payment rate…
Issue: Currency rate for payment is recomputed up to 6 digit. However, it may differ from the official one stored in db up to 4 digits. Which creates differencies between invoice and payment rate made at the same date. Steps to reproduce: - In MX company, - Enable USD, - Set currency rate for today to 1 USD = 17.4455 MXN - Create a PPD invoice (due date > 40 days) in USD - Add a line with - qty: 1, - unit_price: 3.488 - tax: 16% (default tax) - Send it to CFDI - Create payment - On the invoice Form click on "Update Payment" Current behavior: - In the CFDI sheet, Payment and Invoice XML files will have different currency rates Expected behavior: - In the CFDI sheet, Payment and Invoice XML files will have the same currency rate Cause: PACs require having the payment `amount` to be equal to `currency_amount * currency_rate`. For huge amout it may happen that using the 6 digits rounding of currency rate to compute the amount won't fall exactly on the two digit precision for the amount and payment would be refused. Therefore, for all payment, we recompute a 6 digits precision `currency_rate` from `amount` and `currency_amount` then using it to compute the final amount. However, Banxico (Mexican central Bank) publish rates with a 4 digit precision. Recomputing the currency rate up to 6 digits may slightly change it from the 4 digit precision official currency rate. opw-6411530 Forward-Port-Of: odoo/enterprise#132659 Forward-Port-Of: odoo/enterprise#129700
This fixes how copied or linked document attachments are referenced so deleting a source item does not leave broken links or remove related business documents unexpectedly. It improves reliability for Documents, Accounting documents, and Sign workflows that reuse or copy attachments.
Original PR description
The `original_id` field is set to `ondelete="cascade"`. The field is meant to mean "derived from" so that when the original attachment is deleted, then the derived attachments are also removed. Which means that after copying, the original would be deleted. Before we may introduce support for ondelete in the ORM, the deletion of the sign template in test_create_update_copy_unlink_template is deleting the linked sign document implicitely leaving the attachment with an invalid reference. See `test_correct_reference_doc_set`.
Italian invoices using the Import/Export fiscal position now apply the correct 0% tax instead of adding both standard and N7 zero-rate taxes. This prevents incorrect tax setup on invoice lines and supports more accurate Italian accounting and e-invoicing data.
Original PR description
Upon Import/Export, the 0% EX N7 tax is added by default on each tax excluded line, as it incorrectly shares the same default Import/Export fiscal position with the standard 0% EX tax. This causes both to be applied simultaneously to a single invoice line. 1. Install Accounting and `l10n_it` 2. Switch to IT company 3. Go to Invoices and create a new one 4. Select the Import/Export fiscal position 5. Add a line with a new product (so it's clean of custom product taxes) 6. Both `0% EX` and `0% EX N7` taxes are applied, instead of just `0% EX` Ticket [link](https://www.odoo.com/odoo/project.task/6518926) opw-6518926 Forward-Port-Of: odoo/odoo#285586
Attendance officers without full Employees app access can now open the Employees menu from Attendance without hitting an access error. The menu now shows an attendance-specific employee view with only the information they are allowed to see, improving usability while keeping HR data restrictions in place.
Original PR description
A user configured with "Officer: Manage all attendances" but no access to the Employees app can see the "Employees" entry under Attendances > Overview, since that menu only requires Attendance…
A user configured with "Officer: Manage all attendances" but no access to the Employees app can see the "Employees" entry under Attendances > Overview, since that menu only requires Attendance rights. Opening it, however, raises an access error naming the "Current Time Off Type" field. Steps to reproduce: ------------------- * Go to Settings > Users, open a user and set their access rights to: Employees app: no access, Attendances app: "Officer: Manage all attendances" * Log in as that user * Go to Attendances > Overview > Employees > Observation: Error: "You do not have enough rights to access the field "current_leave_id" on Employee (hr.employee). Please contact your system administrator." Why the fix: ------------ The "Employees" menu pointed to `hr.open_view_employee_list_my`, the full HR Employees action (model `hr.employee`, no view_id override), which resolves to the same default kanban view used by the Employees app. That view is extended by hr_holidays to embed `current_leave_id` (and other Time Off fields), declared with `groups="hr.group_hr_user"` on the model. That group restriction is enforced by the ORM on read, independently of whether the field is actually shown in the view, so any attendance-only officer opening the menu had that read rejected outright. The menu now points to `hr_employee_attendance_action_kanban`, an attendance-scoped action already shipped in the module for this exact purpose: it uses the `hr.employee.public` model with a minimal kanban view (name, avatar, job, work location, check-in state), none of which require HR app access, restoring the ability to browse employees from the Attendance app without needing `hr.group_hr_user`. opw-6488582 Forward-Port-Of: odoo/odoo#289884 Forward-Port-Of: odoo/odoo#287140
Kenya eTIMS reporting now excludes taxes that do not have a KRA tax code from the reported tax-inclusive total. This prevents levies owed to other authorities, such as tourism levies, from being incorrectly included in tax authority submissions.
Original PR description
Issue: Non KRA taxes are sent in eTIMS tax total Steps to reproduce: - With l10n_ke_edi_oscu - Create a 2% Tax named CTL with no KRA Tax Code - Create an invoice - Add a line with 16% and CTL taxes - Confirm - Send to eTIMS Current behavior: - eTIMS JSON (unaccessible) is created with 'totAmt' (total_tax_included) including non-KRA Taxes Expected Behavior! - eTIMS JSON 'totAmt' doesn't incldue non-KRA Taxes Note: eTIMS is used to report to Tax Autority, however some "taxes" (e.g. Tourism levy) are paid to other authorities (e.g. Tourism Fund) and shouldn't be included in eTIMS. opw-6456478 Forward-Port-Of: odoo/enterprise#131577
Dutch VAT returns and ICP declarations could fail when companies used a password-protected Digipoort private key. The update reads the key in the expected unencrypted form so submissions and status checks work again.
Original PR description
Steps to reproduce: 1. Set a Digipoort certificate whose private key has a password 2. Submit a VAT return or an ICP declaration 3. It fails with 'bad password read' Analysis: Before 19.0 the PEM key was in an unencrypted format. Since f88f8258ead, env['certificate.key'].pem_key is encrypted whenever the key has a password. Every consumer in this module loads it without a passphrase: the VAT wizard, the ICP wizard and the status polling cron. Same cause as (odoo/enterprise#96562), which fixed it for l10n_mx_edi. Solution: Decrypt the key when reading it, as was already the case before 19.0. opw-6421300 Forward-Port-Of: odoo/enterprise#132023 Forward-Port-Of: odoo/enterprise#127528
Accounting users in Chilean companies can now upload invoice XML files without administrator rights blocking the import. This prevents invoices from being created without the attached XML being processed, reducing manual follow-up and support needs.
Original PR description
Scenario: - be not an admin but have access to accounting - switch to chilean company - go to customer invoices - click on Upload and upload an XML file Result: an invoice is created, but the XML is not treated because of this permission error: 19.0/l10n_cl_edi/…/account_move.py", line 1078, in _l10n_cl_import_dte invoice.l10n_cl_dte_file = file_data['attachment'] odoo.exceptions.AccessError: You do not have enough rights to access the field "l10n_cl_dte_file" on Journal Entry (account.move). Please contact your system administrator Cause: l10n_cl_dte_file field is only accessible to administrator. opw-6509550 Forward-Port-Of: odoo/enterprise#131575 Forward-Port-Of: odoo/enterprise#130416
Customer payments in the Mexican electronic invoicing module now correctly inherit the payment method set on the selected bank journal. This prevents payment complements sent to the tax authority from using the default bank transfer method when another valid method, such as credit card, was configured.
Original PR description
Currently, payment way configured on a bank journal is not taken into account, payments will default to "03 Transferencia electrónica de fondos". Steps to reproduce: - Set the "Payment Way" of a bank journal to "04 Tarjeta de Crédito". - Manually create a customer payment in that journal - Look at the "Payment Way" of the payment, then send the payment complement (REP) to the SAT. Issue: The payment way is "03 Transferencia electrónica de fondos" and the REP carries FormaDePagoP="03" The one set on the journal is ignored. Analysis: We should evaluate the journal before the transferencia default so a payment inherits the payment way, and keep transferencia as the last possible value. opw-6493514 Forward-Port-Of: odoo/enterprise#132074 Forward-Port-Of: odoo/enterprise#130133
Australian Payroll users can now add or remove people from payroll groups through the Groups form without causing a save error. These membership changes are also consistently audit-logged, improving traceability for payroll administration.
Original PR description
#### Description of the issue/feature this PR addresses:
Adding a user to a group from the Groups form crashes on an Australian Payroll-API database, and removals from that form are never audit-logged.
#### Current behavior before PR:
The audit-logging mixin reads the changed users out of the raw write command with vals.get("user_ids")[0][2], which assumes a 3-element command tuple. The Groups form sends the 2-element (4, id) LINK command, so the write raises an IndexError; UNLINK commands are silently not logged for the same reason.
#### Desired behavior after PR is merged:
Group membership changes made from the Groups form are audit-logged for both additions and removals, regardless of the command used to write user_ids. The mixin reads the members before and after the write instead of interpreting the command. No field, model or method-signature change, so it is safe in stable.
opw-6397011
Forward-Port-Of: odoo/enterprise#132821
Forward-Port-Of: odoo/enterprise#125124The website shop now blocks combo products from being added to the cart unless every required choice is properly selected. This prevents customers from checking out with incomplete combo orders, even if browser controls are bypassed.
Original PR description
Steps to reproduce: =================== 1. Publish a combo product whose choices each offer more than one item, so the combo configurator is shown. 2. On the shop, open the product and click "Add to…
Steps to reproduce: =================== 1. Publish a combo product whose choices each offer more than one item, so the combo configurator is shown. 2. On the shop, open the product and click "Add to Cart". 3. Select an item for one combo choice only. The dialog's "Add to cart" button stays disabled. 4. Remove the `disabled` attribute from that button with the browser developer tools and click it. => The combo is added to the cart with one of its choices unanswered, and the order can be paid in that state. Root cause: =========== The incomplete selection is only prevented on the client side, by disabling the button until every choice has been answered. Server side, `/website_sale/combo_configurator/update_cart` only rejects a completely empty selection, never that the selected items cover every choice. Fix: ==== Reject the request unless the selected combo items cover exactly the combo choices of the product. Comparing the set of choices rather than counting the items also rejects a selection answering the same choice twice while leaving another one unanswered. opw-6478837 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#289886 Forward-Port-Of: odoo/odoo#283465
The Time Off Ledger now shows expected working hours based on each employee's actual schedule for the specific day, instead of repeating a weekly average. This makes reports accurate for staff with shorter or longer scheduled days, improving attendance and time off tracking.
Original PR description
The Time Off Ledger report shows the same "Expected Hours" value for every working day of an employee, even when their working schedule assigns different hours to different weekdays. ### Steps to…
The Time Off Ledger report shows the same "Expected Hours" value for every working day of an employee, even when their working schedule assigns different hours to different weekdays. ### Steps to reproduce: 1) Install hr_holidays_attendance. 2) Create/assign a working schedule where daily hours vary across the week (e.g. Monday-Thursday 8.5h, Friday 5h). 3) Go to Attendance > Reporting > Time Off Ledger, filter on that employee. ### Observed behavior: "Expected Hours" is identical on every day (the schedule's average hours/day), regardless of which weekday the row is for. ### Expected behavior: "Expected Hours" should match the hours actually scheduled for that specific weekday, so a shorter Friday shows less than a full Monday. ### Root cause: `Time off Ledger` is a SQL view. Its `_select()` builds `expected_hours` from `rc.hours_per_day` at [1], i.e. `resource.calendar.hours_per_day`, a field explicitly labelled **"Average Hour per Day"** and is computed via [_get_hours_per_day] as `hours_per_week / days_per_week`, a single flat value for the whole calendar. The per-weekday hours are available in `resource.calendar.attendance` it stores `dayofweek`, `hour_from`/`hour_to` and a computed `duration_hours` per line, and can legitimately differ per weekday (e.g. Monday 8h vs Friday 4h) at [2]. The report's own [_cte_cal_workday()] CTE already reads this table to decide whether a weekday is a working day (`cal_workday`, joined as `cw` in `_from()`), but discarded the actual hours, keeping only `(calendar_id, dayofweek)`. `_select()` then fell back to the calendar-wide average via `rc.hours_per_day` instead of the per-day value. Example: calendar with Monday 8h and Tuesday 4h -> `hours_per_day` averages to 6h; the report showed 6h on both Monday and Tuesday instead of 8h and 4h respectively. [1]- https://github.com/odoo/odoo/blob/5568f6e472e2e53bc2931e744421015b0f0f3550/addons/hr_holidays_attendance/report/hr_leave_attendance_report.py#L256 [_get_hours_per_day]: https://github.com/odoo/odoo/blob/5568f6e472e2e53bc2931e744421015b0f0f3550/addons/resource/models/resource_calendar.py#L703-L707 [2]- https://github.com/odoo/odoo/blob/5568f6e472e2e53bc2931e744421015b0f0f3550/addons/resource/models/resource_calendar_attendance.py#L15-L31 [_cte_cal_workday()]: https://github.com/odoo/odoo/blob/5568f6e472e2e53bc2931e744421015b0f0f3550/addons/hr_holidays_attendance/report/hr_leave_attendance_report.py#L82-L89 ### Fix: `_cte_cal_workday()` now aggregates `SUM(duration_hours)` per `(calendar_id, dayofweek)` from `resource_calendar_attendance`, instead of just selecting the distinct keys. `_select()` reads this per-weekday value (`cw.hours_per_day`) instead of the calendar-wide `rc.hours_per_day` for both `expected_hours` and `difference_hours`. **opw-6425167** Forward-Port-Of: odoo/odoo#289812 Forward-Port-Of: odoo/odoo#280664