Daily updates from Odoo
Wednesday, July 29, 2026
53 changes · master
New functionality added to Odoo
Adds the Monthly Alphalist of Payees report required by the Philippine BIR for form 1600-VT. Businesses can now list VAT withheld from suppliers and generate the required DAT export directly from Odoo, helping simplify compliance reporting.
Original PR description
The BIR requires a Monthly Alphalist of Payees (MAP), attachment to form 1600-VT, listing the VAT withheld from suppliers. Added MAP report along with its .dat export for form 1600-VT. Community PR: https://github.com/odoo/odoo/pull/278533 Upgrade PR: https://github.com/odoo/upgrade/pull/10868 task-6314000
Enhancements to existing features
When users open the new-product form from barcode lookup, existing notifications are no longer cleared automatically. This keeps helpful messages visible because mobile notifications now appear at the bottom and no longer block the form.
Original PR description
…n click This reverts commit https://github.com/odoo/enterprise/pull/68352. That commit cleared all open toast notifications before opening the new-product form, because on mobile a notification used to take up a large chunk of the screen, forcing the user to wait out its autoclose timeout before they could interact with the form underneath. Notifications on mobile are now anchored to the bottom of the screen (M3 snackbar), so they no longer overlap the form and this workaround is no longer needed.
ZKTeco attendance punches are now processed one transaction at a time, so an issue with one punch no longer stops the whole batch. The update also adds scheduled processing and clearer status information, helping teams spot and resolve attendance import issues more easily.
This update refreshes icon usage in several Odoo Enterprise areas to align with the latest web interface standards. Users should see more consistent visual elements in affected screens, with minimal change to day-to-day workflows.
Belgian payroll reporting now supports the withholding tax exemption for worker training, allowing selected employees' eligible training months to be included in the 274.XX report. The calculation respects legal limits by applying R&D exemptions first and capping the training exemption at the remaining withholding tax.
Original PR description
Add the "Exemption from withholding tax for worker training" (nature 274.64) to the 274.XX report. The exemption is 11.75% of the taxable gross of the months during which the training took place for the manually selected employees. The cumulative exemption for an employee cannot exceed the total withholding tax for them, so the training exemption is floored to the withholding left after the R&D exemption (274.32/33/34, applied first). task-6326855
Belgian payroll screens and reference data were updated to make DMFA work location information clearer and more consistent. This helps payroll users identify and manage work location details more easily when preparing Belgian social security reporting.
Original PR description
[IMP] l10n_be: dmfa work location adjustments Renaming and view adjustments for dmfa work location task-6381334
SEPA direct debit payment pages now use the shared pending payment instruction flow. Customers see the beneficiary name and bank account from the selected journal on status and confirmation pages, helping them understand payment details more clearly.
Original PR description
Adapt SEPA with the generic pending payment instructions introduced in `payment_custom`. Display beneficiary name and bank account number from the selected journal on payment status and confirmation pages. task-4975272
Add a new notification in the bank reco widget when a user do a reconciliation with a partner different from the one on the st_line. The idea is to let the user chose if he wants to move the bank account from the st_line partner to the move he tries to reconcile. task-6303397 Forward-Port-Of: odoo/enterprise#125702 Forward-Port-Of: odoo/enterprise#120900
Original PR description
Add a new notification in the bank reco widget when a user do a reconciliation with a partner different from the one on the st_line. The idea is to let the user chose if he wants to move the bank account from the st_line partner to the move he tries to reconcile. task-6303397 Forward-Port-Of: odoo/enterprise#125702 Forward-Port-Of: odoo/enterprise#120900
Australian payroll now applies the required superannuation contribution cap in the qualifying earnings rule. This helps employers stay aligned with ATO regulations, including updated super guarantee calculations from 1 July 2026.
Original PR description
Added superannuation limit to the QE rule. Task-6221399 Forward-Port-Of: odoo/enterprise#119792
Belgian payroll users can now see which reporting areas are affected when changing a time type. The time type form now shows the related DRS nature and triggered types, helping users understand the consequences of configuration changes before making them.
Original PR description
In order to help the user which reports gets impacted in case of modifying a time type, DRS nature and triggered types have been added to the time type form view. Task: 6330987
Belgian payroll now excludes Flexi-job workers from the holiday pay tax provision because they receive holiday pay directly. If their employment declaration is accepted with warnings, only the affected wage portion is treated like regular work and included proportionally, improving payroll accuracy.
Original PR description
…ision Flexi-job workers get their holiday pay directly, so the tax provision should not apply to them. However, if a Dimona declaration for the period was "Accepted with Warnings", that portion of the wage is treated as a regular occupation and prorated into the provision. This commit splits the old employee/worker rules into a shared HOLIDAY_TAX_PROV_BASE (wage, prorated for Flexi-jobs) and HOLIDAY_TAX_PROV_EMP (applies the worker/employee rate on top). Task-6352428
Belgian payroll now shows a non-blocking warning when an employee's part-time schedule is below the legal 10% minimum of the company’s full-time reference hours. Student and Flexi-job categories are excluded, helping payroll users spot compliance risks without stopping the save process.
Original PR description
Purpose
Part-time contracts must be scheduled for a minimum of 10% of the reference Full-Time working duration selected for the company.
Specifications
Show a non-blocking popup message when saving an employee profile if:
- The scheduled working hours are shorter than 10% of the reference working hours.
- The employee's Dimona category is not Student ('stu') or Flexi-job ('flx').
The popup informs the user of the legal 10% minimum regulation and allows them to close it without blocking the save pipeline.
Task: 6317799Users can now create new records directly from Odoo map views, making maps work more like familiar list and kanban views. Businesses can keep the button enabled by default, disable it where record creation should be restricted, or manage its visibility through Studio customization.
Original PR description
This commit adds record creation support to the map view, bringing it in line with standard Odoo views (such as List and Kanban). The "New" button is enabled by default and can be suppressed programmatically using the `create` attribute in the view XML (e.g., `create="false"`), or toggled visually via Studio customizations. task-6377660
HR contract signing now shows all available signing templates, whether they require one signer or multiple signers. This makes it easier to use the right template and supports both simple and multi-person approval workflows.
Original PR description
Before this change, selecting a signer template with one signer prevented other signer templates from being displayed. After this change, all templates are listed, including those with one or multiple signers. The signature workflow has been verified to work correctly for both single-signer and multi-signer cases. Task-6186566
Payroll users can now open the full Time Off request form directly from a leave entry in the Gantt view. The new expand button makes it easier to review or update all request details without navigating away manually.
Original PR description
Before this commit, users could click on a leave entry in the Gantt view of the Payroll app, but they could not open its full form view. This commit adds an expand button (double arrow icon) that allows users to open the complete Time Off request form. Task-6360136
Customer payment reminder workflows have been redesigned to make both automatic and manual reminders easier to manage. Open Items, Partner Ledger, and Customer Statement reports were also improved to provide clearer, more reliable follow-up information for finance teams.
Original PR description
This commit introduces new features and simplifies the reminder workflow for both automatic and manual reminders. It also includes changes to the Open Items report, providing a more robust and user-friendly experience.
When users try to create an expense card before Stripe is connected, they are now directed to the settings page to complete the connection. This reduces confusion and helps users resolve the setup issue more quickly.
Original PR description
When a user tries to create a card but the configuration is not connected, redirect the user towards the settings to do the connection. task-6272805 Forward-Port-Of: odoo/enterprise#125113
This update makes the field selection experience in Studio behave consistently when debug mode is enabled. It helps advanced users see the same options and behavior when configuring relational fields as they already do in domain filters.
Original PR description
This commit evaluates the `isDebugMode` prop which is passed to ModelFieldSelector so that the component acts the same for Relational field selector as in Domain field selector. Task~6369639
This update standardizes how access tokens are retrieved and refreshed across supported social media channels. It helps ensure linked social accounts continue to work consistently when publishing or reading social content.
Original PR description
Purpose ======= Ensure the access tokens can be read, and unify the way we get them for all social medias. Update in SUDO the access token when linking an account. Task-6330626
This update refines the Time Off planning Gantt view as a follow-up to a previous improvement. It helps make leave planning information easier to display and manage for users working with employee absences.
Original PR description
for this pr: https://github.com/odoo/enterprise/pull/109537
Bank statement reconciliation has been optimized to avoid timeouts in large multi-company databases. This should make scheduled reconciliation jobs run much faster and more reliably, reducing delays in accounting operations.
Original PR description
The standard cron process reconciles batches of 100 bank statement lines at a time. In multi-company environments with large historical datasets, this query frequently timed out, exceeding the…
The standard cron process reconciles batches of 100 bank statement lines at a time. In multi-company environments with large historical datasets, this query frequently timed out, exceeding the 15-minute execution limit. Even when throttled to a batch size of 10 records, the query required approximately 18.8 seconds to execute. The performance degradation was driven by the following factors: 1. Suboptimal Lateral Filtering: The statement line batch array filter was placed inside the `LATERAL` block's `WHERE` clause. This prevented the query planner from optimizing the drive path effectively across iterations. 2. Inefficient Join Sequence and Filtering: The original join order scanned `account_move_line` before resolving the company hierarchy constraint. As a result, millions of rows across all companies were retrieved from the index, forcing repeated primary key lookups on `res_company` before ultimately discarding over 99.9% of the records via the late `parent_path` hierarchy filter. This commit addresses these issues by: 1. Moving the `st_line.id` filtering constraint out of the lateral subquery and into the outer main query block to guide the execution path properly. 2. Reordering the inner `LATERAL` subquery to resolve the company hierarchy (`res_company`) prior to joining `account_move_line`. This constraints the scan boundaries early in the pipeline. Performance Benchmarks (10 record batch): - Before Execution Time: ~18,818 ms - Before Shared Hit Blocks: 8,535,272 - After Execution Time: ~130 ms - After Shared Hit Blocks: 67,204 ms Before Plan: https://explain.dalibo.com/plan/h4739gh3519eaa43 After Plan: https://explain.dalibo.com/plan/5ebc5g8deff272gc Forward-Port-Of: odoo/enterprise#125686 Forward-Port-Of: odoo/enterprise#125250
Marketing automation synchronization is now prepared to focus on campaigns that are currently running, helping avoid unnecessary processing for inactive campaigns. The related enrollment tests were reorganized to make future improvements easier to maintain.
Original PR description
Add some filters on main API synchronization methods so that they are limited to running campaigns. Move enroll sepcific tests into a new test file to ease future updates. Prepares Task-6425785 [marketing_automation] Incremental sync
Resolved issues and error corrections
This fixes outdated internal test expectations for marketing automation after a previous change was merged. It helps keep performance monitoring accurate and reduces false alarms in automated checks, with no direct change for end users.
Original PR description
Finally forgotten when merging odoo/enterprise#66823
Field service shifts now keep equipment that users manually remove from the shift list, even after changing shift times or signing in. This prevents deleted serial-numbered equipment from reappearing while still refreshing equipment correctly when the customer changes.
Original PR description
Issue: When a user manually removes a specific equipment (SN) from a shift's list, editing the shift times or signing in reloads the entire list, bringing the deleted equipment back. Solution: Skip reassignment if the currently selected lots (`._origin`) are a valid subset of the customer's total equipment. This preserves manual deletions while still correctly updating the list if the customer is completely changed. Task: 6346404 Forward-Port-Of: odoo/enterprise#125040
This fix prevents incoming Chilean electronic document emails from repeatedly blocking mailbox processing when a recipient tax ID is missing. Instead of crashing, the system now handles the missing value through the existing validation flow, keeping email imports running reliably.
Original PR description
### Problem `Mail: Fetchmail Service` cron aborts with `AttributeError: 'NoneType' object has no attribute 'upper'` in `l10n_cl_edi/models/fetchmail_server.py::_process_incoming_customer_claim` when…
### Problem
`Mail: Fetchmail Service` cron aborts with `AttributeError: 'NoneType' object has no attribute 'upper'` in `l10n_cl_edi/models/fetchmail_server.py::_process_incoming_customer_claim` when an incoming customer claim DTE has no `<RUTRecep>`:
```python
dte.findtext('.//ns0:RUTRecep', ...).upper() or
dte.findtext('.//ns0:RutReceptor', ...).upper()
```
`findtext()` returns `None` when the tag is missing, so `.upper()` blows up before the `or` fallback can run. Once the cron hits such a message it re-crashes on every subsequent run and blocks the whole mailbox until the offending mail is deleted.
### Fix
Guard each `findtext(...)` with `or ''` so the `or` chain actually falls through. Empty `partner_vat` is already handled by the existing "Partner … has not been found" branch a few lines below.
### Traceback (Odoo 19)
```
File "/mnt/extra-addons/enterprise/l10n_cl_edi/models/fetchmail_server.py", line 285, in _process_incoming_customer_claim
dte.findtext('.//ns0:RUTRecep', namespaces=XML_NAMESPACES).upper() or
AttributeError: 'NoneType' object has no attribute 'upper'
```
### Ticket
No ticket open for this but opw-5257481 is related.
Forward-Port-Of: odoo/enterprise#123387Accrual report totals now display the correct combined amounts when users group purchase or sales accounting lines by dates. This prevents misleading zero totals in grouped views, helping accounting teams review bills to receive and related reports accurately.
Original PR description
Currently, when users group accrual reports by dates, aggregated computed fields are not calculated correctly. As a result, values such as the total amount may be displayed as zero even when the…
Currently, when users group accrual reports by dates, aggregated computed fields are not calculated correctly. As a result, values such as the total amount may be displayed as zero even when the grouped records contain non-zero amounts.
## Steps to produce:
- Install Purchase and Accounting
- Create a product `Energy drink Sample` with cost 10$
- Create and Confirm a PO with the energy drink sample with vendor as `Administrator`
- Set `Received` as 1.
- Go to Accounting > Review > Bill to Receive
- Search Filter> Remove vendor grouping > Use Custom Group `Order Date`
- Expand the group
## Observed Behavior
Although the grouped lines contain an amount of 10 dollars, the aggregated total displayed in the sum remains zero.
The total should reflect the combined value of the grouped lines.
## Root Cause:
This issue occurs because opening the view triggers `_read_group_for_accrual`, which overrides the `_read_group` method on purchase order lines. The purpose of this override is to support grouping on computed fields that are not stored in the database such as `amount_to_invoice_at_date (Amount)`, `qty_received_at_date (Received)`.
When `_read_group_for_accrual` is executed, it delegates grouping for non-computed fields to the parent `_read_group` implementation, as shown at [1].
The parent method returns results in `res` similar to:
```
[(datetime.datetime(2026, 6, 1, 0, 0), 1.0, 10.0, 1)]
```
During iteration over res at [2], the code uses `group[0]` as the grouping key. In this example, group[0] is `datetime.datetime(2026, 6, 1, 0, 0)`, which represents the granularity date
(e.g., the first day of the month when grouping by month).
However, `records_by_group` is keyed by the actual purchase order line order dates rather than the granularity dates returned by `_read_group`. For example:
```
{datetime.datetime(2026, 6, 12, 0, 0): purchase.order.line(1,)}
```
As a result, the lookup performed using the granularity date (`datetime.datetime(2026, 6, 1, 0, 0))` does not find a matching entry in `records_by_group`. Consequently, records falls back to an empty `purchase.order.line()` recordset.
Later, at [3], the aggregation logic computes totals using this empty recordset. Since the required fields are evaluated on an empty set of records, the aggregated values are computed as zero.
This ultimately causes the method to return a total value of zero
[1]-
https://github.com/odoo/enterprise/blob/eeea1377a7d36d11e140c44dee30a45228e7b4a6/account_accountant/models/analytic_mixin.py#L9-L24
[2]-
https://github.com/odoo/enterprise/blob/eeea1377a7d36d11e140c44dee30a45228e7b4a6/account_accountant/models/analytic_mixin.py#L40-L42
[3]-
https://github.com/odoo/enterprise/blob/eeea1377a7d36d11e140c44dee30a45228e7b4a6/account_accountant/models/analytic_mixin.py#L44-L47
## Solution:
The issue can be resolved by grouping records using the same date granularity specified in the groupby, rather than using the field values.
By aligning the grouping logic with the granularity returned by `_read_group` (for example, grouping by the first day of the month when using monthly grouping ), the keys in `records_by_group` match the values returned in `res`. As a result, the corresponding records are correctly retrieved during aggregation.
This ensures that the aggregation is performed on the appropriate purchase order lines instead of an empty recordset, allowing the computed totals to be calculated correctly.
[opw-6261225](https://www.odoo.com/odoo/project/49/tasks/6261225)
Forward-Port-Of: odoo/enterprise#120369Uruguayan export e-invoices that are fully offset by discounts now generate the required discount details correctly. This helps exporters issue valid zero-total documents for customs or incoterm scenarios and avoid rejection by Uruware validation.
Original PR description
## Problem When generating an export CFE (e-Factura Exportación) in the Uruguayan EDI module, invoices that include a discount line equal to the subtotal — resulting in a **total of 0.00** — were not…
## Problem When generating an export CFE (e-Factura Exportación) in the Uruguayan EDI module, invoices that include a discount line equal to the subtotal — resulting in a **total of 0.00** — were not handled correctly by the XML/CFE generation logic. This use case is valid and required by exporters who need to reflect the declared value of goods/services while invoicing at zero (e.g. to comply with customs or incoterm requirements such as FCA). In Uruware's validation portal, the "Descuentos y Recargos" (discounts & surcharges) section of the subtotal block must be correctly populated for the CFE to be accepted. **Example:** An invoice with a line of 648.00 UYU and a global discount of −648.00 UYU → Total: 0.00. The export value is still declared, taxes are zero, but the CFE must reflect the discount amount explicitly. <img width="592" height="679" alt="example_expo_invoice_discount" src="https://github.com/user-attachments/assets/aa83c158-e342-4da5-a251-fc209bbed5c4" /> ## Root Cause The CFE template (`cfe_template.xml`) and the move computation logic (`account_move.py`) did not account for the case where export invoices carry line-level or global discounts that zero out the total. The discount amount was either omitted from the XML nodes or computed incorrectly, causing Uruware validation to fail or the discount block to not render. ## Fix - **`l10n_uy_edi/models/account_move.py`** — Updated the export invoice computation to correctly include discount amounts in the CFE data dict, ensuring the `ValorDR` is filled with the value of the discount per line. - **`l10n_uy_edi/views/cfe_template.xml`** — Adjusted the template condition so `MntExpoyAsim` node accepts 0 as value. ## Steps to Reproduce (before fix) 1. Create an export invoice (e-Factura Exportación) for a foreign partner. 2. Add a product line with a unit price, e.g. 216.00 × 3 = 648.00 UYU. 3. Add a global discount of 648.00 (same amount) so the total is 0.00. 4. Confirm and send to Uruware — the CFE is rejected / discount block is missing. ## Verification After the fix, the same invoice generates a valid CFE accepted by Uruware with the discount correctly reflected in the `DscRcgGlobal` node and the discount line visible on the printed document. Forward-Port-Of: odoo/enterprise#124910 Forward-Port-Of: odoo/enterprise#120130
The Vietnam Sales Tax Report now shows VAT amounts consistently as positive values when users expand report details to the invoice level. This prevents confusion from sales tax amounts appearing negative in detailed views while totals remain positive.
Original PR description
## Current behavior: In Vietnam's Sales Tax Report, when unfolding until the minimum layer, the VAT now displays the value in negative ## Expected behavior: The VAT value in the minimum layer should…
## Current behavior: In Vietnam's Sales Tax Report, when unfolding until the minimum layer, the VAT now displays the value in negative ## Expected behavior: The VAT value in the minimum layer should be consistent with the upper layers and kept positive ## Steps to reproduce: - Install l10n_vn (l10n_vn_reports will install as well) - Switch to VN Company - With demo data, go to Invoicing / Reporting / Tax Report - Change Tax Report (VN) to Sales/Purchase Tax Report (VN) - Unfold the lines all the way to the minimum layer: VAT on sales of goods and services 10% -> INV/2026/00003 - Observe that the VAT 10% line is at negative, which is inconsistent with the Total line below ## Cause of the issue: - In Odoo, tax journal items store tax_base_amount with the accounting sign (negative for sales). This is expected behavior - However, Vietnamese VAT listing expects commercial amounts, which means sales bases need to be displayed as positive numbers ## Fix: Normalized tax_base_amount sign in _query_tax_lines function before building the SQL query opw-6344577 Forward-Port-Of: odoo/enterprise#125257 Forward-Port-Of: odoo/enterprise#122785
Sales order information on planning slots is now visible for companies using a single-company setup. This prevents users from missing key sales order links when viewing or editing planning slot forms.
Original PR description
The `sale_line_id` field was previously injected after `company_id`. Because the first instance of `company_id` in the base view is wrapped inside a `<t groups="base.group_multi_company">` block, the inserted fields were inadvertently hidden in single-company databases. This commit changes the XPath target to `role_id` to ensure the sales order fields are always visible in the planning slot form view, regardless of multi-company settings. task: 6398673 Forward-Port-Of: odoo/enterprise#125712
Odoo Social Marketing now disables the reply option for Twitter posts when Twitter does not permit a reply, such as posts that do not mention the company account or quote one of its tweets. This helps prevent accidental or automated replies that would fail or risk unwanted outreach.
Original PR description
Purpose ======= To prevent LLM from spamming Twitter users, Twitter does not allow to reply to a tweet if we are not mentioned in it, or if the tweet does not quote one of our tweet. For that reason, we disable the reply button when needed. Task-5964524 Forward-Port-Of: odoo/enterprise#125739 Forward-Port-Of: odoo/enterprise#112161
Mexican payroll can now calculate expected work hours even when a payslip has not yet been created. This helps off-cycle payroll runs and related checks produce consistent attendance and work-hour results earlier in the process.
Original PR description
Previously, the `_preprocess_work_hours_data` method would abort early if no payslip was found for the given period. This prevented the correct generation or evaluation of expected Mexican work hours…
Previously, the `_preprocess_work_hours_data` method would abort early if no payslip was found for the given period. This prevented the correct generation or evaluation of expected Mexican work hours in contexts where a draft payslip does not yet exist (i.e., when an off-cycle payslip is initially generated for a given time period). To resolve this, the strict dependency on the payslip record has been removed. It now falls back to the contract version's base data when a payslip is absent: - The calendar defaults to the contract version's `resource_calendar_id`. - The duration is assumed to be standard (`is_wrong_duration = False`). - The Mexican schedule table (`l10n_mx_schedule_table`) is fetched globally from the environment (`hr.rule.parameter`) rather than relying on the payslip-specific helper method. This ensures expected work hours and attendance fields are calculated consistently across all payroll workflows, regardless of whether the payslip has been instantiated. opw-6351402 Forward-Port-Of: odoo/enterprise#125219
Users without certain Planning or Project permissions can now open the product catalog from sales quotations without hitting an access error. The fix checks user permissions before reading restricted field service or planning information, keeping sales workflows usable for limited-access users.
Original PR description
A user without Project rights cannot add a product from the catalog on a sale order Steps to reproduce: 1. Install industry_fsm_sale module 2. Go to Settings > Users & Companies > Users and open user Marc Demo 3. Set Field Service and Project rights to No 4. Log in as Marc Demo 5. Go to Sales and open any quotation 6. Click on Catalog in the order lines 7. An access error is raised Issue: industry_fsm_sale overrides `action_add_from_catalog` and tries to read sale.order.tasks_ids but users can't always access this field as it requires Project rights Solution: Check that the user has Project rights before trying to read tasks_ids opw-6315647 Forward-Port-Of: odoo/enterprise#125526 Forward-Port-Of: odoo/enterprise#123228
The Australian payroll scheduled data update now restores required rule category data before updating salary rules. This prevents the scheduled action from failing if payroll rule categories were previously deleted, helping payroll maintenance run reliably.
Original PR description
Currently, an error occurs when the "Payroll: Update Data" scheduled action is run. **Steps to Reproduce:** - Install `l10n_au_hr_payroll` with demo data. - Switch to `Australian Company`. - Go to…
Currently, an error occurs when the "Payroll: Update Data" scheduled action is run. **Steps to Reproduce:** - Install `l10n_au_hr_payroll` with demo data. - Switch to `Australian Company`. - Go to `Payroll` > `Configuration` > `Salary` > `Rule Categories`. - Delete all records related to the `Australian Company`. - Go to `Scheduled Actions` and run `Payroll: Update Data`. `ValueError: External ID not found in the system: l10n_au_hr_payroll.rule_category_ote` After [this commit], the category_id field becomes non-required, allowing users to delete a rule category record even if it is linked to a salary rule. When updating the data file [1], an error is raised due to the missing rule category. This commit ensures that when updating the salary rule data, it updates the category data beforehand as like [here] [this commit]: https://github.com/odoo/enterprise/commit/c663fd2a81b7f6b34f8199fdbdc4a75c4f21379e [1] https://github.com/odoo/enterprise/blob/b6612dd58276646b81a3a12cd48e8427ea5359c2/l10n_au_hr_payroll/models/hr_payslip.py#L76-L83 [here]: https://github.com/odoo/enterprise/blob/b6612dd58276646b81a3a12cd48e8427ea5359c2/l10n_ch_hr_payroll/models/hr_payslip.py#L1074-L1087 sentry-7349905716 Forward-Port-Of: odoo/enterprise#121167
Guatemalan credit notes now reference the original invoice’s actual issue date instead of a technical certification timestamp. This helps ensure electronic documents comply with SAT validation rules and reduces the risk of rejected credit notes.
Original PR description
### Issue before this commit: When reverting a Guatemalan invoice (creating a credit note), the XML node FechaEmisionDocumentoOrigen incorrectly reports the EDI document's technical certification…
### Issue before this commit: When reverting a Guatemalan invoice (creating a credit note), the XML node FechaEmisionDocumentoOrigen incorrectly reports the EDI document's technical certification date instead of the original invoice's emission date. This causes the SAT to reject the document. ### Steps to reproduce the issue: 1. Download Accounting and l10n_gt 2. Revert an invoice (credit note) inserting a different date than the one of the invoice 3. See that FechaEmisionDocumentoOrigen report the date of the credit note instead of the one of the invoice ### Cause of the issue: The _l10n_gt_edi_add_reference_values method extracted the date from original_document.datetime (the technical timestamp of when the XML was generated) rather than using the actual accounting date of the original invoice. ### Reason to introduce the fix: SAT validation rules strictly require the reference date to match the exact commercial emission date of the original invoice. Fetching invoice_date directly ensures compliance, avoids timezone conversion errors, and prevents the XML from being rejected. Source: https://www.lawinsider.com/es/contracts/dJXl4Vo79L2 <img width="730" height="205" alt="2026-07-17_10-19" src="https://github.com/user-attachments/assets/802e7bb3-fcf9-48db-b86f-227b494001b6" /> opw-6394409 Forward-Port-Of: odoo/enterprise#125788 Forward-Port-Of: odoo/enterprise#124794
Marketing Automation campaigns no longer trigger an error when a user clears the Target field while editing a campaign. This keeps campaign setup stable and avoids an unexpected interruption in the user workflow.
Original PR description
Currently, an error occurs when a user removes the target model from a marketing campaign. **Steps to Reproduce:** - Install the `marketing_automation` module. - Go to `Marketing Automation` >…
Currently, an error occurs when a user removes the target model from a marketing campaign. **Steps to Reproduce:** - Install the `marketing_automation` module. - Go to `Marketing Automation` > `Campaigns`. - Create a `new campaign` and clear the `Target` field. `KeyError: False` After the recent commit that added the recipients_count field and its computation [1], when the user removes model_id(Target), model_name is set to False [2]. The domain is then updated by a compute method, which triggers the computation of recipients_count. Since the computation only checks whether domain is set and does not verify that model_name is available, it attempts to access the model using model_name, raising the error [3]. This commit ensures that, when computing the recipient count, it also checks that model_name is set. Since model_id is a required field, once it is set, the recipient count is computed correctly based on the domain and model_name. [recent commit]: https://github.com/odoo/enterprise/commit/5485e8eaa7636c7dd0b305b4e26fb772aff6d030 [1]: https://github.com/odoo/enterprise/blob/1cbb21eaf0f24cedb4cc18a31065a76b1dd9783e/marketing_automation/models/marketing_campaign.py#L43 [2]: https://github.com/odoo/enterprise/blob/1cbb21eaf0f24cedb4cc18a31065a76b1dd9783e/marketing_automation/models/marketing_campaign.py#L33 [3]- https://github.com/odoo/enterprise/blob/1cbb21eaf0f24cedb4cc18a31065a76b1dd9783e/marketing_automation/models/marketing_campaign.py#L146-L148 sentry-7612724367 Forward-Port-Of: odoo/enterprise#124649
The Malaysia Statement of Account PDF now calculates total and overdue amounts using the selected statement date. This ensures the totals match the displayed balance lines, improving accuracy for historical customer account reporting.
Original PR description
## Current behavior: In Malaysia's Statement of Account, the total and total overdue amounts dont consider the selected Statement Date, and will calculate all the balances up until today in the…
## Current behavior: In Malaysia's Statement of Account, the total and total overdue amounts dont consider the selected Statement Date, and will calculate all the balances up until today in the generated PDF report ## Expected behavior: The total and total overdue amounts should only sum the balances included in the report up until the selected Statement Date ## Steps to reproduce: 1. Install l10n_my_reports module, switch to Malaysian company 2. Go inside Invoicing > Report > Aged receivable 3. Select a specific date in the past 4. Observe that the total amounts dont match with the balance column, and wont change regardless of the date selected ## Cause of the issue: The template used o.total_overdue which ignores the report domain and statement date ## Fix: Accumulate overdue_total in the template loop with the same domain and date_to cutoff as the balance lines, so it always matches the displayed Balance lines for the selected Statement Date opw-6332970 Forward-Port-Of: odoo/enterprise#125410 Forward-Port-Of: odoo/enterprise#123694
This fixes an internal test setup for Indian payroll so percentage calculations are checked using dedicated sample employee data. It helps prevent unrelated employee payroll values from affecting test results, without changing payroll behavior for users.
Original PR description
Use a dedicated employee/version for the percentage computation test instead of Rahul, whose existing payroll values affect copied version data. Define the test amounts in common and reuse `employee.version_id` in the test, so percentages are derived from amounts without changing payroll behavior. task-6340923 Forward-Port-Of: odoo/enterprise#124330 Forward-Port-Of: odoo/enterprise#121918
Japanese Zengin bank statement files from some banks can now be imported even when they use unusual or missing line breaks. This prevents valid bank statement files from being rejected and improves reliability for companies reconciling Japanese bank accounts.
Original PR description
Some banks export Zengin bank statement files as a single continuous string with no `\r\n` separators (or using a bare `\n`). The parser split only on `\r\n`, so such a file produced one oversized "record" that failed the header/transaction length checks and could not be imported. Split on line breaks when present (self-correcting per record), and only fall back to fixed-length record chunking when the file has no separators at all. That fallback needs the record width. The parser took it as 199 characters for transfers (type code `01`) and 200 for deposit/withdrawal, but there is no such distinction: every Zengin record of every statement type is padded to 200 characters. Use a single `ZENGIN_RECORD_LENGTH` of 200 everywhere, and pad the test fixtures, which had their trailing filler trimmed to 199. task-6375791
Swiss payroll contract templates have been aligned with the employee contract view so the same wage-related fields are available. When a template is loaded for an employee, key details such as hourly wage and wage type now carry over correctly, reducing manual corrections and payroll setup errors.
Original PR description
## Issue When creating a Contract Template for a Swiss company, the template does not match the version shown in the Employee's view. Also, some fields are not correctly applied when loading a…
## Issue
When creating a Contract Template for a Swiss company, the template does not match the version shown in the Employee's view. Also, some fields are not correctly applied when loading a contract template on an employee (e.g. `hourly_wage`, `wage`, ...).
## Steps to reproduce
1. Install *Switzerland - Swissdec Certified ELM 5.0 - Payroll* (`l10n_ch_hr_payroll`)
2. (Create and) Use a Swiss company
3. In Employees > Configuration > Contract Templates, create a Contract Template
- Wage Type: Hourly Wage
- Hourly Wage: Any value > 0
- **(Notice how the aforementionned fields are missing from the template)**
4. In Employees > Employees, create an Employee
5. On the new employee's view, on the Payroll tab, click "Load Template"
and load the template created in step 3
6. **The data from the template is not applied to the employee's contract**
## Cause
The fields loaded from a contract template are listed in the `whitelist` variable of the `hr.version.wizard`:
https://github.com/odoo/odoo/blob/5c3deb11627f4d6762c4994207bd582afb96f064/addons/hr/wizard/hr_contract_template_wizard.py#L15-L30
Multiple fields were missing from the whitelist (e.g. `hourly_wage`, `l10n_ch_has_{hourly|monthly|lesson}`, ...). These fields would not be loaded from the template when applying a template on an employee.
**This commit replicates the employee's version view on the contract template and adds the related fields to the whitelist for them to be correctly applied when loading a contract template.**
opw-5966664
opw-6128467
Forward-Port-Of: odoo/enterprise#125435
Forward-Port-Of: odoo/enterprise#110683Draft invoices no longer show the vehicle field as a clickable link on invoice lines. This keeps draft invoice behavior consistent with products and prevents users from opening related vehicle records before the invoice is posted.
Original PR description
The vehicle under account on the invoice lines should not be clickable when the invoice is in draft. Only when it is posted, like the product. task-6385436 Forward-Port-Of: odoo/enterprise#125688 Forward-Port-Of: odoo/enterprise#124514
Manufacturing planning now uses the product's bill of materials batch size even when the BOM was not manually selected while adding the product to the Master Production Schedule. This prevents under-planning replenishment quantities and helps production teams generate more accurate manufacturing plans.
Original PR description
In MPS, if a product’s Bill of Materials (BOM) is not specified at the time of addition, the system will not correctly account for batch size. Steps to reproduce: ------------------- * Create a…
In MPS, if a product’s Bill of Materials (BOM) is not specified at the time of addition, the system will not correctly account for batch size. Steps to reproduce: ------------------- * Create a product with a bom that has a batch size of 2 * Open MPS * Add the product - without specifying the bom - Route Manufacture * Add 1 in the Forcast Demand -> the batch size from the bom it's not taken into account. Observation: ------------- When updating mps, it will call get_production_schedule_view_state: https://github.com/odoo/enterprise/blob/7092dd2cc3578c3f22d1fbc82d958d57e2f93553/mrp_mps/models/mrp_mps.py#L424 this function when calculating the quantity to resplenish will call _get_resplenish_qty: https://github.com/odoo/enterprise/blob/7092dd2cc3578c3f22d1fbc82d958d57e2f93553/mrp_mps/models/mrp_mps.py#L534 to know the quantity to resplenish it will need the batch size, in mps they will only consider the batch size from the bom registered: https://github.com/odoo/enterprise/blob/7092dd2cc3578c3f22d1fbc82d958d57e2f93553/mrp_mps/models/mrp_mps.py#L863-L865 Since there is no default value for bom_id, If there is no bom selected, there is no batch size. opw-6259956 Forward-Port-Of: odoo/enterprise#124922 Forward-Port-Of: odoo/enterprise#119560
Timesheet descriptions in the assistant now expand automatically so long entries can be read in full instead of being cut off. This helps users review and edit detailed time entries without losing important context.
Original PR description
- changed the description field to expand dynamically to display long descriptions in full instead of truncating them in the assistant Task-6348575 Forward-Port-Of: odoo/enterprise#125536 Forward-Port-Of: odoo/enterprise#123428
Payroll salary rule account settings are no longer overwritten when another app, such as POS, triggers accounting setup steps. This protects manual payroll accounting configurations from being reset unexpectedly.
Original PR description
### Steps to reproduce: - In a database with Switzerland localization, install 'Accounting' and 'Payroll' - Manually change the debit and credit accounts on the Swiss ELM salary rules (rule code…
### Steps to reproduce: - In a database with Switzerland localization, install 'Accounting' and 'Payroll' - Manually change the debit and credit accounts on the Swiss ELM salary rules (rule code 1000) - Install 'POS' - Check the accounts you configured on the salary rules >The accounts are reset to their default values ### Cause of Issue: POS depends on the module `stock_account`. When `stock_account` is installed, the `_configure_journals` method in its `__init__.py` creates a new `account.journal` for inventory valuation. To apply default values to this journal, the method retrieves data from the chart template. https://github.com/odoo/odoo/blob/7d16ef88784e18e885b97dbded3231775f1349d2/addons/stock_account/__init__.py#L41 The `hr_payroll_account` module overrides `_post_load_data` and unconditionally calls `_load_payroll_accounts(template_code, company)`. https://github.com/odoo/enterprise/blob/fcf06997a0eb999af86e4b6917311a86f04a390e/hr_payroll_account/models/account_chart_template.py#L16-L18 This triggers the reinstallation of the default payroll accounts, which overwrites and discards any manual configuration changes the user has made to their salary rules. ### Fix: Ensure that default payroll accounts are only reset during a genuine chart of accounts loading process, and not during localized post-load operations triggered by other modules. opw-6251112 Forward-Port-Of: odoo/enterprise#121687
Opening the Scrap action from a new manufacturing barcode operation no longer causes an error when no location record is available yet. This also prevents a related crash when scanning products on new manufacturing orders with consignment enabled, improving reliability for warehouse and production users.
Original PR description
Versions -------- - 18.0+ Steps ----- 1. Open Barcode app; 2. click Operations; 3. click MANUFACTURING 4. click New; 5. click cogwheel on top right; 6. click Scrap. Issue ----- Traceback: > Error: Record stock.location with id=undefined doesn't exist in the cache Cause ----- When setting up the default context for the scrap menu, it it assumes `this.record` is not empty. Solution -------- Make `cache.getRecord` not raise an error when a location isn't found. Use optional chaining for other parts of the context that rely on a `record` being present. Also fixes a related issue introduced by 4b457fe, where the same traceback would be thrown on opening a new MO and scanning a product whilst consignment is enabled. opw-6397774 Forward-Port-Of: odoo/enterprise#125571 Forward-Port-Of: odoo/enterprise#124818
Fixed an issue that could cause the Planning Gantt view to crash when users grouped shifts by role and a role had no assigned resource or working schedule. This improves reliability for planning teams using role-based scheduling and custom date ranges.
Original PR description
Currently, an error occurs when grouping planning slots by role. **Steps to Reproduce:** - Install the `Planning` module. - Go to `Planning` > `Configuration` > `Roles`. - Create a `role` without…
Currently, an error occurs when grouping planning slots by role.
**Steps to Reproduce:**
- Install the `Planning` module.
- Go to `Planning` > `Configuration` > `Roles`.
- Create a `role` without assigning any resource to it (or assign a resource without a working time).
- Go to `Planning`, create a new `planning slot`, assign the `role` created above, set the start date to `20/07/2026 12:00 PM` and the end date to `21/07/2026 2:00 AM`.
- Switch to the `Gantt view` of the `planning slots`.
- Group by `Role` and set the custom date range to `07/19/2026 -> 07/20/2026`, then click `Apply`.
`KeyError: 1`
The error occurs when the user groups the planning slots by role in the Gantt view. During
the computation of the Gantt progress bar, if the existing slot's role has no resource, or has
a flexible resource without a calendar, the regular resources become empty [1]. Then it
attempts to compute the valid work intervals for these empty resources [2], resulting in an
empty calendar work interval dictionary ({}) [3]. Later, when computing the duration over the
period with the valid range slots, it tries to access the resource directly from the empty
calendar_intervals dictionary [4], which raises the error.
This commit ensures that, when no work intervals are available for a resource, an empty
work interval is used instead.
[1]- https://github.com/odoo/enterprise/blob/3871b75fb74a7b35bfea9610ca08b853eb723320/planning/models/planning_slot.py#L307
[2]: https://github.com/odoo/odoo/blob/5663509fe5caa1191fafcea3b3879dcef9ceca8f/addons/resource/models/resource_resource.py#L220
[3]: https://github.com/odoo/enterprise/blob/3871b75fb74a7b35bfea9610ca08b853eb723320/planning/models/planning_slot.py#L3415-L3417
[4]- https://github.com/odoo/enterprise/blob/3871b75fb74a7b35bfea9610ca08b853eb723320/planning/models/planning_slot.py#L3300
sentry-7620222164
Forward-Port-Of: odoo/enterprise#125930
Forward-Port-Of: odoo/enterprise#124991This update corrects how Belgian payroll notification files are analyzed. It helps ensure payroll declarations are processed more reliably, reducing the risk of errors when handling official ONSS notifications.
Original PR description
Forward-Port-Of: odoo/enterprise#125500
Fixed Chilean invoice PDFs so the legally required CEDIBLE disclaimer is always shown in Spanish, regardless of the customer's language settings. This helps ensure printed invoice copies remain compliant with Chilean requirements.
Original PR description
Steps to reproduce: - Set the database language to Spanish (Latin America). - Create a customer invoice, confirm it and send it to the SII. - Print it using Print > Invoice PDF copy (Chile). - Scroll…
Steps to reproduce:
- Set the database language to Spanish (Latin America).
- Create a customer invoice, confirm it and send it to the SII.
- Print it using Print > Invoice PDF copy (Chile).
- Scroll to the CEDIBLE section at the bottom of the PDF.
Cause of the issue:
The CEDIBLE footer is merged into l10n_cl.report_invoice_document, which account.report_invoice (odoo/addons/l10n_cl/views/report_invoice.xml) renders with t-lang set to the invoice partner's lang, not the database/user language. The disclaimer text was hardcoded in English and relied on the regular translation to be shown in Spanish, so as
soon as the partner's lang field isn't Spanish, the translation lookup falls back to the untranslated English source, regardless of the database language.
Solution:
This disclaimer is boilerplate mandated by Chilean law: it must always be printed in Spanish, independently of the invoice partner's or current user's language. The same template already follows that rule a few lines above for the SII stamp block ("Timbre Electrónico SII..."), which is hardcoded in Spanish instead of relying on translation.
opw-6390207
Forward-Port-Of: odoo/enterprise#125463
Forward-Port-Of: odoo/enterprise#124916This fixes how Swiss payroll declarations check the status of BVG-LPP pension fund submissions. The fund number is no longer included where it should not be, helping avoid incorrect status lookups or rejected declaration handling.
Original PR description
Forward-Port-Of: odoo/enterprise#126040
The Belgian Partner VAT Listing now always uses the required calendar year, from January 1 to December 31. This prevents incorrect reporting periods for companies whose fiscal year does not match the calendar year, improving compliance accuracy.
Original PR description
The Belgian Partner VAT Listing must always report on the civil calendar year (01/01/N to 12/31/N). Previously, the report was relying on the company's fiscal year configuration, which caused incorrect reporting periods for companies with non-calendar fiscal years. This commit overrides `_custom_options_initializer` to strictly enforce a civil year date range based on the selected year, entirely ignoring custom fiscal year boundaries. Task-6086513 Forward-Port-Of: odoo/enterprise#125887 Forward-Port-Of: odoo/enterprise#114337
This fix prevents the Mexican e-invoicing status check from repeatedly reprocessing the same documents and potentially running indefinitely. It prioritizes older customer invoices, limits vendor bill checks to a shorter period, and reduces unnecessary background processing that could affect system performance.
Original PR description
While trying to fix the SAT cron, we did not think it through it could cause infinite cron triggering. Indeed, the write_date is updated on every record that is handled. Fix is manyfold: - Avoid…
While trying to fix the SAT cron, we did not think it through it could cause infinite cron triggering. Indeed, the write_date is updated on every record that is handled. Fix is manyfold: - Avoid re-processing what we already check within the last 4 hours/12 hours depending on the type of the document. - The domain takes the *static* create date instead of the write_date to make sure we don't endless re-process the same record and that the window of 7/60 days applies. - Limit the Vendor Bill to be checked only during 7 days after their creation. - Use the create_date in the order of the search to ensure we process older records first, before their time-window closes. - Process the Vendor Bills last, this ensure Customer Invoices will be processed in priority in case we are not able to process everything within the last 4/12 hours. This is still imperfect and a little fragile, we will find a better solution in master, most likely by adding a dedicated field to keep track of the last SAT check. See https://github.com/odoo/enterprise/pull/123213 See https://github.com/odoo/enterprise/pull/103272 task-none Forward-Port-Of: odoo/enterprise#125598 Forward-Port-Of: odoo/enterprise#125317
Swiss employee payslips now show the actual contract withdrawal date instead of a related version end date. This helps ensure payroll reports display the correct employment end information when those dates differ.
Original PR description
The Withdrawal Date in the payslip of CH employees was printing the date_end relative to the version related to the payslip. Instead, it should print the end of the contract of that version, since they can be different. The end date of the contract is in l10n_ch_withdrawal. Task: 6398291 Forward-Port-Of: odoo/enterprise#124848
Code cleanup and technical improvements
This update refreshes internal component wiring to align with the latest Owl framework behavior. It helps keep several Odoo Enterprise apps maintainable and compatible without changing user-facing features.
Original PR description
Follow-up of the community commit removing `useChildRef` and `useForwardRefToParent`: Owl 3 refs are signals, so a parent creates its ref with `signal.ref()`, hands it to the child (which binds it with `t-ref`) and reads the element by calling it instead of through `.el`.
Default values for certain records are now initialized per record instead of being shared globally, reducing the risk of confusing or unintended behavior. The WhatsApp composer patch was also cleaned up to avoid copying stray data onto the shared model definition.
Original PR description
A plain value on a model prototype, typically from patch(Model.prototype, { flag: false }), is shared data: every record of the model reads the same value, and nothing tells a reader whether it got a default or a value set on the record. Such defaults belong to the record, so they move into setup().
The whatsapp composer went through Object.assign with a stray name argument between the target and the values, so the characters of that name were copied onto the prototype as numeric keys. It uses patch() like every other model patch.
https://github.com/odoo/odoo/pull/279104