Daily updates from Odoo
Navigate
Branch
Wednesday, August 5, 2026
345 changes
8 changes
Enhancements to existing features
SEPA direct debit batch validation has been optimized to handle large payment batches more efficiently. Businesses processing hundreds or thousands of payments should see shorter validation and notification times, reducing delays during payment collection workflows.
Original PR description
- Replace the `id:recordset` aggregation in `_get_expiry_date_per_mandate()` with `date:max` to compute the latest payment date directly in SQL. - Render `email_from` for all payments in batch and cache the computed authors by sender email to avoid repeated partner lookups during SDD pre-notification. This reduces ORM/cache overhead when validating large SEPA batches containing thousands of payments. Measured on a production-sized database: | metric | before | after | factor | |--------|-------:|------:|-------:| | `_get_expiry_date_per_mandate` (500 payments) | 564 ms | 111 ms | ~5x | | `_send_after_validation` notification (500 payments) | 92.9 s | 55.7 s | ~1.7x | | `_get_expiry_date_per_mandate` (1000 payments) | 890 ms | 178 ms | ~5x | | `_send_after_validation` notification (1000 payments) | timed out (>159 s) | 108.9 s | completed | OPW-6377340 Forward-Port-Of: odoo/enterprise#126429 Forward-Port-Of: odoo/enterprise#125439
Resolved issues and error corrections
Bank transaction imports now ignore archived bank account records when automatically identifying the partner. This prevents old or inactive bank details from assigning transactions to the wrong partner, improving reconciliation accuracy.
Original PR description
Steps to reproduce: - Have a partner with a bank account, then archive the res.partner.bank record (keep the partner active). - Import or create a bank transaction (e.g. via bank sync) whose account number matches that archived bank account, and whose label/payment_ref would otherwise match a reconciliation model for a different partner. - Let the transaction go through automatic partner retrieval. => The archived bank account's partner is assigned, even though a normal manual entry (which skips the account-number match) would have used the label instead. Cause of the issue: `AccountBankStatementLine._retrieve_partner()` matches statement lines to partners in batch using raw SQL joining `res_partner_bank`. The query's WHERE clause filters out archived partners (`AND partner.active`) but never filters `res_partner_bank.active`. opw-6340479 Forward-Port-Of: odoo/enterprise#124748 Forward-Port-Of: odoo/enterprise#124537
The Helpdesk unanswered filter now treats automatic acknowledgement messages as already answered. This prevents newly submitted website tickets from being incorrectly flagged as needing a customer response, helping teams focus on genuinely unanswered conversations.
Original PR description
Steps to reproduce: --------- - install website_helpdesk - set an email address on the company partner if it is empty ( it is empty in a database without demo data). - generate a ticket from the website. - apply the Unanswered filter. Issue: ------ system generated acknowledgement message is considered an unanswered customer reply. Fix: -------- system generated acknowledgement messages are now considered answered. task-5138678 Forward-Port-Of: odoo/enterprise#125977
This change corrects test setup data for Belgian POS blackbox modules so automated checks no longer fail with repeated component errors. It improves reliability of internal validation without changing business workflows or user-facing behavior.
Original PR description
### Issue: During RunBot single module tests, some tests caused an error: `Maximum call stack size exceeded` after repeated: `[Owl] Unhandled error. Destroying the root component` ### Affected tests:…
### Issue:
During RunBot single module tests, some tests caused an error: `Maximum call stack size exceeded` after repeated: `[Owl] Unhandled error. Destroying the root component`
### Affected tests:
- `sign_money_in_out.called at right time`
- `sign_drawer_open.called at right time`
- `sign_work_in.called when opening register, setting & resetting cashier`
- `sign_work_in_employee.called from login screen (closed session)`
### Cause:
The tests passed `dialogData: {}` to the component env But `dialogData` must at least define `scrollToOrigin`, which is called automatically in `onWillDestroy`:
https://github.com/odoo/odoo/blob/0042e83fb60353a49d4759a79a3ceb0eee6f74b6/addons/web/static/src/core/dialog/dialog.js#L122-L126
Calling `scrollToOrigin()` on an empty object raises a `TypeError`, which Owl catches and re-throws repeatedly until the call stack is exceeded
The full `dialogData` shape is defined in `makeDialogMockEnv`: https://github.com/odoo/odoo/blob/62c540d96fc49d9e74d8c660019754651cb0e085/addons/web/static/tests/_framework/env_test_helpers.js#L151-L161
### Steps to reproduce:
- Install `l10n_be_pos_blackbox` (fresh `-i`, or `-u` with `web` on an existing db)
- Run the tests in MobileWebSuite
Before the fix, the errors are triggered
runbot-941232
Forward-Port-Of: odoo/enterprise#125474The aged payable and receivable report drill-down now hides fully paid invoices and bills, so users only see items that were actually outstanding. It also respects the selected report date, improving accuracy for historical balance reviews.
Original PR description
Steps to Reproduce: 1. Create a vendor/customer with multiple bills/invoices. 2. Fully pay one or more, leaving at least one still open for the same partner. 3. Open Accounting > Reporting > Partner…
Steps to Reproduce:
1. Create a vendor/customer with multiple bills/invoices.
2. Fully pay one or more, leaving at least one still open for the same partner.
3. Open Accounting > Reporting > Partner Reports > Aged Payable/Receivable.
4. Set to any date and click into an aging bucket for that partner.
Issue:
The drill-down list shows fully settled bills (residual = 0.00) alongside genuinely outstanding ones. Only surfaces when the partner has at least one open balance — if everything is paid, there is no bucket to click into.
Root Cause:
aged_partner_balance_audit builds the drill-down domain filtering only by reconcile flag, journal type, and date range — never checking residual. Additionally it completely overwrites the XML action domain (account.action_amounts_to_settle) which already had ('amount_residual', '!=', 0), losing that protection entirely.
Fix:
Added ('residual_at_date', '!=', 0) to the domain in aged_partner_balance_audit and set recon_limit in the action context so residual_at_date computes as of the report's 'as of' date rather than today's value:
action['context'] = {
'recon_limit': options['date']['date_to'],
}
Without recon_limit, residual_at_date falls back to amount_residual (today's value) which incorrectly excludes bills that were genuinely open on the report date but paid after it.
Result:
The drill-down now correctly shows only genuinely outstanding items regardless of whether the report is run as of today or a historical date.
opw 6333699
Forward-Port-Of: odoo/enterprise#126021Fixed an issue that prevented users from confirming multiple Brazilian customer invoices at once when Avalara Brazil tax mapping was enabled. This removes an error during batch validation, allowing finance teams to process invoices together as expected.
Original PR description
**_Steps to reproduce:_** * Install `l10n_br_avatax` and configure Avalara Brazil. * Create at least two customer invoices. * Ensure the fiscal position is set to **Automatic Tax Mapping (Avalara…
**_Steps to reproduce:_** * Install `l10n_br_avatax` and configure Avalara Brazil. * Create at least two customer invoices. * Ensure the fiscal position is set to **Automatic Tax Mapping (Avalara Brazil)**. * Select the invoices and click **Action → Confirm Entries**. **_Observed behavior:_** * A traceback is raised with `ValueError: Expected singleton: account.move(...)` and the invoices cannot be validated. **_Cause:_** * During tax extraction, `_extract_tax_values_from_l10n_br_avatax_detail` accesses `self.invoice_filter_type_domain` while `self` may contain multiple `account.move` records. * Accessing `invoice_filter_type_domain` on a multi-recordset raises an `Expected singleton` error, preventing the validation of multiple invoices. **_Fix:_** * Build the returned tax values by iterating over each invoice in the recordset and using the corresponding `invoice_filter_type_domain`. * This ensures `_extract_tax_values_from_l10n_br_avatax_detail` correctly handles multiple invoices during validation without raising a singleton error. opw-6334761 Forward-Port-Of: odoo/enterprise#126437 Forward-Port-Of: odoo/enterprise#124993
This fix prevents appraisal survey records from failing when the allowed survey type list is empty or unavailable. It helps ensure appraisal-related survey configuration continues to load reliably, including during upgrades.
Original PR description
Avoid a TypeError in _compute_allowed_survey_types when allowed_survey_types is False by falling back to an empty list before unpacking and appending the appraisal survey type.
```py
File "/home/odoo/src/enterprise/saas-19.3/hr_appraisal_survey/models/survey_survey.py", line 33, in _compute_allowed_survey_types
survey.allowed_survey_types = [*survey.allowed_survey_types, 'appraisal']
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: Value after * must be an iterable, not bool
```
Ref: https://github.com/odoo/odoo/pull/268125
Bug introduced in: https://github.com/odoo/enterprise/commit/896f54532338b07265722cb4a4161131d408f58c
upg-[4458975](https://upgrade.odoo.com/odoo/request/4458975?debug=1)
Forward-Port-Of: odoo/enterprise#124417The manufacturing planning tests were adjusted to match how monthly demand now counts the full current day. This helps ensure replenishment planned later on the same day is correctly reflected in forecast suggestions, reducing the risk of planning validation errors.
Original PR description
Updated the forecast suggestion test expectations after monthly demand was updated to count the full current day, so same-day orderpoint replenishment moves scheduled later in the day are also included Community PR: odoo/odoo#262435 TaskID-5490137 Forward-Port-Of: odoo/enterprise#126578 Forward-Port-Of: odoo/enterprise#115944
26 changes
New functionality added to Odoo
Adds a dedicated Romanian Declarația 390 report so businesses can prepare the required monthly EU cross-border transaction declaration in Odoo. The update includes ANAF-compatible XML export, declarant details collection, corrective filing support, and more accurate audit drill-downs for EC sales report lines.
Original PR description
This commit introduces a new module, 'Romania - EC Sales D390 Report'. For the support of Declarația 390 report as an EC List report for Romania in stable versions. Romanian localization has…
This commit introduces a new module, 'Romania - EC Sales D390 Report'.
For the support of Declarația 390 report as an EC List report for Romania in
stable versions.
Romanian localization has different requirements for the
EC Sales List report. So the generic EC Sales List does not work in the case of
Romania.
LEGAL REQUIREMENTS:
- Romanian tax authority accepts the Declarația 390 (Form 390) report for
cross-border transactions within the European Union.
- This declaration is filed on a monthly basis.
- The declaration must be submitted electronically to ANAF by the 25th of the
month following the month in which the transactions occurred. For example,
the declaration for transactions made in July must be filed by August 25th.
- The declaration must include all the intra-community transactions. These
transactions include:
1. Intra-Community acquisition of Goods
2. Intra-Community acquisition of Services
3. Intra-Community triangular trades
4. Intra-Community supplies of Goods
5. Intra-Community supplies of Services
REQUIRED FORMAT:
- Declarația 390 must be submitted electronically in a specific XML format.
The structure of this XML file is defined by ANAF.
- To facilitate compliance, ANAF provides a free software application called
'DUKIntegrator'. This tool allows businesses to:
1. Validate the generated XML file against the official schema to ensure it is
correctly formatted.
2. Generate the final PDF file with the XML attachment, which is the official
format for submission.
TECHNICAL DETAILS:
- Implemented the tax returns for the D390 EC Sales List report filing.
- Implemented XML export file generator, which creates the whole D390 XML report
with the required schema format.
- The D390 report needs to have the declarant's details in the report, the
attributes like 'nume_declar(Middle Name)', 'prenume_declar(First Name)',
'functie_declar(Job Position)' and 'adresa(Fiscal Domicile Address)'.
For collecting these details, we've created a wizard that will be on the
return validation action. Along with these details, we ask the user if the
current return is the corrected/rectified one, with the 'corrective_declaration'
field in this wizard. This wizard will then store these details in the
respective return. And in the XML export file generator, we are retrieving
these details from the return to show in the report.
REFERENCES:
- Drive link for official XML report schema, report structure, 'DUKIntegrator'
software and XML report attribute explanation in English: (
https://drive.google.com/drive/folders/1uzROZAM5Vuiv0HlBXw-vU28x5a9sVOpb)
- Official ANAF sources for D390 report: (
https://static.anaf.ro/static/10/Anaf/Declaratii_R/390.html)
- Official ANAF website for Electronic Declaration: (
https://www.anaf.ro/anaf/internet/ANAF/servicii_online/declaratii_electronice)
Forward-Port-Of: odoo/enterprise#109921Enhancements to existing features
Payment XML files now include the building number field required by the ISO 20022 standard from November 2026. This helps keep SEPA and related bank payment exports compliant ahead of the deadline, reducing the risk of rejected payments later.
Original PR description
This commit adds the <BldgNb> node in the iso20022 XML files, as it will be mandatory starting November 2026. Linked: https://github.com/odoo/odoo/pull/271855 task-6317758 Forward-Port-Of: odoo/enterprise#126532 Forward-Port-Of: odoo/enterprise#121674
Validating large SEPA direct debit batches is now faster, especially when processing hundreds or thousands of payments. This reduces waiting time and helps prevent timeouts during payment validation and customer pre-notification.
Original PR description
- Replace the `id:recordset` aggregation in `_get_expiry_date_per_mandate()` with `date:max` to compute the latest payment date directly in SQL. - Render `email_from` for all payments in batch and cache the computed authors by sender email to avoid repeated partner lookups during SDD pre-notification. This reduces ORM/cache overhead when validating large SEPA batches containing thousands of payments. Measured on a production-sized database: | metric | before | after | factor | |--------|-------:|------:|-------:| | `_get_expiry_date_per_mandate` (500 payments) | 564 ms | 111 ms | ~5x | | `_send_after_validation` notification (500 payments) | 92.9 s | 55.7 s | ~1.7x | | `_get_expiry_date_per_mandate` (1000 payments) | 890 ms | 178 ms | ~5x | | `_send_after_validation` notification (1000 payments) | timed out (>159 s) | 108.9 s | completed | OPW-6377340 Forward-Port-Of: odoo/enterprise#126429 Forward-Port-Of: odoo/enterprise#125439
This update backports additional automated checks for Marketing Automation campaigns, including message failure, bounce handling, enrollment, and synchronization jobs. It helps reduce the risk of regressions in campaign processing, especially around scheduled synchronization and WhatsApp or SMS activity behavior.
Original PR description
Backport various tests added in Odoo 19.4+ in order to better spot potential regressions. Add new tests for synchronization cron behavior, notably in case of failure. Forward-Port-Of: odoo/enterprise#126334
Creating reconciliation rules from bank statement lines is now more reliable when transaction references are very long. The update reduces memory use and processing time, avoiding failures that could block users from assigning accounts to bank statements.
Original PR description
When setting an account to an account.bank.statement there is a step to automatically create a reconciliation rule/model if one does not exist already. To do so, we retrieve 5…
When setting an account to an account.bank.statement there is a step to automatically create a reconciliation rule/model if one does not exist already. To do so, we retrieve 5 account.bank.statement.lines and use them to define the reconciliation model config. A matching is done on the payment_ref of the account.bank.statement.lines by finding the longest common substring in the reference. ### Current Implementation The current algorithm does so by first generating all the possible substrings for all the payment_ref before doing the intersection between these sets and returning the max if `len(substring) >=10`. This is reasonable when the payment_ref follows either a SEPA communication national standard like the Belgian one or the Creditor Reference standard (ISO 11649). For transactions with large, unstructured communication with more than 100 chars, the method `_get_common_substrings` quickly overfill the memory, sometimes raising a MemoryErorr, and takes a significant amount of time. That's because the nested function `_generate_all_substrings` generates n*(n+1)/2 substrings, with n being the lenght of a payment_ref, called `label` in `generate_all_substrings`. ### Proposed Fix This commit introduces another algorithm to find the largest common substring. It starts by taking the two smallest labels to find their substrings intersection. We know that for an arbitrary collection of labels, the intersection of their substrings sets A ∩ B ∩...∩ Z is included in the intersection of any two substrings sets. The underlying assumption of the first step is that for an arbitrary collection of labels the intersection of the substrings sets of the two smallest labels will be the smallest intersection of any given pair of substrings sets. This won't hold true everytime and using a metric such as label similarity instead of shortest string might be better. But on average this should be good enough and it's easier to implement + it removes the need of preprocessing the labels to compute the similarity. The point of the new nested function `common_substrings` is to discard common substrings as we build them. Using the current `generate_all_substsrings` on either the smallest label or both smallest labels would still generate and store a lot of substrings, especially for large labels. By yielding the common substrings as we find them, the memory footprint is vastly reduced. Lastly, the next substring in the common_substrings iterable is only checked against the remaining labels if it's longer than the current match. This speeds up the whole process ### speedup In a customer database with some account.bank.statement.line with payment_ref > 500 chars, setting a specific account (code 4970) on transactions goes from MemoryError to < 1Mb memory consumption. Because of the memory consumption it was not possible to gather timing value on the current version. Testing the new algorithm in a shell and using as labels the 5 longest payment_ref in the customer database (831, 831, 1117, 1178, 1300 chars), averaging to 2000 chars once normalised, the average time to execute `_get_common_substrings` is 900 ms ± 10.3 ms. Forward-Port-Of: odoo/enterprise#121575 Forward-Port-Of: odoo/enterprise#118824
The signing feature now avoids loading unnecessary role data when opening a template. This reduces background work and can make the signing setup screen respond faster, especially in databases with many signing roles.
Original PR description
This `search_read` is done - without `domain` which means it fetches the entire table - without `fields` which means it fetches all fields And the business code only actually needs the id of the very first record which is returned. See `SignTemplateIframe`'s constuctor: `this.props.signRoles[0].id;` AFAICS, that's the only place where it's used. This will be better refactored in master.
Resolved issues and error corrections
The Helpdesk unanswered filter now treats automatic acknowledgement emails as already answered. This prevents newly created website tickets from being incorrectly flagged as waiting for a customer response, helping teams focus on real unanswered messages.
Original PR description
Steps to reproduce: --------- - install website_helpdesk - set an email address on the company partner if it is empty ( it is empty in a database without demo data). - generate a ticket from the website. - apply the Unanswered filter. Issue: ------ system generated acknowledgement message is considered an unanswered customer reply. Fix: -------- system generated acknowledgement messages are now considered answered. task-5138678 Forward-Port-Of: odoo/enterprise#125977
Businesses using Avalara Brazil can now confirm multiple customer invoices at once without the process failing. This prevents validation interruptions and supports smoother batch invoicing workflows.
Original PR description
**_Steps to reproduce:_** * Install `l10n_br_avatax` and configure Avalara Brazil. * Create at least two customer invoices. * Ensure the fiscal position is set to **Automatic Tax Mapping (Avalara…
**_Steps to reproduce:_** * Install `l10n_br_avatax` and configure Avalara Brazil. * Create at least two customer invoices. * Ensure the fiscal position is set to **Automatic Tax Mapping (Avalara Brazil)**. * Select the invoices and click **Action → Confirm Entries**. **_Observed behavior:_** * A traceback is raised with `ValueError: Expected singleton: account.move(...)` and the invoices cannot be validated. **_Cause:_** * During tax extraction, `_extract_tax_values_from_l10n_br_avatax_detail` accesses `self.invoice_filter_type_domain` while `self` may contain multiple `account.move` records. * Accessing `invoice_filter_type_domain` on a multi-recordset raises an `Expected singleton` error, preventing the validation of multiple invoices. **_Fix:_** * Build the returned tax values by iterating over each invoice in the recordset and using the corresponding `invoice_filter_type_domain`. * This ensures `_extract_tax_values_from_l10n_br_avatax_detail` correctly handles multiple invoices during validation without raising a singleton error. opw-6334761 Forward-Port-Of: odoo/enterprise#126437 Forward-Port-Of: odoo/enterprise#124993
Cancelled Mexican CFDI invoices now keep showing their required fiscal details when reprinted, including QR codes, digital stamps, and fiscal folios. This helps businesses retain legally relevant proof that an invoice was issued and later cancelled.
Original PR description
### Issue before this commit: When an invoice's CFDI cancellation request is confirmed (state moves from sent to cancel), reprinting the invoice PDF no longer displays the fiscal information (QR…
### Issue before this commit: When an invoice's CFDI cancellation request is confirmed (state moves from sent to cancel), reprinting the invoice PDF no longer displays the fiscal information (QR code, digital stamps, fiscal folio/UUID, etc.), even though the signed CFDI attachment is still present on the invoice. ### Steps to reproduce the issue: 1. Download Accounting and l10n_mx 2. Create an invoice and send it to CFDI 3. Select 'Request for cancel' 4. Wait and click retry button in the CFDI tab until the invoice is marked as cancelled 5. Print the invoice again 6. See PDF does not show fiscal information (QR, fiscal folio, etc.) ### Cause of the issue: https://github.com/odoo/enterprise/blob/f6c94d4ca3ef4211a5ab00bf0b39f6a7675c8f79/l10n_mx_edi/models/account_move.py#L904-L909 Once the CFDI is cancelled, the computed field switches to 'cancel', so the condition fails and the method falls back to the generic account.report_invoice_document template, which has no knowledge of CFDI fiscal fields. ### Reason to introduce the fix: A cancelled CFDI invoice is still a legally relevant fiscal document in Mexico and must be reprintable with its fiscal data intact (to prove it was issued and later cancelled). The fix extends the condition to also cover the 'cancel' state, ensuring the CFDI-specific report template is used whenever a valid attachment exists, regardless of whether the CFDI is currently signed or cancelled. opw-6393656 Forward-Port-Of: odoo/enterprise#126466
The aged payable and receivable drill-down now hides invoices and bills that were already fully settled for the selected reporting date. This helps users see only genuinely outstanding items and improves accuracy when reviewing historical balances.
Original PR description
Steps to Reproduce: 1. Create a vendor/customer with multiple bills/invoices. 2. Fully pay one or more, leaving at least one still open for the same partner. 3. Open Accounting > Reporting > Partner…
Steps to Reproduce:
1. Create a vendor/customer with multiple bills/invoices.
2. Fully pay one or more, leaving at least one still open for the same partner.
3. Open Accounting > Reporting > Partner Reports > Aged Payable/Receivable.
4. Set to any date and click into an aging bucket for that partner.
Issue:
The drill-down list shows fully settled bills (residual = 0.00) alongside genuinely outstanding ones. Only surfaces when the partner has at least one open balance — if everything is paid, there is no bucket to click into.
Root Cause:
aged_partner_balance_audit builds the drill-down domain filtering only by reconcile flag, journal type, and date range — never checking residual. Additionally it completely overwrites the XML action domain (account.action_amounts_to_settle) which already had ('amount_residual', '!=', 0), losing that protection entirely.
Fix:
Added ('residual_at_date', '!=', 0) to the domain in aged_partner_balance_audit and set recon_limit in the action context so residual_at_date computes as of the report's 'as of' date rather than today's value:
action['context'] = {
'recon_limit': options['date']['date_to'],
}
Without recon_limit, residual_at_date falls back to amount_residual (today's value) which incorrectly excludes bills that were genuinely open on the report date but paid after it.
Result:
The drill-down now correctly shows only genuinely outstanding items regardless of whether the report is run as of today or a historical date.
opw 6333699
Forward-Port-Of: odoo/enterprise#126021The AI chat now handles screens that do not provide view-switching information, such as Shopfloor, without failing. This prevents users from seeing an error when sending a message after navigating between apps.
Original PR description
### Issue When AI chat is used in views where `config.viewSwitcherEntries` is not initialized, sending a message raises a `TypeError` because the code attempts to call `.map()` on an undefined value.…
### Issue
When AI chat is used in views where `config.viewSwitcherEntries` is not initialized, sending a message raises a `TypeError` because the code attempts to call `.map()` on an undefined value.
### Steps to Reproduce
[Video](https://drive.google.com/file/d/1i7kWDnmv4mebGtf1to12BNHCG5omBTXl/view?usp=sharing)
1. Click the **Ask AI** button.
2. Open the AI chat.
3. Keep it open and navigate to the **Shopfloor** app.
4. Send a message in the AI chat.
### Error
```text
TypeError: Cannot read properties of undefined (reading 'map')
at WithSearch.getCurrentViewInfo
```
### Fix
Safely handle cases where `config.viewSwitcherEntries` is undefined by using optional chaining and falling back to an empty array.
**Before**
```js
result.available_view_types = config.viewSwitcherEntries.map((v) => v.type);
```
**After**
```js
result.available_view_types =
config.viewSwitcherEntries?.map((v) => v.type) || [];
```
opw-6414684
Forward-Port-Of: odoo/enterprise#125821Users can now duplicate several maintenance requests at the same time without the system showing an error. This removes an interruption in maintenance workflows and makes bulk request handling more reliable.
Original PR description
Currently, when a user attempts to duplicate multiple maintenance requests simultaneously, the system throws a ValueError (Expected singleton). This PR fixes that. ### How to reproduce the issue: - Install `mrp_maintenance` module; - Open maintenance request list view; - Select multiple records and try to duplicate them using the Action button; - It will throw a traceback stating a singleton error. ### Expected behavior after PR is merged: Now multiple maintenance requests will be copied without raising any errors. Forward-Port-Of: odoo/enterprise#124255
Updated Peruvian electronic invoice address formatting to match SUNAT's current UBL 2.1 requirements. This helps invoices pass official validation by correctly structuring district and urban subdivision information.
Original PR description
Update electronic invoicing address nodes to align with current SUNAT requirements. This transitions the geographic data formatting from the legacy UBL 2.0 schema to the standard UBL 2.1 specification, ensuring proper structural validation for districts and urban subdivisions. Documentation used: https://cpe.sunat.gob.pe/sites/default/files/inline-files/guia+xml+factura+version+2-1+1+0+(2)_0+(2).pdf opw-6282314 Forward-Port-Of: odoo/enterprise#126380 Forward-Port-Of: odoo/enterprise#121390
The spreadsheet pivot field picker now hides date and datetime fields once all available time breakdowns have already been added. This prevents duplicate entries and makes drag-and-drop behavior more reliable for users configuring pivots.
Original PR description
Current behavior before PR: - Date and datetime fields remained visible even when all their granularities were already added to the pivot. - Users could add the same field with the same granularity multiple times, creating duplicate IDs and causing unexpected drag and drop behavior. Desired behavior after PR is merged: - Hide date and datetime fields from the popup once all available granularities have already been added to the pivot. - This prevents duplicate field IDs and keeps the popup behavior consistent with spreadsheet pivots during drag-and-drop. Task: [6295794](https://www.odoo.com/odoo/project/2328/tasks/6295794) Forward-Port-Of: odoo/enterprise#123280
The Planning app now applies employee and material filter rules correctly when looking at open shifts. This prevents shifts from being incorrectly included or excluded, helping planners see the right staffing and resource information.
Original PR description
Before this commit, the domain wrongly assumes that we always search on shifts having no role or a role containing resources of types 'user' or 'material' (1). Additionally to the basic domain which searches on the shifts having resources of types 'user' or 'material' (2). After this commit, we add a condition on domain (1) to only apply it for open shifts (shifts having no resource_id). no-task Forward-Port-Of: odoo/enterprise#126616 Forward-Port-Of: odoo/enterprise#126247
The Malaysian Statement of Account option now only appears and runs for companies based in Malaysia. This prevents users in other countries from seeing or using a country-specific report that does not apply to them.
Original PR description
### Current behavior: After installing `l10n_my_reports`, the Malaysian's Statement of Account button appears on Aged Receivable for every company, and the partner Action "Print Statement of Account" can be run from non-MY companies ### Expected behavior: To avoid user confusion, it is advised to restrict its visibility so that it is only accessible to Malaysia-specific companies ### Steps to reproduce: 1. Install `l10n_my_reports` 2. Switch to a non-Malaysian company 3. Open Invoicing > Reporting > Aged Receivable 4. Observe the "Statement of Account" button on partner lines ### Cause of the issue: Missing checks for 'MY' company country code in UI and print report action ### Fix: - show the Aged Receivable SoA button only when `company_country_code === 'MY'` - guard `action_print_report_statement_account` for non-MY companies opw-6340854 Forward-Port-Of: odoo/enterprise#126172
Fixed an error where customer Total Due in Point of Sale could show the wrong amount when the company currency differed from the PoS currency. Pay-later balances are now calculated in the correct currency, helping staff see accurate customer debt amounts.
Original PR description
Steps to reproduce: - set the company currency to XCG - set the PoS sales journal currency and the PoS pricelist currency to USD - configure a XCG <-> USD rate - create a customer without any…
Steps to reproduce: - set the company currency to XCG - set the PoS sales journal currency and the PoS pricelist currency to USD - configure a XCG <-> USD rate - create a customer without any outstanding balance - open the PoS, create an order of USD 100 and validate it with the Customer Account (Pay Later) payment method - open the Customers screen and look at the Total Due of that customer Issue: The Total Due shows about USD 55.56, i.e. the amount converted once too many, instead of the expected USD 100. Cause: get_total_due() sums two amounts that are not expressed in the same currency before converting them. partner.total_due comes from the accounting entries, it is the sum of account.move.line.amount_residual and is therefore in company currency, while total_settled is the sum of pos.payment.amount of the still open sessions, which is in the currency of the order, so the PoS one. The addition is done first and the result is then converted from the company currency to the PoS one, so the pay later payments end up converted a second time. opw-6403320 Forward-Port-Of: odoo/enterprise#126402 Forward-Port-Of: odoo/enterprise#125798
The planning test expectations were updated to match how monthly demand now counts the full current day. This helps ensure manufacturing forecast suggestions correctly include same-day replenishment activity scheduled later in the day.
Original PR description
Updated the forecast suggestion test expectations after monthly demand was updated to count the full current day, so same-day orderpoint replenishment moves scheduled later in the day are also included Community PR: odoo/odoo#262435 TaskID-5490137 Forward-Port-Of: odoo/enterprise#126578 Forward-Port-Of: odoo/enterprise#115944
Appointment booking links now open correctly when the appointment type uses non-ASCII characters, such as Arabic names. This prevents customers from getting stuck in repeated redirects and lets them complete the booking form as expected.
Original PR description
Clicking a slot on an appointment type with a non-ASCII name (for example an Arabic title) puts the browser in an endless 301 loop, so the info form never opens. ### Steps to reproduce - Create an…
Clicking a slot on an appointment type with a non-ASCII name (for example an Arabic title) puts the browser in an endless 301 loop, so the info form never opens. ### Steps to reproduce - Create an appointment type with an Arabic name, e.g. `عنوان`. - Open its page and pick a time slot. - The browser keeps redirecting on `/appointment/<slug>/info` and fails with "too many redirections". ### Cause The info URL is built from the slug `<name>-<id>`, here `عنوان-1`. We build a `URL` with `encodeURIComponent(slug)`, so `url.href` is already encoded once (`عنوان` becomes `%D8%B9...`). But we then navigate with `encodeURI(url.href)`, and `encodeURI` escapes the `%` signs a second time, so `%D8%B9...` becomes `%25D8%25B9...`. The slug is now encoded twice. To canonicalize the URL, the server decodes the request path and the path it rebuilds from the route, once each, and redirects if they differ. For a normal URL they are equal. For ours they are not, because one side is decoded one step less than the other, so the server keeps answering 301 with the same double-encoded URL. An ASCII slug has no `%` for `encodeURI` to escape, so only non-ASCII names hit this. ### Fix Navigate to `url.href` directly. It is already encoded, so the extra `encodeURI` only broke it. Same fix on the manual resource confirmation path. opw-6409641
This update fixes incorrect Italian wording in balance sheet report fields. It improves clarity for Italian-language accounting users and helps reports show the proper labels.
Original PR description
### Steps to reproduce the issue: 1. Download Accounting and l10n_it 2. Install and switch to italian language 3. Go to Balance Sheets and select Balance Sheet (IT) 4. Some words are not correct [Here]( https://docs.google.com/spreadsheets/d/1-w83oAHTxDRIi-W_VSJiscNclw-yijzQUHOgMnTq7jE/edit?gid=0#gid=0) the wrong fields with their correct translations. opw-6424609 Forward-Port-Of: odoo/enterprise#126253
The timesheet assistant now avoids creating suggestions with missing or undefined text. This helps users see clearer, more reliable suggested timesheet entries.
Original PR description
Several aw.rule regexes use (.*) for the capture groups feeding the suggestion name/description, allowing an empty match and producing incorrect suggestions (e.g. "Discussing with undefined") Task-6377168 Forward-Port-Of: odoo/enterprise#125771
Users who open a bank statement line from an in-app notification will now see the related discussion panel. This makes it easier to follow comments and mentions directly from notifications in Accounting.
Original PR description
Problem: When navigating to a bank statement line through a notification, the chatter doesn't appear. Steps to reproduce: 1. Set in app notifications for one of the users 2. Open Accounting > Bank > To Reconcile 3. Select any bank statement line 4. Tag the user from step 1 in a comment 5. Log in as that user 6. Check notifications and click the new notification 7. Notice how the chatter does not appear on the bank statement line after navigating there Cause: The chatter was not enabled on the bank statement line form view. opw-6410186 Forward-Port-Of: odoo/enterprise#125777
This fix makes Belgian payroll export tests for Partena and UCM run against only the company being checked. It prevents demo or additional company data from interfering with test results, improving reliability without changing business functionality.
Original PR description
The UCM and Partena export tests assumed that only the current company was available in the environment. With demo data installed, another allowed company may have a valid external code, so the export wizard does not raise the expected `RedirectWarning`. this commit restricts allowed_company_ids to the company under test to ensure the validation is exercised independently of other installed companies. Related: https://github.com/odoo/enterprise/pull/100932 [error-242729](https://runbot.odoo.com/odoo/error/242729)
This change prevents refund payslips from being recalculated when a user clicks the compute action, preserving their existing payroll lines. Users can still intentionally clear those lines by using the reset action, reducing the risk of accidental payroll changes.
Original PR description
When a payslip is a refund payslip, we don't want to compute it if we click on "compute". The lines can still be reset when clicking on "reset"
User-facing messages and warnings now show selection field values in the user's language instead of leaving some labels untranslated. This improves clarity across accounting, payroll, recruitment, appointments, IoT, point of sale, documents, surveys, and localization reports.
Original PR description
The `selection` attribute of `fields.Selection` is not generally translated (unless it is a function instead of a list). For user facing strings, we generally need to translate the value displayed. Forward-Port-Of: odoo/enterprise#126633 Forward-Port-Of: odoo/enterprise#126538
This update corrects an internal method name used when checking rental dates in the website rental planning flow. It helps ensure the recent rental date validation change is applied consistently, reducing the risk of errors during online rental orders.
Original PR description
In https://github.com/odoo/enterprise/pull/126275, I forgot to rename method `_is_valid_renting_dates` to `_has_valid_rental_dates` opw-6274035
22 changes
New functionality added to Odoo
Adds a dedicated Romanian D390 EC Sales report so businesses can prepare the legally required monthly declaration for intra-EU transactions. The change includes XML export in the ANAF-required format and a guided step to collect declarant details, helping Romanian companies submit compliant filings.
Original PR description
This commit introduces a new module, 'Romania - EC Sales D390 Report'. For the support of Declarația 390 report as an EC List report for Romania in stable versions. Romanian localization has…
This commit introduces a new module, 'Romania - EC Sales D390 Report'.
For the support of Declarația 390 report as an EC List report for Romania in
stable versions.
Romanian localization has different requirements for the
EC Sales List report. So the generic EC Sales List does not work in the case of
Romania.
LEGAL REQUIREMENTS:
- Romanian tax authority accepts the Declarația 390 (Form 390) report for
cross-border transactions within the European Union.
- This declaration is filed on a monthly basis.
- The declaration must be submitted electronically to ANAF by the 25th of the
month following the month in which the transactions occurred. For example,
the declaration for transactions made in July must be filed by August 25th.
- The declaration must include all the intra-community transactions. These
transactions include:
1. Intra-Community acquisition of Goods
2. Intra-Community acquisition of Services
3. Intra-Community triangular trades
4. Intra-Community supplies of Goods
5. Intra-Community supplies of Services
REQUIRED FORMAT:
- Declarația 390 must be submitted electronically in a specific XML format.
The structure of this XML file is defined by ANAF.
- To facilitate compliance, ANAF provides a free software application called
'DUKIntegrator'. This tool allows businesses to:
1. Validate the generated XML file against the official schema to ensure it is
correctly formatted.
2. Generate the final PDF file with the XML attachment, which is the official
format for submission.
TECHNICAL DETAILS:
- Implemented the tax returns for the D390 EC Sales List report filing.
- Implemented XML export file generator, which creates the whole D390 XML report
with the required schema format.
- The D390 report needs to have the declarant's details in the report, the
attributes like 'nume_declar(Middle Name)', 'prenume_declar(First Name)',
'functie_declar(Job Position)' and 'adresa(Fiscal Domicile Address)'.
For collecting these details, we've created a wizard that will be on the
return validation action. Along with these details, we ask the user if the
current return is the corrected/rectified one, with the 'corrective_declaration'
field in this wizard. This wizard will then store these details in the
respective return. And in the XML export file generator, we are retrieving
these details from the return to show in the report.
REFERENCES:
- Drive link for official XML report schema, report structure, 'DUKIntegrator'
software and XML report attribute explanation in English: (
https://drive.google.com/drive/folders/1uzROZAM5Vuiv0HlBXw-vU28x5a9sVOpb)
- Official ANAF sources for D390 report: (
https://static.anaf.ro/static/10/Anaf/Declaratii_R/390.html)
- Official ANAF website for Electronic Declaration: (
https://www.anaf.ro/anaf/internet/ANAF/servicii_online/declaratii_electronice)
Forward-Port-Of: odoo/enterprise#109921Enhancements to existing features
SEPA direct debit batch validation has been optimized to handle large payment batches more efficiently. This reduces processing time for companies validating hundreds or thousands of payments, helping avoid delays and timeouts during payment workflows.
Original PR description
- Replace the `id:recordset` aggregation in `_get_expiry_date_per_mandate()` with `date:max` to compute the latest payment date directly in SQL. - Render `email_from` for all payments in batch and cache the computed authors by sender email to avoid repeated partner lookups during SDD pre-notification. This reduces ORM/cache overhead when validating large SEPA batches containing thousands of payments. Measured on a production-sized database: | metric | before | after | factor | |--------|-------:|------:|-------:| | `_get_expiry_date_per_mandate` (500 payments) | 564 ms | 111 ms | ~5x | | `_send_after_validation` notification (500 payments) | 92.9 s | 55.7 s | ~1.7x | | `_get_expiry_date_per_mandate` (1000 payments) | 890 ms | 178 ms | ~5x | | `_send_after_validation` notification (1000 payments) | timed out (>159 s) | 108.9 s | completed | OPW-6377340 Forward-Port-Of: odoo/enterprise#126429 Forward-Port-Of: odoo/enterprise#125439
This update backports additional automated tests and test tools for marketing automation flows, including synchronization jobs and message failure or bounce scenarios. It helps reduce the risk of regressions in campaign enrollment, participant state handling, SMS, and WhatsApp-related automation behavior.
Original PR description
Backport various tests added in Odoo 19.4+ in order to better spot potential regressions. Add new tests for synchronization cron behavior, notably in case of failure. Forward-Port-Of: odoo/enterprise#126334
Resolved issues and error corrections
Helpdesk tickets created from the website will no longer appear as unanswered just because the system sent an automatic acknowledgement message. This keeps the Unanswered filter focused on tickets that actually need a human follow-up, improving team prioritization.
Original PR description
Steps to reproduce: --------- - install website_helpdesk - set an email address on the company partner if it is empty ( it is empty in a database without demo data). - generate a ticket from the website. - apply the Unanswered filter. Issue: ------ system generated acknowledgement message is considered an unanswered customer reply. Fix: -------- system generated acknowledgement messages are now considered answered. task-5138678 Forward-Port-Of: odoo/enterprise#125977
Date and datetime fields now disappear from the pivot popup once all available time breakdowns have already been added. This avoids duplicate entries and makes drag-and-drop behavior more reliable for users working with spreadsheet pivots.
Original PR description
Current behavior before PR: - Date and datetime fields remained visible even when all their granularities were already added to the pivot. - Users could add the same field with the same granularity multiple times, creating duplicate IDs and causing unexpected drag and drop behavior. Desired behavior after PR is merged: - Hide date and datetime fields from the popup once all available granularities have already been added to the pivot. - This prevents duplicate field IDs and keeps the popup behavior consistent with spreadsheet pivots during drag-and-drop. Task: [6295794](https://www.odoo.com/odoo/project/2328/tasks/6295794) Forward-Port-Of: odoo/enterprise#123280
This fixes an error that stopped users from confirming several Brazilian customer invoices at once when Avalara Brazil tax mapping was enabled. Businesses can now validate batches of invoices without interruption, reducing manual work and failed processing.
Original PR description
**_Steps to reproduce:_** * Install `l10n_br_avatax` and configure Avalara Brazil. * Create at least two customer invoices. * Ensure the fiscal position is set to **Automatic Tax Mapping (Avalara…
**_Steps to reproduce:_** * Install `l10n_br_avatax` and configure Avalara Brazil. * Create at least two customer invoices. * Ensure the fiscal position is set to **Automatic Tax Mapping (Avalara Brazil)**. * Select the invoices and click **Action → Confirm Entries**. **_Observed behavior:_** * A traceback is raised with `ValueError: Expected singleton: account.move(...)` and the invoices cannot be validated. **_Cause:_** * During tax extraction, `_extract_tax_values_from_l10n_br_avatax_detail` accesses `self.invoice_filter_type_domain` while `self` may contain multiple `account.move` records. * Accessing `invoice_filter_type_domain` on a multi-recordset raises an `Expected singleton` error, preventing the validation of multiple invoices. **_Fix:_** * Build the returned tax values by iterating over each invoice in the recordset and using the corresponding `invoice_filter_type_domain`. * This ensures `_extract_tax_values_from_l10n_br_avatax_detail` correctly handles multiple invoices during validation without raising a singleton error. opw-6334761 Forward-Port-Of: odoo/enterprise#126437 Forward-Port-Of: odoo/enterprise#124993
This fix prevents the US ADP payroll test setup from failing when optional attendance-related apps are not installed. It keeps the test behavior compatible with both minimal and full installations, improving reliability of automated validation without changing payroll functionality.
Original PR description
Steps to reproduce the bug: - Install l10n_us_hr_payroll_adp without hr_attendance/hr_holidays_attendance - Run the test suite (runbot build 941182) - TestL10nUsHrPayrollADPExport.setUpClass fails…
Steps to reproduce the bug: - Install l10n_us_hr_payroll_adp without hr_attendance/hr_holidays_attendance - Run the test suite (runbot build 941182) - TestL10nUsHrPayrollADPExport.setUpClass fails Problem: setUpClass raised `ValueError: Invalid field 'overtime_deductible' in 'hr.work.entry.type'` when writing on the overtime work entry type. The field overtime_deductible is only defined by hr_holidays_attendance https://github.com/odoo/odoo/blob/saas-19.2/addons/hr_holidays_attendance/models/hr_work_entry_type.py#L10-L12 which depends on hr_attendance and auto-installs only when hr_attendance is present. l10n_us_hr_payroll_adp's dependency chain (l10n_us_hr_payroll -> hr_payroll) never pulls in hr_attendance, so the field doesn't always exist in the test's registry. However, when hr_holidays_attendance IS installed (e.g. on the full runbot build), the field must still be set to False: leaving it at its default causes hr.leave.create() to run hr_holidays_attendance's _check_overtime_deductible(), which raises "The employee does not have enough extra hours to request this leave." for the overtime leaves created further down in setUpClass, since the test employees have no recorded attendance/overtime hours. Solution: Only include overtime_deductible in the write() vals when the field exists on hr.work.entry.type, keeping it disabled either way. runbot-941182
Ecuadorian invoices now print with the required local header and barcode again. This restores legally required information on PDF invoices and prevents documents from falling back to the generic invoice layout.
Original PR description
### Issue:
In 19.2, the EC invoice header was no longer rendered on invoices, falling back to the standard layout
The header includes legally required data and a barcode, both missing from the printed PDF
### Cause:
The XPath targeting `//t[@t-set='o']` relied on the position of the `t-set` for `o` in `report_invoice_document`
After the refactor in commit `eb6e88a25050`, the injection point no longer resolves as expected, preventing the header from rendering
Targeting `//div[hasclass('invoice_main')]` instead provides a stable anchor that is less sensitive to template restructuring
### Steps to reproduce:
- Install `l10n_ec_edi` and switch to the EC company
- Create and confirm an invoice
- Print the invoice
Before the fix, the EC header and barcode are missing from the PDF
opw-6375733The aged payable and receivable report drill-down now hides bills and invoices that were already fully settled for the selected report date. This helps finance users see only genuinely outstanding items, including when reviewing historical balances.
Original PR description
Steps to Reproduce: 1. Create a vendor/customer with multiple bills/invoices. 2. Fully pay one or more, leaving at least one still open for the same partner. 3. Open Accounting > Reporting > Partner…
Steps to Reproduce:
1. Create a vendor/customer with multiple bills/invoices.
2. Fully pay one or more, leaving at least one still open for the same partner.
3. Open Accounting > Reporting > Partner Reports > Aged Payable/Receivable.
4. Set to any date and click into an aging bucket for that partner.
Issue:
The drill-down list shows fully settled bills (residual = 0.00) alongside genuinely outstanding ones. Only surfaces when the partner has at least one open balance — if everything is paid, there is no bucket to click into.
Root Cause:
aged_partner_balance_audit builds the drill-down domain filtering only by reconcile flag, journal type, and date range — never checking residual. Additionally it completely overwrites the XML action domain (account.action_amounts_to_settle) which already had ('amount_residual', '!=', 0), losing that protection entirely.
Fix:
Added ('residual_at_date', '!=', 0) to the domain in aged_partner_balance_audit and set recon_limit in the action context so residual_at_date computes as of the report's 'as of' date rather than today's value:
action['context'] = {
'recon_limit': options['date']['date_to'],
}
Without recon_limit, residual_at_date falls back to amount_residual (today's value) which incorrectly excludes bills that were genuinely open on the report date but paid after it.
Result:
The drill-down now correctly shows only genuinely outstanding items regardless of whether the report is run as of today or a historical date.
opw 6333699
Forward-Port-Of: odoo/enterprise#126021Automatic bank transaction matching now ignores archived bank accounts when identifying the related partner. This prevents transactions from being assigned to an outdated partner record and allows the normal label-based matching rules to select the correct partner.
Original PR description
Steps to reproduce: - Have a partner with a bank account, then archive the res.partner.bank record (keep the partner active). - Import or create a bank transaction (e.g. via bank sync) whose account number matches that archived bank account, and whose label/payment_ref would otherwise match a reconciliation model for a different partner. - Let the transaction go through automatic partner retrieval. => The archived bank account's partner is assigned, even though a normal manual entry (which skips the account-number match) would have used the label instead. Cause of the issue: `AccountBankStatementLine._retrieve_partner()` matches statement lines to partners in batch using raw SQL joining `res_partner_bank`. The query's WHERE clause filters out archived partners (`AND partner.active`) but never filters `res_partner_bank.active`. opw-6340479 Forward-Port-Of: odoo/enterprise#124748 Forward-Port-Of: odoo/enterprise#124537
Cancelled Mexican CFDI invoices can now be reprinted with their required fiscal information, including QR codes, digital stamps, and fiscal folio details. This helps businesses keep legally relevant cancelled invoice records complete and verifiable.
Original PR description
### Issue before this commit: When an invoice's CFDI cancellation request is confirmed (state moves from sent to cancel), reprinting the invoice PDF no longer displays the fiscal information (QR…
### Issue before this commit: When an invoice's CFDI cancellation request is confirmed (state moves from sent to cancel), reprinting the invoice PDF no longer displays the fiscal information (QR code, digital stamps, fiscal folio/UUID, etc.), even though the signed CFDI attachment is still present on the invoice. ### Steps to reproduce the issue: 1. Download Accounting and l10n_mx 2. Create an invoice and send it to CFDI 3. Select 'Request for cancel' 4. Wait and click retry button in the CFDI tab until the invoice is marked as cancelled 5. Print the invoice again 6. See PDF does not show fiscal information (QR, fiscal folio, etc.) ### Cause of the issue: https://github.com/odoo/enterprise/blob/f6c94d4ca3ef4211a5ab00bf0b39f6a7675c8f79/l10n_mx_edi/models/account_move.py#L904-L909 Once the CFDI is cancelled, the computed field switches to 'cancel', so the condition fails and the method falls back to the generic account.report_invoice_document template, which has no knowledge of CFDI fiscal fields. ### Reason to introduce the fix: A cancelled CFDI invoice is still a legally relevant fiscal document in Mexico and must be reprintable with its fiscal data intact (to prove it was issued and later cancelled). The fix extends the condition to also cover the 'cancel' state, ensuring the CFDI-specific report template is used whenever a valid attachment exists, regardless of whether the CFDI is currently signed or cancelled. opw-6393656 Forward-Port-Of: odoo/enterprise#126466
Users can now duplicate several maintenance requests at once without the system showing an error. This makes maintenance administration smoother and avoids interruptions when handling requests in bulk.
Original PR description
Currently, when a user attempts to duplicate multiple maintenance requests simultaneously, the system throws a ValueError (Expected singleton). This PR fixes that. ### How to reproduce the issue: - Install `mrp_maintenance` module; - Open maintenance request list view; - Select multiple records and try to duplicate them using the Action button; - It will throw a traceback stating a singleton error. ### Expected behavior after PR is merged: Now multiple maintenance requests will be copied without raising any errors. Forward-Port-Of: odoo/enterprise#124255
This update prevents the AI chat from failing when users navigate to screens that do not provide view-switching information, such as Shopfloor. Users can keep using AI chat across more areas of Odoo without encountering an error when sending messages.
Original PR description
### Issue When AI chat is used in views where `config.viewSwitcherEntries` is not initialized, sending a message raises a `TypeError` because the code attempts to call `.map()` on an undefined value.…
### Issue
When AI chat is used in views where `config.viewSwitcherEntries` is not initialized, sending a message raises a `TypeError` because the code attempts to call `.map()` on an undefined value.
### Steps to Reproduce
[Video](https://drive.google.com/file/d/1i7kWDnmv4mebGtf1to12BNHCG5omBTXl/view?usp=sharing)
1. Click the **Ask AI** button.
2. Open the AI chat.
3. Keep it open and navigate to the **Shopfloor** app.
4. Send a message in the AI chat.
### Error
```text
TypeError: Cannot read properties of undefined (reading 'map')
at WithSearch.getCurrentViewInfo
```
### Fix
Safely handle cases where `config.viewSwitcherEntries` is undefined by using optional chaining and falling back to an empty array.
**Before**
```js
result.available_view_types = config.viewSwitcherEntries.map((v) => v.type);
```
**After**
```js
result.available_view_types =
config.viewSwitcherEntries?.map((v) => v.type) || [];
```
opw-6414684
Forward-Port-Of: odoo/enterprise#125821The self-ordering WhatsApp/SMS flow test was updated to match the current behavior where takeaway is selected automatically when it is the only option. This keeps the validation process aligned with the customer experience and helps prevent false test failures.
Original PR description
In this commit: - The takeaway preset is now automatically selected when it is the only available option. Remove the explicit "Takeaway" selection step from the tour to match the updated behavior. Task:6217791 Community PR : https://github.com/odoo/odoo/pull/274301 Forward-Port-Of: odoo/enterprise#122979
Customer balances in Point of Sale now show the correct Total Due when the company currency differs from the PoS currency. This prevents pay-later amounts from being converted twice, giving staff an accurate view of what customers owe.
Original PR description
Steps to reproduce: - set the company currency to XCG - set the PoS sales journal currency and the PoS pricelist currency to USD - configure a XCG <-> USD rate - create a customer without any…
Steps to reproduce: - set the company currency to XCG - set the PoS sales journal currency and the PoS pricelist currency to USD - configure a XCG <-> USD rate - create a customer without any outstanding balance - open the PoS, create an order of USD 100 and validate it with the Customer Account (Pay Later) payment method - open the Customers screen and look at the Total Due of that customer Issue: The Total Due shows about USD 55.56, i.e. the amount converted once too many, instead of the expected USD 100. Cause: get_total_due() sums two amounts that are not expressed in the same currency before converting them. partner.total_due comes from the accounting entries, it is the sum of account.move.line.amount_residual and is therefore in company currency, while total_settled is the sum of pos.payment.amount of the still open sessions, which is in the currency of the order, so the PoS one. The addition is done first and the result is then converted from the company currency to the PoS one, so the pay later payments end up converted a second time. opw-6403320 Forward-Port-Of: odoo/enterprise#126402 Forward-Port-Of: odoo/enterprise#125798
Automatic bank reconciliation rules now use clearer text matching and consider transaction amounts, reducing incorrect or duplicate rule creation. Users also see only reconciliation rules relevant to the selected journal, making bank matching more accurate and easier to manage.
Original PR description
Reconcile models automatically created now use contains instead of match regex and take the amount into consideration when creating the rule as well as checking for existing rules, it's checked whether all of the lines are positive or negative. Added an extra filter on the reconcile models so that it only shows rules that would be applied on the journal, and did some optimizations in the substring matching. task-6140372 Forward-Port-Of: odoo/enterprise#117256
Peruvian electronic invoices now calculate down payment amounts consistently when withholding tax is involved. This prevents mismatched XML totals and avoids references to cancelled down payment invoices, reducing the risk of rejected or incorrect electronic documents.
Original PR description
### Issue: When an invoice has a down payment on a line with a withholding tax, the `PrepaidPayment/PaidAmount` in the UBL XML included the withholding tax amount, causing a mismatch with…
### Issue: When an invoice has a down payment on a line with a withholding tax, the `PrepaidPayment/PaidAmount` in the UBL XML included the withholding tax amount, causing a mismatch with `LegalMonetaryTotal/PrepaidAmount` which correctly excludes it ### Cause: `PrepaidPayment/PaidAmount` was set directly from `prepayment_move.amount_total`, which includes all taxes `LegalMonetaryTotal/PrepaidAmount` uses `_aggregate_base_line_tax_details` to exclude withholding taxes, but this was not applied to the `PrepaidPayment` node ### Fix: Using `prepayment_move.amount_total` directly includes all taxes and does not match the rounding logic of `LegalMonetaryTotal` Instead, `_aggregate_base_line_tax_details` is used with the same `total_grouping_function` as `LegalMonetaryTotal`, ensuring both nodes use the same rounding logic and exclude withholding taxes Reversed down payment moves are also excluded from `AdditionalDocumentReference` to avoid referencing cancelled invoices ### Steps to reproduce: - Install `l10n_pe_edi` and `sale_management` with demo data - Switch to the PE company - Create and confirm a Sale Order (Customer: PE Company, Product: Any, Unit Price: 200, Taxes: VAT 18% and 3% IGV Withholding) - Create, confirm and pay a Down Payment Invoice (Fixed: 28.92) - Go back to the SO and create the Regular Invoice - Confirm it and click Process Now - Open the EDI Document tab and download the XML Before the fix, the sum of `PrepaidPayment/PaidAmount` did not match `LegalMonetaryTotal/PrepaidAmount` opw-6273903 Forward-Port-Of: odoo/enterprise#121733
This update fixes incorrect Italian wording in the Balance Sheet reports. It improves the clarity and professionalism of localized accounting reports for Italian users without changing report calculations or workflows.
Original PR description
### Steps to reproduce the issue: 1. Download Accounting and l10n_it 2. Install and switch to italian language 3. Go to Balance Sheets and select Balance Sheet (IT) 4. Some words are not correct [Here]( https://docs.google.com/spreadsheets/d/1-w83oAHTxDRIi-W_VSJiscNclw-yijzQUHOgMnTq7jE/edit?gid=0#gid=0) the wrong fields with their correct translations. opw-6424609 Forward-Port-Of: odoo/enterprise#126253
Users opening a bank statement line from an in-app notification will now see the related discussion panel. This ensures comments and mentions remain visible in the Accounting reconciliation flow, reducing confusion when following up on notifications.
Original PR description
Problem: When navigating to a bank statement line through a notification, the chatter doesn't appear. Steps to reproduce: 1. Set in app notifications for one of the users 2. Open Accounting > Bank > To Reconcile 3. Select any bank statement line 4. Tag the user from step 1 in a comment 5. Log in as that user 6. Check notifications and click the new notification 7. Notice how the chatter does not appear on the bank statement line after navigating there Cause: The chatter was not enabled on the bank statement line form view. opw-6410186 Forward-Port-Of: odoo/enterprise#125777
This fixes an issue where rental availability on the website could be blocked because stock from another click-and-collect warehouse was counted incorrectly. Customers can now place rental orders from a warehouse that still has the item available, reducing false out-of-stock errors.
Original PR description
When using the click & collect option, the available qty for renting was not taking the selected warehouse into account. Steps to reproduce: ------------------- * Create 2 different warehouses with 2…
When using the click & collect option, the available qty for renting was not taking the selected warehouse into account. Steps to reproduce: ------------------- * Create 2 different warehouses with 2 different adresses * Create a product available for renting * Setup the product to use serial numbers * Create 2 serial number, 1 in each warehouse * Activate the click & collect option on the website * Create a first sale order to collect in warehouse 1 * In the backend, confirm the order and pick it up * Go back to the website and make a second order for the second warehouse > Observation: When clicking on the "Add to cart" you get an error saying that there is no quantity available Why the fix: ------------ When computing the `product_rented_quantities` it would look for `sale.order.line` in all the warehouse. So it would find the line from the first order even if it's not linked to the selected warehouse. So we just add a new element to the domain to filter out the incorrect warehouses. opw-6328475 Forward-Port-Of: odoo/enterprise#126545 Forward-Port-Of: odoo/enterprise#124969
The Helpdesk Knowledge website app now includes the missing dependency needed for installation in a specific setup mode. This prevents installation failures and helps ensure the app can be deployed reliably.
Original PR description
Trying to install website_helpdesk_knowledge with the flag --skip-auto-install would fail due to website_helpdesk_knowledge/views/helpdesk_views.xml referencing `is_published` which is only defined in `website` https://github.com/odoo/odoo/blob/4d60d5693f3d0253a28dd38412125b2fc6d6b41f/addons/website/models/mixins.py#L184 Reproduciton steps: odoo/odoo-bin --addons-path odoo/addons,odoo/odoo/addons,enterprise,design-themes -d oes_runbot --stop-after-init --log-level=test --max-cron-threads=0 -i website_helpdesk_knowledge --skip-auto-install Adding `website_knowledge` pulls in the relevant dependencies resulting in the field being found and valid Affects **18.0** and **19.0**, **nothing in between** Forward-Port-Of: odoo/enterprise#126260
This fixes an issue in the Barcode app where selecting items from a delivery containing both packaged and unpackaged products could leave two lines selected at once. Warehouse users now get clearer feedback and avoid confusion when processing mixed deliveries.
Original PR description
**Steps to reproduce:** - Enable "Move Entire Packages" setting on deliveries - Make a product A, that has a package P1, on hand qty of 1 - Make product B that don't have a package, but on hand qty…
**Steps to reproduce:** - Enable "Move Entire Packages" setting on deliveries - Make a product A, that has a package P1, on hand qty of 1 - Make product B that don't have a package, but on hand qty of 1 - Make a delivery that has both of those products, requested qty of 1 for both - Mark it as todo - Go to the barcode app, select the delivery - Select the line with product B - Select the line with product A --> The line with product B is not unselected **Why the fix:** When we have a mix of packaged products and products without a package on the same operation, they are handled separately. The products without a package are handled in https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L388-L392 that calls https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L1277-L1284 But as you can see, there are no mention of the selected package line, which is stored in **this.lastScanned.packageId**. As we do not touch this variable, the selected package line stays selected. The same is true for the other way around, when we select a package line we call https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L394-L398 This function does not care for the **selectedLineVirtualId** which represents the selected line without a package. To avoid this and make it so that only one line is selected even if they have different package, we now set the corresponding value to false to unselect the other line in all situation. This is basically how it's done in https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L1202-L1208 to unselect every line regardless of packages. opw-6266203 Forward-Port-Of: odoo/enterprise#125703 Forward-Port-Of: odoo/enterprise#122038
23 changes
New functionality added to Odoo
Adds support for Romania’s Declarația 390 EC Sales report, enabling Romanian businesses to prepare the required monthly EU cross-border transaction declaration in Odoo. The new module generates the ANAF-required XML export and collects declarant details needed for electronic filing, while also improving audit results for EC Sales reports using tax tags.
Original PR description
This commit introduces a new module, 'Romania - EC Sales D390 Report'. For the support of Declarația 390 report as an EC List report for Romania in stable versions. Romanian localization has…
This commit introduces a new module, 'Romania - EC Sales D390 Report'.
For the support of Declarația 390 report as an EC List report for Romania in
stable versions.
Romanian localization has different requirements for the
EC Sales List report. So the generic EC Sales List does not work in the case of
Romania.
LEGAL REQUIREMENTS:
- Romanian tax authority accepts the Declarația 390 (Form 390) report for
cross-border transactions within the European Union.
- This declaration is filed on a monthly basis.
- The declaration must be submitted electronically to ANAF by the 25th of the
month following the month in which the transactions occurred. For example,
the declaration for transactions made in July must be filed by August 25th.
- The declaration must include all the intra-community transactions. These
transactions include:
1. Intra-Community acquisition of Goods
2. Intra-Community acquisition of Services
3. Intra-Community triangular trades
4. Intra-Community supplies of Goods
5. Intra-Community supplies of Services
REQUIRED FORMAT:
- Declarația 390 must be submitted electronically in a specific XML format.
The structure of this XML file is defined by ANAF.
- To facilitate compliance, ANAF provides a free software application called
'DUKIntegrator'. This tool allows businesses to:
1. Validate the generated XML file against the official schema to ensure it is
correctly formatted.
2. Generate the final PDF file with the XML attachment, which is the official
format for submission.
TECHNICAL DETAILS:
- Implemented the tax returns for the D390 EC Sales List report filing.
- Implemented XML export file generator, which creates the whole D390 XML report
with the required schema format.
- The D390 report needs to have the declarant's details in the report, the
attributes like 'nume_declar(Middle Name)', 'prenume_declar(First Name)',
'functie_declar(Job Position)' and 'adresa(Fiscal Domicile Address)'.
For collecting these details, we've created a wizard that will be on the
return validation action. Along with these details, we ask the user if the
current return is the corrected/rectified one, with the 'corrective_declaration'
field in this wizard. This wizard will then store these details in the
respective return. And in the XML export file generator, we are retrieving
these details from the return to show in the report.
REFERENCES:
- Drive link for official XML report schema, report structure, 'DUKIntegrator'
software and XML report attribute explanation in English: (
https://drive.google.com/drive/folders/1uzROZAM5Vuiv0HlBXw-vU28x5a9sVOpb)
- Official ANAF sources for D390 report: (
https://static.anaf.ro/static/10/Anaf/Declaratii_R/390.html)
- Official ANAF website for Electronic Declaration: (
https://www.anaf.ro/anaf/internet/ANAF/servicii_online/declaratii_electronice)Enhancements to existing features
Large SEPA direct debit batches now validate more quickly by reducing repeated system work during mandate checks and customer pre-notification emails. This improves processing reliability for high-volume payment runs, including cases that previously risked timing out.
Original PR description
- Replace the `id:recordset` aggregation in `_get_expiry_date_per_mandate()` with `date:max` to compute the latest payment date directly in SQL. - Render `email_from` for all payments in batch and cache the computed authors by sender email to avoid repeated partner lookups during SDD pre-notification. This reduces ORM/cache overhead when validating large SEPA batches containing thousands of payments. Measured on a production-sized database: | metric | before | after | factor | |--------|-------:|------:|-------:| | `_get_expiry_date_per_mandate` (500 payments) | 564 ms | 111 ms | ~5x | | `_send_after_validation` notification (500 payments) | 92.9 s | 55.7 s | ~1.7x | | `_get_expiry_date_per_mandate` (1000 payments) | 890 ms | 178 ms | ~5x | | `_send_after_validation` notification (1000 payments) | timed out (>159 s) | 108.9 s | completed | OPW-6377340 Forward-Port-Of: odoo/enterprise#126429 Forward-Port-Of: odoo/enterprise#125439
This update backports expanded test coverage and supporting tools for Marketing Automation, including checks for message failures, bounces, campaign enrollment, and scheduled synchronization behavior. It helps reduce the risk of regressions in automated campaigns, especially when participant synchronization or message delivery encounters errors.
Original PR description
Backport various tests added in Odoo 19.4+ in order to better spot potential regressions. Add new tests for synchronization cron behavior, notably in case of failure. Forward-Port-Of: odoo/enterprise#126334
Resolved issues and error corrections
Date and datetime fields now disappear from the pivot setup popup once all available time options have already been used. This prevents users from adding duplicates, avoiding confusing drag-and-drop behavior and keeping spreadsheet pivot configuration consistent.
Original PR description
Current behavior before PR: - Date and datetime fields remained visible even when all their granularities were already added to the pivot. - Users could add the same field with the same granularity multiple times, creating duplicate IDs and causing unexpected drag and drop behavior. Desired behavior after PR is merged: - Hide date and datetime fields from the popup once all available granularities have already been added to the pivot. - This prevents duplicate field IDs and keeps the popup behavior consistent with spreadsheet pivots during drag-and-drop. Task: [6295794](https://www.odoo.com/odoo/project/2328/tasks/6295794) Forward-Port-Of: odoo/enterprise#123280
Cancelled Mexican CFDI invoices now keep showing their required fiscal information when reprinted, including QR codes, digital stamps, and fiscal folios. This ensures businesses can provide legally relevant invoice copies even after cancellation.
Original PR description
### Issue before this commit: When an invoice's CFDI cancellation request is confirmed (state moves from sent to cancel), reprinting the invoice PDF no longer displays the fiscal information (QR…
### Issue before this commit: When an invoice's CFDI cancellation request is confirmed (state moves from sent to cancel), reprinting the invoice PDF no longer displays the fiscal information (QR code, digital stamps, fiscal folio/UUID, etc.), even though the signed CFDI attachment is still present on the invoice. ### Steps to reproduce the issue: 1. Download Accounting and l10n_mx 2. Create an invoice and send it to CFDI 3. Select 'Request for cancel' 4. Wait and click retry button in the CFDI tab until the invoice is marked as cancelled 5. Print the invoice again 6. See PDF does not show fiscal information (QR, fiscal folio, etc.) ### Cause of the issue: https://github.com/odoo/enterprise/blob/f6c94d4ca3ef4211a5ab00bf0b39f6a7675c8f79/l10n_mx_edi/models/account_move.py#L904-L909 Once the CFDI is cancelled, the computed field switches to 'cancel', so the condition fails and the method falls back to the generic account.report_invoice_document template, which has no knowledge of CFDI fiscal fields. ### Reason to introduce the fix: A cancelled CFDI invoice is still a legally relevant fiscal document in Mexico and must be reprintable with its fiscal data intact (to prove it was issued and later cancelled). The fix extends the condition to also cover the 'cancel' state, ensuring the CFDI-specific report template is used whenever a valid attachment exists, regardless of whether the CFDI is currently signed or cancelled. opw-6393656 Forward-Port-Of: odoo/enterprise#126466
Peruvian electronic invoices now calculate prepaid amounts consistently when down payments include withholding tax. This prevents mismatched XML totals and avoids references to cancelled down payment invoices, reducing rejection risk during electronic invoicing.
Original PR description
### Issue: When an invoice has a down payment on a line with a withholding tax, the `PrepaidPayment/PaidAmount` in the UBL XML included the withholding tax amount, causing a mismatch with…
### Issue: When an invoice has a down payment on a line with a withholding tax, the `PrepaidPayment/PaidAmount` in the UBL XML included the withholding tax amount, causing a mismatch with `LegalMonetaryTotal/PrepaidAmount` which correctly excludes it ### Cause: `PrepaidPayment/PaidAmount` was set directly from `prepayment_move.amount_total`, which includes all taxes `LegalMonetaryTotal/PrepaidAmount` uses `_aggregate_base_line_tax_details` to exclude withholding taxes, but this was not applied to the `PrepaidPayment` node ### Fix: Using `prepayment_move.amount_total` directly includes all taxes and does not match the rounding logic of `LegalMonetaryTotal` Instead, `_aggregate_base_line_tax_details` is used with the same `total_grouping_function` as `LegalMonetaryTotal`, ensuring both nodes use the same rounding logic and exclude withholding taxes Reversed down payment moves are also excluded from `AdditionalDocumentReference` to avoid referencing cancelled invoices ### Steps to reproduce: - Install `l10n_pe_edi` and `sale_management` with demo data - Switch to the PE company - Create and confirm a Sale Order (Customer: PE Company, Product: Any, Unit Price: 200, Taxes: VAT 18% and 3% IGV Withholding) - Create, confirm and pay a Down Payment Invoice (Fixed: 28.92) - Go back to the SO and create the Regular Invoice - Confirm it and click Process Now - Open the EDI Document tab and download the XML Before the fix, the sum of `PrepaidPayment/PaidAmount` did not match `LegalMonetaryTotal/PrepaidAmount` opw-6273903 Forward-Port-Of: odoo/enterprise#121733
The self-ordering test flow now matches the current behavior where takeaway is selected automatically when it is the only option. This keeps validation reliable without changing the customer-facing ordering experience.
Original PR description
In this commit: - The takeaway preset is now automatically selected when it is the only available option. Remove the explicit "Takeaway" selection step from the tour to match the updated behavior. Task:6217791 Community PR : https://github.com/odoo/odoo/pull/274301 Forward-Port-Of: odoo/enterprise#122979
International shipments through Sendcloud DPD can now include the customer's tax number in the customs details required by the carrier. This prevents validation errors caused by missing or translated VAT information and adds fallbacks for required customs fields.
Original PR description
### This is a revision of #119399 which had to be reverted. Original issue ----- Deliveries cannot be validated using DPD with Sendcloud, users get an error. Steps to reproduce ----- - Set up…
### This is a revision of #119399 which had to be reverted. Original issue ----- Deliveries cannot be validated using DPD with Sendcloud, users get an error. Steps to reproduce ----- - Set up Sendcloud DPD - Create a SO - Interntional customer - Some VAT number - Some product - Add sendcloud delivery - Confirm SO - Validate the linked picking > Error: “The receiver VAT number is missing; please provide it to continue” Issue's cause ----- Tax numbers should be included in the `customs_information` field of the request as per the API https://sendcloud.dev/api/v2/parcels/create-a-parcel-or-parcels#body-one-of-0-parcel-customs-information-tax-numbers For the `vat_label` field, we have to force the language to English in the context because the field is translated by default, but sendcloud only accepts the english names (eg French "TVA" is not accepted, expected value is "VAT"). https://github.com/odoo/odoo/blob/d1d1610332a1596d026fb0a42ec236d1a79c71cc/odoo/addons/base/models/res_country.py#L75 Revert cause ----- The vat_label field is marked for translation (translate=True) https://github.com/odoo/odoo/blob/d1d1610332a1596d026fb0a42ec236d1a79c71cc/odoo/addons/base/models/res_country.py#L75 So if the user has the DB in french for example, we are sending "TVA" instead of "VAT" in the name field. Other issues ----- - We need to provide an actual fallback for `customs_invoice_nr`. As it stands, if we create a new delivery it cannot be validated because Sendcloud doesn't accept for the field to be empty. - Same for `name`, we need to provide an actual fallback. ----- Ticket: opw-6250860 Forward-Port-Of: odoo/enterprise#124245
AI chat now stays usable when users navigate to areas such as Shopfloor where view switcher information is not available. This prevents an error when sending a message, reducing interruption for users who keep the AI chat open while moving between apps.
Original PR description
### Issue When AI chat is used in views where `config.viewSwitcherEntries` is not initialized, sending a message raises a `TypeError` because the code attempts to call `.map()` on an undefined value.…
### Issue
When AI chat is used in views where `config.viewSwitcherEntries` is not initialized, sending a message raises a `TypeError` because the code attempts to call `.map()` on an undefined value.
### Steps to Reproduce
[Video](https://drive.google.com/file/d/1i7kWDnmv4mebGtf1to12BNHCG5omBTXl/view?usp=sharing)
1. Click the **Ask AI** button.
2. Open the AI chat.
3. Keep it open and navigate to the **Shopfloor** app.
4. Send a message in the AI chat.
### Error
```text
TypeError: Cannot read properties of undefined (reading 'map')
at WithSearch.getCurrentViewInfo
```
### Fix
Safely handle cases where `config.viewSwitcherEntries` is undefined by using optional chaining and falling back to an empty array.
**Before**
```js
result.available_view_types = config.viewSwitcherEntries.map((v) => v.type);
```
**After**
```js
result.available_view_types =
config.viewSwitcherEntries?.map((v) => v.type) || [];
```
opw-6414684
Forward-Port-Of: odoo/enterprise#125821Users can now duplicate several maintenance requests at the same time without the system showing an error. This makes bulk maintenance work smoother and avoids interruptions when managing manufacturing-related maintenance requests.
Original PR description
Currently, when a user attempts to duplicate multiple maintenance requests simultaneously, the system throws a ValueError (Expected singleton). This PR fixes that. ### How to reproduce the issue: - Install `mrp_maintenance` module; - Open maintenance request list view; - Select multiple records and try to duplicate them using the Action button; - It will throw a traceback stating a singleton error. ### Expected behavior after PR is merged: Now multiple maintenance requests will be copied without raising any errors. Forward-Port-Of: odoo/enterprise#124255
Bank reconciliation now keeps the right settings even when users open the page directly from a bookmark or copied URL. This ensures matching rules can still reconcile transactions automatically and synchronized bank journals no longer show an upload option that should be hidden.
Original PR description
### Issue: When accessing the Bank Reconciliation view directly via URL or bookmark, auto-matching with reconciliation models may not trigger and the upload button may be visible on synchronized…
### Issue: When accessing the Bank Reconciliation view directly via URL or bookmark, auto-matching with reconciliation models may not trigger and the upload button may be visible on synchronized journals ### Cause: `_action_open_bank_reconciliation_widget` injects two context keys: - `auto_statement_processing`: triggers auto-reconciliation on statement creation - `bank_statements_source`: hides the upload button for synchronized journals When the view is accessed directly, these keys are not present, causing the UI to ignore them `auto_statement_processing` is now set directly in the user context via `onWillRender`/`onWillDestroy` in `BankRecKanbanController` `bank_statements_source` requires an ORM call to fetch the journal's value and is resolved via `fetchBankStatementsSourceInto` on startup Notes: The fix for `bank_statements_source` was added opportunistically while addressing `auto_statement_processing` Steps to reproduce: - Install `accountant` with demo data - Duplicate the Bank Journal and set Bank Feeds to Online Synchronization - Open the Accounting Dashboard and open the Bank (copy) - Create a transaction (Label: Test, any amount) and click Add & Close - In the 3 dots menu, choose Manage Models - Create a Reconciliation Model (Label contains: Test, Lines: any account, default values) - Click Automate - Go back to the Bank Reconciliation page and verify: -- The transaction is reconciled automatically -- No Upload button is displayed - Create a new transaction, it should be reconciled automatically - Copy the URL and open it in a new tab - Create a new transaction Before the fix, the transaction is not reconciled and the Upload button is present opw-6391107 Forward-Port-Of: odoo/enterprise#126359
This fixes a test issue where cash basis report checks depended on a specific generated account code. The tests now use the configured outstanding receipts account, preventing false failures when account codes vary between databases.
Original PR description
Description of the issue this commit addresses: Commit 63f5646cfd75 made the tests use the default outstanding account but hard-coded code 101403. In an all-module database, generated account codes depend on existing accounts, so Outstanding Receipts may use code 101404 and make otherwise correct report assertions fail. --- Desired behavior after this commit is merged: This commit derives the expected report line name from the configured outstanding receipts account, making the assertions independent of its generated code. --- runbot-[231581](https://runbot.odoo.com/odoo/error/231581) Forward-Port-Of: odoo/enterprise#125652
Timesheet assistant suggestions now use the intended event duration instead of estimating time from start and end times. This prevents planning shifts with breaks or differing allocated hours from suggesting the wrong timesheet duration, while keeping calendar event suggestions accurate.
Original PR description
*_: project_timesheet_forecast, timesheet_grid, timesheet_grid_calendar Previously, the timesheet assistant derived suggested entry durations from an event's start and stop datetimes. This worked for calendar events but produced incorrect suggestions for planning shifts whenever the allocated working hours differed from the overall scheduled time window. This commit introduces an explicit ``duration`` field in assistant events and updates all providers to supply it. Planning slots now use their allocated hours as the event duration, while calendar events expose their existing duration value. The assistant now consistently relies on this field instead of computing the duration from the event time range. As a result, suggested timesheet durations accurately reflect the intended working time for both planning shifts and calendar events. task-6366593
Updated incorrect Italian wording in the Balance Sheet reports so users see the proper field names when using the Italian language. This improves clarity and reduces confusion for accounting teams reviewing Italian financial statements.
Original PR description
### Steps to reproduce the issue: 1. Download Accounting and l10n_it 2. Install and switch to italian language 3. Go to Balance Sheets and select Balance Sheet (IT) 4. Some words are not correct [Here]( https://docs.google.com/spreadsheets/d/1-w83oAHTxDRIi-W_VSJiscNclw-yijzQUHOgMnTq7jE/edit?gid=0#gid=0) the wrong fields with their correct translations. opw-6424609 Forward-Port-Of: odoo/enterprise#126253
The Helpdesk Knowledge website feature now declares the dependency it needs to install correctly in special installation scenarios. This prevents setup failures when auto-installation is skipped, improving reliability for deployments and upgrades.
Original PR description
Trying to install website_helpdesk_knowledge with the flag --skip-auto-install would fail due to website_helpdesk_knowledge/views/helpdesk_views.xml referencing `is_published` which is only defined in `website` https://github.com/odoo/odoo/blob/4d60d5693f3d0253a28dd38412125b2fc6d6b41f/addons/website/models/mixins.py#L184 Reproduciton steps: odoo/odoo-bin --addons-path odoo/addons,odoo/odoo/addons,enterprise,design-themes -d oes_runbot --stop-after-init --log-level=test --max-cron-threads=0 -i website_helpdesk_knowledge --skip-auto-install Adding `website_knowledge` pulls in the relevant dependencies resulting in the field being found and valid Affects **18.0** and **19.0**, **nothing in between** Forward-Port-Of: odoo/enterprise#126260
Employee unavailable time is now shown consistently across Attendance and Time Off planning views. Days outside an employee’s contract, including employees without contracts, are correctly greyed out, while flexible schedules are handled more accurately.
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
- 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#113253Fixes an issue in the Barcode app where selecting items from a delivery containing both packaged and unpackaged products could leave two lines selected at once. This helps warehouse users avoid confusion and reduces the risk of processing the wrong delivery line.
Original PR description
**Steps to reproduce:** - Enable "Move Entire Packages" setting on deliveries - Make a product A, that has a package P1, on hand qty of 1 - Make product B that don't have a package, but on hand qty…
**Steps to reproduce:** - Enable "Move Entire Packages" setting on deliveries - Make a product A, that has a package P1, on hand qty of 1 - Make product B that don't have a package, but on hand qty of 1 - Make a delivery that has both of those products, requested qty of 1 for both - Mark it as todo - Go to the barcode app, select the delivery - Select the line with product B - Select the line with product A --> The line with product B is not unselected **Why the fix:** When we have a mix of packaged products and products without a package on the same operation, they are handled separately. The products without a package are handled in https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L388-L392 that calls https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L1277-L1284 But as you can see, there are no mention of the selected package line, which is stored in **this.lastScanned.packageId**. As we do not touch this variable, the selected package line stays selected. The same is true for the other way around, when we select a package line we call https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L394-L398 This function does not care for the **selectedLineVirtualId** which represents the selected line without a package. To avoid this and make it so that only one line is selected even if they have different package, we now set the corresponding value to false to unselect the other line in all situation. This is basically how it's done in https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L1202-L1208 to unselect every line regardless of packages. opw-6266203 Forward-Port-Of: odoo/enterprise#125703 Forward-Port-Of: odoo/enterprise#122038
This fix ensures that surcharge fees are added to point-of-sale orders before the payment is completed. It prevents affected Tyro transactions from being validated without the required surcharge line, improving order accuracy and checkout reliability.
Original PR description
Currently when completing a Tyro payment with a surcharge fee in some cases there is a race condition preventing the surcharge line to be added to the pos order before its validation This PR fixes that issue opw-6402191 Forward-Port-Of: odoo/enterprise#125852
Customer balances in Point of Sale now show the correct amount when the company and PoS use different currencies. This prevents pay-later orders from being converted twice, so staff see accurate customer dues at checkout.
Original PR description
Steps to reproduce: - set the company currency to XCG - set the PoS sales journal currency and the PoS pricelist currency to USD - configure a XCG <-> USD rate - create a customer without any…
Steps to reproduce: - set the company currency to XCG - set the PoS sales journal currency and the PoS pricelist currency to USD - configure a XCG <-> USD rate - create a customer without any outstanding balance - open the PoS, create an order of USD 100 and validate it with the Customer Account (Pay Later) payment method - open the Customers screen and look at the Total Due of that customer Issue: The Total Due shows about USD 55.56, i.e. the amount converted once too many, instead of the expected USD 100. Cause: get_total_due() sums two amounts that are not expressed in the same currency before converting them. partner.total_due comes from the accounting entries, it is the sum of account.move.line.amount_residual and is therefore in company currency, while total_settled is the sum of pos.payment.amount of the still open sessions, which is in the currency of the order, so the PoS one. The addition is done first and the result is then converted from the company currency to the PoS one, so the pay later payments end up converted a second time. opw-6403320 Forward-Port-Of: odoo/enterprise#126402 Forward-Port-Of: odoo/enterprise#125798
This update ensures the Ecuador electronic invoicing module installs with the payment dependency it needs. It prevents automated installation tests from failing when optional modules are skipped, improving release stability without changing day-to-day user behavior.
Original PR description
Runbot test would fail when running with `--skip-auto-install` due to the file l10n_ec_edi/views/withhold_portal_templates.xml referencing something that didn't exist as `account_payment` wasn't installed. Element `<xpath expr="//div[@name='invoice_paid_badge']">` cannot be located in parent view Reproduction step: odoo/odoo-bin --addons-path odoo/addons,odoo/odoo/addons,enterprise,design-themes -d oes_test --stop-after-init --log-level=test --max-cron-threads=0 -i l10n_ec_edi --skip-auto-install runbot-[237864](https://runbot.odoo.com/odoo/error/237864)
Confirmed manufacturing orders now correctly reflect changes made to their bill of materials when users choose to update them. This prevents outdated or removed operations from remaining on production orders and helps manufacturing teams work from accurate instructions.
Original PR description
Steps to reproduce: - Create a product with a bom and 2 operations - Create an MO for 1 unit of that product - Confirm the MO - On the bom, delete the second operation and modify the first operation…
Steps to reproduce: - Create a product with a bom and 2 operations - Create an MO for 1 unit of that product - Confirm the MO - On the bom, delete the second operation and modify the first operation on anything else than the company, name or workcenter - Go back to the MO, click the "Update Bom" button > The second operation is not unlinked and the first operation is not updated Cause of the issue: The `action_update_bom` updates the move raws and operations of the MO via the `_link_bom`: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L1214-L1218 For draft MO's all the work of these updates is done via the compute methods and by deleting all the records unrelevant to the new bom: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L2603-L2626 And, in that case all the workorders that are not linked to an operation of the bom are expected to be deleted. However, when the MO is not in draft, the update of operations is expected to be performed here: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L2647-L2664 However, since the operation of the bom has been deleted, the workorder that is expected to be deleted is not linked to any operation and hence does not satisfy the condition to be deleted: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L2663-L2664 Concerning the non update of operations, it happens because the MO's operation are only updated on the three fields: `company_id`, `workcenter_id`, `name`: https://github.com/odoo/odoo/blob/31df5033e31c193b4576ef37dfbc5fc683817bc5/addons/mrp/models/mrp_production.py#L2647-L2664 https://github.com/odoo/odoo/blob/31df5033e31c193b4576ef37dfbc5fc683817bc5/addons/mrp/models/mrp_production.py#L2628-L2629 However, many other cahnges can and are actually relevant. Note: Prior to commit 80e6ed658fb43584bc2fad673ca40d9af6cf0ab6 operations were archived on boms rather than deleted: https://github.com/odoo/odoo/blob/4a5270218fe6fd7d30edb6d684b3340dc7423bab/addons/mrp/views/mrp_routing_views.xml#L53-L55 As such they would still be linked to an operation (but unrelated to the present values of the bom) and hence would fall into the condition of being unlinked from the MO. Since the bom operations are no longer archived there is no way to determine if an operation used to be linked to a bom and we therefore need to chose between deleting all operations unrelated to the present bom or to keep them all (when the MO has been confirmed). Community: https://github.com/odoo/odoo/pull/269747 opw-6285878 opw-6261738 Forward-Port-Of: odoo/enterprise#120709
Replacing a Sign document now keeps multiple signature fields correctly linked to the same signer. This prevents duplicate signer entries and helps ensure signing workflows remain accurate after a document is replaced.
Original PR description
### Description of the issue/feature this PR addresses: This PR fixes an issue in the Sign module where replacing a document breaks the link between a signer and their multiple signature fields,…
### Description of the issue/feature this PR addresses: This PR fixes an issue in the Sign module where replacing a document breaks the link between a signer and their multiple signature fields, causing Odoo to erroneously generate separate signers for each individual field. ### Current behavior before PR: When a document with multiple signature fields assigned to the same person is replaced, the _copy_sign_items_to function duplicates the sign.item records. During this duplication process, Odoo duplicates the old responsible_ids, creating copies with new ids. These new copies overwrite the old responsible_ids, ensuring that the newly created sign_items have entirely new responsible_ids. Because a shared responsible_id is the primary key Odoo uses to group multiple signature items under a single signer, this change in ID causes the system to lose the grouping. As a result, Odoo treats each copied field as belonging to a completely new, separate signer. _Note_: Because of the limitation mentioned before, any responsible_id that is passed through the copy function, and thereby the copy_data function, is overwritten with new ids. The only work-around then is to update the responsible_id value attached to the new_sign_item after the copy_data function has completed and the new_sign_item has been created. ### Desired behavior after PR is merged: The original responsible_id is explicitly carried over and assigned to the newly copied sign.item immediately after the copy operation completes. This ensures the copied signature fields retain their original role IDs and grouping, keeping them correctly assigned to the single original signer. opw-6354334 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/enterprise#123628
This fix reverts a module dependency change in the Helpdesk Knowledge website integration because dependency changes are not allowed in stable releases. It helps keep the stable version predictable and reduces the risk of unintended installation or upgrade behavior.
Original PR description
Changes to depends are not allowed in stable Merge through saas-19.1 https://github.com/odoo/enterprise/pull/126260 Forward-Port-Of: odoo/enterprise#126892
6 changes
Resolved issues and error corrections
Peruvian electronic invoices now calculate down payment amounts consistently when withholding tax is involved. This prevents mismatched invoice totals in the generated XML and avoids references to cancelled down payment invoices.
Original PR description
### Issue: When an invoice has a down payment on a line with a withholding tax, the `PrepaidPayment/PaidAmount` in the UBL XML included the withholding tax amount, causing a mismatch with…
### Issue: When an invoice has a down payment on a line with a withholding tax, the `PrepaidPayment/PaidAmount` in the UBL XML included the withholding tax amount, causing a mismatch with `LegalMonetaryTotal/PrepaidAmount` which correctly excludes it ### Cause: `PrepaidPayment/PaidAmount` was set directly from `prepayment_move.amount_total`, which includes all taxes `LegalMonetaryTotal/PrepaidAmount` uses `_aggregate_base_line_tax_details` to exclude withholding taxes, but this was not applied to the `PrepaidPayment` node ### Fix: Using `prepayment_move.amount_total` directly includes all taxes and does not match the rounding logic of `LegalMonetaryTotal` Instead, `_aggregate_base_line_tax_details` is used with the same `total_grouping_function` as `LegalMonetaryTotal`, ensuring both nodes use the same rounding logic and exclude withholding taxes Reversed down payment moves are also excluded from `AdditionalDocumentReference` to avoid referencing cancelled invoices ### Steps to reproduce: - Install `l10n_pe_edi` and `sale_management` with demo data - Switch to the PE company - Create and confirm a Sale Order (Customer: PE Company, Product: Any, Unit Price: 200, Taxes: VAT 18% and 3% IGV Withholding) - Create, confirm and pay a Down Payment Invoice (Fixed: 28.92) - Go back to the SO and create the Regular Invoice - Confirm it and click Process Now - Open the EDI Document tab and download the XML Before the fix, the sum of `PrepaidPayment/PaidAmount` did not match `LegalMonetaryTotal/PrepaidAmount` opw-6273903
UrbanPiper online orders with tax-included prices now calculate the per-item price correctly when customers order more than one unit. This prevents overstated POS order totals and improves billing accuracy for restaurants and retailers using the integration.
Original PR description
Steps to reproduce: --- - Configure a Point of Sale with UrbanPiper credentials. - Create a product priced at 100 with a 5% GST (Tax Included). - Sync the product with UrbanPiper. - Place an online order with a quantity greater than 1. Issue: --- - `total_with_tax` was incorrectly treated as the unit price for multi-quantity tax-included orders. Fix: --- - Calculate the unit price by dividing `total_with_tax` by the ordered quantity before creating the POS order line. task-6427634 Forward-Port-Of: odoo/enterprise#126585 Forward-Port-Of: odoo/enterprise#125989
Fixed an issue where rapidly clicking to expand a report line could create duplicate entries and prevent the line from closing again. This improves reliability when users interact quickly or work on slower network connections.
Original PR description
Steps to reproduce:- - Open any report. - Click on a particular line to unfold more than once very fast(or throttle network to 3G) - Once line is unfolded click again to fold that line. - Line is not…
Steps to reproduce:- - Open any report. - Click on a particular line to unfold more than once very fast(or throttle network to 3G) - Once line is unfolded click again to fold that line. - Line is not folding. Cause:- - When we clicked multiple times to unfold line, duplicate child lines were created(as many times as many times we clicked). - Because when first promise was not resolved so `unfolded = false` and we clicked again so new promise also tries to unfold the same line, resulting in unfolding the same line multiple times. - In version 17.0 these duplicate child lines are created but somehow not visible but it breaks `foldLine`. From version 18.0 onwards these duplicate child lines are visible. Solution: In `unfoldLine` set the flag `unfolding`. So in all clicks other than first, we get `unfolding = true` and don't proceed further, preventing unfolding the same line multiple times. task-6260425 Forward-Port-Of: odoo/enterprise#126504 Forward-Port-Of: odoo/enterprise#120392
The Helpdesk Knowledge website module now includes the required dependency so it can be installed reliably in more setup scenarios. This prevents installation failures when automatic dependency installation is skipped, helping deployments and tests complete successfully.
Original PR description
Trying to install website_helpdesk_knowledge with the flag --skip-auto-install would fail due to website_helpdesk_knowledge/views/helpdesk_views.xml referencing `is_published` which is only defined in `website` https://github.com/odoo/odoo/blob/4d60d5693f3d0253a28dd38412125b2fc6d6b41f/addons/website/models/mixins.py#L184 Reproduciton steps: odoo/odoo-bin --addons-path odoo/addons,odoo/odoo/addons,enterprise,design-themes -d oes_runbot --stop-after-init --log-level=test --max-cron-threads=0 -i website_helpdesk_knowledge --skip-auto-install Adding `website_knowledge` pulls in the relevant dependencies resulting in the field being found and valid Affects **18.0** and **19.0**, **nothing in between** Forward-Port-Of: odoo/enterprise#126260
Users can now duplicate several maintenance requests at once without the system showing an error. This keeps bulk maintenance workflows running smoothly and avoids interruptions for teams managing multiple requests.
Original PR description
Currently, when a user attempts to duplicate multiple maintenance requests simultaneously, the system throws a ValueError (Expected singleton). This PR fixes that. ### How to reproduce the issue: - Install `mrp_maintenance` module; - Open maintenance request list view; - Select multiple records and try to duplicate them using the Action button; - It will throw a traceback stating a singleton error. ### Expected behavior after PR is merged: Now multiple maintenance requests will be copied without raising any errors. Forward-Port-Of: odoo/enterprise#124255
This change reverts a manifest dependency update in the Website Helpdesk Knowledge module because dependency changes are not permitted in stable releases. It helps keep the stable version predictable and reduces the risk of unexpected installation or upgrade behavior.
Original PR description
Changes to depends are not allowed in stable Merge through saas-19.1 https://github.com/odoo/enterprise/pull/126260 Forward-Port-Of: odoo/enterprise#126892
7 changes
Enhancements to existing features
Odoo now checks a bank institution's maximum allowed payment amount before starting an online or batch payment. This helps businesses avoid failed payment attempts when their bank provider enforces transaction limits.
Original PR description
Before trying to initiate payments through Odoo/Odoofin, we should check that the total amount for the (batch) payment does not exceed the maximum payment amount allowed by the institution (some Powens institutions introduced that limit). task-6310729 Forward-Port-Of: odoo/enterprise#121513
The Amazon sales integration now uses Amazon's newer Orders API ahead of the old API's planned shutdown. This keeps order imports compatible with Amazon's platform and should improve synchronization efficiency by retrieving order and item details together.
Original PR description
Amazon has announced the deprecation of the Orders v0 API, with a removal date of March 27, 2027. In this commit, we migrate to the new v2026-01-01 API. This new version restructures how order data is queried and delivered, shifting from a multi-request architecture to a nested consolidated payload. This optimizes our sync performance by eliminating the N+1 query problem when fetching order items. Key changes: - Operation Consolidation: `getOrders` is replaced by `searchOrders`. Because Amazon now embeds orderItems directly inside each order object natively, we remove our secondary item-fetching loops. - Financial aggregation: Item prices, taxes, shipping, and discounts are no longer flat fields on the item but are centralized into a `proceeds` object. - Replacing of deprecated flags. - Reorganization of order-related fields. task-5972714 Forward-Port-Of: odoo/enterprise#126712 Forward-Port-Of: odoo/enterprise#114591
Resolved issues and error corrections
This fixes an issue where quickly clicking to expand a report line could create duplicate entries and stop the line from collapsing correctly. Financial reports now behave consistently even when users click quickly or have a slow network connection.
Original PR description
Steps to reproduce:- - Open any report. - Click on a particular line to unfold more than once very fast(or throttle network to 3G) - Once line is unfolded click again to fold that line. - Line is not…
Steps to reproduce:- - Open any report. - Click on a particular line to unfold more than once very fast(or throttle network to 3G) - Once line is unfolded click again to fold that line. - Line is not folding. Cause:- - When we clicked multiple times to unfold line, duplicate child lines were created(as many times as many times we clicked). - Because when first promise was not resolved so `unfolded = false` and we clicked again so new promise also tries to unfold the same line, resulting in unfolding the same line multiple times. - In version 17.0 these duplicate child lines are created but somehow not visible but it breaks `foldLine`. From version 18.0 onwards these duplicate child lines are visible. Solution: In `unfoldLine` set the flag `unfolding`. So in all clicks other than first, we get `unfolding = true` and don't proceed further, preventing unfolding the same line multiple times. task-6260425 Forward-Port-Of: odoo/enterprise#126504 Forward-Port-Of: odoo/enterprise#120392
This fix prevents an optional worksheet guide from interrupting an automated field service report test when demo data is absent. It makes testing more reliable without changing day-to-day user functionality.
Original PR description
When there is only one worksheet, the ‘Explore Worksheets Using an Example Template’ wizard opens. Because of this, the test fails without demo data. If we add steps for this wizard, it won’t open when there is more than one worksheet, which will again cause the test to fail. Also, we cannot add this conditon on step. Therefore, to ignore this wizard, i created a worksheet before running the tour so that the wizard does not open. backport of https://github.com/odoo/enterprise/commit/5bb2d96087f50f7df1d51bbd4c31bb23b6d313da runbot-242471 Forward-Port-Of: odoo/enterprise#124885
Users can now duplicate several maintenance requests at once without the system showing an error. This prevents interruptions when managing maintenance work in bulk and makes the request list action behave as expected.
Original PR description
Currently, when a user attempts to duplicate multiple maintenance requests simultaneously, the system throws a ValueError (Expected singleton). This PR fixes that. ### How to reproduce the issue: - Install `mrp_maintenance` module; - Open maintenance request list view; - Select multiple records and try to duplicate them using the Action button; - It will throw a traceback stating a singleton error. ### Expected behavior after PR is merged: Now multiple maintenance requests will be copied without raising any errors. Forward-Port-Of: odoo/enterprise#124255
Planning analysis now includes slots assigned to fully flexible employees who do not have a fixed working schedule. This ensures managers see a complete view of planned work and staffing in timesheet and planning reports.
Original PR description
Steps to reproduce: ------------------- 1. Install project_timesheet_forecast. 2. Create a fully flexible employee (without a working schedule). 3. Create a planning slot. 4. Open the Timesheet/planning Analysis report. Issue: ------ Planning slots for fully flexible employees are not included in the report. Cause: ------ https://github.com/odoo/enterprise/blob/7d4b43cfa1934856d41992cbe8242eaf62575c2c/project_timesheet_forecast/report/timesheet_forecast_report.py#L142-L161 The report assumes every resource has a working schedule and only considers resources with a resource calendar. As a result, resources without a calendar are excluded from the report. Solution: --------- Handle resources without a working schedule separately so that planning slots for fully flexible employees are also included in the report. opw-6361571 Forward-Port-Of: odoo/enterprise#125072
The barcode batch picking test flow now waits for the first scanned item quantity to update before selecting the next line. This prevents quantities from being assigned to the wrong product line during rapid scanning, helping ensure batch picking remains accurate and reliable.
Original PR description
Problem: When scanning the first product, the second move line is clicked immediately after.…
Problem: When scanning the first product, the second move line is clicked immediately after. https://github.com/odoo/enterprise/blob/bfb8bab7636a84c829f16087771e00bf31ad2cce/stock_barcode_picking_batch/static/tests/tours/tour_test_barcode_batch_flows.js#L1529-L1541 If this happens before the first scan has finished, its quantity is incorrectly applied to the second move line that is clicked. This causes a 0 - 3 split instead of a 1 - 2 split, which results in there only being 6 move lines instead of 7. We updated our quantity on the `currentLine` https://github.com/odoo/enterprise/blob/bfb8bab7636a84c829f16087771e00bf31ad2cce/stock_barcode/static/src/models/barcode_model.js#L1478 When finding `currentLine`, we go through `_findLine` and use `this.selectedLineVirtualId`, which is the one that is currently selected in the UI https://github.com/odoo/enterprise/blob/bfb8bab7636a84c829f16087771e00bf31ad2cce/stock_barcode/static/src/models/barcode_model.js#L1705-L1712 Purpose: By adding this step, we wait until the first line’s quantity to be updated before it moves on and clicks on the second product. runbot-941211 Forward-Port-Of: odoo/enterprise#124162
8 changes
Enhancements to existing features
Appointment pages now calculate bookable capacities much more efficiently, especially when many linked resources are involved. This makes availability pages load far faster and also corrects capacity values in some resource-selection cases.
Original PR description
Before --- - When opening the appointment page, the possible capacities that a user can book needs to be calculated to show the capacity dropdown. - This is currently done by getting all the possible…
Before
---
- When opening the appointment page, the possible capacities that a user can book needs to be calculated to show the capacity dropdown.
- This is currently done by getting all the possible combinations that could arise from each resource along with its linked resources (Linked resources are resources that are used to combine with the main resource to allow a bigger capacity)
- The complexity of this approach blows up with the increase in linked resources. For each resource we end up with O(2^m) where m is the number of linked resources it has. If they have the same number of linked resources, and n is the number of resources, we end up with O(n*2^m)
Solution:
- Flipping the algorithm, we create a structure for possible capacities and only keep the best combination for a found capacity.
- We first store all available capacity for relevant resources.
Algorithm
---
For a resource:
- We initialize the solution S to {0: []}
- Greedy dynamic programming is then used to get all the possible combinations by building the result dict, adding one resource at a time. We add its capacity to all entries of S -> we use the combination if a new capacity is reached OR update the combination if the number of elements of combination is less than the existing one.
Then, for the global solution:
- We go through S of resources (in the order of self), and add entries to G (the general dict of solutions). Again, on collision, we only keep the lower-cardinal combination.
The complexity of this algorithm is O(n*u) where u is the dynamic programming complexity. u would be quadratic O(m^2) if the sub-sums of capacities overlap heavily, for instance when resources have the same capacity, like tables of a restaurant, but could reach (2^m) in the worst case scenario.
Related changes / side effects
---
1. Fixing an issue
2. Cleaning strange logic
3. Cleaning max capacity computation
Benchmark:
- opw-5177932 goes down from 6 mins to less than 2 seconds using the new algorithm.
Also include
---
Fix the max capacity on resources when skipping resource selection. It computed the max capa based on values that were not yet emptied in the website_appointment controller.
Task-6233563The preparation display now uses the clearer label “Footer Note” instead of “General Note,” alongside an updated icon. This makes the action button easier for staff to understand when managing order notes.
Original PR description
Following this commit : ==== - General Note is renamed to Footer Note. task- 4210929
The Amazon sales integration now uses Amazon's newer Orders API ahead of the 2027 retirement of the old version. This keeps order imports compatible with Amazon's platform and should improve synchronization performance by retrieving order details more efficiently.
Original PR description
Amazon has announced the deprecation of the Orders v0 API, with a removal date of March 27, 2027. In this commit, we migrate to the new v2026-01-01 API. This new version restructures how order data is queried and delivered, shifting from a multi-request architecture to a nested consolidated payload. This optimizes our sync performance by eliminating the N+1 query problem when fetching order items. Key changes: - Operation Consolidation: `getOrders` is replaced by `searchOrders`. Because Amazon now embeds orderItems directly inside each order object natively, we remove our secondary item-fetching loops. - Financial aggregation: Item prices, taxes, shipping, and discounts are no longer flat fields on the item but are centralized into a `proceeds` object. - Replacing of deprecated flags. - Reorganization of order-related fields. task-5972714 Forward-Port-Of: odoo/enterprise#114591
Resolved issues and error corrections
The Vietnam reports module now classifies short-term loan balances under Held to Maturity Investment as required by Circular 99/2025. This helps businesses produce compliant balance sheet reports without manually adjusting the classification.
Original PR description
### Expected behavior: As per circular 99/2025, short-term loan (12831) balance is required to fall under Held to Maturity Investment (Code 123) instead of 112 ### Steps to reproduce: Install `l10n_vn_reports` module ### Fix: Update the Balance Sheet code formula for the 12381 account opw-6411771
This fix makes the batch picking barcode test wait for the first scanned item quantity to update before selecting the next item. It prevents timing issues that could make the test record quantities on the wrong line, improving confidence in barcode batch picking behavior.
Original PR description
Problem: When scanning the first product, the second move line is clicked immediately after.…
Problem: When scanning the first product, the second move line is clicked immediately after. https://github.com/odoo/enterprise/blob/bfb8bab7636a84c829f16087771e00bf31ad2cce/stock_barcode_picking_batch/static/tests/tours/tour_test_barcode_batch_flows.js#L1529-L1541 If this happens before the first scan has finished, its quantity is incorrectly applied to the second move line that is clicked. This causes a 0 - 3 split instead of a 1 - 2 split, which results in there only being 6 move lines instead of 7. We updated our quantity on the `currentLine` https://github.com/odoo/enterprise/blob/bfb8bab7636a84c829f16087771e00bf31ad2cce/stock_barcode/static/src/models/barcode_model.js#L1478 When finding `currentLine`, we go through `_findLine` and use `this.selectedLineVirtualId`, which is the one that is currently selected in the UI https://github.com/odoo/enterprise/blob/bfb8bab7636a84c829f16087771e00bf31ad2cce/stock_barcode/static/src/models/barcode_model.js#L1705-L1712 Purpose: By adding this step, we wait until the first line’s quantity to be updated before it moves on and clicks on the second product. runbot-941211
The Vietnam reports module now classifies short-term held-to-maturity loan balances under the correct balance sheet category required by Circular 99/2025. This helps businesses produce financial statements that better align with the latest Vietnamese reporting rules.
Original PR description
### Expected behavior: As per circular 99/2025, short-term loan (12831) balance is required to fall under Held to Maturity Investment (Code 123) instead of 112, translated: ``` Short-term held-to-maturity investments (Code 123): includes held-to-maturity investments with a remaining term of 12 months or less from the end of the accounting period, such as term deposits, bonds, commercial paper, loans, and other debt securities. This item does not include held-to-maturity investments that have been presented in the item “Cash equivalents” ``` ### Steps to reproduce: Install `l10n_vn_reports` module ### Fix: PO validated: Update the Balance Sheet code formula for the 12381 account opw-6413120
Documents uploaded from a contact are now saved in the intended default workspace instead of reusing the last folder selected in Documents. This prevents files from being accidentally placed in unrelated folders, making document organization more reliable for users.
Original PR description
Steps to reproduce ================== 1. Open Documents. 2. Select Finance. 3. Return to the home page and open the Contacts app. 4. Open any contact. 5. Click the Documents stat button. 6. Upload a document. Issue ===== The document is uploaded to the Finance folder instead of My Drive. Reason ====== When uploading a document using the upload button, we use `currentFolderAccessToken` to determine the destination folder. When opening the Documents view from a contact, `searchpanel_default_folder_id` is set to `False` so that documents are uploaded to the `All` workspace. However, when the search model is loaded, we do not reset `currentFolderAccessToken` when `folder_id` is `False`, causing the previously selected folder (Finance) to be reused. Task-6352242
The portal now updates the number of documents awaiting a user's signature after they sign. This prevents users from seeing already completed signature requests as still pending, reducing confusion in the signing workflow.
Original PR description
Version: 18.0 Steps to reproduce: - Create a sign request with two signers. - Assign the first signature to a portal user. - Log in as the portal user and sign the document. Issue: After signing, the to-sign count in the portal does not decrease. This is because the query only checks the overall sign request state instead of the individual signer's item state, so the count remains unchanged Fix: Added an item level state check to the count query so it only counts items that are still pending for that specific user. Task ID: 6412976