Thursday, March 26, 2026
17 changes · saas-18.3
Resolved issues and error corrections
This update resolves an issue where Field Service Reports generated for multiple tasks sometimes produced duplicate PDF files. The fix ensures that reports are generated correctly, avoiding the creation of redundant files. This improves the reliability of report generation for users.
Original PR description
### Issue: When we try to print the field service report on multiple tasks, some with worksheets, then everything is duplicated in the PDF. ### Steps to reproduce: - Install `industry_fsm` and `sale`…
### Issue: When we try to print the field service report on multiple tasks, some with worksheets, then everything is duplicated in the PDF. ### Steps to reproduce: - Install `industry_fsm` and `sale` - Create two tasks with the same customer - Add timesheet, products and save a worksheet on one of them (the goal is to have titles on two different pages) - In list view select both tasks and click Report > Field Service Report - The downloaded PDF has the report twice ### Cause: When printing for several records then `_render_qweb_pdf_prepare_streams()` tries to split the document. If the document has more pages than the number of records [we fetch the "Outlines"](https://github.com/odoo/odoo/blob/55a58571fbfa6a6bb0edacd6f9676382cc23630b/odoo/addons/base/models/ir_actions_report.py#L938-L954). These are the biggest sections in the document. In our case these sections are the `<h2>` tags, as there are no `<h1>`: [the main title](https://github.com/odoo/enterprise/blob/6c4b88a1dfe245a63a424e3f51ff803e51ccde61/industry_fsm/report/worksheet_custom_report_templates.xml#L31-L33), [the Timesheet section title](https://github.com/odoo/enterprise/blob/6c4b88a1dfe245a63a424e3f51ff803e51ccde61/industry_fsm/report/worksheet_custom_report_templates.xml#L39), etc. Then we check the pages where these titles are displayed; if we get the same number of pages as the number of records, we use them to split the report. If not, then we [render the report for each record individually](https://github.com/odoo/odoo/blob/55a58571fbfa6a6bb0edacd6f9676382cc23630b/odoo/addons/base/models/ir_actions_report.py#L974-L976), add them to `collected_streams`. Then add the initial report generated on the recordset and return. These streams are later merged into one, which explains the duplication: - Task 1 report individually generated - Task 2 report individually generated - Report of the recordset containing the two first reports ### Solution: The issue was introduced by [this commit](https://github.com/odoo/odoo/commit/7fc1ebd4466a2d9b4a48dfe86332b5844026c4fc) which implements the individual generation without returning. So the individual documents will always be followed by the recordset document. This commit adds the return directly after the individual reports generation. opw-6032935 Forward-Port-Of: odoo/odoo#255581
This update corrects a technical error that prevented Point of Sale sessions from closing properly in the German localization (l10n_de_pos_cert). The fix involves renaming a method to ensure correct cash move formatting, resolving a problem that impacted POS functionality. This ensures seamless POS operations for our German-speaking users.
Original PR description
**Steps to Reproduce:** 1. Start a new Point of Sale session from the Odoo backend. 2. Create and validate a POS order to ensure the session contains at least one transaction. 3. In the POS…
**Steps to Reproduce:** 1. Start a new Point of Sale session from the Odoo backend. 2. Create and validate a POS order to ensure the session contains at least one transaction. 3. In the POS interface, open the menu (☰ icon) in the top-right corner. 4. Navigate to the Cash In/Out functionality. 5. Perform a cash operation: - Select either Cash In or Cash Out - Choose a Category Reason - Select a Type Reason - Confirm the operation 6. Attempt to close the POS session. **Issue:** In version saas-18.2, an error occurs when closing the POS session because the name of the cash move (in the Cash Register) is incorrect. It should be formatted as: `Hauptmarkt/00006-out-category reason-reason` However, it is currently generated as: `Hauptmarkt/00006-out-reason` This happens because the method `"_prepare_try_cash_in_out_payload"` in "l10n_de_pos_cert" is not called due to an incorrect method name. **Solution:** The issue is resolved by renaming the method to the correct name `"_prepareTryCashInOutPayload"`. This ensures the proper method is invoked, generates the correct cash move name, and allows the POS session to close successfully. opw-6059143 Forward-Port-Of: odoo/enterprise#111597
This update ensures Odoo correctly processes invoices following the PEPPOL BIS3 standard (SE-R-005). Previously, this rule was missing, and this fix adds it to the newer helper functions, ensuring compliance with industry standards for electronic invoice processing. This improves the accuracy and reliability of our accounting integrations.
Original PR description
After this commit 9cb237d, the rule was added, but from 18.0 and upper the old helps has been deprecated and removed on saas~18.4. With this commit, we add the rule also to the new helpers. OPW-5881918 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#255870
This update fixes an issue where the expiration date on stock moves wasn't correctly updated when switching between lots. Now, the system accurately reflects the expiration date based on the lot being used, ensuring accurate tracking of perishable inventory. This improves inventory management and reduces the risk of expired products.
Original PR description
Steps to reproduce: - Enable "Expiration Dates" in Inventory settings - Create a storable product "P1" - Add 10 units with "Lot 1" - Enable expiration dates on product P1 - Add 10 units with "Lot 2"…
Steps to reproduce: - Enable "Expiration Dates" in Inventory settings - Create a storable product "P1" - Add 10 units with "Lot 1" - Enable expiration dates on product P1 - Add 10 units with "Lot 2" and set an expiration date - Create a delivery for 10 units of P1 - Mark as "To Do" - Open the move line -> "Lot 1" is automatically reserved - Change the lot from "Lot 1" to "Lot 2" -> The expiration date is not updated automatically - Save and reopen the move line -> The expiration date is correctly set - Change again to "Lot 1" - Save and reopen the move line -> The expiration date is not reset and incorrectly keeps the value from "Lot 2" Cause: The expiration date was only computed based on `lot_id`, ignoring the `quant_id` used during reservation. Additionally, the value was not reset when switching to a lot without an expiration date. Solution: - Add `quant_id` to the compute dependencies - Compute the expiration date based on `quant_id.lot_id` - Explicitly set an expiration date to today when the use_expiration_date product is set to True and the lot doesn't have an expiration date. Result: The expiration date is now correctly updated and cleared when changing lots on stock move lines. opw-5999294 Forward-Port-Of: odoo/odoo#254610
This update ensures that when an employee leaves, their outstanding appraisal schedules are automatically cancelled, preventing confusion and outdated data. It also removes the employee from appraisal roles and archives their personal goals, streamlining the system and improving data accuracy. This resolves an issue where departing employees continued to appear on appraisal schedules.
Original PR description
Currently, when an employee leaves the company, their future appraisals remain active and can still be completed. This fix ensures that, upon employee departure: - all future appraisals are removed - the employee is removed from appraisals where they are an appraiser - all their personal goals are archived task: 6036427 Forward-Port-Of: odoo/enterprise#111589
This update resolves an issue where the POS scale wasn't accurately displaying product weights due to a change in how the IoT box sends scale data. The fix ensures that the POS correctly reads and displays the weight from the physical scale, improving the accuracy of order processing. This change impacts the IoT scale integration for POS systems.
Original PR description
Steps to reproduce - Use a localisation other than a european one (l10n_eu_iot_scale_cert must not be installed) - Setup the scale for the POS - Open the POS - Add a product to be weighted by scale to the order - Add product to the physical scale - The displayed weight is always 0 Cause: New versions of the IoT box uses the field result to return the scale measure instead of value. Fix for version 18.0 and its intermediary versions. [opw-5990467](https://www.odoo.com/odoo/project/49/tasks/5990467) Forward-Port-Of: odoo/enterprise#111963
This update optimizes how the system loads partner data for self-ordering, addressing performance issues when partners had extensive information. By only loading essential data, the change reduces loading times and improves the overall responsiveness of the self-ordering process.
Original PR description
Partner data loading for self-ordering was not optimized, leading to performance issues when the partner had a lot of data. This commit optimizes the partner data loading by only loading the necessary fields for self-ordering. Forward-Port-Of: odoo/odoo#253563
This update fixes an issue where employee pay calculations were inaccurate when using paid leave. The change ensures that worked days are correctly attributed to a single employee's payslip, preventing incorrect wage calculations for UAE employees with attendance-based work entries. This improves the accuracy of payroll processing.
Original PR description
### Steps to reproduce: - Install the l10n_ae_hr_payroll module. - Configure at least two employees, who'll use the UAE Monthly pay structure. - On at least one of the employees, set the work entry…
### Steps to reproduce: - Install the l10n_ae_hr_payroll module. - Configure at least two employees, who'll use the UAE Monthly pay structure. - On at least one of the employees, set the work entry source to attendance. - Register a paid leave time off entry, for the employee whose work entry source is set to attendance. - Compute a payslip batch using the UAE Monthly pay structure. - Go to the payslip of the employee with the work entry source set to attendance and compute the sheet again. - The 'Paid Leave' salary rule results, will change given that the computation of the field l10n_ae_hourly_wage is different when the computation is done for batches and individually. ### Cause: In 'Paid Leave' rule we use l10n_ae_hourly_wage to compute its result and while computing this field we use self.worked_days_line_ids instead of record inside the loop. This leads to an issue when self has more than one payslip it will take into account all the worked days for each payslip for different employees ### Fix: We use record instead of self to avoid taking other payslips into consideration while computing the hourly wage. opw-5979631 Forward-Port-Of: odoo/enterprise#111280
This update resolves an issue where POS orders with both regular sales and settlement lines weren't being properly validated. The change ensures that mixed orders are now correctly blocked during settlement, aligning with the latest 'pos_settle_due' module updates. This improves the accuracy of financial reporting for Saudi businesses using Odoo POS.
Original PR description
# Description of the issue/feature this PR addresses: From saas-18.3 onward, the pos_settle_due module introduced a new method to identify settlement lines. While the old method **isSettleDueLine()**…
# Description of the issue/feature this PR addresses: From saas-18.3 onward, the pos_settle_due module introduced a new method to identify settlement lines. While the old method **isSettleDueLine()** is still there, the new **isAnySettleLine()** covers both order settlement and invoice settlement. This change was not reflected in the Saudi POS EDI integration during forward-porting, which caused incorrect validation when processing POS orders containing both regular sale lines and settlement lines. # Current behavior before PR: - Orders containing a mix of new sale lines and settlement lines could bypass the intended validation. - The validation logic relied on the old isSettleDueLine() method # Desired behavior after PR is merged: - Update the validation flow to use isAnySettleLine() (when available) to correctly detect settlement lines. - Prevent validation of POS orders that contain both settlement lines and new sale lines. - Ensure compatibility with newer versions of the pos_settle_due module and restore the intended settlement validation behavior. - Test case to ensure no regression on this feature I confirm I have signed the CLA and read the PR guidelines at [www.odoo.com/submit-pr](http://www.odoo.com/submit-pr)
This update fixes an issue where invoices with exchange differences and exchange accounts as write-offs were incorrectly fully reconciled even when the user chose to keep the invoice open for partial payment. The fix ensures that the system accurately handles payment registration and reconciliation when an exchange account is used, preventing incorrect accounting entries.
Original PR description
Currently, if a user selects an exchange difference account as a write-off but then decides to keep the invoice open, the system still fully reconciles the invoice. Steps to reproduce: - Create an…
Currently, if a user selects an exchange difference account as a write-off but then decides to keep the invoice open, the system still fully reconciles the invoice. Steps to reproduce: - Create an invoice in foreign currency - Click 'Register Payment' - Select company currency - Change the amount to a lower one - Select 'Mark as fully paid' - Add the exchange difference loss/gain account as write off account - Select 'Keep open' - Click 'Create payment' Issue: Even though the user selected the option to create a partial payment and keep the invoice open, it is totally reconciled with a difference booked in the selected exchange account. Analysis: This occurs because the use of the exchange account as write off account trigger a specific flow used in localization where a writeoff is not allowed. Once the payment registration process is ongoing, the system does not check that user kept the same choice on how to handle the payment difference. opw-5468052 Forward-Port-Of: odoo/odoo#254479 Forward-Port-Of: odoo/odoo#251965
This update resolves an issue where requests to localhost weren't correctly processed, preventing stable communication with printers running on the same device. By switching to 'loopback' TargetAddressSpace, the system now reliably connects with locally-installed printers and other devices, simplifying setup and improving functionality. This enhancement ensures seamless operation for users relying on local USB/network printers.
Original PR description
This commit backports support for loopback TargetAddressSpace from 19.0. Before: LNA requests to localhost (127.0.0.1) used "local" TargetAddressSpace, which caused communication issues (CORS/PNA restrictions). After: Requests to localhost now correctly use "loopback" TargetAddressSpace, allowing proper communication with locally running devices. Impact: Enables stable communication with USB/network printers running on localhost without requiring IoT devices. Reference: https://github.com/odoo/odoo/pull/250972 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#255648 Forward-Port-Of: odoo/odoo#255540
This update resolves an issue where dropship orders weren't accurately reflecting delivered quantities. The fix adjusts how the system tracks moves during dropship transactions, ensuring the correct quantity is displayed on sale order lines. This ensures accurate order fulfillment and reporting.
Original PR description
**Steps to reproduce:** - Make sure you have 3 companies (comp A, B and C) - Navigate to Settings/Users & Companies/ Companies - for each company in the 'Inter Company Transactions' tab: check…
**Steps to reproduce:** - Make sure you have 3 companies (comp A, B and C) - Navigate to Settings/Users & Companies/ Companies - for each company in the 'Inter Company Transactions' tab: check 'generate Sale Orders', 'generate purchase orders' and 'synchronize Deliveries to your receipts' then select a warehouse and a receipt operation type From company A - create a storable product - in the Purchase tab, set the company B as a vendor From company B - in the Purchase tab of the product, set company C as a vendor From company C - set a positive on hand quantity From Company A - create a SO for 1 quantity of your product - on the sale order line, unhide de route_id column and set it to dropship - confirm the SO and the linked PO From company B - on the SO created with company A as customer (you might need to remove the 'my quotations filter to find it), set the dropship route in the route_id column of the sale order line - confirm the SO and the linked PO From company C - confirm SO created with company B as customer - validate the delivery From company B - validate the dropship **Current behavior:** the quantity delivered on the sale order line is 0 **Expected behavior:** it should be 1 **Cause of the issue:** inside _compute_qty_delivered, we fetch the incoming and outgoing moves using _get_outgoing_incoming_moves() https://github.com/odoo/odoo/blob/b936b64ed0217909ff96a1b28d1370f5064be46a/addons/sale_stock/models/sale_order_line.py#L200 There, for the move of the dropship picking, inside the if condition, move._is_dropshipped_returned() will be True https://github.com/odoo/odoo/blob/b936b64ed0217909ff96a1b28d1370f5064be46a/addons/sale_stock/models/sale_order_line.py#L348-L354 That's because the move is going from transit to transit https://github.com/odoo/odoo/blob/b936b64ed0217909ff96a1b28d1370f5064be46a/addons/stock_account/models/stock_move.py#L186-L195 So it will not be added to the outgoing moves and qty_delivered will stay 0. **fix** is_dropshipped_returned should not prevent the move to be added to the outgoing moves if is_dropshipped() is aslo true (i.e. it's a transit to transit move) opw-5023215 Forward-Port-Of: odoo/odoo#255314 Forward-Port-Of: odoo/odoo#254618
This update resolves an issue where dropship orders weren't correctly reflecting delivered quantities. The fix adjusts how the system tracks moves during dropship transactions, ensuring the correct quantity is displayed on the sale order line. This ensures accurate order fulfillment and reporting for inter-company dropship sales.
Original PR description
**Steps to reproduce:** - Make sure you have 3 companies (comp A, B and C) - Navigate to Settings/Users & Companies/ Companies - for each company in the 'Inter Company Transactions' tab: check…
**Steps to reproduce:** - Make sure you have 3 companies (comp A, B and C) - Navigate to Settings/Users & Companies/ Companies - for each company in the 'Inter Company Transactions' tab: check 'generate Sale Orders', 'generate purchase orders' and 'synchronize Deliveries to your receipts' then select a warehouse and a receipt operation type From company A - create a storable product - in the Purchase tab, set the company B as a vendor From company B - in the Purchase tab of the product, set company C as a vendor From company C - set a positive on hand quantity From Company A - create a SO for 1 quantity of your product - on the sale order line, unhide de route_id column and set it to dropship - confirm the SO and the linked PO From company B - on the SO created with company A as customer (you might need to remove the 'my quotations filter to find it), set the dropship route in the route_id column of the sale order line - confirm the SO and the linked PO From company C - confirm SO created with company B as customer - validate the delivery From company B - validate the dropship **Current behavior:** the quantity delivered on the sale order line is 0 **Expected behavior:** it should be 1 **Cause of the issue:** inside _compute_qty_delivered, we fetch the incoming and outgoing moves using _get_outgoing_incoming_moves() https://github.com/odoo/odoo/blob/b936b64ed0217909ff96a1b28d1370f5064be46a/addons/sale_stock/models/sale_order_line.py#L200 There, for the move of the dropship picking, inside the if condition, move._is_dropshipped_returned() will be True https://github.com/odoo/odoo/blob/b936b64ed0217909ff96a1b28d1370f5064be46a/addons/sale_stock/models/sale_order_line.py#L348-L354 That's because the move is going from transit to transit https://github.com/odoo/odoo/blob/b936b64ed0217909ff96a1b28d1370f5064be46a/addons/stock_account/models/stock_move.py#L186-L195 So it will not be added to the outgoing moves and qty_delivered will stay 0. **fix** is_dropshipped_returned should not prevent the move to be added to the outgoing moves if is_dropshipped() is aslo true (i.e. it's a transit to transit move) opw-5023215 Forward-Port-Of: odoo/enterprise#111632 Forward-Port-Of: odoo/enterprise#111108
This update fixes an issue where global invoices generated from customer invoices weren't correctly using the issued address's zip code in the required XML format for Mexican tax reporting. The change ensures accurate data transmission for compliance with local regulations, preventing potential errors during tax processing. This update impacts the l10n_mx_edi and l10n_mx_edi_extended modules.
Original PR description
**STEP TO REPRODUCE** 1. install l10n_mx_edi_extended. 2. Add an issued address on the customer invoice journal, with a zip code. 3. Create invoices, and create a global invoice with them. 4. download the xml, and notice the field LugarExpedicion is not using the zip from the issued address while it should. opw-5956837 Forward-Port-Of: odoo/enterprise#108732
This update fixes an issue where stock moves weren't correctly split when a quality control check resulted in a partial failure. Specifically, the system was incorrectly calculating the demand for the failed quantity, leading to an inaccurate stock split. This change ensures that stock moves are properly divided when a product fails quality control, improving inventory accuracy.
Original PR description
**Steps to reproduce:** * Install the `quality_control` module. * Create a storable product. * Configure a Quality Control Point: * Set Control per : Quantity. * Set Operation Type to Receipts. * Set…
**Steps to reproduce:** * Install the `quality_control` module. * Create a storable product. * Configure a Quality Control Point: * Set Control per : Quantity. * Set Operation Type to Receipts. * Set Product to the created product. * Create a Receipt for the product with a demand of 5 units. * Confirm the receipt and mark it as To Do. * Click on the Quality Check button. * Click on Fail and set the failed quantity to 3. * Click on Confirm. **Observed behavior:** * A new stock move is created for the failed quantity. * The original move is split incorrectly: * First move: 2 `product_uom_qty` and 2 `quantity`. * Second move: 2 `product_uom_qty` and 3 `quantity`. * The failed move has a demand of **2** instead of **3**. **Cause:** * Clicking on *Quality Check* triggers `check_quality`, which opens the wizard `action_open_quality_check_wizard`: https://github.com/odoo/enterprise/blob/90567af2703a3928c35814a0c4862b4cd98b8432/quality_control/models/stock_picking.py#L79-L82 * Clicking on *Fail* triggers `do_fail`, opening the confirmation wizard: https://github.com/odoo/enterprise/blob/90567af2703a3928c35814a0c4862b4cd98b8432/quality_control/wizard/quality_check_wizard.py#L85-L88 * Clicking on *Confirm* triggers `confirm_fail`, which calls `_move_line_to_failure_location`: https://github.com/odoo/enterprise/blob/90567af2703a3928c35814a0c4862b4cd98b8432/quality_control/wizard/quality_check_wizard.py#L97 * In `_move_line_to_failure_location`, a new stock move is created for the failed quantity: https://github.com/odoo/enterprise/blob/90567af2703a3928c35814a0c4862b4cd98b8432/quality_control/models/quality.py#L480 * The demand quantity is computed using the minimum of the failed quantity and the move line quantity. * This leads to an incorrect demand of *2* instead of *3*. * However, the move line quantity was already reduced by the failed quantity: https://github.com/odoo/enterprise/blob/90567af2703a3928c35814a0c4862b4cd98b8432/quality_control/models/quality.py#L472 **Fix:** * Ensure that partial failures properly split stock moves with correct `product_uom_qty` and `quantity` values. --- opw-5492095 Forward-Port-Of: odoo/enterprise#112005 Forward-Port-Of: odoo/enterprise#107493
This update resolves a problem preventing SBR tax reports from being submitted correctly. The commit restores a previous date format and simplifies consultant information, ensuring compliance with validation requirements. This ensures accurate tax reporting and avoids submission failures.
Original PR description
Description of the issue this commit addresses: During the tax return flow for the SBR development[^1], we discovered that the date format for the "DateTimeCreation" node had been wrongly readjusted and that the "ProfessionalAssociationForTaxServiceProvidersName" content could be too long due to showing the entire description. Those two issue cause the file to be rejected and make submission impossible. [^1]: https://www.odoo.com/odoo/967/tasks/6034675 --- Desired behavior after this commit is merged: This commit reintroduces the old DateTimeCreation format which is the only one that passes the tests done on the xbrl validation service[^2] and replaces the ProfessionalAssociationForTaxServiceProvidersName's value for the abreviation of the order instead of the entire description. [^2]: https://aansluiten.procesinfrastructuur.nl/site/validaties-digipoort/xbrl-validatie --- task-none Forward-Port-Of: odoo/enterprise#111923 Forward-Port-Of: odoo/enterprise#111817
This update ensures that when scanning barcodes in batches, the system correctly creates a new lot in stock even if the barcode serial number doesn't match the reserved one. This prevents incorrect lot assignments and ensures accurate inventory tracking within the barcode scanning process.
Original PR description
Issue ----- When processing batches in barcode, scanning a BC with a different SN than the reserved one does not lead to creating a new lot in stock. The reserved one is still the one getting taken…
Issue
-----
When processing batches in barcode, scanning a BC with a different SN than the reserved one does not lead to creating a new lot in stock. The reserved one is still the one getting taken regardless of setting.
Steps to reproduce
-----
- Enable GS1 nomenclature, lots & batches
- Go to Inventory > Configuration > Operation Types > Delivery Orders
- Enable Lots/Serial Numbers > Create New
- Create a product
- Barcode 23456789012344
- Tracked by SN
- 1 in stock (SN 1234)
- Create a delivery for the product and add it to a batch
- Open the batch in barcode
- Scan 012345678901234410BATCHSN1
- Confirm the delviery
- Go back to the picking and see the lines' details
> The line used the reserved SN
Cause
-----
The existing line gets matched in `_findLine`
https://github.com/odoo/enterprise/blob/45d3a537c3b2eaccee425d959e89d26229e376cd/stock_barcode/static/src/models/barcode_model.js#L1085
because none of the conditions before
https://github.com/odoo/enterprise/blob/45d3a537c3b2eaccee425d959e89d26229e376cd/stock_barcode/static/src/models/barcode_model.js#L1402
get matched. This is unexpected but necessary for batches, as it ensures barcode correctly swaps to the correct picking in the batch. If the line was not matched we would be creating a new line in the same picking than the last scanned line, regardless of which picking the reservation is made in.
Because a line is matched, we have to force its' `lot_id` to `false` so that the new one gets created (`lot_name` is used for display but `lot_id` takes precedence).
-----
Ticket:
opw-5216921
Forward-Port-Of: odoo/enterprise#111799
Forward-Port-Of: odoo/enterprise#109671