Daily updates from Odoo
Thursday, June 4, 2026
120 changes
16 changes
Enhancements to existing features
This update streamlines the invoicing process by automatically reconciling invoices created from sale orders. Previously, this required manual steps; now, the system directly links invoices to the corresponding sale order, improving efficiency and accuracy. This change simplifies the accounting workflow and reduces the risk of errors.
Original PR description
This commit will allow to automatically reconcile the invoice create from the sale order by passing a context key that will be used in the create_invoices function. task-5502964 Forward-Port-Of: odoo/enterprise#108546
This update enhances how we track usage of our AI models by adding detailed labels to each request. This allows us to better understand which sources – like agents or web searches – are driving token consumption, leading to more accurate cost analysis and optimization of our AI investments. The changes improve our ability to monitor and manage AI resource utilization.
Original PR description
Tag each completion request with a human-readable label identifying what issued it (the agent, web search, AI field, AI server action, ...) so token usage can be attributed to a given source-model combination. Agent-driven requests are prefixed with "Agent:" to set them apart from feature calls. Example: ``` AI: [Agent: Ask AI] gemini-2.5-flash-lite request [0.68s] - Tokens: 115 in (0 cached)|5 out|0 reasoning AI: [Agent: Ask AI] gemini-3-flash-preview request [2.64s] - Tokens: 5295 in (4050 cached)|79 out|186 reasoning AI: [web search] gemini-3-flash-preview request [21.24s] - Tokens: 562 in (226 cached)|708 out|1343 reasoning AI: [Agent: Odoo Image Generation Agent] gemini-2.5-flash-image request [8.25s] - Tokens: 423 in (0 cached)|1324 out|0 reasoning ```
Resolved issues and error corrections
This update resolves an error that occurred when users created new accounts in the accounting module, specifically for the Mexican (l10n_mx) localization. A recent change made account codes optional, but the system was incorrectly handling the absence of a code. This fix ensures accounts are created correctly regardless of whether an account code is provided.
Original PR description
Currently, an error occurs when a user creates an account record. Steps to Reproduce: - Install `Accounting` and `l10n_mx` module with demo data. - Switch to `ZAPATERIA URTADO ÑERI` company. - Go to…
Currently, an error occurs when a user creates an account record. Steps to Reproduce: - Install `Accounting` and `l10n_mx` module with demo data. - Switch to `ZAPATERIA URTADO ÑERI` company. - Go to `Accounting` > `Configuration` > `Accounting` > `Chart of Accounts` and create a record. `TypeError: 'bool' object is not subscriptable` After a [recent commit], account codes became optional and can be removed. As a result, when a user creates an account without a code, the code attempts to check whether the first letter of the account code is in the debit codes [1]. Since the account code is False, it raises an error. This commit ensures that if the internal group of an account is asset or expense, the debit tag is assigned to the account. Otherwise, the credit tag is assigned to the account tags. [recent commit]: https://github.com/odoo/odoo/commit/c3313b336b9f1305c363097745926f2bdf61e277 [1]- https://github.com/odoo/odoo/blob/a60643538479caf29aefeec89b8d356d8d5439c7/addons/l10n_mx/models/account_account.py#L17-L20 sentry-7490691483 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves an issue where Luxembourg tax reports were incorrectly generating company registry numbers instead of the agent's RCS number when a natural person accountant wasn't linked. The fix ensures the correct RCS number is included in the XML, preventing rejection by Luxembourg tax authorities. This ensures compliance and accurate reporting.
Original PR description
**Steps to reproduce:** * install `l10n_lu_reports`. * Create a company in Luxembourg with a `company_registry` number set. * Link this company to an accounting firm that is a natural person…
**Steps to reproduce:** * install `l10n_lu_reports`. * Create a company in Luxembourg with a `company_registry` number set. * Link this company to an accounting firm that is a natural person (independent accountant) with no business registration number — i.e. `l10n_lu_agent_rcs_number` is left empty on the agent partner. * Go to the tax report and generate the XML declaration. **Observed behavior:** * The `<Agent><RCSNbr>` field in the generated XML contains the company's own `company_registry` value instead of `NE`. * The file is rejected by the Luxembourg tax administration. **Cause:** * In `l10n_lu_generate_xml.py`, the `agent_rcs_number` template value was built with a plain `or` chain: `agent.l10n_lu_agent_rcs_number or company.company_registry or "NE"` * When an agent is set but has no RCS number (natural person), the fallback incorrectly continued to `company.company_registry` instead of stopping at `"NE"`. **Fix:** * Use a conditional expression so that `company.company_registry` is only used as a fallback when **no agent is linked** to the company: `(agent.l10n_lu_agent_rcs_number if agent else company.company_registry) or "NE"` opw-6044689 Forward-Port-Of: odoo/enterprise#112968
This update ensures that manufacturing orders linked to projects with mandatory analytic plans are properly configured before confirmation. Previously, users could bypass this requirement, leading to potential accounting discrepancies. Now, the system enforces the use of a valid analytic distribution, preventing errors and improving data accuracy.
Original PR description
Currently, it is possible to confirm a manufacturing order linked to a project without an analytic distribution, even when a plan is set as mandatory for Manufacturing Orders. Fix: On action_confirm, check whether the related project has mandatory plans set and, if so, ensure they are filled — raising a ValidationError otherwise. task-id [6250034](https://www.odoo.com/odoo/project/967/tasks/6250034) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#266943
This update fixes an issue where group allocations with past start dates were not correctly calculating accrual amounts. The change ensures that accruals are accurately computed when a group allocation is created, regardless of the start date, preventing zero accrual values.
Original PR description
Problem ------------------ When creating group allocations, when the allocation type is accrual and the start date is set in the past, the newly created allocations have the accrual amounts at 0. To…
Problem ------------------ When creating group allocations, when the allocation type is accrual and the start date is set in the past, the newly created allocations have the accrual amounts at 0. To reproduce: 1. Create an accrual plan with an easily measurable milestone (e.g. 1 day every day) 2. From the allocations view -> New Group Allocation 3. Enter the following values: Grant -> By Employee Employees -> select your employee Time Off Type -> Paid Time Off (doesn't matter too much) Allocation Type -> Based on Accrual Plan Validity Period -> any date a few days in the past (Personally I tested with 1/1/2025 and no end date) Allocation -> Keep at 0 Allocate Time Off 4. Go to the newly created allocation The allocation amount is 0. Reason ---------------------- When creating group allocations, the `hr.leave.allocation.generate.multi.wizard` calls the `_process_accrual_plans()` method to compute the accruals, but when the allocations are created, the nextcall and lastcall fields are set, so the accruals are not computed and the scheduled action also does nothing until the nextcall date. The onchange method manually sets the nextcall date to False so the accruals are processed. Solution ------------------ Created a method to get the fields that need to be set to calculate the initial accrual amounts from the start date, which is called both in the onchange and to batch write in the wizard before accrual plans are processed. The wizard checks the duration values before overwriting the number_of_days field, since user manually setting the amount should overwrite the calculations. task-4938695 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#267768 Forward-Port-Of: odoo/odoo#265783
This update corrects an issue where decreasing line quantities in POS orders wasn't working reliably, particularly when using certification modules like Point of Sale. The change ensures that line decreases are accurately tracked and reflected in the order, preventing incorrect quantity calculations. This improves the overall POS order management experience.
Original PR description
This commit will affect all certification modules for the POS (pos_blackbox_be, l10n_se_pos, l10n_de_pos_res_cert) Inside the base `handleDecreaseLine` we match all the lines which have the same…
This commit will affect all certification modules for the POS (pos_blackbox_be, l10n_se_pos, l10n_de_pos_res_cert) Inside the base `handleDecreaseLine` we match all the lines which have the same product_id and compute the new quantity based on those. At the end we create a new line with the decreased quantity. This method is called when `disallowLineQuantityChange()` returns `false`, so when either of `pos_blackbox_be`, `l10n_se_pos` or `l10_de_pos_res_cert` are installed. The problem is that different combos will still have the same product_id and total_excluded_currency, so the `current_saved_quantity` adds the other unrelated combos together and tries to remove from the total of all the combos with the same parent. This commit will keep the decrease line for an order in the uiState. So instead of iterating over all the lines in the order and matching lines which have the same product_id we always keep track of the original line and the matching decrease line for that line. Task-[6173236](https://www.odoo.com/odoo/project/1737/tasks/6173236) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262744
This update corrects a problem where DHL shipping labels weren't using the correct template dimensions, resulting in labels printed in the wrong size (8x4 instead of 6x4). The fix maps the incorrect label template selection to the correct DHL API format, ensuring labels match the specified dimensions.
Original PR description
Issue ----- Labels generated with DHL do not respect the template (dimensions) set on the delivery method. Steps to reproduce ----- - Set up DHL - set label template as 6X4_A4_PDF - Create a delivery…
Issue
-----
Labels generated with DHL do not respect the template (dimensions) set on the
delivery method.
Steps to reproduce
-----
- Set up DHL
- set label template as 6X4_A4_PDF
- Create a delivery using the method
- Validate the delivery
> The generated label is in 8x4 inch format instead of 6x4 full page
Explanation
-----
All info below was found in DHL's API doc from the following YAML file
https://developer.dhl.com/sites/default/files/2026-05/dpdhl-express-api-3.3.0.yaml
There are 2 issues with the current implementation regarding the label format.
1. The formats defined on the model (the `ProviderDHL` `delivery.carrier`) do not match the ones of the API. From the API, the accepted values are the following:
- ECOM26_84_A4_001
- ECOM26_84_001
- ECOM_TC_A4
- ECOM26_A6_002
- ECOM26_84CI_001
- ECOM26_84CI_002
- ECOM26_84CI_003
- ECOM_A4_RU_002
- ECOM26_84_LBBX_001
- ECOM26_64_LBBX_001
(values taken from the excerpt below)
```
templateName:
description: >-
Please enter DHL Express document template name.
<BR> Sample Transport label
templates:<BR> ECOM26_84_A4_001
<BR> ECOM26_84_001 - default<BR>
ECOM_TC_A4<BR> ECOM26_A6_002<BR>
ECOM26_84CI_001<BR> ECOM26_84CI_002 - supported
single customer barcode<BR> ECOM26_84CI_003 -
to be used if customer barcodes are used<BR>
ECOM_A4_RU_002<BR>
ECOM26_84_LBBX_001 - supported for loose BBX shipment<BR>
ECOM26_64_LBBX_001 - supported for loose BBX shipment<BR>
[...]
type: string
maxLength: 25
example: ECOM26_84_001
```
[...]: additional info unrelated to labels (useful only for other `typeCode` values)
Since `ProviderDHL` is a model, the `dhl_label_template` selection values cannot be changed and must thus be mapped to the corresponding API values.
- 8X4_A4_PDF => ECOM26_84_A4_001
- 8X4_thermal => ECOM26_84_001
- 8X4_A4_TC_PDF => ECOM_TC_A4
- 6X4_thermal => ECOM26_A6_002
- 6X4_A4_PDF => ECOM26_A6_002
- 8X4_CI_PDF => ECOM26_84CI_001
- 8X4_CI_thermal => ECOM26_84CI_001
- 8X4_RU_A4_PDF => ECOM_A4_RU_002
- 6X4_PDF => ECOM26_A6_002
- 8X4_PDF => ECOM26_84_001
Couple notes about this matching:
- There is no 6x4 in the API, so A6 is used instead (A6 is 105x148mm, 4x6 is 101.6x152.4mm so not a perfect match but the best option still)
- ECOM26_84_001 and ECOM26_A6_002 are used as default values for the respective formats when there is no exact match possible (eg 6x4 only has one option in the API, the default one)
- "A4" is being ignored, because of point 2
2. There is a specific field to force the label to be in A4 format (according to the API, see excerpt below)
```
fitLabelsToA4:
description: >-
To print respective Transport Label and Waybill document into
A4 margin PDF.<BR> Note:
ECOM26_A6_002,ECOM26_84CI_001,ECOM26_84CI_002,ARCH_6X4,ARCH_8X4
template. <BR> This option is applicable only
for PDF encodingFormat selection.<BR> false:
Transport Label and Waybill document will use default margin
settings (default behavior) <BR> true:
Transport Label and Waybill document will print into A4 margin
PDF
type: boolean
example: false
```
-----
Ticket:
opw-6148713
Forward-Port-Of: odoo/enterprise#117281This update fixes an issue where purchase bills were incorrectly created in the company's default currency, regardless of the original purchase order currency. Now, bills automatically inherit the currency of the purchase order, ensuring accurate financial reporting. This improves the reliability of our accounting processes.
Original PR description
**Steps to reproduce:** - create a storable product - confirm a PO in another currency than the main for this product - click on the "bill matching" smart button - select only the purchase order line from your PO - click on match **Current behavior:** this creates on Bill in the main currency **Expected behavior:** the currency should be inherited from the POL **Cause of the issue:** Inside action_match_lines() if there is no amls selected we call _action_create_bill_from_po_lines(). https://github.com/odoo/odoo/blob/e3b0ca11d99b2ef819cdad68b169112cd73668b6/addons/purchase/models/purchase_bill_line_match.py#L157 Inside this method, there's currently no mechanism to take the currency from the POL when we create the bill. **fix:** If multiple different other currencies we take the main currency of the company opw-6131314 Forward-Port-Of: odoo/odoo#267090 Forward-Port-Of: odoo/odoo#266013
This update significantly speeds up the process of validating stock quantities within Odoo, a key function for managing inventory. The changes address inefficiencies in how stock quantities were checked, resulting in a dramatic reduction in processing time, especially for large datasets. This improves overall system performance and responsiveness.
Original PR description
Applying stock quants validation was performing poorly due to multiple bottlenecks in `Picking._check_entire_pack` and `StockMoveLine._apply_putaway_strategy`: * **Redundant updates** were performed…
Applying stock quants validation was performing poorly due to multiple bottlenecks in `Picking._check_entire_pack` and `StockMoveLine._apply_putaway_strategy`: * **Redundant updates** were performed on `location_dest_id` in the move lines and the package levels (which internally update all related move lines too), even when the location remained unchanged. * The main loop inside `_check_entire_pack` was **O(N^2)** time relative to the number of move lines due to internal filtering logic. * **Cache misses** triggered unnecessary SQL queries when retrieving `move_line_ids` from `package levels`, while they are already cached via the pickings and can be grouped by `package_level`. --- ### Benchmark Benchmark conducted on a customer database with **400k** `stock_move_line` records within **800** `pickings`, testing performance of the action `StockQuant.action_validate` with different sizes of move lines. Each test was run multiple times and shown is the average mean, all with negligible variance. | Metric | Before | After | Delta | | :--- | :--- | :--- | :--- | | **Benchmark (1k lines)** | 10.5s | 2.2s | -80% | | **Benchmark (5k lines)** | 121s | 8.5s | -93% | | **Benchmark (50k lines)** | 887s | 56s | -94% | | **Benchmark (400k lines)** | timeout | 777s | (within time limit) | **OPW-6045513** Forward-Port-Of: odoo/odoo#262717 Forward-Port-Of: odoo/odoo#257829
This update fixes a previous issue where purchase order information was missing from vendor credit notes (in_refund). Now, users can easily see which purchase order each credit note line is associated with, improving accuracy and streamlining the credit note process. This ensures consistent reporting and simplifies reconciliation.
Original PR description
The purchase_order_id column in invoice lines was hidden for vendor credit notes (in_refund), while it was visible for vendor invoices (in_invoice). This prevented users from identifying which purchase order each line belonged to when a credit note was linked to one or more POs. Include 'in_refund' in the column_invisible condition so the purchase order column is also available on vendor credit note lines. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#267316
This update resolves an issue where currency amounts in Arabic RTL (right-to-left) user interfaces were incorrectly displayed with the minus sign appearing to the right of the currency symbol. The fix ensures that currency amounts are consistently formatted left-to-right, improving readability and accuracy for users in Arabic-speaking regions. This ensures financial data is presented correctly for all users.
Original PR description
Steps to reproduce 1. Create a company with Egypt localization, currency EGP 2. On a bank journal, set Outstanding Receipt and Outstanding Payment accounts 3. Register a customer payment so the…
Steps to reproduce 1. Create a company with Egypt localization, currency EGP 2. On a bank journal, set Outstanding Receipt and Outstanding Payment accounts 3. Register a customer payment so the journal dashboard shows the Payments row with a negative amount 4. Switch the user language to Arabic 5. Open the Accounting dashboard Issue The Payments amount renders as "LE 5,000.00-" instead of "-5,000.00 LE". formatCurrency returns the string "-5,000.00 LE". In an Arabic page the leading "-" has no intrinsic direction, so the browser attaches it to the surrounding right-to-left Arabic text and visually moves it past the symbol. Sibling rows on the same dashboard render correctly because they already wrap the amount in dir="ltr", see https://github.com/odoo/odoo/blob/d0424f2ffcf99ee59befe288150f1643b3fa0112/addons/account/views/account_journal_dashboard_view.xml#L252 opw-6183749 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#267812 Forward-Port-Of: odoo/odoo#266742
This update fixes an issue where SII invoices generated with quarterly tax periods were incorrectly using monthly formats. The change ensures that generated JSON documents accurately reflect the company's chosen quarterly periodicity, aligning with Spanish tax regulations. This improves data accuracy for tax reporting.
Original PR description
### Issue: When the company `tax_periodicity` is set to quarterly, the generated SII invoice JSON still uses the monthly period format According to the documentation, the options for Periodo include…
### Issue: When the company `tax_periodicity` is set to quarterly, the generated SII invoice JSON still uses the monthly period format According to the documentation, the options for Periodo include distinction between monthly and trimester (p224 - 225): https://sede.agenciatributaria.gob.es/static_files/Sede/Procedimiento_ayuda/G417/FicherosSuministros/V_1_1/SII-Descripcion-ServicioWeb-v1-1_es_es.pdf ### Cause: The invoice JSON generation does not consider the company's `tax_periodicity` This logic was probably omitted because `account_reports` may not be installed However, when the periodicity is configured, the generated SII document should reflect it correctly ### Steps to reproduce: - Install `l10n_es_edi_sii` and `account_reports` - In Settings, set `Tax Periodicity` to `Quarterly` - In Settings, set `Tax Agency for SII` to `Agencia Tributaria Española` - Change ES Company vat number to `ESA12345674` - Create an invoice (Date: 01/05/2026, Customer: ES Company) - Open the generated JSON document - Check the Periodo value, it should be 2T in May opw-6050587 Forward-Port-Of: odoo/odoo#267708 Forward-Port-Of: odoo/odoo#264063
This update resolves an issue where Odoo would crash when a customer canceled a Redsys payment and returned to the system. Previously, the system didn't properly handle missing payment information, leading to errors. Now, Odoo gracefully manages payment cancellations, ensuring a smoother customer experience.
Original PR description
Description of the issue/feature this PR addresses: Prevent an internal server error when a customer cancels a Redsys payment and returns to Odoo. Current behavior before PR: When the customer…
Description of the issue/feature this PR addresses: Prevent an internal server error when a customer cancels a Redsys payment and returns to Odoo. Current behavior before PR: When the customer cancels the payment from the Redsys checkout page, Redsys redirects back to Odoo without the `Ds_MerchantParameters` parameter. The payment flow assumes the parameter is always present and tries to decode it unconditionally, causing an internal server error. Desired behavior after PR is merged: Odoo gracefully handles payment cancellations when `Ds_MerchantParameters` is missing from the callback parameters. The customer is redirected correctly without triggering a server error. Steps to reproduce: 1. Install the Redsys payment provider. 2. Configure a test environment. 3. Create a sales order or invoice. 4. Start the payment process. 5. Cancel the payment from the Redsys checkout page. 6. Return to Odoo. 7. Observe the internal server error caused by the missing `Ds_MerchantParameters` parameter. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#265655
A recent change unintentionally caused all expense lines to be incorrectly reconciled with Stripe transactions. This fix restores the proper filtering of expense lines during reconciliation, ensuring accurate tracking of payments and preventing over-reconciliation. This resolves a disruption in expense reporting and financial accuracy.
Original PR description
In 1f6f4ee3, the account reconciliation filtering was removed from the automatic reconciliation. This broke the reconciliation as all lines would be taken into the reconciliation after-hand Steps to reproduce: - Install `hr_expense_stripe_demo` - Create a Stripe account in the settings - Refresh the account status until validated - Top-up the account in the accounting dashboard - Create a virtual card and activate it - Simulate a transaction with capture - Submit the expense created after checking it has at least one tax - Approve and post the expense - Check the reconciled transaction in the stripe journal - All the lines of the expense move have been reconciled
This update corrects a reporting error that caused combo products to incorrectly appear in the 'Invoiced Not Delivered' report even after items were fully delivered. The fix accurately reflects the actual delivery status of combo items, ensuring accurate reporting and avoiding duplicate information.
Original PR description
**Problem:** A combo product's parent line appears in the "Invoiced Not Delivered" report (Accounting > Review) and stays there permanently, even after all of its combo items are delivered. **Steps…
**Problem:** A combo product's parent line appears in the "Invoiced Not Delivered" report (Accounting > Review) and stays there permanently, even after all of its combo items are delivered. **Steps to reproduce:** 1. Create a combo product bundling two storable items. 2. Sell the combo on a sale order, confirm and invoice it. 3. Deliver every combo item. 4. Open Accounting > Review > Invoiced Not Delivered. **Current behavior:** The combo parent line is listed. While items are partially delivered, both the parent and the items are listed, duplicating the same information. **Expected behavior:** The combo parent is not listed; only the combo item lines, which carry the real delivery state, appear when they are genuinely not delivered. **Cause of the issue:** A combo parent is a virtual sale order line with no stock move of its own, so its delivered quantity is never advanced and always reads 0. The accrual report selects lines where `qty_invoiced_at_date > qty_delivered_at_date`, so the parent (which does receive an invoiced quantity from the combo logic) matches forever. **Fix:** Combo parents carry no delivery information of their own, so excluding them from the accrual search domain is more accurate than inventing a delivered quantity for them. Their combo item lines already represent the real delivery state, so the report stays correct. opw-6215110 Forward-Port-Of: odoo/enterprise#118942
18 changes
Enhancements to existing features
This update allows users to seamlessly continue their actions after they've been temporarily blocked due to security checks (like fingerprint authentication). It eliminates friction by automatically replaying the action once identity is verified, ensuring a smoother user experience. This change improves usability and reduces disruption for users.
Original PR description
The introduction of the mechanism for blocking untrusted devices allows the user to be re-authenticated automatically (via fingerprint)[^1]. If automatic re-authentication is successful, from a UX perspective, the user does not see their action being performed. This commit introduces the ability to replay the action that was blocked with an identity check if the identity is verified. This way, the user does not experience any friction. Note: Correct linter alerts. Task-5941988 [^1]: Commit: 61f22175ef3df37087887e7419dac54a620bbd55
Resolved issues and error corrections
This update resolves an issue where Luxembourg tax reports were incorrectly generating company registry numbers instead of the agent's RCS number when a natural person accountant wasn't linked. The fix ensures the correct RCS number is included in the XML, preventing rejection by the Luxembourg tax administration. This ensures compliance and accurate reporting.
Original PR description
**Steps to reproduce:** * install `l10n_lu_reports`. * Create a company in Luxembourg with a `company_registry` number set. * Link this company to an accounting firm that is a natural person…
**Steps to reproduce:** * install `l10n_lu_reports`. * Create a company in Luxembourg with a `company_registry` number set. * Link this company to an accounting firm that is a natural person (independent accountant) with no business registration number — i.e. `l10n_lu_agent_rcs_number` is left empty on the agent partner. * Go to the tax report and generate the XML declaration. **Observed behavior:** * The `<Agent><RCSNbr>` field in the generated XML contains the company's own `company_registry` value instead of `NE`. * The file is rejected by the Luxembourg tax administration. **Cause:** * In `l10n_lu_generate_xml.py`, the `agent_rcs_number` template value was built with a plain `or` chain: `agent.l10n_lu_agent_rcs_number or company.company_registry or "NE"` * When an agent is set but has no RCS number (natural person), the fallback incorrectly continued to `company.company_registry` instead of stopping at `"NE"`. **Fix:** * Use a conditional expression so that `company.company_registry` is only used as a fallback when **no agent is linked** to the company: `(agent.l10n_lu_agent_rcs_number if agent else company.company_registry) or "NE"` opw-6044689 Forward-Port-Of: odoo/enterprise#112968
This update ensures that manufacturing orders linked to projects always have a correctly configured analytic plan. Previously, users could confirm orders without a plan, even when one was required. Now, the system will prevent order confirmation until a valid plan is selected, improving data accuracy and financial reporting.
Original PR description
Currently, it is possible to confirm a manufacturing order linked to a project without an analytic distribution, even when a plan is set as mandatory for Manufacturing Orders. Fix: On action_confirm, check whether the related project has mandatory plans set and, if so, ensure they are filled — raising a ValidationError otherwise. task-id [6250034](https://www.odoo.com/odoo/project/967/tasks/6250034) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#266943
This update fixes an issue where SII invoice JSONs weren't accurately representing quarterly tax periods. The system now correctly uses '2T' for the Periodo field when the company's tax periodicity is set to quarterly, aligning with Spanish tax regulations. This ensures accurate reporting for VAT compliance.
Original PR description
### Issue: When the company `tax_periodicity` is set to quarterly, the generated SII invoice JSON still uses the monthly period format According to the documentation, the options for Periodo include…
### Issue: When the company `tax_periodicity` is set to quarterly, the generated SII invoice JSON still uses the monthly period format According to the documentation, the options for Periodo include distinction between monthly and trimester (p224 - 225): https://sede.agenciatributaria.gob.es/static_files/Sede/Procedimiento_ayuda/G417/FicherosSuministros/V_1_1/SII-Descripcion-ServicioWeb-v1-1_es_es.pdf ### Cause: The invoice JSON generation does not consider the company's `tax_periodicity` This logic was probably omitted because `account_reports` may not be installed However, when the periodicity is configured, the generated SII document should reflect it correctly ### Steps to reproduce: - Install `l10n_es_edi_sii` and `account_reports` - In Settings, set `Tax Periodicity` to `Quarterly` - In Settings, set `Tax Agency for SII` to `Agencia Tributaria Española` - Change ES Company vat number to `ESA12345674` - Create an invoice (Date: 01/05/2026, Customer: ES Company) - Open the generated JSON document - Check the Periodo value, it should be 2T in May opw-6050587 Forward-Port-Of: odoo/odoo#267708 Forward-Port-Of: odoo/odoo#264063
This update resolves an issue where decreasing a line item in a POS order wasn't functioning reliably, particularly when certain certification modules (like those for SE and DE) were enabled. The change ensures that line decreases are accurately tracked and applied to the order, improving the overall POS experience. This fix impacts all certified POS modules.
Original PR description
This commit will affect all certification modules for the POS (pos_blackbox_be, l10n_se_pos, l10n_de_pos_res_cert) Inside the base `handleDecreaseLine` we match all the lines which have the same…
This commit will affect all certification modules for the POS (pos_blackbox_be, l10n_se_pos, l10n_de_pos_res_cert) Inside the base `handleDecreaseLine` we match all the lines which have the same product_id and compute the new quantity based on those. At the end we create a new line with the decreased quantity. This method is called when `disallowLineQuantityChange()` returns `false`, so when either of `pos_blackbox_be`, `l10n_se_pos` or `l10_de_pos_res_cert` are installed. The problem is that different combos will still have the same product_id and total_excluded_currency, so the `current_saved_quantity` adds the other unrelated combos together and tries to remove from the total of all the combos with the same parent. This commit will keep the decrease line for an order in the uiState. So instead of iterating over all the lines in the order and matching lines which have the same product_id we always keep track of the original line and the matching decrease line for that line. Task-[6173236](https://www.odoo.com/odoo/project/1737/tasks/6173236) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262744
This update resolves an issue where multiple Mercado Pago payment terminals were incorrectly linked to a single WebSocket connection. Previously, this meant responses from additional terminals wouldn't be processed correctly. The fix ensures that each active terminal receives its own connection, guaranteeing accurate webhook handling and payment processing. This improves the reliability of the Mercado Pago integration.
Original PR description
Issue Upon initialization of the pos a PaymentInterface is constructed for every pos_payment_method (even archived pos payment methods ?!). [As we allow only one WebSocket subscription per…
Issue Upon initialization of the pos a PaymentInterface is constructed for every pos_payment_method (even archived pos payment methods ?!). [As we allow only one WebSocket subscription per channel](https://github.com/odoo/odoo/blob/4e1c89890c5fd54a79dcf5bf20268e51d8fe6e69/addons/point_of_sale/static/src/app/utils/payment/payment_interface.js#L100) for the PaymentInterface, all webhook responses will be linked to only one PaymentInterface. Meaning that when you have two Mercado Pago pos_payment_method terminals configured, only the first pos_payment_method (id=1) will be subscribed to the WebSocket and all the webhook responses from the second pos_payment_method terminal (id=2) will arrive to the PayementInterface of the first pos_payment_method (id=1). Where payload.payment_method_id (id=2) != this.payment_method_id.id (id=1). Solution - Only iterate and create a PaymentInterface for compatible pos_payment_methods which are active - Check if the webhook response is linked to the PendingPaymentLine opw-6069455 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262184
This update corrects a problem where DHL shipping labels weren't using the correct dimensions (6x4 inches) due to a mismatch between Odoo's settings and the DHL API. The code now maps the selected label template to the correct DHL API format, ensuring labels are printed in the intended size. This prevents incorrect label dimensions and potential shipping errors.
Original PR description
Issue ----- Labels generated with DHL do not respect the template (dimensions) set on the delivery method. Steps to reproduce ----- - Set up DHL - set label template as 6X4_A4_PDF - Create a delivery…
Issue
-----
Labels generated with DHL do not respect the template (dimensions) set on the
delivery method.
Steps to reproduce
-----
- Set up DHL
- set label template as 6X4_A4_PDF
- Create a delivery using the method
- Validate the delivery
> The generated label is in 8x4 inch format instead of 6x4 full page
Explanation
-----
All info below was found in DHL's API doc from the following YAML file
https://developer.dhl.com/sites/default/files/2026-05/dpdhl-express-api-3.3.0.yaml
There are 2 issues with the current implementation regarding the label format.
1. The formats defined on the model (the `ProviderDHL` `delivery.carrier`) do not match the ones of the API. From the API, the accepted values are the following:
- ECOM26_84_A4_001
- ECOM26_84_001
- ECOM_TC_A4
- ECOM26_A6_002
- ECOM26_84CI_001
- ECOM26_84CI_002
- ECOM26_84CI_003
- ECOM_A4_RU_002
- ECOM26_84_LBBX_001
- ECOM26_64_LBBX_001
(values taken from the excerpt below)
```
templateName:
description: >-
Please enter DHL Express document template name.
<BR> Sample Transport label
templates:<BR> ECOM26_84_A4_001
<BR> ECOM26_84_001 - default<BR>
ECOM_TC_A4<BR> ECOM26_A6_002<BR>
ECOM26_84CI_001<BR> ECOM26_84CI_002 - supported
single customer barcode<BR> ECOM26_84CI_003 -
to be used if customer barcodes are used<BR>
ECOM_A4_RU_002<BR>
ECOM26_84_LBBX_001 - supported for loose BBX shipment<BR>
ECOM26_64_LBBX_001 - supported for loose BBX shipment<BR>
[...]
type: string
maxLength: 25
example: ECOM26_84_001
```
[...]: additional info unrelated to labels (useful only for other `typeCode` values)
Since `ProviderDHL` is a model, the `dhl_label_template` selection values cannot be changed and must thus be mapped to the corresponding API values.
- 8X4_A4_PDF => ECOM26_84_A4_001
- 8X4_thermal => ECOM26_84_001
- 8X4_A4_TC_PDF => ECOM_TC_A4
- 6X4_thermal => ECOM26_A6_002
- 6X4_A4_PDF => ECOM26_A6_002
- 8X4_CI_PDF => ECOM26_84CI_001
- 8X4_CI_thermal => ECOM26_84CI_001
- 8X4_RU_A4_PDF => ECOM_A4_RU_002
- 6X4_PDF => ECOM26_A6_002
- 8X4_PDF => ECOM26_84_001
Couple notes about this matching:
- There is no 6x4 in the API, so A6 is used instead (A6 is 105x148mm, 4x6 is 101.6x152.4mm so not a perfect match but the best option still)
- ECOM26_84_001 and ECOM26_A6_002 are used as default values for the respective formats when there is no exact match possible (eg 6x4 only has one option in the API, the default one)
- "A4" is being ignored, because of point 2
2. There is a specific field to force the label to be in A4 format (according to the API, see excerpt below)
```
fitLabelsToA4:
description: >-
To print respective Transport Label and Waybill document into
A4 margin PDF.<BR> Note:
ECOM26_A6_002,ECOM26_84CI_001,ECOM26_84CI_002,ARCH_6X4,ARCH_8X4
template. <BR> This option is applicable only
for PDF encodingFormat selection.<BR> false:
Transport Label and Waybill document will use default margin
settings (default behavior) <BR> true:
Transport Label and Waybill document will print into A4 margin
PDF
type: boolean
example: false
```
-----
Ticket:
opw-6148713
Forward-Port-Of: odoo/enterprise#117281This update corrects a bug where analytic accounts weren't consistently linked to invoice cost lines, leading to unbalanced accounting reports. The change ensures that both invoice cost lines and related purchase orders have the correct analytic account assigned, resulting in accurate financial reporting. This resolves an issue impacting project cost analysis.
Original PR description
Steps to reproduce: - Activate Anglo-Saxon accounting - Create a product with track inventory and an automated inventory valuation product category - Define MTO on the product - Add this product to…
Steps to reproduce: - Activate Anglo-Saxon accounting - Create a product with track inventory and an automated inventory valuation product category - Define MTO on the product - Add this product to an Analytic Distribution Model (i.e. Legal) - Create a SO for this product - Create and confirm the PO related to it, the Analytic account is set on the PO. - Confirm the reception of the product - This creates a Stock valuation layer with the Analytic account - Confirm the SO - Confirm the delivery of the product - This creates a Stock valuation layer with the Analytic account too - Create the Invoice Issue: Missing analytic account on the 110300 Stock Interim (Delivered) creating unabalanced analytic accounting Other: test_report_invoice_items_anglo_saxon_automatic_valuation introduced in this PR https://github.com/odoo/odoo/pull/205777 checks that in a project's analytic report, the values based on cogs lines are displayed in the cost section. With this fix, both cogs lines will have an analytic account so their impact on the project analytic report will even out. This made the test fail. To keep the benefit of this test, we simulate that the user manually removes the analytic account on some of the cogs lines (those targetting stock interim received). The test was removed by https://github.com/odoo/odoo/pull/236971 from 19.2 onward opw-6060567 Forward-Port-Of: odoo/odoo#266617 Forward-Port-Of: odoo/odoo#261798
This update significantly speeds up the process of validating stock quantities within Odoo, a key function for managing inventory. The changes addressed inefficiencies in how stock quantities were checked, resulting in a dramatic reduction in processing time, especially for large datasets. This improves overall system performance and responsiveness.
Original PR description
Applying stock quants validation was performing poorly due to multiple bottlenecks in `Picking._check_entire_pack` and `StockMoveLine._apply_putaway_strategy`: * **Redundant updates** were performed…
Applying stock quants validation was performing poorly due to multiple bottlenecks in `Picking._check_entire_pack` and `StockMoveLine._apply_putaway_strategy`: * **Redundant updates** were performed on `location_dest_id` in the move lines and the package levels (which internally update all related move lines too), even when the location remained unchanged. * The main loop inside `_check_entire_pack` was **O(N^2)** time relative to the number of move lines due to internal filtering logic. * **Cache misses** triggered unnecessary SQL queries when retrieving `move_line_ids` from `package levels`, while they are already cached via the pickings and can be grouped by `package_level`. --- ### Benchmark Benchmark conducted on a customer database with **400k** `stock_move_line` records within **800** `pickings`, testing performance of the action `StockQuant.action_validate` with different sizes of move lines. Each test was run multiple times and shown is the average mean, all with negligible variance. | Metric | Before | After | Delta | | :--- | :--- | :--- | :--- | | **Benchmark (1k lines)** | 10.5s | 2.2s | -80% | | **Benchmark (5k lines)** | 121s | 8.5s | -93% | | **Benchmark (50k lines)** | 887s | 56s | -94% | | **Benchmark (400k lines)** | timeout | 777s | (within time limit) | **OPW-6045513** Forward-Port-Of: odoo/odoo#262717 Forward-Port-Of: odoo/odoo#257829
This update fixes a previous issue where purchase order information was missing from vendor credit notes (in_refund). Now, users can easily see which purchase order each credit note line is associated with, improving accuracy and streamlining the credit note process. This ensures consistent reporting and simplifies reconciliation.
Original PR description
The purchase_order_id column in invoice lines was hidden for vendor credit notes (in_refund), while it was visible for vendor invoices (in_invoice). This prevented users from identifying which purchase order each line belonged to when a credit note was linked to one or more POs. Include 'in_refund' in the column_invisible condition so the purchase order column is also available on vendor credit note lines. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#267316
This update corrects a rounding issue in the generation of Peppol invoices, ensuring accurate calculations for invoice line amounts. Previously, the system rounded unit prices too aggressively, leading to validation errors. This fix ensures invoices comply with Peppol standards and prevents potential shipping delays or payment issues.
Original PR description
**PROBLEM** Previously, we rounded the unit price up to 6 digits in the generated xml for peppol. However, odoo compute the lineExtensionAmount with the raw unit price. The generated xml is invalid because priceAmount*InvoicedQuantity != LineExtensionAmount. **STEP TO REPRODUCE** Create an invoice with unit price of 0.01110515964, and quantity of 278362.5. Generate an XML with peppol, and try validating the invoice. You should have the following error: [PEPPOL-EN16931-R120]-Invoice line net amount MUST equal (Invoiced quantity * (Item net price/item price base quantity) + Sum of invoice line charge amount - sum of invoice line allowance amount opw-6009771 Forward-Port-Of: odoo/odoo#262242
This fix ensures that account moves generated during inventory valuation use the correct branch company (Branch A) instead of the parent company (Company A). This resolves an access error when navigating to the inventory valuation view, ensuring accurate financial reporting for multi-branch businesses. The change updates how the company ID is determined during account move creation.
Original PR description
**Steps to reproduce:** - create a new company A - in the branch tab, create a new branch A for this company - create a warehouse for the company A and a warehouse for the branch A - from the company…
**Steps to reproduce:** - create a new company A - in the branch tab, create a new branch A for this company - create a warehouse for the company A and a warehouse for the branch A - from the company A, in settings for the 'fiscal localization' set Package : Generic Chart of account, if not already set (to have account journals). From the branch A: - create a storable product with standard perpetual category - set a cost of 10 - confirm a PO for 10 and validate delivery - navigate to 'inventory valuation' Make sure the branch A is the main company, but both branch A and company A are selected: - click on generate entry - click on the 'Other Info' tab **Current behavior:** The company of the account move is the parent company (Company A) **Expected behavior:** It should be the branch A. (As it is the case if only branch A is selected when clicking on "Generate entry") IAs a consequence, f you click on 'Inventory Valuation' on the top left to go back to the view, you will have an access error. **Cause of the issue:** When computing the company_id on the account move, move.journal_id.company_id will be the parent company because the journal_id of the branch is the one of the parent company (by default). So we will call _accessible_branches() on the parent company. https://github.com/odoo/odoo/blob/661ddbb7f12e32394a3c11b5a4cd2f38a9e156f5/addons/account/models/account_move.py#L878-L881 Inside __accessible_branches(), 'accessible' will be based on self.env.companies https://github.com/odoo/odoo/blob/661ddbb7f12e32394a3c11b5a4cd2f38a9e156f5/odoo/addons/base/models/res_company.py#L430-L439 (which is based on 'allowed_company_ids' in the context. https://github.com/odoo/odoo/blob/661ddbb7f12e32394a3c11b5a4cd2f38a9e156f5/odoo/orm/environments.py#L266) So the return value of __accessible_branches() will be a list with 2 ids, the one of the parent company and the one of the branch. And we will use the first element of this list, which will be the parent company_id, in _compute_company_id to set the company of the account move. **fix:** When fetching the data for the inventory valuation view, only the data from the main company selected matters, https://github.com/odoo/odoo/blob/dd84309df7fd39e9e97ed02d135d25b211085135/addons/stock_account/report/stock_valuation_report.py#L13 The idea of the fix is to do the same in action_close_stock_valuation when creating the account move. We already did something very similar in this PR https://github.com/odoo/odoo/pull/262776 where we also modified the context in action_close_stock_valuation() before calling _action_close_stock_valuation() https://github.com/odoo/odoo/blob/43f5ceadbc1f7df9898c327bf65bffdbe9860c1c/addons/stock_account/models/res_company.py#L56 opw-6144294 Forward-Port-Of: odoo/odoo#265369 Forward-Port-Of: odoo/odoo#263828
This update fixes an issue where adding a new product attribute to a template with existing variant prices would reset those prices to the template's base price. The fix ensures that manually set variant prices are preserved, preventing data loss and maintaining accurate pricing for products with variations. This improves the consistency of product pricing within the system.
Original PR description
**Problem:** Adding a single-value attribute to a product template that has variants with manually-set sales prices wipes those prices, resetting each variant back to the template's base list_price.…
**Problem:** Adding a single-value attribute to a product template that has variants with manually-set sales prices wipes those prices, resetting each variant back to the template's base list_price. **Steps to reproduce:** 1. Create a template "Cable" with attribute Length [1m, 5m, 10m, 15m] (template list_price=1.0). 2. On each variant, manually set a unique Sales Price (10/20/30/40). 3. Add a single-value attribute (e.g. Brand=MELODIKA) to the template. 4. Observe variant Sales Prices. **Current behavior:** All four variant prices are reset to 1.0 (the template list_price). Variant ids are unchanged. **Expected behavior:** Variant prices remain at the manually-set values, since no variant is created or removed. **Cause of the issue:** In 19.x, product.product.lst_price is a stored compute with readonly=False, allowing per-variant overrides. The single-value branch of product.template._create_variant_ids writes product_template_attribute_value_ids on each existing variant to attach the new attribute. That write invalidates the variant's price_extra (One2many depends), which in turn invalidates the stored lst_price compute. On the next flush, lst_price is recomputed as list_price + price_extra, overwriting the user override. **Fix:** Snapshot each variant's lst_price before the single-value-attribute write loop and restore the snapshot afterwards if the recompute changed it. This preserves user-set per-variant prices in the case the loop already exists to handle (single-value attribute that does not require recreating variants). Trade-off: if the single-value attribute itself carries a non-zero price_extra and the user had manual overrides, the extra will not auto-propagate to overridden variants. That is preferable to wiping the override entirely, which is the reported regression. opw-6229147
This update fixes an issue where negative line items in the MX CFDI tax reporting were incorrectly handled. The change addresses a conflict introduced by new features and ensures that negative lines are properly distributed as required by Mexican regulations. This ensures accurate tax reporting for our MX customers.
Original PR description
In MX CFDI, negative lines are not allowed so they are distributed over other lines. But because this PR introduces some other `special_type` like `global_discount` and `down_payment`, it becomes useless to check `base_line['special_type'] == False`. Fix for https://github.com/odoo/odoo/pull/267435 task-5900496 --- I confirm I have signed the CLA and read the PR guidelines at [www.odoo.com/submit-pr](http://www.odoo.com/submit-pr) Forward-Port-Of: odoo/enterprise#119254
This update corrects a reporting issue where combo products incorrectly appeared in the 'Invoiced Not Delivered' report, even after full delivery. The fix ensures that only actual undelivered items are listed, improving the accuracy of financial reporting for combo product sales. This prevents duplicate information and provides a clearer view of inventory.
Original PR description
**Problem:** A combo product's parent line appears in the "Invoiced Not Delivered" report (Accounting > Review) and stays there permanently, even after all of its combo items are delivered. **Steps…
**Problem:** A combo product's parent line appears in the "Invoiced Not Delivered" report (Accounting > Review) and stays there permanently, even after all of its combo items are delivered. **Steps to reproduce:** 1. Create a combo product bundling two storable items. 2. Sell the combo on a sale order, confirm and invoice it. 3. Deliver every combo item. 4. Open Accounting > Review > Invoiced Not Delivered. **Current behavior:** The combo parent line is listed. While items are partially delivered, both the parent and the items are listed, duplicating the same information. **Expected behavior:** The combo parent is not listed; only the combo item lines, which carry the real delivery state, appear when they are genuinely not delivered. **Cause of the issue:** A combo parent is a virtual sale order line with no stock move of its own, so its delivered quantity is never advanced and always reads 0. The accrual report selects lines where `qty_invoiced_at_date > qty_delivered_at_date`, so the parent (which does receive an invoiced quantity from the combo logic) matches forever. **Fix:** Combo parents carry no delivery information of their own, so excluding them from the accrual search domain is more accurate than inventing a delivered quantity for them. Their combo item lines already represent the real delivery state, so the report stays correct. opw-6215110 Forward-Port-Of: odoo/enterprise#118942
This update fixes an issue where the Cost of Goods Sold (COGS) was incorrectly calculated when products were delivered and subsequently returned. Previously, returns were not properly accounted for, leading to inaccurate COGS figures. Now, returns are correctly deducted, ensuring accurate COGS calculations for invoices, especially when dealing with multiple deliveries and returns.
Original PR description
When the cogs are computed using the Stock Moves values, we would not differentiate between deliveries and returns, taking both in the cogs value computation. This meant that when doing multiple…
When the cogs are computed using the Stock Moves values, we would not differentiate between deliveries and returns, taking both in the cogs value computation. This meant that when doing multiple deliveries with returns before posting the invoice, if the deliveries/returns had different cost, the COGS would be an average of all of them. Example: Delivery $10 -> Return $10 -> Delivery $20 ==> COGS $13.33
## HOW TO REPRODUCE
- Create Product FIFO Perpetual, cost=10, onHand=1
- Create Sale order for 1 unit
- Deliver and return
- Change cost from 10 to 20:
- Set on hand to 0
- Change product cost to 20
- Set on hand to 1
- Duplicate SO delivery and validate
- Create and Post Invoice => COGS == 13.33
## FIX EXPLANATION
Returns / Refunds are counted negatively.
So when we compute the moves value, instead of doing `(10 + 10 + 20) / (1 + 1 + 1)`, we do `(10 - 10 + 20) / (1 - 1 + 1)`.
We need to propagate this logic to the cogs quantity, so that we don't believe that we invoiced 3 units while only 1 (1-1+1) was delivered.
---
Note:
For the update in test `test_fifo_delivered_invoice_post_delivery_with_return`, I put back the original values modified by 5978bc5dc683d317f4ab87f6c9c9d843568bf4ea
---
<img width="1852" height="363" alt="image" src="https://github.com/user-attachments/assets/ea9f16b2-a818-4c21-b3c3-aa296792f477" />
<img width="1203" height="787" alt="image" src="https://github.com/user-attachments/assets/7348d15a-b840-4ee0-b1da-2b954cdb3d5e" />
---
## Test result without fix:
```
2026-05-28 11:57:45,899 36667 INFO oes_test_19.0 odoo.addons.sale_stock.tests.test_anglo_saxon_valuation: Starting TestAngloSaxonValuation.test_fifo_invoice_with_delivery_with_return ...
2026-05-28 11:57:47,138 36667 INFO oes_test_19.0 odoo.addons.sale_stock.tests.test_anglo_saxon_valuation: ======================================================================
2026-05-28 11:57:47,138 36667 ERROR oes_test_19.0 odoo.addons.sale_stock.tests.test_anglo_saxon_valuation: FAIL: TestAngloSaxonValuation.test_fifo_invoice_with_delivery_with_return
Traceback (most recent call last):
File "/home/odoo/Odoo/src/19.0/odoo/addons/sale_stock/tests/test_anglo_saxon_valuation.py", line 1099, in test_fifo_invoice_with_delivery_with_return
self.assertRecordValues(invoice.line_ids, [
File "/home/odoo/Odoo/src/19.0/odoo/odoo/tests/common.py", line 727, in assertRecordValues
self.assertSequenceEqual(expected_reformatted, record_reformatted, seq_type=list)
AssertionError: Lists differ: [{'ac[22 chars]t': 0, 'credit': 50}, {'account_id': 9141, 'de[114 chars]: 0}] != [{'ac[22 chars]t': 0.0, 'credit': 50.0}, {'account_id': 9141,[132 chars]0.0}]
First differing element 2:
{'account_id': 9138, 'debit': 0, 'credit': 20}
{'account_id': 9138, 'debit': 0.0, 'credit': 13.33}
- [{'account_id': 9162, 'credit': 50, 'debit': 0},
+ [{'account_id': 9162, 'credit': 50.0, 'debit': 0.0},
? ++ ++
- {'account_id': 9141, 'credit': 0, 'debit': 50},
+ {'account_id': 9141, 'credit': 0.0, 'debit': 50.0},
? ++ ++
- {'account_id': 9138, 'credit': 20, 'debit': 0},
? ^^
+ {'account_id': 9138, 'credit': 13.33, 'debit': 0.0},
? ^^^^^ ++
- {'account_id': 9168, 'credit': 0, 'debit': 20}]
? ^^
+ {'account_id': 9168, 'credit': 0.0, 'debit': 13.33}]
? ++ ^^^^^
```
---
OPW-6213321
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#266917This update fixes an issue where currency differences were incorrectly aggregated in hierarchical reports, leading to inaccurate financial summaries. The change ensures that totals are calculated based on the original currency of each transaction, providing more reliable reporting for financial analysis. This improves the accuracy of key business reports.
Original PR description
opw-6015098 Forward-Port-Of: odoo/enterprise#119073 Forward-Port-Of: odoo/enterprise#114827
This update fixes an issue where payments for Mexican invoices were being sent to CFDI multiple times, leading to inaccurate reporting. The change ensures the 'Update Payments' button only appears after the invoice payment is fully reconciled, preventing duplicate submissions and maintaining accurate financial records. This improves compliance with Mexican tax regulations.
Original PR description
Issue: Sending payments to SAT before its full amount is reconciled allow sending the same invoice payment several times to CFDI. Steps to reproduce: - In a Mexican company - Create an invoice A of…
Issue: Sending payments to SAT before its full amount is reconciled allow sending the same invoice payment several times to CFDI. Steps to reproduce: - In a Mexican company - Create an invoice A of $40 to Inmobiliaria CVA - Confirm and send to CFDI - Go to bank, create a new Bank transaction of $80 - reconcile with Invoice A - Go to invoice A => click on button "Update payments" (it doesn't appear in previous versions) - Then sheet CFDI and Download There is the first XML sent to CFDI with payment for invoice A - Create an invoice B of $40 to Inmobilira CVA - Confirm and send to CFDI - reconcile the transaction with Invoice B - Go to invoice B - Click on button "Update payments" - Then sheet CFDI and Download There is the second XML sent to CFDI with payment for invoices A and B Invoice A payment was sent twice to CFDI Expected behavior: - The "Update payment" button should appear only once the invoice payment is fully reconciled. Current behavior: - The update payment button appear once the invoice is reconciled with a payment. The method `_l10n_mx_edi_cfdi_invoice_get_payments_diff` is called twice, once to check whether it's needed to display the "Update button" and once when you try to update the payment (called only after clicking on said button). opw-5432421 Forward-Port-Of: odoo/enterprise#118850 Forward-Port-Of: odoo/enterprise#108355
15 changes
Enhancements to existing features
This update adjusts how global discounts are handled in Odoo to meet the requirements of UBL (Universal Business Language) standards. Previously, discounts were represented as negative invoice lines, which is now changed to 'allowances'. This ensures Odoo-generated invoices are correctly formatted for international trade and compliance.
Original PR description
Export global discounts as Allowances instead of negative invoice lines to comply with UBL specifications. task-5900496 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#267435 Forward-Port-Of: odoo/odoo#261029
Resolved issues and error corrections
This update fixes an issue where EDI invoices were incorrectly assigned to individual contacts due to shared VAT numbers. The change prioritizes main companies and active vendors during matching, ensuring invoices are routed to the correct business entity. This improves data accuracy and reduces manual intervention in invoice processing.
Original PR description
### Description of the issue/feature this PR addresses: **Issue:** When processing incoming EDI/Peppol invoices, multiple contacts (parent companies, joint ventures, child contacts) frequently share…
### Description of the issue/feature this PR addresses: **Issue:** When processing incoming EDI/Peppol invoices, multiple contacts (parent companies, joint ventures, child contacts) frequently share the same VAT number. Because the parser's tie-breaker relies primarily on VAT, invoices are often incorrectly assigned to individual child contacts or newly created joint ventures rather than the correct vendor. **Solution:** Prepend is_company DESC, supplier_rank DESC to the SQL search order in the _import_retrieve_customer fallback domain. This ensures that the matching logic explicitly prioritizes business entities over individual contacts, and active vendors over other records. ### Current behavior before PR: When searching by VAT with limit=1, the parser uses order='company_id, parent_id DESC, id DESC'. If a parent company and a child contact share a VAT, the query frequently returns the child contact or a newer joint venture due to the id DESC fallback. ### Desired behavior after PR is merged: The parser will correctly prioritize main companies over individual contacts when VAT numbers are shared. If multiple companies share the same VAT, the most active vendor will be selected. opw-6174628 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#266224
This update resolves an issue where Luxembourg tax reports were incorrectly including the company's registry number instead of the agent's RCS number. This prevented the reports from being accepted by the Luxembourg tax administration. The fix ensures the correct RCS number is used when an agent is linked, complying with Luxembourg tax regulations.
Original PR description
**Steps to reproduce:** * install `l10n_lu_reports`. * Create a company in Luxembourg with a `company_registry` number set. * Link this company to an accounting firm that is a natural person…
**Steps to reproduce:** * install `l10n_lu_reports`. * Create a company in Luxembourg with a `company_registry` number set. * Link this company to an accounting firm that is a natural person (independent accountant) with no business registration number — i.e. `l10n_lu_agent_rcs_number` is left empty on the agent partner. * Go to the tax report and generate the XML declaration. **Observed behavior:** * The `<Agent><RCSNbr>` field in the generated XML contains the company's own `company_registry` value instead of `NE`. * The file is rejected by the Luxembourg tax administration. **Cause:** * In `l10n_lu_generate_xml.py`, the `agent_rcs_number` template value was built with a plain `or` chain: `agent.l10n_lu_agent_rcs_number or company.company_registry or "NE"` * When an agent is set but has no RCS number (natural person), the fallback incorrectly continued to `company.company_registry` instead of stopping at `"NE"`. **Fix:** * Use a conditional expression so that `company.company_registry` is only used as a fallback when **no agent is linked** to the company: `(agent.l10n_lu_agent_rcs_number if agent else company.company_registry) or "NE"` opw-6044689 Forward-Port-Of: odoo/enterprise#112968
This update resolves an issue preventing Live Chat users with standard access from using chatbot messages within custom filters. The fix adjusts security permissions to allow the ‘im_livechat_group_manager’ group access to chatbot messages, ensuring broader functionality for Live Chat users.
Original PR description
**Steps to Reproduce** 1. Install the **Live Chat** module in version 18.4 or above. 2. Go to: **Settings → Users** * Open your user and change the access rights from **Live Chat / Administrator** to…
**Steps to Reproduce**
1. Install the **Live Chat** module in version 18.4 or above.
2. Go to: **Settings → Users**
* Open your user and change the access rights from **Live Chat / Administrator** to **Live Chat / User**.
* Alternatively, create a new user giving him rights of the **Live Chat / User** group.
3. Login using the Live Chat user.
4. Open the **Live Chat** application and navigate to: **Live Chat → Sessions**
5. Open any existing session. The session and its messages are accessible without any issue.
6. In the search bar, click: **Filters → Custom Filter**
7. Select the field `Chatbot Messages (chatbot_message_ids)`. You will face the below traceback.
**Issue Description:**
The issue happens because `discuss.channel` records are accessible to users having the `im_livechat_group_user` group through the Sessions menu: https://github.com/odoo/odoo/blob/459a775a066fe1465e53fc751045baed39f80118/addons/im_livechat/views/im_livechat_channel_views.xml#L310-L315
The field `chatbot_message_ids` is defined as:
https://github.com/odoo/odoo/blob/459a775a066fe1465e53fc751045baed39f80118/addons/im_livechat/models/discuss_channel.py#L165
This field points to the `chatbot.message` model, but access to that model is restricted to `im_livechat_group_manager` only:
https://github.com/odoo/odoo/blob/459a775a066fe1465e53fc751045baed39f80118/addons/im_livechat/security/ir.model.access.csv#L15
As a result, when a Live Chat user tries to use `chatbot_message_ids` in a custom filter, Odoo attempts to read `chatbot.message` records and raises an `AccessError`.
This issue started happening after the access rights changes introduced in pr : https://github.com/odoo/odoo/pull/201880
Specifically, the following ACL changes:
https://github.com/odoo/odoo/pull/201880/changes#diff-c1592d633a34db44a7cc2a527482cecc56127cbba72649e7318dcf63ccf477afR19-R20
**Solution:**
To fix this issue, added the group `im_livechat_group_manager` on the field `chatbot_message_ids` so only those user can access the field who belong to the group.
**Traceback:**
```.py
odoo.exceptions.AccessError: You are not allowed to access
'Chatbot Message' (chatbot.message) records.
This operation is allowed for the following groups:
- Live Chat/Administrator
Contact your administrator to request access if necessary.
```
opw - [6169395]
upg - [4274573]
Description of the issue/feature this PR addresses:
Current behavior before PR:
Desired behavior after PR is merged:
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#264682This update ensures that manufacturing orders linked to projects with mandatory analytic plans are properly configured before confirmation. Previously, users could bypass this requirement, leading to potential accounting discrepancies. Now, the system enforces the use of a valid analytic distribution, preventing errors and improving data accuracy.
Original PR description
Currently, it is possible to confirm a manufacturing order linked to a project without an analytic distribution, even when a plan is set as mandatory for Manufacturing Orders. Fix: On action_confirm, check whether the related project has mandatory plans set and, if so, ensure they are filled — raising a ValidationError otherwise. task-id [6250034](https://www.odoo.com/odoo/project/967/tasks/6250034) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#266943
This update fixes an issue where SII invoice JSONs weren't accurately displaying quarterly tax periods. The change ensures that the generated JSON correctly reflects the company's 'Tax Periodicity' setting, aligning with Spanish tax regulations. This improves data accuracy for tax reporting.
Original PR description
### Issue: When the company `tax_periodicity` is set to quarterly, the generated SII invoice JSON still uses the monthly period format According to the documentation, the options for Periodo include…
### Issue: When the company `tax_periodicity` is set to quarterly, the generated SII invoice JSON still uses the monthly period format According to the documentation, the options for Periodo include distinction between monthly and trimester (p224 - 225): https://sede.agenciatributaria.gob.es/static_files/Sede/Procedimiento_ayuda/G417/FicherosSuministros/V_1_1/SII-Descripcion-ServicioWeb-v1-1_es_es.pdf ### Cause: The invoice JSON generation does not consider the company's `tax_periodicity` This logic was probably omitted because `account_reports` may not be installed However, when the periodicity is configured, the generated SII document should reflect it correctly ### Steps to reproduce: - Install `l10n_es_edi_sii` and `account_reports` - In Settings, set `Tax Periodicity` to `Quarterly` - In Settings, set `Tax Agency for SII` to `Agencia Tributaria Española` - Change ES Company vat number to `ESA12345674` - Create an invoice (Date: 01/05/2026, Customer: ES Company) - Open the generated JSON document - Check the Periodo value, it should be 2T in May opw-6050587 Forward-Port-Of: odoo/odoo#267708 Forward-Port-Of: odoo/odoo#264063
This update corrects a bug in the POS system that was incorrectly handling line quantity decreases, particularly when certain certification modules (like those for SE and DE) were enabled. The change ensures accurate tracking of decreased lines within orders, preventing incorrect quantity calculations and improving order accuracy. This resolves a previous issue impacting the POS experience for users with these modules.
Original PR description
This commit will affect all certification modules for the POS (pos_blackbox_be, l10n_se_pos, l10n_de_pos_res_cert) Inside the base `handleDecreaseLine` we match all the lines which have the same…
This commit will affect all certification modules for the POS (pos_blackbox_be, l10n_se_pos, l10n_de_pos_res_cert) Inside the base `handleDecreaseLine` we match all the lines which have the same product_id and compute the new quantity based on those. At the end we create a new line with the decreased quantity. This method is called when `disallowLineQuantityChange()` returns `false`, so when either of `pos_blackbox_be`, `l10n_se_pos` or `l10_de_pos_res_cert` are installed. The problem is that different combos will still have the same product_id and total_excluded_currency, so the `current_saved_quantity` adds the other unrelated combos together and tries to remove from the total of all the combos with the same parent. This commit will keep the decrease line for an order in the uiState. So instead of iterating over all the lines in the order and matching lines which have the same product_id we always keep track of the original line and the matching decrease line for that line. Task-[6173236](https://www.odoo.com/odoo/project/1737/tasks/6173236) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262744
This update fixes an issue where the calculation of Cost of Goods Sold (COGS) was incorrectly averaging delivery and return values, leading to inaccurate COGS figures. Previously, returns weren't properly accounted for, resulting in inflated COGS calculations. Now, returns are correctly deducted, ensuring accurate COGS reporting for sales with deliveries and returns.
Original PR description
When the cogs are computed using the Stock Moves values, we would not differentiate between deliveries and returns, taking both in the cogs value computation. This meant that when doing multiple…
When the cogs are computed using the Stock Moves values, we would not differentiate between deliveries and returns, taking both in the cogs value computation. This meant that when doing multiple deliveries with returns before posting the invoice, if the deliveries/returns had different cost, the COGS would be an average of all of them. Example: Delivery $10 -> Return $10 -> Delivery $20 ==> COGS $13.33
## HOW TO REPRODUCE
- Create Product FIFO Perpetual, cost=10, onHand=1
- Create Sale order for 1 unit
- Deliver and return
- Change cost from 10 to 20:
- Set on hand to 0
- Change product cost to 20
- Set on hand to 1
- Duplicate SO delivery and validate
- Create and Post Invoice => COGS == 13.33
## FIX EXPLANATION
Returns / Refunds are counted negatively.
So when we compute the moves value, instead of doing `(10 + 10 + 20) / (1 + 1 + 1)`, we do `(10 - 10 + 20) / (1 - 1 + 1)`.
We need to propagate this logic to the cogs quantity, so that we don't believe that we invoiced 3 units while only 1 (1-1+1) was delivered.
---
Note:
For the update in test `test_fifo_delivered_invoice_post_delivery_with_return`, I put back the original values modified by 5978bc5dc683d317f4ab87f6c9c9d843568bf4ea
---
<img width="1852" height="363" alt="image" src="https://github.com/user-attachments/assets/ea9f16b2-a818-4c21-b3c3-aa296792f477" />
<img width="1203" height="787" alt="image" src="https://github.com/user-attachments/assets/7348d15a-b840-4ee0-b1da-2b954cdb3d5e" />
---
## Test result without fix:
```
2026-05-28 11:57:45,899 36667 INFO oes_test_19.0 odoo.addons.sale_stock.tests.test_anglo_saxon_valuation: Starting TestAngloSaxonValuation.test_fifo_invoice_with_delivery_with_return ...
2026-05-28 11:57:47,138 36667 INFO oes_test_19.0 odoo.addons.sale_stock.tests.test_anglo_saxon_valuation: ======================================================================
2026-05-28 11:57:47,138 36667 ERROR oes_test_19.0 odoo.addons.sale_stock.tests.test_anglo_saxon_valuation: FAIL: TestAngloSaxonValuation.test_fifo_invoice_with_delivery_with_return
Traceback (most recent call last):
File "/home/odoo/Odoo/src/19.0/odoo/addons/sale_stock/tests/test_anglo_saxon_valuation.py", line 1099, in test_fifo_invoice_with_delivery_with_return
self.assertRecordValues(invoice.line_ids, [
File "/home/odoo/Odoo/src/19.0/odoo/odoo/tests/common.py", line 727, in assertRecordValues
self.assertSequenceEqual(expected_reformatted, record_reformatted, seq_type=list)
AssertionError: Lists differ: [{'ac[22 chars]t': 0, 'credit': 50}, {'account_id': 9141, 'de[114 chars]: 0}] != [{'ac[22 chars]t': 0.0, 'credit': 50.0}, {'account_id': 9141,[132 chars]0.0}]
First differing element 2:
{'account_id': 9138, 'debit': 0, 'credit': 20}
{'account_id': 9138, 'debit': 0.0, 'credit': 13.33}
- [{'account_id': 9162, 'credit': 50, 'debit': 0},
+ [{'account_id': 9162, 'credit': 50.0, 'debit': 0.0},
? ++ ++
- {'account_id': 9141, 'credit': 0, 'debit': 50},
+ {'account_id': 9141, 'credit': 0.0, 'debit': 50.0},
? ++ ++
- {'account_id': 9138, 'credit': 20, 'debit': 0},
? ^^
+ {'account_id': 9138, 'credit': 13.33, 'debit': 0.0},
? ^^^^^ ++
- {'account_id': 9168, 'credit': 0, 'debit': 20}]
? ^^
+ {'account_id': 9168, 'credit': 0.0, 'debit': 13.33}]
? ++ ^^^^^
```
---
OPW-6213321
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#266917This change corrects a problem where DHL shipping labels weren't using the correct template dimensions, resulting in labels printed in the wrong size (8x4 instead of 6x4). The code now maps the selected label template to the correct format required by the DHL API, ensuring accurate label dimensions.
Original PR description
Issue ----- Labels generated with DHL do not respect the template (dimensions) set on the delivery method. Steps to reproduce ----- - Set up DHL - set label template as 6X4_A4_PDF - Create a delivery…
Issue
-----
Labels generated with DHL do not respect the template (dimensions) set on the
delivery method.
Steps to reproduce
-----
- Set up DHL
- set label template as 6X4_A4_PDF
- Create a delivery using the method
- Validate the delivery
> The generated label is in 8x4 inch format instead of 6x4 full page
Explanation
-----
All info below was found in DHL's API doc from the following YAML file
https://developer.dhl.com/sites/default/files/2026-05/dpdhl-express-api-3.3.0.yaml
There are 2 issues with the current implementation regarding the label format.
1. The formats defined on the model (the `ProviderDHL` `delivery.carrier`) do not match the ones of the API. From the API, the accepted values are the following:
- ECOM26_84_A4_001
- ECOM26_84_001
- ECOM_TC_A4
- ECOM26_A6_002
- ECOM26_84CI_001
- ECOM26_84CI_002
- ECOM26_84CI_003
- ECOM_A4_RU_002
- ECOM26_84_LBBX_001
- ECOM26_64_LBBX_001
(values taken from the excerpt below)
```
templateName:
description: >-
Please enter DHL Express document template name.
<BR> Sample Transport label
templates:<BR> ECOM26_84_A4_001
<BR> ECOM26_84_001 - default<BR>
ECOM_TC_A4<BR> ECOM26_A6_002<BR>
ECOM26_84CI_001<BR> ECOM26_84CI_002 - supported
single customer barcode<BR> ECOM26_84CI_003 -
to be used if customer barcodes are used<BR>
ECOM_A4_RU_002<BR>
ECOM26_84_LBBX_001 - supported for loose BBX shipment<BR>
ECOM26_64_LBBX_001 - supported for loose BBX shipment<BR>
[...]
type: string
maxLength: 25
example: ECOM26_84_001
```
[...]: additional info unrelated to labels (useful only for other `typeCode` values)
Since `ProviderDHL` is a model, the `dhl_label_template` selection values cannot be changed and must thus be mapped to the corresponding API values.
- 8X4_A4_PDF => ECOM26_84_A4_001
- 8X4_thermal => ECOM26_84_001
- 8X4_A4_TC_PDF => ECOM_TC_A4
- 6X4_thermal => ECOM26_A6_002
- 6X4_A4_PDF => ECOM26_A6_002
- 8X4_CI_PDF => ECOM26_84CI_001
- 8X4_CI_thermal => ECOM26_84CI_001
- 8X4_RU_A4_PDF => ECOM_A4_RU_002
- 6X4_PDF => ECOM26_A6_002
- 8X4_PDF => ECOM26_84_001
Couple notes about this matching:
- There is no 6x4 in the API, so A6 is used instead (A6 is 105x148mm, 4x6 is 101.6x152.4mm so not a perfect match but the best option still)
- ECOM26_84_001 and ECOM26_A6_002 are used as default values for the respective formats when there is no exact match possible (eg 6x4 only has one option in the API, the default one)
- "A4" is being ignored, because of point 2
2. There is a specific field to force the label to be in A4 format (according to the API, see excerpt below)
```
fitLabelsToA4:
description: >-
To print respective Transport Label and Waybill document into
A4 margin PDF.<BR> Note:
ECOM26_A6_002,ECOM26_84CI_001,ECOM26_84CI_002,ARCH_6X4,ARCH_8X4
template. <BR> This option is applicable only
for PDF encodingFormat selection.<BR> false:
Transport Label and Waybill document will use default margin
settings (default behavior) <BR> true:
Transport Label and Waybill document will print into A4 margin
PDF
type: boolean
example: false
```
-----
Ticket:
opw-6148713
Forward-Port-Of: odoo/enterprise#117281This update significantly speeds up the process of validating stock quantities within Odoo, a key function for managing inventory. The changes addressed inefficiencies in how stock quantities were checked, resulting in a dramatic reduction in processing time, especially for large datasets. This improves overall system responsiveness and reduces delays in order fulfillment.
Original PR description
Applying stock quants validation was performing poorly due to multiple bottlenecks in `Picking._check_entire_pack` and `StockMoveLine._apply_putaway_strategy`: * **Redundant updates** were performed…
Applying stock quants validation was performing poorly due to multiple bottlenecks in `Picking._check_entire_pack` and `StockMoveLine._apply_putaway_strategy`: * **Redundant updates** were performed on `location_dest_id` in the move lines and the package levels (which internally update all related move lines too), even when the location remained unchanged. * The main loop inside `_check_entire_pack` was **O(N^2)** time relative to the number of move lines due to internal filtering logic. * **Cache misses** triggered unnecessary SQL queries when retrieving `move_line_ids` from `package levels`, while they are already cached via the pickings and can be grouped by `package_level`. --- ### Benchmark Benchmark conducted on a customer database with **400k** `stock_move_line` records within **800** `pickings`, testing performance of the action `StockQuant.action_validate` with different sizes of move lines. Each test was run multiple times and shown is the average mean, all with negligible variance. | Metric | Before | After | Delta | | :--- | :--- | :--- | :--- | | **Benchmark (1k lines)** | 10.5s | 2.2s | -80% | | **Benchmark (5k lines)** | 121s | 8.5s | -93% | | **Benchmark (50k lines)** | 887s | 56s | -94% | | **Benchmark (400k lines)** | timeout | 777s | (within time limit) | **OPW-6045513** Forward-Port-Of: odoo/odoo#262717 Forward-Port-Of: odoo/odoo#257829
This update fixes a previous issue where purchase order information was missing from vendor credit notes (in_refund). Now, users can easily see which purchase order each credit note line is associated with, improving accuracy and streamlining the reconciliation process. This ensures consistent reporting across invoice and credit note types.
Original PR description
The purchase_order_id column in invoice lines was hidden for vendor credit notes (in_refund), while it was visible for vendor invoices (in_invoice). This prevented users from identifying which purchase order each line belonged to when a credit note was linked to one or more POs. Include 'in_refund' in the column_invisible condition so the purchase order column is also available on vendor credit note lines. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#267316
This update fixes an error in the executive summary report that was incorrectly calculating the period length. Previously, it was measuring the gap between dates instead of the number of days, leading to inaccurate metrics like Average Debtor Days. This change ensures the report accurately reflects the period's length, improving the reliability of key business data.
Original PR description
`_report_custom_engine_executive_summary_ndays` returned `date_to - date_from`, which is the gap between the two dates, not the count of days they span. For example April 2026-04-01 to 2026-04-30 will returned 29 instead of 30, making Average Debtor Days incorrect. Add +1 so the day count is inclusive of both endpoints, matching the rest of the report's date handling. opw-6215362 Forward-Port-Of: odoo/enterprise#118953
This update corrects an issue where combo products incorrectly appeared in the 'Invoiced Not Delivered' report, even after full delivery of their items. The fix ensures that only actual undelivered items are listed, improving the accuracy of this key accounting report. This prevents duplicate reporting and provides a more reliable view of inventory.
Original PR description
**Problem:** A combo product's parent line appears in the "Invoiced Not Delivered" report (Accounting > Review) and stays there permanently, even after all of its combo items are delivered. **Steps…
**Problem:** A combo product's parent line appears in the "Invoiced Not Delivered" report (Accounting > Review) and stays there permanently, even after all of its combo items are delivered. **Steps to reproduce:** 1. Create a combo product bundling two storable items. 2. Sell the combo on a sale order, confirm and invoice it. 3. Deliver every combo item. 4. Open Accounting > Review > Invoiced Not Delivered. **Current behavior:** The combo parent line is listed. While items are partially delivered, both the parent and the items are listed, duplicating the same information. **Expected behavior:** The combo parent is not listed; only the combo item lines, which carry the real delivery state, appear when they are genuinely not delivered. **Cause of the issue:** A combo parent is a virtual sale order line with no stock move of its own, so its delivered quantity is never advanced and always reads 0. The accrual report selects lines where `qty_invoiced_at_date > qty_delivered_at_date`, so the parent (which does receive an invoiced quantity from the combo logic) matches forever. **Fix:** Combo parents carry no delivery information of their own, so excluding them from the accrual search domain is more accurate than inventing a delivered quantity for them. Their combo item lines already represent the real delivery state, so the report stays correct. opw-6215110 Forward-Port-Of: odoo/enterprise#118942
This update fixes an issue where currency differences were incorrectly aggregated in hierarchical financial reports. Previously, the reports presented a single total that didn't accurately reflect the underlying currency values. This change ensures that reports display totals in the correct currency, providing more reliable financial data.
Original PR description
opw-6015098 Forward-Port-Of: odoo/enterprise#119073 Forward-Port-Of: odoo/enterprise#114827
This update fixes an issue where discounts entered with a comma (used in some regions) were incorrectly interpreted as zero. The change ensures that discounts with commas are now correctly applied to orders, preventing revenue loss and improving order accuracy. This resolves a technical bug impacting discount calculations.
Original PR description
Before this commit, if comma was used as decimal separator, the fixed discount valu was added to the order as zero discount. opw-6268557 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
1 change
Resolved issues and error corrections
This update fixes an issue where barcode scanning incorrectly displayed delivered quantities on sales orders. The problem stemmed from how the system processed barcode scans, leading to inaccurate order fulfillment. The fix ensures that quantities are correctly reflected after scanning lots, resolving delivery discrepancies.
Original PR description
Currently when user adds adds quantity in barcode using lots it leads to incorrect sale order quantities. ## Steps to replicate: - Install Sales and Barcode (no demo data). - Enable Lots & Serial…
Currently when user adds adds quantity in barcode using lots it leads to incorrect sale order quantities.
## Steps to replicate:
- Install Sales and Barcode (no demo data).
- Enable Lots & Serial Numbers in settings.
- Create Test Product with Tracking by Lots.
- Go to Inventory > Products>Lots & Serial Numbers and create 3 lots for the product.
- Update each lot’s on-hand quantity to 10 from the product page.
- Create and confirm a Sales Order for the product (lines: qty 3 and 2 units).
- Open the delivery in the Barcode app:
- Scan lot 2 > increase qty to 3 using +1 button
- Scan lot 3 > increase qty to 2 using +1 button
- Validate and go to the sale order.
## Observed Behavior:
The sale order delivered quantities are flipped and a backorder is created even though the quantity for the product is satisfied.
## Root cause:
The issue occurs because when a sales order is confirmed, the system defaults to
using lot 1 on the delivery receipt. When a user scans lot 2, the `_processBarcode` function is triggered, which calls `_findLine` at [1] to select the appropriate line on the receipt.
As the loop in `_findLine` iterates through `pageLines` with values like:
```
[{display_name: "Test product", quantity: 3, lot_id: { name: 'lot1' }},
{display_name: "Test product", quantity: 2, lot_id: { name: 'lot1' }}]
```
During the first iteration, `foundLine` is set at [2] for the line with quantity 3 . Since the subsequent if condition is not satisfied, the loop hits the continue block at [3].
On the next iteration, the line with quantity 2 causes `foundLine` to be overwritten at [2], and the continue block is executed again at [3].
This results in the line with quantity 2 being selected as the line to update at the end of the function.
When the user manually increases the quantity to 3, the line that originally required quantity 2 is updated and fulfilled.
Later, when lot 3 is scanned, the line that required quantity 3 is selected for update, and manually increasing the quantity to 2 before validating the order leads to a backorder and causes the delivered quantities to be flipped.
[1]:
https://github.com/odoo/enterprise/blob/81eaeb4b18d849c644160234def6c69013591abe/stock_barcode/static/src/models/barcode_model.js#L1335-L1337 [2]:
https://github.com/odoo/enterprise/blob/81eaeb4b18d849c644160234def6c69013591abe/stock_barcode/static/src/models/barcode_model.js#L1690-L1699 [3]:
https://github.com/odoo/enterprise/blob/81eaeb4b18d849c644160234def6c69013591abe/stock_barcode/static/src/models/barcode_model.js#L1727-L1729
## Solution:
Avoid grouping lines from different moves unless using batch transfers. This ensures that backorders are not created when the barcode lines are fulfilled.
opw-5423943
Forward-Port-Of: odoo/enterprise#118085
Forward-Port-Of: odoo/enterprise#1090326 changes
Resolved issues and error corrections
This update corrects a bug where taxes were incorrectly applied to COGS lines generated from vendor bills. The fix ensures that COGS lines, representing internal operations, are not subject to tax calculations, maintaining accurate financial reporting. This resolves a previous issue impacting tax accuracy on sales transactions.
Original PR description
Issue: After manually modifying the taxes on a vendor bill that generates COGS lines, confirming the vendor bill causes the taxes to revert to their original values before the manual edit. This…
Issue: After manually modifying the taxes on a vendor bill that generates COGS lines, confirming the vendor bill causes the taxes to revert to their original values before the manual edit. This happens because the product’s purchase taxes are applied to the generated COGS lines, which triggers the tax recomputation logic and overwrites the manually adjusted tax amounts. However, COGS lines represent internal operations and should not have taxes applied to them Steps to reproduce: 1. Turn on Anglo-Saxon accounting 2. Turn on automatic accounting 3. Make a FIFO product category and make the valuation automatic 4. Make a new product and set the FIFO product category on it 5. Make sure the product has a vendor tax set 6. Make a purchase order for 10 of the FIFO product category at $10 7. Create and validate the receipt for 10 8. Make a sales order for 6 of the FIFO product category at $10 9. Create and validate the delivery for 6 10. Create the vendor bill for 10 the purchase order created above (make sure that there is a tax set on the vendor bill; the vendor tax that was set on the product). Make this vendor bill set for 10 at $20 11. Edit the tax at the bottom of the total 12. Confirm the vendor bill 13. Notice that the tax at the bottom of the total changes 14. Reset the vendor bill 15. Remove the purchase tax from the product 16. Confirm the vendor bill again and notice that the tax at the bottom of the total does not change this time Cause: On confirmation, the COGS lines on the vendor bill will be generated and “_compute_tax_ids” will be triggered on those lines. Since COGS lines have a “product_id” set on them, those lines will receive the purchase tax set on the product. Setting the “tax_ids” on those COGS lines will cause tax computation to trigger again, which will reset the manually edited tax amount to the new computed amount. However, since COGS lines come in pairs that are equal and opposite in amount, the taxes from both COGS lines will cancel out, and the new computed tax amount does not change Solution: Skip setting the purchase taxes of the product onto COGS lines in “_compute_tax_ids” opw-6110692 Forward-Port-Of: odoo/odoo#267957 Forward-Port-Of: odoo/odoo#265352
This update resolves an issue preventing users from correctly inserting dynamic fields into SMS templates within Marketing Automation. The fix ensures the system recognizes the correct data source (`mailing_model_real`) for SMS templates, allowing users to build campaigns with accurate, personalized messages. This improves the overall reliability of the SMS marketing feature.
Original PR description
The SMS template form view in Marketing Automation was missing the `dynamic_placeholder_model_reference_field` option on the `body_plaintext` field. Without this option, the dynamic placeholder hook falls back to looking for a `model` field in the record data, but `mailing.mailing` uses `mailing_model_real` instead. Steps To Reproduce: - Install marketing_automation_sms and CRM modules (also activate Leads). - Start a new Campaign in Marketing Automation. - Set Target to Lead/Opportunity. - Add New Activity > Activity Type = SMS > SMS Template = create one. - In the SMS template dialog, click the "Insert Field" button. - Error appears: "You need to select a model before opening the dynamic placeholder selector." Ticket [link](https://www.odoo.com/odoo/project.task/5488849) opw-5488849 Forward-Port-Of: odoo/enterprise#104423
This update fixes an issue where incorrect tax reason codes were being generated when using co-contractant fiscal positions. This prevented the system from properly validating invoices against Peppol standards, ensuring compliance and accurate tax reporting. The change ensures the correct tax reason code is applied, resolving a validation error.
Original PR description
When a co-contractant fisacl position is selected and the user chooses a tax that does not belong to that fiscal position, a tax exemption reason code is added, which breaks the schematron validation on peppol. related-task-id-5905176 Forward-Port-Of: odoo/odoo#266429 Forward-Port-Of: odoo/odoo#264887
This update resolves an issue where lengthy address fields during credit card payments via Authorize.net caused error messages. The system now automatically truncates excessively long fields to comply with the Authorize.net API requirements, ensuring smooth payment processing. This improves payment reliability and prevents disruptions for our customers.
Original PR description
Steps to reproduce: - install payment_authorize module; - complete a credit card payment using Authorize.net with more than 60 characters on any other field than first name, last name or company; - confirm the payment. Issue: An error message appears. Cause: The Authorize.net API define the max length of information. It is possible that some information exceeds the maximum length. (https://apitest.authorize.net/xml/v1/schema/AnetApiSchema.xsd) Solution: Truncate information if the number of character is too large. opw-6141441 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262154
This update resolves an issue preventing Peruvian businesses from generating Closing Entries in Odoo 18.3. The change introduces a dedicated tax report variant and Return Type, ensuring accurate VAT calculations and proper accounting workflows within multi-VAT environments. This allows users to utilize Odoo's automated closing processes safely.
Original PR description
### Issue Since the introduction of the Tax Returns feature in 18.3, it was no longer possible to generate a Closing Entry as the button has been replaced by Returns The Return mechanism implies that…
### Issue Since the introduction of the Tax Returns feature in 18.3, it was no longer possible to generate a Closing Entry as the button has been replaced by Returns The Return mechanism implies that you need a Return Type in order to make a Closing Entry using the Validate button Additionally, using the Generic Tax Report by default creates a risk in Multi-VAT environments, as it mixes taxes from all countries instead of isolating Peruvian taxes ### Cause The new 18.3 accounting workflow requires at least one active Return Type associated with a country-specific report variant to display the Return options and process the closing entry Peru was relying on the Generic Tax Report, without a dedicated report variant No Return Type was configured, which blocked Odoo's automatic VAT closing workflow and prevented the system from prompting the user to configure the required closing accounts ### Steps to reproduce - Install `l10n_pe_reports` and `accountant` - Switch to a PE Company - Go to the Tax Report Before the fix, no Returns button is available for any of the existing reports, making it impossible to use Odoo's automatic process to configure the tax accounts and trigger the closing entry ### Notes This is fixed by creating a dedicated Peruvian tax report variant directly in Enterprise that inherits from the generic tax report A custom handler is added to force the domain filtering on Peruvian taxes only, and a corresponding Return Type is defined to restore the full closing entry process safely enterprise-pr: https://github.com/odoo/enterprise/pull/117891 opw-5978673
This update resolves a bug that caused unexpected pop-ups and errors when using preset orders in the restaurant POS. The fix ensures that the time slot selection process correctly exits when an existing order is merged and deleted, improving the overall stability and usability of the system. This prevents disruptions during order creation.
Original PR description
pos*: point_of_sale, pos_restaurant Steps to reproduce: - Configure a preset identified by name and managed by time. - Open the restaurant POS. - Create a direct order and set a tab for it. - Return to the floor screen and create another direct order. - Select the configured preset and choose the previously created order from the order name popup. Issue: - The time slot selection popup appears unexpectedly. - Selecting a time slot triggers a traceback. Cause: - When selecting an existing order, the current order is merged into the selected order. - However, the time slot selection flow remains active for the merged order, which has already been deleted. Fix: - Exit the preset selection flow when the order is merged and deleted. Task-6032880
4 changes
Resolved issues and error corrections
This update fixes a bug that allowed internal transfer validations to proceed without scanning the destination location. Previously, deleting a line would cause validation to succeed even if the location wasn't scanned. The fix ensures validation only occurs after a destination location has been scanned, improving data accuracy and user experience.
Original PR description
Currently, when a user deletes a line and validates internal movement in the barcode system, the system allows validation even though specifying the destination location after each scan is required.…
Currently, when a user deletes a line and validates internal movement in the barcode system, the system allows validation even though specifying the destination location after each scan is required. ## Steps to produce: - Install the Inventory module - Go to Settings and enable Storage Locations. - Inventory > Configuration > Operation Types > Internal Transfers > Barcode App - Configure the Destination Location to require scanning after each product. - Create an Internal Transfer for Pedal Bin, demand 1. - Mark the transfer as To Do and open it in the Barcode app. - Add quantity using +1, then scan the barcode for the Pedal Bin(Barcode: 6016478556493). - Delete the newly added line and attempt to Validate. ## Observed Behavior: The system should prevent transfer validation when the destination location has not been scanned and display a notification to the user, similar to the behavior before user deleted the newly added line. ## Root cause: This issue occurs because when the delete button is pressed, the deleteLine function [1] removes the line, but the deleted line becomes the selected line due to [2] being triggered before the UI updates. As a result, the selected line is now undefined. Since the selected line is undefined, it fails to meet the condition at [3] during validation. This prevents notifications from being triggered and allows the transfer to be validated before the destination location has been scanned. [1]: https://github.com/odoo/enterprise/blob/3476d15bf8e75eb6530658dd623861b60963ab40/stock_barcode/static/src/models/barcode_model.js#L826-L836 [2] : https://github.com/odoo/enterprise/blob/327d4478128f33fb2e0c477533bd4983178abf17/stock_barcode/static/src/components/line.js#L129-L133 [3]: https://github.com/odoo/enterprise/blob/6ff158ca3a6d2d2b3d285a7f8317622844811688/stock_barcode/static/src/models/barcode_picking_model.js#L945-L948 ## Solution: We can prevent users from validating if any line has an unscanned destination location when destination-location scanning is mandatory after scanning each product. To enforce this behavior, we can track whether a line has been modified and whether a destination location has been scanned and applied to that line. This allows us to identify which lines still require destination location scanning before validation can proceed. However, line state information is currently discarded and recreated on every save. As a result, information about lines that were updated and already had their destination location scanned is lost. This may incorrectly require users to rescan the destination location, even though it was previously scanned. To address this, we preserve the destination-scanned and modified state by carrying it forward from existing lines to their corresponding newly created versions using a loop. This ensures that destination location scan status is retained and users are not asked to rescan unnecessarily. opw-6069614 Forward-Port-Of: odoo/enterprise#113618
This update resolves an error that occurred when users attempted to use property fields within auto-fill fields in the sign module. The fix restricts property field selection, ensuring data integrity and preventing the application from crashing. This change improves the stability of the sign process.
Original PR description
Currently, an error occurs when user tries to select a property field in auto field. Steps to replicate: - Install `sale_management` and `sign`. - Open Sales > Products > Products > Open any product.…
Currently, an error occurs when user tries to select a property field in auto field.
Steps to replicate:
- Install `sale_management` and `sign`.
- Open Sales > Products > Products > Open any product.
- From the Gear icon, Click Edit Properties and save the record.
- Enable Debug mode if you are using a version lower than 19.0 .
- Open Sign > Configuration > Field Types.
- Create a new Field > Give a name > Select model as `Product`.
- Select Field as `Property > Property 1` and click save.
Error:
- saas-18.3 and later:
```
File '/home/odoo/odoo18/enterprise/sign/models/sign_item_type.py', line 57, in _check_auto_field_exists
auto_field_value = record.mapped(sign_type.auto_field)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File '/home/odoo/odoo18/community/odoo/orm/models.py', line 5472, in mapped
field = records._fields[field_name]
^^^^^^^^^^^^^^^
AttributeError: 'Property' object has no attribute '_fields'. Did you mean: 'field'?
```
- saas-18.2:
```
File '/home/odoo/odoo18/enterprise/sign/models/sign_item_type.py, line 41, in _check_auto_field_exists
auto_field_value = record.mapped(sign_type.auto_field)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File '/home/odoo/odoo18/community/odoo/orm/models.py', line 5744, in mapped
if len(records) > PREFETCH_MAX:
^^^^^^^^^^^^
TypeError: object of type 'bool' has no len()
```
Cause:
- As the user gave auto fill field as a Property field the [line] called `mapped()` to access its value, this caused the error to occur.
- This occurs because `mapped()` expects a `recordset` (models.Model), but instead it receives a Property object, which does not have `_fields`.
Solution:
- Using `'allow_properties': 'False'`, the property fields wont appear in the list of field selection.
[line]: https://github.com/odoo/enterprise/blob/cdaeb79e1f623831fffa553dbb658698367c7e19/sign/models/sign_item_type.py#L41
sentry-7378769090This update resolves an issue preventing the automatic saving of IRN numbers when sending invoices via e-invoicing with email in the Indian localization. Previously, a technical glitch caused the IRN to be lost, now it's correctly recorded. This ensures accurate e-invoicing compliance.
Original PR description
**Issue**: Sending invoice through e-invoicing with email in Indian localization will not save the IRN number on the invoice because of a cache issue on the attachment id. **Steps to reproduce:** 1. Install l10n_in_edi_gstr module. 2. Create an invoice and send it through e-invoicing with email option. 3. The IRN number will not be saved on the invoice. **Causes:** When sending the invoice through e-invoicing with email option, the attachment id is not saved on the invoice before calling the method _l10n_in_edi_send_invoice(). This causes a cache issue and the IRN number is not saved on the invoice. **Fix:** Save the attachment id on the invoice after the creation of the attachement. **Note:** This pr: https://github.com/odoo/enterprise/pull/114350 fixes the issue in 18.3+ when only selecting e-invoicing while sending the invoice but the issue still happens in 18.2. The issue still happens when email is also selected for versions 18.2+. opw-6243256
This update resolves an issue where customer labels appeared blank and refund flows failed in DIAN POS orders. The fix ensures the 'Final Consumer' partner is always included in the POS order data, preventing data loading problems and improving the customer experience. This aligns with recent improvements.
Original PR description
When DIAN POS is enabled, l10n_co_edi_pos auto-assigns the `Consumidor Final` partner to new POS orders. However, POS only preloads a limited partner set in frontend memory. If `Consumidor Final` is not part of that set, the order gets a partner id whose full partner data is not loaded in the UI. This causes the customer label to appear blank and refund flows to fail with "Can't change customer" mentioning `undefined`. To avoid this, always include the final consumer partner in `get_limited_partners_loading()`. This matches the approach already present in newer branches. opw-6238935 Forward-Port-Of: odoo/enterprise#118408
17 changes
New functionality added to Odoo
This update integrates official worker ONSS statuses into the Odoo Enterprise Belgian localization. This collaboration with Partena ensures accurate payroll processing by aligning with Belgian labor regulations and improving data consistency.
Original PR description
As part of the payroll collaboration with Partena, official worker ONSS statuses needed to be added to the belgian localization. Task: 6174501
Enhancements to existing features
This update introduces a new feature that allows users to easily compare all report lines to a single, chosen line, displaying percentage differences. This enhances reporting accuracy and provides a clearer understanding of variances. The feature is designed to work optimally within a single column view, ensuring a reliable user experience.
Original PR description
This feature allows users to compare all report lines against a specific, user-selected line. An additional column is then displayed with a percentage. Note that this only works when in a single column group. When using more than one, the feature is disabled (and the filter is hidden, so that we don't promise a feature that's not working). task-5144252
This update resolves an issue preventing Odoo invoices from being accepted by the Colombian Tax Authority (DIAN). Previously, global discounts were handled incorrectly, requiring manual adjustments. Now, discounts are automatically applied to individual lines during XML generation, ensuring compliance and streamlining the invoicing process.
Original PR description
Current Behavior: The Colombian Tax Authority (DIAN) does not accept negative lines in the electronic invoice XML, but promotions, coupons, and global discounts are added as separate negative order lines. As a workaround, users have to manually apply discounts to each line which is inefficient. Change: To allow users to use "Coupons and Loyalty" features to apply global discounts, the negative lines will be redistributed into line-level discounts during the XML generation. Expected Behavior: Users will continue to see negative lines in Odoo, but the negative lines will be redistributed to the invoice lines as discounts, so the DIAN will accept the XML. task-5412446
This update enhances Odoo's performance by ensuring proper indexing on related data fields. Specifically, it optimizes how Odoo recalculates information based on dependencies, leading to faster updates and a smoother user experience. This change addresses a potential performance bottleneck within several key modules.
Original PR description
See https://github.com/odoo/odoo/pull/258675 task-6095328
This update optimizes the generation of payroll reports in the Odoo Enterprise system. The previous process was slow, taking around 7 seconds. This change significantly reduces processing time, improving efficiency and user experience.
Original PR description
Investigation in process. task-6259077
Resolved issues and error corrections
This update fixes an issue where intercompany sales and purchases with multiple identical products resulted in incorrect stock reservation during receipt picking. The fix ensures that all units of a product are properly reserved when processing intercompany transactions, preventing discrepancies in inventory tracking. This improves the accuracy of stock management between companies.
Original PR description
…lit for same-product lines When doing an intercompany Sale->Purchase with multiple lines having the same products, the receipt picking would be incorrectly assigned: - Enable Inter-Company…
…lit for same-product lines
When doing an intercompany Sale->Purchase with multiple lines having the same products, the receipt picking would be incorrectly assigned:
- Enable Inter-Company Transactions on both companies (Create and validate)
- Create SO in company A to company B with 2 lines having the same product P, Confirm. => Delivery in company A, Purchase and Receipts in company will be created => The SO/PO/Delivery/Receipt will all have 2 lines
- Validate delivery => On the receipt, the 2 units of P are reserved on the 1st move, and the 2nd move is not reserved.
https://github.com/user-attachments/assets/b4816051-120e-4226-9228-fd552649d5ef
---
### Test result without fix:
```
2026-04-23 13:16:44,577 48027 INFO oes_test_18.0 odoo.addons.sale_purchase_stock_inter_company_rules.tests.test_inter_company_so_to_po: Starting TestInterCompanySaleToPurchaseWithStock.test_02_inter_company_multiple_lines_with_same_product ...
2026-04-23 13:16:44,949 48027 INFO oes_test_18.0 odoo.addons.sale_purchase_stock_inter_company_rules.tests.test_inter_company_so_to_po: ======================================================================
2026-04-23 13:16:44,949 48027 ERROR oes_test_18.0 odoo.addons.sale_purchase_stock_inter_company_rules.tests.test_inter_company_so_to_po: FAIL: TestInterCompanySaleToPurchaseWithStock.test_02_inter_company_multiple_lines_with_same_product
Traceback (most recent call last):
File "/home/odoo/Odoo/src/18.0/enterprise/sale_purchase_stock_inter_company_rules/tests/test_inter_company_so_to_po.py", line 109, in test_02_inter_company_multiple_lines_with_same_product
self.assertRecordValues(purchase_from_a.picking_ids.move_ids, [
File "/home/odoo/Odoo/src/18.0/odoo/odoo/tests/common.py", line 709, in assertRecordValues
self.assertSequenceEqual(expected_reformatted, record_reformatted, seq_type=list)
AssertionError: Lists differ: [{'pr[18 chars]0, 'quantity': 1.0}, {'product_uom_qty': 1.0, 'quantity': 1.0}] != [{'pr[18 chars]0, 'quantity': 2.0}, {'product_uom_qty': 1.0, 'quantity': 0.0}]
First differing element 0:
{'product_uom_qty': 1.0, 'quantity': 1.0}
{'product_uom_qty': 1.0, 'quantity': 2.0}
- [{'product_uom_qty': 1.0, 'quantity': 1.0},
? ^
+ [{'product_uom_qty': 1.0, 'quantity': 2.0},
? ^
- {'product_uom_qty': 1.0, 'quantity': 1.0}]
? ^
+ {'product_uom_qty': 1.0, 'quantity': 0.0}]
? ^
```
OPW-6145683
Forward-Port-Of: odoo/enterprise#118805
Forward-Port-Of: odoo/enterprise#114873This update fixes a problem where AI responses weren't being correctly delivered to embedded AI Livechat instances. The issue stemmed from how the system handled streaming data, and has been resolved by changing the way the AI response is delivered, ensuring proper functionality for embedded livechat experiences.
Original PR description
AI livechat embedded on another origin could not receive AI responses. The response stream is requested with fetch(), so it bypassed the livechat CORS routing that only wraps RPC calls. The matching CORS controller was also exposed as JSON-RPC, which cannot return the streamed HTTP response correctly. Expose the CORS endpoint as an HTTP stream, route the embedded fetch call to it, and pass the livechat guest token explicitly. task-id-6201054 Forward-Port-Of: odoo/enterprise#118916 Forward-Port-Of: odoo/enterprise#117535
This pull request resolves errors occurring when generating CFDI invoices for payslips including IMSS disability time off. The fix ensures the required 'Incapacidades' node is correctly declared in the XML, addressing a legal requirement for Mexican payroll reporting. It also corrects an incorrect calculation of the total amount due, ensuring accurate invoice generation.
Original PR description
Several error are logged in the chatter when signing a payslip that includes an IMSS disability time off. Steps to reproduce: * Install l10n_mx_hr_payroll_account modules * Switch to "INNOVACION…
Several error are logged in the chatter when signing a payslip that includes an IMSS disability time off.
Steps to reproduce:
* Install l10n_mx_hr_payroll_account modules
* Switch to "INNOVACION VALOR Y DESARROLLO SA SA" company
* Go to Employees and open Cesar Osbaldo Cruz Solorzano
* Click on "Time Off" smart button and create a new time off with "Disability due to illness (IMSS)" type for "02/01/2026"(Any date).
* Go to Payroll > Payslips > Payslips and create a new pay run
* Select Salary Structure 'Mexico: Regular Pay', Pay Schedule 'Monthly' and the Period '01/01/2026 -> 01/31/2026'
* Click on Continue, select Cesar and click on Select
* Open the payslip, click on "Validate" and "Ok"
* Mark as paid, open the "Journal Entry" from the smart button and click on "Post".
* Back to the payslip, and click on "Generate CFDI" button.
* An error is added to the chatter.
### Missing node to declare disabilities
Original message
```py
An error occurred while signing the CFDI document with the government:
Code : NOM111 Message : Error no clasificado. Extra Info : El nodo
"Incapacidades" se debera informar si se incluye en percepciones la
clave 014 "Subsidios por Incapacidad" o bien en deducciones la clave 006
"Descuento por incapacidad".
```
Translated message
```py
An error occurred while signing the CFDI document with the government:
Code: NOM111 Message: Unclassified error. Extra Info: The "Incapacidades"
(Disabilities) node must be reported if the perception key 014
"Subsidios por Incapacidad" (Disability Subsidies) is included, or if
the deduction key 006 "Descuento por incapacidad" (Disability Deduction)
is included.
```
Legal Context:
According to Mexican law, IMSS disabilities must be declared in a specific XML node.
There are two primary scenarios for reporting these amounts:
* Deduction (Type 006): The employer does not pay for these days, as the IMSS is responsible for the payment to the employee.
This is the most common scenario.
* Perception (Type 014): The employer pays for these days as a superior benefit. For example, by law, the IMSS does not pay for the first 3 days of a disability due to illness, and employers are not obligated to cover them either. However, companies offering superior benefits may choose to pay these days as a "Disability Subsidy."
Solution:
The chosen approach is to configure the Deduction node.
For the `l10n_mx_regular_pay_imss_disabilities` rule, the `l10n_mx_concept` has been set to `l10n_mx_concept_d6` (D06 - Disability Deduction). This ensures the required node is added.
### Missing "ImporteMonetario" attribute
Original message
```
An error occurred while signing the CFDI document with the government:
Code : NOM95 Message : El atributo Deduccion:Importe no es igual a la
suma de los nodos Incapacidad:ImporteMonetario, ya que la clave
expresada en Nomina.Deducciones.Deduccion.TipoDeduccion es "006".
```
Translated message
```
An error occurred while signing the CFDI document with the government:
Code: NOM95 Message: The attribute "Deduccion:Importe" does not match
the sum of the "Incapacidad:ImporteMonetario" nodes, as the key
expressed in "Nomina.Deducciones.Deduccion.TipoDeduccion" is "006".
```
Problem:
The "Incapacidades" node requires the "ImporteMonetario" attribute, which should represent the sum of the monetary value associated with the disabilities.
Solution:
Add the "ImporteMonetario" attribute and calculate its value using `l10n_mx_daily_salary`.
### Invalid "DiasIncapacidad" format
```py
An error occurred while signing the CFDI document with the government:
Code : 301 Message : XML mal formado Extra Info : Element
'{[http://www.sat.gob.mx/nomina12}Incapacidad](http://www.sat.gob.mx/nomina12%7DIncapacidad)', attribute
'DiasIncapacidad': '4.0' is not a valid value of the local atomic type.
```
Problem:
Altough the defaultdict where the values are sum up, `number_of_days` is
a float field, and when we get back the value, it is a float, adding for
example 4.0 instead of 4, which is not a valid value.
Solution:
Cast the value to int.
### Duplicate deduction on disabilities
```py
Wrong python code defined for:
- Employee: Cesar Osbaldo Cruz Solorzano
- Version: False
- Payslip: Salary Slip - Cesar Osbaldo Cruz Solorzano - 05/01/2026 - 05/15/2026
- Salary rule: ISR (Income Tax) (ISR)
- Error: TypeError('cannot unpack non-iterable NoneType object') while
evaluating
"
def find_rates(x, rates):
for low, high, fix, rate in rates:
if low <= x <= high:
return low, high, fix, rate
gross = categories['GROSS']
result = 0
if gross:
isr_table = payslip._rule_parameter('l10n_mx_isr_tables')[version.schedule_pay]
low, high, fix, rate = find_rates(gross, isr_table)
result = -((gross - low) * rate + fix)
period_factor = payslip._rule_parameter('l10n_mx_schedule_table')[version.schedule_pay]
if period_factor >= 15:
period_factor = (period_factor / 30) * (365 / 12)
min_wage = payslip._rule_parameter('l10n_mx_daily_min_wage') * period_factor
if gross <= min_wage:
result_qty = 0.0
"
```
Problem:
The IMSS disability amount is being deducted twice:
1. During "Worked Days" calculation, the IMSS disability is already not considered because the work entries belong to the "Unpaid Work Entry Types" of "Mexico: Regular Pay" structure.
2. During "Salary Computation", the `IMSS_DISABLE` salary rule deducts another time because it is in the `TAXABLE_ALW` category, and this one is deducted in the `NET` rule.
When the disability covers more than half of the period (e.g., 20 days in a monthly schedule), the double deduction causes the NET to become negative. This prevents the ISR rule from finding a correct stage in the tax tables, leading to a traceback.
Example: For a monthly wage of 30,000.0 and 5 disability days:
- The total amount in "Worked Days" is 25,000.0 (disabilities already deducted).
- The IMSS_DISABLE rule calculates -5,000.0, and when the NET rule is calculated, the disabilities are deducted again. Total NET becomes 16,843.84 instead of the expected 20,834.85.
Solution:
Change the rule category to `INTERMEDIARY_COMPUTATION` and avoid the double deduction when the `NET` is calculated, as it is already considered in the "Worked Days".
### Incorrect values in the XML
The signing process completes without errors, but some amounts in the generated XML are incorrect.
Problem:
The introduction of the Deduction 006 (Disability) directly impacts the calculation of the SubTotal and Total attributes in the Comprobante node.
For a monthly payslip with a wage of 30,000.00 (daily salary of 1,000.00) and 5 disability days (work risk), the values are calculated incorrectly as follows:
Attribute | Calculation | Actual Value | Correct Value
---------------------|----------------------------------|--------------|--------------
Comprobante:SubTotal | Sum of Perceptions (P01) | 25000.00 | 30000.00 (1)
Comprobante:Total | SubTotal - Total Deductions (2) | 15803.74 | 20803.74
(1) Must include the 5,000.00 from disabilities to balance the deduction.
(2) Total Deductions = D06 (5,000.00) + ISR (3,451.65) + IMSS (744.61) = 9,196.26.
The Total is currently undercalculated because the 5,000.00 is being
deducted from the SubTotal that already had those 5,000.00 excluded.
Solution:
Since the `SubTotal` is derived from Perceptions, and the "(P01)
Salaries, Wages, Stripes, and Day Labor" amount is driven by the
`GROSS_WITHOUT_HOLIDAY` rule, the disability amount must be added. This
balances the Deduction 006, ensuring `SubTotal` is correct.
### Absenteeism and Disabilities
By law, the calculation of IMSS contributions depends on these two types of unpaid days:
* Disabilities: Refers to medical leave issued by the Institute (IMSS).
* Absenteeism: Refers to unjustified leave; apply for periods of fewer than 8 days.
Source: [Artículo 31](https://www.imss.gob.mx/sites/all/statics/pdf/leyes/LSS.pdf)
Translated text:
Article 31. When wages are not paid due to the employee's absence from work, but the employment relationship persists, the monthly contribution shall be adjusted according to the following rules:
I. If the employee's absences are for periods of fewer than eight consecutive or non-consecutive days, contributions shall be calculated and paid for such periods only for the sickness and maternity insurance...
If the employee's absences are for periods of eight consecutive days or more, the employer shall be released from the payment of employer-employee contributions...
IV. In the case of absences covered by medical disabilities issued by the Institute, it shall not be mandatory to cover the employer-employee contributions, except regarding the retirement branch.
The following table summarizes the contribution requirements based on the type of absence:
Insurance Branch (RAMA) | Section I (Absenteeism) | Section IV (Disability)
--------------------------------|-------------------------|------------------------
Sickness and Maternity | Paid | Not Paid
Disability and Life | Not Paid | Not Paid
Severance and Old Age | Not Paid | Not Paid
Work Risk | Not Paid | Not Paid
Daycare and Social Benefits | Not Paid | Not Paid
INFONAVIT | Not Paid | Paid
Retirement | Not Paid | Paid
The type of unpaid day to be considered depends on the specific insurance branch being calculated within the employer-employee contributions.
### Add test for cfdi with disabilities.
target: 19.0
task-6066160
Forward-Port-Of: odoo/enterprise#116819This update resolves an error that occurred when opening payslips with multiple attachments. The fix prevents a data conflict that arose when deleting related documents, ensuring payslips can be opened and viewed correctly. It improves the stability of the payroll process.
Original PR description
Currently, an error occurs when a user opens a payslip. **Steps to Reproduce:** - Install the `documents_hr_payroll` module. - Go to `Payroll` > `Payslips` > `Payslips` and open an `existing payslip`…
Currently, an error occurs when a user opens a payslip. **Steps to Reproduce:** - Install the `documents_hr_payroll` module. - Go to `Payroll` > `Payslips` > `Payslips` and open an `existing payslip` or `create a new one`. - Add `two or more attachments` to the payslip. - Go to `Documents` and, in the left panel, navigate to `Company` > `Employees - YourCompany` > `Payroll YourCompany`, then `Move to Trash` all documents related to those `payslip attachments`. - Go back to `Payslips` and open the `same payslip` again. `ValueError: Expected singleton: hr.payslip(4, 4)` With [this commit], the attachment's "Add to Document" action allows creating a Document from a mail.thread record attachment. When the user deletes the documents related to the attachments and then opens the payslip again, the compute method runs to calculate the linked document ID for the payslip attachments and tries to retrieve attachments without documents [1]. The issue occurs when two or more attachments share the same payslip ID. While mapping the res_id of the attachments and grouping them by ID, the same payslip record is included multiple times for a single key [2] [3], which raises error here [4]. This commit ensures that the mapped res_id values are wrapped in a set, so duplicate IDs are removed and each payslip ID appears only once. [this commit]: https://github.com/odoo/enterprise/commit/5fa4b74a2345ddd4858585c5e9a780d1ca5add57 [1]- https://github.com/odoo/enterprise/blob/21477b333f7a33cb582cd806236e4f9f8346d022/documents/models/ir_attachment.py#L26 [2]- https://github.com/odoo/enterprise/blob/21477b333f7a33cb582cd806236e4f9f8346d022/documents/models/ir_attachment.py#L45 [3]- https://github.com/odoo/enterprise/blob/21477b333f7a33cb582cd806236e4f9f8346d022/documents/models/ir_attachment.py#L48 [4]- https://github.com/odoo/enterprise/blob/21477b333f7a33cb582cd806236e4f9f8346d022/documents_hr_payroll/models/hr_payslip.py#L74-L76 sentry-7494229711 Forward-Port-Of: odoo/enterprise#118033
This update resolves an error that prevented users from canceling draft POS orders. The issue stemmed from a recent code change that incorrectly returned order data. The fix removes this problematic code, restoring the ability to cancel draft orders as intended.
Original PR description
Currently an error is generated when the user tries to cancel a draft POS order as follows: - Install the `pos_enterprise` module with demo data - Open the register of `Furniture store` and select…
Currently an error is generated when the user tries to cancel a draft POS order as follows: - Install the `pos_enterprise` module with demo data - Open the register of `Furniture store` and select any product - Click on the `Upload` icon to save the draft order and go to the backend. - Navigate Orders > Orders > open Draft order - Click the `cog` icon and click `Cancel Order` >>> Error occurs This issue is caused by the recent refactor introduced in [1]. The `action_pos_order_cancel` action now returns the `order` (`pos.order` recordset) instead of default returning `None`. As a result, the `action` variable contains a `pos.order` recordset, and an error is raised at line [2] when `setdefault` is called on it, since `setdefault` expects a dictionary-like object. This commit fixes the above issue by removing the code that returns the `pos.order` object from the action. As a result, the action now behaves as expected and returns the default value (`None`). [1]: https://github.com/odoo/enterprise/commit/27f57036a1d0468efe6e68d7aceafe0f01b21f93 [2]: https://github.com/odoo/odoo/blob/48f93ca056633bd5cba36b66ee1008fb57ca666c/addons/web/controllers/utils.py#L24 Sentry-7354160052 Forward-Port-Of: odoo/enterprise#118035
This update addresses a security vulnerability where test databases could incorrectly pass subscription checks on Odoo.com. The change adds a new verification step specifically for duplicated SAAS databases with a neutralized status, ensuring accurate subscription validation and preventing unauthorized access. This enhances the security and reliability of the Odoo Enterprise platform.
Original PR description
Odoo.com does not create a distinction between a production and duplicated SAAS database. This allows test databases to pass the check for subscription. This commit adds an additional check for duplicated SAAS databases with a neutralised status. task-6249752 Forward-Port-Of: odoo/enterprise#118281
This update resolves an issue that was slowing down map loading times by fixing a problem with how map pin data was being updated. The change ensures that map pins load more efficiently, especially in larger maps, by creating fresh copies of the data as needed. This results in a smoother and faster map experience for users.
Original PR description
Fixes a core model issue where `_filterUnlocatedRecords` destructively mutated `data.recordGroups` in place, making it impossible to evaluate subsequent progressive OSM coordinate arrivals. The baseline state is now preserved in `data.allRecordGroups` at load time, and a fresh copy is derived on each call. To support this progressive rendering, `MapPinListPopover` is equipped with a `useBus` subscription. This ensures that while the core controller subtree updates automatically, this isolated popover also stays in sync with the model. task-6255163 Forward-Port-Of: odoo/enterprise#118694
This update fixes an issue where flexible employee time off wasn't accurately displayed in the attendance calendar. Now, time off durations are correctly grayed out from midnight to 11 PM, aligning with expected behavior across day and week/month views. This ensures accurate tracking of flexible work schedules.
Original PR description
__ ## Short functional explanation of the error When setting a time off for an employee who has a flexible schedule, in the attendance app, on the calendar with the 'days' view. We can see that the…
__ ## Short functional explanation of the error When setting a time off for an employee who has a flexible schedule, in the attendance app, on the calendar with the 'days' view. We can see that the hours are grayed out from 8 hours to 16 hours. However, according to this message: https://www.odoo.com/mail/message/1027495005 "[...] the entire day of absence might not be represented as such, which is an issue (for example if a flexible employee with 8h/day takes a day off, the duration of the leave should be 1 day/8 hours but on the gantt view everything should be gray from midnight to midnight)". Moreover, when we select the Week or Month view on the calendar, the day off isn't grayed out. This comes from the fact that, for a flexible schedule, we consider that any time of the day can be a working hour; and we only grey out days in the calendar where no hour has been worked at all. Hence, the hours considered during a flexible day off should be from midnight to 23:59:59. ## Reproduction Steps 1. Go to an employee's profile and set their schedule to flexible. 2. Create a time off of a one-day duration for this employee. 3. Go to the attendance app and see the calendar. ### Expected behavior When clicking on the Day view, all hours from midnight to 11pm should be grayed out. When clicking on the Week/month view, the day of the time off should be grayed out. ### Unexpected behavior When clicking on the Day view, hours from 8am to 4pm are grayed out. When clicking on the Week/month view, the day of the time off isn't grayed out. ## Origin of the issue First, we only consider the leave if the resource is fully flexible, i.e if the employee has no working calendar set: https://github.com/odoo/odoo/blob/394a30f8a2814d460cfe220b5017e7ac95d8cddc/addons/resource/models/resource_calendar.py#L546 However, if the schedule of the employee is flexible, the leave resource isn't considered as fully flexible, thus leading us to a leave from 8 am to 4 pm. Moreover, when processing flexible leaves, we return the unavailable intervals with the timezone of the employee: https://github.com/odoo/odoo/blob/394a30f8a2814d460cfe220b5017e7ac95d8cddc/addons/resource/models/resource_calendar.py#L589-L592 Whereas when we process fixed leaves, we return the unavailable intervals under utc: https://github.com/odoo/odoo/blob/394a30f8a2814d460cfe220b5017e7ac95d8cddc/addons/resource/models/resource_calendar.py#L597-L601 This leads us to display problems: when the user is under European/ Brussels time in summer, the leave starts at 2 am and ends at 11pm, instead of starting at midnight. Note: after discussion with AJU, it has been agreed that the behavior should be the same on the Planning app. __ opw-6030212 Forward-Port-Of: odoo/enterprise#118832 Forward-Port-Of: odoo/enterprise#112482
This update significantly improves the performance of the VAT Books ES report by processing invoices in batches instead of loading everything into memory at once. This prevents crashes and slowdowns caused by excessive memory usage, especially when dealing with large invoice volumes. The change ensures the report generates reliably and efficiently.
Original PR description
### Description of the issue/feature this PR addresses: This PR introduces batch processing to the VAT Books ES (Libros de IVA) report generation. When attempting to export the report for periods…
### Description of the issue/feature this PR addresses: This PR introduces batch processing to the VAT Books ES (Libros de IVA) report generation. When attempting to export the report for periods containing a massive volume of invoices, the ORM cache continuously accumulates records, leading to severe memory consumption. By implementing batching and explicitly clearing the environment cache, use memory use will remain stable and efficient. ### Current behavior before PR: Generating the VAT Books report loads all account move lines into memory at once. Because the ORM cache is never cleared during the iteration, RAM usage spikes continuously. On databases with tens or hundreds of thousands of invoices in a single period, this leads to significant performance degradation, worker timeouts, or complete Out-Of-Memory (OOM) crashes. ### Desired behavior after PR is merged: The report engine now splits the recordset into manageable batches (e.g., 50,000 accounts per batch). After processing each chunk to extract the income and expense line values, invalidate_model() is called to flush the ORM cache related to the searched records. This frees up memory continuously, keeping the server's RAM usage flat and allowing the successful export of massive datasets without crashing. ### Benchmark: The model is iterating through ~1.1M account move lines when generating the full report. For Memory: | # Input Data | Before PR | After PR| | -------- | -------- | -------- | | ~77,000 account move lines | 385 MB | 666 MB | | ~340,000 account move lines |1.2 GB | 1.5 GB | | ~1.2M account move lines | MemoryError | 1.5 GB | For Speed: | # Input Data | Before PR | After PR| | -------- | -------- | -------- | | ~77,000 account move lines | 32s | 12s | | ~340,000 account move lines | 2:29min | 1:11min | | ~1.2M account move lines | MemoryError | 4:11min | ### Reference opw-6037414 ----------------------------------------------------------------- I confirm I have signed the CLA and read the PR guidelines at [www.odoo.com/submit-pr](http://www.odoo.com/submit-pr) Forward-Port-Of: odoo/enterprise#118903 Forward-Port-Of: odoo/enterprise#116139
This update fixes a bug preventing the use of the 'NABN' document type for vendor credit notes in the GT accounting module. Previously, this option was unavailable, which caused issues with processing electronic payments. Now, users can correctly select 'NABN' when reversing vendor credit notes, ensuring accurate GT accounting.
Original PR description
**Steps to reproduce:** - Install the `l10n_gt_edi` module and switch to a `GT Company`. - Navigate to Invoicing > Vendors > Bills. - Create a new vendor bill. - Observe that `GT Document Type`…
**Steps to reproduce:** - Install the `l10n_gt_edi` module and switch to a `GT Company`. - Navigate to Invoicing > Vendors > Bills. - Create a new vendor bill. - Observe that `GT Document Type` includes `NABN - Nota de Pago Electrónica` option. - `Confirm` the bill. - Click `Credit Note`, add a reason, and click `Reverse`. - Observe the available options in the `GT Document Type` field. **Observation:** The `NABN - Nota de Pago Electrónica` option is not available for vendor credit notes (`in_refund`), even though `NABN` is a GT-specific credit note document type. **Root Cause:** At [1], `NABN` is added for vendor bills (`in_invoice`, `in_receipt`) instead of vendor credit notes (`in_refund`). **Fix:** This commit ensures users can correctly select `NABN - Nota de Pago Electrónica` on GT vendor credit notes. [1]: https://github.com/odoo/enterprise/blob/c7fa8c9c6f6830f5702fab4f6efaf3ac33f7fe72/l10n_gt_edi/models/account_move.py#L159-L160 opw-6252256 Forward-Port-Of: odoo/enterprise#119259 Forward-Port-Of: odoo/enterprise#118711
This update resolves an issue where Luxembourg tax reports were incorrectly generating company registry numbers instead of the agent's RCS number when a natural person accountant was not linked. The fix ensures accurate XML declaration for Luxembourg tax authorities, preventing report rejection. This improves compliance and avoids potential delays in tax processing.
Original PR description
**Steps to reproduce:** * install `l10n_lu_reports`. * Create a company in Luxembourg with a `company_registry` number set. * Link this company to an accounting firm that is a natural person…
**Steps to reproduce:** * install `l10n_lu_reports`. * Create a company in Luxembourg with a `company_registry` number set. * Link this company to an accounting firm that is a natural person (independent accountant) with no business registration number — i.e. `l10n_lu_agent_rcs_number` is left empty on the agent partner. * Go to the tax report and generate the XML declaration. **Observed behavior:** * The `<Agent><RCSNbr>` field in the generated XML contains the company's own `company_registry` value instead of `NE`. * The file is rejected by the Luxembourg tax administration. **Cause:** * In `l10n_lu_generate_xml.py`, the `agent_rcs_number` template value was built with a plain `or` chain: `agent.l10n_lu_agent_rcs_number or company.company_registry or "NE"` * When an agent is set but has no RCS number (natural person), the fallback incorrectly continued to `company.company_registry` instead of stopping at `"NE"`. **Fix:** * Use a conditional expression so that `company.company_registry` is only used as a fallback when **no agent is linked** to the company: `(agent.l10n_lu_agent_rcs_number if agent else company.company_registry) or "NE"` opw-6044689 Forward-Port-Of: odoo/enterprise#112968
Code cleanup and technical improvements
This update refactors several Odoo addons (including marketing automation, MRP, POS, and planning) to use a new proxy-based approach instead of `useState`. This change improves the underlying architecture and prepares the system for future development. It impacts multiple modules within the enterprise suite.
Original PR description
In Owl3, uses of `useState` or replace with `proxy`. This commit changes all those uses for addons in the range [m..!w]. *: marketing_automation,mrp_workorder,planning,pos_appointment,pos_blackbox_be,pos_enterprise,pos_iot_six,pos_platform_order,pos_restaurant_appointment,pos_sale_planning,pos_tyro,pos_urban_piper,quality_mrp_workorder,room,sale_planning,sale_renting,sale_timesheet_enterprise,sign,sign_emsigner,social,social_linkedin,social_push_notifications,social_twitter,social_youtube,spreadsheet_dashboard_edition,spreadsheet_edition,spreadsheet_sale_management,stock_barcode,stock_barcode_mrp,timer,timesheet_grid,timesheet_grid_hr_attendance,voip
8 changes
Resolved issues and error corrections
This update resolves a bug where the AI's search suggestions were incorrectly applied to multiple Odoo tabs. The fix ensures that AI-driven actions only affect the tab where they originated, preventing unexpected behavior across different views. This improves the stability and reliability of the AI feature.
Original PR description
[FIX] ai: scope AI_ADJUST_SEARCH bus event to originating session The AI_ADJUST_SEARCH handler did not check aiSessionIdentifier, so any browser tab subscribed to the bus would apply the AI's…
[FIX] ai: scope AI_ADJUST_SEARCH bus event to originating session
The AI_ADJUST_SEARCH handler did not check aiSessionIdentifier, so any
browser tab subscribed to the bus would apply the AI's resulting search
to its current view. When the view's model lacked a field referenced in
the response (e.g. an "Active or Queue" filter on stage_id leaking from
a project.task chat into a timesheet view), the view raised a KeyError.
Align it with the four AI_OPEN_MENU_* handlers, which already drop events
from other sessions since https://github.com/odoo/enterprise/commit/d85e17d9ccf70f9cfd51c7d6b2a5b52510807484.
Steps to reproduce:
- Run Odoo with the crm and contacts modules installed
- Open two tabs:
- Tab 1: navigate to CRM and ensure you are in List view
- Tab 2: navigate to Contacts and ensure you are also in List view
- In Tab 1 (CRM), open the Ask AI chat and type "Switch to Kanban view"
- CRM switches to Kanban view as expected
- Bug: Tab 2 (Contacts) also switches to Kanban view along with Tab 1,
even though you did not interact with itThis update resolves an issue where attached documents generated for Colombia were incorrectly using a generic line number instead of the required official document ID. This caused rejection by DIAN validation tools. The fix ensures the correct document ID is used, allowing the documents to pass validation and integrate correctly with external systems.
Original PR description
### Issue When generating the attached document (AttachedDocument) for Colombia, the parent document reference tag <cbc:ID> incorrectly exported a generic line counter instead of the actual document…
### Issue
When generating the attached document (AttachedDocument) for Colombia, the parent document reference tag <cbc:ID> incorrectly exported a generic line counter instead of the actual document identification number
While the DIAN platform itself accepted the file, this caused rejections in external validation tools and third-party software because they could not resolve the link back to the original invoice
DIAN Documentation: https://www.dian.gov.co/impuestos/factura-electronica/Documents/Anexo_tecnico_factura_electronica_vr_1_7_2020.pdf
On page 213 there is an example for ParentDocumentLineReference
On page 216 there is the specification that does not show any check
Example of the incorrect XML structure:
```xml
<cac:ParentDocumentLineReference>
<cbc:LineID>1</cbc:LineID>
<cac:DocumentReference>
<cbc:ID>1</cbc:ID>
</cac:DocumentReference>
</cac:ParentDocumentLineReference>
```
Expected XML structure:
```xml
<cac:ParentDocumentLineReference>
<cbc:LineID>1</cbc:LineID>
<cac:DocumentReference>
<cbc:ID>SETP990001021</cbc:ID>
</cac:DocumentReference>
</cac:ParentDocumentLineReference>
```
### Cause
In the template, the value for <cbc:ID> was retrieved using `parent_document.get('id')` which fetched the sequential loop index https://github.com/odoo/enterprise/blob/cd25713fd2c35737d98db29df72b2d07ae9146e8/l10n_co_dian/views/templates.xml#L272-L275
The dictionary parsing logic did not extract the true document identifier from the XML tree response or the original XML data https://github.com/odoo/enterprise/blob/13dc30679e382df5845993c880a97df600c39ed4/l10n_co_dian/models/l10n_co_dian_document.py#L429-L432
### Steps to reproduce
- Install `l10n_co_dian`
- Setup DIAN configuration
- Generate an attached document for a commercial event or invoice
- Open the generated XML file
Before the fix, the `<cac:ParentDocumentLineReference>/<cac:DocumentReference>/<cbc:ID>` tag contains a technical integer like "1" instead of the official document sequence number
opw-6164321This update resolves a problem where users couldn't correctly insert dynamic fields into SMS templates within Marketing Automation. The fix adds a necessary setting to ensure the system uses the correct data source (mailing_model_real) instead of defaulting to a different field, allowing users to build SMS campaigns with dynamic content. This ensures proper functionality for SMS marketing.
Original PR description
The SMS template form view in Marketing Automation was missing the `dynamic_placeholder_model_reference_field` option on the `body_plaintext` field. Without this option, the dynamic placeholder hook falls back to looking for a `model` field in the record data, but `mailing.mailing` uses `mailing_model_real` instead. Steps To Reproduce: - Install marketing_automation_sms and CRM modules (also activate Leads). - Start a new Campaign in Marketing Automation. - Set Target to Lead/Opportunity. - Add New Activity > Activity Type = SMS > SMS Template = create one. - In the SMS template dialog, click the "Insert Field" button. - Error appears: "You need to select a model before opening the dynamic placeholder selector." Ticket [link](https://www.odoo.com/odoo/project.task/5488849) opw-5488849 Forward-Port-Of: odoo/enterprise#104423
This update ensures that work orders can only be assigned to employees specifically authorized for the relevant work center. Previously, all employees could be assigned, but now the system restricts assignments based on pre-defined work center permissions, improving accuracy and control. This change addresses a previous issue (opw-6208602) and enhances work order management.
Original PR description
Add domain on `employee_assigned_ids` to restrict selectable employees based on the workcenter configuration. If `all_employees_allowed` is True, no filter is applied. Otherwise, only employees listed in `allowed_employees` are selectable. opw-6208602
This update resolves an issue where new appointments created through the Gantt view were defaulting to midnight instead of the intended booking time. The team corrected a misconfiguration that prevented the custom logic from being used, ensuring accurate start times for bookings.
Original PR description
The [commit] replaced the `onAddClicked` method with `_onNewClicked`, and updated all related calls and overrides accordingly. However, the appointment Gantt view override was mistakenly changed to override a non-existent `_onAddClicked` method, leaving the custom logic unused. As a result, bookings created through the `New` button in the Gantt view used midnight (12:00 AM) instead of the time derived from the custom logic as the default start datetime. This commit fixes the issue by correctly overriding `_onNewClicked`. [commit]: https://github.com/odoo/enterprise/commit/bc779c9ec5295f8d1fe06e8432c518c78c606ea2
This update corrects a technical issue preventing signature requirement features from working correctly for US to US deliveries when using UPS. The fix adjusts the API request to accurately reflect whether a delivery is package-level or shipment-level, aligning with UPS API specifications. This ensures signature requirements function as expected for US shipments.
Original PR description
Issue ----- Enabling signature requirement blocks US -> US deliveries. Steps to reproduce ----- - Setup UPS - enable signature requirement - Set current company to US - Create a US Customer - Create…
Issue ----- Enabling signature requirement blocks US -> US deliveries. Steps to reproduce ----- - Setup UPS - enable signature requirement - Set current company to US - Create a US Customer - Create a product with some weight - Create a SO for the product - Add UPS delivery and try to get a rate > Error: "The requested accessory option is unavailable between the selected locations." Cause ----- Depending on the type of transfer, signature is requested at shipment or package level (see the "Delivery Confirmation Origin-Destination Pairs" category of the following link) https://developer.ups.com/api/reference/shipping/appendix1?loc=en_US US50 -> US50 & Canada -> Canada is package level Everything else is shipment level By default we use 'ShipmentServiceOptions_DeliveryConfirmation' for which 'DCISType' = 1 is the correct value. https://github.com/UPS-API/api-documentation/blob/b4064887ebcd9cd98085bc4cce088677c664473f/Shipping.yaml#L8902-L8911 For package level, we should use 'PackageServiceOptions_DeliveryConfirmation' for which 'DCISType' = 2 would be the expected value https://github.com/UPS-API/api-documentation/blob/b4064887ebcd9cd98085bc4cce088677c664473f/Shipping.yaml#L10410-L10421 ----- Ticket: opw-6173624
This update fixes an issue where currency differences were incorrectly aggregated in hierarchical financial reports. Previously, the system treated all currencies as equivalent, leading to inaccurate totals. This change ensures that report totals accurately reflect the amounts in each currency, improving reporting reliability.
Original PR description
opw-6015098 Forward-Port-Of: odoo/enterprise#119073 Forward-Port-Of: odoo/enterprise#114827
This update resolves an issue where refunded orders were still visible in the 'Orders to Settle' list when the customer account was balanced. The fix ensures that orders and their associated refunds are removed from this list when the customer account reaches zero, streamlining the settlement process for users. This improves clarity and reduces manual intervention.
Original PR description
Currently, if you refund an order made on the customer account with the customer account as well, you can still see the order in the list of orders to settle. Steps to reproduce: -------------------…
Currently, if you refund an order made on the customer account with the customer account as well, you can still see the order in the list of orders to settle. Steps to reproduce: ------------------- * Open shop * Make an order using the customer account for a customer, don't invoice it * Refund one of the order using the customer account, don't invoice it * Make a new order using the customer account * In the customer list, find the customer used and select "Settle Orders" > The 2 orders are present in the list Why the fix: ------------ Originally the list would only show the orders for chich the customers have due (>0). https://github.com/odoo/enterprise/commit/bf4b6043b999b4a081b1afa73fc4113bf4db28f8 But recently the code we also see the refunds in the list as well. https://github.com/odoo/enterprise/commit/12af23d5382e972facfaa999e4c5ab30c97e8d1f However this new behavior is not visible if, with the refund, the customer account temporarily falls to 0. So currently we have some refunds that impact the amount to settle and some that don't. Originally we were thinking that either we should show all refunds in that list (given they use the customer account) or we shouldn't show any as it was previously. Both solutions are not ideal. * Showing them all would get the list bigger than it is and would require the customer to select the order and its refund(s) and settle them together. Since refunds are not usually done right after the order they would not be close it that list. However this solution would enable the option to remove the orders from the list requiring a few step from the customer. * Showing none isn't idea either with this use case as it means that we still see orders that were cancelled out by their refunds. To remove to order the customer has two options. Either going backend and searching the order and its refund(s) and invoice them, either settling the order but that means that now there's money deposited on the customer account. Any of the two option isn't perfect a it still requires manual intervention from the customer and wouldn't work on previous data. Creating a server action to correct those data wouldn't have been feasible either. Instead, the approach we're taking is the following: When loading the list of order to settle we want to remove the orders and the potential refunds were the customer account is evened out. We only need to look at the orders of the partners that contains refunds for which the customer account was used. If the sum of the transactions made on the customer account is 0 we can say that the order and its refunds have cancelled out each other (in terms of customer account) and we don't show them if the list of orders remaining to settle. opw-6170830
15 changes
Enhancements to existing features
This update enhances how Odoo finds partners during UBL (UBL) imports, primarily for Peppol transactions. It now uses exact name matches and incorporates bank account details for more accurate identification, reducing errors. A key fix ensures correct partner creation when VAT information is present in the UBL file.
Original PR description
Before this commit: Partner was searched using contains on the name, which could match unrelated partners with similar names (e.g. `Global Tech` matching `Global Technologies Ltd`). With this update: - Partner retrieval now uses an exact name match to avoid incorrect matches caused by partial name search. - For UBL imports for Peppol, bank details are also used to help identify the partner by matching the bank account number. The retrieval logic has also been improved: 1. If VAT exists in the XML: - If a partner found with no VAT then enrich that partner by filing VAT from xml - If a partner found with a different VAT than the one in the XML, then a new partner will be created Also fix the test case where it finds `partner_1` through the `bank account number` and creates a new partner instead of returning the correct `partner_2`. task-5485563 Forward-Port-Of: odoo/odoo#250309
Resolved issues and error corrections
This update ensures that refund flows work seamlessly when DIAN POS is enabled. Previously, a technical issue caused the customer label to appear blank and refund attempts to fail. This fix guarantees the correct customer data is loaded for all POS transactions using DIAN POS.
Original PR description
When DIAN POS is enabled, l10n_co_edi_pos auto-assigns the `Consumidor Final` partner to new POS orders. However, POS only preloads a limited partner set in frontend memory. If `Consumidor Final` is not part of that set, the order gets a partner id whose full partner data is not loaded in the UI. This causes the customer label to appear blank and refund flows to fail with "Can't change customer" mentioning `undefined`. To avoid this, always include the final consumer partner in `get_limited_partners_loading()`. This matches the approach already present in newer branches. opw-6238935
This update reverts a recent change that was disrupting the process of reconciling bank statements with previous transactions. It ensures users can continue to accurately match current transactions with historical data. This change is a fix to improve usability and prevent workflow disruptions.
Original PR description
This reverts commit e2a9f3bfbb8a89533146f76509bf2785c085ebea as it disrupt workflow where users needs to reconcile with a previous bank transaction Enterprise PR: https://github.com/odoo/enterprise/pull/118169 opw-6230807 Forward-Port-Of: odoo/odoo#266057
This update addresses a problem where manual reconciliation operations were incorrectly being matched. It reverses a previous change that caused this issue, ensuring that reconciliation processes work as intended. This prevents potential data discrepancies and ensures accurate financial reporting.
Original PR description
This reverts commit 038f527793757c3148b775af1657c5a70a5abc66. opw-6230807 Forward-Port-Of: odoo/enterprise#118169
This update addresses a potential issue where lengthy address fields during credit card payments via Authorize.net could cause errors. The system now automatically limits the length of these fields to comply with the Authorize.net API requirements, ensuring smooth payment processing. This improves payment reliability and prevents disruptions for our customers.
Original PR description
Steps to reproduce: - install payment_authorize module; - complete a credit card payment using Authorize.net with more than 60 characters on any other field than first name, last name or company; - confirm the payment. Issue: An error message appears. Cause: The Authorize.net API define the max length of information. It is possible that some information exceeds the maximum length. (https://apitest.authorize.net/xml/v1/schema/AnetApiSchema.xsd) Solution: Truncate information if the number of character is too large. opw-6141441 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262154
This update resolves a validation error that occurred when renting kits within delivery orders. The fix prevents a traceback by ensuring that record iteration doesn't attempt to access deleted records during the validation process. This ensures the kit explosion and subsequent component validation can complete successfully.
Original PR description
**Problem:** If the Rental Transfers setting is enabled, a traceback occurs when validating a delivery order containing a kit that will be exploded during the validation. **Cause:** When validating a…
**Problem:** If the Rental Transfers setting is enabled, a traceback occurs when validating a delivery order containing a kit that will be exploded during the validation. **Cause:** When validating a delivery (`button_validate`), `_action_done` is run https://github.com/odoo/odoo/blob/af6e45146e3ac3d43f8cfb312e3392ed0c747855/addons/stock/models/stock_picking.py#L1441 The `sale_stock_renting` and `sale_mrp_renting` overrides of this method both execute after other overrides https://github.com/odoo/enterprise/blob/37ccd8bffea96fcd5a0f2f7fae658951824f7f9a/sale_stock_renting/models/stock_move.py#L63 https://github.com/odoo/enterprise/blob/37ccd8bffea96fcd5a0f2f7fae658951824f7f9a/sale_mrp_renting/models/stock_move.py#L11 The `mrp` override of `_action_done` calls `action_explode`, which can unlink records contained in `self` in the calls of `_action_done` https://github.com/odoo/odoo/blob/af6e45146e3ac3d43f8cfb312e3392ed0c747855/addons/mrp/models/stock_move.py#L543-L544 https://github.com/odoo/odoo/blob/af6e45146e3ac3d43f8cfb312e3392ed0c747855/addons/mrp/models/stock_move.py#L582 The `sale_stock_renting` and `sale_mrp_renting` overrides of `_action_done` then resolve after this, and attempt to iterate on `self` or values within `self`, causing a Missing Record Error to occur when attempting to read properties of a deleted record within `self` https://github.com/odoo/enterprise/blob/37ccd8bffea96fcd5a0f2f7fae658951824f7f9a/sale_stock_renting/models/stock_move.py#L65 https://github.com/odoo/enterprise/blob/37ccd8bffea96fcd5a0f2f7fae658951824f7f9a/sale_mrp_renting/models/stock_move.py#L13 **Purpose:** Modify the _action_done method's overrides to ensure that records that no longer exist are not iterated on. This allows the validation to resolve correctly and explode the kit, requiring a second validation for the individual components of the kit. **Steps to Reproduce in Runbot:** 1. Enable the Rental Transfers setting. 2. Create a Product with Tracked Inventory, then add it to a Quotation and confirm it. 3. Add a Kit type Bill of Materials to the Product. 4. Attempt to validate the Delivery made when confirming the Quotation. Similar Fix: https://github.com/odoo/odoo/pull/258403 opw-6144693
This update fixes an issue where flexible employee schedules were incorrectly calculating expected hours due to a timezone calculation error. Specifically, the system was adding an extra day to the calculation when employee and schedule timezones were significantly different. This ensures accurate expected hour reporting in the Attendances app.
Original PR description
**Problem:** When the time zone of an employee's schedule is different from the employee's time zone, and that the employee's time zone has more than 9 hours of difference with UTC. and the schedule…
**Problem:**
When the time zone of an employee's schedule is different from the employee's time zone, and that the employee's time zone has more than 9 hours of difference with UTC. and the schedule is flexible and is set to 40h per week. When we open the Attendances app, the expected hours for this employee show 48h.
**Steps to reproduce:**
- Create an employee with a flexible 40h/week schedule and a contract.
- Set employee timezone to Asia/Pyongyang and the working schedule timezone to Europe/Brussels.
- Open Attendances > Overview > Dashboard in week view.
- denominator shows 48h or any other number than 40h.
**Cause:**
In flexible calendars, weekly expected hours are computed by iterating within `[start_dt, end_dt]`. and That logic truncated bounds to `.date()`, assuming `end_dt - 1 second` would always move to the previous day.
That assumption breaks when employee timezone differs from schedule timezone and the employee timezone is far from UTC (like Asia/Pyongyang). so, `end_datetime` is no longer near midnight in local time, so subtracting one second keeps the same date. The loop then includes one extra day and allocates an extra 8h, showing 48h expected instead of 40h in Attendances.
**Fix:**
This change keeps full datetime bounds (instead of truncating to date), so comparisons preserve timezone offset and time of day precision. This prevents the extra day and restores correct weekly expected hours. The original code before this 332cb43 was like this:
```python
start_date = start_datetime.date()
end_datetime_adjusted = end_datetime - relativedelta(seconds=1)
end_date = end_datetime_adjusted.date()
```
this will not work as `.date()` will do the same problem of the extra day allocation.
Affected from 18.0 -> 18.4
Fixed in 19.0+ by this
Backport of https://github.com/odoo/odoo/pull/252847
opw-6171432
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThis update fixes an issue where vendor bills imported from Poland's KSeF system were not correctly accounting for discounts applied per unit. The change adds support for the 'P_10' XML node, as specified in official KSeF documentation, ensuring accurate bill import and compliance. This improves the reliability of financial data.
Original PR description
When fetching vendor bills from KSeF, the XML node "P_10" is used to indicate a discount per unit on a line. This node is currently being ignored when parsing the file. Official documentation: https://ksef.podatki.gov.pl/media/gn2kt4gl/broszura-informacyjna-struktury-logicznej-e-faktury-fa-1-wersja-anglojezyczna.pdf opw-6235460 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update fixes an issue where the 'Cancel Reason' wasn't being properly transmitted when reversing invoices in Peruvian companies. The change ensures that credit notes generated after a reversal accurately reflect the user-specified cancellation details required by the Peruvian tax authority (SUNAT). This improves data accuracy and compliance for Peruvian businesses using Odoo.
Original PR description
### Issue before this commit: When reversing an invoice in a Peruvian company, the "Cancel Reason" entered in the credit note window is not propagated to the Peruvian EDI tab of the resulting Credit…
### Issue before this commit: When reversing an invoice in a Peruvian company, the "Cancel Reason" entered in the credit note window is not propagated to the Peruvian EDI tab of the resulting Credit Note. Only the Credit Reason is successfully reported. ### Steps to reproduce the issue: 1. Download Accounting and l10n_pe 2. Switch to PE company 3. Create an invoice and confirm it 4. Create a credit note for the invoice with a cancel reason and a credit reason and click the reverse button 5. See that in the Peruvian EDI tab only the Credit Reason is reported but not the Cancel Reason ### Cause of the issue: In the l10n_pe_edi module, the override of the _prepare_default_reversal method maps the l10n_pe_edi_refund_reason to the new move's values, but completely omits the mapping of the wizard's textual reason field to the l10n_pe_edi_cancel_reason field of the resulting credit note. ### Reason to introduce the fix: To ensure the generated credit notes contain all required information for the Peruvian EDI (SUNAT). Mapping the cancel reason guarantees that the electronic document accurately reflects both the refund code and the descriptive cancellation text provided by the user. opw-6238525
This update resolves a checkout bug where applying discounts on products with different taxes caused an infinite reload cycle. The fix ensures discount lines are correctly grouped by reward ID, synchronizing the backend and frontend for accurate checkout processes. This improves the user experience and prevents disruptions during discount application.
Original PR description
**Step to reproduce :** 1. Create a deliverable product with a sales tax. 2. Create another product with a different sales tax. 3. Publish both products on the eCommerce website. 4. Create a discount…
**Step to reproduce :**
1. Create a deliverable product with a sales tax.
2. Create another product with a different sales tax.
3. Publish both products on the eCommerce website.
4. Create a discount program.
5. Add both products to the shopping cart.
6. Apply the discount code.
7. Proceed to checkout.
**Issue :**
Applying a discount on multiple products with different taxes causes an infinite reload cycle during checkout.
**Reason :**
The reload is supposed to sync the discount lines in the back-end with the discount lines displayed during checkout. If the number of lines don't match, a reload is triggered.
https://github.com/odoo/odoo/blob/18.0/addons/website_sale_loyalty/static/src/js/checkout.js#L22-L24
After the fix introduced in:
https://github.com/odoo/odoo/pull/248215
However, when a discount is applied to products with different taxes, the corresponding reward lines are still categorized as `discounted_lines` instead of `groupable_lines`. As a result, they continue to be processed individually rather than being grouped by reward.
This leads to a mismatch between the backend, which generates one discount line per tax combination, and the frontend, which expects a single discount entry per reward. Consequently, the checkout page continuously reloads while attempting to synchronize both states.
**Solution:**
When a discount applies to products with different tax configurations, the corresponding reward lines should be included in `groupable_lines` rather than `discounted_lines`. This ensures that discount lines are grouped by
`reward_id` consistently on both the frontend and backend, preventing the checkout reload loop.
opw-6210411This update corrects a bug in how leads are assigned to sales teams, ensuring a more equitable distribution, especially when team members have similar quotas. Previously, older team members received a disproportionate number of leads due to a bias in the assignment process. This change improves fairness and prevents imbalances in lead distribution.
Original PR description
_assign_and_convert_leads() is biased towards team members created earlier because they're ordered by create_date, id. When members have equal quota, the round-robin order falls back to the order of the team members. If the amount of leads distributed across the team is not a multiple of the team size, then the oldest members will get more leads assigned. This advantage repeats each time the cron runs and can add up to a big difference, the provided test case ends up assigning all 30 leads to the more senior member without the fix. Note that the lead_day_count field used in _get_assignment_quota() doesn't solve the problem. It helps to balance leads assigned in the same 24 hour window, but because the same senior person always goes first inside one of those windows, they will always get more leads assigned to them. To fix it we break ties in the quota randomly. task-6119168
This update fixes an issue where closing a POS session could incorrectly attempt to cancel transactions belonging to other POS terminals. The change now ensures transactions are fetched and canceled only for the current POS terminal, enhancing the reliability and accuracy of session closure. This prevents errors and improves the overall POS experience.
Original PR description
Before this commit, when closing a POS session, it fetched all active transactions via generic /tx endpoint, which returns transactions across all TSS. Attempting to cancel a transaction belonging to another TSS raised:
"Not a Transaction of TSS <tss_id>"
Fix by scoping the fetch to /tss/<tss_id>/tx so only transactions of the current TSS are returned, and appending client_id as an additional filter to avoid touching transactions from other POS terminals sharing the same TSS. A JS-side client_id check is kept as a defensive safety net before the cancellation loop.
opw-6243187This update fixes a bug that prevented proper error messages from appearing when new IoT Boxes encountered problems. The change ensures that users receive clear notifications about errors, improving the overall reliability and troubleshooting of the IoT Box functionality within Odoo Enterprise. This resolves a previously missed error handling issue.
Original PR description
This completes odoo/enterprise#11196, which missed error message handling for new IoT Boxes errors. `message_body` was undefined on `data.status` when `data.status === "error"`. <img width="1871" height="942" alt="image" src="https://github.com/user-attachments/assets/30b54c5b-da0d-497d-8d9e-912f7139140b" />
This update corrects a bug in the VAT reporting module that was incorrectly displaying '01' as the operation code for invoices with 'No Sujeto por reglas de localización' (PT VAT) taxes. The fix ensures accurate reporting by aligning with the Spanish VAT regime code table, improving the reliability of VAT book exports.
Original PR description
**Steps to reproduce:** * Install the **l10n_es_edi_sii** module. * Create a **Portuguese customer**. * Go to **Settings** and enable **EU Intra-community Distance Selling**, then refresh the tax…
**Steps to reproduce:** * Install the **l10n_es_edi_sii** module. * Create a **Portuguese customer**. * Go to **Settings** and enable **EU Intra-community Distance Selling**, then refresh the tax mapping. * Create a customer invoice with a **"No Sujeto por reglas de localización"** tax (e.g. **23.0% PT VAT**). * Go to **Accounting → Reporting → Tax Report → OSS Sales**. * Export the **VAT Record Books (XLSX)** file and open it. **Observed behavior:** * The "Clave de Operación" column shows "01" for lines with no_sujeto_loc taxes instead of "17". * The SII JSON for the same invoice correctly shows "ClaveRegimenEspecialOTrascendencia": "17". **Cause:** * In `_l10n_es_libros_get_common_line_vals()`, `operation_code` was computed manually as `'02' if exempt_reason else '01'`, which only handled the E2 exempt case and defaulted everything else to "01". * This missed OSS/no_sujeto_loc taxes (e.g. FR VAT, PT VAT) that should produce "17" per the Spanish VAT regime code table. **Fix:** * Extract operation code computation into a new dedicated method `_l10n_es_libros_get_operation_code()`. * For customer invoices, delegate to the existing `_l10n_es_get_regime_code()` method already used by SII, which correctly returns "17" for OSS-tagged taxes, "02" for E2 exempt, and "01" otherwise. * For vendor bills, mirror the SII logic by checking whether the invoice taxes include tags from `mod_303_casilla_10_balance` or `mod_303_casilla_11_balance` (intra-community indicators), returning "09" if so and "01" otherwise. opw-6197141,6216485
This update fixes a calculation error in the executive summary report that was underreporting the number of days in a period. Previously, the report was calculating the gap between dates instead of the total number of days. This change ensures the average debtor days and other key metrics are accurately calculated, improving the reliability of the report.
Original PR description
`_report_custom_engine_executive_summary_ndays` returned `date_to - date_from`, which is the gap between the two dates, not the count of days they span. For example April 2026-04-01 to 2026-04-30 will returned 29 instead of 30, making Average Debtor Days incorrect. Add +1 so the day count is inclusive of both endpoints, matching the rest of the report's date handling. opw-6215362 Forward-Port-Of: odoo/enterprise#118953