Friday, July 10, 2026
37 changes · saas-19.2
Enhancements to existing features
Databases can now show the status of the Know Your Client process as a KPI. This helps teams quickly see customer verification progress directly from database information.
Original PR description
Add a new type kyc_status to display the status of the Know Your Client procedure in the databases. Task-id: [6348952](https://www.odoo.com/odoo/project.task/6348952) Forward-Port-Of: odoo/enterprise#122510
backport of 5324615 As in Finland the tax rate will change from 14 to 13.5 on certain goods and services those taxes and the corresponding tax group were added to the l10n task-6332565 Forward-Port-Of: odoo/odoo#274792 Forward-Port-Of: odoo/odoo#274460
Original PR description
backport of 5324615 As in Finland the tax rate will change from 14 to 13.5 on certain goods and services those taxes and the corresponding tax group were added to the l10n task-6332565 Forward-Port-Of: odoo/odoo#274792 Forward-Port-Of: odoo/odoo#274460
This update ensures the iMin printer driver continues to function correctly with recent changes to Odoo's core point-of-sale system. The configuration has been moved to align with new standards, preventing potential errors and ensuring seamless receipt printing. This update also includes improvements to testing and reliability.
Original PR description
Following recent updates to the base `pos.printer` architecture in the point_of_sale module, the iMin driver configuration must be adapted to maintain compatibility and ensure seamless integration.…
Following recent updates to the base `pos.printer` architecture in the point_of_sale module, the iMin driver configuration must be adapted to maintain compatibility and ensure seamless integration. This commit backports the alignment logic and structure originally introduced in saas-19.3. Previously, iMin configuration lived inside the general POS settings overrides. To align with the updated base class interface and prevent tracebacks or broken flows, the driver's configuration logic is now migrated directly into the native `pos.printer` model ecosystem. This adaptation includes: - Moving the configuration views and logic to inherit from `pos.printer`. - Restricting iMin devices strictly to receipt printing via a new constraint. - Adding a 3-second timeout to the WebSocket availability check to comply with the base class's expectations for non-blocking status checks. - Updating backend testing support by patching `TestEPos`. opw-6218933 Forward-Port-Of: odoo/odoo#265709
Resolved issues and error corrections
Canadian check printing now hides check numbers on payment stubs when pre-numbered checks are used. This keeps the stub layout consistent with the check itself and avoids showing duplicate or misleading numbering.
Original PR description
The check itself respected the check_manual_sequencing field, but the stubs did not. Hide the numbers on stubs as well, exactly like on US checks. task-6343701 Forward-Port-Of: odoo/enterprise#122565
Users who are not linked to an employee can now create an expense from a document, provided they already have permission to create expenses for another employee. This removes an unnecessary blocker while keeping existing access controls in place.
Original PR description
Removes the constraint saying a user has to be linked to an employee to create an expense from a document. In this case, the user still needs the rights to create an expense for another employee. task-6237021 Forward-Port-Of: odoo/enterprise#123635 Forward-Port-Of: odoo/enterprise#118955
The Knowledge automated tour was updated to match a recent interface change where a property type dropdown became a select menu. This prevents false test failures and improves reliability by addressing timing issues in the tour.
Original PR description
The dropdown for property definition type was replaced with a select menu, leading to an error in the tour as it tried to search for the previous implementation which contained a button. There are also changes to fix the race conditions that exist in the tour which were not evident due to the original issue Related pr: https://github.com/odoo/odoo/pull/234484 runbot-238409
Invoices from partners with foreign EU VAT numbers are now placed in the correct Czech VAT control statement section. This prevents qualifying non-domestic transactions from being incorrectly reported as domestic VAT entries, improving report accuracy and compliance.
Original PR description
With l10n_cz company: - Create an invoice for a partner with a foreign vat (EU) with an amount greater than 10000 CZ and a 21% tax. In the vat control statement of the tax report, the move is classified under A4. But the section A4 should only contain move with domestic vat opw-6268506 Forward-Port-Of: odoo/enterprise#120002
This fix prevents an error when users remove the start or end date from a field service planning shift. The change keeps shift editing stable by safely skipping break-time calculations when required dates are missing.
Original PR description
before: when removing the start and end date of a shift, a trace back happens in the `_onchange_break_time` cause: it depends on the start and end date values, so it breaks when they are falsy after: apply a guard to the `_onchange_break_time` function to check on those fields to avoid breaking it --- task-6361418
Fixed a display issue in the Planning list where rows for material resources could appear with the wrong height after the resource field was changed. This keeps the schedule easier to read and ensures resource avatars fit properly in the list view.
Original PR description
commit - https://github.com/odoo/enterprise/pull/106700/changes/3f27d96bda7c0b20683adb3fc1d38b5c3279c4a4 When the resource field was converted from m2o to m2m, the corresponding SCSS selector in the planning list was not updated. so the row height was not adjusted correctly for material resources using the m2m avatar widget.
This fixes the displayed total exemption amount in Belgian payroll 274 declarations. The correction helps payroll teams see accurate declaration totals, while the amount is used for display only and does not change payroll calculations.
Original PR description
The total exemption amount (only used for display) was wrongly computed.
Draft planning items in My Planning now use the expected hatched display instead of appearing like confirmed entries. This helps users quickly distinguish draft plans from regular calendar entries and avoid confusion when reviewing schedules.
Original PR description
Issue: Calendar entries appear plain even when they should appear hatched. (ex. while in draft status) Steps to reproduce: If you create any planning and set it to draft. Then go to Planning > Planning > My Planning, the newly created plan should be in hatched but it becomes plain. Cause: In the view planning.slot.my.calendar there was missing the element that causes the views to become hatched when in draft status. Solution: Added said element. opw-6260055
Payslip email activity now records a neutral sent-by-email note instead of incorrectly saying a payslip was re-sent the first time. When multiple employees are processed, each payslip receives only one chatter note, reducing confusion in payroll records.
Original PR description
**Issue:** Clicking Send By Email on a payslip opens the hr.payslip.send.mail wizard. Its action_send() always logs "The payslip has been re-send to the employee." in the payslip chatter, even when…
**Issue:** Clicking Send By Email on a payslip opens the hr.payslip.send.mail wizard. Its action_send() always logs "The payslip has been re-send to the employee." in the payslip chatter, even when the payslip is being sent for the first time. The log call also runs inside the loop over the employees and goes through all the payslips of the wizard on each pass, so when the wizard sends payslips of several employees every payslip gets the same note once per employee. This started with the rework of the wizard in https://github.com/odoo/enterprise/commit/39e0488a7e076ee648b47cc3d1cad41cadfd692e **Fix:** The wizard cannot tell a first send from a resend. There is no field on the payslip that keeps track of a previous send, and the chatter cannot be used for that either because the mail sent automatically on validation can be deleted after sending. The fix changes the log in action_send() to say the payslip has been sent by email, which is true in both cases, and moves it out of the employee loop so each payslip gets exactly one note. **Steps to reproduce:** 1. In Payroll > Configuration > Settings, set "Send payslips to employees" to When Paid and save 2. In Payroll > Payslips, create an off-cycle payslip for an employee, click Compute, then Validate 3. Go back to the settings and set "Send payslips to employees" to When Confirmed 4. On the payslip, click Pay, then Mark as Paid 5. Click Print so the payslip document is generated 6. Click Send By Email and send the mail 7. Check the payslip chatter => The chatter shows "The payslip has been re-send to the employee." while the payslip was never sent before Ticket [link](https://www.odoo.com/odoo/project.task/6324204) opw-6324204
`_add_manual_models` builds Python model classes for custom ("manual") `ir.model` records with a raw `SELECT *` on the `ir_model` table, then hands each row to `_instanciate_attrs`, which reads a fixed list of expected columns (`model`, `name`, `abstract`, `transient`, `order`, `fold_name`, `info`) via dict subscription (`model_data['xxx']`). This assumes every one of these fields is always backed by a real database column. That assumption breaks whenever a field originally declared as stored
Original PR description
`_add_manual_models` builds Python model classes for custom ("manual") `ir.model` records with a raw `SELECT *` on the `ir_model` table, then hands each row to `_instanciate_attrs`, which reads a…
`_add_manual_models` builds Python model classes for custom ("manual") `ir.model` records with a raw `SELECT *` on the `ir_model` table, then hands each row to `_instanciate_attrs`, which reads a fixed list of expected columns (`model`, `name`, `abstract`, `transient`, `order`, `fold_name`, `info`) via dict subscription (`model_data['xxx']`).
This assumes every one of these fields is always backed by a real database column. That assumption breaks whenever a field originally declared as stored on `ir.model` gets redeclared as non-stored (`store=False`) by another module inheriting the same model: Odoo correctly drops the now-unneeded column during that module's `_auto_init()`, but any code still doing `SELECT *` on the table no longer gets that key in the result row, and the subscript access raises a bare `KeyError`. This aborts the *entire* registry load, for every model in the database, not just the one whose field changed -- because `_add_manual_models` runs once per registry load and any database with at least one manual/custom model exercises it.
This is exactly the scenario introduced by 267bec440d56 ("[IMP] base: add IrModel.abstract field"): it added a new, plain stored `abstract` field on `ir.model`. `web_studio` has independently defined its own `abstract` field on `ir.model` since 2016 (ac1129f6577), as a computed, `store=False` field. Once both are loaded together, Odoo's field- merging logic settles on the `store=False` definition, so `_auto_init()` drops the `abstract` column -- and any database that also has at least one manual model (built through Studio, or via a module that dynamically generates SQL-view-backed models) then fails to boot its registry at all:
File ".../odoo/orm/model_classes.py", line 554, in _add_manual_models
attrs = env['ir.model']._instanciate_attrs(model_data)
File ".../odoo/addons/base/models/ir_model.py", line 487, in _instanciate_attrs
'_abstract': bool(model_data['abstract']),
KeyError: 'abstract'
Fix `_instanciate_attrs` to fall back to a sane default instead of assuming the column exists. This doesn't just patch the `base`/ `web_studio` collision -- it hardens `_add_manual_models` against any future field made non-stored by an inheriting module, which is otherwise a silent, whole-database-breaking failure with no visible relation to whichever module actually changed the field.
A companion fix removing web_studio's now-redundant override (the actual root cause of the collision) is proposed separately.
Steps to reproduce:
1. Install `base` and `web_studio` together (or in either order) --
Odoo's field-merging settles on web_studio's `store=False`
definition, but leaves the `abstract` column physically in place;
it is not dropped automatically.
2. Have at least one manual model in the database (`state='manual'`
on `ir.model`, e.g. created through Settings > Technical > Models).
3. Actually remove the now-orphaned `abstract` column -- e.g. via the
OCA `database_cleanup` module's column-purge wizard
(`cleanup.purge.wizard.column`), which explicitly targets exactly
this kind of column (computed + non-stored fields are excluded
from its "keep" list, so `abstract` gets flagged and dropped).
4. Restart Odoo / reload the registry: it fails to boot entirely with
a KeyError on that field name, for every model, not just the one
whose owning module changed.
Related: odoo/enterprise#123572
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#275092**Steps to reproduce:** - Install Accounting and l10n_ar_withholding - Switch to an Argentinian company (e.g. (AR) Responsable Inscripto) - Create a 0% Payment Withholding tax: * Tax Type: Customer Payment Withholding * Amount: 0.00 % * Add an account for the tax distribution lines - Create an invoice with a tax - Confirm the invoice - Pay the invoice: * Withholdings: - Add a line with the created 0% Payment Withholding tax - Add a line with another Payment
Original PR description
**Steps to reproduce:** - Install Accounting and l10n_ar_withholding - Switch to an Argentinian company (e.g. (AR) Responsable Inscripto) - Create a 0% Payment Withholding tax: * Tax Type: Customer…
**Steps to reproduce:**
- Install Accounting and l10n_ar_withholding
- Switch to an Argentinian company (e.g. (AR) Responsable Inscripto)
- Create a 0% Payment Withholding tax:
* Tax Type: Customer Payment Withholding
* Amount: 0.00 %
* Add an account for the tax distribution lines
- Create an invoice with a tax
- Confirm the invoice
- Pay the invoice:
* Withholdings:
- Add a line with the created 0% Payment Withholding tax
- Add a line with another Payment Withholding tax
- Create Payment
- Go to the payment
**Issue 1:**
When clicking on the first withholding line, a JS error is raised due to a missing index (i.e. currency_id).
**Cause 1:**
One of the fields has an aggregate sum function applied on it (i.e. amount_currency).
As it is a monetary field, the corresponding currency field is required in the view.
**Issue 2:**
When resetting the payment to draft, the withholding line with the 0% tax is deleted.
As the withholding table is not editable, it is not possible to add the line again.
**Cause 2:**
When the payment is reset to draft, the state of the associated journal entry is also set to draft and a "_sync_dynamic_lines" is triggered, which remove tax lines having a zero amount during the process.
**Solution 2:**
Keep all the lines with a Customer Payment Withholding tax as it is not possible to add a withholding line in the payment afterwards.
opw-6298058
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#274604
Forward-Port-Of: odoo/odoo#271555Problem: When filtering lost leads and grouping them, the lost leads are not counted in the groups' totals. Steps to Reproduce: 1. Go to CRM 2. Go to Reporting > Leads 3. Select List View 4. Before applying any grouping, check the total number of leads and make sure there are some closed leads among the leads and that the applied filter includes the inactive/lost leads 5. Apply any grouping 6. Check how the sum of the groups totals doesn't equal the leads total Cause: When readin
Original PR description
Problem: When filtering lost leads and grouping them, the lost leads are not counted in the groups' totals. Steps to Reproduce: 1. Go to CRM 2. Go to Reporting > Leads 3. Select List View 4. Before…
Problem: When filtering lost leads and grouping them, the lost leads are not counted in the groups' totals. Steps to Reproduce: 1. Go to CRM 2. Go to Reporting > Leads 3. Select List View 4. Before applying any grouping, check the total number of leads and make sure there are some closed leads among the leads and that the applied filter includes the inactive/lost leads 5. Apply any grouping 6. Check how the sum of the groups totals doesn't equal the leads total Cause: When reading a group, the domain from the applied filter gets optimized, meaning that the applied rules get simplified logically. https://github.com/odoo/odoo/blob/f4d079cc5a9c47672cf1a6747bb073e8e74f7350/addons/web/models/models.py#L421 When looking for all leads, we filter by both active and inactive leads, but the optimize method removes both of them since active=TRUE OR active=FALSE = TRUE always. When removed, no filtering on the active field is in the domain now, which leads to the search method returning only active leads (default behaviour of search method when the active field is not set in the domain). opw-6302388 Forward-Port-Of: odoo/odoo#272390
Steps to reproduce: - Install `account` module - Enable dark mode - Open `view_account_form` to create a record - On the Accounting page, open type dropdown - The dropdown background remains in light mode This commit applies $dropdown-bg on `o_field_account_type_selection` as in odoo/odoo@0cd148eb389078c896aaa719af5733d05377fd1c Forward-Port-Of: odoo/odoo#274626 Forward-Port-Of: odoo/odoo#271352
Original PR description
Steps to reproduce: - Install `account` module - Enable dark mode - Open `view_account_form` to create a record - On the Accounting page, open type dropdown - The dropdown background remains in light mode This commit applies $dropdown-bg on `o_field_account_type_selection` as in odoo/odoo@0cd148eb389078c896aaa719af5733d05377fd1c Forward-Port-Of: odoo/odoo#274626 Forward-Port-Of: odoo/odoo#271352
When a POS line comes from a sale order, its invoice line name is overridden with the source sale order line's name. When a down payment is invoiced directly from the POS, the invoice is generated before the down payment POS line is linked to its sale order line, so sale_order_line_id is still empty and the override resolved to an empty recordset, setting the invoice line name to False. Only override the name when a sale order line is actually set, so the down payment line keeps its own name.
Original PR description
When a POS line comes from a sale order, its invoice line name is overridden with the source sale order line's name. When a down payment is invoiced directly from the POS, the invoice is generated before the down payment POS line is linked to its sale order line, so sale_order_line_id is still empty and the override resolved to an empty recordset, setting the invoice line name to False. Only override the name when a sale order line is actually set, so the down payment line keeps its own name. opw-6305649 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274000
Steps to reproduce: - Open Chrome. - Set the browser zoom below or above 100%. - Edit a website page. - Hover a resize or padding handle in the overlay. => A white line appears in the middle of the handle. Before this commit, overlay handles changed their inner outline color on hover. With Chrome zoom levels different from 100%, this could leave a white line visible in the middle of the handle. After this commit, overlay handles change their background color on hover and use a consiste
Original PR description
Steps to reproduce: - Open Chrome. - Set the browser zoom below or above 100%. - Edit a website page. - Hover a resize or padding handle in the overlay. => A white line appears in the middle of the handle. Before this commit, overlay handles changed their inner outline color on hover. With Chrome zoom levels different from 100%, this could leave a white line visible in the middle of the handle. After this commit, overlay handles change their background color on hover and use a consistent inner outline width, so no white line is visible. task-6048647 Forward-Port-Of: odoo/odoo#273722
Steps to reproduce ------------------- - Install sale_project, accountant and project_timesheet_forecast_sale modules; - Activate analytic accounting in the settings; - Add an outstanding account to the bank journal’s manual outgoing payment method; - Create a new billable project; - Open the top menu, add vendor bills and open it; - Create a new bill from there, it should use the project’s analytic distribution; - Confirm it and create a payment; - Open the payment’s journal entry, i
Original PR description
Steps to reproduce ------------------- - Install sale_project, accountant and project_timesheet_forecast_sale modules; - Activate analytic accounting in the settings; - Add an outstanding account to…
Steps to reproduce ------------------- - Install sale_project, accountant and project_timesheet_forecast_sale modules; - Activate analytic accounting in the settings; - Add an outstanding account to the bank journal’s manual outgoing payment method; - Create a new billable project; - Open the top menu, add vendor bills and open it; - Create a new bill from there, it should use the project’s analytic distribution; - Confirm it and create a payment; - Open the payment’s journal entry, it is using the analytic distribution too; Why is it happening -------------------- When opening a vendor bill from the project, the project_id is added to the account.move's context to use the correct analytic distribution when we create a bill. If we create a payment after accessing the bill from this route, the context is transfered to account.payment.register, and then to the payment's entry lines in the `_create_payments` method. Due to the `_compute_analytic_distribution` method, the project's distribution is used on the payment's entry. We propose to filter out payment lines in this compute method. opw-6329475 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275076
# How to reproduce - Create a new product - Add a reordering rule to that product with : - Trigger : Auto - Min : > Forecast - Activate dev mode - Go to Seetings > Technical > Automation > Scheduled Actions - Find the "Procurement: run Scheduler" action & run it manually # The issue We get a traceback : psycopg2.errors.SerializationFailure: could not serialize access due to concurrent update # Cause In Odoo, we use an isolation level of "REPEATABLE READ" for transactions : htt
Original PR description
# How to reproduce - Create a new product - Add a reordering rule to that product with : - Trigger : Auto - Min : > Forecast - Activate dev mode - Go to Seetings > Technical > Automation > Scheduled…
# How to reproduce - Create a new product - Add a reordering rule to that product with : - Trigger : Auto - Min : > Forecast - Activate dev mode - Go to Seetings > Technical > Automation > Scheduled Actions - Find the "Procurement: run Scheduler" action & run it manually # The issue We get a traceback : psycopg2.errors.SerializationFailure: could not serialize access due to concurrent update # Cause In Odoo, we use an isolation level of "REPEATABLE READ" for transactions : https://github.com/odoo/odoo/blob/7c35e183d6cc33a6e5d20e5e97ffef79e03b49d4/odoo/sql_db.py#L373 Even with that isolation level psql can throw a `SerializationFailure` if a transaction attempts to update a row that was modified by another transaction after the isolation snapshot was taken. ### Example that will raise an error : Session 1 ```SQL BEGIN ISOLATION LEVEL REPEATABLE READ; UPDATE accounts SET balance = balance - 100 WHERE id = 1; ``` Session 2 ```SQL BEGIN ISOLATION LEVEL REPEATABLE READ; UPDATE accounts SET balance = balance - 50 WHERE id = 1; COMMIT; ``` Back to Session 1 ```SQL COMMIT; ``` When running our action, we do this : https://github.com/odoo/odoo/blob/dff0835346f30fd1ef77260d94bcceeeab4d9051/addons/stock/models/stock_rule.py#L697-L703 Which correspond exactly to the first example : We first update some records with their compute Then `orderpoints.sudo()._procure_orderpoint_confirm(...)` creates a new transaction, update some rows & commits : https://github.com/odoo/odoo/blob/dff0835346f30fd1ef77260d94bcceeeab4d9051/addons/stock/models/stock_orderpoint.py#L716-L719 https://github.com/odoo/odoo/blob/dff0835346f30fd1ef77260d94bcceeeab4d9051/addons/stock/models/stock_orderpoint.py#L781-L783 Finally, we commit the original transaction with `_commit_progress(1)` # Proposed solution Inverse the order of `_commit_progress(1)` and `orderpoints.sudo()._procure_orderpoint_confirm(...)` so we commit the first transaction before starting the second one. opw-6261675 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#268616
In the bubble layout, the `name="company_address"` div was inside an unconstrained `<td>`, causing percentage-based widths set in `company_details` (e.g. `width: 25%` on a image) to resolve against the full table cell width, resulting in oversized content compared to other layouts. **Without fix:** <img width="1127" height="411" alt="withoutfix" src="https://github.com/user-attachments/assets/244c3407-1dbb-4b83-95d9-ebaba2b2b13c" /> For e.g, The folder layout wraps the same block in a `w-
Original PR description
In the bubble layout, the `name="company_address"` div was inside an unconstrained `<td>`, causing percentage-based widths set in `company_details` (e.g. `width: 25%` on a image) to resolve against…
In the bubble layout, the `name="company_address"` div was inside an unconstrained `<td>`, causing percentage-based widths set in `company_details` (e.g. `width: 25%` on a image) to resolve against the full table cell width, resulting in oversized content compared to other layouts. **Without fix:** <img width="1127" height="411" alt="withoutfix" src="https://github.com/user-attachments/assets/244c3407-1dbb-4b83-95d9-ebaba2b2b13c" /> For e.g, The folder layout wraps the same block in a `w-50` div, so percentage widths resolve against ~half the page width. <img width="1111" height="410" alt="folderexp" src="https://github.com/user-attachments/assets/ee72712a-94da-483c-9a8e-cb3a850dac8e" /> Added `w-50 ms-auto` to the `name="company_address"` div in the bubble layout to align its sizing context with the other layouts, ensuring consistent rendering of user-defined styles in `company_details` across both layouts. **With fix:** <img width="1119" height="413" alt="wfix" src="https://github.com/user-attachments/assets/6b1caf24-3a8e-450f-865e-cce2b9788fe9" /> Commit which made the bubble layout in table: https://github.com/odoo/odoo/commit/8eb61a245cd3b650e309fdb55d24654c34d785cd opw-6287230 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275228 Forward-Port-Of: odoo/odoo#270725
When opening a table that has no order, `setTable` recycles an existing empty floating order instead of creating a new one (to avoid leaving dangling blank orders behind). The filter only checked for the absence of a table, lines and finalized state, so it could grab any empty floating order, including one deliberately created for takeout or delivery. Steps to reproduce: - Open a restaurant POS with presets enabled (e.g. Dine in / Takeaway). - Cashier A creates a new floating order for a ph
Original PR description
When opening a table that has no order, `setTable` recycles an existing empty floating order instead of creating a new one (to avoid leaving dangling blank orders behind). The filter only checked for…
When opening a table that has no order, `setTable` recycles an existing empty floating order instead of creating a new one (to avoid leaving dangling blank orders behind). The filter only checked for the absence of a table, lines and finalized state, so it could grab any empty floating order, including one deliberately created for takeout or delivery. Steps to reproduce: - Open a restaurant POS with presets enabled (e.g. Dine in / Takeaway). - Cashier A creates a new floating order for a phone customer: selects the Takeaway preset with a future time slot, but has not added any product yet. - Meanwhile, cashier B opens an empty table from the floor screen. - => The takeout order is assigned to the table and becomes a dine-in order, losing its takeout context. Only recycle blank direct sale orders: skip orders that have a floating order name, a scheduled preset time or a preset different from the config default, as those were created on purpose. Tapping a table while on a blank dine-in scratch order still converts it as before. opw-6041750 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262573
In this PR https://github.com/odoo/odoo/pull/237069 we used t-att-class for applying the style and because of that style was not properly applying and ICE was visible on address page on initial rendering for a moment even it does not have anything to do with MA. Used t-att-style instead t-att-class. task-5208254 Forward-Port-Of: odoo/odoo#274678
Original PR description
In this PR https://github.com/odoo/odoo/pull/237069 we used t-att-class for applying the style and because of that style was not properly applying and ICE was visible on address page on initial rendering for a moment even it does not have anything to do with MA. Used t-att-style instead t-att-class. task-5208254 Forward-Port-Of: odoo/odoo#274678
Steps to reproduce: - Create a promotion program (e.g. "10% discount on your order", reward_point_mode "per order") and restrict its rule to a specific product A; leave the minimum quantity at 0 - Open a PoS session and add any other product B to the order Issue: The discount was applied even though the order contained none of the rule's valid products. Cause: In `pointsForPrograms`, a rule was only gated on its quantity and amount thresholds (`totalProductQty < rule.minimum_qty`), nev
Original PR description
Steps to reproduce: - Create a promotion program (e.g. "10% discount on your order", reward_point_mode "per order") and restrict its rule to a specific product A; leave the minimum quantity at 0 -…
Steps to reproduce: - Create a promotion program (e.g. "10% discount on your order", reward_point_mode "per order") and restrict its rule to a specific product A; leave the minimum quantity at 0 - Open a PoS session and add any other product B to the order Issue: The discount was applied even though the order contained none of the rule's valid products. Cause: In `pointsForPrograms`, a rule was only gated on its quantity and amount thresholds (`totalProductQty < rule.minimum_qty`), never on the actual presence of a valid product in the order. Program templates (promotion, promo_code, next_order_coupons) create rules with minimum_qty = 0, so a product-restricted rule passed with zero matching items and, in "order" point mode, granted its points unconditionally. The same hole existed in `_canGenerateRewards` for scanned coupon programs, where rules act as conditions. The backend does not have this issue: `_program_check_compute_points` in sale_loyalty skips any rule whose valid products are not present in the order. Fix: Mirror the backend behavior in the PoS frontend: skip a product-restricted rule in `pointsForPrograms` when no (non-reward) order line matches its valid products, and make `_canGenerateRewards` return false in the same situation. Gift card and eWallet flows are unaffected since their "money"/"unit" point modes already gave 0 points when the trigger product was absent. opw-6357241 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275073
When uploading a font file "FontName 123 Light.otf" the baseFontName needs to be quoted in the font-face CSS to be valid. Single font files parsing for the shortestNamedFont now also correctly keeps the weight for the targetFonts. Description of the issue/feature this PR addresses: Uploaded fonts with spaces in the name are not working. Current behavior before PR: When uploading a font with a space in the filename like "FontName 123 Light.otf" the css declaration in the attachement i
Original PR description
When uploading a font file "FontName 123 Light.otf" the baseFontName needs to be quoted in the font-face CSS to be valid. Single font files parsing for the shortestNamedFont now also correctly keeps…
When uploading a font file "FontName 123 Light.otf" the baseFontName needs to be quoted in the font-face CSS to be valid.
Single font files parsing for the shortestNamedFont now also correctly keeps the weight for the targetFonts.
Description of the issue/feature this PR addresses:
Uploaded fonts with spaces in the name are not working.
Current behavior before PR:
When uploading a font with a space in the filename like "FontName 123 Light.otf" the css declaration in the attachement is wrong and not working:
```css
@font-face {
font-family: FontName 123 Light;
font-style: normal;
font-weight: 400;
src: url("/web/content/1057/FontName 123 Light.otf");
}@font-face {
font-family: FontName 123 Light;
font-style: normal;
font-weight: 400;
src: url("/web/content/1057/FontName 123 Light.otf");
}
```
Desired behavior after PR is merged:
The font name is now correctly quoted and the font attributes are no longer overwritten for the shortestNameFont:
```css
@font-face {
font-family: "FontName 123 Light";
font-style: normal;
font-weight: 400;
src: url("/web/content/1057/FontName 123 Light.otf");
}@font-face {
font-family: "FontName 123 Light";
font-style: normal;
font-weight: 300;
src: url("/web/content/1057/FontName 123 Light.otf");
}
```
Info @wt-io-it
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#273534
Forward-Port-Of: odoo/odoo#268842Reduce idletimeout task id: 6374370 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Reduce idletimeout task id: 6374370 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Currently the number grouping for Portuguese and Hindi is missing. Number grouping is used to separate long numbers in logical groups to make then easier to read. In Western countries, the grouping is usually done in groups of three digits (e.g. `1,000,000` instead of `1000000`), while in India, the grouping is done in groups of two digits after the first three digits (e.g. `10,00,000` instead of `1000000`). Source: https://www.unicode.org/cldr/charts/48/by_type/numbers.number_formatting_patt
Original PR description
Currently the number grouping for Portuguese and Hindi is missing. Number grouping is used to separate long numbers in logical groups to make then easier to read. In Western countries, the grouping is usually done in groups of three digits (e.g. `1,000,000` instead of `1000000`), while in India, the grouping is done in groups of two digits after the first three digits (e.g. `10,00,000` instead of `1000000`). Source: https://www.unicode.org/cldr/charts/48/by_type/numbers.number_formatting_patterns.html#24a93b3d14ba17b2 All languages will be revised in a follow-up `master` PR. [task-6320391](https://www.odoo.com/odoo/project.task/6320391) Forward-Port-Of: odoo/odoo#275237 Forward-Port-Of: odoo/odoo#274443
#### Issue: When a credit note is renamed so that it sorts before the related invoices, the lot assigned on invoice previews can become incorrect. Already posted invoices can appear to consume the first lot again. Example: A sale order is delivered in 2 batches: 10 units from SN01, then 10 units from SN02. Invoice 1 correctly shows SN01 and Invoice 2 correctly shows SN02. If Invoice 1 is refunded, re-invoiced, and the credit note is then renamed so it sorts before the invoices, Invoice
Original PR description
#### Issue: When a credit note is renamed so that it sorts before the related invoices, the lot assigned on invoice previews can become incorrect. Already posted invoices can appear to consume the…
#### Issue: When a credit note is renamed so that it sorts before the related invoices, the lot assigned on invoice previews can become incorrect. Already posted invoices can appear to consume the first lot again. Example: A sale order is delivered in 2 batches: 10 units from SN01, then 10 units from SN02. Invoice 1 correctly shows SN01 and Invoice 2 correctly shows SN02. If Invoice 1 is refunded, re-invoiced, and the credit note is then renamed so it sorts before the invoices, Invoice 2 can incorrectly switch back to SN01. #### Steps to reproduce: - Enable "Display Lots & Serial Numbers on Invoices". - Create a sale order for 20 units of a tracked product. - Deliver 10 units from the first lot/serial number and 10 units from a second one in a backorder. - Create and post 2 invoices, one for each delivery. - Create and post a credit note for the first invoice. - Create and post a new invoice for 10 units. - Reset the credit note to draft, rename it so that it sorts before the invoices, then repost it. - Check the lot previews on the invoices. #### Root Cause: _get_invoiced_lot_values() orders invoice lines with move_name, which is mutable, then computes the previously invoiced quantities from that order. When a refund is renamed so it sorts before the invoices, the set of "previous" invoice lines changes. On top of that, reversed invoices are filtered out too broadly, even when their reversing move should not yet impact the current invoice chronology. #### Fix: Order invoice lines with immutable move ids instead of move_name, and only ignore reversed invoices once their reversing move is also before the current invoice in the effective chronology. This keeps posted invoices stable while preserving the re-invoice behavior. opw-6110232 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#264776
When computing taxes for the order, we group the base lines based on a grouping key. One of the components of this key is `is_refund`, and reward lines where considered as refund lines, which caused them to be grouped separately. This caused a discrepency between the tax amount computed in the frontend and the one computed in the backend. Steps to reproduce: ------------------- * Change the rounding method to globally * Create a 21% tax not included in price * Create a product with a pric
Original PR description
When computing taxes for the order, we group the base lines based on a grouping key. One of the components of this key is `is_refund`, and reward lines where considered as refund lines, which caused…
When computing taxes for the order, we group the base lines based on a grouping key. One of the components of this key is `is_refund`, and reward lines where considered as refund lines, which caused them to be grouped separately. This caused a discrepency between the tax amount computed in the frontend and the one computed in the backend. Steps to reproduce: ------------------- * Change the rounding method to globally * Create a 21% tax not included in price * Create a product with a price of 76.01 and the tax created above * Create a loyalty program with a 10% discount * Create a POS order with the product above and apply the loyalty program * Validate the order and generate the invoice > Observation: The invoice states that 0.01$ is still due Why the fix: ------------ In `round_tax_details_tax_amounts`, we try to detect any delta with the expeced tax amount. To do that we group the base lines based on a grouping key. The grouping key `is_refund` was incorrectly set to `true` for reward lines, which caused them to not be grouped. The delta was then not detected and tax amounts were not adjusted. We now make sure not to consider reward lines as refund. opw-6052112 Forward-Port-Of: odoo/odoo#275145 Forward-Port-Of: odoo/odoo#271577
When an orderpoint fails during a portal user's transaction (e.g., eCommerce checkout), the system catches the `Procurement Exception` and logs a warning activity on the product template. The exception handler uses `.sudo().activity_schedule()`, which bypasses the write access restriction but leaves `env.uid` as the portal user. Therefore, the restricted portal user permanently becomes the `create_uid` (Author) of the activity. System exception activities should always be authored by the s
Original PR description
When an orderpoint fails during a portal user's transaction (e.g., eCommerce checkout), the system catches the `Procurement Exception` and logs a warning activity on the product template. The…
When an orderpoint fails during a portal user's transaction (e.g., eCommerce checkout), the system catches the `Procurement Exception` and logs a warning activity on the product template. The exception handler uses `.sudo().activity_schedule()`, which bypasses the write access restriction but leaves `env.uid` as the portal user. Therefore, the restricted portal user permanently becomes the `create_uid` (Author) of the activity. System exception activities should always be authored by the system (OdooBot), never by a portal or public user. This context leak corrupts the activity metadata by injecting an external user ID into internal backend logs. Chain `.with_user(SUPERUSER_ID)` to the `.sudo()` call in `stock_orderpoint.py` when scheduling the exception activity. This ensures the environment context is stable and the activity is authored by OdooBot, which transcends multi-company record rules. Steps to Reproduce on Runbot/Fresh Database on version 17.0: 1. Enable Multi-Company with Company A and Company B. Set Company B as the active company for the website. 2. Restrict the main Admin (Runbot) user strictly to Company A. 3. Create a Shared Product (Company field left blank). 4. Set a Reordering Rule (Orderpoint) for the product that is guaranteed to fail routing. 5. Navigate to the frontend website and sign up as a new user (this creates a Portal User in Company B). 6. As the newly signed-up Portal User, complete an eCommerce checkout for the shared product. 7. The checkout succeeds, but the backend triggers the orderpoint failure and logs the exception activity on the product template. 8. Check the chatter for this product: the `create_uid` is incorrectly set to the Portal User instead of OdooBot (1). 9. (In 19.0 Upgrade) Log in as the Admin user (set strictly to view Company A), navigate to the product, and the AccessError for reading will appear due to this leaked id. [opw-6253978](https://www.odoo.com/odoo/my-support-tasks/6253978?debug=assets) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275140 Forward-Port-Of: odoo/odoo#269395
Since [1] elements within the link preview can be focused. However, when pressing tab an error is raised. This commit prevents this error from happening. [1]: https://github.com/odoo/odoo/commit/34db19f4a2b42d7e41205d7d793f5b3f408c19af task-6366337 Forward-Port-Of: odoo/odoo#275336 Forward-Port-Of: odoo/odoo#274682
Original PR description
Since [1] elements within the link preview can be focused. However, when pressing tab an error is raised. This commit prevents this error from happening. [1]: https://github.com/odoo/odoo/commit/34db19f4a2b42d7e41205d7d793f5b3f408c19af task-6366337 Forward-Port-Of: odoo/odoo#275336 Forward-Port-Of: odoo/odoo#274682
This update corrects a previous issue where a process was unnecessarily triggered repeatedly, impacting performance. Now, the update runs only when a specific date is set, streamlining the French VAT (PDP) processing and improving system efficiency. This change ensures smoother operations for our French clients.
Original PR description
In previous fix https://github.com/odoo/odoo/commit/29b24a17a40d0f45a0e459cda68ca53b7d40075e we called _force_update_l10n_fr_f10_moves when the value of _compute_l10n_fr_pdp_flow_10_start_date changed as if it was stored, whitch it's not, calling the method each time the compute was triggered. Now _force_update_l10n_fr_f10_moves is run when l10n_fr_pdp_annuaire_start_date is set. Forward-Port-Of: odoo/odoo#275019
This update addresses a warning message appearing when editing the partner view in Odoo. The warning was caused by a hidden field being flagged as missing. The change ensures the warning disappears while maintaining the intended functionality of the hidden field.
Original PR description
There is a warning saying that there is no "true" field when editing the view. But in reality this is currently working as expected and the field is hidden. related to opw-5947987 Forward-Port-Of: odoo/odoo#275218 Forward-Port-Of: odoo/odoo#273041
This update ensures that deprecation warnings in Odoo consistently use string messages, resolving a compatibility issue with older Python versions. This change improves the reliability of warning messages and prevents potential errors when using the Odoo platform.
Original PR description
The native `warnings.deprecated` decorator strictly requires a string literal as its first positional argument and cannot be applied as a bare decorator. This commit enforces the same type verification in the fallback implementation for Python < 3.13. Follow-up of odoo/odoo@42fcc766af0584ef720a1cee5beb7878cdd1a572 runbot-941402 Forward-Port-Of: odoo/odoo#275037
This update fixes an issue where the list price set when creating a product from an invoice wasn't being saved to the product's template. Now, the list price will consistently reflect the value set during product creation, ensuring accurate product pricing information.
Original PR description
Problem: When creating a product from an invoice form view, the list price set on the product is not saved on the product template. After creating the product, when checking the product from the…
Problem: When creating a product from an invoice form view, the list price set on the product is not saved on the product template. After creating the product, when checking the product from the products list, the set list price is not shown. Steps to reproduce: 1. Go to Accounting > Customers > Invoices 2. Create a new invoice 3. Create and edit a new product from the invoice line and set a new list price for the new product 4. Go to Sales > Products and open the created product 5. Check the list price of the product 6. Notice how the set list price is not shown on the product form view Cause: Product variants show lst_price while product templates show list_price on their form views. When creating a product from the invoice line, the shown form is for the product variant. When setting the list price on the product variant form (lst_price in that case), the inverse method of llst_price, which sets the list_price in return, is called during the creation of the variant, after the template has been created and saved. As a result, editing the list price does not trigger a write on the already saved product template, causing the list_price of the variant to be different than the list_price of the template. opw-6272825 Forward-Port-Of: odoo/odoo#270614
This update fixes an ambiguity in how dates are grouped by hour in Odoo. Previously, hour labels lacked AM/PM indicators, leading to unclear grouping of times like 1:00 PM. Now, all hour labels use a 24-hour format (HH:00), ensuring dates are grouped unambiguously and consistently.
Original PR description
Description of the issue/feature this PR addresses: When grouping datetime fields by hour, `read_group` formats the group display label using `hh:00 dd MMM`. In Babel/LDML formatting, `hh` represents…
Description of the issue/feature this PR addresses:
When grouping datetime fields by hour, `read_group` formats the group display label using `hh:00 dd MMM`.
In Babel/LDML formatting, `hh` represents a 12-hour clock. Since the format does not include an AM/PM marker, afternoon/evening hours are displayed ambiguously in grouped views.
Current behavior before PR:
A datetime value in the afternoon is grouped under a 12-hour label without AM/PM.
For example, records around `13:50` are displayed under:
01:00 20 Mar
Similarly, a datetime value around `16:20` may be grouped under:
04:00 26 Mar
This is ambiguous because the group header does not indicate whether the hour is AM or PM.
Example screenshot showing records around 13:xx grouped under `01:00`:
<img width="310" height="240" alt="image" src="https://github.com/user-attachments/assets/8768f2e8-9aaa-436b-af9f-40055a6032e9" />
Desired behavior after PR is merged:
Hour-based datetime group labels should be unambiguous.
The hour grouping format now uses `HH:00 dd MMM`, so grouped datetime labels render using a 24-hour clock.
For example:
13:00 20 Mar
16:00 26 Mar
This fixes the datetime hour grouping label shown in grouped list views and other `read_group` consumers.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#275219
Forward-Port-Of: odoo/odoo#274724A recent test failure related to API documentation generation was resolved. The issue stemmed from the test taking longer to complete as more Odoo modules are installed. This change ensures the test runs reliably regardless of the number of modules used.
Original PR description
The test_cache test failed a couple times on a timeout error, this is because the more modules are installed, the longer it takes to index them all and generate the json document. [runbot-240550](https://runbot.odoo.com/odoo/error/240550) Forward-Port-Of: odoo/odoo#274773