Friday, April 17, 2026
17 changes · 18.0
New functionality added to Odoo
This update adds the ability to generate SAT trial balance reports in a supplementary format, aligning with Mexican tax authority requirements. The changes ensure correct formatting, including specific file naming conventions and data attributes, to meet SAT specifications and facilitate accurate tax reporting. This supports compliance with Mexican tax regulations.
Original PR description
Adds support for generating SAT (Mexican tax authority) trial balance reports in supplementary (complementary) format, as required by SAT specifications. Changes: - Add default value for submit_type…
Adds support for generating SAT (Mexican tax authority) trial balance reports in supplementary (complementary) format, as required by SAT specifications. Changes: - Add default value for submit_type in SAT XML generation to fix tests that call the method directly without going through the wizard - Add new tests for normal (TipoEnvio=N) and supplementary (TipoEnvio=C) formats - Verify that FechaModBal attribute is correctly included only for supplementary reports - Verify that filenames correctly use BN (normal) or BC (complementary) suffixes The SAT technical specification requires: - TipoEnvio="C" (complementary) for supplementary balance sheets - FechaModBal attribute (date of last accounting modification) when tipo is C - File naming convention: RFC+Year+Month+BN (normal) or BC (complementary) SAT technical specification: https://wwwmat.sat.gob.mx/cs/Satellite?blobcol=urldata&blobkey=id&blobtable=MungoBlobs&blobwhere=1461173762094&ssbinary=true Ticket: https://www.odoo.com/es_ES/my/tasks/6025590 @moduon MT-14181
Resolved issues and error corrections
This update resolves a bug that prevented bill matching from working correctly when a vendor bill line lacked a product definition. The fix ensures that quantity calculations are handled appropriately, avoiding errors and improving the reliability of the bill matching process. This change ensures accurate record keeping and prevents disruptions to the purchasing workflow.
Original PR description
Steps to reproduce: - Import or create a vendor bill with a line that has a unit of measure but no product. - Open the bill and go for the bill matching. Issue: Bill lines without a product have product_uom_id set to False. During bill matching, _compute_product_uom_qty calls _compute_quantity without checking this value, which raises a UserError due to missing or invalid UoM configuration. Solution: Add a check to ensure _compute_quantity is only called when product_uom_id is set. Otherwise, fall back to the original line quantity to avoid conversion errors. opw - 6109513
This update optimizes the workcenter planning process by streamlining how it identifies available time slots. By using a more efficient method to detect conflicting intervals, the system now finds available slots significantly faster, especially for short scheduling durations. This reduces processing time and improves overall planning efficiency.
Original PR description
### Description of the issue/feature this PR addresses: The workcenter planning logic in _get_first_available_slot can become inefficient when searching for very short available slots. The method…
### Description of the issue/feature this PR addresses: The workcenter planning logic in _get_first_available_slot can become inefficient when searching for very short available slots. The method repeatedly builds small candidate time windows and checks them against existing workorder and leave intervals, potentially iterating many times before finding a free slot. This leads to unnecessary computational overhead in scenarios where a large number of busy intervals exist and the remaining duration to schedule is small. ### Current behavior before PR: The planner checks for conflicts by computing the intersection between the candidate window and the busy intervals. When a conflict is detected, the candidate window is shifted forward (or backward) to the end (or start) of the intersection, and the process is repeated until a free slot is found. This approach requires repeatedly performing full interval merge operations, which becomes disproportionately expensive when the candidate windows are very small and the loop iterates many times. ### Desired behavior after PR is merged: The planner uses a new Intervals.conflicting() helper to retrieve the entire busy interval that overlaps with the candidate window. Instead of advancing only to the end of the intersection slice, the planner can jump directly to the end (or start) of the full busy interval. This avoids repeated full-merge work, reduces the number of iterations needed to find a valid slot, and prevents pathological performance slowdowns in short-duration planning scenarios. ### Benchmarks Profiling _get_first_available_slot with different workorder durations. Database has multiple months that are fully booked. Speedup is more dramatic with shorter durations but there is at minimum minor improvements across the board. | Work Order Duration | Before | After | | --- |---|---| | 1sec | ~2.5min | <1sec | | 1min | ~2sec | <1sec | ### References opw-5437256 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update corrects a rounding issue in the generation of Peppol invoices, ensuring accurate calculations for line amounts. Previously, the system rounded unit prices, leading to validation errors. This fix ensures invoices comply with Peppol standards and avoids 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** 1. Create an invoice with unit price of 0.01110515964, and quantity of 278362.5. 2. 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
This update fixes a security issue where unauthorized users could access asset information linked to invoices. Now, only users in specific accounting groups (read-only or invoice-related) can view assets, preventing potential data access problems. This ensures data integrity and protects sensitive financial information.
Original PR description
Only groups `account.group_account_readonly`, `account.group_account_invoice` or higher have access to model `account.asset`, therefore if an user goes to see an invoice with assets and they are not on either group, they will receive an error and won't be able to access said invoice. How to reproduce: - Create a vendor bill - Create an account.asset and link it to said account.move - Go to the form view with an user that it's on group "Purchase: User" for example --> They get a traceback --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/enterprise#113523 Forward-Port-Of: odoo/enterprise#112890
This update fixes a calculation error in the timesheet grid's monthly view for flexible schedules. Previously, it incorrectly displayed a deficit, even with fully completed workdays. The fix ensures accurate required hour calculations by adjusting the formula to account for standard working days.
Original PR description
When using a flexible working schedule, the month view for timesheets shows a deficit even when all working days are fully completed. ### **Steps to reproduce:** 1) Install Timesheet Grid. 2) Assign…
When using a flexible working schedule, the month view for timesheets shows a deficit even when all working days are fully completed. ### **Steps to reproduce:** 1) Install Timesheet Grid. 2) Assign a flexible working schedule (40 hrs/week, 8 hrs/day) to an admin. 3) Enter timesheets with 8 hours per weekday for a full month (except Feb). 4) Open the timesheets grid month view. Note: current formula correctly calculates for feb month **((40/7)** * **28) = 160** ### **Observed behavior:** The weekly view shows correct totals, but the monthly view displays a deficit (176 h with -1:08 h), despite all working days being fully completed. <img width="1920" height="366" alt="image" src="https://github.com/user-attachments/assets/df98c3e0-ee89-455d-86c6-7941ba0cb7a8" /> ### **Expected behavior:** The monthly view should correctly calculate the required hours i.e 176 h <img width="1909" height="357" alt="image" src="https://github.com/user-attachments/assets/c082953a-62ad-4096-8774-76d9ff7b3b25" /> ### **Root Cause:** The method [_count_daily_working_hours](https://github.com/odoo/enterprise/blob/3cf76350794078f807fc07cd0b42d0bb0315ccab/timesheet_grid/models/hr_employee.py#L82) calculated `full_time_required_hours` for a period by dividing the weekly required hours by 7 (including weekends) and multiplying by the total calendar days in the period at [1]. This gave incorrect required hours for months that have extra weekend days. [1]- https://github.com/odoo/enterprise/blob/3cf76350794078f807fc07cd0b42d0bb0315ccab/timesheet_grid/models/hr_employee.py#L115 ### **Fix:** Update the computation to divide the weekly `full_time_required_hours` by `5` (standard working days) and multiply by the actual number of weekdays in the requested period. **Example calculation for the month March 2026:** | | Formula | Values | Calculation | Result | |--------|--------|--------|--------|--------| | Before Fix | round(full_time_required_hours / 7 * (delta.days + 1), 2) | full_time_required_hours = 40, delta.days + 1 = 31 | round(40 / 7 * 31, 2) | **177.14 h** | | After Fix | round((full_time_required_hours / 5) * working_days_in_period, 2) | full_time_required_hours = 40, working_days_in_period = 22 | round((40 / 5) * 22, 2) | **176.00 h** | **opw-5966769**
This update fixes an issue where bank statement creation didn't consistently use the specified journal type. Now, when a journal type is set during bank statement creation, the system correctly assigns the appropriate journal, ensuring accurate financial record-keeping. This improves the reliability of bank statement processing.
Original PR description
When a account.bank.statement is created via a action where the journal_type is set in the context this value isn't used to compute the right journal for the account.bank.statement.line/account.move --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves an issue where invoices could fail to process correctly with the Peppol system. The fix involved a temporary workaround to prevent a specific error during invoice generation, ensuring invoices can now be properly tracked and status updates retrieved. This improves the reliability of Peppol invoice processing.
Original PR description
1. Send an invoice that will return an error when send to IAP 2. Send the invoice 3. Click "Fetch Peppol Invoice status" on the dashboard 4. There is a traceback (see the bottom of this message) To…
1. Send an invoice that will return an error when send to IAP
2. Send the invoice
3. Click "Fetch Peppol Invoice status" on the dashboard
4. There is a traceback (see the bottom of this message)
To create an invoice that will return an error I locally removed the EndpointID from the UBL generation (and the constraint to check that during the genreation).
```
Traceback (most recent call last):
File "/home/odoo/src/odoo/odoo/http.py", line 2167, in _transactioning
return service_model.retrying(func, env=self.env)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/odoo/service/model.py", line 157, in retrying
result = func()
^^^^^^
File "/home/odoo/src/odoo/odoo/http.py", line 2134, in _serve_ir_http
response = self.dispatcher.dispatch(rule.endpoint, args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/odoo/http.py", line 2382, in dispatch
result = self.request.registry['ir.http']._dispatch(endpoint)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/odoo/addons/base/models/ir_http.py", line 333, in _dispatch
result = endpoint(**request.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/odoo/http.py", line 754, in route_wrapper
result = endpoint(self, *args, **params_ok)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/addons/web/controllers/dataset.py", line 42, in call_button
action = call_kw(request.env[model], method, args, kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/odoo/api.py", line 535, in call_kw
result = getattr(recs, name)(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/addons/account_peppol/models/account_journal.py", line 34, in peppol_get_message_status
edi_users._peppol_get_message_status()
File "/home/odoo/src/odoo/addons/account_peppol/models/account_edi_proxy_user.py", line 287, in _peppol_get_message_status
processed_message_uuids = edi_user._peppol_process_messages_status(messages_to_process, uuid_to_record)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/addons/account_peppol_response/models/account_edi_proxy_user.py", line 180, in _peppol_process_messages_status
peppol_response = uuid_to_record[uuid]
^^^^^^^^^^^^^^^^^^^^^^^^
KeyError: 'document_type'
```
task-NoneThis update allows administrators to control whether subscription users are automatically reset. Previously, this process was fixed, making it difficult to manage. By providing greater control, this change improves flexibility and operational efficiency for subscription-based sales.
Original PR description
After this commit, the auto resetting of subscription user is overridable. Doing business logic in CRUD methods makes them impossible to bypass, by encapsulating the logic in another method, it would be easily overridable.
This update resolves an issue where backorder returns weren't properly associated with the original delivery. The fix ensures that when a backorder is returned, it's correctly linked to the associated delivery, improving the accuracy of inventory tracking. This prevents discrepancies and simplifies the return process.
Original PR description
### Steps to reproduce: - Create, confirm and validate a delivery for 2 units of a product A - Click Return > Return All - Validate the return for 1 unit and backorder #### > The backorder does not belong to the return list of the delivery ### Cause of the issue: Backorder pickings are created by copying the picking to backorder: https://github.com/odoo/odoo/blob/9ad995ff6b59a6a2fdfbbd6cf385fe27568dd3ea/addons/stock/models/stock_picking.py#L1580-L1593 https://github.com/odoo/odoo/blob/9ad995ff6b59a6a2fdfbbd6cf385fe27568dd3ea/addons/stock/models/stock_picking.py#L1571-L1578 However, the `return_id` is a `copy=False` field that is not manully set during this copy process: https://github.com/odoo/odoo/blob/9ad995ff6b59a6a2fdfbbd6cf385fe27568dd3ea/addons/stock/models/stock_picking.py#L558 opw-6111544 --- 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 Italian tax reporting module was incorrectly removing parts of VAT numbers when generating XML invoices. The fix ensures that VAT numbers, like those used in Spain, are accurately exported to the tax agency, preventing reporting errors. This improves data accuracy and compliance.
Original PR description
**Steps to reproduce:** * Install `l10n_it_edi` module. * Create a partner with country **Spain** and VAT `A95758389`. * Create an invoice and send it to the Tax Agency, and download XML. **Observed behavior:** * The exported XML contains `5758389` in <IdCodice> instead of `A95758389` — the first two characters of the VAT are silently dropped. **Cause:** * In `_l10n_it_edi_get_values`, the EU branch that strips the country-code prefix used a bare `else` after the `isdecimal()` check, unconditionally removing the first two characters of any VAT that does not start with two digits. Spanish NIFs like `A95758389` start with `A9` (letter + digit), which is not a country-code prefix but was treated as one, corrupting the value. **Fix:** * Remove country prefix from normalized VAT by `removeprefix(normalized_country)` Instead of removing the first two characters. It will ensure that only the country prefix will be removed. opw-6089198 Forward-Port-Of: odoo/odoo#258626
This update resolves an issue where users without the necessary permissions could still access the Documents app. The fix restricts access to the Documents app icon and dashboard to only administrator users, ensuring data security and proper user access control. This prevents unauthorized access to sensitive documents.
Original PR description
Steps to reproduce: =================== - Login as admin and create another user. - Download 'Documents' app. - Revoke user of 'Documents' app access . - Login as the other user. - The 'Documents' app is showing even-though the user shouldn't have access to it. Cause of Issue: ====== - 'Documents' icon and dashboard have 'base.group_user' access. https://github.com/odoo/enterprise/blob/3e8c4e90b07bd7ddc034c9c6df114a66753e2ef3/documents/views/documents_menu_views.xml#L4-L12 opw-5914433
This update resolves an issue where the custom declaration field wasn't automatically filled for international World Express Pro shipments through the BPost module. Now, the necessary information is correctly populated, ensuring accurate customs documentation and smoother international deliveries. This improves compliance and reduces potential delays.
Original PR description
Before this commit, the bpost module was not filling the custom declaration in case of international shipping (World Express Pro) After this commit, the section is filled opw-4932970
This update enhances the accuracy of tax calculations for Odoo's Argentina localization (l10n_ar). By modernizing the tax calculation methods, the system now aligns with best practices and prepares for potential future adjustments to Argentine tax regulations. This ensures more reliable financial reporting for users in Argentina.
Original PR description
This commit refactors the tax amount calculations on the `_get_vat` and `_l10n_ar_get_amounts` method so that it uses the tax computation engine helpers properly, to prepare for any future fixes done on how Argentina tax calculations differs from all other localizations. This replaces all move line queries with the proper `base_line` calculation, with the proper aggregating methods. related-enterprise-PR: https://github.com/odoo/enterprise/pull/92639 task-4891206
This update fixes inaccuracies in how tax amounts are calculated within the l10n_ar_edi module. By utilizing the Odoo's tax computation engine, the changes ensure more precise and reliable tax calculations across various sales and invoice scenarios. This improves financial reporting accuracy.
Original PR description
- Rewrite all tax amounts calculations on `_get_tributes` and `_get_line_details` to properly use the tax computation engine helpers (`base_line`, and aggregating methods) - Ensure that all final amounts from the calculation are formatted with `float_repr` with appropriate precision. related-community-PR: https://github.com/odoo/odoo/pull/223393 task-4891206
This update ensures that subcontracted items always display a cost in the BOM report, even when an exact supplier match isn't found. Previously, the cost would be hidden if no supplier met the quantity requirements. This change guarantees a complete and accurate BOM cost structure, improving reporting and decision-making.
Original PR description
Description of the issue/feature this PR addresses: When visualizing the structure of a BOM with subcontracted components, the subcontracting cost is omitted if no supplierinfo record exists with a…
Description of the issue/feature this PR addresses: When visualizing the structure of a BOM with subcontracted components, the subcontracting cost is omitted if no supplierinfo record exists with a `min_qty` less than or equal to the requested quantity. This leads to an inconsistent experience compared to regular components, which still show a price by selecting the closest lower `min_qty`. For subcontracted components, if the requested quantity does not match any valid `supplierinfo`, the cost line silently disappears from the report. Current behavior before PR: The subcontracting cost is not shown in the BOM cost structure if no `supplierinfo` matches the requested quantity (i.e., `min_qty > quantity`). Desired behavior after PR is merged: If no matching supplier is found for the requested quantity, the fallback logic uses any available supplierinfo (as already done in `_format_route_info`), ensuring a price is shown for subcontracted lines. This guarantees the BOM cost structure always includes the subcontracting cost, making the report complete and coherent. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update fixes a problem where canceling a transaction on a point-of-sale terminal (without initiating the cancellation process within the POS system) would cause errors. The change ensures the system correctly handles cancellation requests, regardless of where they originate, improving transaction reliability. This prevents data inconsistencies and potential disruptions to sales.
Original PR description
Currently if you cancel a transaction on the terminal (not in pos) this lead to a traceback TypeError: this.cancel_resolve is not a function at Proxy._waitingPayment (https://varoconsult-be-itve.odoo.com/web/assets/4473ba8/point_of_sale.assets_prod.min.js:16764:298) at Proxy._onValueChange (https://varoconsult-be-itve.odoo.com/web/assets/4473ba8/point_of_sale.assets_prod.min.js:16758:184) at Proxy._onSuccess (https://varoconsult-be-itve.odoo.com/web/assets/4473ba8/point_of_sale.assets_prod.min.js:16674:190) at Proxy._onSuccess (https://varoconsult-be-itve.odoo.com/web/assets/4473ba8/point_of_sale.assets_prod.min.js:16778:1228) at https://varoconsult-be-itve.odoo.com/web/assets/4473ba8/point_of_sale.assets_prod.min.js:16672:417 This PR fixes the issue to ensure the scenario when the pos didnt ask for cancellation is managed