Thursday, June 4, 2026
19 changes · saas-19.2
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
This update fixes an issue where project profitability reports were inaccurate when vendor bills included negative subtotals (like downpayments). The system now correctly accounts for these negative amounts, ensuring accurate cost calculations for projects with complex billing arrangements. This improves the reliability of project financial reporting.
Original PR description
**Problem:** If a vendor bill associated with a project through its analytic distribution has lines with negative subtotals, those lines are not considered in the project profitability report. An…
**Problem:** If a vendor bill associated with a project through its analytic distribution has lines with negative subtotals, those lines are not considered in the project profitability report. An example use case is a downpayment invoice, followed by a final invoice with the downpayment amount deducted. **Steps to Reproduce:** - Ensure project_purchase is not installed - Create a new project with "Billable" enabled - Go to the project settings and create an analytic account - Create and post a vendor bill with a line labeled "downpayment", the analytic account set, and a unit price of 5 - Duplicate the vendor bill, set the "downpayment" line unit price to -5, add a line labeled "product" with the analytic account set and a unit price of 10, and post the bill -> Go to the project updates and see that the vendor bill costs is wrong (15) **Solution:** A similar bug affecting customer invoices was resolved in PR #130992. AMLs with non-zero subtotals should be considered, so the domain is adjusted accordingly. opw-6172523 Forward-Port-Of: odoo/odoo#265378