Wednesday, September 2, 2026
20 changes · saas-19.4
Enhancements to existing features
Timesheet timers now suggest tasks based only on recent activity from the past month, instead of pulling in tasks last used a long time ago. This helps employees log time faster and reduces mistakes caused by outdated task suggestions.
Original PR description
When selecting a project in the timesheet timer, the prefilled task could be one the user last logged time on years ago, which is no longer relevant. The prefill now only considers timesheets from the past month and follows the user's most recent one: if that timesheet has no task, none is prefilled rather than reaching further back. task-6485260 Forward-Port-Of: odoo/enterprise#128738
This change helps Odoo handle many simultaneous real-time server tasks without running into connection pool limits. It reduces the risk of service interruptions or errors when usage spikes, especially for live communication features such as bus/websocket traffic.
Original PR description
make gevent connection pool non-blocking to avoid 'The Connection Pool Is Full' error when too many coroutines are borrowing connections in gevent server. https://github.com/odoo/iap-apps/pull/1827 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
The timesheet assistant now favors recent work patterns over old historical matches, so suggested projects and tasks better reflect current assignments. It also keeps stored suggestion data leaner and improves detection rules for Odoo.sh staging-style databases.
Original PR description
Previously, the timesheet assistant's local configuration matched activities to projects/tasks using a strict historical tally. A match made 6 months ago carried the exact same mathematical weight as a match made today. This caused old habits to stubbornly override new assignments. This commit introduces an exponential time-decay algorithm to the frequency computation: - Matches are now weighted based on their `datetime` stamp. - The weight drops by 50% every 5 days (half-life algorithm). - Recent timesheet entries quickly accumulate enough fractional votes to surpass the decayed votes of older, outdated projects. in this commit i updated the matching of local rules to be case sensitive for better matching (eg. "Meeting with client" is the same as "meeting with client") Task: 6267713 Forward-Port-Of: odoo/enterprise#129631 Forward-Port-Of: odoo/enterprise#124669
Businesses in Ecuador can now record their third-party billing software provider's RUC in invoicing settings. The value is automatically included on electronic documents and printed RIDE reports, including delivery guides, helping comply with SRI reporting requirements.
Original PR description
Purpose: SRI Resolution requires taxpayers using 3rd-party billing software in Ecuador to report the software provider's RUC on all electronic documents and printed representations (RIDE). A new system parameter is introduced and displayed in Invoicing > Setting > Ecuadorian Localization > Electronic Invoicing, so users can add their software provider's RUC. This value will be automatically sent to the EDI and displayed on the report. task-6432810 Forward-Port-Of: odoo/enterprise#129456
Resolved issues and error corrections
This update re-enables many previously skipped valuation checks across inventory, purchasing, manufacturing, point of sale, repair, and project accounting. While mostly internal quality work, it also fixes issues found during testing, including incorrect costing for subcontracted/dropshipped kits and analytic accounting exclusions for re-invoiced products.
Original PR description
*: stock_landed_costs, purchase_{stock,mrp}, stock_dropshipping, sale_mrp, pos_mrp, repair, mrp_landed_costs, mrp_subcontracting_{dropshipping,landed_costs}, point_of_sale, {project_,}stock_account…
*: stock_landed_costs, purchase_{stock,mrp}, stock_dropshipping, sale_mrp, pos_mrp, repair, mrp_landed_costs, mrp_subcontracting_{dropshipping,landed_costs}, point_of_sale, {project_,}stock_account
Adapts the test skipped to fast merge the valuation refactoring made in https://github.com/odoo/odoo/commit/08b62a4bbcc6f9a391b2cc00a621ef4c76100229.
<img width="482" height="297" alt="table" src="https://github.com/user-attachments/assets/ba57f350-2a9e-4a51-990d-fabe14f5a56a" />
(*) Includes the one sale_project_stock_account test re-enabled through the TestAnalytics subclass.
It is organised as one commit per module. Two of the re-enabled tests surfaced genuine bugs in the new valuation model; those commits also carry the related fixes: purchase_mrp, project_stock_account Every other commit changes tests-only.
Only one skipped test remains: point_of_sale TestUi.test_05_ticket_screen, a browser tour with no stock-valuation content that was swept into the mass skip by mistake and fails for an unrelated reason (it is left to a separate point-of-sale tour investigation).
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#278698
Forward-Port-Of: odoo/odoo#275246This fixes incorrect occupation calculations used in Belgian payroll holiday attestations. It helps ensure employee holiday documents and related payroll validations reflect accurate employment information.
Original PR description
This commit fixes the occupation computations which were wrong. Forward-Port-Of: odoo/enterprise#129837
The scheduled process for retrieving Turkish Nilvera e-Dispatch purchase PDFs no longer fails when checking for attached XML files. This helps ensure purchase dispatch documents can be collected automatically without manual intervention.
Original PR description
## Steps to Reproduce: - Install `l10n_tr_nilvera_edispatch` module. - Run "**Nilvera: retrieve e-Dispatch purchase PDFs**" Scheduled Action. ## Error: ``` ValueError: Binary field stored in…
## Steps to Reproduce:
- Install `l10n_tr_nilvera_edispatch` module.
- Run "**Nilvera: retrieve e-Dispatch purchase PDFs**" Scheduled Action.
## Error:
```
ValueError: Binary field stored in attachment, accepts only existence check; skipping domain in condition ('l10n_tr_nilvera_edispatch_xml_file', 'in', OrderedSet([True]))
```
## Cause:
After commit https://github.com/odoo/odoo/commit/3641f23a9b4cd401444ca3371873d8123922f7b1, The condition operators `=` and `!=` are normalized to `in` and `not in` respectively.
As a result:
```
('field', '=', True) becomes ('field', 'in', OrderedSet([True])) and
('field', '=', False) becomes ('field', 'in', OrderedSet([False]))
```
After this normalization, the domain optimizer `_optimize_type_binary_attachment()` is applied - [1].
For attachment-type binary fields, it only allows `in/not in` operators, and a value should be `{False}`.
Therefore, the condition (converted) `('l10n_tr_nilvera_edispatch_xml_file', 'in', [True])` is rejected.
Binary fields with `attachment=True` are not stored as a boolean value. When converting their domain to SQL, `condition_to_sql()` - [2] handles them as an EXISTS check on `ir.attachment` to determine whether an attachment exists.
## Fix:
This commit replaces the `= True` in the condition with `!= False`.
[1] - https://github.com/odoo/odoo/blob/762fd7c0b65e8f8e3eb59eb8a57b1394cb176339/odoo/orm/domains.py#L1782-L1784
[2] - https://github.com/odoo/odoo/blob/762fd7c0b65e8f8e3eb59eb8a57b1394cb176339/odoo/orm/fields_binary.py#L217-L218
sentry-7627832395Checkout now prevents carts from getting stuck when pricing rules make a product free but zero-priced sales are not allowed. Customers are sent back to the cart with a clear warning instead of experiencing a timeout during payment.
Original PR description
When 'Prevent Sale of Zero Priced Product' is enabled and a country-group pricelist prices a product at 0 once the customer's country becomes known during checkout, the cart total becomes 0. The 'free order' branch then validated the order at the payment step, which could hang and time out for a cart that is not actually sellable. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285739 Forward-Port-Of: odoo/odoo#284959
Vendor bills created from incoming emails will no longer use the stored original email copy as the main invoice attachment. This ensures the actual PDF or image extracted from the email is shown for preview, avoiding broken or misleading invoice previews.
Original PR description
When an incoming mail server has the "Keep Original" option enabled, a copy of every incoming mail is stored as original_email.eml. Because it is not a document of the invoice, the system unattaches…
When an incoming mail server has the "Keep Original" option enabled, a copy of every incoming mail is stored as original_email.eml. Because it is not a document of the invoice, the system unattaches it, however it may still be used as main attachment in case no other PDF or image was attached to the message. Steps to reproduce: - Configure an incoming mail server with "Keep Original" enabled, using an alias pointing to a vendor bill journal. - Send a mail to that alias containing an xml embedding a PDF. - Open that bill Issue: The invoice's main attachment points to the .eml file. This occurs because it is set before the PDF is extracted from the xml. Then, when import extracts the PDF, it is added as attachment on the invoice, but we already have a main attachment that won't be overwritten. However, once a pdf or image is added as attachment, the system will show the (broken) preview. opw-6431726 Forward-Port-Of: odoo/odoo#285409 Forward-Port-Of: odoo/odoo#280318
This fix ensures Point of Sale configurations keep the required default sale and down payment products before a new session can start. It prevents blank screens and checkout interruptions when staff select products or process sales orders with down payments.
Original PR description
Step to reproduce: - install `pos_sale` - create a pos and go to settings - remove product from `Default Sale Product` - start pos and select a product Observation: - we will get a blank screen and…
Step to reproduce:
- install `pos_sale`
- create a pos and go to settings
- remove product from `Default Sale Product`
- start pos and select a product
Observation:
- we will get a blank screen and error in browser console
```
TypeError: Cannot read properties of undefined (reading 'id')
at get orderDisplayProductName (point_of_sale.assets_prod.min.js:20914:497)
at get orderDisplayProductName (point_of_sale.assets_prod.min.js:27593:14)
```
- similar case when we de-select downpayment product and load a SO
with downpayment
Cause:
- `default_product_id` was introduce in commit[1] which is necessary for
description first order line
- if we remove this field, for pos config, `this.config.default_product_id`
is undefined, and accessing its id raises error
[1] https://github.com/odoo/odoo/commit/0ce605f8db9aa9901bf6b14c4888e5bcc0734401
Fix:
- as in stable, we cannot make a field "required", we use python constraint
and hook `_check_before_creating_new_session` to ensure every session/config
has these products available with only exception to those session which are
already running
- for master, we plan to make the field required.
opw-6458117
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThis fix prevents French e-invoicing status updates from failing when the external service returns a response that cannot be tracked. It avoids creating invalid pending records, helping scheduled invoice status processing continue reliably.
Original PR description
Steps to reproduce: - Install `l10n_fr_pdp` and `l10n_be` module - Activate `French e-invoicing` (you need to put your DB in test mode) (i.e: `account_peppol.edi.mode = 'test'` in system parameter)…
Steps to reproduce:
- Install `l10n_fr_pdp` and `l10n_be` module
- Activate `French e-invoicing` (you need to put your DB in test mode)
(i.e: `account_peppol.edi.mode = 'test'` in system parameter) Refer this Documentation https://www.odoo.com/documentation/19.0/applications/finance/fiscal_localizations/france.html?highlight=e%20invoicing#localizations-france-e-invoicing-fac-elec-config
- Create a Invoice and Sent with `E-invoicing`
- Run `PEPPOL: retrieve new documents` Cron
- In Invoice Other Info > `E-Invoicing Status` should be in `Done` state
- Now Vendor Bill is created for that invoice > Cancel that bill with reason > Check `E-Invoicing Status` response for bill(one response will be without UUID)
- Go to schedule actions > `PEPPOL: update message status`
- Run it and get the traceback: `KeyError: 'false'`
Issue:
When sending a lifecycle response to the French PDP, `_pdp_send_response` calls the `/api/pdp/1/send_response` endpoint and expects IAP to return a `message_uuid` for each response.
However, IAP return a response without a message UUID, for example: ` {'messages': [{'message_uuid': False}]}` `_pdp_send_response` currently assumes that every returned message has a valid UUID and creates an `account.peppol.response` with:
```
'peppol_message_uuid': False
'peppol_state': 'processing'
```
This leaves an `account.peppol.response` in `processing` state without a UUID that can be used to track it.
During the next execution of `_cron_peppol_get_message_status`, `_peppol_get_message_status` retrieves this response through `_peppol_get_documents_for_status` and builds `uuid_to_record` using `peppol_message_uuid` as the key. The resulting mapping contains the Python value `False` as a key.
The cron then calls the PDP `1/get_document` endpoint with this invalid UUID. IAP returns it as the string `'false'`, which is passed to `_peppol_process_messages_status`. The French PDP implementation tries to retrieve the corresponding record with: `uuid_to_record[uid]`
Since the mapping contains `False` while `uid` is `'false'`, this raises: `KeyError: 'false'`
This failure prevents the status cron from completing the processing of the messages.
Solution:
Avoid creating the `account.peppol.response` when IAP does not return a `message_uuid`. A response without a UUID cannot be tracked through the PDP status flow, so creating it in `processing` state only leaves an
invalid record that will later cause the status processing to fail.
opw-6453133
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#281691Factur-X e-invoices received through Peppol are now correctly inspected by extracting the embedded XML before import. This prevents missing or empty invoice records and improves handling of self-billed documents in the French PDP flow.
Original PR description
When importing new documents from Peppol into the database, we determine whether they are self-billed by checking a Type Code in the XML file. Factur-X is an hybrid format where the XML is embedded inside a PDF. Currently, we are not extracting the XML before searching for that Type Code, and it leads to an error that prevents the document from being imported correctly: - V17, V18: An empty invoice is created and linked with the attachment. - V19+: Only the attachment is created. Additionnaly, we only check for InvoiceTypeCode or CreditNoteTypeCode, but the CII XML format embedded inside the hybrid Factur-X format use TypeCode instead. This PR aims at fixing both these issues. Ticket: opw-6417682 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285513 Forward-Port-Of: odoo/odoo#280714
Users can now safely discard changes after reordering very long lists, such as quotation order lines spread across multiple pages. This prevents an error that interrupted the workflow and forced users to recover from a failed discard action.
Original PR description
**Steps to reproduce:** - Create a quotation - Add order lines until reaching 200 (duplicating helps), save and ensure that the pager appeared (1-200/201) - Drag one of the lines with the handle to…
**Steps to reproduce:** - Create a quotation - Add order lines until reaching 200 (duplicating helps), save and ensure that the pager appeared (1-200/201) - Drag one of the lines with the handle to reorder them - Discard all changes (X shaped button) You will have an evaluation error **Behavior:** When loading a list of records exceeding the limit, only parts of the records are saved in `_cache`. When triggering a reordering of said list, all records need to be loaded including the ones on other pages: https://github.com/odoo/odoo/blob/d4eff7b14d37a9b59c95d304542a5a12629bc90b/addons/web/static/src/model/relational_model/static_list.js#L1139-L1149 `_getResIdsToLoad()` gets all Ids missing from the cache, these are then passed through `._createRecordDatapoint` and will then be stored in `_cache`. The issue is that the Datapoints are getting created with only `activeFields` as data, which in our case are `id` and `sequence` When discarding the changes `._checkValidity()`is called on each Datapoint: https://github.com/odoo/odoo/blob/d4eff7b14d37a9b59c95d304542a5a12629bc90b/addons/web/static/src/model/relational_model/record.js#L423-L429 And then `._isInvisible()` is called. This is where the issue happens, since only `sequence` and `id` are stored, when we try evaluate `combo_item_id`, which is the condition to see if sequence is invisible, `combo_item_id` is not found and we get an Evaluation Error. This commit prevents going into `._checkValidity()` by adding `this.isInEdition` to the check leading to it, requiring that the record is in 'edit' mode which is not the case for records created with `_createRecordDatapoint()` opw-6399024 Forward-Port-Of: odoo/odoo#281018
The timesheet screen now blocks repeated save or add actions while the first request is still processing. This prevents duplicate timesheets or duplicate-looking entries from appearing when users click quickly on slow connections.
Original PR description
Steps to reproduce: 1. Open the ActivityWatch timesheets view. 2. Throttle the network speed to simulate a slow connection. 3. Rapidly click "Add" on an ActivityWatch suggestion. 4. Click 'New', fill in the details, and rapidly click "Create" (or mash Ctrl+Enter). Issue: - Suggestion List: Multiple duplicate timesheets are created in the database. - Creation Form: The newly created timesheet appears multiple times in the UI list on the left side, even though only one might be created in the database. Cause: Both the `onTake` (ActivityWatch list) and `onSave` (Timesheet form) methods are asynchronous. Without a concurrency lock, rapid user interactions trigger these methods multiple times before the initial network request finishes, causing parallel ORM calls and duplicate UI array pushes. task-6462515 Forward-Port-Of: odoo/enterprise#130061 Forward-Port-Of: odoo/enterprise#127806
Incoming VoIP calls that time out after ringing are now recorded as missed calls instead of remaining in a confusing in-progress state. Users will see a clear "Call missed" message, making call history more accurate and easier to understand.
Original PR description
Steps to reproduce: - Call your softphone with your smartphone. - Let the smartphone ring forever. => At some point, you reach the voicemail and the softphone stops ringing but: - The softphone…
Steps to reproduce: - Call your softphone with your smartphone. - Let the smartphone ring forever. => At some point, you reach the voicemail and the softphone stops ringing but: - The softphone displays a weird message with emojis. - The call record stays "Trying to call" (and might *display* "Ended unexpectedly" in 19.2). This commit fixes those two issues by showing a proper "Call missed" message and switching the call record status to "Missed". This is done in 19.2 and not before... because the behavior before is even more problematic: - 19.1: the softphone keeps ringing and crash if you try to answer, that was mostly fixed thanks to [1] and this commit takes profit of those big ameliorations to fix the issue here. - 19.0: you do not even reach voicemail (it stops without saying anything). This was apparently fixed as a side-effect of [2], which we do not consider worth even partially backporting as not critical. [1]: https://github.com/odoo/enterprise/commit/942f32316ab02d8c739fe7fdd5ec2bdde472a68e [2]: https://github.com/odoo/enterprise/commit/d24d7f3406ca47e7ac529d69957b0ad481d553bf task-6453500 Forward-Port-Of: odoo/enterprise#128731 Forward-Port-Of: odoo/enterprise#127075
This fix ensures that opening tickets from a Helpdesk Team reached through an email alias uses the correct team information. Business users can now navigate from aliases to related Helpdesk tickets without encountering an error screen.
Original PR description
### Steps to Reproduce: 1. In Debug mode, go to Aliases 2. Click on any active Alias, ex. customer-care 3. Click on "Open Parent Document" smart button 4. Click on "Tickets" smart button and observe…
### Steps to Reproduce: 1. In Debug mode, go to Aliases 2. Click on any active Alias, ex. customer-care 3. Click on "Open Parent Document" smart button 4. Click on "Tickets" smart button and observe error ### Description of the issue/feature this PR addresses: **Issue:** When navigating from an email alias to its parent document (e.g., a Helpdesk Team), the web client incorrectly retains the `active_id` and `active_model` of the alias in the context. **Solution:** We updated the `action_view_ticket` method in `helpdesk.team` to explicitly inject the correct `active_model` and `active_id` into the context before calling `_for_xml_id`. This overwrites the polluted Alias data before the window action is evaluated. ### Current behavior before PR: Clicking the "Tickets" smart button passes the old alias context into the action. This bad data flows into the ticket view, which attempts to look up a Helpdesk Team using the Alias's ID to generate the empty list help message, resulting in a `MissingError`. ### Desired behavior after PR: The Python action sanitizes the context at the source, ensuring that the XML action and subsequent view evaluations receive the correct Helpdesk Team ID. Ultimately, the view will load normally without crashing. opw-6395638 Forward-Port-Of: odoo/enterprise#129939 Forward-Port-Of: odoo/enterprise#125232
This fixes an issue where receipts involving subcontracted products could incorrectly treat reserved quantities as already selected, causing backorders to be created with the wrong quantities. The change helps ensure partial receipts from subcontractors are processed accurately and reduces inventory and fulfillment errors.
Original PR description
### Steps to reproduce: - Create a subcontracted product P1 - Create a storable product P2 - Buy 5 units of both products from your subcontractor - On the receipt set both moves quantity to 2 Units -…
### Steps to reproduce: - Create a subcontracted product P1 - Create a storable product P2 - Buy 5 units of both products from your subcontractor - On the receipt set both moves quantity to 2 Units - Validate the receipt and create a backorder #### > Only the subcontracted move has been kept on the receipt and a backorder was created for 3 units of P1 and 5 of P2. ### Cause of the issue: Setting the quantity of the subcontracted move will automatically record the quantities on the subcontracted MO: https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/mrp_subcontracting/models/stock_move.py#L83 https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/mrp_subcontracting/models/stock_move.py#L123 https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/mrp_subcontracting/models/mrp_production.py#L91 However, the `_update_finished_move` method adds and update the related subcontracted move lines marking them as *picked* to adapt the related reservation: https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/mrp_subcontracting/models/mrp_production.py#L118-L164 This is problematic since picking a move line will also pick the move: https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/stock/models/stock_move.py#L261-L267 And only picked moves are considered to be processed at picking validation. ### Note: The exact same issue had already been fixed in 17.0: db8b33ebb9fe23507bcba30b12741e4d688ae549 However, the fix had an issue concerning the barcode behavior as it removed the picked computation for subcontracted moves which made hybrid pickings such as the above one (with one subcontracted and one non-subcontracted move) impossible to process in the barcode app. As such, the fix and test where reverted in cf2d18c92bee55ef79db1a338e9baf12f258ee5b The present commit provides an alternative fix of the original issue keeping subcontracted moves unpicked by quantity changes without affecting the picked computation of subcontracted moves (e.g. adding a picked move line on a subcontracted move will still pick that move). Enterprise: https://github.com/odoo/enterprise/pull/123884 opw-6330584 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285614 Forward-Port-Of: odoo/odoo#275304
This fix makes Uruguay electronic invoicing use the exchange rate saved on the original invoice instead of recalculating it later. This prevents mismatches on credit notes when currency rates are updated after an invoice is posted.
Original PR description
18.0 introduced an `invoice_currency_rate` field, storing the currency rate used for each invoice. Currently `_l10n_uy_edi_get_used_rate` uses the `currency.convert()` method using the date and company of the invoice. This is vulnerable to inaccuracy if the currency rates are changed after the invoice posting. For example, if an invoiceis posted and the currency rates are updated, the invoice will use the old rate, while `_l10n_uy_edi_get_used_rate` will return the new one. In the case of the customer in the related ticket, this caused their credit note reference currency rate to mismatch with the one on the invoice. This PR changes the `currency.convert()` call to fetching and inverting the `invoice_currency_rate` field. This ensures the returned value will match the one used for the invoice. opw-6456867 Forward-Port-Of: odoo/enterprise#128190
Fixed an issue where expanding a newly created Calendar event opened a blank form instead of the event just created. This prevents users from accidentally creating duplicate events for the same time slot.
Original PR description
Problem: In Calendar, dragging a slot opens the quick create dialog. Typing a subject and clicking the expand button in the dialog header creates the event, but the form that opens is empty, and…
Problem: In Calendar, dragging a slot opens the quick create dialog. Typing a subject and clicking the expand button in the dialog header creates the event, but the form that opens is empty, and saving it creates a second event for the same slot. Cause: `FormViewDialog` stores the id of the record it saved in `currentResId`, which `onExpand` passes as `res_id`. `saveRecord` sets it only in the branch that runs when no `onRecordSave` prop is given. `AttendeeCalendarController` passes one since 30478fe855cd (odoo/odoo#239435), so `currentResId` stays false and the action opens a new record. Solution: Set `currentResId` in the shared branch of `saveRecord`. It is private to `FormViewDialog`, so a consumer passing `onRecordSave` cannot set it. Steps to reproduce: - Open Calendar. - Drag a slot in the week view to open the quick create dialog. - Type a meeting subject. - Click the expand button in the dialog header. - Observe that the form opens on a new record while the event is created. Ticket [link](https://www.odoo.com/odoo/project/49/tasks/6476930) opw-6476930 Forward-Port-Of: odoo/odoo#285899
This fix ensures Mexican CFDI invoice XML files use the customer's configured language for units of measure when invoices are sent in bulk. It prevents Spanish-language invoices from showing English unit labels, improving consistency and compliance in customer-facing documents.
Original PR description
### Issue before this commit: When a CFDI invoice was sent through a mass action (Send & Print executed by OdooBot), the unit of measure in the generated CFDI appeared in English instead of the…
### Issue before this commit: When a CFDI invoice was sent through a mass action (Send & Print executed by OdooBot), the unit of measure in the generated CFDI appeared in English instead of the configured language (e.g. Spanish. ### Steps to reproduce the issue: 1.Download Accounting, Contacts and l10n_mx 2. Switch to Spanish (MX) language 3. Set the language of "Inmoviliaria CVA" and "XENON INDUSTRIAL ARTICLES" to Spanish (MX) 4. In contacts select Archived in filters and switch OdooBot language to Spanish (MX) 5. Create and confirm two invoices in the database, one for each customer but don't send these invoices 6. Go to the list view and select these two invoices, and click on "Send and print" and select CFDI 7. Check any of the XML files generated in any of the invoices (in the CFDI tab of the invoice) 8. See that the UoM in the XML file, will be set in english rather than Spanish (MX) ### Cause of the issue: The context under which the batch action runs does not contain the lang key. As a result, translated fields (such as product_uom_id.name) were read in the source language (English) instead of the executing user's language, because nothing in the CFDI generation chain explicitly forced the correct lang into the context. ### Reason to introduce the fix: A CFDI must always report translated fields in the correct language. The fix ensures the invoice is read with the executing user's language when the context doesn't already specify one, so translated fields are consistently correct across both flows. opw-6399860 Forward-Port-Of: odoo/enterprise#129916 Forward-Port-Of: odoo/enterprise#125698