Monday, August 17, 2026
18 changes · saas-19.3
Enhancements to existing features
Filters are now completely exclusive, which prevent 0 results but also prevents more "open" searches as "Lenovo" OR "HP" AND "512GB SSD". Stop updating the filters based on selected attribute values to avoid the extra product query and allow selecting non exclusive filters from the same attribute. task-6341310 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Filters are now completely exclusive, which prevent 0 results but also prevents more "open" searches as "Lenovo" OR "HP" AND "512GB SSD". Stop updating the filters based on selected attribute values to avoid the extra product query and allow selecting non exclusive filters from the same attribute. task-6341310 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Doing an euclidean division on floats with the native operators is unreliable: because of IEEE-754 representation errors, `value1 % value2` can return a spurious remainder (e.g. `50.4 % 16.8 == 16.799999999999997` instead of 0.0) and `int(value1 / value2)` can truncate the quotient one step too low (e.g. `int(0.3 / 0.1) == 2` instead of 3). `float_div` returns the `(quotient, remainder)` pair free of those errors. The key is to never run a lossy `%` or `//` on the raw floats. Instead both ope
Original PR description
Doing an euclidean division on floats with the native operators is unreliable: because of IEEE-754 representation errors, `value1 % value2` can return a spurious remainder (e.g. `50.4 % 16.8 ==…
Doing an euclidean division on floats with the native operators is unreliable: because of IEEE-754 representation errors, `value1 % value2` can return a spurious remainder (e.g. `50.4 % 16.8 == 16.799999999999997` instead of 0.0) and `int(value1 / value2)` can truncate the quotient one step too low (e.g. `int(0.3 / 0.1) == 2` instead of 3). `float_div` returns the `(quotient, remainder)` pair free of those errors. The key is to never run a lossy `%` or `//` on the raw floats. Instead both operands are first snapped onto the precision grid with `float_round` and then scaled to integers: since a grid-snapped value is a multiple of `rounding`, dividing it by `rounding` counts how many grid steps it spans. That division is still noisy (`4.35 / 0.05 == 86.99999999999999`), so the result is passed through `builtins.round` to coerce it to the exact integer step count. The euclidean division itself is then a plain integer `divmod`, which is exact, and the remainder is scaled back to real units. This is why the correction is applied to the inputs and not to the output: rounding the result of a native `%` would only round an already-corrupt value, and would still misreport the quotient in the corner cases the util exists to handle. Dividing by `rounding` is meaningful for any precision, not only powers of ten: the grid step can be `0.05`, `0.25`, `0.5`, `0.03`, ... and `value / step` counts the steps in every case. This mirrors the normalize/denormalize scheme `float_round` already uses internally. The util shares `float_round`'s inherent limitation: the scaled step count must stay representable as an exact `float` integer, so exactness is lost past ~2**53 grid steps (extreme magnitudes at a fine precision). This is the IEEE-754 double-precision ceiling and is well outside any realistic quantity or price range. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280883 Forward-Port-Of: odoo/odoo#277160
Resolved issues and error corrections
An internal accounting test was updated to match a related platform fix that changes how grouped data is read. This helps keep automated checks accurate and reduces the risk of false test failures during future accounting updates.
Original PR description
The fix at https://github.com/odoo/odoo/pull/281911 adds bin_size: tru in the web_read_group. This commit adpats an accounting test as a consequence Forward-Port-Of: odoo/enterprise#127719 Forward-Port-Of: odoo/enterprise#127638
Miscellaneous changes
Allow resetting sent moves to draft. Ensures a rectificative flow exists or is created. Task: 6273211 Forward-Port-Of: odoo/odoo#273013
Original PR description
Allow resetting sent moves to draft. Ensures a rectificative flow exists or is created. Task: 6273211 Forward-Port-Of: odoo/odoo#273013
Changing the request unit of a time type should not recompute existing leaves, as their computed dates and duration must be preserved. This behavior was introduced in hr_holidays by removing the request unit from the dependencies of the leave date and duration computations. The French localization still declared `work_entry_type_request_unit` as a dependency of `_compute_date_from_to`, causing existing leaves to be invalidated and recomputed when the time type configuration changed. Thi
Original PR description
Changing the request unit of a time type should not recompute existing leaves, as their computed dates and duration must be preserved. This behavior was introduced in hr_holidays by removing the request unit from the dependencies of the leave date and duration computations. The French localization still declared `work_entry_type_request_unit` as a dependency of `_compute_date_from_to`, causing existing leaves to be invalidated and recomputed when the time type configuration changed. This commit removes this dependency to align the French computation with the base behavior and preserve historical leave values. Related: https://github.com/odoo/odoo/pull/261036 [error-243674 ](https://runbot.odoo.com/odoo/error/243674) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
## Issue When filtering projects using the "Timesheets >100%" filter, some projects with negative remaining hours (and with their `is_project_overtime` field set to True) won't be displayed, even though their expected hours are completed. This happens with projects which have tasks set to the "Done" or "Cancelled" state. The timesheets entries in those tasks are not taken into account when searching using the "Timesheets >100%" filter. ## Steps to reproduce 1. Install *Task Logs* (`hr_ti
Original PR description
## Issue When filtering projects using the "Timesheets >100%" filter, some projects with negative remaining hours (and with their `is_project_overtime` field set to True) won't be displayed, even…
## Issue
When filtering projects using the "Timesheets >100%" filter, some projects with negative remaining hours (and with their `is_project_overtime` field set to True) won't be displayed, even though their expected hours are completed.
This happens with projects which have tasks set to the "Done" or "Cancelled" state. The timesheets entries in those tasks are not taken into account when searching using the "Timesheets >100%" filter.
## Steps to reproduce
1. Install *Task Logs* (`hr_timesheet`)
2. Create a Project P (with Timehseets enabled)
3. Set the allocated hours of the project to 3:00 (3 hours)
4. Create two tasks:
- T1: State "In progress", and one timesheet entry of 2:00 (2 hours)
- T2: State "Done", and one timesheet entry of 2:00 (2 hours)
5. Back to the project view, set the filter to "Timesheets >100%"
6. **Project P is not shown, even though the total time spent on the project is 4 hours, completing the allocated hours set on the project.**
## Cause
The `_search_is_project_overtime` method filters out the tasks in "closed" states (Done/Cancelled) when computing the amount of time spent on the project.
https://github.com/odoo/odoo/blob/126b5bdd1e85771549198976f8570cd2ff167608/addons/hr_timesheet/models/project_project.py#L103-L114
This does not match with the behavior of the `_compute_is_project_overtime`, which does not take into account the state of the tasks to determine the value of the field:
https://github.com/odoo/odoo/blob/126b5bdd1e85771549198976f8570cd2ff167608/addons/hr_timesheet/models/project_project.py#L85-L94
This leads to a confusing behavior, where a project can have its `is_project_overtime` field set to True, but will still not be shown when using the "Timsheets >100%", even though that filter is defined as `[("is_project_overtime", "=", True)]`.
The compute method was updated by https://github.com/odoo/odoo/commit/d4252825f52a3172420dcda0ea394e42da9f8853, but the related search method was left unchanged, leading to this slight incoherence between the two methods.
opw-6422173
Forward-Port-Of: odoo/odoo#282338
Forward-Port-Of: odoo/odoo#281997On highly loaded runbots, waiting a single animation frame might not be sufficient for the table deselection to be available in the DOM after a key press. This commit waits for the table to be deselected before continuing the test. runbot-944722 Forward-Port-Of: odoo/odoo#282008
Original PR description
On highly loaded runbots, waiting a single animation frame might not be sufficient for the table deselection to be available in the DOM after a key press. This commit waits for the table to be deselected before continuing the test. runbot-944722 Forward-Port-Of: odoo/odoo#282008
**Steps to reproduce:** 1. Install Accounting 2. Import a new invoice with more than 1000 lines (xlsx file found in ticket attachments) 3. Test the imported records **Issue:** - `RecursionError: maximum recursion depth exceeded`. **Cause:** - In a previous commit (3e32d7b9eace62dfa7334009707a93967906c726) aimed at fixing stale analytic distribution totals, the assignment loop in `_compute_discount_allocation_needed` was changed from iterating over `self` to `self.move_id.line_ids`. -
Original PR description
**Steps to reproduce:** 1. Install Accounting 2. Import a new invoice with more than 1000 lines (xlsx file found in ticket attachments) 3. Test the imported records **Issue:** - `RecursionError:…
**Steps to reproduce:** 1. Install Accounting 2. Import a new invoice with more than 1000 lines (xlsx file found in ticket attachments) 3. Test the imported records **Issue:** - `RecursionError: maximum recursion depth exceeded`. **Cause:** - In a previous commit (3e32d7b9eace62dfa7334009707a93967906c726) aimed at fixing stale analytic distribution totals, the assignment loop in `_compute_discount_allocation_needed` was changed from iterating over `self` to `self.move_id.line_ids`. - While this ensured all lines generated updated distribution ratios, it violated the compute logic: assigning values to records outside the current compute batch (`self`). - By executing `line.discount_allocation_dirty = True` on external sibling lines, the method forced the ORM to trigger out-of-band `write()` calls. These writes re-triggered dependency checks (`_field_will_change`), which invoked the compute method again, leading to a recursive loop. **Fix:** 1. Revert the assignment iteration back to `for line in self:`. 2. To preserve the intention of the previous commit (ensuring all lines recompute their shared distribution pool when one line changes), modify the method's `@api.depends` to be `move_id.line_ids.discount` and `move_id.line_ids.analytic_distribution`. By declaring these relational dependencies, modifying a single line now batches all sibling lines into `self` from the start. This allows the lines to synchronize properly without triggering new ORM writes, eliminating the recursion. opw-6451854 Forward-Port-Of: odoo/odoo#282050
Steps to reproduce --- 1. Create and confirm a sale order. 2. Create a down payment invoice on it and post it: the down payment line reads "Down Payment (ref: INV/... on ...)". 3. Open that invoice and use Reverse and Create Invoice, then post the newly created draft down payment invoice. 4. Open the sale order: the down payment line has lost its reference and now reads only "Down Payment", and that empty label also carries over to the down payment section when generating the final invoice.
Original PR description
Steps to reproduce --- 1. Create and confirm a sale order. 2. Create a down payment invoice on it and post it: the down payment line reads "Down Payment (ref: INV/... on ...)". 3. Open that invoice…
Steps to reproduce --- 1. Create and confirm a sale order. 2. Create a down payment invoice on it and post it: the down payment line reads "Down Payment (ref: INV/... on ...)". 3. Open that invoice and use Reverse and Create Invoice, then post the newly created draft down payment invoice. 4. Open the sale order: the down payment line has lost its reference and now reads only "Down Payment", and that empty label also carries over to the down payment section when generating the final invoice. Issue --- The down payment line description is built by `_get_downpayment_description`, which only produces the "Down Payment (ref: ... on ...)" label when exactly one customer invoice is linked to the down payment `sale.order.line`, guarded by `len(invoice) == 1`. https://github.com/odoo/odoo/blob/3a5f7431effd4b2b2eb8ce3eed81aaba42fcd8ea/addons/sale/models/sale_order_line.py#L484-L509 Reverse and Create Invoice runs `account.move.reversal.modify_moves`, which copies the reversed invoice with `include_business_fields=True`, so the copied line keeps its `sale_line_ids` and the new draft invoice is attached to the very same down payment line as the reversed original. https://github.com/odoo/odoo/blob/3a5f7431effd4b2b2eb8ce3eed81aaba42fcd8ea/addons/account/wizard/account_move_reversal.py#L142-L149 That down payment line then references two `out_invoice` moves (the reversed one and the re-issued one), so `len(invoice) == 1` is false and the label silently falls back to the bare "Down Payment", losing the reference that the final invoice's down payment section reuses. Going back to the sale order to raise a fresh down payment instead creates a new line, which keeps a single invoice and is why the slower flow is unaffected. The `len(invoice) == 1` guard was introduced in ba954604e529. Discarding the reversed invoice (`payment_state == 'reversed'`) leaves the active re-issued invoice as the single match, so its reference is shown again; when the only linked invoice is itself reversed, the fallback keeps displaying it so existing descriptions are preserved. opw-6353384 Forward-Port-Of: odoo/odoo#277802
### Steps to reproduce: - Enable "Lots & Serial Numbers" in the Inventory settings - Create a storable product tracked by lots - Create a lot for that product and leave it without any quantity - Open the lot form > cog menu > Scrap #### > ValueError: Expected singleton: stock.location() ### Cause of the issue: A lot is only given a `location_id` when all its positive quants lay in a single location, so a lot with no quant at all has none: https://github.com/odoo/odoo/blob/8b8852f1c3
Original PR description
### Steps to reproduce: - Enable "Lots & Serial Numbers" in the Inventory settings - Create a storable product tracked by lots - Create a lot for that product and leave it without any quantity - Open…
### Steps to reproduce: - Enable "Lots & Serial Numbers" in the Inventory settings - Create a storable product tracked by lots - Create a lot for that product and leave it without any quantity - Open the lot form > cog menu > Scrap #### > ValueError: Expected singleton: stock.location() ### Cause of the issue: A lot is only given a `location_id` when all its positive quants lay in a single location, so a lot with no quant at all has none: https://github.com/odoo/odoo/blob/8b8852f1c3ae5b78a4a3e99c99eacab83f0be5c9/addons/stock/models/stock_lot.py#L169-L172 The `action_scrap` nevertheless always forwards that value to the scrap move, so the form is opened with `default_location_id` set to `False`: https://github.com/odoo/odoo/blob/8b8852f1c3ae5b78a4a3e99c99eacab83f0be5c9/addons/stock/models/stock_lot.py#L415-L426 Now, the issue is that the `_onchange_lot_ids` of the new stock move then evaluates the reservation of a move whose source location is still empty which raises the traceback because of a `self.ensure_one` required on the location to determine if the move `should_bypass_reservation`: https://github.com/odoo/odoo/blob/8b8852f1c3ae5b78a4a3e99c99eacab83f0be5c9/addons/stock/models/stock_move.py#L1515 https://github.com/odoo/odoo/blob/8b8852f1c3ae5b78a4a3e99c99eacab83f0be5c9/addons/stock/models/stock_move.py#L1989-L1992 https://github.com/odoo/odoo/blob/8b8852f1c3ae5b78a4a3e99c99eacab83f0be5c9/addons/stock/models/stock_location.py#L414-L416 Note that if the default key was not present, the traceback would not be triggered and the scrap would be performed from the `default_stock_location` of the company: https://github.com/odoo/odoo/blob/4c4219a7d9d51f703b15e83ab755faf1f2c8a71d/addons/stock/models/res_company.py#L21-L22 Indeed the issue is that the `default_get` looks the context key up by *membership*, so that a falsy `default_location_id` is still returned as a default value for the field if provided: https://github.com/odoo/odoo/blob/8b8852f1c3ae5b78a4a3e99c99eacab83f0be5c9/odoo/orm/models.py#L1313-L1317 And therefore will not be computed in the first onchange: https://github.com/odoo/odoo/blob/8b8852f1c3ae5b78a4a3e99c99eacab83f0be5c9/addons/web/models/models.py#L1974-L1988 Note: The `stock.lot.action_scrap`, and this `default_location_id` line with it, were introduced by 1c7d80a10b5d, which replaced the `stock.scrap` model by scrap `stock.move` records. That commit is only present from saas-19.2 onwards, so earlier versions are not affected. opw-6441937 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280666
How to reproduce: - In a Fiscal Position, map the Downpayment account set in the settings to anything else - Put that Fiscal Position on a SO. - On that SO, create a Downpayment invoice -> The regular Downpayment account is used on the Downpayment invoice, but it should have been mapped because of the Fiscal Position account mapping Solution: Pre-map the company's default down payment account using the Sales Order's Fiscal Position before passing it to the invoice line creation
Original PR description
How to reproduce: - In a Fiscal Position, map the Downpayment account set in the settings to anything else - Put that Fiscal Position on a SO. - On that SO, create a Downpayment invoice -> The regular Downpayment account is used on the Downpayment invoice, but it should have been mapped because of the Fiscal Position account mapping Solution: Pre-map the company's default down payment account using the Sales Order's Fiscal Position before passing it to the invoice line creation. This ensures the correct account mapping is always respected for advance payment invoices. Task-6212218 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280777 Forward-Port-Of: odoo/odoo#279464
Before this commit and since the new read_group (which fetches records from open groups server side), images were loaded as base64, overloading the return payload and potentially triggering overload errors (MemoryError) This was because the bin_size = true context key was forgotten. After this commit, images are not loaded as base64 thanks to that context key Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged:
Original PR description
Before this commit and since the new read_group (which fetches records from open groups server side), images were loaded as base64, overloading the return payload and potentially triggering overload errors (MemoryError) This was because the bin_size = true context key was forgotten. After this commit, images are not loaded as base64 thanks to that context key 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#282099 Forward-Port-Of: odoo/odoo#281911
Steps: - Install sale_management - Make sure you have 100 quotations with 1 activity each - Open activity view - Default pager displays `1-100/100` - Activity count display `To-do 80` ActivityController uses `useModel` which passes the raw `component.props` to `model.load()`, including the limit from `ir.actions.act_window` (default 80). This value ended up in `fetchActivityData` via `params.limit || this.initialLimit`, overriding `ActivityModel.DEFAULT_LIMIT` (100). The records li
Original PR description
Steps: - Install sale_management - Make sure you have 100 quotations with 1 activity each - Open activity view - Default pager displays `1-100/100` - Activity count display `To-do 80`…
Steps: - Install sale_management - Make sure you have 100 quotations with 1 activity each - Open activity view - Default pager displays `1-100/100` - Activity count display `To-do 80` ActivityController uses `useModel` which passes the raw `component.props` to `model.load()`, including the limit from `ir.actions.act_window` (default 80). This value ended up in `fetchActivityData` via `params.limit || this.initialLimit`, overriding `ActivityModel.DEFAULT_LIMIT` (100). The records list was not affected because `RelationalModel._getNextConfig` never reads `params.limit` (limit is not a `SEARCH_KEY`), so it always loaded 100 records correctly. But `fetchActivityData` used 80, causing a mismatch between the records shown and the activity counts in the column headers. ```js export const SEARCH_KEYS = ["comparison", "context", "domain", "groupBy", "orderBy"]; ``` The fix strips `params.limit` in `ActivityModel.load()` before passing params to `fetchActivityData`, so it falls back to `this.initialLimit (100)`. The pager `onUpdate` handler calls `fetchActivityData` directly with its own `params.limit` and is not affected. However, `ActivityController` never forwards `limit` to the model. This is why we always have `ActivityModel.DEFAULT_LIMIT (100)` without taking into account actions's limit. To fix this we have to add the limit via `this.props.limit`, as `ListController`. `useModelWithSampleData` already had the correct behavior by calling `model.load(getSearchParams(props))` which filters out non-search params like limit. In 19.0 useModel was updated to do the same, so the issue does not exist there. Link to 19.0 fix: https://github.com/odoo/odoo/pull/211697 opw-6281125 Forward-Port-Of: odoo/odoo#281227 Forward-Port-Of: odoo/odoo#273929
In this commit: - Ensure event ticket information is preserved during self-order processing and use the configured ticket price when recomputing order line prices. - This prevents ticket prices from being replaced by the product price after proceeding to payment and keeps the amounts consistent across the payment page. Task:6375899 Forward-Port-Of: odoo/odoo#275645
Original PR description
In this commit: - Ensure event ticket information is preserved during self-order processing and use the configured ticket price when recomputing order line prices. - This prevents ticket prices from being replaced by the product price after proceeding to payment and keeps the amounts consistent across the payment page. Task:6375899 Forward-Port-Of: odoo/odoo#275645
Before this commit, deleting a record leaves its id in the relations of a record deleted before it in the same update, and reading one of those relations hands out an entry for a record that is gone. This happens because an update takes a deleted record out of the relations that hold it, but forgets it as soon as it is deleted. However, deleting a record is what queues the deletion of the records it holds: `channelMembers` carries `onDelete: (r) => r.delete()`, so the members of a thread are
Original PR description
Before this commit, deleting a record leaves its id in the relations of a record deleted before it in the same update, and reading one of those relations hands out an entry for a record that is gone. This happens because an update takes a deleted record out of the relations that hold it, but forgets it as soon as it is deleted. However, deleting a record is what queues the deletion of the records it holds: `channelMembers` carries `onDelete: (r) => r.delete()`, so the members of a thread are deleted once the thread is already forgotten, and their ids stay in its `onlineMembers`. This commit fixes the issue by keeping the records deleted by an update known until it ends. Forward-Port-Of: odoo/odoo#282485 Forward-Port-Of: odoo/odoo#281983
When searching on the Website site, using the main search on the navbar, it opens a list view with the results (`website.list_hybrid`) which raises the warning on the logs (2 times): "Unknown directives or unused attributes: {'t-key'} in website.list_hybrid"  This happens after the attribute `t-key` was added to the template [\[1\]] because the template is only use
Original PR description
When searching on the Website site, using the main search on the navbar, it opens a list view with the results (`website.list_hybrid`) which raises the warning on the logs (2 times): "Unknown…
When searching on the Website site, using the main search on the navbar, it opens a list view with the results (`website.list_hybrid`) which raises the warning on the logs (2 times):
"Unknown directives or unused attributes: {'t-key'} in website.list_hybrid"

This happens after the attribute `t-key` was added to the template [\[1\]] because the template is only used in QWeb. The validation for them doesn't include the `t-key` [\[2\]] as one of the "iter_directives" nor has a `_compile_directive_*` method to check and remove it from the validation as it's done with the `t-as` and `t-foreach`.
This also causes the raise of the warnings on tours that use the tour method `searchProduct` (of the module `website_sale`) because it uses the first input with the name of search and happens to be the search on the navbar.

[\[1\]]: https://github.com/odoo/odoo/commit/7b1d82aa
[\[2\]]: https://github.com/odoo/odoo/blob/f52cfb09/odoo/addons/base/models/ir_qweb.py#L1400
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#179017Currently, with images enabled for quotation reports and if the product name is long enough, it overflows through the column border a bit before breaking to the next line. This seems to be caused by some incompatibility between wkhtmltopdf and d-flex, adding `col` to the product name container forces it to respect column boundaries. This commit also adds `text-break` as having a long uninterupded string in the description would end up stretching the column and making the next ones disapear
Original PR description
Currently, with images enabled for quotation reports and if the product name is long enough, it overflows through the column border a bit before breaking to the next line. This seems to be caused by…
Currently, with images enabled for quotation reports and if the product name is long enough, it overflows through the column border a bit before breaking to the next line. This seems to be caused by some incompatibility between wkhtmltopdf and d-flex, adding `col` to the product name container forces it to respect column boundaries. This commit also adds `text-break` as having a long uninterupded string in the description would end up stretching the column and making the next ones disapear. <img width="811" height="266" alt="image" src="https://github.com/user-attachments/assets/90043c88-d03f-4324-9935-e669f6a256ab" /> <img width="964" height="431" alt="image" src="https://github.com/user-attachments/assets/2b8e8a6c-6fd5-4813-8160-d94bbb5490d1" /> ### Steps to reproduce: - Enable Display Product Images in the setting - Create a product with an image - Create a quotation with said product and add a description that is long enough to break to the next line - Print said quotation - You will notice that before the line breaks it will overflow to the next column (you might need to tweak the description a bit by removing or adding a few lines) opw-6367076
Steps to reproduce: 1. Install `l10n_pe` 2. Create and set the current company to the Peru company 3. In mobile view, try to create a contact 4. Fill in the identification number type to RUC Issue: - The field of VAT is collapsed and not visible Cause: - The VAT div `vat_div` is displayed as a flex row (`o_row d-flex`) so the 'add identifier' button sits on the same line as the VAT field. https://github.com/odoo/odoo/blob/7d2d41fdef3446ca118290c1b31287887c0794db/addons/account/vie
Original PR description
Steps to reproduce: 1. Install `l10n_pe` 2. Create and set the current company to the Peru company 3. In mobile view, try to create a contact 4. Fill in the identification number type to RUC Issue: -…
Steps to reproduce:
1. Install `l10n_pe`
2. Create and set the current company to the Peru company
3. In mobile view, try to create a contact
4. Fill in the identification number type to RUC
Issue:
- The field of VAT is collapsed and not visible
Cause:
- The VAT div `vat_div` is displayed as a flex row (`o_row d-flex`) so the 'add identifier' button sits on the same line as the VAT field.
https://github.com/odoo/odoo/blob/7d2d41fdef3446ca118290c1b31287887c0794db/addons/account/views/partner_view.xml#L169-L171
Localizations based on `l10n_latam_base` also put an identification type field (e.g. RUC, DNI) in that same row, before the VAT field.
https://github.com/odoo/odoo/blob/7d2d41fdef3446ca118290c1b31287887c0794db/addons/l10n_latam_base/views/res_partner_view.xml#L14-L21
That identification type field carried the `oe_inline` class, which matched an unrelated, pre-existing mobile-only rule forcing any inline many2one to `width: 100% !important`.
https://github.com/odoo/odoo/blob/7d2d41fdef3446ca118290c1b31287887c0794db/addons/web/static/src/views/form/form_controller.scss#L999-L1001
Inside the flex row this left no space for its sibling, collapsing the VAT value input.
<table>
<tr>
<th width="50%">Before</th>
<th width="50%">After</th>
</tr>
<tr>
<td width="50%">
<img src="https://github.com/user-attachments/assets/12b1774f-2c60-4c89-a348-ccf514528552" width="100%">
</td>
<td width="50%">
<img src="https://github.com/user-attachments/assets/3f1571f1-8e88-41d3-89bb-b9e2ce1e85fc" width="100%">
</td>
</tr>
</table>
Solution:
- Drop the `oe_inline` class from the identification type field in `l10n_latam_base`'s partner view.
opw-6375655