Daily updates from Odoo
Friday, July 17, 2026
63 changes · saas-19.4
Resolved issues and error corrections
This fixes an issue that could interrupt the signing workflow when the system is running in debug mode. The signing page now reliably selects the correct signing field even when extra hidden page markers are present, reducing errors for users preparing or completing documents.
Original PR description
Use lastElementChild when retrieving the sign item from the target element. In debug mode, inherited templates may introduce HTML comments into the DOM. Since lastChild return a comment node, accessing classList on the returned node raises an error. Using lastElementChild ensures that the last HTML element is always retrieved, regardless of comment nodes in the DOM. Forward-Port-Of: odoo/enterprise#123991 Forward-Port-Of: odoo/enterprise#122106
Hong Kong IRD payroll reports now use the correct tax year based on employee start or departure dates. The update also enforces required details when an employee departure reason is marked as “other,” helping businesses meet IRD certification and filing requirements.
Original PR description
As we now have complete support for IRD reports (in master), we started to try to get our system certified by the IRD.
A first submission highlighted a few issues that we are now fixing.
From 19.0:
- In IR56F, the RTN_ASS_YR should be the tax year in which the employee left the company. E.g. after april, the next year.
- In the same report, if the code for the cessation reason is 5 (other), the reason MUST be provided.
From 19.2:
- Same change has to be done when setting RTN_ASS_YR for IR56G
- A same change has to also be done for IR56E, based on the date the employee joined the company.
task-6332150
Forward-Port-Of: odoo/enterprise#124456
Forward-Port-Of: odoo/enterprise#121877The Budget Report now opens much faster for companies with large accounting and purchasing datasets. This fixes timeouts that previously made the report unusable from budget records, improving access to budget tracking and analysis.
Original PR description
**Description** Opening the Budget Report from any budget record times out on databases with significant data volume. The request to `budget.report/formatted_read_grouping_sets` consistently times…
**Description**
Opening the Budget Report from any budget record times out on databases
with significant data volume. The request to
`budget.report/formatted_read_grouping_sets` consistently times out,
making the Budget Report completely unusable.
**Root cause:**
`budget.report` is an SQL view that consists of 5 UNION ALL branches.
When the list view loads, the ORM translates the `budget_analytic_id`
domain into a WHERE clause on the outer query wrapping the full UNION
ALL subquery. PostgreSQL cannot push this filter through a UNION ALL as
it's a hard optimization barrier. It must fully materialize the subquery
regardless of which budget is being viewed.
**Fix:**
Override _search on budget.report to extract budget_analytic_id and
budget_line_id conditions from the incoming domain using the Domain API.
budget_line_id is rewritten as Domain('id', op, value) so _to_sql()
correctly emits bl.id in the raw SQL. The resulting domain is injected
in context under budget_line_domain and read in _get_bl_query,
_get_aal_query (base module), and _get_pol_query (purchase module) to
filter budget_line rows inside each branch's LEFT JOIN ON clause.
This also removes the budget_report_budget_line_ids context key from
budget_line._compute_all, unifying both filters under one mechanism.
---
On customer DB (568k `account_analytic_line`, 27k `budget_line`,
116k confirmed `purchase_order_line`, 114k posted vendor bill lines
with purchase link):
| Budget | Before | After |
|---|---|---|
| 8 lines, 730d span | timeout | 2.27s |
| 14 lines | timeout | 2.39s |
| 14 lines, 1095d span | timeout | 1.63s |
- Before: https://explain.dalibo.com/plan/ehed5eb8de251426
- After: https://explain.dalibo.com/plan/db8aef35cag9hg6f
opw-6098047
Forward-Port-Of: odoo/enterprise#120707
Forward-Port-Of: odoo/enterprise#114692Colombian POS orders containing combo products now generate electronic documents that DIAN can accept. The system excludes zero-priced combo parent lines from the submitted XML, preventing card-paid combo sales from failing validation.
Original PR description
Issue: When ordering through POS combo items won't be accepted by DIAN. Steps to reproduce: Set company to Colombia and activate the DIAN module. Simulate a sell of an combo item with POS. Pay with card. Error will ensue. Cause: The XML sent to DIAN is not accepted because one of the items has 0 price (the combo item). Solution: Not sending lines that are combo items. opw-6232599 Forward-Port-Of: odoo/enterprise#123928 Forward-Port-Of: odoo/enterprise#119652
This fixes an issue where attendee email previews could show an outdated event start date after an event was rescheduled. Attendees now receive emails with the correct updated event timing, reducing confusion for multi-day events.
Original PR description
Steps to reproduce: ------------------------------------------------ 1. Install Event module 2. Create a multi day event 3. Create one attendee for the event 4. Change the event dates 5. Go to…
Steps to reproduce: ------------------------------------------------ 1. Install Event module 2. Create a multi day event 3. Create one attendee for the event 4. Change the event dates 5. Go to attendee and Click on Send by Email Observation: ------------------------------------------------ The event start date displayed in the email body is not updated after the event dates are modified. Issue: ------------------------------------------------ In `saas-18.2`, `event_begin_date` and `event_end_date` were simple related fields that automatically updated when their source fields changed. https://github.com/odoo/odoo/blob/saas-18.2/addons/event/models/event_registration.py#L57-L58 However, in `saas-18.3`, slots were introduced and these fields were converted to computed fields https://github.com/odoo/odoo/pull/205945/changes/e2bf8a89d6a50bd40f4673bef38176465f83ba0f * `event_begin_date` is made stored for cohort view grouping * However, the base compute method only depends on `event_id` and `event_slot_id` https://github.com/odoo/odoo/blob/ac37b479321dbe9dbf864e833900e043b1cc70df/addons/event/models/event_registration.py#L177-L180 * When you change `event.date_begin` or `event.date_end`, the registration records don't recompute because the dependency is on the `event_id`, not on the related date fields (`event_id.date_begin`, `event_id.date_end`) * Non-stored computed fields recalculate on-the-fly when accessed, so `event_end_date` appeared to work * Stored computed fields only recalculate when their explicit dependencies change Solution: ------------------------------------------------ * Corrected the dependencies of `_compute_event_begin_date` to recompute value on changing the date of the event opw-6284576 Forward-Port-Of: odoo/enterprise#120184
Payroll frequency labels now appear in the user's selected language across core payroll and multiple country-specific payroll modules. This improves clarity for HR users working in localized interfaces, such as French, by showing salary schedule options in the expected language.
Original PR description
Issue: ---------------------------------------- The values of the field `schedule_pay` aren't translated. Steps to reproduce: ---------------------------------------- - Switch the language to French - Open an employee form, "Paie" tab - The selection in the "Salaire" tab is not translated to French Cause: ---------------------------------------- When the selection values were moved to a method in 7a123d71925b25f26ba0a8abff0c4a159147bdd0. The strings were not declared as translatable. opw-6359395 Forward-Port-Of: odoo/enterprise#124504 Forward-Port-Of: odoo/enterprise#123718
Managers will no longer see the Print option twice in the Planning Gantt view. This makes the interface cleaner and reduces confusion when using planning actions.
Original PR description
Issue: - Managers see the "Print" action twice in the Gantt view: once as a standalone button and once in the Actions dropdown. Cause: - The standalone Print button is guarded on `!this.isManager`, but `isManager` lives on the model. The expression is therefore always truthy, so the button always renders. Fix: - Use `!this.model.isManager` instead. task-6364971 Forward-Port-Of: odoo/enterprise#123442
This fixes an error that could occur when validating certain stock operations involving kits in the Kenyan OSCU stock integration. Businesses using the Kenyan localization can complete affected inventory workflows more reliably without unexpected interruptions.
Original PR description
**CAUSE** super()._action_done() delete a record from self, and return a new recordset of stock.moves. We filter the old recordset instead of filtering the new one, leading to an MissingError traceback. **STEP TO REPRODUCE** On a fresh db, install: `l10n_ke,l10n_ke_edi_oscu,l10n_ke_edi_oscu_mrp,l10n_ke_edi_oscu_pos,l10n_ke_edi_oscu_stock,l10n_ke_edi_tremol,l10n_ke_hr_payroll,l10n_ke_hr_payroll_account,l10n_ke_reports` and run `TestKitPicking.test_add_sml_with_kit_to_confirmed_picking`. runbot-241262 Forward-Port-Of: odoo/enterprise#124663
This fixes an issue that prevented exchange rate adjustment entries from appearing in the bank reconciliation widget. Accounting users can now see the expected exchange movements when reconciling bank transactions, reducing confusion and helping reconciliation stay accurate.
Original PR description
Fix a bug where the exchange moves are no more displayed in the bank reco widget. Bug introduced here: https://github.com/odoo/enterprise/pull/119557 no-task Forward-Port-Of: odoo/enterprise#124495
This fixes a crash when downloading or printing German POS receipts that include Fiskaly TSS certification data. Businesses using certified German point-of-sale flows can reliably access receipts from the backend without errors.
Original PR description
With fiskaly in production, when printing the pos receipt, it crashes because the tss values dictionnary is not correctly interacted with. To reproduce: install l10n_de_pos_cert create a DE shop activate fiskaly and the tss in the settings of the POS create an order in the POS and pay it go to the backend, open the pos order and download the receipt it will crash To reproduce without production credentials, you can not activate fiskaly and the tss but still create and pay the pos order. Then, you can change the pos.config to add the l10n_de_fiskaly_tss_id and change the pos.order to add the l10n_de_fiskaly_time_start. Then download the receipt. opw-6356628 Fixes https://github.com/odoo/enterprise/pull/115676 Forward-Port-Of: odoo/enterprise#123473
This update prevents the Avalara tax integration from keeping a proxy connection active when a database is neutralized. It helps avoid unintended external communication from copied or non-production environments while keeping normal business data unchanged.
Original PR description
backport of https://github.com/odoo/enterprise/pull/122024 no-task Forward-Port-Of: odoo/enterprise#124681
This fixes an internal test setup issue in the Timesheet Grid module so automated checks run reliably. It helps prevent false test failures during development and release validation, with no direct change to end-user behavior.
Original PR description
Before this commit, the component was mounted in the `beforeEach` block before its `onRpc` mocks were registered. This caused the initial data fetch to fail because the mocks were not yet available during initialization. This commit fixes the test by moving the component mount (`doAction`) inside the test block, strictly after the mocks are defined. Forward-Port-Of: odoo/enterprise#123683
VoIP call smart buttons now open the same family-wide records that they count, covering the contact and related company contacts. New records created from those actions still default to the original contact person, reducing confusion for sales, CRM, helpdesk, project, and subscription users.
Original PR description
Commit [1] change the smart buttons on voip.call to count records from all family of the partner (count all record from all partners from the partner's company). However, the actions on the buttons stay the same, they will only open records from the partner itself. This is confusing, we change it to also show records from the whole partner family. [1]: 16772c5c1e604d6beb514f9e5b166fc0c2f452a7 Task-6379569
Coding editor activity in the timesheet assistant now uses the correct event category, so it displays with the intended code-related icon. This avoids confusing or missing visual cues when users review assistant events.
Original PR description
In the assistant, events from a coding editor use the "code" event type, which doesn't exist. This PR changes it to the correct value, which is "development". Task-6392585 Forward-Port-Of: odoo/enterprise#124502
Payroll schedule options in the Kuwait payroll localization now appear in the user's selected language. This fixes a missed localization issue so business users see consistent translated labels in payroll configuration.
Original PR description
The values returned by `_get_selection_schedule_pay()` wern't translated. This localization was missed by this forward port: 961bedf91d754cce5d3cdecabe1e504770902d05 opw-6359395
Chilean point-of-sale receipts with SII barcodes now print correctly instead of crashing during receipt generation. This ensures sales can be validated and customers can receive compliant receipts without interruption.
Original PR description
Steps to reproduce: - Have a Chilean company with DTE configured (a resolution number/date and a signed boleta/factura, so the order's move has an SII barcode) - Open a PoS session, pay an order and validate it Issue: The receipt fails to render and printing crashes with: `TypeError: ctx.image.l10n_cl_sii_barcode_image.to_base64 is not a function` Cause: Commit 0b50021bdae adapted this template as part of the BinaryValue migration (odoo/odoo#244421), calling `to_base64()` on the barcode image. However `l10n_cl_sii_barcode_image` is a computed `fields.Char` that already holds a base64 string (`_pdf417_barcode` returns `b64encode(...).decode()`), not a Binary, so it is never wrapped in a `BinaryValue`. Moreover, this template is also rendered client-side by the PoS QWeb engine, where the value loaded from the server is a plain string with no `to_base64` method either. opw-6389718 Forward-Port-Of: odoo/enterprise#124438
Service sale order lines created from field service planning now let Odoo calculate prices automatically. This ensures customer pricelists and product pricing rules are applied correctly instead of being bypassed by a fixed unit price.
Original PR description
Before this commit, in the method `_generate_service_sale_order_lines` the `price_unit` for sale order lines used an explicitly defined unit price. This prevented the pre-computation of the price. It may cause some issues, for example if there was a pricelist defined on the product, we didn't apply the prices from that pricelist. This commit removes explicit definition of the `price_unit` to let the sale order creation process handle it. [error-941068](https://runbot.odoo.com/odoo/error/941068)
The Balance Sheet report now displays numeric column headers with the correct spacing. This small visual fix improves readability and consistency in financial reports without changing any report data or calculations.
Original PR description
Due to `padding: 0.25rem 0.75rem !important;` To reproduce: - Open Balance Sheet - Check the Balance column numeric-header
Opening the template picker from an audit report article without a parent no longer causes an error. Instead, users see a clear message when no article template is available, keeping the audit report editing flow usable.
Original PR description
Currently, users encounter a traceback when clicking the "Load a Template" button in the WYSIWYG article helper if the article is linked to an audit report and has no parent article. Steps to…
Currently, users encounter a traceback when clicking the "Load a Template" button in the WYSIWYG article helper if the article is linked to an audit report and has no parent article. Steps to reproduce: 1. Install `accountant_knowledge`. 2. Create and open a new audit report. 3. Delete all content from article (the root). 4. Click the "Load a Template" button in the helper. => Crash with `AssertionError: Invalid falsy real id.` The issue occurs because the method responsible for loading the annex to display (see: `get_suggested_templates`) expects at least one record in the recordset. When the article has no parent, the recordset is empty, causing the method to fail. Before attempting to load a template, we will check whether the article has a parent article. If no parent exists, no template will be provided to the template picker. In that case, the picker will display a helper message indicating that no article template is available to load. Task [link](https://www.odoo.com/odoo/project.task/6333859) Task-6333859 Forward-Port-Of: odoo/enterprise#121807
This fixes cases where Point of Sale payments could get stuck when websocket connections were unavailable and the system fell back to longpolling. It also corrects Six payment handling in kiosk mode, improving payment reliability for affected stores.
Original PR description
A change from odoo/enterprise#116705 made the `iot_http_service` try to access the `self_ordering_mode` on the session`, leading to longpolling failure on non-self order as data would be undefined. Also, a mistake in error catching in the longpolling service made it so that an event request thrown would abort directly with the previous one, instead of only the previous one. If websocket was unavailable at the same time, it would result on the PoS getting stuck waiting for confirmation of the payment. In addition, we fixed Six payments in Kiosk, failing because it tryed to access `user.id` where user was `undefined`. task-6391166
Colombian electronic invoice XML imports now treat the listed price as the actual unit price, matching DIAN rules. This prevents incorrect negative discounts from appearing on vendor bills when imported products have quantities greater than one.
Original PR description
Problem: When importing XML files to generate vendor bills, the system uses UBL parser and assumes that the PriceAmount node needs to be divided by the BaseQuantity node to obtain the exact price…
Problem: When importing XML files to generate vendor bills, the system uses UBL parser and assumes that the PriceAmount node needs to be divided by the BaseQuantity node to obtain the exact price unit. However, in Colombia, the DIAN treats the PriceAmount node as the exact price unit. This was not flagged in the system so the parser incorrectly divides the PriceAmount by BaseQuantity, resulting in negative discounts to be added to match the subtotal. Solution: Extract the basis_qty logic into a helper method so other localizations can override when needed. Current behavior: When importing a Colombian XML with a product that has a BaseQuantity greater than 1, the PriceAmount gets incorrectly divided, resulting in negative discounts on the vendor bill. Expected Behavior: When importing a Colombian XML with a product that has a BaseQuantity greater than 1, the PriceAmount gets parses as the exact unit price with no negative discounts applied. task-6215466 Forward-Port-Of: odoo/enterprise#124567 Forward-Port-Of: odoo/enterprise#122313
This fix prevents an accounting dashboard filter from accidentally affecting document creation during Mexican electronic invoicing payment updates. It avoids an error that could block users from updating payments on CFDI invoices after reconciling bank transactions.
Original PR description
Issue: The `default_type` context can leak into documents creation with invalid values (e.g., 'sale' for documents.document.type), causing a ValueError. Steps to reproduce: - Use a Mexican company with CFDI credentials configured. - Install the documents_account module and create a folder for journals where you will place customer payments. - Create an invoice with "payment policy = PPD", and send it to CFDI. - Create a bank transaction and reconcile it with the invoice. - Go to the Accounting Dashboard, remove current filters, and group by "Type" (this injects default_type into the context). - From there, enter the "Sales" journal and open the invoice. - Click on the "Update Payments" button. - Result: `ValueError: Wrong value for documents.document.type: 'sale'` Fix: Clean context from the `default_*` keys when creating the attachment of the document. opw-6141172 Forward-Port-Of: odoo/enterprise#124578 Forward-Port-Of: odoo/enterprise#124074
This fix ensures contract updates use the right template, preferring the current contract version when available or falling back to the template from the salary offer. This helps HR teams avoid incorrect contract documents during offer and contract update workflows.
Original PR description
contract update template should come from current version if any or from the offer's contract template. Task-6094733 Forward-Port-Of: odoo/enterprise#124638 Forward-Port-Of: odoo/enterprise#123450
Since 414e55cf7c397, we can assign multiple users to a user-defined filter but because it's now a many2many, any user that got archived won't be shown in the `user_ids` fields anymore, it could mislead the filter being a global filter; whereas it's not. This commit also display archived users so we can see all users effectively assigned to the user-defined filter. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275841
Original PR description
Since 414e55cf7c397, we can assign multiple users to a user-defined filter but because it's now a many2many, any user that got archived won't be shown in the `user_ids` fields anymore, it could mislead the filter being a global filter; whereas it's not. This commit also display archived users so we can see all users effectively assigned to the user-defined filter. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275841
The more() action helper caches the More Actions object and only refreshes its inner actions list, leaving disabledCondition unchanged. As a result, if the dropdown is created while disabled, it remains disabled even after the composer is re-enabled. Individual actions (e.g., Attach files) don't exhibit this issue because they use a dynamic callback `(({ owner }) => owner.areAllActionsDisabled)` that is evaluated when needed. task-6393956 --- I confirm I have signed the CLA and read th
Original PR description
The more() action helper caches the More Actions object and only refreshes its inner actions list, leaving disabledCondition unchanged. As a result, if the dropdown is created while disabled, it remains disabled even after the composer is re-enabled.
Individual actions (e.g., Attach files) don't exhibit this issue because they use a dynamic callback `(({ owner }) => owner.areAllActionsDisabled)` that is evaluated when needed.
task-6393956
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#276870Steps to produce: --- - Install the `sales` module. - Create a product and `enable track inventory.` - Log in as user with only view access rights in products and also have the sales access rights. - Create a sale order containing product and confirm it. Issue: --- - An access error is raised during order confirmation. Root cause: --- - In [commit], to handle inventory tracking, the `qty_available` field was moved to `product.product`. Unlike before, this value is increased or
Original PR description
Steps to produce: --- - Install the `sales` module. - Create a product and `enable track inventory.` - Log in as user with only view access rights in products and also have the sales access rights. -…
Steps to produce: --- - Install the `sales` module. - Create a product and `enable track inventory.` - Log in as user with only view access rights in products and also have the sales access rights. - Create a sale order containing product and confirm it. Issue: --- - An access error is raised during order confirmation. Root cause: --- - In [commit], to handle inventory tracking, the `qty_available` field was moved to `product.product`. Unlike before, this value is increased or decreased depending on the operation performed. - As a consequence, creating or updating a sale order triggers a write to this `qty_available` field on the related product. This write happens under the current user's permissions, so users who only have read access to products (but can create/edit sale orders) hit an `AccessError`, since they lack write access on `product.product`. Solution: --- - Use `sudo()` when accessing the required product quantity information to ensure the operation can be completed without requiring additional product access rights. The same issue also occurs when confirming a purchase order. [commit]: https://github.com/odoo/odoo/commit/ca96992919b11105da44238c3e522f8eec4a740b opw-6290608 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276563 Forward-Port-Of: odoo/odoo#270067
Version: --------- - 19.0+ Steps to Reproduce: ----------------------- 1. Install sale_management, purchase, stock modules. 2. Create a storable product with Tracking: By Lot, 3. Create two Purchase Orders, each for 10 units. Receive PO-1 → 10 units with tagged as lot-1 Receive PO-2 → 10 units with tagged as lot-2 4. Create two Sale Orders: SO-1 → deliver 2 units from lot-1 (validate) SO-2 → deliver 4 units from lot-2 (validate) 5. Open Inventory > Reporting > Stock,
Original PR description
Version: --------- - 19.0+ Steps to Reproduce: ----------------------- 1. Install sale_management, purchase, stock modules. 2. Create a storable product with Tracking: By Lot, 3. Create two Purchase…
Version:
---------
- 19.0+
Steps to Reproduce:
-----------------------
1. Install sale_management, purchase, stock modules.
2. Create a storable product with Tracking: By Lot,
3. Create two Purchase Orders, each for 10 units.
Receive PO-1 → 10 units with tagged as lot-1
Receive PO-2 → 10 units with tagged as lot-2
4. Create two Sale Orders:
SO-1 → deliver 2 units from lot-1 (validate)
SO-2 → deliver 4 units from lot-2 (validate)
5. Open Inventory > Reporting > Stock,
click "Total Value", then check the "Remaining Quantity" column
Issue:
-------
Observed : remaining_qty = 10 for lot-2 receipt, 4 for lot-1 receipt
Expected : remaining_qty = 8 for lot-1 receipt (10−2), 6 for lot-2 receipt (10−4)
Cause:
--------
When the "Remaining Quantity" column is computed, the following call
chain executes:
stock.move._compute_remaining_qty()
→ calls product.product._get_remaining_moves()
→ calls product._run_fifo_get_stack() ← HERE is the problem
https://github.com/odoo/odoo/blob/f4d079cc5a9c47672cf1a6747bb073e8e74f7350/addons/stock_account/models/product.py#L372
`_get_remaining_moves` calls `_run_fifo_get_stack()` with NO lot
argument. Inside `_run_fifo_get_stack`, because no lot is given, it
computes the stack size from the TOTAL product qty across all lots:
https://github.com/odoo/odoo/blob/f4d079cc5a9c47672cf1a6747bb073e8e74f7350/addons/stock_account/models/product.py#L583
fifo_stack_size = 14 (10 received lot-1 + 10 received lot-2
− 2 delivered lot-1 − 4 delivered lot-2)
It then builds a domain to find incoming moves with NO lot filter:
https://github.com/odoo/odoo/blob/f4d079cc5a9c47672cf1a6747bb073e8e74f7350/addons/stock_account/models/product.py#L607
https://github.com/odoo/odoo/blob/f4d079cc5a9c47672cf1a6747bb073e8e74f7350/addons/stock_account/models/product.py#L614-L618
```Domain: [('is_in', '=', True), ('product_id', '=', X)]
↳ returns both receipts ordered:
[lot-2 receipt (10 qty), lot-1 receipt (10 qty)]
then walks this list consuming `fifo_stack_size = 14`:
So it take: [move_lot1_receipt(10)] First Lot
remaining_qty_on_first = min(10, 14) = 10
after consuming fifo_stack_size → 14−10=4 left → move_lot1 gets 4
```
So back in `_get_remaining_moves`:
qty_by_move = {
lot-2 receipt → 10, ← wrong (should be 6)
lot-1 receipt → 4, ← wrong (should be 8)
}
- The root cause: `_run_fifo_get_stack` is designed for products that
have one shared FIFO stack. For lot-valuated products, each lot is an
independent inventory layer. Running a single combined stack mixes both
lots together, so the deductions (2 from lot-1, 4 from lot-2) are not
attributed to the correct receipt moves — the algorithm just consumes
from the oldest receipts first with no awareness of which lot was
actually delivered.
Fix:
-----
`_run_fifo_get_stack` already accepts a `lot=` argument that:
- sets `fifo_stack_size = lot.product_qty` (correct per-lot qty)
- adds `('move_line_ids.lot_id', 'in', lot.id)` to the domain
so only the receipts that touched that specific lot are returned
The only missing piece was calling it per lot instead of once globally.
- With the fix, the stack for each lot is built correctly:
lot-1: fifo_stack_size = 8 → lot-1 receipt remaining_qty = 8 ✓
lot-2: fifo_stack_size = 6 → lot-2 receipt remaining_qty = 6 ✓
---
opw-6311341
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#276690
Forward-Port-Of: odoo/odoo#272411[FIX] fleet: fix vendor bill vehicle association bug Bug reprod: Go to 19.2 or above 1 - Go to vendor bills. 2 - Create an invoice line add vehicle. 3 - Click to vehicle via the link 4 - You will see fleet model and try to press to some smart buttons, traceback will occur (Odometer, Services...) Bug cause: 1 - When we press to smart buttons for Odometer or Services we are going to return_action_to_open function. 2 - In this function corresponding action's
Original PR description
[FIX] fleet: fix vendor bill vehicle association bug Bug reprod: Go to 19.2 or above 1 - Go to vendor bills. 2 - Create an invoice line add vehicle. 3 - Click to vehicle via the link 4 - You will see…
[FIX] fleet: fix vendor bill vehicle association bug
Bug reprod: Go to 19.2 or above
1 - Go to vendor bills.
2 - Create an invoice line add vehicle.
3 - Click to vehicle via the link
4 - You will see fleet model and try to press to some smart buttons, traceback will occur (Odometer, Services...)
Bug cause:
1 - When we press to smart buttons for Odometer or Services we are going to return_action_to_open function.
2 - In this function corresponding action's xml id is calculated and we are calling that action and that will load some view.
3 - self.env.context is passed directly as a context
4 - In the view_move_form (That include invoice lines, account_id and vehicle_id fields), account_id has a context list_view_ref="account.view_account_list_from_entry"
5 - This context is passed in self.env.context and that's why it tries to load this list_view when we press to odometer,service smart buttons, which shouldn't be the case.
6 - In 19.1 this context is not in self.env.context because >=19.2 m2o_cell_with_extra_m2o_fields is used for account_id and account_id and vehicle_id fields are combined in the single cell.
7 - That's why the context of account_id is passed to the vehicle page as well.
Bug solution:
1 - In the return_action_to_open function I'm dropping the list_view_ref context and we can load the correct related views about odometer or service or other ones.
task - 6385611
Description of the issue/feature this PR addresses:
Current behavior before PR:
Desired behavior after PR is merged:
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#276167Issue: ---------------------------------------- The units (day, year, etc.) aren't being translated in the Milestones view. Steps to reproduce: ---------------------------------------- - Switch the language to French - Go on an Accrual plan form view - In the milestones view, the units aren't translated Cause: ---------------------------------------- We input the key value of the selections fields `start_type` and `added_value_type`. These values aren't translated. Solution: --
Original PR description
Issue: ---------------------------------------- The units (day, year, etc.) aren't being translated in the Milestones view. Steps to reproduce: ---------------------------------------- - Switch the language to French - Go on an Accrual plan form view - In the milestones view, the units aren't translated Cause: ---------------------------------------- We input the key value of the selections fields `start_type` and `added_value_type`. These values aren't translated. Solution: ---------------------------------------- We create a dictionary with the same keys as the fields and a translated value as values. In the view, we read the values of the dictionary to get the translated units. opw-6367235 Forward-Port-Of: odoo/odoo#276665 Forward-Port-Of: odoo/odoo#275575
If we are in a case of a salary simulation, we don't care about future public holidays. The unlink done in _delete_future_public_holidays_timesheets was causing some cache invalidations which were messing up with the original offer. Forward-Port-Of: odoo/odoo#276520
Original PR description
If we are in a case of a salary simulation, we don't care about future public holidays. The unlink done in _delete_future_public_holidays_timesheets was causing some cache invalidations which were messing up with the original offer. Forward-Port-Of: odoo/odoo#276520
It can happen that _ref_vat has some lazy translate object. Without the self.env._ the translation would be ignored. (no translation language detected, skipping translation) runbot-941504 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276076 Forward-Port-Of: odoo/odoo#275561
Original PR description
It can happen that _ref_vat has some lazy translate object. Without the self.env._ the translation would be ignored. (no translation language detected, skipping translation) runbot-941504 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276076 Forward-Port-Of: odoo/odoo#275561
**Purpose of this PR:** Before this PR, the Voice detection sensitivity indicator in call settings could get stuck showing the last detected level after clicking "Stop" right after "Test". The `AudioWorkletNode`'s port kept receiving tic messages briefly after `disconnect()`, since disconnecting only unroutes the audio graph and does not stop the worklet from posting pending messages. <img width="546" height="73" alt="voice_test_bug" src="https://github.com/user-attachments/assets/05a10d23
Original PR description
**Purpose of this PR:** Before this PR, the Voice detection sensitivity indicator in call settings could get stuck showing the last detected level after clicking "Stop" right after "Test". The…
**Purpose of this PR:** Before this PR, the Voice detection sensitivity indicator in call settings could get stuck showing the last detected level after clicking "Stop" right after "Test". The `AudioWorkletNode`'s port kept receiving tic messages briefly after `disconnect()`, since disconnecting only unroutes the audio graph and does not stop the worklet from posting pending messages. <img width="546" height="73" alt="voice_test_bug" src="https://github.com/user-attachments/assets/05a10d23-fe60-4a85-b906-bfec6d235ec5" /> Steps to reproduce: 1. Open Voice & Video Settings. 2. Start the Voice detection sensitivity test. 3. Quickly click Stop immediately after clicking Test. 4. It may take a few tries, but eventually the Voice detection sensitivity indicator remains stuck at the last detected level. > [!NOTE] > this is timing-dependent. A tic message must already be in-flight from the worklet thread when `disconnect()` runs, so it won't happen every attempt. This race condition existed in the `disconnect` callback of `_loadAudioWorkletProcessor` since #66611, but stayed silent until #183969 introduced the Voice detection sensitivity feature in call settings, exposing it. This PR clears `port.onmessage` before disconnecting so late tic messages can no longer update the Voice detection sensitivity indicator after monitoring has stopped. Forward-Port-Of: odoo/odoo#275933
Before this commit: If a user, with crm.leads linked to it, decided to request a password reset AND during that password reset process decided to activate the google oauth for their account, it would cause a crash. The reason is, during the password rest + oauth activation, self.env.user is an empty record set, which obviously will fail during the _is_portal check, due to its call to ensure_one() opw-6347228 Forward-Port-Of: odoo/odoo#275375
Original PR description
Before this commit: If a user, with crm.leads linked to it, decided to request a password reset AND during that password reset process decided to activate the google oauth for their account, it would cause a crash. The reason is, during the password rest + oauth activation, self.env.user is an empty record set, which obviously will fail during the _is_portal check, due to its call to ensure_one() opw-6347228 Forward-Port-Of: odoo/odoo#275375
**Steps to reproduce:** - Create a fiscal position T1, with detect automatically - Create another one T2, without the detect automatically - When looking at the fiscal positions list, make sure T1 is on top, followed by T2 - Go to the PoS settings, check flexible taxes - Put T2 as default and in allowed, don't put T1 in allowed - Go to the PoS, chose a customer - The fiscal position is T1 even though it's not allowed **Why the fix:** Currently, the fiscal position is chosen like thi
Original PR description
**Steps to reproduce:** - Create a fiscal position T1, with detect automatically - Create another one T2, without the detect automatically - When looking at the fiscal positions list, make sure T1 is…
**Steps to reproduce:** - Create a fiscal position T1, with detect automatically - Create another one T2, without the detect automatically - When looking at the fiscal positions list, make sure T1 is on top, followed by T2 - Go to the PoS settings, check flexible taxes - Put T2 as default and in allowed, don't put T1 in allowed - Go to the PoS, chose a customer - The fiscal position is T1 even though it's not allowed **Why the fix:** Currently, the fiscal position is chosen like this in order: - A FP specified on the customer's profile - A FP detected with the detect automatically setting - The default FP from the PoS settings When we have a tie, it's the first one in the fiscal positions list that is chosen. Before this commit, we did not check that the fiscal position was allowed to be used in the PoS, so we just fetched whatever fiscal position fit the best for a given customer and didn't check if we could actually use it. We now make sure that the fiscal position we try to use is allowed in the current PoS, and if it's not we fall back to the default one. opw-6032031 Forward-Port-Of: odoo/odoo#276151 Forward-Port-Of: odoo/odoo#271343
Steps to reproduce: =================== 1. Drop an "Events" block on a website page. 2. In edit mode, try selecting the inner text by clicking multiple times. => Uncaught client error: TypeError: Cannot read properties of undefined (reading 'nodeType'). Root cause: =========== When a mouse selection crosses an uncrossable element, the selection restriction plugin moves the focus to the deepest position of the element sibling adjacent to the uncrossable one. When the first selec
Original PR description
Steps to reproduce: =================== 1. Drop an "Events" block on a website page. 2. In edit mode, try selecting the inner text by clicking multiple times. => Uncaught client error: TypeError:…
Steps to reproduce: =================== 1. Drop an "Events" block on a website page. 2. In edit mode, try selecting the inner text by clicking multiple times. => Uncaught client error: TypeError: Cannot read properties of undefined (reading 'nodeType'). Root cause: =========== When a mouse selection crosses an uncrossable element, the selection restriction plugin moves the focus to the deepest position of the element sibling adjacent to the uncrossable one. When the first selected node is itself an uncrossable element (event cards are `div` elements) that has no previous/next element sibling, `node.previousElementSibling` is null and `tempFocusNode` was never assigned by a previous iteration, so it is undefined. `nodeSize` then reads `nodeType` on undefined and throws. The plugin only exists from saas-19.3, which is why the issue is not reproducible on earlier versions. Fix: ==== When there is no sibling to place the focus on, fall back to the boundary just outside the uncrossable node itself (`leftPos` when selecting left to right, `rightPos` when selecting right to left) instead of calling `nodeSize`/`getDeepestPosition` with undefined. opw-6362955 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274739
See commit messages for details. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
See commit messages for details. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
When creating or editing a portal billing address, the Company Name field was pre-filled from `commercial_company_name`. For contacts without a parent company, the commercial partner is the contact itself, so the contact name was shown as the company name. Use the partner's actual parent company name instead, so the field stays empty when no company is linked while still showing the existing parent company when one exists. see: https://github.com/odoo/odoo/commit/18a59cf26f2d9400f76deec483
Original PR description
When creating or editing a portal billing address, the Company Name field was pre-filled from `commercial_company_name`. For contacts without a parent company, the commercial partner is the contact itself, so the contact name was shown as the company name. Use the partner's actual parent company name instead, so the field stays empty when no company is linked while still showing the existing parent company when one exists. see: https://github.com/odoo/odoo/commit/18a59cf26f2d9400f76deec483f6ddab87da0c55 Task-6372638 Forward-Port-Of: odoo/odoo#276621 Forward-Port-Of: odoo/odoo#274972
Before this commit: - When importing a **UBL** or **Factur-X (CII)** invoice, Odoo determines whether the document should be imported as an invoice or a credit note based on the `TaxExclusiveAmount (UBL)` /` TaxBasisTotalAmount (Factur-X)`. - In some rare cases, a valid invoice can contain a negative `TaxExclusiveAmount` / `TaxBasisTotalAmount` while still having a positive `TaxInclusiveAmount` / `GrandTotalAmount`. - In such situations, Odoo incorrectly imports the document as a credit note
Original PR description
Before this commit: - When importing a **UBL** or **Factur-X (CII)** invoice, Odoo determines whether the document should be imported as an invoice or a credit note based on the `TaxExclusiveAmount…
Before this commit: - When importing a **UBL** or **Factur-X (CII)** invoice, Odoo determines whether the document should be imported as an invoice or a credit note based on the `TaxExclusiveAmount (UBL)` /` TaxBasisTotalAmount (Factur-X)`. - In some rare cases, a valid invoice can contain a negative `TaxExclusiveAmount` / `TaxBasisTotalAmount` while still having a positive `TaxInclusiveAmount` / `GrandTotalAmount`. - In such situations, Odoo incorrectly imports the document as a credit note. Technical reason: - The method `_get_import_document_amount_sign()` uses `TaxExclusiveAmount` / `TaxBasisTotalAmount `to determine whether the imported document is an invoice or a refund. After this commit: - **UBL** now uses `TaxInclusiveAmount` instead of `TaxExclusiveAmount`, and **Factur-X** now uses `GrandTotalAmount `instead of `TaxBasisTotalAmount` to determine whether the document should be imported as an invoice or a credit note. - Prevent valid invoices with negative `TaxExclusiveAmount` / `TaxBasisTotalAmount` from being incorrectly converted into credit notes. Task-6321262 Forward-Port-Of: odoo/odoo#276307 Forward-Port-Of: odoo/odoo#271829
Before this commit, a crash could occur in kanban views but it required a very precise timing. If 2 renderings of the kanban renderer occurred at the same time, one coming from a group that has just been opened, and one coming from a new groupby being applied in the search view, we tried to scroll to the opened group to ensure that it is in the viewport, but we couldn't find it. Task~6391414 Forward-Port-Of: odoo/odoo#276750 Forward-Port-Of: odoo/odoo#276488
Original PR description
Before this commit, a crash could occur in kanban views but it required a very precise timing. If 2 renderings of the kanban renderer occurred at the same time, one coming from a group that has just been opened, and one coming from a new groupby being applied in the search view, we tried to scroll to the opened group to ensure that it is in the viewport, but we couldn't find it. Task~6391414 Forward-Port-Of: odoo/odoo#276750 Forward-Port-Of: odoo/odoo#276488
The translate button next to a translatable field saves the record before opening the translation dialog for its id. Since https://github.com/odoo/odoo/commit/a85ca9679e3855936afc66b034d05d75f672dd26 it saves record.model.root rather than the record itself. When the field belongs to a new record still edited inside an x2many, for example an answer added in the survey question popup, saving the root only saves the parent and the new line keeps no database id. The dialog then opens with the id set
Original PR description
The translate button next to a translatable field saves the record before opening the translation dialog for its id. Since https://github.com/odoo/odoo/commit/a85ca9679e3855936afc66b034d05d75f672dd26…
The translate button next to a translatable field saves the record before opening the translation dialog for its id. Since https://github.com/odoo/odoo/commit/a85ca9679e3855936afc66b034d05d75f672dd26 it saves record.model.root rather than the record itself. When the field belongs to a new record still edited inside an x2many, for example an answer added in the survey question popup, saving the root only saves the parent and the new line keeps no database id. The dialog then opens with the id set to false and calls update_field_translations on it, which builds WHERE id = false and the database rejects it with operator does not exist: integer = boolean. Such a record gets no id of its own, and after a save and reload there is no reliable way to match the saved line back to the one that was clicked, so the dialog can never open for it. A canTranslate getter in TranslationButton returns false for a new record whose model root is another record, which is exactly a line still edited inside an x2many, and the template only renders the button when it is true. The variant in editable lists, where model.root is a list rather than a record, was handled in https://github.com/odoo/odoo/commit/cb34b318004c3ca9db755d8dbbad429609220df3. Steps to reproduce: 1. Activate a second language in Settings > Translations > Languages 2. Open the Surveys app and create a survey 3. Add a question, then in the Answers tab add a line and type a value 4. Click the EN button next to the answer, fill the second language, and Save => RPC error operator does not exist: integer = boolean from WHERE id = false Ticket [link](https://www.odoo.com/odoo/project.task/6260427) opw-6260427 Forward-Port-Of: odoo/odoo#275401 Forward-Port-Of: odoo/odoo#267781
_reset_inventory() counter balances the stock implied by the move history when a product becomes storable, to reset the valuation of goods received while untracked. It assumed the product had no quants. But unticking Track Inventory does not clear the existing quants, so toggling it off then on again counter balances stock that is still on hand. The quants then desynchronize from their moves and the historical stock and valuation reports show quantities before the product ever existed. Onl
Original PR description
_reset_inventory() counter balances the stock implied by the move history when a product becomes storable, to reset the valuation of goods received while untracked. It assumed the product had no quants. But unticking Track Inventory does not clear the existing quants, so toggling it off then on again counter balances stock that is still on hand. The quants then desynchronize from their moves and the historical stock and valuation reports show quantities before the product ever existed. Only counter balance the part of the move history that is not already on hand. Steps to reproduce: - Create a storable product tracked by lots, 10 units on hand - Untick then re-tick "Track Inventory" on the product - Inventory > Reporting > Inventory at Date, pick a date before the product existed > The report shows 10 units on hand although there was no stock at that date. opw-6373051 Forward-Port-Of: odoo/odoo#275565
opw-6368979 Description of the issue/feature this PR addresses: Update the Worldline Cofidis payment method mapping to match the latest payment product ID defined in the Worldline documentation. Current behavior before PR: The Cofidis payment method was mapped to the outdated payment product ID (3012), causing payment requests to use an incorrect mapping. Desired behavior after PR is merged: The Cofidis payment method is mapped to the correct payment product ID (5129) as per
Original PR description
opw-6368979 Description of the issue/feature this PR addresses: Update the Worldline Cofidis payment method mapping to match the latest payment product ID defined in the Worldline documentation. Current behavior before PR: The Cofidis payment method was mapped to the outdated payment product ID (3012), causing payment requests to use an incorrect mapping. Desired behavior after PR is merged: The Cofidis payment method is mapped to the correct payment product ID (5129) as per the latest Worldline documentation, ensuring payment requests use the correct mapping. Forward-Port-Of: odoo/odoo#276132 Forward-Port-Of: odoo/odoo#275881
Problem: When a user attempts to create a new partner, and before saving the partner, they attempt to create a bank account in the same form view, they will be faced with a validation error for missing partner_id on the bank account. Solution: This commit solves this issue by only allowing the user to modify bank accounts for existing partners (with id). task-6373918 Forward-Port-Of: odoo/odoo#275062
Original PR description
Problem: When a user attempts to create a new partner, and before saving the partner, they attempt to create a bank account in the same form view, they will be faced with a validation error for missing partner_id on the bank account. Solution: This commit solves this issue by only allowing the user to modify bank accounts for existing partners (with id). task-6373918 Forward-Port-Of: odoo/odoo#275062
Hide the "All" option in the Apps search panel to avoid mixing Official Apps and Industries. Task ID: 5222706
Original PR description
Hide the "All" option in the Apps search panel to avoid mixing Official Apps and Industries. Task ID: 5222706
### Steps to Reproduce: - Insert text in the editor and select it. - Open the font size dropdown from the toolbar and select a font size. - Once editor focus returns to the editable area, type any character. - Observe that the editor throws a traceback. ### Purpose of this PR: - When selecting text & changing its font size or font family, typing character deletes selection and empties the formatting element. The editor converts this empty element to a pending format intent, but it pr
Original PR description
### Steps to Reproduce: - Insert text in the editor and select it. - Open the font size dropdown from the toolbar and select a font size. - Once editor focus returns to the editable area, type any…
### Steps to Reproduce: - Insert text in the editor and select it. - Open the font size dropdown from the toolbar and select a font size. - Once editor focus returns to the editable area, type any character. - Observe that the editor throws a traceback. ### Purpose of this PR: - When selecting text & changing its font size or font family, typing character deletes selection and empties the formatting element. The editor converts this empty element to a pending format intent, but it previously discarded the format's parameters (like class names, sizes, or font-family names). When editor later tried to apply format to newly typed character, it crashed because properties were undefined. ### Solution: - Implements a `getProps` method on font-size and font-family format specs to extract their properties before deletion. - Updates `convertEmptyFormatToPendingIntent` to save these properties. - Makes `addStyle` robust against empty properties using optional chaining. task-6377076 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Steps to reproduce: =================== - Ensure `pos_sale` is install. - Try to install `l10n_in_pos` Issue: ====== - `l10n_in_pos` cannot be installed because the XPath no longer matches the parent view. Cause: ====== - Since this PR odoo/odoo#259842, `pos_sale` replaces the `product_id` field with a `column` element in the POS order line view. Because of this, the XPath used by `l10n_in_pos` no longer matches when `pos_sale` is installed. Fix: ==== - Update the XPath to find
Original PR description
Steps to reproduce: =================== - Ensure `pos_sale` is install. - Try to install `l10n_in_pos` Issue: ====== - `l10n_in_pos` cannot be installed because the XPath no longer matches the parent view. Cause: ====== - Since this PR odoo/odoo#259842, `pos_sale` replaces the `product_id` field with a `column` element in the POS order line view. Because of this, the XPath used by `l10n_in_pos` no longer matches when `pos_sale` is installed. Fix: ==== - Update the XPath to find the `product_id` field anywhere inside the order line list, so it works with both the original view and the view modified by `pos_sale`. task-6352053 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
When the pos_discount module is installed while a session is open (the typical case: the user enables "Global Discounts" in the PoS settings while the PoS is running), `_default_discount_value_on_module_install` skipped the configs having a non-closed session (or any rescue session, even a closed one). Those configs ended up with the Global Discount feature enabled but no `discount_product_id`, and opening the PoS then raised "A discount product is needed to use the Global Discount feature." wit
Original PR description
When the pos_discount module is installed while a session is open (the typical case: the user enables "Global Discounts" in the PoS settings while the PoS is running),…
When the pos_discount module is installed while a session is open (the typical case: the user enables "Global Discounts" in the PoS settings while the PoS is running), `_default_discount_value_on_module_install` skipped the configs having a non-closed session (or any rescue session, even a closed one). Those configs ended up with the Global Discount feature enabled but no `discount_product_id`, and opening the PoS then raised "A discount product is needed to use the Global Discount feature." with no way to recover other than manually re-saving the PoS settings. The skip was introduced in 13.0 by 4c4adf472453 because, at the time, `pos.config.write()` refused any modification while a session was open, which made the module installation crash. That blanket restriction has since been narrowed to a few specific fields (`module_pos_restaurant`, `payment_method_ids`, `active`), so writing `discount_product_id` on a config with an open session is now perfectly valid. Remove the obsolete exclusion so that all configs get the default discount product at install time, regardless of their session state. opw-6385274 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276537
Update the XPath of the empty header of the 'Pay Now' button column to the last header of the table. Use a deterministic XPath expression for the 'Pay Now' button column cell. as the last cell of the table. Forward-Port-Of: odoo/odoo#272710
Original PR description
Update the XPath of the empty header of the 'Pay Now' button column to the last header of the table. Use a deterministic XPath expression for the 'Pay Now' button column cell. as the last cell of the table. Forward-Port-Of: odoo/odoo#272710
**Steps to reproduce:** - Make a product with a category - In the category, make the inventory valuation to automated - Set the income and expense account - Set a cost for the product - Make a fiscal position and set it as default for the PoS - In the Account Mapping tab, map the income and expense to two other accounts - Go to the PoS - Make a sale for that product, without invoice - Close the session and in the backend check the session - Check the journal entries - The income acc
Original PR description
**Steps to reproduce:** - Make a product with a category - In the category, make the inventory valuation to automated - Set the income and expense account - Set a cost for the product - Make a fiscal…
**Steps to reproduce:** - Make a product with a category - In the category, make the inventory valuation to automated - Set the income and expense account - Set a cost for the product - Make a fiscal position and set it as default for the PoS - In the Account Mapping tab, map the income and expense to two other accounts - Go to the PoS - Make a sale for that product, without invoice - Close the session and in the backend check the session - Check the journal entries - The income account has been mapped to the fiscal position's - The outcome account stayed the same as in the category's **Why the fix:** When we invoice an order, the income and expense accounts are immediately updated, in a different place than if it has not been invoiced. At the session's closure, we update the accounts for every order that hasn't been invoiced. In this flow, the account mapping defined on the fiscal position was not applied, so we took the one defined on the product's category. The income account was already mapped as we need to do it earlier than the session closure, so it had already been set as the right one before our flow. For the expense account, we only need it at this specific time, so we can map it as the session's closure. We now map the account depending on the fiscal position if we are able to find one, otherwise, we use the category's default as we did before. opw-6171677 Forward-Port-Of: odoo/odoo#276715 Forward-Port-Of: odoo/odoo#266700
When registering a payment for multiple bills from different partners, the `source_currency_id` becomes empty/evaluates differently in the wizard. Because of this, the `currency_conversion_div` `invisible` condition failed, causing the UI to redundantly display the exchange rate even when the currencies were identical (e.g., showing '1 EUR = 1 EUR'). This commit simplifies the invisible condition to only check if the `currency_id` matches the `company_currency_id`, keeping the UI clean. se
Original PR description
When registering a payment for multiple bills from different partners, the `source_currency_id` becomes empty/evaluates differently in the wizard. Because of this, the `currency_conversion_div` `invisible` condition failed, causing the UI to redundantly display the exchange rate even when the currencies were identical (e.g., showing '1 EUR = 1 EUR'). This commit simplifies the invisible condition to only check if the `currency_id` matches the `company_currency_id`, keeping the UI clean. see ent pr- https://github.com/odoo/enterprise/pull/118183 task- 6237870 Forward-Port-Of: odoo/odoo#266072
Registration token now needs to be valid for much longer than 1 hour due to manual verifications Forward-Port-Of: odoo/odoo#276550
Original PR description
Registration token now needs to be valid for much longer than 1 hour due to manual verifications Forward-Port-Of: odoo/odoo#276550
*: website, website_sale `forEach` is a synchronous operation, so it doesn't support promises. We refactor its usage to use `for` loops. task-4794299 Forward-Port-Of: odoo/odoo#276590 Forward-Port-Of: odoo/odoo#275262
Original PR description
*: website, website_sale `forEach` is a synchronous operation, so it doesn't support promises. We refactor its usage to use `for` loops. task-4794299 Forward-Port-Of: odoo/odoo#276590 Forward-Port-Of: odoo/odoo#275262
Before this commit, in the test `test_ticket_price_with_currency_conversion` the exchange rate was not correctly assigned because `rate_ids` was not initialized when running tests on app install. As a result the the rate was left empty and the currency conversion was not applied. This commit creates the rate_ids in the test to make sure the rates are correctly applied. Runbot error: https://runbot.odoo.com/odoo/error/242431 --- I confirm I have signed the CLA and read the PR guidelines
Original PR description
Before this commit, in the test `test_ticket_price_with_currency_conversion` the exchange rate was not correctly assigned because `rate_ids` was not initialized when running tests on app install. As a result the the rate was left empty and the currency conversion was not applied. This commit creates the rate_ids in the test to make sure the rates are correctly applied. Runbot error: https://runbot.odoo.com/odoo/error/242431 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276218 Forward-Port-Of: odoo/odoo#265503
Steps to reproduce: - Create a promotions program with a rule granting 1 point per currency unit spent (minimum 2 items and 50.00 spent) and a reward "10% discount on the cheapest product" for 1 point - Open a PoS session and add 2 products to trigger the program - Keep adding products to the order Issue: A new "10% on the cheapest product" line is added for every product added. In eCommerce and Sales the discount is only applied once. Cause: The rule grants far more points than the r
Original PR description
Steps to reproduce: - Create a promotions program with a rule granting 1 point per currency unit spent (minimum 2 items and 50.00 spent) and a reward "10% discount on the cheapest product" for 1…
Steps to reproduce: - Create a promotions program with a rule granting 1 point per currency unit spent (minimum 2 items and 50.00 spent) and a reward "10% discount on the cheapest product" for 1 point - Open a PoS session and add 2 products to trigger the program - Keep adding products to the order Issue: A new "10% on the cheapest product" line is added for every product added. In eCommerce and Sales the discount is only applied once. Cause: The rule grants far more points than the reward costs, so the reward remains claimable after being applied. The auto-claim loop of `updateRewards` therefore re-applies it on every order change, stacking one discount line per change. The already-applied check in `getClaimableRewards` only covered 'coupons' programs, while `_get_claimable_rewards` in sale_loyalty also skips discount rewards already present on the order lines. Solution: When auto-claiming, skip discount rewards that are already applied on the order, unless they belong to a payment program (ewallet, gift card). The reward can still be claimed manually several times through the Reward button by spending more points. opw-6380421 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276300
Steps to reproduce: - Create a partner without pincode - Create a picking and Challan for that partner - Click print Will result in the following traceback- ```py Traceback (most recent call last): File "<1103>", line 710, in template_l10n_in_ewaybill_report_ewaybill_1103 File "<1103>", line 692, in template_l10n_in_ewaybill_report_ewaybill_1103_content File "<1103>", line 674, in template_l10n_in_ewaybill_report_ewaybill_1103_t_call_0 File "<1103>", line 86, in template_l10n
Original PR description
Steps to reproduce: - Create a partner without pincode - Create a picking and Challan for that partner - Click print Will result in the following traceback- ```py Traceback (most recent call last):…
Steps to reproduce:
- Create a partner without pincode
- Create a picking and Challan for that partner
- Click print
Will result in the following traceback-
```py
Traceback (most recent call last):
File "<1103>", line 710, in template_l10n_in_ewaybill_report_ewaybill_1103
File "<1103>", line 692, in template_l10n_in_ewaybill_report_ewaybill_1103_content
File "<1103>", line 674, in template_l10n_in_ewaybill_report_ewaybill_1103_t_call_0
File "<1103>", line 86, in template_l10n_in_ewaybill_report_ewaybill_1103_t_call_1
File "/home/odoo/odoo18/community/addons/l10n_in_ewaybill/models/l10n_in_ewaybill.py", line 727, in _ewaybill_generate_direct_json
**self._prepare_ewaybill_base_json_payload(),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo18/community/addons/l10n_in_ewaybill_stock/models/l10n_in_ewaybill.py", line 289, in _prepare_ewaybill_base_json_payload
ewaybill_json = super()._prepare_ewaybill_base_json_payload()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo18/community/addons/l10n_in_ewaybill/models/l10n_in_ewaybill.py", line 669, in _prepare_ewaybill_base_json_payload
**prepare_details(
^^^^^^^^^^^^^^^^
File "/home/odoo/odoo18/community/addons/l10n_in_ewaybill/models/l10n_in_ewaybill.py", line 641, in prepare_details
f"{place}{key}": fun(partner, place) if key == "StateCode" else fun(partner)
^^^^^^^^^^^^
File "/home/odoo/odoo18/community/addons/l10n_in_ewaybill/models/l10n_in_ewaybill.py", line 674, in <lambda>
"Pincode": lambda p: int(p.zip) if p.country_id.code == "IN" else 999999,
^^^^^^^^^^
ValueError: invalid literal for int() with base 10: ''
```
In this commit, we resolve the traceback
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#276180When editing a partner, changing fields like `routing_identifier` triggers the onchange method `_onchange_verify_peppol_status()`, which in turn calls `button_account_peppol_check_partner_endpoint()`. Before: Calling `self.invalidate_recordset(...)` directly on the virtual record cleare the cache, reverting the user's unsaved input in the form back to the database value. After: Calling `self._origin.invalidate_recordset(...)` instead invalidates the database record cache, preserving the
Original PR description
When editing a partner, changing fields like `routing_identifier` triggers the onchange method `_onchange_verify_peppol_status()`, which in turn calls `button_account_peppol_check_partner_endpoint()`. Before: Calling `self.invalidate_recordset(...)` directly on the virtual record cleare the cache, reverting the user's unsaved input in the form back to the database value. After: Calling `self._origin.invalidate_recordset(...)` instead invalidates the database record cache, preserving the unsaved changes in the UI. > This fix was discussed with and suggested by @clbr-odoo no-task
**Description of the problem** The age verification popup snippet (`s_age_verification_popup`) does not work properly when dropped into the `#product_details` element of a product page. In particular, the popup is rendered below the blurred background and cannot be interacted with (it should be rendered above the blur instead). **How to reproduce** 1. Open a product page. 2. Drop `s_age_verification_popup` into the product details. 3. The popup is rendered below the blurred background.
Original PR description
**Description of the problem** The age verification popup snippet (`s_age_verification_popup`) does not work properly when dropped into the `#product_details` element of a product page. In…
**Description of the problem** The age verification popup snippet (`s_age_verification_popup`) does not work properly when dropped into the `#product_details` element of a product page. In particular, the popup is rendered below the blurred background and cannot be interacted with (it should be rendered above the blur instead). **How to reproduce** 1. Open a product page. 2. Drop `s_age_verification_popup` into the product details. 3. The popup is rendered below the blurred background. **Why the problem happens** The `s_age_verification_popup` snippet applies the blur effect to the `#wrapwrap` element. The popup is expected to be rendered above the blur thanks to its `z-index`. However, `z-index` only applies within the same stacking context. A child element cannot be rendered above elements outside its parent's stacking context, regardless of how high its own `z-index` is. Since `#product_details` has a defined `z-index`, it creates a stacking context. As a result, the popup, which is a child of `#product_details`, is rendered below the blur element. **Fix** This commit adds an SCSS rule to `#product_details` so that it no longer creates a stacking context when it contains an open age verification popup. To prevent the stacking context from being created, `z-index` is set to `auto` and `position` to `relative`. task-6358990 Forward-Port-Of: odoo/odoo#275368
When a push subscription is renewed by the browser (typically every few days), the pushsubscriptionchange event fires and the service worker attempts to re-register the new subscription endpoint via register_devices(). However, the VAPID public key was missing from the request kwargs. The server-side register_devices() always validates the VAPID key first and raises InvalidVapidError when it is absent. This caused the renewed subscription to never be saved in the database, silently breaking p
Original PR description
When a push subscription is renewed by the browser (typically every few days), the pushsubscriptionchange event fires and the service worker attempts to re-register the new subscription endpoint via…
When a push subscription is renewed by the browser (typically every few days), the pushsubscriptionchange event fires and the service worker attempts to re-register the new subscription endpoint via register_devices(). However, the VAPID public key was missing from the request kwargs. The server-side register_devices() always validates the VAPID key first and raises InvalidVapidError when it is absent. This caused the renewed subscription to never be saved in the database, silently breaking push notifications after the first subscription renewal. Fix by extracting the applicationServerKey from the new subscription's options and encoding it as a base64url string (without padding) — matching the existing logic in webclient.js _arrayBufferToBase64(). Description of the issue/feature this PR addresses: Current behavior before PR: Subscriptions don't get renewed causing push notifications to stop eventually. Desired behavior after PR is merged: Subscriptions get renewed successfully. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276085 Forward-Port-Of: odoo/odoo#275217
The `retry` button shown after a failed initial fetch did nothing when clicked (it goes through `thread.fetchMoreMessages` which is for load older and load newer). This change routes the click through `fetchMessages` when the failure is an initial one. task-6223358 backport of #272153 Forward-Port-Of: odoo/odoo#276444 Forward-Port-Of: odoo/odoo#275300
Original PR description
The `retry` button shown after a failed initial fetch did nothing when clicked (it goes through `thread.fetchMoreMessages` which is for load older and load newer). This change routes the click through `fetchMessages` when the failure is an initial one. task-6223358 backport of #272153 Forward-Port-Of: odoo/odoo#276444 Forward-Port-Of: odoo/odoo#275300
This fixes two bugs in the web push subscription flow: - register_devices() compared partner records with 'is not' instead of '!='. Records loaded via sudo() live in a different environment than self.env.user, so 'is not' was always True and the ownership guard never behaved as intended. Use '!=', which compares record identity by model and id as Odoo's ORM intends. - webclient.js sent the previous subscription endpoint under the snake_case key 'previous_endpoint', while the server reads i
Original PR description
This fixes two bugs in the web push subscription flow:
- register_devices() compared partner records with 'is not' instead of '!='. Records loaded via sudo() live in a different environment than self.env.user, so 'is not' was always True and the ownership guard never behaved as intended. Use '!=', which compares record identity by model and id as Odoo's ORM intends.
- webclient.js sent the previous subscription endpoint under the snake_case key 'previous_endpoint', while the server reads it as 'previousEndpoint' (kw.get('previousEndpoint', endpoint)). The mismatch meant the lookup always fell back to the new endpoint, so a refreshed subscription created a duplicate device instead of updating the existing one. Send the camelCase key to match the server.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#276082there is a typo in https://github.com/odoo/odoo/pull/275945 leading to a traceback. opw-6398050 Forward-Port-Of: odoo/odoo#277223
Original PR description
there is a typo in https://github.com/odoo/odoo/pull/275945 leading to a traceback. opw-6398050 Forward-Port-Of: odoo/odoo#277223
The partner credit limit warning on quotations and customer invoices depends on which company the user is currently working in, instead of the company of the document itself. Steps to reproduce: - Enable Sale Credit Limit in the settings of My Company (San Francisco) - Set a Credit Limit of 100 on a customer, e.g. Deco Addict - Create a draft quotation of 500 for that customer => The credit limit warning banner is displayed, as expected - Switch the active company to any other company, fo
Original PR description
The partner credit limit warning on quotations and customer invoices depends on which company the user is currently working in, instead of the company of the document itself. Steps to reproduce: -…
The partner credit limit warning on quotations and customer invoices depends on which company the user is currently working in, instead of the company of the document itself. Steps to reproduce: - Enable Sale Credit Limit in the settings of My Company (San Francisco) - Set a Credit Limit of 100 on a customer, e.g. Deco Addict - Create a draft quotation of 500 for that customer => The credit limit warning banner is displayed, as expected - Switch the active company to any other company, for example My Company (Chicago), keeping access to both companies - Open the same quotation again => The warning banner is gone, although neither the quotation nor the customer changed The credit fields used to build the warning are evaluated against the user's active company: credit_limit is a company-dependent field, and credit / credit_to_invoice are computed on the receivables of the current company. When the active company is not the document's company, the warning is checked against the wrong ledger and the wrong limit, so it can disappear on an over-limit customer or show up for a healthy one. Both computes already contain the line that was meant to handle this, but the result of with_company() was discarded, making it a no-op. Assign it, as every other compute in these files already does, so the warning is always evaluated in the document's company. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276917 Forward-Port-Of: odoo/odoo#276308
Problem: When importing XML files to generate vendor bills, the system uses UBL parser and assumes that the PriceAmount node needs to be divided by the BaseQuantity node to obtain the exact price unit. However, in Colombia, the DIAN treats the PriceAmount node as the exact price unit. This was not flagged in the system so the parser incorrectly divides the PriceAmount by BaseQuantity, resulting in negative discounts to be added to match the subtotal. Solution: Extract the basis_qty logic into
Original PR description
Problem: When importing XML files to generate vendor bills, the system uses UBL parser and assumes that the PriceAmount node needs to be divided by the BaseQuantity node to obtain the exact price…
Problem: When importing XML files to generate vendor bills, the system uses UBL parser and assumes that the PriceAmount node needs to be divided by the BaseQuantity node to obtain the exact price unit. However, in Colombia, the DIAN treats the PriceAmount node as the exact price unit. This was not flagged in the system so the parser incorrectly divides the PriceAmount by BaseQuantity, resulting in negative discounts to be added to match the subtotal. Solution: Extract the basis_qty logic into a helper method so other localizations can override when needed. Current behavior: When importing a Colombian XML with a product that has a BaseQuantity greater than 1, the PriceAmount gets incorrectly divided, resulting in negative discounts on the vendor bill. Expected Behavior: When importing a Colombian XML with a product that has a BaseQuantity greater than 1, the PriceAmount gets parses as the exact unit price with no negative discounts applied. Task [link](https://www.odoo.com/odoo/project.task/6215466) task-6215466 Forward-Port-Of: odoo/odoo#276763 Forward-Port-Of: odoo/odoo#273129