Friday, June 12, 2026
24 changes · saas-19.1
Enhancements to existing features
This update introduces a new 'PINT' layer to enhance the processing of UBL (Universal Business Language) invoices, aligning with European standards. This layer facilitates compliance with regulations like CEN-EN16931 and PEPPOL, ensuring accurate and reliable exchange of invoice data. It improves the handling of invoice data formats for international trade.
Original PR description
Add the layer PINT between UBL and BIS3. task: 5890887 Forward-Port-Of: odoo/odoo#260058
This update introduces a new rule for calculating superannuation guarantee, aligning with Australian Tax Office (ATO) requirements. Specifically, it now separates 'Qualifying Earnings' (QE) from regular time earnings, streamlining superannuation contributions from July 1st, 2026. This ensures accurate and compliant payroll processing for Australian businesses.
Original PR description
Added new salary rule for Qualifying earnings. Super Streams now per payrun. task-6012509 Forward-Port-Of: odoo/enterprise#117367
This update automatically refreshes KYC (Know Your Customer) status information for French PDP (Payment Distribution Platform) users. Previously, users had to manually update this status. Now, the system receives a notification from IAP and updates the status automatically, streamlining the process.
Original PR description
Before this commit, user needed to manually refresh de kyc status, with this commit, the status will be changed when receiving the notification from IAP task-6271596 Forward-Port-Of: odoo/odoo#268528
This update enhances the payment confirmation screen in the Point of Sale system. Now, customers see a "Processing..." message during payment finalization and a visual checkmark with the amount paid upon successful completion. The screen also removes distracting warning notifications and utilizes a reusable animation, creating a smoother and more informative experience.
Original PR description
In this commit : - Show "Processing..." text while payment finalization is running - Show animated success checkmark and "Amount Paid" once processing completes - Remove warning notification when clicking during processing - Extract shared checkmark animation into reusable template - Update tour tests to verify the success state Task:6246377 Forward-Port-Of: odoo/odoo#267635
Resolved issues and error corrections
This update resolves an issue where report customizations made in Odoo's Studio were incorrectly applied to shared layouts, leading to unexpected behavior and potential rendering problems. The fix ensures that report edits are now stored within the specific report document view, preventing these issues and improving Studio's reliability.
Original PR description
Report edits could be applied on shared layouts such as web.basic_layout instead of the report-specific document view. This caused Studio customization diffs to affect unrelated reports and could…
Report edits could be applied on shared layouts such as web.basic_layout instead of the report-specific document view. This caused Studio customization diffs to affect unrelated reports and could also lead to rendering errors when report-specific fields were evaluated in a different report context. The issue occurred because content was inserted directly into the shared layout article section instead of the nested report document view. Steps to reproduce: 1. Open Studio on any module and create or edit a report. 2. Select any of the External, Minimal, or Blank report types. 3. Add content to the report body and save the report. 4. Open another module and create a report using the same report type. 5. Observe that the previous customization is already present. Before this fix, the generated diff could inherit from web.basic_layout. After this fix, body edits are kept inside the report-specific document view. Related Ticket: opw-6245485 Forward-Port-Of: odoo/enterprise#118880
This update resolves an issue where both units of a quality check would be incorrectly moved to the failure location after a partial failure. The fix ensures that the destination of move lines is accurately determined based on remaining demand, preventing unintended movement to the failure location. This improves the reliability of the quality control process.
Original PR description
Version: ---------- - 18.0+ Steps to reproduce: ------------------- 1. Install *quality_control* module. 2. Go to *Settings* and enable *Storage Locations*. 3. Open Quality module go to the Quality…
Version:
----------
- 18.0+
Steps to reproduce:
-------------------
1. Install *quality_control* module.
2. Go to *Settings* and enable *Storage Locations*.
3. Open Quality module go to the Quality control -> Quality points
4. Create a *Quality Point* with:
* *Product* set.
* *Control per* set to *Quantity*.
* *Operation* set to *Receipts*.
* *Failure Location* set to *WH/Stock/Shelf1*.
5. Create a *Receipt* with demand of *2 units* for the product used in QP.
6. Mark the quality check as *To Do*.
7. Update the *Done Quantity* to *1*.
8. Open the quality check and click *Fail*.
9. Update the *Done Quantity* back to *2* and save.
10. Open the quality check again, click *Pass*, and validate the receipt.
11. Open the *Detailed Operations* to inspect move lines.
Issue:
------
* Both units (failed and passed) are moved to the *failure location*.
Cause:
------
When a user fails a move line via the QC wizard, the flow is:
do_fail() → show_failure_message() → confirm_fail()
→ check._move_to_failure_location(failure_location_id, failed_qty)
Inside `_move_to_failure_location`, when `failed_qty == move_line.quantity`,
the condition:
https://github.com/odoo/enterprise/blob/a33f580455a54a81d89a848f7b493d9dcc9ba2b2/quality_control/models/quality.py#L458
e.g. 1 == 1
was True even when `move.product_uom_qty = 2` (demand still 2). It only
compared the done quantities, ignoring that unfulfilled demand remained.
As a result, `move.location_dest_id` was set to the failure location.
Later, when the user increases the quantity from 1 to 2 on the move form,
the flow is:
_set_quantity → process_increase → _set_quantity_done → _prepare_move_line_vals
In `_prepare_move_line_vals` :
'location_dest_id': self.location_dest_id.id,
https://github.com/odoo/odoo/blob/47bf284e1e9d8be0d4255418e0a3f67c74fa5114/addons/stock/models/stock_move.py#L1688
The new move line inherits `move.location_dest_id` directly, which at this
point is already the failure location.
When the user then calls `do_pass()` on the second unit, `do_pass()` only
writes `quality_state = 'pass'` and never touches `location_dest_id`. So
the second (passed) move line silently retains the failure location.
Solution:
---------
Add the guard `move.product_uom_qty <= move_line.quantity` to the condition
so the entire move's destination is only redirected when there is genuinely
no remaining unfulfilled demand:
When demand > done qty, the else-branch runs instead: it reduces the
original move's demand and creates a new separate move pointing to the
failure location, leaving the original move's `location_dest_id` pointing
to stock. Any subsequent move lines created on the original move therefore
correctly inherit the stock destination.
---
opw-6080871
Forward-Port-Of: odoo/enterprise#120175
Forward-Port-Of: odoo/enterprise#112859This update fixes an issue where invoices for French public entities in DROM regions (like Martinique) weren't correctly formatted for Chorus Pro. The system was incorrectly using VAT numbers instead of the required SIRET, preventing proper invoice routing. This ensures accurate data transmission to Chorus Pro for all French customers.
Original PR description
When invoicing a French public entity through Chorus Pro, the SIRET of the recipient was written in the UBL PartyIdentification only when the partner country was France (country_code == 'FR'). Partners located in a DROM (overseas department/region) have a real French SIRET too, but their ISO country code failed the check, so the SIRET was dropped and replaced by the VAT number. This cause the invoice to not be routed correctly in Chorus Pro. Steps to reproduce: - Setup a french company and connect it to Peppol - Create a customer for a public entity located in Martinique, with its SIRET, Peppol address 0009:11000201100044 (Chorus Pro SIRET) and BIS Billing 3.0 format. - Issue and send an invoice to this customer via Peppol. - Open the generated *_ubl_bis3.xml: AccountingCustomerParty PartyIdentification/ID holds the VAT instead of the SIRET, and Chorus Pro never receives the invoice. opw-6153868 Forward-Port-Of: odoo/odoo#269364 Forward-Port-Of: odoo/odoo#268519
This update fixes an error in the vehicle contract report that was incorrectly adding recurring costs. The issue stemmed from overlapping database queries, leading to inflated totals. The change replaces multiple joins with a single, more efficient query to ensure accurate cost calculations.
Original PR description
Steps to reproduce: ------------------- 1. Install Fleet with demo data. 2. Create a contract for a vehicle (A) with a recurring cost of 1000 and "Monthly" frequency. 3. Go to Reporting > Costs and…
Steps to reproduce: ------------------- 1. Install Fleet with demo data. 2. Create a contract for a vehicle (A) with a recurring cost of 1000 and "Monthly" frequency. 3. Go to Reporting > Costs and verify the monthly cost (it shows 1000). 4. Create another contract for the same vehicle (A) with a recurring cost of 50 and "Monthly" frequency. 5. Check the monthly cost again. Issue: ------ The reported cost is incorrect. Instead of 1050 (1000 + 50), it shows 2100. Cause: ------ The query uses multiple LEFT JOINs on the contract table, including: https://github.com/odoo/odoo/blob/9ca36dbe53692309bac84329de3b54a1c510cce0/addons/fleet/report/fleet_report.py#L103 These joins overlap and produce duplicate rows for the same vehicle and month, which results in inflated cost totals. Solution: --------- Replace the multiple LEFT JOINs with a single LATERAL join. This ensures the contract table is processed once per vehicle per month and avoids duplication, resulting in correct totals. **Before:** <img width="940" height="609" alt="image" src="https://github.com/user-attachments/assets/e5b3e747-1135-4674-97c9-4e4fd9986dfd" /> **After:** <img width="1053" height="590" alt="image" src="https://github.com/user-attachments/assets/f0df3819-07fb-4de5-aab3-5b4c6f10d213" /> opw-6024132 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update fixes an error in the Colombian DIAN invoice processing flow. Previously, the system incorrectly flagged invoices due to a mismatch between UTC time and Bogota's local time. The fix ensures invoices are validated correctly based on Colombia's local time zone, preventing processing issues.
Original PR description
**Steps to reproduce:** * Install `l10n_co_edi` module with DEMO DIAN mode enabled. * Go to Accounting > Vendor > Bills and create a new bill. * Select any Colombian partner different from…
**Steps to reproduce:** * Install `l10n_co_edi` module with DEMO DIAN mode enabled. * Go to Accounting > Vendor > Bills and create a new bill. * Select any Colombian partner different from `Consumidor Final`. * Set the invoice date to 6 days in the past. * Select the DIAN Support Documents journal and a product with UNSPSC category. * Confirm the bill and click `Send Support Document to DIAN` after 5 PM Colombia time. **Observed behavior:** * An error is raised stating the issue date cannot be older than 6 days or more than 6 days in the future, even though the invoice date is within the allowed window in Colombia local time. **Cause:** * The date window validation in `_check_move_configuration` used `fields.Datetime.now()` which returns UTC time. Since Colombia is UTC-5, after 5 PM local time the UTC clock has already rolled over to the next calendar day, making a 6-day-old invoice appear 7 days old and failing the validation incorrectly. **Fix:** * Convert the current UTC datetime to the `America/Bogota` timezone and extract its local date before computing the allowed date window. * Compare directly against `move.invoice_date` (a `date` field) instead of using `fields.Datetime.to_datetime()`, keeping the comparison consistent as `date` vs `date`. opw-6011502 Forward-Port-Of: odoo/enterprise#120011 Forward-Port-Of: odoo/enterprise#115256
This update fixes an issue where the shop floor displayed component quantities with excessive decimal places, leading to inaccurate readings. The fix addresses a floating-point calculation error that occurred when combining lot quantities, ensuring more precise and reliable data display for finished product tracking.
Original PR description
**Issue** In the shop floor, floating-point values may display excessive decimals. **Steps to reproduce** - Create a BoM for a product, with a component tracked by lots - Set the component to be…
**Issue** In the shop floor, floating-point values may display excessive decimals. **Steps to reproduce** - Create a BoM for a product, with a component tracked by lots - Set the component to be consumed in a work order operation - Create several lots for the component, per ex 2: - LOT01 with 16.528 units - LOT02 with 10,000.00 units - Create an MO for 220.800 units of the finished product - Click on the shopfloor icon - Click to register the component consumption for the component. - Choose the first lot - Then choose the remaining units from the second lot -> This will display the quantity consumed as 220.79999999999998, even if the decimal accuracy is set to only 2 digits. **Cause** Since, there are 2 `moveLines`, one for each lot, the getter `quantityDone` add 2 floating point together: https://github.com/odoo/enterprise/blob/d7ab7ee1287342638006e290ede20b955aae8370/mrp_workorder/static/src/mrp_display/mrp_record_line/stock_move.js#L63-L69 inducing a floating-point precision error. The result is rendered directly in the XML template: https://github.com/odoo/enterprise/blob/d7ab7ee1287342638006e290ede20b955aae8370/mrp_workorder/static/src/mrp_display/mrp_record_line/stock_move.xml#L8-L14 without rounding. opw-6243804 Forward-Port-Of: odoo/enterprise#118976
This update fixes a discrepancy in pricing displayed for self-order items, ensuring prices align with tax calculations and pricelists. Previously, prices varied between the product selection and the order cart, especially when using takeout presets. Now, self-order prices accurately reflect tax rules and are consistent across the entire ordering process.
Original PR description
Self-order showed one price on product cards / product page and another after adding to the order, when a preset fiscal position (e.g. take-out) changed taxes. The UI used template-only pricing and…
Self-order showed one price on product cards / product page and another after adding to the order, when a preset fiscal position (e.g. take-out) changed taxes. The UI used template-only pricing and sometimes skipped fiscal position on tax computation. Steps to reproduce: ------------------- * Create a fiscal Position (e.g. takeout) * Create a Taxe for that Fiscal Positions replacing the default Taxe (e.g. 0%) * Create a pricelist with a formula increasing the price by the same % as default Taxe (e.g. 15%) * Enable Self-Ordering for a Restaurant * In the takeout Presets, set our Pricelist and Fiscal Positions * Open the Mobile Menu of the Restaurant and add a product that has variants (e.g Pizza VG) > Observation: Price on product selection is different from price in cart Why the fix: ------------ We now make self-order use the same rules as an actual order: default variant for template-only display, pricelist from pos.order first (what setPreset and the session already maintain), fiscal position from the order or the preset everywhere taxes are derived, and correct tax inputs on the product page (price, pricelist, fiscalPosition, variant). Order line tax preparation now uses that same order-or-preset fiscal position, so remapped taxes apply to lines the same way they apply to the prices shown while browsing. opw-6120097 Forward-Port-Of: odoo/odoo#261535
This update resolves an issue preventing valid vendor bills from being created when using the GT company VAT affiliation. The system was incorrectly filtering document types based on company affiliation, impacting purchase workflows. This change ensures all legally valid document types can be used for purchase bills.
Original PR description
Currently, the system restricts fiscal document types for both sales and purchases based on the company’s VAT affiliation, which prevents valid vendor bills from being recorded. **Steps to…
Currently, the system restricts fiscal document types for both sales and purchases based on the company’s VAT affiliation, which prevents valid vendor bills from being recorded. **Steps to reproduce:** - Install the `l10n_gt_edi` module and switch to a `GT company`. - Navigate to Accounting > Vendors > Bills. - Create a vendor bill. - Try to select a document type such as `FPEQ` or `FCAP`. **Observation:** The system hides valid vendor document types (e.g., `FPEQ`, `FCAP`) if they do not match the company’s VAT affiliation. **Root Cause:** At [1], the method `_compute_l10n_gt_edi_available_doc_types` filters document types using the company’s VAT affiliation (`l10n_gt_edi_vat_affiliation`) for all move types. This logic is correct for sales (where the company is the issuer), but incorrect for purchases (where the vendor determines the document type). As a result, valid purchase document types are wrongly excluded. **Fix:** This commit updates the computation logic to: - Apply affiliation-based filtering only for sales (`out_*`). - Bypass the restriction for purchases (`in_*`), allowing all valid document types. This ensures that vendor bills can include any legally valid document type regardless of the company’s affiliation, while preserving the existing restrictions for sales workflows. [1]: https://github.com/odoo/enterprise/blob/7792926504a823590fbbe574a96994002a92fc17/l10n_gt_edi/models/account_move.py#L162-L166 opw-6099863 Forward-Port-Of: odoo/enterprise#113133
This update fixes an issue where barcode scanning incorrectly displayed and managed sale order quantities. The fix ensures that quantities are accurately reflected when using lots, preventing backorders and ensuring correct fulfillment. This improves the reliability of the barcode inventory process.
Original PR description
Currently when user adds adds quantity in barcode using lots it leads to incorrect sale order quantities. ## Steps to replicate: - Install Sales and Barcode (no demo data). - Enable Lots & Serial…
Currently when user adds adds quantity in barcode using lots it leads to incorrect sale order quantities.
## Steps to replicate:
- Install Sales and Barcode (no demo data).
- Enable Lots & Serial Numbers in settings.
- Create Test Product with Tracking by Lots.
- Go to Inventory > Products>Lots & Serial Numbers and create 3 lots for the product.
- Update each lot’s on-hand quantity to 10 from the product page.
- Create and confirm a Sales Order for the product (lines: qty 3 and 2 units).
- Open the delivery in the Barcode app:
- Scan lot 2 > increase qty to 3 using +1 button
- Scan lot 3 > increase qty to 2 using +1 button
- Validate and go to the sale order.
## Observed Behavior:
The sale order delivered quantities are flipped and a backorder is created even though the quantity for the product is satisfied.
## Root cause:
The issue occurs because when a sales order is confirmed, the system defaults to
using lot 1 on the delivery receipt. When a user scans lot 2, the `_processBarcode` function is triggered, which calls `_findLine` at [1] to select the appropriate line on the receipt.
As the loop in `_findLine` iterates through `pageLines` with values like:
```
[{display_name: "Test product", quantity: 3, lot_id: { name: 'lot1' }},
{display_name: "Test product", quantity: 2, lot_id: { name: 'lot1' }}]
```
During the first iteration, `foundLine` is set at [2] for the line with quantity 3 . Since the subsequent if condition is not satisfied, the loop hits the continue block at [3].
On the next iteration, the line with quantity 2 causes `foundLine` to be overwritten at [2], and the continue block is executed again at [3].
This results in the line with quantity 2 being selected as the line to update at the end of the function.
When the user manually increases the quantity to 3, the line that originally required quantity 2 is updated and fulfilled.
Later, when lot 3 is scanned, the line that required quantity 3 is selected for update, and manually increasing the quantity to 2 before validating the order leads to a backorder and causes the delivered quantities to be flipped.
[1]:
https://github.com/odoo/enterprise/blob/81eaeb4b18d849c644160234def6c69013591abe/stock_barcode/static/src/models/barcode_model.js#L1335-L1337 [2]:
https://github.com/odoo/enterprise/blob/81eaeb4b18d849c644160234def6c69013591abe/stock_barcode/static/src/models/barcode_model.js#L1690-L1699 [3]:
https://github.com/odoo/enterprise/blob/81eaeb4b18d849c644160234def6c69013591abe/stock_barcode/static/src/models/barcode_model.js#L1727-L1729
## Solution:
Avoid grouping lines from different moves unless using batch transfers. This ensures that backorders are not created when the barcode lines are fulfilled.
opw-5423943
Forward-Port-Of: odoo/enterprise#119164
Forward-Port-Of: odoo/enterprise#109032This update resolves an issue where payments with tips after payment were incorrectly marked as 'cancelled' in Stripe. The fix ensures that payment status remains consistent, preventing errors and improving the reliability of tip processing when using Stripe terminals. This improves the restaurant's payment processing experience.
Original PR description
Currently when using a stripe terminal and the tips after payment feature the transaction is marked as cancelled while the transaction is marked as uncapured on stripe. Steps to reproduce:…
Currently when using a stripe terminal and the tips after payment feature the transaction is marked as cancelled while the transaction is marked as uncapured on stripe. Steps to reproduce: ------------------- * Set up terminal payment (using SIMULATOR works) * Enable tips after payment feature * Open restaurant * Make an order * Go to payment screen, select stripe * Scan card (with simulator everything is automatic) > Payment line is marked as cancelled Why the fix: ------------ After this commit https://github.com/odoo/odoo/commit/c27deda808660dde89305d574b6d662157d99d16 if `captureAfterPayment` does not return true the status of the payment line will be set to `retry`. However when pos_restaurant_stripe is also installed `captureAfterPayment` can return `undefined` when tips after payment is enabled. https://github.com/odoo/odoo/blob/324df67c099ab18c6fe7c8f77212cf809debf383/addons/pos_restaurant_stripe/static/src/overrides/models/payment_stripe.js#L5-L11 In this case we want to capture later and we expect the pethod to not return anything. In this case we don't want to change the status of the payment line. opw-6223838 Forward-Port-Of: odoo/odoo#268802
This update corrects a problem where test products in the POS system were incorrectly converting prices due to missing company information. By assigning the correct test company, the system now displays the accurate 5.10 PEN price, resolving a failure in the refund process. This ensures accurate pricing and functionality for the Peruvian E-commerce module.
Original PR description
Description of the issue this commit addresses: The POS frontend converts prices using the product's currency_id. Test products created without a company_id had their currency_id fall back to the main company, causing the 5.10 PEN price to be converted unexpectedly and the l10n_pe_edi_pos refund tour to fail its orderline check. --- Desired behavior after this commit is merged: This commit sets the test product's company_id to the PE test company so its currency_id resolves to PEN. This prevents unintended currency conversion in the POS UI and restores the expected displayed price (5.10) in the refund tour. --- runbot-[242597](https://runbot.odoo.com/odoo/error/242597) Forward-Port-Of: odoo/enterprise#119834
This update resolves an issue preventing users from sending PEPPOL invoices through a branch company without direct access. The fix removes a check that was incorrectly blocking this functionality, allowing invoices to be sent as intended. This ensures branch companies can fully utilize PEPPOL invoicing.
Original PR description
# How to reproduce - Activate Accounting & l10n_be modules with demo data - Use "BE Company CoA" - Go to Settings > Users & Companies > Companies > "BE Company CoA" > Branches - Create new branch…
# How to reproduce - Activate Accounting & l10n_be modules with demo data - Use "BE Company CoA" - Go to Settings > Users & Companies > Companies > "BE Company CoA" > Branches - Create new branch company - Go to Settings and Enable PEPPOL, then save - Still in Settings, click on "Activate Electronic Invoicing" > Activate Peppol (demo) - Now use the branch company - In Settings, click on "Activate Electronic Invoicing", select "Send from parent company" > Activate Peppol (demo) - Go to Settings > Users & Companies > Users > any user (can be the current one) - Remove the user's access to "BE Company CoA" - Log in as that user if it is not the current one - Create a partner that can receive PEPPOL invoices : - Country : Belgium - Invoice sending : by Peppol - eInvoice format : EU Standard (Peppol Bis 3.0) - VAT : BE0477472701 - Peppol id : Belgian Company Registry - Create an invoice for that partner - Click on Confirm, then Send # The problem You cannot select the "by Peppol" sending method. It has the "(no access)" error attached to it. # Cause The sending method's enable state is computed by : https://github.com/odoo/odoo/blob/c7f05ae216de64d1f8e76e332bc6dd9cf11ce657/addons/account_peppol/wizard/account_move_send_wizard.py#L13 This method runs multiple check to see if the invoice can be send via peppol and one of them calls `_have_unauthorized_peppol_parent_company()` : https://github.com/odoo/odoo/blame/686a0cf67bb1e818baf43309fc94f3f0462097ed/addons/account_peppol/models/res_company.py#L136-L143 This checks that the current user has access to the parent company, which is our exact use case. This specific flow was indeed blocked by the task that introduced branch company PEPPOL invoicing : https://github.com/odoo/odoo/commit/6dd8bc34ba79c14408dc271c19ca7afb0f85fa44 The reason behind this block is in part explained by this comment : https://github.com/odoo/odoo/pull/216864#discussion_r2205047170 But after talking with the Peppol PO, this flow should be allowed # Proposed solution Entirely remove the `_have_unauthorized_peppol_parent_company()` check. After testing, it does not seem we have any access issues to worry about. opw-6080867 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262523
This update resolves an issue where reducing the PO quantity after a partial receipt in multi-step warehouses incorrectly calculated remaining receipt demands. The fix adjusts the calculation logic to accurately reflect the quantity of available stock when using a 'push' receipt flow, ensuring accurate picking demands.
Original PR description
**Issue** Reducing the PO quantity after performing a partial receipt, in multi-step receipts warehouse can incorrectly update the remaining receipt quantity. **Steps to reproduce** - Setup 2-route…
**Issue** Reducing the PO quantity after performing a partial receipt, in multi-step receipts warehouse can incorrectly update the remaining receipt quantity. **Steps to reproduce** - Setup 2-route receipt warehouse (Inventory > Configuration > Warehouse Management > Warehouses) - Create a PO for 35 units and confirm it - Click on receive products, set received quantity to 10 and create a backorder - Validate the next transfer - Go back to the PO and change the quantity to 20 - Check the receipt demand -> The backorder picking demand become 35 instead of 10 **Cause** Updating the quantity of a purchase order line, also updates the related picking: https://github.com/odoo/odoo/blob/5fc1e34d174f7f61d692d086d0ff65fbfc72b013/addons/purchase_stock/models/purchase_order_line.py#L120 It updates the picking associated to the backorder since the other one is done: https://github.com/odoo/odoo/blob/5fc1e34d174f7f61d692d086d0ff65fbfc72b013/addons/purchase_stock/models/purchase_order_line.py#L185-L187 https://github.com/odoo/odoo/blob/5fc1e34d174f7f61d692d086d0ff65fbfc72b013/addons/purchase_stock/models/purchase_order_line.py#L197 This ultimately calls: https://github.com/odoo/odoo/blob/5fc1e34d174f7f61d692d086d0ff65fbfc72b013/addons/purchase_stock/models/purchase_order_line.py#L228 To compute the new demand for the picking, it retrieves the `move_dest`: https://github.com/odoo/odoo/blob/5fc1e34d174f7f61d692d086d0ff65fbfc72b013/addons/purchase_stock/models/purchase_order_line.py#L240 To compute `qty_to_push`: https://github.com/odoo/odoo/blob/5fc1e34d174f7f61d692d086d0ff65fbfc72b013/addons/purchase_stock/models/purchase_order_line.py#L247-L249 However, since we are in a 2-route receipt setup, `move_dest` is the move from Input to stock for the done picking. Thus, `qty_to_push` is `20 - 10 = 10` instead of `20 - 35 = -15` **Solution** The previous logic assumes a pull flow, where downstream (move_dest_ids) quantities are always up-to-date and can be used as the source of truth to recompute demand. In push flows (e.g., multi-step receipts), this assumption does not hold. To fix this, we instead base the computation on the quantity of the current moves (qty) if nothing has to be attached. **Additional information** Known limitation: this does not address inconsistencies in return flows. When there're returns, units define in the pol and the one define in the sum of the picking can diverge, thus this pr won't fix that. opw-5512172 Forward-Port-Of: odoo/odoo#265583 Forward-Port-Of: odoo/odoo#248626
This update resolves an issue where attempting to create a new Global Invoice after canceling a refund through the CFDI system would fail. The fix ensures that the refund's CFDI status is correctly updated, allowing for the creation of new invoices related to the original order. This improves the functionality for Mexican POS operations.
Original PR description
Steps to reproduce 1. With a Mexican POS configured, create a POS order and sign a Global Invoice for it. 2. Open a new session and partially return the order; close the session. 3. On the original…
Steps to reproduce 1. With a Mexican POS configured, create a POS order and sign a Global Invoice for it. 2. Open a new session and partially return the order; close the session. 3. On the original order, cancel the Global Invoice through the CFDI page. 4. Try to create a new Global Invoice for the original order. Issue The wizard raises "Orders <REFUND-NAME> are already sent or not eligible for CFDI." Validating the refund auto-signs an `invoice_sent` CFDI on the refund pos.order because its parent is `global_sent`, see `_l10n_mx_edi_check_autogenerate_cfdi_refund` at https://github.com/odoo/enterprise/blob/5af8048f0b0956a024d7eaeb10600eec74bdf3ee/l10n_mx_edi_pos/models/pos_order.py#L98. Cancelling the GI only flips its own document to `ginvoice_cancel`; the refund's `invoice_sent` doc stays untouched, so the refund's computed `l10n_mx_edi_cfdi_state` stays `'sent'`. The chain check in `_l10n_mx_edi_check_orders_for_global_invoice` at https://github.com/odoo/enterprise/blob/5af8048f0b0956a024d7eaeb10600eec74bdf3ee/l10n_mx_edi_pos/models/pos_order.py#L184 then rejects the refund as already sent and the new GI cannot be created. opw-6181136 Forward-Port-Of: odoo/enterprise#120100 Forward-Port-Of: odoo/enterprise#117211
This update resolves a bug that occurred when reloading a chart of accounts, specifically when an account was originally set up in a different company. The fix ensures the system correctly identifies and handles accounts with old company prefixes, preventing errors and ensuring accurate account reloading.
Original PR description
When reloading a chart of accounts, `_pre_reload_data` resolves an account via its xmlid and then evaluates: ```py re.match(f'^{values["code"]}0*$', account.code) ``` `account.code` is a non-stored…
When reloading a chart of accounts, `_pre_reload_data` resolves an account via its xmlid and then evaluates:
```py
re.match(f'^{values["code"]}0*$', account.code)
```
`account.code` is a non-stored computed field that reads from the company-dependent field `code_store`. If the resolved account has no `code_store` entry for the target company (e.g. the account was originally set up under a different company but its xmlid was prefixed with the current company id), `_compute_code` returns False instead of a string, causing a TypeError in re.match.
```py
File "/home/odoo/src/odoo/19.0/addons/account/models/chart_template.py", line 442, in _pre_reload_data
if not account or not re.match(f'^{values["code"]}0*$', account.code):
File "/usr/lib/python3.10/re.py", line 190, in match
return _compile(pattern, flags).match(string)
TypeError: expected string or bytes-like object
```
```sql
apan_4342860=> SELECT
aa.id,
aa.code_store,
imd.module,
imd.name
FROM account_account aa
JOIN ir_model_data imd
ON imd.res_id = aa.id
AND imd.model = 'account.account'
WHERE aa.id = 1056;
id | code_store | module | name
------+-----------------+---------+-----------------
1056 | {"2": "510500"} | account | 1_co_puc_510500
(1 row)
```
This situation arises when a customer moves or reassigns an account between companies but the xmlid retains the original company prefix.
**Fix:**
After resolving the account via xmlid, check whether it actually belongs to the target company using filtered_domain with _check_company_domain. If it does not pass the check, unlink the stale ir.model.data entry and treat the account as not found, allowing the reload to re-establish the correct xmlid linkage via the code-based lookup that follows.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#269291This update fixes an issue where timesheets linked to partially refunded invoices were incorrectly being added to new invoices. The fix ensures that timesheets associated with fully invoiced orders are no longer considered when generating new invoices, preventing duplicate invoicing and ensuring accurate financial reporting. This improves the reliability of our invoicing process.
Original PR description
### Steps to reproduce: - Download 'Sales' and 'Timesheets' apps - Create 2 lines for the services product in the SO, invoicing policy = based on timesheets - Create 2 timesheets for both SO items - Invoice the SO - Create a credit note for line 1 => only line 2 is invoiced and line 1 is now released - Back to the SO > create invoice again > Line 2 is added to the invoice again. ### Cause of Issue: When generating the new invoice, `_recompute_qty_to_invoice` identifies timesheets linked to refunded invoices. Because the original invoice was partially refunded, all timesheets attached to that invoice match the domain used to locate timesheets—even the timesheets for line 2, which wasn't refunded. ### Fix: Ensures that lines that have already been completely invoiced are safely ignored and not inadvertently re-added to subsequent invoices. opw-6217684 Forward-Port-Of: odoo/odoo#268972 Forward-Port-Of: odoo/odoo#265840
This update ensures Polish company invoices sent to KSeF (a Polish tax system) correctly include a required field ('PrefiksPodatnika') in the FA(3) XML format. This is necessary for legal compliance with Polish tax regulations for common EU transactions like intra-Community sales and services. The fix addresses a technical issue where the field was missing, preventing proper processing by the KSeF system.
Original PR description
Steps to reproduce 1. Configure a Polish company with KSeF enabled. 2. Create a customer invoice using a tax tagged with K_21 (0% EU G, intra-Community supply of goods), K_12 (0% EU S, services taxed…
Steps to reproduce 1. Configure a Polish company with KSeF enabled. 2. Create a customer invoice using a tax tagged with K_21 (0% EU G, intra-Community supply of goods), K_12 (0% EU S, services taxed in the buyer's EU country) or Triangular Sale. 3. Send the invoice to KSeF and download the generated FA(3) XML. Issue The Podmiot1 (seller) block in the rendered FA(3) XML omits the PrefiksPodatnika element, see https://github.com/odoo/odoo/blob/89219a843545d8bb0cad6ea806a1167cee6289da/addons/l10n_pl_edi/data/fa3_template.xml#L34-L42. According to the official Ministry of Finance documentation (https://ksef.podatki.gov.pl/media/4u1bmhx4/information-sheet-on-the-fa-3-logical-structure.pdf, page 11), this conditional field must carry the value "PL" when the invoice documents: - the intra-Community supply of goods, - the provision of services referred to in Article 100 sec. 1 item 1 of the Act for EU VAT taxpayers, - the supply carried out under a simplified triangular transaction by the second taxpayer (Article 135 sec. 1 item 4 (b) and (c)). The XSD marks the element as optional (minOccurs="0", fixed="PL") so KSeF accepts the XML, but the seller's tax reporting is still legally non-compliant for the three cases above, and the field is missing from the KSeF PDF viewer rendering. opw-6213178 Forward-Port-Of: odoo/odoo#264659
This update resolves an error that occurred when generating payslips for employees with contracts exceeding 35 years. The fix adjusts a key calculation parameter to correctly account for Mexican labor law rules regarding seniority and holiday accrual, ensuring accurate payroll processing for all employees. This change improves payroll accuracy and compliance.
Original PR description
**Steps to reproduce:** 1. Install l10n_mx_hr_payroll. 2. Create an employee with a contract date over 35 years ago (e.g., 1985). 3. Create a payslip for this employee. 4. Click on "Compute Sheet".…
**Steps to reproduce:**
1. Install l10n_mx_hr_payroll.
2. Create an employee with a contract date over 35 years ago (e.g., 1985).
3. Create a payslip for this employee.
4. Click on "Compute Sheet".
```Error: KeyError(36) while evaluating```
**Cause:**
The rule parameter [rule_parameter_holiday_table](https://github.com/odoo/enterprise/blob/c02c4571bb7db7197b07539ba390d4d20fdce9fe/l10n_mx_hr_payroll/data/hr_rule_parameters_data.xml#L722-L758) defines values
only up to 35 years. Seniority exceeding this range causes a KeyError.
**Solution:**
Extended the `rule_parameter_holiday_2024` table from 35 to 60 years,
following the Mexican Federal Labor Law (LFT) reform formula
(+2 days every 5-year milestone from year 6 onwards).
**NOTE:**(Alternative approach)
```python
@staticmethod
def _get_mx_holiday_days(years_worked):
if years_worked <= 0:
return 0
if years_worked <= 5:
return 12 + (years_worked - 1) * 2
five_year_periods = (years_worked - 6) // 5
return 22 + five_year_periods * 2
```
This approach removes the need for XML data maintenance and handles
all future seniority values mathematically without any cap issues.
opw-6090590
Forward-Port-Of: odoo/enterprise#113536This update resolves a critical issue where VoIP registration would fail due to idle sessions, causing error dialogs and preventing users from making calls. The fix ensures that the registration process is reliably restarted when a session becomes inactive, improving VoIP stability and user experience. It prevents a frustrating 'reconnection' loop and ensures calls can be established.
Original PR description
Leaving a session open and idle (page open, no activity at all) eventually pops an error dialog: UncaughtPromiseError > RequestPendingError REGISTER request already in progress, waiting for final…
Leaving a session open and idle (page open, no activity at all) eventually pops an error dialog:
UncaughtPromiseError > RequestPendingError
REGISTER request already in progress, waiting for final response
at Registerer.register (sip.js)
at Registerer.register (registerer.js)
at UserAgent.attemptReconnection (user_agent_service.js)
When the WebSocket transport drops while a REGISTER is in flight (which happens on an idle tab: SIP.js sends a periodic re-REGISTER before the registration expires, and the socket may be closed by an idle timeout or by the machine going to sleep in the meantime), the final response never comes back. SIP.js only clears its internal `waiting` flag from the REGISTER response callbacks (onAccept/onReject/onRedirect); it is never reset on transport loss or request timeout. The Registerer is then stuck `waiting` forever, and every subsequent register() rejects with a RequestPendingError.
On top of that, our wrapper's register() did not return the SIP.js promise, and attemptReconnection() called it without awaiting, so the rejection escaped the surrounding try/catch and surfaced as an unhandled promise rejection. Worse, the WebSocket error was resolved right after, so the user appeared reconnected while VoIP registration was actually dead until the page was reloaded.
This commit makes register() recreate the underlying SIP.js Registerer when it is stuck `waiting` (a clean instance starts with waiting=false), and return the promise so callers can await it. attemptReconnection() now awaits it, so any rejection goes through the existing retry/back-off logic instead of bubbling up as an uncaught error.
The recreation is intentionally conditional: disposing a healthy registerer would send an unregister (REGISTER expires=0) racing with the fresh register (expires=600) and could leave us unregistered, so we only recreate when a request is actually stuck.
Forward-Port-Of: odoo/enterprise#120107
Forward-Port-Of: odoo/enterprise#119701This update optimizes how Odoo retrieves related mailings for testing, addressing a performance bottleneck that caused crashes with large campaigns. The change significantly improves the speed and stability of mass mailing operations, particularly when dealing with numerous or complex campaigns. This resolves a technical issue impacting campaign efficiency.
Original PR description
**Description of the issue/feature this PR addresses:** The method _get_ab_testing_siblings_mailings currently scans all mailings in a campaign to apply a simple filter, which becomes expensive on databases with many large mailings. **Steps to reproduce bug:** 1) Run this script to get [enough sufficiently large mailings](https://gist.github.com/brcut-odoo/bb0d6d334bfe110afe16021d17d1b443) 2) Open one of the mailings and recieve a crash from the _get_ab_testing_siblings_mailings **Current behavior before PR** https://drive.google.com/file/d/19xftvzsGSQ9DxB67LNiLkKApzsD192ax/view?usp=drive_link **Current behavior after PR** https://drive.google.com/file/d/1apTJ0rWTKaATYa67ZmmN-7bKhrw4KuTx/view?usp=drive_link opw-6245908 Forward-Port-Of: odoo/odoo#268283