Daily updates from Odoo
Friday, July 4, 2025
43 changes
19 changes
Resolved issues and error corrections
Price list rules now update correctly when products or variants are changed, reducing pricing mistakes. Archived price lists are hidden from rule views, and price-related labels and inputs are clearer based on enabled settings.
Original PR description
--- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes cases where website-specific hidden elements could still appear because the system checked a shared template status instead of the current website's setting. Website editors can now more reliably show or hide menu and template options for each website.
Original PR description
Fixed cache pollution of _get_cached_template_info and added tests regarding the website editor, more specifically on enabling or disabling options related to views. Context: - Base: - the xmlid and…
Fixed cache pollution of _get_cached_template_info and added tests
regarding the website editor, more specifically on enabling or disabling
options related to views.
Context:
- Base:
- the xmlid and key of ir.ui.view are unique;
- the ir.ui.view are inherited if they are active, otherwise inheritance
is not applied;
- _get_cached_template_info(key) returns the cached record values.
- Website:
- the key of ir.ui.view are not unique; they can exist for different
websites and without a website;
- the ir.ui.view are inherited if they are active, otherwise inheritance
is not applied. If a specific inherited view exists (for the current
website), the default view (with same key) is not applied;
- for t-call, the specific view are used only if the view is active,
otherwise the default view is displayed;
- is_view_active(key) should return False if the view of the website in
question is inactive. If the default view is False, but the website
view is True, then the response should be True;
Issue:
`is_view_active` returns True if a view with this key is active, ignoring
the website-specific inactive view.
The issue was seen because the editor changes the display (active) of the
views by copying them with the website reference. So when we want to
change the menu, and hide it, the view is copied and set active=False.
Part of the menu was still visible because it uses a
`t-if="is_view_active(...)"`.
Issue introduced by: 97c2dd2ec569d34b044da6aa6f473277b48ada12This fix prevents users from being redirected to another website page after clicking Edit while the editor is still loading on a slow connection. It keeps the website builder focused on the intended page, avoiding a broken editing session and user confusion.
Original PR description
With a slow connection, it is possible to click on edit, then click on a menu link before the builder opens and be redirected. This should not be possible and was not the case before [1]. Steps to reproduce: - Set your network to "regular 3G" - Click on Edit - Click on another menu item => The iframe is redirected, then the builder sidebar opens but you can't edit the page. [1]: https://github.com/odoo/odoo/commit/9fe45e2b7ddbbfd0445ffe25a859e67a316d02b2 task-4367641
Website builder snippets now appear in the correct default language when editing multilingual websites, including after switching between websites. The related automated test has also been restored to help prevent this issue from returning.
Original PR description
\* = html_builder, website This PR re-enable the `test_snippet_translation` test that were broken and skipped after the DOM changes introduced by the new Website Builder and adapts it's tour selectors. (commit 2) It also fixes some translation related issues that were introduced by the new Website Builder. (see commit 1 and 3)
Sales orders created under a branch company now calculate unit prices correctly when product taxes belong to the parent company. This prevents incorrect displayed prices when fiscal positions convert price-included taxes to price-excluded B2B taxes.
Original PR description
Versions -------- - 17.0+ Steps ----- 1. Set up 10% price-included tax; 2. copy the tax to a B2B version that's price-excluded; 3. create a B2B fiscal position mapping the first tax to the second; 4.…
Versions -------- - 17.0+ Steps ----- 1. Set up 10% price-included tax; 2. copy the tax to a B2B version that's price-excluded; 3. create a B2B fiscal position mapping the first tax to the second; 4. create a $10 product using the first tax; 5. create a branch for the current company; 6. switch to the branch company; 7. set up a sale order with the fiscal position; 8. add the product to the order. Issue ----- While the line displays the correct B2B tax, the unit price displays $10, as if it was computed without any taxes, instead of a price-excluded tax. Cause ----- In the `_compute_price_unit` method, it filters out all tax records linked to the product that don't have the same company as the order line, so the parent company's tax does not get factored in. Solution -------- Rather than requiring strict equality between companies, also allow taxes that belong to a parent company of the line's company. opw-4853042 Forward-Port-Of: odoo/odoo#217012 Forward-Port-Of: odoo/odoo#216124
Link editing now handles links that contain images, buttons, or other formatted content without removing or breaking that content. This prevents issues in apps like Todo and Recruitment where editing a link could damage the email/template formatting or leave the edit popover stuck open.
Original PR description
reproduction: 18.0+18.1: 1. In Todo, insert an inline image, and create a link including the image and some text 2. click on the text part, click edit button, modify the label area and click apply 3.…
reproduction: 18.0+18.1: 1. In Todo, insert an inline image, and create a link including the image and some text 2. click on the text part, click edit button, modify the label area and click apply 3. the image is removed Test case 2: 1. go to Recruitment, and open an application and click "Send interview" 2. click on the link inside the template, change the url 3. apply, format of the button breaks 18.2: same flow with test case 2, click apply causing a traceback 18.3: same flow with test case 2, click on the link, do nothing and click away, the popover not close Fix: a partial back port of https://github.com/odoo-dev/odoo/pull/4633 The idea is that when the link doesn't only contain text, we don't show the label input field nor apply the label to the link. Because the label field extracts/display the text content of the link element, the field doesn't support html fragment, applying the label on a link including another element inside will break it. on 18.4+, we only rename the variable from isLabelHidden to showLabel task-4881878 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#217226 Forward-Port-Of: odoo/odoo#215023
This fixes an inventory issue where reducing a sales order quantity could create an extra incorrect delivery transfer when a route uses its own destination location. The change ensures stock adjustments use the intended route destination, keeping warehouse movements accurate and avoiding confusing duplicate pickings.
Original PR description
Steps to reproduce: - Install Sales and Stock - Activate the multi-step routes setting - Go to a Delivery route in the warehouse - Change the `location_dest_id` of the operation type set on the rule…
Steps to reproduce: - Install Sales and Stock - Activate the multi-step routes setting - Go to a Delivery route in the warehouse - Change the `location_dest_id` of the operation type set on the rule - Enable the "Location Dest. Taken from Rule" checkbox - Ensure `rule.location_dest_id` and `operation_type.location_dest_id` are different - Create a Sales Order (SO) for a product with quantity = 5 and confirm - Change the SO line quantity to 3 and save Issue: A second picking is created with a move taking the product from `rule.operation_type.location_dest_id -> rule.operation_type. location_src_id` with quantity = -2. This happens because the decrease in the SO quantity triggers a negative move, and this move is not merged with the existing positive move. Instead, a new move is created in the opposite direction. In `_merge_moves`: https://github.com/odoo/odoo/blob/3c4275fb00255e519f01bf5547eff1db3a59d4b5/addons/stock/models/stock_move.py#L1191-L1193 It checks if the negative move has similar characteristics to the existing positive moves. However, the `neg_key(neg_move)` differs in `location_dest_id`, so the merge fails. This happens because the negative move does **not** read the `location_dest_id` from the rule — unlike the procurement, which **does** use the rule and therefore creates positive moves with the correct destination. When the negative move is created with the procurement, it initially has the correct `location_dest_id`. But then: https://github.com/odoo/odoo/blob/b984c72df398c4fe942d8894442e4e893ca0660e/addons/stock/models/stock_move.py#L1191 triggers `_compute_location_dest_id`, which doesn't consider the `rule.location_dest_id` and defaults to `operation_type. location_dest_id`, causing the merge to fail due to mismatched destination_locations. The positive move has read the correct value, because when it was assigned to a picking, the picking has the correct destination from the procurement. But for the neg_move it has picking None so it maps to the operation_type without consdiering the location from rule checkbox. opw-4793171 Forward-Port-Of: odoo/odoo#212355
This fixes an issue where manually adjusted extra hours on an employee attendance could be overwritten when a new attendance was created. The change helps preserve user-entered overtime values in automatic approval setups, reducing payroll and attendance corrections.
Original PR description
**Steps to reproduce** - Set "Extra Hours Validation" to "Automatically approved" - Create an attendance for an employee - Change the "Extra Hours" to a different value - Create another attendance…
**Steps to reproduce** - Set "Extra Hours Validation" to "Automatically approved" - Create an attendance for an employee - Change the "Extra Hours" to a different value - Create another attendance for this employee (not necessarily on the same day) - See that the "Extra hours" of the previous attendance has been recomputed, resetting the value entered by the user. **Cause** When creating an attendance for an employee, we recompute the `validated_overtime_hours` for the other attendances of this employee https://github.com/odoo/odoo/blob/cac96f5d3c391ea0d52da2e3433e7eabe07e8fb0/addons/hr_attendance/models/hr_attendance.py#L426 In case of attendances with no validation, this field is synced with the `overtime_hours` https://github.com/odoo/odoo/blob/cac96f5d3c391ea0d52da2e3433e7eabe07e8fb0/addons/hr_attendance/models/hr_attendance.py#L156 **Solution** We may still want to recompute the `validated_overtime_hours` of automatically approved attendances, since it is their default state, unlike manually approved attendances. If the `validated_overtime_hours` field is different from `overtime_hours`, it means it has been modified. In that case, we avoid recomputing it. This doesn't guarantee a manually set value will never be overriden by a change in its dependencies, but it reduces the likelihood. opw-4639230 Forward-Port-Of: odoo/odoo#207806
This fix restores reliable resizing of grid-based content boundaries in the website editor. Business users editing pages can now adjust elements such as the Pills snippet as expected, reducing layout frustration and editing interruptions.
Original PR description
Before this commit, grid resizing wasn't working properly, because of the pointer up event not firing. To reproduce the issue: - open website, start editing - drop the "pills" snippet - click on text and try to resize its 'boundaries' => It's not working as expected This commit follows the [html_builder refactoring] [html_builder refactoring]: odoo/odoo@9fe45e2b7ddb Related to task-4367641
Payments using an existing third-party check now automatically use the check's original currency, avoiding incorrect currency conversions. The system also blocks combining checks in different currencies, reducing payment errors for Latin American check workflows.
Original PR description
**Steps to reproduce:** - Install accountant, l10n_ar and l10n_latam_check - Switch to an Argentinian company (e.g. (AR) Responsable Inscripto) - Make sure that USD currency has a rate different than…
**Steps to reproduce:**
- Install accountant, l10n_ar and l10n_latam_check
- Switch to an Argentinian company (e.g. (AR) Responsable Inscripto)
- Make sure that USD currency has a rate different than 1
- Create a journal:
* Journal Name: Checks journal
* Type: Cash
- Save the journal
=> a Cash Account should be automatically created
- In "Incoming Payments" tab of the journal, set:
* "New Third Party Checks" with the Cash Account
* "Existing Third Party Checks" with the Cash Account
- In "Outgoing Payments" tab of the journal, set:
* "Existing Third Party Checks" with the Cash Account
- Create an invoice:
* Customer: [an Argentinian customer] (e.g. ADHOC SA)
* Currency: ARS
* Invoice Lines:
- Quantity: 1
- Price: 150000.00
- Taxes: VAT 21%
- Confirm the invoice
- Pay the invoice:
* Journal: [the created Checks journal]
* Currency: ARS
* Checks: [add a line with the amount of the invoice]
- Create a bill:
* Vendor: [an Argentinian customer] (e.g. ADHOC SA)
* Currency: USD
* Invoice Lines:
- Quantity: 1
- Price: 500.00
- Taxes: VAT 21%
- Pay the bill:
* Journal: [the created Checks journal]
* Payment Method: Existing Third Party Checks
* Checks: [add a line and select the check used to pay the invoice]
**Issue:**
When the check (from the invoice) is selected to pay the bill, the original amount (in ARS) is used but the currency stays in USD, which is not correct.
If the currency is changed to ARS, the currency rate is applied on the amount that is already the amount in ARS, which generates a higher incorrect amount.
**Solution:**
Use the currency set on the existing check by default.
Also prevent adding several checks with different currencies.
opw-4741607
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#215435This fixes an issue in Point of Sale where entering extra digits after using quick amount buttons could produce the wrong payment amount. Cashiers can now reliably type payment amounts, reducing checkout errors and manual corrections.
Original PR description
Steps to reproduce: =================== - Add a product to the orderline from the product screen - Click payment - Select any payment method - Enter the amount manually - Press `+20`, then press `2`, OR press `+20`, then press `6` Issue: ====== - In the case of `+20` and `2`, the expected result is `202`, but we get `20` - In the case of `+20` and `6`, the expected result is `206`, but we get `20.01` Cause: ====== - `formatCurrency` is used for the buffer, but the buffer should not depend on the currency Fix: ==== - Remove the usage of `formatCurrency` and treat the buffer as a string Task: 4850543 Forward-Port-Of: odoo/odoo#217108 Forward-Port-Of: odoo/odoo#213294
The live chat widget page now adapts properly to smaller mobile screens. This prevents text and layout from overflowing, making it easier for visitors to use chat from their phones.
Original PR description
**Before this PR:** the livechat widget page was not responsive on mobile devices. This PR fixes the issue by adding the missing meta tag and adjusting font sizing and word wrapping to prevent content overflow on small screens. task-3499603 Forward-Port-Of: odoo/odoo#217127
Fixes several subscription pricing issues so customers see the right recurring and one-time prices, including pricelist visibility, plan availability, and discounts. It also improves product duplication behavior by copying valid pricing rules and ignoring obsolete inactive-product rules, reducing errors for sales teams.
Fixed an issue where some Winbooks journals were skipped during import when their codes were longer than the allowed length and shared the same starting characters. The import now assigns clear temporary codes to those duplicate cases, helping Belgian accounting migrations bring in all journals reliably.
Original PR description
**Steps to reproduce:** - Install accountant, l10n_be and account_winbooks_import - Switch to a Belgian company (e.g. BE Company CoA) - Go to "Accounting / Configuration / Settings" - Click on…
**Steps to reproduce:** - Install accountant, l10n_be and account_winbooks_import - Switch to a Belgian company (e.g. BE Company CoA) - Go to "Accounting / Configuration / Settings" - Click on "Import (for full history)" in "Accounting Import" section - Click on "Import WBK" in "Winbooks" section - Upload a Winbooks file containing several journals having their "DBKID" value longer than 5 characters with the 5 first characters being identical (e.g. "SALES001", "SALES002",...) - Import **Issue:** Some journals are not imported. **Cause:** The code of a journal is limited to 5 characters and is unique per company. When a code is longer than 5 characters, only the 5 first characters are kept. In this case, several journals to create have the same 5 first characters. Therefore, only one of them is created. **Solution:** If the code of a journal to create has the same first 5 characters of a journal that has already been created (and the same last 5 characters), we use a generic code formatted with a starting "*" char followed by a number that is incremented. This format allows to quickly find it if we want to change its value once imported. This solution is limited to 9999 journals that have a code that can starts with the same 5 characters than another journal, but it should be more than enough. opw-4812655 Forward-Port-Of: odoo/enterprise#86068
This fix ensures the invoice sending time is saved before contacting the Mexican e-invoicing provider. If a connection drops during sending, Odoo can reuse the same timestamp when retrying, reducing duplicate CFDIs with slightly different dates.
Original PR description
### Background In https://github.com/odoo/enterprise/pull/85026 we changed the behaviour of `l10n_mx_edi_post_time` so that it gets set during the CFDI sending process, rather than when the invoice…
### Background In https://github.com/odoo/enterprise/pull/85026 we changed the behaviour of `l10n_mx_edi_post_time` so that it gets set during the CFDI sending process, rather than when the invoice is posted. This was needed to ensure that the post time both reflects the sending time and is re-used if the invoice needs to be re-sent. ### Bug description Since then, several Mexican customers have reported that some CFDIs are sent duplicated, with a difference of a few seconds in the CFDI's Fecha. ### Analysis A disconnection might occur during sending of the CFDI. In that case, the PAC will process the CFDI, but in Odoo the transaction will be rolled back, and the `l10n_mx_edi_post_time` will be lost. When Odoo re-sends the CFDI, it will take a new `l10n_mx_edi_post_time`. ### Solution Commit before performing the API call so that the `l10n_mx_edi_post_time` gets committed to DB. opw-4780096 Forward-Port-Of: odoo/enterprise#89263 Forward-Port-Of: odoo/enterprise#89117
Belgian payroll reports now calculate worker counts much faster, reducing a slow operation from about 50 seconds to under a second on odoo.com. This improves responsiveness for payroll teams and reduces waiting time when processing Belgian HR payroll data.
Original PR description
From 50 to 0.4 seconds on odoo.com
The UAE payroll rules now calculate end-of-service compensation in line with the official government calculator. Employees receive the 30-day compensation rate only after completing the sixth year, improving payroll accuracy and compliance.
Original PR description
- to algin with UAE goverment eos calculator, salary rule is update to concider full 30 compensation after completing the 6th year not the 5th. Task: 4756963 Forward-Port-Of: odoo/enterprise#89306 Forward-Port-Of: odoo/enterprise#84752
This fix prevents payslip creation from failing when a Belgian employee has a work entry spanning an unusually long period, such as a full month. Payroll teams can now generate the affected payslips without encountering the error.
Original PR description
There is a bug in the module that made the creation of payslip triggers an error. Steps to reproduce it :
1) Use a Belgian company and an employee with a contract;
2) Create a work entry for a whole month (from 05/01/2025 09:00:00 to 06/01/2025 17:00:00 for example);
3) Try to create a payslip for this employee.
Error :
File "/data/build/enterprise/l10n_be_hr_payroll/models/hr_contract.py", line 517, in _get_work_hours_split_half
work_data[('half', work_entry.work_entry_type_id.id)] += dt.days * 24 + dt.seconds / 3600 # Number of hours
TypeError: 'float' object is not iterable
[opw-4752109](www.odoo.com/odoo/project/49/tasks/4752109)
Forward-Port-Of: odoo/enterprise#88445
Forward-Port-Of: odoo/enterprise#84810Payslip company selection is now locked to the company derived from the employee, preventing mismatched company data in payroll batches. This avoids errors when creating draft accounting entries for batches containing payslips from multiple companies and provides a clearer validation message for older affected records.
Original PR description
Currently a traceback is occurring when the user tries to create a Draft Entry, in the batch that contains payslips of multiple companies. **To reproduce this issue:** 1) Install hr_payroll_account…
Currently a traceback is occurring when the user tries to create a Draft Entry, in the batch that contains payslips of multiple companies. **To reproduce this issue:** 1) Install hr_payroll_account and switch to multi-company environment 2) Create two employees with two running contracts respectively 3) Now create a Batch record from payroll/payslips/batches 4) Create two playslips with different companies with the created batch 5) Compute both the payslips and open the batch 6) Now, try to click on the Create Draft Entry **Error:** A traceback will occur. ``` ValueError: Expected singleton: res.company(1, 2) ``` **Cause:** When the user created multiple payslips with multiple companies containing the same batch and tries to create a Draft Entry, we filtered out the payslips based on the payslip state, and try to change the state to Done using the action_payslip_done method. https://github.com/odoo/enterprise/blob/1e5d7155466f80942f0b8fe2df7fdfb86cae7417/hr_payroll/models/hr_payslip_run.py#L70 So the self will contain multiple payslip recordsets with different company in each payslip. This leads to the above traceback when accessing company_id from self https://github.com/odoo/enterprise/blob/1e5d7155466f80942f0b8fe2df7fdfb86cae7417/hr_payroll_account/models/hr_payslip.py#L61 **Solution:** In payslips, the company_id field should be in readonly state, since the value of the company_id will computed from the employee_id which is a required field. Also raised a validation Error for the previously created record to handle the traceback. Related Upgrade PR:- https://github.com/odoo/upgrade/pull/7763 opw-4797089 Forward-Port-Of: odoo/enterprise#88307 Forward-Port-Of: odoo/enterprise#86628
6 changes
Resolved issues and error corrections
This fix prevents online appointment requests from linking new CRM opportunities to a customer record belonging to a company the appointment staff cannot access. It avoids validation errors in multi-company setups, so anonymous website bookings can be submitted reliably when customer emails already exist elsewhere.
Original PR description
**Steps to reproduce:** - Set up CRM / Appointment / Website apps - Create new company (2) - Create partner contact with specific email and the new company - Create appointment type linked to a staff…
**Steps to reproduce:**
- Set up CRM / Appointment / Website apps
- Create new company (2)
- Create partner contact with specific email and the new company
- Create appointment type linked to a staff user of another company (1) who has no access to the new one
- Enable `Create Opportunities` on the new appointment type
- Go to the website as an anonymous user
- Submit an appointment request using the partner's email
- `Incompatible companies on records:` error
**Issue:**
Previous solution (17.0) was trying to use existing partner if the email was provided and existed in the database
`customer = request.env['res.partner'].sudo().search([('email_normalized', '=', email_normalized)], limit=1`
This means that, in a multi-company environment, the lead created by the new appointment for the appointment user of company 1 can be linked to the partner contact of company 2 and throw an error on validation.
**Fix:**
Restricted partner search domain using current allowed companies using the `staff_user` or the user which created the `appointement_type`.
opw-4713060
Forward-Port-Of: odoo/enterprise#87620
Forward-Port-Of: odoo/enterprise#84006The Winbooks import now handles multiple journals whose original codes become identical after Odoo's five-character limit is applied. This prevents journals from being skipped during Belgian accounting imports and assigns clear temporary codes that users can adjust later if needed.
Original PR description
**Steps to reproduce:** - Install accountant, l10n_be and account_winbooks_import - Switch to a Belgian company (e.g. BE Company CoA) - Go to "Accounting / Configuration / Settings" - Click on…
**Steps to reproduce:** - Install accountant, l10n_be and account_winbooks_import - Switch to a Belgian company (e.g. BE Company CoA) - Go to "Accounting / Configuration / Settings" - Click on "Import (for full history)" in "Accounting Import" section - Click on "Import WBK" in "Winbooks" section - Upload a Winbooks file containing several journals having their "DBKID" value longer than 5 characters with the 5 first characters being identical (e.g. "SALES001", "SALES002",...) - Import **Issue:** Some journals are not imported. **Cause:** The code of a journal is limited to 5 characters and is unique per company. When a code is longer than 5 characters, only the 5 first characters are kept. In this case, several journals to create have the same 5 first characters. Therefore, only one of them is created. **Solution:** If the code of a journal to create has the same first 5 characters of a journal that has already been created (and the same last 5 characters), we use a generic code formatted with a starting "*" char followed by a number that is incremented. This format allows to quickly find it if we want to change its value once imported. This solution is limited to 9999 journals that have a code that can starts with the same 5 characters than another journal, but it should be more than enough. opw-4812655 Forward-Port-Of: odoo/enterprise#86068
Fixed an issue where copied planning shifts could overstate allocated time when an employee was on leave, because lunch time was incorrectly included in the open shift. This helps keep staffing schedules and reported hours accurate when weekly shifts are duplicated.
Original PR description
**Issue:**
When a resource is on leave for a particular day, and an open shift is created for that day, the open shift includes lunch time, which causes the total allocated hours to be incorrect.
**Example:**
- Shift duration: 1 week (27th to 31st January)
- Resource on leave on 30th January
- Move to the next week and copy the previous week's shift
- New shift created:
- Monday to Wednesday and Friday assigned
- Open shift on Thursday (9 hours allocated)
However, 1 extra hour is added in the open shift.
**Steps to Reproduce:**
-Install the planning_holidays module.
- Create a shift for the week (27th to 31st January).
- Add leave for 6th February.
- Copy the previous week's shift.
- Check the allocated hours for 6th February.
task-4224781
Forward-Port-Of: odoo/enterprise#89370
Forward-Port-Of: odoo/enterprise#73478The Work Entries Analysis report now only shows payroll data for the companies selected by the user. This prevents users in multi-company environments from seeing irrelevant company data and makes the report match the active company filter.
Original PR description
BUG - In multi-companies env the report shows all the companies no matter what is selected in the company selection menu Expected behavior: - Only selected company data is presented in the view FIX - add a domain to the report action to show only allowed companies data Task: 4781100 Forward-Port-Of: odoo/enterprise#89367 Forward-Port-Of: odoo/enterprise#85690
This fix ensures the Mexican e-invoice sending timestamp is saved before Odoo contacts the certification provider. If a connection drops during sending, retries now reuse the same timestamp, reducing duplicate CFDIs with slightly different issue times.
Original PR description
### Background In https://github.com/odoo/enterprise/pull/85026 we changed the behaviour of `l10n_mx_edi_post_time` so that it gets set during the CFDI sending process, rather than when the invoice…
### Background In https://github.com/odoo/enterprise/pull/85026 we changed the behaviour of `l10n_mx_edi_post_time` so that it gets set during the CFDI sending process, rather than when the invoice is posted. This was needed to ensure that the post time both reflects the sending time and is re-used if the invoice needs to be re-sent. ### Bug description Since then, several Mexican customers have reported that some CFDIs are sent duplicated, with a difference of a few seconds in the CFDI's Fecha. ### Analysis A disconnection might occur during sending of the CFDI. In that case, the PAC will process the CFDI, but in Odoo the transaction will be rolled back, and the `l10n_mx_edi_post_time` will be lost. When Odoo re-sends the CFDI, it will take a new `l10n_mx_edi_post_time`. ### Solution Commit before performing the API call so that the `l10n_mx_edi_post_time` gets committed to DB. opw-4780096 Forward-Port-Of: odoo/enterprise#89263 Forward-Port-Of: odoo/enterprise#89117
The UAE payroll rules now calculate end-of-service compensation using the full 30-day entitlement only after an employee completes the sixth year, matching the UAE government calculator. This helps businesses produce more accurate final settlement amounts and stay aligned with local guidance.
Original PR description
- to algin with UAE goverment eos calculator, salary rule is update to concider full 30 compensation after completing the 6th year not the 5th. Task: 4756963 Forward-Port-Of: odoo/enterprise#89306 Forward-Port-Of: odoo/enterprise#84752
4 changes
Resolved issues and error corrections
The Mexican electronic invoicing flow now saves the invoice sending time before contacting the external certification provider. This helps prevent duplicate CFDI documents with slightly different timestamps when a connection is interrupted and Odoo retries the send.
Original PR description
### Background In https://github.com/odoo/enterprise/pull/85026 we changed the behaviour of `l10n_mx_edi_post_time` so that it gets set during the CFDI sending process, rather than when the invoice…
### Background In https://github.com/odoo/enterprise/pull/85026 we changed the behaviour of `l10n_mx_edi_post_time` so that it gets set during the CFDI sending process, rather than when the invoice is posted. This was needed to ensure that the post time both reflects the sending time and is re-used if the invoice needs to be re-sent. ### Bug description Since then, several Mexican customers have reported that some CFDIs are sent duplicated, with a difference of a few seconds in the CFDI's Fecha. ### Analysis A disconnection might occur during sending of the CFDI. In that case, the PAC will process the CFDI, but in Odoo the transaction will be rolled back, and the `l10n_mx_edi_post_time` will be lost. When Odoo re-sends the CFDI, it will take a new `l10n_mx_edi_post_time`. ### Solution Commit before performing the API call so that the `l10n_mx_edi_post_time` gets committed to DB. opw-4780096 Forward-Port-Of: odoo/enterprise#89263 Forward-Port-Of: odoo/enterprise#89117
This fix prevents the invoice OCR process from creating duplicate supplier records when multiple documents from the same supplier are processed at the same time. It improves data quality and reduces manual cleanup for accounting teams using automated invoice extraction.
Original PR description
When the OCR parses documents from the same supplier concurrently, it can happen that it creates duplicated `res.partner` entry for it. This typically happen when the update of the documents is done…
When the OCR parses documents from the same supplier concurrently, it can happen that it creates duplicated `res.partner` entry for it. This typically happen when the update of the documents is done through the webhook. In that case, the different SQL transactions overlap each other and can't "see" the partner created by another request. In order to prevent this, a new field `is_created_by_ocr` and a unique index are introduced to be able to detect duplicated partners created by the OCR. This solution is quite costly as it requires introducing a new field and an index on `res.partner`... Other alternatives were considered: - Updating the documents through a cron instead -> introduces latency, especially on the SaaS where we can't force a cron to run immediately, even with a cron trigger. - Introducing a new model on which we could add the uniqueness model -> also costly, requires a new model just to fix the issue, and we need a way to frequently clean the records, so probably a cron on top of it (or using autovacuum, but its frequency might be too low). - Adding random delay on OCR side before calling the webhook -> introduces latency and no guarantee, it only reduces the chances of duplicated partners. - Using explicit SQL locks -> no guarantee, we only know what should be locked late in the SQL transaction (after fetching the results from the OCR), it wouldn't be very effective. Locking the whole `res_partner` table from the start of the transaction would be too restrictive and equivalent to serializing the transactions. An attempt was made in #88830, but it was deemed too complicated. task-[4904333](https://www.odoo.com/odoo/project/2068/tasks/4904333)
Fixes an issue where GSTR-2B JSON files were attached to messages but not properly linked to newly created vendor bills. Bookkeepers can now open these attachments without seeing a 404 error, improving reliability during GSTR-2B matching.
Original PR description
**Before this PR:** - The GSTR-2B JSON was attached to the message but not linked to the newly created bills (`res_id` was not set). - As a result, when a Bookkeeper user created a new GSTR-2B bill and tried to open the attachment, it raised a 404 error: `"The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again."` **After this PR:** - The issue is resolved. - During GSTR-2B matching, unattached message attachments are now properly linked to the newly created bills by updating their res_model and res_id fields. Task ID : 4831758 Forward-Port-Of: odoo/enterprise#89250 Forward-Port-Of: odoo/enterprise#86785
This fixes inconsistent data loading between the standard Point of Sale and self-ordering flows. Businesses should see fewer errors when shared POS information is needed, including receipt printing in self-ordering scenarios where session data may not always be available.
Original PR description
*: l10n_br_edi_pos, l10n_cl_edi_pos, l10n_ec_edi_pos, l10n_ke_edi_oscu_pos, l10n_mx_edi_pos, l10n_pe_edi_pos, pos_blackbox_be, pos_iot, pos_mobile, pos_preparation_display, pos_restaurant_appointment, pos_self_order_iot, pos_settle_due Before this commit, the loading data behavior between self-ordering and PoS was merged but not consistent. This led to issues when we try to add some data to load for both self-ordering and PoS. At the moment, we need to create two separate method to handle both cases. Now with this commit, we have consistent methods which will load data for both self-ordering and PoS. This will allow us to have a more consistent behavior and avoid issues when adding data to load. An explicit example is about `_server_version` object which is added to the `pos.session` model and used when printing the receipt. Since the session isn't always available in self-ordering, sometimes that object isn't available, leading to issues when printing the receipt.
14 changes
Resolved issues and error corrections
Mobile self-ordering no longer fails when customers order items priced at zero. The fix preserves the original order details so free orders can be completed without errors or lost tracking information.
Original PR description
Issue: When [currentOrder](https://github.com/odoo/odoo/blob/a43ef8e15f4e0ee28bdb1975a8a359d3373e8d2c/addons/pos_self_order/static/src/app/self_order_service.js#L377) evaluates orders, it returns an…
Issue: When [currentOrder](https://github.com/odoo/odoo/blob/a43ef8e15f4e0ee28bdb1975a8a359d3373e8d2c/addons/pos_self_order/static/src/app/self_order_service.js#L377) evaluates orders, it returns an order only if it's in 'draft' state or 'paid' with zero amount in kiosk mode. https://github.com/odoo/odoo/blob/a43ef8e15f4e0ee28bdb1975a8a359d3373e8d2c/addons/pos_self_order/static/src/app/self_order_service.js#L377-L386 If self_ordering_mode is not 'kiosk' (e.g., 'mobile'), such orders do not match the filter. (Note: 0 priced orders are considered as 'paid') if order is not found (because it didn't pass the filter), a new order is created and returned https://github.com/odoo/odoo/blob/a43ef8e15f4e0ee28bdb1975a8a359d3373e8d2c/addons/pos_self_order/static/src/app/self_order_service.js#L393-L412 and the original order context— like access_token and tracking_number—is lost in new order, raising a traceback. Steps to reproduce: - Enable the self-ordering for a POS Restaurant - change the price of a product available for self-ordering to 0 - open the self-ordering and just order the product FIx: As this is a corner case, concerning, 0 priced orders from `mobile` mode, we return the original order in this case, else return the current order Note: - A [fix](https://github.com/odoo/odoo/commit/9f1441cc43c951356dc1a48555621c326a5be8f2 ) was applied for this exact issue, but it gradully got removed later in other PRs. [here](https://github.com/odoo/odoo/pull/192874/files#diff-0c985bf4d5fc0f1d25c9014209f090dd09727488ec15ca71897986119d49d5bfL366) and [here](https://github.com/odoo/odoo/pull/197569/files#diff-0c985bf4d5fc0f1d25c9014209f090dd09727488ec15ca71897986119d49d5bfL706-R640) - issue only in 18.0 opw-4677724 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Printing a delivery for a kit product no longer fails when the selected packaging uses different units than its components. This prevents an error during sales and delivery processing, helping users complete quotations and delivery documents smoothly.
Original PR description
…ating **Steps to reproduce:** - Inside Settings/Sales activate the "Product Packagings" setting - Create a new product (the final product) - Inside the inventory tab add a packaging line for a pack…
…ating **Steps to reproduce:** - Inside Settings/Sales activate the "Product Packagings" setting - Create a new product (the final product) - Inside the inventory tab add a packaging line for a pack of 9 units - Create a new product (the comp product) - In the general information tab, set a unit of mesure of g - In the inventory tab add a packaging line for a pack of 0.9 g - Set an on hand quantity for the comp product - Create a new BOM for the final product - Add a a line with the comp product for a quantity of 0.1 g - Select kit - Create a new quotation and select your kit product - Select your packaging > Confirm - Click on the delivery smart button - print without validating **Current behavior:** traceback with error message : "The unit of measure g defined on the order line doesn't belong to the same category as the unit of measure Units defined on the product." **Cause of the issue:** https://github.com/odoo/odoo/blob/57282becdeab5cdd7f581e149dede683fc352abe/addons/stock/models/stock_move_line.py#L136 line.move_id.product_packaging_id is the packaging of the final product whose uom is unit. ine.product_uom_id is grams so _compute_quantity will fail **fix** the fix is a backport of https://github.com/odoo/odoo/pull/201580 with an adaptation of the filtering so that the lines where the packaging was changed on the line to a packaging of the component are sent to super (it otherwise results in a wrong quantity computation) related to opw-4781180 Forward-Port-Of: odoo/odoo#214814
Tax reports now show the correct net amount when invoice lines use the same tax but different analytic distributions. This prevents overstated taxable bases in grouped tax reports, improving accuracy for accounting and reporting.
Original PR description
### Issue: When having two lines on an invoice with the same tax and different analytic distribution, the base value is doubled on the tax report. ### Steps to reproduce: - Create a new tax on sales…
### Issue: When having two lines on an invoice with the same tax and different analytic distribution, the base value is doubled on the tax report. ### Steps to reproduce: - Create a new tax on sales (eg 10%) - Make sure the option "Analytic Accounting" is ticked in the settings - Create an invoice with two lines (eg both at $100), add the tax on both - Change the analytic distribution on both lines to different values - Confirm the invoice - Go to the tax report - Select the report "Group By: Account > Tax" - On the report the "Net" amount is doubled ($400), the tax amount is correct ($20) ### Cause: On the invoice we can see in "Journal Items" that two tax lines are created instead of one (one for each analytic distribution). The "Group By" reports are generated by [this query](https://github.com/odoo/odoo/blob/51fcbd211d2b1abf4b93becedbcbb9e03002cdd6/addons/account/models/account_move_line_tax_details.py#L92). At the [creation of the second subtable](https://github.com/odoo/odoo/blob/51fcbd211d2b1abf4b93becedbcbb9e03002cdd6/addons/account/models/account_move_line_tax_details.py#L164-L198) the move lines are linked together based among other things on the tax id. The [filter on analytic distribution](https://github.com/odoo/odoo/blob/51fcbd211d2b1abf4b93becedbcbb9e03002cdd6/addons/account/models/account_move_line_tax_details.py#L187-L191) does not apply here as `tax.analytic = False`. The result is that each tax line is linked with both base lines. The second subtable have 4 lines in this case, with each base line doubled. The result of the query have the base amount doubled. ### Solution: We cannot fix the query as there is no link to find the tax line origin among the base lines. The method `_read_generic_tax_report_amounts` in `account_reports` is made to fix the base values in report in case of duplicate. Until now, it did not include the duplication caused by analytic distribution but duplication because of repartition lines for example. The fix is to use this method also for analytic distribution. So we add `tdr.analytic_distribution` in the `GROUP BY`. This value must be returned by the query in `account` so we add it. opw-4753676 Forward-Port-Of: odoo/odoo#213751
Fixed an issue where sending invoices to customers with different languages in the same batch could show the email action button in the wrong language. Each invoice email now uses the correct customer language, improving clarity for international customers.
Original PR description
**Issue**: When multiple invoices with different customer languages are sent and printed together, the invoice email button may appear with an incorrect translation for some of them. **Steps to…
**Issue**: When multiple invoices with different customer languages are sent and printed together, the invoice email button may appear with an incorrect translation for some of them. **Steps to reproduce**: - Open the Accounting app - Go to Customers > invoices - Create a new invoice with a customer with its language set to German - Create a new invoice with a customer with its language set to English - Go back to Customers > invoices - Select the two invoices just created and click on action > Sent & Print and then click on the Sent & Print button - Go to Settings > Technical > Email > Emails and check the two last emails. One of them should have the invoice email button wrongly translated **Cause**: Before sending an email, it retrieve the `type_name` using the lang of the customer https://github.com/odoo/odoo/blob/28c3b9cf10488536dce5a4927fdbe8fcd6e5a839/addons/account/wizard/account_move_send.py#L596C1-L605C14 This will trigger that compute method https://github.com/odoo/odoo/blob/a6368e8a5787f3067d09d79516a2924b3f1207f0/addons/account/models/account_move.py#L841C1-L850C67 which set the `type_name` of all the records. Since the compute method only depends on move_type, it does not recompute type_name per record. As a result, all records may share the same type_name, regardless of language context. Please notice that `type_name` is used to display the invoice email button in the right language. **Solution**: Make the compute method `_compute_type_name` depending to the lang parameter, thus it will use the right `type_name` for each email to send. opw-4748741 Forward-Port-Of: odoo/odoo#216811
Fixes an accounting issue where imported invoice, payment, and exchange difference entries in a foreign currency could fail to reconcile completely. This helps keep journal items balanced after currency rate changes and reduces manual correction work for accounting teams.
Original PR description
# How to reproduce the issue - Create an invoice with price 1000 in a non-company currency (e.g., CHF). - Modify the currency rate after the invoice date, then generate the payment for this invoice.…
# How to reproduce the issue - Create an invoice with price 1000 in a non-company currency (e.g., CHF). - Modify the currency rate after the invoice date, then generate the payment for this invoice. - This will generate three journal entries (invoice, payment, and currency exchange difference). - Export those journal entries and include in the export the `matching_number`, `currency`, and `amount_currency` fields. - Import those three entries with the matching number and post them. - In the Journal Items, the line corresponding to the currency exchange difference is not matched with the lines from the invoice and the payment, leading to an unbalanced credit and debit. # Cause In `_prepare_reconciliation_single_partial` within `account_move_line`, the reconciliation is stopped by checking whether the debit/credit is fully matched. However, this check only considers `amount_residual_currency` and not `amount_residual`, which, in the case of an exchange difference, are different. opw-4776188 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#216097
Fixed an issue that could block manufacturing users from generating serial or lot numbers for tracked components. The system now uses the stock move’s demand quantity when needed, ensuring lot generation continues reliably during shop floor operations.
Original PR description
**Steps to Reproduce :** 1. Install MRP. 2. Create a Bill of Materials (BOM) and add a component with lot tracking. 3. Create and confirm a Manufacturing Order (MO) with BOM. 4. Navigate to the shop…
**Steps to Reproduce :** 1. Install MRP. 2. Create a Bill of Materials (BOM) and add a component with lot tracking. 3. Create and confirm a Manufacturing Order (MO) with BOM. 4. Navigate to the shop floor and click on Generate Serials/Lots. 5. The error appears when trying to generate the lot . **Issue :** Error raised when try to Generate Serials/Lots during the manufacturing process. `TypeError: unsupported operand type(s) for //: 'NoneType' and 'int'` **Cause:** This error occurs because the quantity field is undefined when Generate Serials/Lots is triggered, the quantity field is not being passed in the context, and its value is undefined, which is leading to a division by [none](https://github.com/odoo/odoo/blob/18.0/addons/stock/models/stock_move.py#L993). **Solution:** To fix this, we added the stock move’s demand quantity as a fallback.This ensures the quantity field value is present and its value correctly passed during lot generation. opw-4763600 Enterprise: https://github.com/odoo/enterprise/pull/88739
The point of sale search has been corrected so products with names similar to variant names are not hidden by an early variant match. This helps cashiers find the intended product when searching terms like brand or model names, reducing checkout confusion.
Original PR description
If you have a product template with variant, ex: Telephone case, variant name : Iphone 15 SE, Samsung Galaxy, Nokia 1999 When doing a search with more then 2 letters you will only find the Telephone…
If you have a product template with variant, ex: Telephone case, variant name : Iphone 15 SE, Samsung Galaxy, Nokia 1999
When doing a search with more then 2 letters you will only find the Telephone case, search exemple: Iphone 15 SE, Galaxy, Samsung.
** Step to reproduce **
- Create a product with variant samsung galaxy S24 ultra
- Create a product called Samsung galaxy
- Enable them for point of sale (don't forget to select a category that will appear on your shop)
- Do a search for the product Samsung galaxy
- Only Telephone case will appear.
** Cause of the issue **
Doing a search will call getProductsBySearchWord:
https://github.com/odoo/odoo/blob/5a1fff2cc61bd8676049879039defa3fb2a3f13d/addons/point_of_sale/static/src/app/services/pos_store.js#L2401-L2407
During the product.exactMatch(words) we will get a hit since we will have a name of the product variant:
https://github.com/odoo/odoo/blob/5a1fff2cc61bd8676049879039defa3fb2a3f13d/addons/point_of_sale/static/src/app/models/product_template.js#L265-L278
And the call for the function will finish there since the searchword lenght > 2 and we have a hit.
opw-4864976The live chat widget page has been adjusted so it fits properly on mobile screens. This helps visitors use chat without text overflowing or the page appearing incorrectly on smaller devices.
Original PR description
**Before this PR:** the livechat widget page was not responsive on mobile devices. This PR fixes the issue by adding the missing meta tag and adjusting font sizing and word wrapping to prevent content overflow on small screens. task-3499603 Forward-Port-Of: odoo/odoo#217127
Scanning a package in the Barcode app now correctly converts quantities when the package and transfer line use different units of measure. This prevents confusing or incorrect picked quantities, such as showing 10 grams instead of 10,000 grams for a 10 kg package.
Original PR description
**Problem:** when scanning a package with a different uom than the barcode line, the conversion is not made **Steps to reproduce:** - enable the "packages" settings - create a new storable product…
**Problem:** when scanning a package with a different uom than the barcode line, the conversion is not made **Steps to reproduce:** - enable the "packages" settings - create a new storable product and set uom of kg - click on the on hand smart button - add a new line - in the package column create a new package - set a quantity of 10 kg - create a new internal transfer and select your product - set a demand on 10000 and the uom of g - mark as todo - open the barcode app - inside internal operations click on your move - scan the name of the pack **Current behavior:** the quantity on the line is now 10/10000g **Expected behavior:** it should be 10000/10000g **Cause of the issue:** https://github.com/odoo/enterprise/blob/4c9fa9dc010958710d848fbcb3241b17ea7205ca/stock_barcode/static/src/models/barcode_picking_model.js#L1500-L1505 remaining_qty is expressed in the uom of the quant so it will be 10 but qty_needed is expressed in the uom of the line is it will be 10000. qty_used beeing the minimum of those two it will be 10. **fix** for the comparison to work we need to convert qty_needed before compairing. Also we need to make sure that the line is updated with the quantity converted in its own uom. Adding the uom to fieldsParam enables _udpdateLineQty to do the conversion https://github.com/odoo/enterprise/blob/4c9fa9dc010958710d848fbcb3241b17ea7205ca/stock_barcode/static/src/models/barcode_picking_model.js#L1669 opw-4860064 Forward-Port-Of: odoo/enterprise#87642
Tax reports now show the correct net amount when invoices have multiple lines using the same tax but different analytic distributions. This prevents overstated taxable bases while keeping the tax amount accurate, improving reliability of financial reporting.
Original PR description
### Issue: When having two lines on an invoice with the same tax and different analytic distribution, the base value is doubled on the tax report. ### Steps to reproduce: - Create a new tax on sales…
### Issue: When having two lines on an invoice with the same tax and different analytic distribution, the base value is doubled on the tax report. ### Steps to reproduce: - Create a new tax on sales (eg 10%) - Make sure the option "Analytic Accounting" is ticked in the settings - Create an invoice with two lines (eg both at $100), add the tax on both - Change the analytic distribution on both lines to different values - Confirm the invoice - Go to the tax report - Select the report "Group By: Account > Tax" - On the report the "Net" amount is doubled ($400), the tax amount is correct ($20) ### Cause: On the invoice we can see in "Journal Items" that two tax lines are created instead of one (one for each analytic distribution). The "Group By" reports are generated by [this query](https://github.com/odoo/odoo/blob/51fcbd211d2b1abf4b93becedbcbb9e03002cdd6/addons/account/models/account_move_line_tax_details.py#L92). At the [creation of the second subtable](https://github.com/odoo/odoo/blob/51fcbd211d2b1abf4b93becedbcbb9e03002cdd6/addons/account/models/account_move_line_tax_details.py#L164-L198) the move lines are linked together based among other things on the tax id. The [filter on analytic distribution](https://github.com/odoo/odoo/blob/51fcbd211d2b1abf4b93becedbcbb9e03002cdd6/addons/account/models/account_move_line_tax_details.py#L187-L191) does not apply here as `tax.analytic = False`. The result is that each tax line is linked with both base lines. The second subtable have 4 lines in this case, with each base line doubled. The result of the query have the base amount doubled. ### Solution: We cannot fix the query as there is no link to find the tax line origin amongst the base lines. The method `_read_generic_tax_report_amounts` in `account_reports` is made to fix the base values in report in case of duplicate. Until now it did not include the duplication caused by analytic distribution but duplication because of repartition lines for example. The fix is to use this method also for analytic distribution. So we add `tdr.analytic_distribution` in the `GROUP BY`. This value must be returned by the query in `account` so we add it. opw-4753676 Forward-Port-Of: odoo/enterprise#87404
Fixed an issue that could block manufacturing users when generating serial or lot numbers from the shop floor. The process now uses the planned demand quantity when the expected quantity value is missing, preventing the error and keeping production workflows moving.
Original PR description
This [PR](https://github.com/odoo/odoo/pull/209860) adds a fallback to product_uom_qty when the quantity field is not present during serial/lot generation from the shop floor. Includes a tour and…
This [PR](https://github.com/odoo/odoo/pull/209860) adds a fallback to product_uom_qty when the quantity field is not present during serial/lot generation from the shop floor. Includes a tour and test case in mrp_workorder to validate the fix. **Steps to Reproduce :** 1. Install MRP. 2. Create a Bill of Materials (BOM) and add a component with lot tracking. 3. Create and confirm a Manufacturing Order (MO) with BOM. 4. Navigate to the shop floor and click on Generate Serials/Lots. 5. The error appears when trying to generate the lot . **Issue :** Error raised when try to Generate Serials/Lots during the manufacturing process. `TypeError: unsupported operand type(s) for //: 'NoneType' and 'int'` **Cause:** This error occurs because the quantity field is undefined when Generate Serials/Lots is triggered, the quantity field is not being passed in the context, and its value is undefined, which is leading to a division by [none](https://github.com/odoo/odoo/blob/18.0/addons/stock/models/stock_move.py#L993). **Solution:** To fix this, we added the stock move’s demand quantity as a fallback.This ensures the quantity field value is present and its value correctly passed during lot generation. opw-4763600 Community: https://github.com/odoo/odoo/pull/209860
Online bank connections are no longer incorrectly marked as payment-enabled when they should not be. The change also cleans up affected existing connections and adds checks to help prevent the issue from returning.
Original PR description
Due to an overly restrictive condition, all online account connections were being marked as payment enabled/activated, even when they shouldn't be. This commit removes the faulty condition and introduces a small test to validate the correct behavior. Additionally, a fallback mechanism has been added to clean up improperly configured connections by removing the incorrect payment_activated flag where needed. no task id
This fix makes Odoo save the invoice sending time before contacting the Mexican e-invoicing provider. If a connection issue happens during sending, retries reuse the same timestamp, reducing duplicate CFDIs with slightly different dates for Mexican customers.
Original PR description
### Background In https://github.com/odoo/enterprise/pull/85026 we changed the behaviour of `l10n_mx_edi_post_time` so that it gets set during the CFDI sending process, rather than when the invoice…
### Background In https://github.com/odoo/enterprise/pull/85026 we changed the behaviour of `l10n_mx_edi_post_time` so that it gets set during the CFDI sending process, rather than when the invoice is posted. This was needed to ensure that the post time both reflects the sending time and is re-used if the invoice needs to be re-sent. ### Bug description Since then, several Mexican customers have reported that some CFDIs are sent duplicated, with a difference of a few seconds in the CFDI's Fecha. ### Analysis A disconnection might occur during sending of the CFDI. In that case, the PAC will process the CFDI, but in Odoo the transaction will be rolled back, and the `l10n_mx_edi_post_time` will be lost. When Odoo re-sends the CFDI, it will take a new `l10n_mx_edi_post_time`. ### Solution Commit before performing the API call so that the `l10n_mx_edi_post_time` gets committed to DB. opw-4780096 Forward-Port-Of: odoo/enterprise#89263 Forward-Port-Of: odoo/enterprise#89117
Delivery barcode scanning now correctly warns users when a scanned location differs from the product's reserved location, especially for lot-tracked products. After the warning, repeating the expected scan sequence confirms the change, helping prevent accidental inventory movements while still allowing intentional corrections.
Original PR description
Issue ----- The ticket raises 2 issues products tracked by lots and stored in a specific location: 1. Scanning Location > Lot overrides the reserved location without asking the user for confirmation…
Issue
-----
The ticket raises 2 issues products tracked by lots and stored in a specific location:
1. Scanning Location > Lot overrides the reserved location without asking the user for confirmation
2. Scanning Location > Product > Lot should first produce a warning then, if repeated, override the reserved location with the scanned one
Setup & issue reproduction
-----
- Enable in settings
- Lots & Serial Numbers
- Storage Locations
- Create 2 storage locations Shelf1 & Shelf2
- Create a product Prod tracked by lots
- Create a lot Lot1 of Prod in location Shelf2
- Go to Inventory > Configuration > Operations Types > Delivery Orders
- In "Barcode App" page, set "Source Location" to "Mandatory Scan"
- Create a new delivery for Prod, set it as To-Do
- Open the delivery in barcode
To reproduce issue 1:
- Scan Shelf1
- Scan Lot1
--> No warning, the user can validate the transfer
To reproduce issue 2:
- Scan Shelf1
- Scan Prod1
- Scan Lot1
--> You get a warning & repeating the steps doesn't work as the warning suggests
Problem analysis
-----
#### TLDR
**The current behaviour is flawed. The warning is for when there is a reserved quantity so the check should happen in `updateLine` and not `createNewLine`. Also, there is a confusion with `needSourceConfirmation` serving for both the need for a warning and indicating the user has been warned. These should be 2 separate flags.**
List of tested flows (with fix) can be found [here](https://github.com/odoo/enterprise/pull/87740#issuecomment-3004459646).
#### Warning popup
The warning popup happens thanks to the check for matching of locations which happens in `createNewLine`
https://github.com/odoo/enterprise/blob/5d10fb2c734d1379c1415f683f3c5ab0620d425b/stock_barcode/static/src/models/barcode_picking_model.js#L51-L57
but not in `updateLine`. This is incorrect as the warning is meant to protect changing the location of an *existing* line. Since it has no reason to be in `createNewLine`, we can move it from there to `updateLine`.
#### Setting the warning flag
When scanning a product after a wrong location, the flag value can be changed in 2 parts of the code...
1. In `_findLine`, where we iterate over the existing lines and, for each, check whether it can be taken from the current location (using `lineCanBeTakenFromTheCurrentLocation`)
https://github.com/odoo/enterprise/blob/cf13e6b102ad33ace724b5ffd28d508158db2d15/stock_barcode/static/src/models/barcode_model.js#L1351
2. In `createNewLine` (`updateLine` after fix) where we check if we need to warn the user before setting the flag to false
https://github.com/odoo/enterprise/blob/cf13e6b102ad33ace724b5ffd28d508158db2d15/stock_barcode/static/src/models/barcode_picking_model.js#L49
#### lineCanBeTakenFromTheCurrentLocation problems
https://github.com/odoo/enterprise/blob/cf13e6b102ad33ace724b5ffd28d508158db2d15/stock_barcode/static/src/models/barcode_picking_model.js#L188-L191
The condition only works for one "acceptable" use flow. Updating the condition wouldn't make much sense, because there is no way to make en exhaustive list of "acceptable" use flows (e.g. adding X unrecognised scans between the location and product scan). The domain of "acceptable" use flows is too large for a simple condition.
We set the flag to true only for "acceptable" use flows. This is the opposite of what we want. We don't want to warn the user when they scan again using an "acceptable" flow.
We `return false` although there is a line we want to take from. This tells `_findLine` that no line can be taken, leading `processBarcode` to create a new line instead.
https://github.com/odoo/enterprise/blob/cf13e6b102ad33ace724b5ffd28d508158db2d15/stock_barcode/static/src/models/barcode_picking_model.js#L192-L193
Setting the flag to false here doesn't make sense, since only non "acceptable" flows lead to here.
We can simplify the behaviour here to simply set the flag to true and not do anything else in this block. This is possible thanks to
https://github.com/odoo/enterprise/blob/cf13e6b102ad33ace724b5ffd28d508158db2d15/stock_barcode/static/src/models/barcode_picking_model.js#L183-L184
which ensures that we are in the case of a mismatch of locations with an existing line. We don't return in here because a line was found so the closing return of the function suffices.
The reason why we want to return true here even when there is a mismatch is because we want the code to try to edit the line. It is up to `updateLine` to ensure no line needing confirmation will be edited. This change means we will have to make adaptations to other parts of the code that were written with the previous behaviour in mind.
#### Updating the condition in `updateLine`
After applying the above change, we have a problem with the condition in `updateLine`. If we set the flag to false when warning the user, we get the following behaviour when scanning the product:
- `lineCanBeTakenFromTheCurrentLocation` sets the flag to true then
- `updateLine` sees that the flag is true, it will warn the user and set the flag back to false.
We have to change how `updateLine` checks if it has to warn the user to avoid this logical loop. We want to warn the user using some combination of the following conditions
1. the location of the line we are trying to update doesn't match with the scanned location (`needSourceConfirmation` is true)
2. the user has been warned (we use a new `askedSourceConfirmation` flag with the same structure as `needSourceConfirmation`)
3. the scanning sequence is an "acceptable" confirmation one (the new `isConfirmationSequence` function)
Using these, we can define 2 scenarios which require a user warning:
A. The locations don't match and the user hasn't been warned yet => 1 AND (NOT 2)
OR
B. The locations don't match, the user has been warned but the scanning sequence isn't "acceptable" => 1 AND 2 AND (NOT 3)
If we are in either scenario, we warn the user and set 2 to true. If both A and B are false, we can update the line and reset both 1 and 2 to false.
#### Example of a simple flow with flag values
- Initial values
> 1 = false, 2 = false, 3 = false
> A = 1 AND (NOT 2) = false, B = 1 AND 2 AND (NOT 3) = false
- Scan wrong location
- Scan product => 1 is set to true
> 1 = true, 2 = false, 3 = true
> A = 1 AND (NOT 2) = true, B = 1 AND 2 AND (NOT 3) = false
- The user gets a warning because A is true => 2 is set to true
>1 = true, 2 = true, 3 = true
> A = 1 AND (NOT 2) = false, B = 1 AND 2 AND (NOT 3) = false
- Scan wrong location
- Scan product => 1 is set to true
> 1 = true, 2 = true, 3 = true
> A = 1 AND (NOT 2) = false, B = 1 AND 2 AND (NOT 3) = false
- The line is succesfully updated because both A and B are false
#### Arbitrary limitation of condition 3 in implementation
We arbitrarily decide to only accept 3 flows for location confirmation.
>this.scanHistIsProd(0) && this.scanHistIsLoc(1) && !line.lot_id ||
>this.scanHistIsLot(0) && this.scanHistIsLoc(1) ||
>this.scanHistIsLot(0) && this.scanHistIsProd(1) && this.scanHistIsLoc(2)
This is to avoid possibly costly computations. Imagine the user gets the warning message. They scan the location again. Then, instead of scanning the product, they scan an unrecognised barcode. After this, they scan the product. Adding this specific case would be easy. But what if the unrecognised scan happens multiple times? Or they scan many products in the meantime? We would have to go through the whole scanning history to see if we can find the "Wrong Location > Product" scanning sequence twice (a first time raising the warning, the second confirming). And what if the first time didn't raise the warning but simply confirmed an existing line?
The domain of possible use cases is hard to formally define. Instead, we can make the reasonable assumption that when prompted the warning, the user will simply rescan "Wrong Location > Product".
-----
Ticket:
opw-4731237