Thursday, March 12, 2026
22 changes · saas-18.3
Enhancements to existing features
This change optimizes the process of generating GST reports by streamlining the database query. Specifically, it removes a complex domain filter that caused performance issues with large datasets, resulting in faster report generation times. This improvement focuses on efficiency and scalability for handling substantial amounts of financial data.
Original PR description
If account.move and account.move.line have big data then domain with create problme ORM create sub query like this ``` SELECT account_move.id FROM account_move WHERE (…
If account.move and account.move.line have big data then domain with create problme ORM create sub query like this
```
SELECT
account_move.id
FROM
account_move
WHERE
(
account_move.l10n_in_gst_return_period_id = 23
OR (
account_move.move_type IN ('in_invoice', 'in_refund')
AND account_move.invoice_date >= '2025-11-01'
AND account_move.invoice_date <= '2025-11-30'
AND account_move.company_id IN (1)
AND account_move.state = 'posted'
AND (
account_move.l10n_in_gst_treatment NOT IN ('composition', 'unregistered', 'consumer')
OR account_move.l10n_in_gst_treatment IS NULL
)
AND account_move.id IN (
SELECT
account_move_line.move_id
FROM
account_move_line
WHERE
EXISTS (
SELECT 1
FROM account_move_line_account_tax_rel AS account_move_line__tax_ids
WHERE account_move_line__tax_ids.account_move_line_id = account_move_line.id
)
)
)
)
ORDER BY
account_move.date DESC,
account_move.name DESC,
account_move.invoice_date DESC,
account_move.id DESC
```
See this EXPLAIN for big database
```
Gather Merge (cost=165759176482.82..2983665158687.50 rows=36 width=30)
Workers Planned: 2
-> Incremental Sort (cost=165759175482.80..2983665157683.32 rows=18 width=30)
Sort Key: account_move.date DESC, account_move.name DESC, account_move.invoice_date DESC, account_move.id DESC
Presorted Key: account_move.date
-> Parallel Index Scan Backward using account_move__date_index on account_move (cost=59.28..2983665157682.51 rows=18 width=30)
Filter: ((l10n_in_gst_return_period_id = 23) OR (((move_type)::text = ANY ('{in_invoice,in_refund}'::text[])) AND (invoice_date >= '2025-11-01'::date) AND (invoice_date <= '2025-11-30'::date) AND (company_id = 1) AND ((state)::text = 'posted'::text) AND (((l10n_in_gst_treatment)::text <> ALL ('{composition,unregistered,consumer}'::text[])) OR (l10n_in_gst_treatment IS NULL)) AND (SubPlan 1)))
SubPlan 1
-> Materialize (cost=58.84..1601427.18 rows=4994548 width=4)
-> Merge Semi Join (cost=58.84..1556944.44 rows=4994548 width=4)
Merge Cond: (account_move_line.id = account_move_line__tax_ids.account_move_line_id)
-> Index Scan using account_move_line_pkey on account_move_line (cost=0.44..1339780.32 rows=26611459 width=8)
-> Index Only Scan using account_move_line_account_tax_rel_pkey on account_move_line_account_tax_rel account_move_line__tax_ids (cost=0.43..88678.65 rows=4994548 width=4)
```
So removing this from domain and put it as condition it's faster
Forward-Port-Of: odoo/enterprise#109795Resolved issues and error corrections
This update resolves an issue where expense reports created from incoming emails weren't being generated due to a company mismatch. The fix ensures the system always uses the employee's company when creating the expense, regardless of any associated user, preventing the 'Incompatible companies' error. This improves the reliability of automated expense reporting.
Original PR description
**Steps to reproduce:** - Install Expenses - Activate "Incoming Emails" in the settings - Configure the expense Alias - Configure an "Incoming Mail Server" - Create a Branch for a company - Create a…
**Steps to reproduce:** - Install Expenses - Activate "Incoming Emails" in the settings - Configure the expense Alias - Configure an "Incoming Mail Server" - Create a Branch for a company - Create a User: * Email Address: [an existing email address] * Allowed Companies: [the parent company + the branch company] * Default Company: [the branch company] * User Types: Internal User - Create an employee for the user in the parent company - From the email address, send a PDF to the expense alias **Issue:** The expense is not created in the database due to a UserError: "Incompatible companies on records". **Cause:** When the email is received and treated, the system tries to create an expense. From the email address, it retrieves an employee that is linked to the expense. For the company of the expense, if a user is linked to the employee, it takes the default company of the user. Otherwise, it takes the company of the employee. In this case, the company set on the expense is the default company of the user (i.e. the branch company) and the employee set on the expense belongs to the parent company ; which triggers the UserError during the company check. **Solution:** Always use the company of the employee, even if there is a user linked to the employee. opw-5346809 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#253313 Forward-Port-Of: odoo/odoo#249415
This update ensures accurate sub-line total calculations in the stock barcode module, which now requires the 'stock.group_production_lot' setting to be active. Without this setting, the system fails to group lines correctly, leading to incorrect totals. This fix was introduced during the 18.3 forward port and resolves an issue observed in Single App and Single L10n environments.
Original PR description
This issue occurs on Single App and Single L10n, without demo data ### Summary This part of the test verifies that the sub line totals are calculated correctly, which from 18.3 requires the…
This issue occurs on Single App and Single L10n, without demo data ### Summary This part of the test verifies that the sub line totals are calculated correctly, which from 18.3 requires the stock.group_production_lot setting to be active. Specifically, it validates that the sum accurately reflects the Unit of Measure (UOM) across various packagings. https://github.com/odoo/enterprise/blob/93e3c6f13fbab8d54694648d04908e451f1e97fc/stock_barcode/static/tests/tours/tour_test_barcode_flows_picking.js#L6472-L6498 ### Observation The grouping logic is contingent on the stock.group_production_lot setting. If this setting is inactive, the system fails to group lines, preventing the calculation of the aggregate total. Without the production lot group active, the conditional checks will bypass the grouping process: https://github.com/odoo/enterprise/blob/d664e1f97f6e7fa462b4cf1806322a54762c0de4/stock_barcode/static/src/models/barcode_model.js#L53 https://github.com/odoo/enterprise/blob/d664e1f97f6e7fa462b4cf1806322a54762c0de4/stock_barcode/static/src/models/barcode_model.js#L224-L225 When the demo data are enabled [the group is implied](https://github.com/odoo/odoo/blob/8a7ca8beac521f41faf79a6022935fdbb605de76/addons/stock/data/stock_demo.xml#L185-L187) ### Impact When stock.group_production_lot is disabled: - Lines remain ungrouped. - The total sum of the grouped line is never generated. - The test fails as it cannot find or validate the expected sub-line totals. This issue originate from the 18.3 forward port of this [commit](https://github.com/odoo/enterprise/commit/84d4b1f144e8a437fe76ec5ef3bc9799cdf993b0) runbot-241109
This update fixes an issue where the MPS wasn't accurately reflecting demand for dependent components. Previously, the system defaulted to the oldest BoM, regardless of user-defined preferences. This change ensures that component demand is correctly calculated and updated within the MPS, improving forecasting accuracy.
Original PR description
## Issue: When computing the product tree, the system would use `_bom_find` to find the BoM. However, it's possible to have multiple BoM for the same product, and the user should have chosen which…
## Issue:
When computing the product tree, the system would use `_bom_find` to find the BoM. However, it's possible to have multiple BoM for the same product, and the user should have chosen which BoM he wants to use. `_bom_find` ignores the user configuration in MPS, and simply select the first (oldest) BoM in the list. This means that the components in the MPS would not be correctly updated.
---
## How to reproduce:
https://github.com/user-attachments/assets/c7e6f4d4-332a-4e2b-a40a-1b831daeb6c8
- Create Products FNS & CMP
- Create BoM for FNS without bom line (V1)
- Create BoM for FNS with CMP in bom lines (V2)
- Add FNS to MPS using bom V2
- Set Forecast Qty of FNS to 10
- => Indirect Demand Qty for CMP is not shown (because it's 0)
---
## Test Result without fix:
```
2026-03-05 15:00:24,601 52396 INFO oes_test_18.0 odoo.addons.mrp_mps.tests.test_mrp_mps: Starting TestMpsMps.test_indirect_multiple_boms ...
2026-03-05 15:00:24,742 52396 INFO oes_test_18.0 odoo.addons.mrp_mps.tests.test_mrp_mps: ======================================================================
2026-03-05 15:00:24,742 52396 ERROR oes_test_18.0 odoo.addons.mrp_mps.tests.test_mrp_mps: FAIL: TestMpsMps.test_indirect_multiple_boms
Traceback (most recent call last):
File "/home/odoo/Odoo/src/18.0/enterprise/mrp_mps/tests/test_mrp_mps.py", line 1556, in test_indirect_multiple_boms
self.assertEqual(forecast_cmp['forecast_ids'][0]['indirect_demand_qty'], 10)
AssertionError: 0.0 != 10
```
---
OPW-5979738
Forward-Port-Of: odoo/enterprise#109693This update resolves conflicts in how transactions are managed for the German Point of Sale (POS) system, specifically related to Fiskaly reporting. It ensures that only transactions tied to a specific terminal are cancelled, preventing issues with shared POS systems. The changes improve reliability and accuracy of transaction state management.
Original PR description
Changes:
- cancelActiveTransactions: use the TSS-scoped endpoint
/tss/{tss_id}/tx and filter results by client_id so only orphaned
transactions from this terminal are cancelled, never those from
other POS sessions sharing the same TSS
- transactionCall: on non-retryable errors (400 revision conflict or
terminal state mismatch), call _handleTransactionStateConflict which
GETs the actual transaction state and recovers:
- Cancelling already CANCELLED → silent success
- Finishing already FINISHED → return existing tx data
- Finishing a CANCELLED tx → create a fresh transaction and finish it
- handleFiskalyCancellation: correctly reset transactionState to
inactive on the uiState after cancellation
opw-5972708
Forward-Port-Of: odoo/enterprise#109996This update resolves an access error that occurred when confirming orders with gift cards in the DE company setup. The issue stemmed from a misplaced sudo() call, preventing proper access to product accounts. By correctly applying sudo() during stock valuation, the system now successfully processes gift card payments during order confirmation.
Original PR description
**Steps to reproduce:** - Install `l10n_de, website_sale and appointment` modules. - Create a website for the `DE company` and make it default. (simply place it first in the sequence.) - From…
**Steps to reproduce:** - Install `l10n_de, website_sale and appointment` modules. - Create a website for the `DE company` and make it default. (simply place it first in the sequence.) - From settings enable `Automatic Invoice` and `Discounts, Loyalty & Gift Card`. - Go to the appointment module and create a new appointment for the DE company. - In the options tab, enable `Up-front payment` and publish it. - Create a new gift card program and generate a gift card to test (should cover the entire cost of the appointment booking). - Now go to an Incognito tab, go to the appointment, and book the currently created appointment. When confirming the order, use the gift card and then confirm the order. **Issue:** - When you confirm the order, an access error occurs. **Root cause:** - Since automatic invoicing is enabled, at [1] the method `get_product_accounts` is called for the DE company. Inside this method at [2], self.sudo(False) is used, which removes the elevated access rights. As a result, the `Public product template` record rule is triggered, and because the public user cannot access the product, an AccessError is raised. - In this [commit], we can see that `sudo(False)` was added when coming from the stock flow because the stock valuation layer was being created as sudo. **Solution:** - Instead of adding `sudo(False)` in **l10n_de**, we can apply `sudo(False)` at the point where the **stock valuation layer** is created using `sudo()`. [1]https://github.com/odoo/odoo/blob/9d5d5c08f950d32bf61c2186181e8eddad9036da/addons/account/models/account_move_line.py#L603-L604 [2]https://github.com/odoo/odoo/blob/9d5d5c08f950d32bf61c2186181e8eddad9036da/addons/l10n_de/models/datev.py#L20 [commit]: https://github.com/odoo/odoo/pull/236931/changes/0919774791bb998954b870798c88843f999f2de4 opw-5483472 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#253131 Forward-Port-Of: odoo/odoo#246920
This update fixes an issue where leave hours weren't being calculated correctly for time off allocations without end dates. The change adjusts the system to treat these allocations as continuous, starting from the earliest start date, ensuring accurate tracking of taken hours. This improves the reliability of leave balance reporting.
Original PR description
### Steps to reproduce: - Create a Overtime hours time off type - Create mutliple allocations with different start dates but no end date - Create some leaves for the created allocations one after…
### Steps to reproduce: - Create a Overtime hours time off type - Create mutliple allocations with different start dates but no end date - Create some leaves for the created allocations one after each allocation start date - Compare the number of hours remaining for the allocations' employee in his time off dashboard and in the Balance report. ### Cause: After this commit https://github.com/odoo/odoo/pull/245860/changes/d9bb4d206e91d10eac7311adede307b8c5019213 we changed the way we match leaves with allocations but we were strict that the leave has to lie in between the allocation dates and this created a wrong accumlated taken_hours in the taken_per_allocation subquery. ### Fix: Following the same approach we use in if the allocation has no expiry date we don't check if the leave.date_to > allocation.date_from as we are going to treat all allocations as they form one big allocation that started in the earliest start date opw-5474596 Forward-Port-Of: odoo/odoo#251704 Forward-Port-Of: odoo/odoo#250432
A bug was causing accrual leave calculations to be delayed by one month. This update corrects a logic error in the system that was incorrectly applying carry-over dates, resulting in missed accruals. This ensures employees receive the correct accrual amounts as intended.
Original PR description
steps to reproduce: ------------------- 1. Install Time Off 2. Go to Configuration > Accrual Plans 3. Create an accrual plan: * Set the accrued gain time to "At the start of the accrual period" * Set…
steps to reproduce: ------------------- 1. Install Time Off 2. Go to Configuration > Accrual Plans 3. Create an accrual plan: * Set the accrued gain time to "At the start of the accrual period" * Set the carry-over time to "At the start of the year" 4. Create a milestone: * Set the number of accrued days to 1 * Set the accrual frequency to "monthly" and the carry over to "None.Accrued time reset to 0" 5. Go to Management > Allocations 6. Create an allocation: * Set the start date to 2025-01-01 * Set the accrual plan to the one created above 7. Use future allocations to check accruals current behavior: ----------------- - On 2026-01-01 --> accrued days = 1 (correct) - On 2026-02-01 --> accrued days = 1 (should be 2) - On 2026-03-01 --> accrued days = 2 (delayed accrual, off by one month) cause of the issue: ------------------- Commit 30c7011 introduced a condition that accrues time off on the carry over date: https://github.com/odoo/odoo/blob/1416aad902a97ce56aaecc2aadc4dd9f7814ee53/addons/hr_holidays/models/hr_leave_allocation.py#L559 This incorrectly evaluates accruals across the carry over period instead of restricting to the current month, causing February accruals to be skipped. **Reason February accruals are skipped:** https://github.com/odoo/odoo/blob/dcb072f675c5630327d27d785b86e1ec8e2d442d/addons/hr_holidays/models/hr_leave_allocation.py#L559-L561 https://github.com/odoo/odoo/blob/dcb072f675c5630327d27d785b86e1ec8e2d442d/addons/hr_holidays/models/hr_leave_allocation.py#L541-L544 * After January, the last_executed_carryover_date is set to 2026-01-01. * Therefore, February uses last_executed_carryover_date = 2026-01-01. * The condition evaluates as true for February: ```python3 last_executed_carryover_date <= allocation.nextcall <= carryover_period_end 2026-01-01 <= 2026-02-01 <= 2026-02-01 ``` As a result, the February accrual is skipped. **Why it works correctly in March:** * After February, the last_executed_carryover_date is updated to 2027-01-01. * March now uses this updated date: ```python3 last_executed_carryover_date <= allocation.nextcall <= carryover_period_end 2027-01-01 <= 2026-03-01 <= 2027-02-01 ``` The condition is not satisfied, so accruals are processed correctly. solution: ---------- Add a condition to check if the loop has already run for the current carryover period. This ensures the system avoids applying the carryover twice, allowing subsequent accruals to process as expected. opw-5020834 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#253153 Forward-Port-Of: odoo/odoo#227646
This update corrects a validation error that occurred when sending invoices to Peppol. The system previously incorrectly converted 'qt (US)' to 'QT', which is no longer a valid unit code according to UN/ECE standards. This fix ensures invoices comply with international regulations and avoids rejection during electronic data exchange.
Original PR description
Currently, the Odoo UoM 'qt (US)' is converted to 'QT', which is not valid anymore. Based on investigation, this was originally set to QT following this link: https://unece.org/fileadmin/DAM/cefact/recommendations/rec20/rec20_rev3_Annex2e.pdf But this document seems dated from 2005. Step to reproduce: - Create an invoice with a line with 'qt (US)' as UoM - Try to send the invoice to Peppol - You will get a validation error: "[BR-CL-23]-Unit code MUST be coded according to the UN/ECE Recommendation 20 with Rec 21" Also removed the link to unece.org since the link is no longer valid. opw-5961476 Forward-Port-Of: odoo/odoo#252803 Forward-Port-Of: odoo/odoo#252174
A bug preventing users from copying their two-factor authentication codes through the portal has been resolved. The update corrected a technical issue related to how the 'Copy' button was configured, ensuring users can now reliably access and copy their security codes. This improves the security and usability of the Odoo portal.
Original PR description
__Problem__ Since odoo/odoo@e3da5f1 the onclick listener set on `copyButton` is lost because we give the HTML of the body as argument at the dialog creation. __Steps to reproduce__ 1. Go to `/my/security` 2. Click on "Enable two-factor authentication" 3. Confirm password 4. Click on "Cannot scan it?" 5. The "Copy" button doesn't work __Fix__ - Inherit from `InputConfirmationDialog` to add a listener to the button. - At the same time, remove the remaining jQuery dependency in this part of the code Forward-Port-Of: odoo/odoo#253314 Forward-Port-Of: odoo/odoo#251429
This update resolves an issue where the Nemhandel XML format for Danish tax reporting was missing a crucial identifier. Specifically, the `schemeID` attribute was added to correctly identify the buyer as 'DK:CVR', ensuring compliance with OIOUBL 2.1 standards. This ensures accurate data transmission for tax purposes.
Original PR description
Nemhandel follows the OIOUBL 2.1 XML format. To specify the Buyer identifier, we use the <cac:PartyIdentification> node. But we are missing the `schemeID` attribute, which should be for DK "DK:CVR". This commit adds this attribute. opw-5232123 Forward-Port-Of: odoo/odoo#253132 Forward-Port-Of: odoo/odoo#250942
This update resolves an issue where the HTML editor would get stuck in an infinite loop when removing formatting from text containing icons. The fix ensures that icons are correctly processed during format removal, preventing the loop and restoring normal functionality. This improves the overall stability and usability of the To-do app.
Original PR description
Steps to reproduce: =================== 1. Open the To-do app and pick any task. 2. In the description add text and an icon with a bg color. `(you can add this: <i class="fa rounded rounded-circle…
Steps to reproduce: =================== 1. Open the To-do app and pick any task. 2. In the description add text and an icon with a bg color. `(you can add this: <i class="fa rounded rounded-circle fa-user bg-o-color-1 fa-4x" contenteditable="false"></i>)` 3. Select all and click "Remove format". Result: -> Traceback due to an infinite loop. Cause: ====== Remove format calls `removeAllColor()`, which loops forever at: https://github.com/odoo/odoo/blob/626bde21a25366d0bb29662bae2057c247a1638e/addons/html_editor/static/src/main/font/color_plugin.js#L194-L194 Why: _applyColor doesn't remove the icon's background class, so hasAnySelectedNodeColor keeps returning true and the removal loop never terminates. This happens because `font` is already the `<i>` element with the `fa` class, using `querySelectorAll` on it won't include the element itself, so the icon is never checked or updated. https://github.com/odoo/odoo/blob/6cdc6f55886ea48e90f9023a6c6142bf072745b9/addons/html_editor/static/src/main/font/color_plugin.js#L290 Solution: ========= Check if the font itself has the fa class before doing the `querySelectorAll`, and include it in the nodes to check for color. Test Impact: ============ Before this fix, a `<span>` containing an icon was wrapped in a `<font>` when applying color, treating the icon as a normal span (without size) instead of applying the color directly. https://github.com/odoo/odoo/blob/8792c2d38eb0aadac8d778d83fd76f270404ecd5/addons/html_editor/static/src/main/font/color_plugin.js#L397 opw-5928627 Forward-Port-Of: odoo/odoo#248449
This update fixes an issue where manufacturing orders created through the barcode app incorrectly used product UoMs instead of the specified BoM UoMs. Now, MOs created with BoMs will accurately reflect the BoM's component quantities, ensuring correct stock management within the barcode workflow. This resolves a previous traceback and improves data accuracy.
Original PR description
Previous behaviour: * Traceback if MO created with a BoM whose lines have UoMs that don't correspond to those of the products, then UoM setting disabled and MO viewed in the barcode app. * BoM line UoMs ignored in favour of product UoMs when creating MO in the barcode app. New behaviour: * No traceback. * Stock moves in MOs properly created with the corresponding BoM line UoMs. Task ID: [4674196](https://www.odoo.com/odoo/my-tasks/4674196) Forward-Port-Of: odoo/enterprise#109723 Forward-Port-Of: odoo/enterprise#90408
This update resolves a bug where invoices created by registered Peppol companies were being incorrectly rejected by accounting partners. The fix prevents automatic recalculation of EAS/Endpoint data when VAT information changes, ensuring accurate invoice generation and avoiding the need for users to un-register and re-register their companies. This improves invoice processing and data synchronization.
Original PR description
To reproduce: - Register your company on Peppol (even sender). - Change the VAT on your company (will be done if you choose your document layout). - Send an invoice on the network - => The invoice…
To reproduce: - Register your company on Peppol (even sender). - Change the VAT on your company (will be done if you choose your document layout). - Send an invoice on the network - => The invoice will be refused by the AP. The issue is that the EAS and Endpoint are automatically re-computed when you write on the VAT. It causes issues as the UBL will be filled with the values on the partner, resulting in a non-synchronised SBD and UBL, which will result in all new invoices to be in error. Their only solution would be to revert back the EAS/Endpoint on the partner, which will sometimes be blocked meaning they have to un-register->re-register Also adapt the query count, as we need to do a search in each compute. opw-5923552 opw-5924552 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#252549 Forward-Port-Of: odoo/odoo#249017
This update resolves an issue where refunding orders in Point of Sale (POS) would fail due to a missing component in the system. Specifically, the 'pos.order' model was not being properly loaded, causing errors when attempting to retrieve related order lines. This change ensures refunds process smoothly.
Original PR description
Before this commit, the pos.order model was not included in the auto-loaded models. It causes issue when loading the orders to refund. Because the `refund_orderline_ids` field loads order lines from another order, if the order is not loaded, it raises an error. opw-5383907 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update fixes an issue where group leave durations were incorrectly calculated when overlapping with existing approved leave requests. The fix ensures that group leave durations accurately reflect all allocated time off, resolving a discrepancy in how the system processed conflicting leave types. This improves the accuracy of time off scheduling.
Original PR description
Problem ------------------------ When an employee has approved leaves, and a group leave is created that overlaps with the approved leave and overrides it, the duration of the new group leave is not…
Problem ------------------------ When an employee has approved leaves, and a group leave is created that overlaps with the approved leave and overrides it, the duration of the new group leave is not computed correctly. The duration does not include the overridden days. To reproduce: 1. Create allocated leave for employee and approve and validate it. 2. Go to Management > Time Off and create a group leave for the employee that includes the approved time off dates. The dates of all leaves are updated correctly, but the duration of the group leave is incorrect. Objective --------------------------- Even though conflicting leaves were correctly split in the multi leave generation wizard, the resource.calendar.leaves table was not synchronized within the same transaction. Because the leave types required allocation, the duration was computed by subtracting the old time off days from the new leave's duration, since they were treated as unavailable. Solution -------------------------- Manually unlink the resource.calendar.leaves records associated with the conflicting leaves before calculating the new duration. The clears the employee's schedule in the database so that the dates are correctly processed as available. The calendar blocks for the remaining days of the approved time off and the new group leave are generated when the leaves are created. Task: 5911074 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#249527
This update resolves an issue where multiple pickings were created when reducing the quantity of a multi-step kit order. The fix corrects a calculation error within the system's inventory management process, ensuring accurate procurement generation and preventing unnecessary stock movements. This improves order fulfillment efficiency and reduces potential errors.
Original PR description
Backport of 0432a982dfea6e68419f137502c018c0a9241181 ### Steps to reproduce: 1. In the settings enable: Multi-steps route 2. Put your warehouse in 2-step deliveries 3. Create a kit product: - With…
Backport of 0432a982dfea6e68419f137502c018c0a9241181 ### Steps to reproduce: 1. In the settings enable: Multi-steps route 2. Put your warehouse in 2-step deliveries 3. Create a kit product: - With one component - There is one component in the stock 4. Create and confirm a SO with 1 x K 5. Process the pick and ship 6. Return the delivery 7. Set the sol qty to 0 ### > Two unexpected pickings are created to put the kit in output Decreasing the sol quantity to 0 will call the `_action_launch_stock_rule` in order to create and run procurements related to that quantity change. However, the quantity currently handled by other procurements is determined here by the `_compute_kit_quantities`: https://github.com/odoo/odoo/blob/87e176ad76c9d7b87cd622ae38a8b9a62813b1cb/addons/sale_stock/models/sale_order_line.py#L388 https://github.com/odoo/odoo/blob/87e176ad76c9d7b87cd622ae38a8b9a62813b1cb/addons/sale_mrp/models/sale_order_line.py#L154-L166 https://github.com/odoo/odoo/blob/87e176ad76c9d7b87cd622ae38a8b9a62813b1cb/addons/mrp/models/stock_move.py#L578-L580 Now, the issue is that `_compute_kit_quantities` does not handle move chains properly, as all delivery moves contribute to the `incoming_qty` and all return moves contribute to the `outgoing_qty`. This results in an `incoming_qty` of 1 (for the pick) + 1 (for the ship) and an `outgoing_qty` of 1 (for the 1-step return), that is a `qty_processed` of 1. As a result, the procurement will be generated for a quantity of `0 - 1` (rather than 0): https://github.com/odoo/odoo/blob/87e176ad76c9d7b87cd622ae38a8b9a62813b1cb/addons/sale_stock/models/sale_order_line.py#L388-L402 which leads to the unexpected picking creations. opw-6006543 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#253061
This update ensures Odoo invoices sent to the AFIP web service (ARCA) comply with their strict requirements for numeric fields like price and quantity. By limiting precision to 3 decimal places, we prevent invoice rejections and maintain accurate accounting data. This change aligns with AFIP's specifications and Odoo's existing rounding practices.
Original PR description
… request ARCA requires numeric fields such as unit price and quantity to have a maximum of 12 integer digits and 6 decimal places. If these fields are sent with more than 6 decimals, AFIP rejects…
… request ARCA requires numeric fields such as unit price and quantity to have a maximum of 12 integer digits and 6 decimal places. If these fields are sent with more than 6 decimals, AFIP rejects the invoice with errors like: `Code 1814: Campo Cmp.Items.Pro_precio_uni invalido. El valor debe tener 12 enteros y 6 decimales como máximo.` To ensure compliance, values are formatted before sending the request to ARCA. **Precision rationale** ARCA WS documentation mentions 4 decimal places, while the WS error message itself refers to 6 decimals, and in practice the service accepts up to 6 decimals without rejection. In this implementation, we intentionally use 2 decimal places. The reason is consistency with the rest of the monetary amounts in the invoice: line totals, invoice total, taxes, and related amounts are all rounded to 2 decimals, even in cases where the documentation allows higher precision (e.g., 3 decimals). Before the changes in rounding precision, the stable version already rounded values according to line rounding. In real-world accounting scenarios, the vast majority of use cases operate with 2 decimal places. Keeping this behavior ensures consistency across calculations and avoids discrepancies caused by mixed rounding strategies. For a stable release, this was considered the safest and most predictable option, even though the WS technically allows higher precision. Stable version changes are covered in the following commits: https://github.com/odoo/odoo/pull/243987/changes/8a21ec45f9d72a7c80d9c1f8398fe01e298ae775 https://github.com/odoo/odoo/pull/246347/changes/79ceeed707ef274f19a04e741f6cb8ac60c44321 <img width="780" height="435" alt="image" src="https://github.com/user-attachments/assets/9f25a0e8-b9d2-4ad2-bbcf-e988c7f8a4c9" /> [WSFEX - Manual de desarrollador](https://www.afip.gob.ar/ws/WSFEX/WSFEX-Manualparaeldesarrollador.pdf) Forward-Port-Of: odoo/enterprise#106509
This update addresses a previous memory issue that occurred when calculating depreciation, particularly with large numbers of accounting records. The fix utilizes a more efficient method to process data, reducing memory usage and improving performance. This ensures the system can handle a greater volume of transactions without errors.
Original PR description
The previous compute method loaded all moves records into memory, which caused an out-of-memory issue for large number of record. Replaced the logic with read_group aggregation to perform the…
The previous compute method loaded all moves records into memory, which caused an out-of-memory issue for large number of record. Replaced the logic with read_group aggregation to perform the calculation using sql and reduce memory usage.
Note: the issue is faced during 16.0 version too but as 16.0 is no more supported for bug fix. So, doing it from 17.0 version.
```
Traceback (most recent call last):
File "/tmp/tmpkvo8a96w/migrations/base/tests/test_mock_crawl.py", line 333, in crawl_menu
self.mock_action(action_vals)
File "/tmp/tmpkvo8a96w/migrations/base/tests/test_mock_crawl.py", line 346, in mock_action
return self.mock_act_window(action)
File "/tmp/tmpkvo8a96w/migrations/base/tests/test_mock_crawl.py", line 506, in mock_act_window
mock_method(model, view, fields_list, domain, group_by)
File "/tmp/tmpkvo8a96w/migrations/base/tests/test_mock_crawl.py", line 657, in mock_view_tree
self.mock_web_search_read(model, view, [domain], fields_list)
File "/tmp/tmpkvo8a96w/migrations/base/tests/test_mock_crawl.py", line 691, in mock_web_search_read
data = model.search_read(domain=domain, fields=fields_list, limit=80, order=filter_order(model))
File "/home/odoo/src/odoo/16.0/odoo/models.py", line 5074, in search_read
result = records.read(fields, **read_kwargs)
File "/home/odoo/src/odoo/16.0/odoo/models.py", line 3038, in read
return self._read_format(fnames=fields, load=load)
File "/home/odoo/src/odoo/16.0/odoo/models.py", line 3219, in _read_format
vals[name] = convert(record[name], record, use_name_get)
File "/home/odoo/src/odoo/16.0/odoo/models.py", line 6007, in __getitem__
return self._fields[key].__get__(self, self.env.registry[self._name])
File "/home/odoo/src/odoo/16.0/odoo/fields.py", line 1222, in __get__
self.compute_value(recs)
File "/home/odoo/src/odoo/16.0/odoo/fields.py", line 1404, in compute_value
records._compute_field_value(self)
File "/home/odoo/src/odoo/16.0/addons/mail/models/mail_thread.py", line 403, in _compute_field_value
return super()._compute_field_value(field)
File "/home/odoo/src/odoo/16.0/odoo/models.py", line 4276, in _compute_field_value
fields.determine(field.compute, self)
File "/home/odoo/src/odoo/16.0/odoo/fields.py", line 98, in determine
return needle(*args)
File "/home/odoo/src/enterprise/16.0/account_asset/models/account_asset.py", line 293, in _compute_value_residual
posted_depreciation_moves = record.depreciation_move_ids.filtered(lambda mv: mv.state == 'posted')
File "/home/odoo/src/odoo/16.0/odoo/models.py", line 5496, in filtered
return self.browse([rec.id for rec in self if func(rec)])
File "/home/odoo/src/odoo/16.0/odoo/models.py", line 5496, in <listcomp>
return self.browse([rec.id for rec in self if func(rec)])
File "/home/odoo/src/enterprise/16.0/account_asset/models/account_asset.py", line 293, in <lambda>
posted_depreciation_moves = record.depreciation_move_ids.filtered(lambda mv: mv.state == 'posted')
File "/home/odoo/src/odoo/16.0/odoo/fields.py", line 1187, in __get__
recs._fetch_field(self)
File "/home/odoo/src/odoo/16.0/odoo/models.py", line 3245, in _fetch_field
self._read(fnames)
File "/home/odoo/src/odoo/16.0/odoo/models.py", line 3351, in _read
self.env.cache.insert_missing(fetched, field, values)
File "/home/odoo/src/odoo/16.0/odoo/api.py", line 1123, in insert_missing
field_cache.setdefault(id_, val)
MemoryError
```
opw-5921410
upg-3891767
Forward-Port-Of: odoo/enterprise#109008This update resolves an issue where users couldn't properly validate UY CFEs due to permission restrictions on company data. By adding `sudo()` access, the system now correctly retrieves the necessary information, ensuring accurate CFE processing. This improves the reliability of the UY accounting module.
Original PR description
This pull request makes a small update to the `_ucfe_inbox` method in `l10n_uy_edi_document.py` to ensure that company-specific fields are always accessed with the appropriate permissions. This is achieved by using the `sudo()` method when retrieving the `l10n_uy_edi_ucfe_commerce_code` and `l10n_uy_edi_ucfe_terminal_code` fields from the `company` record. * Ensured that `l10n_uy_edi_ucfe_commerce_code` and `l10n_uy_edi_ucfe_terminal_code` fields are accessed with elevated permissions by calling `company.sudo()` in the `_ucfe_inbox` method (`l10n_uy_edi_document.py`). Without this fix, if the user doesn't belong to group "base system", it won't be able to validate CFEs, receiving the following message: <img width="1272" height="400" alt="image" src="https://github.com/user-attachments/assets/ec4223fb-5b96-4a3e-babf-2f6a35ecd123" /> Forward-Port-Of: odoo/enterprise#105918
This update fixes an issue where annual returns incorrectly used a fiscal year filter when company fiscal years differed. Now, returns always follow the civil year, ensuring accurate reporting and the correct display of return period filters. This improves the reliability of financial data presented to users.
Original PR description
Backported from https://github.com/odoo/enterprise/pull/104726 When a company fiscal year differs from the civil year, the annual return incorrectly falls back to the report’s FY-aligned year filter. The return should always follow the civil year, so the fallback is skipped and the return period filter is shown instead. task-5511074
This update resolves rounding errors that occurred when creating kit products, specifically during purchase order validation. The fix ensures that kit product values are accurately calculated, preventing discrepancies between the purchase order and the resulting inventory valuation. This improves the reliability of kit product costing.
Original PR description
### Steps to reproduce: - Create a kit product with 6 bom lines (with a `cost_share` of `0.0%`) - Create + confirm a purchase order for 1 unit of the kit product at 60 - Validate the delivery #### >…
### Steps to reproduce: - Create a kit product with 6 bom lines (with a `cost_share` of `0.0%`) - Create + confirm a purchase order for 1 unit of the kit product at 60 - Validate the delivery #### > 6 layers were created with values 9.99, 10, 10, 10, 10 and 10 There are two issues with purchased kit valuation addressed in this PR: ### Issue 1: Since 8c199f7783527735b35c9fbda334cbdcd55a004f, the product price unit is not supposed to be rounded anymore. However, kit products rely on the rounded `cost_share` field of the `mrp.bom.line` to determine which part of the price of the kit product is handled by which component: https://github.com/odoo/odoo/blob/591102ff37fef1f0b9a946fee3f9d85789653e65/addons/mrp/models/stock_move.py#L245-L246 https://github.com/odoo/odoo/blob/591102ff37fef1f0b9a946fee3f9d85789653e65/addons/purchase_mrp/models/stock_move.py#L28 https://github.com/odoo/odoo/blob/591102ff37fef1f0b9a946fee3f9d85789653e65/addons/purchase_mrp/models/stock_move.py#L38 This leads to inevitable rounding issues where `60/6` does not match `10`: https://github.com/odoo/odoo/blob/591102ff37fef1f0b9a946fee3f9d85789653e65/addons/purchase_mrp/tests/test_purchase_mrp_flow.py#L1273-L1275 simply because 1/6 is represented as `16.67%` and not by `16.66666666666666%`. However, values such as 1/6 can be obtained if you do not set any `cost_share`, since the kit explosion will equidistribute its cost share: https://github.com/odoo/odoo/blob/591102ff37fef1f0b9a946fee3f9d85789653e65/addons/purchase_mrp/models/mrp_bom.py#L42-L48 ### Fix of this issue: We set the digits to `False` for stability reason as the columns have been initiallised as "numeric" values and needs to stay numeric: https://github.com/odoo/odoo/blob/b007b0a4f7e56f6dc44df3154e13745c9981eae3/odoo/fields.py#L1627-L1650 Note that when the digit is Falsy on the field, the field value is formatted to the second digit by the front end: https://github.com/odoo/odoo/blob/3542c542eac5b204e69a8dd6ae1907cfcef60af3/addons/web/static/src/views/fields/float/float_field.js#L58-L76 https://github.com/odoo/odoo/blob/12e453302a950df4d9ee45954f54bdf610888eda/addons/web/static/src/core/utils/numbers.js#L214-L227 In particular, when we create the bom and set the `cost_share`, all possible values will be rounded to the second decimal just as before. This change will therefore only alter the rounding behavior in the DB for equidistributed values such as `16.66666666666666%`. ### Issue 2: While the value of the kit product is exploded and distributed among components, the values of each individual `stock.valuation.layer` are themselves rounded before creation based on the company currency: https://github.com/odoo/odoo/blob/4188436a9e800b062bf9f3b0055cad86acc47e19/addons/stock_account/models/product.py#L240-L255 https://github.com/odoo/odoo/blob/4188436a9e800b062bf9f3b0055cad86acc47e19/addons/stock_account/models/stock_valuation_layer.py#L30 Now, this is problematic since the sum of the values of the layers is expected to match the total value of the purchase order line (that is, the non-rounded value of the components of the purchased kit). ### Fix of this issue: We compute and distribute the rounding error among layers corresponding to the purchased kit product before creation (since layer values are not expected to be modified afterwards), based on the non-rounded computation, since this value should now be exact (as the unit cost is not rounded anymore). opw-5085457 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#252460 Forward-Port-Of: odoo/odoo#252034