Daily updates from Odoo
Thursday, July 23, 2026
62 changes · saas-19.2
Enhancements to existing features
French VAT declarations now handle SIRET numbers even when users enter spaces, preventing avoidable submission failures. The update also adds a warning for incorrectly formatted bank account numbers, helping users correct payment details before sending declarations.
Original PR description
This commit resolves an issue where VAT declarations failed when the provided SIRET number included spaces. Since check_siret verifies the format, we now strip all spaces from the input. Additionally, this commit introduces a validation for bank account numbers, ensuring that we warn the user if the account number is wrongly formatted. task-6253745 Forward-Port-Of: odoo/enterprise#124718 Forward-Port-Of: odoo/enterprise#120689
When users choose a project in the timesheet timer, the system now automatically suggests the task they most recently logged time on for that project. For Helpdesk projects, it similarly suggests the most recent ticket, helping users continue work faster while still allowing easy changes.
Original PR description
When selecting a project in the timesheet timer, the task on which the user most recently logged time for that project is now prefilled, as they are most likely to keep logging time on it. If not, selecting a different task only requires one click. For Helpdesk projects, where the timer shows the ticket field instead of the task field, the most recently timesheeted ticket is prefilled in the same way. task-6359030
The employee time-off planning view now loads absence information much faster for large teams by grouping background data requests and limiting records to the selected date range. This helps managers and operational teams quickly see who is away without long waiting times.
Original PR description
At odoo, our friendly kitchen chef needs to know who is off on any given day. To know that, they use the holiday gantt view and display all employees and check the sum. For 200+ employees working at GR2, `get_gantt_data` takes 7+ seconds `_unavailable_intervals_batch` is called for each individual version, which means it's not batched. Ultimatly, it leads to lots of sql queries that could be grouped together. With this commit, the calls are batched per calendar before: ~7s after: ~900ms-1s
Since [website builder refactor], a date field or a datetime that appears in the page is not editable from website builder. This commit re-introduces the ability to do so. [website builder refactor]: 9fe45e2b7ddbbfd0445ffe25a859e67a316d02b2 task-6230582 Forward-Port-Of: odoo/odoo#277408 Forward-Port-Of: odoo/odoo#270325
Original PR description
Since [website builder refactor], a date field or a datetime that appears in the page is not editable from website builder. This commit re-introduces the ability to do so. [website builder refactor]: 9fe45e2b7ddbbfd0445ffe25a859e67a316d02b2 task-6230582 Forward-Port-Of: odoo/odoo#277408 Forward-Port-Of: odoo/odoo#270325
Before this commit, when an authentication process was ongoing it was not very clear to the user This commit adds a banner to warn the user to not cancel the ongoing process or it will be aborted. task-6372665 Forward-Port-Of: odoo/odoo#277074 Forward-Port-Of: odoo/odoo#275230
Original PR description
Before this commit, when an authentication process was ongoing it was not very clear to the user This commit adds a banner to warn the user to not cancel the ongoing process or it will be aborted. task-6372665 Forward-Port-Of: odoo/odoo#277074 Forward-Port-Of: odoo/odoo#275230
In some cases, you want to redirect a record with ModelConverter, whatever the slug value. E.g. /shop/old-name-1 => /shop/alt-product-10 /shop/new-name-1 => /shop/alt-product-10 /fr/shop/nom-1 => /shop/alternatif-product-10 /de/shop/produktname-1 => /de/shop/produktname-10 In this case, adding only one redirect /shop/1 => /shop/10 covers the need to support all the translated slugs and the old name that we remember. On odoo.com we have this need e.g. when we archive a
Original PR description
In some cases, you want to redirect a record with ModelConverter, whatever the slug value.
E.g. /shop/old-name-1 => /shop/alt-product-10
/shop/new-name-1 => /shop/alt-product-10
/fr/shop/nom-1 => /shop/alternatif-product-10
/de/shop/produktname-1 => /de/shop/produktname-10
In this case, adding only one redirect /shop/1 => /shop/10 covers the need to support all the translated slugs and the old name that we remember.
On odoo.com we have this need e.g. when we archive a Job Position, we create a redirect, but in some cases the job position is translated or has been renamed and we don't remember all the old urls. With this change, we will be able to redirect all old urls, translated urls, ... with only one redirect.
/jobs/10 -> /explore-more-opportunities-with-us
task-6391567
Forward-Port-Of: odoo/odoo#276515Resolved issues and error corrections
The asset screen now labels the related accounting lines more clearly as Related Items. Opening that list keeps users in the useful list view instead of sending them to an unhelpful journal item form, reducing confusion when reviewing asset entries.
Original PR description
If you create an asset and confirm it, you can see the Related Entries using the smart button Related Entries. The list view that opens is clickable, but it opens a quite useless form view of the Journal Items. - Rename breadcrumb button to Related Items - Make it behave like action_account_moves_all, to not open form view Ticket: [6385260](https://www.odoo.com/odoo/project/967/tasks/6385260)
This fix makes automated barcode scrap testing more reliable by ensuring entered scrap quantities are properly retained before saving. It helps prevent false test failures that could slow down validation and release workflows.
Original PR description
These barcode scrap tours randomly trigger "You can only enter positive quantities." on runbot: the quantity set with a raw input.value is dropped when the field re-renders before the scrap is saved, so it scraps 0. Dispatching an input event keeps the typed value. error-238911
This fix removes an outdated internal call that could cause an error when the timer feature was opened or used. It helps keep timer-related workflows stable without changing how users interact with the feature.
Original PR description
`getServerOffset` was removed from the timer service, so calling it in the `useTimer` hook causes a traceback once the hook is actually used. This PR removes the leftover call.
The French VAT report XML now places the express mention in the correct form section instead of the identification area. This helps ensure submissions to Aspone meet the expected format and reduces the risk of rejected filings.
Original PR description
in this commit: https://github.com/odoo/enterprise/commit/93c1a4fe15d1f09e4c3df3a5db0e06006121c027 we added a way to have an express mention in the xml sent to aspone. But we placed it in the "T-IDENTIF" zone, but this zone doesn't accept express mention. It should be located in the form it self. task-6253745 Forward-Port-Of: odoo/enterprise#124471 Forward-Port-Of: odoo/enterprise#123235
Opening transfers in the Barcode app now uses a default limit when loading reusable packages. This prevents very large package lists from causing long wait times, helping warehouses with high package volumes access transfers more quickly.
Original PR description
# How to reproduce - Have a lot of reusable & locationless packages (e.g. > 10 000) - Go to any transfer via the barcode application # The issue There is a very long loading time, even in local…
# How to reproduce - Have a lot of reusable & locationless packages (e.g. > 10 000) - Go to any transfer via the barcode application # The issue There is a very long loading time, even in local testing. The client of the tickets experiences loadings up to 120 seconds with 50k packages # Cause When opening a transfer, we load barcode data by doing an API call to `_get_stock_barcode_data` : https://github.com/odoo/enterprise/blob/fe058ef501767b7ed9758fc9264f664b32c6bae8/stock_barcode/models/stock_picking.py#L85 During this we preload a lot of records, notably packages : https://github.com/odoo/enterprise/blob/fe058ef501767b7ed9758fc9264f664b32c6bae8/stock_barcode/models/stock_picking.py#L128 The issue is that in the fields we read for the packages, two of them (`location_dest_id` & `contained_quant_ids`) have a `_read_group` in their compute (or in the compute of one of the fields they depend on) : https://github.com/odoo/odoo/blob/625e6bcbd66c45ea2f699df14e2ea12e2e28a893/addons/stock/models/stock_package.py#L65 https://github.com/odoo/odoo/blob/625e6bcbd66c45ea2f699df14e2ea12e2e28a893/addons/stock/models/stock_package.py#L146 Fortunately, this does not mean that we make a query for every records. Instead, in Odoo, we fetch records in batch of 1000. So, for the case of the client, every time he loads the database, the backend does 50 000 / 1000 x 2 = 100 queries, which hinders performance a lot A [PERF] commit was done to limit the number of packages that are fetched base on a config parameter. The problem is that this parameter does not have a default value, so clients still end up with the problem. [PERF]: https://github.com/odoo/enterprise/commit/efe18bc1ea479270e42846986d7ed449b0865617 # Proposed Solution Add a default value for that config parameter. The exact value is up to discussion opw-6200730 Forward-Port-Of: odoo/enterprise#124538 Forward-Port-Of: odoo/enterprise#123696
Fixed Belgian annual statement XBRL exports so required values like true/false and currency units are no longer translated when generated in Dutch. This prevents affected filings from being rejected by the National Bank of Belgium validator.
Original PR description
Steps to reproduce: - Set the user language to Dutch. - Go to Accounting > Reporting > Annual Statements. - Generate the XBRL export for a report other than the "company, abridged" (acon) balance…
Steps to reproduce:
- Set the user language to Dutch.
- Go to Accounting > Reporting > Annual Statements.
- Generate the XBRL export for a report other than the "company,
abridged" (acon) balance sheet/P&L combination, e.g. an association
(asso_a/asso_f) or "company, full"/"company, capital" report.
- Open the file: the `<met:bln1>` boolean facts are exported as
"onwaar" instead of "false", which is not a valid XBRL boolean
lexical value and gets rejected by the NBB validator.
Cause of the issue:
QWeb templates translate static text nodes by default. The base
module ships a generic `msgid "false" -> msgstr "onwaar"` translation,
used elsewhere in the UI, which silently hijacks the literal
"false"/"true" and unit tokens ("iso4217:EUR", "pure") in the XBRL
data templates whenever the file is generated in Dutch.
Solution:
Add `t-translation="off"` on the `<met:bln1>` boolean facts and the
`<measure>` unit tokens in the 5 remaining XBRL templates,
so these fixed-vocabulary XBRL values are never subject to translation
opw-6395785
Forward-Port-Of: odoo/enterprise#124945A test setup for AI embeddings was corrected so it no longer mixes demo data using a different provider format. This helps keep automated quality checks reliable and prevents false failures when validating Gemini-related AI behavior.
Original PR description
_cron_generate_embedding retrieves all the sources that don't have an embedding and generate embeddings for those using the model from the provider of the agent configured on the source. The agent configured on the demo sources has OpenAI as the provider and these sources don't have embeddings. When _cron_generate_embedding runs in the test case, it retrieves these demo sources + the source defined in the test case (Which relies on embeddings from Google) and generates the embeddings but then fails. This happens because the _request method is mocked to return the response in Google's format as the test case is specific to Gemini models. runbot.build.error-944173 Forward-Port-Of: odoo/enterprise#124977
Odoo updated its e-signature integration to match recent emSigner interface and API changes. Certificates added through emSigner should now appear in the correct position on signed PDFs, avoiding confusing or unprofessional document output.
Original PR description
Before: - Certificate added by emSigner was misaligned in the signed PDF after recent UI changes. After: - Updated coordinates to ensure the emSigner certificate is properly aligned and displayed correctly in Odoo. task-6105264 Forward-Port-Of: odoo/enterprise#113402
Delivery guides for Chilean electronic stock documents no longer fail when a kit includes components measured in a different unit type than the kit itself. The system now prices those component lines using the component product pricing instead of attempting an invalid unit conversion, allowing users to print delivery guides successfully.
Original PR description
When a kit is delivered, each component move is linked to the kit's sale order line. Pricing the delivery guide in "sale order" mode converted the component quantity into the kit's sale UoM. For a component sold in a different UoM category than the kit, this cross-category conversion raises a UserError. Steps to reproduce: - Create a BoM for a kit product with a component in a different UoM category - Create a customer with Delivery Guide Price = "From Sale Order" - Sold the kit in a sale order and deliver it - On the delivery, print the delivery guide -> error This fix makes the guide price for a component move to be "product" if the component's product is different from the related sale line product, avoiding the cross-category UoM conversion. opw-6327895 Forward-Port-Of: odoo/enterprise#125114 Forward-Port-Of: odoo/enterprise#122776
The timesheet progress percentage now updates immediately when timesheets are added, changed, or deleted. This keeps project and sales tracking information accurate on screen without requiring users to refresh the page.
Original PR description
Issue: The percentage is only updated after reloading the page. Cause: The percentage computation is performed inside `loadTimesheets`, which is only called when the timesheets are loaded. Fix: Move the percentage computation into a helper function and invoke it whenever a timesheet is added, updated, or removed. task-6401186 Forward-Port-Of: odoo/enterprise#125074
The Barcode app now correctly blocks a package from being scanned twice during deliveries, even when multiple packages are part of the same transfer. This prevents duplicated stock movements and avoids creating incorrect negative inventory quantities after validation.
Original PR description
Steps to reproduce --- 1. Enable Packages and turn on "Move Entire Packages" on the delivery operation type. 2. Create a storable product P and add 2 units in different package in stock: 1 in…
Steps to reproduce --- 1. Enable Packages and turn on "Move Entire Packages" on the delivery operation type. 2. Create a storable product P and add 2 units in different package in stock: 1 in PACK001, 1 in PACK002 3. In the Barcode app > Operations > Delivery > New 4. Scan a first package PACK001, then a second different package PACK002 5. Scan the first package PACK001 again. Issue --- Re-scanning an already scanned package is meant to be rejected with a "This package is already scanned." warning, but the rejection stops working as soon as a second package is present in the transfer, so the package content gets added a second time and, once validated, the source quant goes negative (the package ends up holding a negative and a positive quant of the same product). Commit 23613c63947 added a canPackSomeLines flag that is set to true for every package line that is not the scanned one, so any other package in the transfer makes the alreadyDonePackId && !canPackSomeLines guard false and silently skips the warning. The scanned package already exposes whether it had something left to pack through scannedPackages, so gating the warning on that flag instead keeps the check working regardless of how many other packages are in the transfer. https://github.com/odoo/enterprise/blob/3cc1a162e61662814b0e52c0c720831952d208a8/stock_barcode/static/src/models/barcode_picking_model.js#L1976-L2006 opw-6279105 Forward-Port-Of: odoo/enterprise#121755
Resetting a submitted tax return no longer removes the company-wide tax lock date, preventing closed accounting periods from being unintentionally reopened for all users. The change also ensures companies can set the tax lock date before submitting a return while still allowing the required closing entry to be created correctly.
Original PR description
To reproduce the issue: 1) Initialize a company in Belgium, create the tax returns 2) Submit the VAT return from January 3) Open the lock date wizard. The tax lock date is January 31st. 4) Add a lock…
To reproduce the issue:
1) Initialize a company in Belgium, create the tax returns 2) Submit the VAT return from January
3) Open the lock date wizard. The tax lock date is January 31st. 4) Add a lock date exception removing the tax lock date just for you, for 5 min. 5) Reset January's return
6) Reopen the lock date wizard.
====> Your exception is still there, but the tax lock date for everyone has been reset to December 31st.
This is plain wrong. Resetting a return should not automatically reopen the period for everyone. Lock dates exceptions/modifications are anyway required to reset the return ; they should pilot the whole flow. Nothing being magically hidden from the user means there can't be someone else mistakenly encoding something into the reopened period.
Another fix was required to make this one work: setting the tax lock date before submitting the return should work. In bigger environments, users might want to do that as a first step to reduce the number of people encoding data before actually doing the submission of the return. Therefore, the case where the tax lock date is already set at the date_to of the return when submitting it was supposed to be already supported, and allow the creation of the closing entry for that return, despite it being on the tax lock date. The test ensuring this was however badly written, and the feature didn't work: the closing was created at a later date than the lock date automatically, due to the Bills' Algorithm.
Forward-Port-Of: odoo/enterprise#124872
Forward-Port-Of: odoo/enterprise#124811This fixes an issue where setting certain Uruguay electronic invoicing records back to draft could fail when triggered remotely. The change ensures the action returns a valid response, preventing an error that could interrupt accounting workflows.
Original PR description
Calling the method in RPC causes an error: ``` TypeError: cannot marshal None unless allow_none is enabled ``` Forward-Port-Of: odoo/enterprise#124740 Forward-Port-Of: odoo/enterprise#124653
Point of sale IoT setup now works better with newer IoT Boxes that no longer report certain device details. The system avoids relying on missing subtype or manufacturer information, helping printers and payment terminals be found more reliably.
Original PR description
Newer IoT Boxes don't share device subtype or manufacturer. We then adapt the domains to avoid searching on fields that aren't filled. task-6388669 task-6388733 Forward-Port-Of: odoo/enterprise#124937 Forward-Port-Of: odoo/enterprise#124306
This fix ensures POS invoice settlement amounts are recalculated correctly when a POS session is closed. It prevents customers from being shown or charged an inflated settlement amount after a partial invoice payment.
Original PR description
`pos_amount_unsettled` is a stored computed field defined as the invoice's residual minus the settle lines belonging to sessions that are not yet closed. Its compute method filters the lines on…
`pos_amount_unsettled` is a stored computed field defined as the invoice's residual minus the settle lines belonging to sessions that are not yet closed. Its compute method filters the lines on `order_id.session_id.state`, but that state is not in the compute dependencies. When closing a session holding a settle order, `_validate_session()` first reconciles the settle payment with the invoice (which lowers `amount_residual_signed` and flags the field for recomputation) and only then writes `state = 'closed'` on the session. If the pending recomputation is executed in that window (any flush of `account.move` does it: recomputing the field for any other flagged record drags the whole queue along), the settle line is deducted from the already reconciled residual, i.e. counted twice, and the field is stored as `residual - settled` instead of `residual`. Since the session state is not a dependency, writing `state = 'closed'` does not flag the field again and the wrong value is never corrected. The partner's `invoices_amount_due` then goes negative, which hides the "Settle invoices" option in the POS partner list and inflates the "Settle due amount" proposal (`remainingDue = total_due - pos_orders_amount_due - invoices_amount_due`): a customer owing e.g. 500 is proposed, and charged, 700. Steps to reproduce: 1. Post a customer invoice of 1000. 2. In the POS, select the customer > Settle invoices, pick the invoice, set the amount to 700 and pay in cash. 3. Close the session. The issue only occurs when the pending recomputation runs during the closing, which depends on the other operations performed by it (not deterministic in real usage; the regression test forces it with a flush after the reconciliation). 4. The invoice's "Amount To Pay In POS" shows -400 instead of 300 and the POS proposes to settle 700 instead of 300. Add the session state to the compute dependencies so that the field is recomputed once the session is closed, yielding the correct amount regardless of any intermediate recomputation. opw-6375095 Forward-Port-Of: odoo/enterprise#123783
This fixes a layout issue in Knowledge where embedded views could lose their intended top alignment when placed as the first editable item. Users get a more consistent editing experience with embedded content appearing where expected.
Original PR description
This commit updates the embedded view top-alignment selector to account for selection placeholders introduced by https://github.com/odoo/odoo/commit/edf7f7bb0c62978640c181eccb4934855d5d872d. This preserves the intended top-alignment behavior when an embedded view is the first editable element in the knowledge editor. Task-5951196 Forward-Port-Of: odoo/enterprise#125080
This update fixes an unstable automated test in Web Studio that could fail unpredictably. It helps keep quality checks reliable so valid changes are less likely to be blocked by false test failures.
Belgian VAT returns can once again include comments in the generated XML file. This restores a previously removed capability, helping businesses add required context or explanations when submitting VAT returns.
Original PR description
This feature had been mistakenly removed. Forward-Port-Of: odoo/enterprise#124865
Account reports opened from a VAT return check now continue to work when the page is refreshed. This prevents users from hitting an error and losing access to the report in that workflow, while reports opened from menus are unchanged.
Original PR description
Opening an account report through the VAT return button on an account.return.check record returns an inline client action whose report_id only exists in context. On refresh, Odoo will throw an error because it will try to rebuild the action context based off of the URL which is deficient. This will not effect reports opened via the menu since those follow a different pathway. This fix anchors the inline action to the "path" property stored on the client action. A helper method was added for deriving the action_id from a given report. opw-6366964 Forward-Port-Of: odoo/enterprise#124560
The trial balance report now handles load-more rows that contain no column data, avoiding a crash in the Colombian partner-grouped view. This keeps users working smoothly when expanding large account sections with limited row loading enabled.
Original PR description
…umn dict Steps to reproduce: - Install l10n_co_reports and select CO company - Open the trial balance grouped by partner variant - Set the load more limit to 2 - Go back to report, unfold an account, and press load-more line -> Traceback because it's expected the column dict to contain a column group. The report engine, however, accepts lines with empty dicts. Therefore, the trial balance should handle this case. task-6384451 Forward-Port-Of: odoo/enterprise#124102
Steps to reproduce: - Install `project`, open a project and switch to the Gantt view - Start dragging a task while holding Ctrl (copy mode), then switch browser tab with Ctrl+Tab (or Ctrl+Shift+Tab, Ctrl+PgUp/PgDn) - Come back to the Gantt tab and drop the task without holding Ctrl Issue: The task is duplicated instead of rescheduled. Cause: The copy/reschedule behavior is tracked through window keydown/keyup listeners on the Control key. While the document is hidden, the keyup for Co
Original PR description
Steps to reproduce: - Install `project`, open a project and switch to the Gantt view - Start dragging a task while holding Ctrl (copy mode), then switch browser tab with Ctrl+Tab (or Ctrl+Shift+Tab, Ctrl+PgUp/PgDn) - Come back to the Gantt tab and drop the task without holding Ctrl Issue: The task is duplicated instead of rescheduled. Cause: The copy/reschedule behavior is tracked through window keydown/keyup listeners on the Control key. While the document is hidden, the keyup for Control is never received, so the drag sequence resumes with a stale "Ctrl pressed" state and the drop is treated as a copy. Fix: Keyboard and pointer states cannot be reliably tracked while the document is hidden, so cancel any ongoing drag sequence from `makeDraggableHook` as soon as the tab is no longer visible (through the `visibilitychange` event). This applies to every drag and drop instance built on the hook builder. opw-6298440 Forward-Port-Of: odoo/odoo#276859
**Steps to reproduce:** 1. Create a Sales Order. 2. Create a 50% down payment invoice. 3. Create a credit note for the down payment invoice. 4. Reset the credit note to Draft and cancel it. 5. Create the final invoice from the Sales Order. **Issue:** The final invoice is generated for 100% of the order amount, acting as if the down payment invoice does not exist. **Expected behavior:** The final invoice should only include the remaining 50% of the order amount because a valid 50% do
Original PR description
**Steps to reproduce:** 1. Create a Sales Order. 2. Create a 50% down payment invoice. 3. Create a credit note for the down payment invoice. 4. Reset the credit note to Draft and cancel it. 5. Create…
**Steps to reproduce:** 1. Create a Sales Order. 2. Create a 50% down payment invoice. 3. Create a credit note for the down payment invoice. 4. Reset the credit note to Draft and cancel it. 5. Create the final invoice from the Sales Order. **Issue:** The final invoice is generated for 100% of the order amount, acting as if the down payment invoice does not exist. **Expected behavior:** The final invoice should only include the remaining 50% of the order amount because a valid 50% down payment invoice still exists. **Why this happens:** - The `price_unit` on the Sales Order's down payment line is manually updated during `action_post()` based on the sum of posted invoices minus posted credit notes. - When the credit note is posted, `price_unit` drops to 0. However, when that credit note is subsequently reset to draft and cancelled, it triggers `button_cancel()` which only refreshed the line's display name and failed to recalculate `price_unit`. As a result, `price_unit` remained at 0 even though the credit note was no longer active, causing the final invoice to deduct nothing. opw-6373578 Forward-Port-Of: odoo/odoo#277043 Forward-Port-Of: odoo/odoo#275684
Before this commit, when changing the Tip product in the POS settings, the change was reverted and the default Tip product was used instead. opw-6366774 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Before this commit, when changing the Tip product in the POS settings, the change was reverted and the default Tip product was used instead. opw-6366774 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Steps to reproduce: - Install Argentina(l10n_ar) localization > Change Company - Accounting > Customers > Invoices > Select an invoice > Click "Pay" - In "Journal" select "Third Party Checks" > In "Payment Method" select "New Third Party Checks" > Fill the rest of the check info (Number, Bank Account, Issuer Vat, Payment Date and Amount) > Click on "Create Payment" - Repeat the payment process for another invoice with same info > Validation Error A change in [PR] caused the check uniquene
Original PR description
Steps to reproduce: - Install Argentina(l10n_ar) localization > Change Company - Accounting > Customers > Invoices > Select an invoice > Click "Pay" - In "Journal" select "Third Party Checks" > In…
Steps to reproduce: - Install Argentina(l10n_ar) localization > Change Company - Accounting > Customers > Invoices > Select an invoice > Click "Pay" - In "Journal" select "Third Party Checks" > In "Payment Method" select "New Third Party Checks" > Fill the rest of the check info (Number, Bank Account, Issuer Vat, Payment Date and Amount) > Click on "Create Payment" - Repeat the payment process for another invoice with same info > Validation Error A change in [PR] caused the check uniqueness constraint apply to all checks. Because of this, using the same check number with the "New Third Party Checks" payment method now raises a validation error. This is not the intended behavior. The uniqueness constraint should only apply to "Own Checks" when using a "Bank" journal for Vendor Bills. It should not apply to "Third Party Checks" with the "New Third Party Checks" payment method in Customer Invoice. Avoid linking `l10n_latam_check_ids` on liquidity lines for outbound "Own Checks" payments so that the uniqueness constraint is enforced only for the "Vendor Bills". [PR]: https://github.com/odoo/odoo/pull/243509/changes opw-6334965 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
**Steps to reproduce:** Both problem are reproducible on runbot aswell but for more clarity (and for empty accounting), those steps are on a fresh db with no demo data Problem 1 : - create a new db with stock_account, purchase and accountant - In the companies view, select your company - in the branch tab, create a branch for your company - for both the branch and the company, in the settings set the valuation as periodic daily With only the branch company selected: - create
Original PR description
**Steps to reproduce:** Both problem are reproducible on runbot aswell but for more clarity (and for empty accounting), those steps are on a fresh db with no demo data Problem 1 : - create a new db…
**Steps to reproduce:** Both problem are reproducible on runbot aswell but for more clarity (and for empty accounting), those steps are on a fresh db with no demo data Problem 1 : - create a new db with stock_account, purchase and accountant - In the companies view, select your company - in the branch tab, create a branch for your company - for both the branch and the company, in the settings set the valuation as periodic daily With only the branch company selected: - create a warehouse for your branch - create a storable prod with a cost of 10 - validate a receipt for 1 unit of the prod - open inventory valuation view and check that there is variation lines for 10 - open 'scheduled actions' view - select 'inventory valuation closing' - click on 'run manually' With the main company selected: - Open journal items - click on the journal entry of any of the move line with label 'closing stock variation global for company [branch]' - select the 'other info' tab Problem 2: - create a new db with stock_account, purchase and accountant - create a company 2 - for both companies, in the settings set the valuation as periodic daily With company 2 selected - create a warehouse for company 2 - in the settings for fiscal localization set the 'generic chart of account' - create a storable product with a cost of 10 - validate a receipt for 1 quantity of the product - open inventory valuation view and check that there is variation lines for 10 - open 'scheduled actions' view - select 'inventory valuation closing' - click on 'run manually' **Current behavior:** Problem 1: the company of the account move is the main company Problem 2: There is a traceback including 'UserError: Everything is correctly closed' **Expected behavior:** Problem 1: It should be the branch company Problem 2: Everything is closed in company 1, but it shouldn't prevent to generate the entries for company 2 **Cause of the issue:** Problem 1: Inside _cron_post_stock_valuation we call action_close_stock_valuation for each company (if periodic daily or periodic monthly and we're the last day of the month) https://github.com/odoo/odoo/blob/b8e5291d103d9f43bd8db6d2dfe708076a57ea37/addons/stock_account/models/res_company.py#L143-L144 Inside action_close_stock_valuation when creating the account move we add a context to be sure that the move is created for the main company selected https://github.com/odoo/odoo/blob/b8e5291d103d9f43bd8db6d2dfe708076a57ea37/addons/stock_account/models/res_company.py#L72 The fix comes from this PR https://github.com/odoo/odoo/pull/263828 and was improved starting from 19.1 to simply add a the company_id on the moves_vals. But the problem is that this fix failed to consider the case where we come from cron because in this case self.env.company is the main company of the user, which is a problem because as we iterate through the companies we want each account move to be created for its own company. This other PR https://github.com/odoo/odoo/pull/269152 corrects this by using self.id instead of self.company.id but only starting from 19.1. The fix is essentially a back port of those 2 PR. Problem 2: When you call action_close_stock_valuation from _cron_post_stock_valuation for the company that has no inventory valuation and thus no account move to create we will raise the user error https://github.com/odoo/odoo/blob/b8e5291d103d9f43bd8db6d2dfe708076a57ea37/addons/stock_account/models/res_company.py#L58-L60 This makes sense if the method was called from the inventory valuation view. But in our case it's called from cron so we might also call it on other companies and therefore we don't want to raise an exception if there is no account move to create on one of the companies. opw-6144294 Forward-Port-Of: odoo/odoo#276771 Forward-Port-Of: odoo/odoo#275294
The context variable skip_is_manually_modified needs to be passed in order for the autoposting feature to work. The is_manually_modified variable of the move needs to evaluate to true Fixes error in test TestInvoiceExtract.test_autopost_bills_ocr for mc and fr localizations Related pr: https://github.com/odoo/odoo/pull/271865 runbot-6369932 Forward-Port-Of: odoo/odoo#276953
Original PR description
The context variable skip_is_manually_modified needs to be passed in order for the autoposting feature to work. The is_manually_modified variable of the move needs to evaluate to true Fixes error in test TestInvoiceExtract.test_autopost_bills_ocr for mc and fr localizations Related pr: https://github.com/odoo/odoo/pull/271865 runbot-6369932 Forward-Port-Of: odoo/odoo#276953
Issue: When a shopper pays for an online order entirely using a reward (e.g. a discount code covering 100% of the total), the order total is zero. With automatic invoicing enabled, an invoice with an amount of 0 is created. But, the 0 invoice is never emailed to the customer. Whereas, for orders where the total is more than 0, an invoice is created, then emailed to the customer. The customer should be emailed the invoice, even if its amount is 0. Steps to reproduce: 1. Enable automatic invo
Original PR description
Issue: When a shopper pays for an online order entirely using a reward (e.g. a discount code covering 100% of the total), the order total is zero. With automatic invoicing enabled, an invoice with an…
Issue: When a shopper pays for an online order entirely using a reward (e.g. a discount code covering 100% of the total), the order total is zero. With automatic invoicing enabled, an invoice with an amount of 0 is created. But, the 0 invoice is never emailed to the customer. Whereas, for orders where the total is more than 0, an invoice is created, then emailed to the customer. The customer should be emailed the invoice, even if its amount is 0. Steps to reproduce: 1. Enable automatic invoicing. 2. Create a code for a 100% discount. 3. As a shopper, add a product to cart on the website. 4. While checking out, apply the 100% discount code to the order. 5. Complete the checkout. 6. Confirm that an invoice was created and posted, but was not emailed to the customer. Explanation: Normally, order confirmation and invoicing are handled by the `_post_process` method on the `payment.transaction` model. With automatic invoicing enabled, `_post_process` confirms the sale order, creates the invoice, and sends the invoice via `_send_invoice` (another method on the `payment.transaction` model). If `sale.async_emails` is enabled, `_post_process` will trigger a cron that invokes `_send_invoice` instead of invoking it directly. When an order is fully covered by a reward, there's nothing to pay. In this case, no payment.transaction record is ever created, and `_post_process` never runs. Instead, the order is confirmed through the `_validate_order` method on the `sale.order` model. The `sale_loyalty` module extends `_validate_order` so that, with automatic invoicing enabled, it will create and post an invoice for zero-amount orders. But, nothing in this path ever calls `_send_invoice` or an equivalent. So, the invoice is created and posted but never sent. Solution: This adds logic for sending invoices to the extension of `_validate_order` in the `sale_loyalty` module. We mirror the logic used in `_send_invoice` in the `payment.transaction` model. Notes: There is duplicated code from `_send_invoice` in this fix. That is because `_send_invoice`, a method on the `payment.transaction` model, can't be used in this flow. A fix that avoids code duplication would require serious refactoring. This will never trigger a cron to send the invoice, even if `sale.async_emails` is enabled. That is because the cron invokes `_send_invoice`. Since fully reward-covered orders are probably not common, any performance benefits of using a cron are probably not significant. But, making a new cron to be used in this case is also an option. opw-6363334 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275750 Forward-Port-Of: odoo/odoo#275190
# Step to reproduce - Install eCommerce - Activate dev mode with tests assets (important!) - Go to the website & add a Countdow in the footer - Add a new product from the website system tray - Put any name & Save - Go into Edit mode - In the Style tab, (un)toggle "Tax Indication" (may need to do it multiple times) > Note that the issue is quite inconsistent to reproduce # Issue A traceback is shown # Cause The only thing I'm sure of is that the error is caused by this code : htt
Original PR description
# Step to reproduce - Install eCommerce - Activate dev mode with tests assets (important!) - Go to the website & add a Countdow in the footer - Add a new product from the website system tray - Put…
# Step to reproduce - Install eCommerce - Activate dev mode with tests assets (important!) - Go to the website & add a Countdow in the footer - Add a new product from the website system tray - Put any name & Save - Go into Edit mode - In the Style tab, (un)toggle "Tax Indication" (may need to do it multiple times) > Note that the issue is quite inconsistent to reproduce # Issue A traceback is shown # Cause The only thing I'm sure of is that the error is caused by this code : https://github.com/odoo/odoo/blob/8759429547e42e9f63b15a7c80475be46ef437e2/addons/website/static/tests/tour_utils/lifecycle_dep_interaction.js#L18-L20 And that it is linked to `browser.localStorage`. I suspect it is due to some weird localStorage and WysiwygAdapter interaction : https://github.com/odoo/odoo/blob/d6a08b67a948f569a1ca893b6337ce50b4ef9f07/addons/website/static/tests/tours/widget_lifecycle.js#L53-L60 But I can't be sure because debugging tools do not seem to be working. See the inverstigation comment in the associated PR for more information. # Proposed Solution Since this code is only used for this test : https://github.com/odoo/odoo/blob/96a0a9a0332ae460973b6f01b461a0f7e3e2f7fa/addons/website/static/tests/tours/interaction_lifecycle.js#L14-L15 And the test directly parses from the `window.localStorage` : https://github.com/odoo/odoo/blob/96a0a9a0332ae460973b6f01b461a0f7e3e2f7fa/addons/website/static/tests/tours/interaction_lifecycle.js#L50 We can use `window.localStorage` instead of `browser.localStorage` as it fixes the issue opw-6246850 Forward-Port-Of: odoo/odoo#272736
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#270635 Forward-Port-Of: odoo/odoo#267781
**Steps to reproduce:** - Create an attribute of type always, 2 values A and B for it - The two values should have an extra price, like 100 for A and 150 for B - Create an attribute of type dynamic, 2 values C and D for it - C should have an extra price of 100 and 150 for D - Make a product with both of those product, set the price to 100 2 possibilities: - In the PoS, click the product, on the product popup, the price is 100 - This 100 is the product's price and does not change ev
Original PR description
**Steps to reproduce:** - Create an attribute of type always, 2 values A and B for it - The two values should have an extra price, like 100 for A and 150 for B - Create an attribute of type dynamic,…
**Steps to reproduce:** - Create an attribute of type always, 2 values A and B for it - The two values should have an extra price, like 100 for A and 150 for B - Create an attribute of type dynamic, 2 values C and D for it - C should have an extra price of 100 and 150 for D - Make a product with both of those product, set the price to 100 2 possibilities: - In the PoS, click the product, on the product popup, the price is 100 - This 100 is the product's price and does not change even if we change the values - Order that product and buy it with variants A and C - Click on the product again, the price is 300, which is correct - When we click on D, the price is reset to 100, but should be 350 **Why the fix:** When computing the popup's title, we try to get the current product based on the variants choices in the popup. If the product is found, we take that, because it means that it's already in the database. https://github.com/odoo/odoo/blob/0d7f5058664b501779b833609468e535b34356bf/addons/point_of_sale/static/src/app/components/popups/product_configurator_popup/product_configurator_popup.js#L260 If we do not find it, we just take the product template, which does not contain the current extra prices, which is why we got a price of 100 in the exemple. The product is not found because in the case of dynamic variants, the product is only created once it has been ordered at least once. Which means that for this newly created product, it is not yet in the database, so we take the product template instead of the product itself. We now also add the extra price for a product if it is undefined, meaning it has not been found in the database yet. We can't directly update the getter for the priceExtra, as it's also used to build the payload. As the rest of the code works fine with dynamic products with extra price the way it is sent now, we only change the title instead of changing the entire logic and computation. opw-6326125 Forward-Port-Of: odoo/odoo#273411
PR #247474 fixed an error where the lock date restriction was applied overzealously, restricting `stock.picking` models with a `scheduled_date` field before the lock date. This field does not affect accounting entries. The previous fix was to only check the `scheduled_date` field if the picking was in the `done` state. A more complete fix is to simply not check the `scheduled_date` field. opw-6311703 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-
Original PR description
PR #247474 fixed an error where the lock date restriction was applied overzealously, restricting `stock.picking` models with a `scheduled_date` field before the lock date. This field does not affect accounting entries. The previous fix was to only check the `scheduled_date` field if the picking was in the `done` state. A more complete fix is to simply not check the `scheduled_date` field. opw-6311703 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270875
## Problem When generating accrual entries for multiple sale orders, the stock variation lines would all show the same order name, even if the line belonged to a different sale order. This is caused by the `order` variable being reused from a previous loop. ## Solution We will pull the order name directly from the order line in the current iteration. ## Steps to reproduce (Runbot v19) 1. Create a product with AVCO perpetual valuation 2. Make sure all accounts are configured properly (I
Original PR description
## Problem When generating accrual entries for multiple sale orders, the stock variation lines would all show the same order name, even if the line belonged to a different sale order. This is caused…
## Problem When generating accrual entries for multiple sale orders, the stock variation lines would all show the same order name, even if the line belonged to a different sale order. This is caused by the `order` variable being reused from a previous loop. ## Solution We will pull the order name directly from the order line in the current iteration. ## Steps to reproduce (Runbot v19) 1. Create a product with AVCO perpetual valuation 2. Make sure all accounts are configured properly (Income, Expense, Stock, and stock variation accounts) 3. Add units to the stock (it can be with an adjustment, as long as the product has a cost already set) 4. Create 2 separate sales orders for this product 5. Deliver both of the sales orders, do not invoice them 6. Now go to the Accounting App Review>Invoices to be issued 7. Select the 2 invoices that were created. The Revenue accrual lines are correct, with each SO being referenced, but on the Stock variation lines, only the last SO selected will appear. opw-6361032 Forward-Port-Of: odoo/odoo#277058
Calling the method in RPC causes an error: ``` TypeError: cannot marshal None unless allow_none is enabled ``` 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#277047 Forward-Port-Of: odoo/odoo#276541
Original PR description
Calling the method in RPC causes an error: ``` TypeError: cannot marshal None unless allow_none is enabled ``` 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#277047 Forward-Port-Of: odoo/odoo#276541
Current behavior before PR, [1](https://github.com/odoo/odoo/pull/261837) introduced a rule with higher specificity, overriding the animation-delays of the specific dots in the typing indicator. This caused all dots to jump together at the same time. Desired behavior after PR is merged, the different animation-delays are moved inside the specific rule to correctly apply the delay. Before/After, <img width="125" height="160" alt="bug" src="https://github.com/user-attachments/asset
Original PR description
Current behavior before PR, [1](https://github.com/odoo/odoo/pull/261837) introduced a rule with higher specificity, overriding the animation-delays of the specific dots in the typing indicator. This caused all dots to jump together at the same time. Desired behavior after PR is merged, the different animation-delays are moved inside the specific rule to correctly apply the delay. Before/After, <img width="125" height="160" alt="bug" src="https://github.com/user-attachments/assets/8011fe05-6e78-45d6-aee7-a82b7c9bfdd1" /> <img width="125" height="160" alt="expected" src="https://github.com/user-attachments/assets/f367311f-b9a4-4d18-9be1-ae1e7d059a9a" /> --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Before this fix, if a custom group was added in an Odoo PIVOT in a spreadsheet, without sorting, the custom group name was added to the RPC kwards.order, causing a server error. After this fix, the custom group name is removed from the RPC kwards.order. Task: 6401442 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277478
Original PR description
Before this fix, if a custom group was added in an Odoo PIVOT in a spreadsheet, without sorting, the custom group name was added to the RPC kwards.order, causing a server error. After this fix, the custom group name is removed from the RPC kwards.order. Task: 6401442 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277478
Note: In odoo all date/datetime fields are stored and computed by default as UTC Before this commit, dates were called using local timezone getters. This caused the time returned from web to be shifted by the timezone as the dates returned would be treated as UTC. After this commit, dates are now called using UTC timzone getters. Now all web times are retrived as UTC and in sync with the rest of the odoo fields and computations. task-6271421 Forward-Port-Of: odoo/odoo#276683 Forward-Po
Original PR description
Note: In odoo all date/datetime fields are stored and computed by default as UTC Before this commit, dates were called using local timezone getters. This caused the time returned from web to be shifted by the timezone as the dates returned would be treated as UTC. After this commit, dates are now called using UTC timzone getters. Now all web times are retrived as UTC and in sync with the rest of the odoo fields and computations. task-6271421 Forward-Port-Of: odoo/odoo#276683 Forward-Port-Of: odoo/odoo#265250
Problem: Some users with limited access rights cannot access invoices they created, after another user duplicates their sales order and invoices it. Steps to reproduce: 1. Create a user with minimal access rights (only access rights to their own sales orders and invoices). 2. Sign in as that user and create a sales order and confirm it. 3. Create an invoice for that sales order and validate it. 4. Sign in as an administrator and create a duplicate sales order for that sales order, but as
Original PR description
Problem: Some users with limited access rights cannot access invoices they created, after another user duplicates their sales order and invoices it. Steps to reproduce: 1. Create a user with minimal…
Problem: Some users with limited access rights cannot access invoices they created, after another user duplicates their sales order and invoices it. Steps to reproduce: 1. Create a user with minimal access rights (only access rights to their own sales orders and invoices). 2. Sign in as that user and create a sales order and confirm it. 3. Create an invoice for that sales order and validate it. 4. Sign in as an administrator and create a duplicate sales order for that sales order, but assign it to a different user (not the one created in step 1). 5. Confirm the duplicate sales order, create an invoice for it and validate it. 6. Sign in as the user created in step 1 and try to access the invoice created in step 3. 7. Note the access error Cause: When reading an account.move record, the system searches for duplicate moves and adds them to the duplicated_ref_ids field. However, it does not check if the user has read access to those duplicate moves, which leads to access errors when trying to access the main account.move record (which the user has read access to) because the system tries to read the duplicate moves (which the user does not have read access to). opw-6374566 Forward-Port-Of: odoo/odoo#276547
The footer slideout state was computed only once during interaction setup. If the main content height changed afterward, e.g. in edit mode: dropping or removing snippets, or resizing the window, the effect could remain enabled/disabled even though the content had become taller/shorter than the viewport. Steps to reproduce: - Go into edit mode - Add two snippets on the page - On the footer, set the "Slideout Effect" option to "Slide Hover" - Remove one snippet - Half of the footer is
Original PR description
The footer slideout state was computed only once during interaction setup. If the main content height changed afterward, e.g. in edit mode: dropping or removing snippets, or resizing the window, the effect could remain enabled/disabled even though the content had become taller/shorter than the viewport. Steps to reproduce: - Go into edit mode - Add two snippets on the page - On the footer, set the "Slideout Effect" option to "Slide Hover" - Remove one snippet - Half of the footer is hidden by the hover effect, which should not happen task-6117257 Forward-Port-Of: odoo/odoo#277614 Forward-Port-Of: odoo/odoo#275291
**Description of the issue/feature this PR addresses:** ---------------------------------------------- On mobile devices, the meeting view had two UI issues affecting the call experience. The call permission dialog could display an unwanted focus outline around its content because the dialog body was focused on touch devices. Additionally, meeting action buttons could be partially hidden, especially in portrait mode, as the meeting view could extend beyond the visible viewport height.
Original PR description
**Description of the issue/feature this PR addresses:** ---------------------------------------------- On mobile devices, the meeting view had two UI issues affecting the call experience. The call…
**Description of the issue/feature this PR addresses:** ---------------------------------------------- On mobile devices, the meeting view had two UI issues affecting the call experience. The call permission dialog could display an unwanted focus outline around its content because the dialog body was focused on touch devices. Additionally, meeting action buttons could be partially hidden, especially in portrait mode, as the meeting view could extend beyond the visible viewport height. **Current behavior before PR:** ---------------------------------------------- - Opening the call permission dialog on mobile could show an unwanted focus outline around the dialog content - Meeting action buttons could be partially hidden on mobile devices - In portrait mode, the footer could overflow below the visible viewport **Desired behavior after PR is merged:** ---------------------------------------------- - Call permission dialog opens on mobile without showing the unwanted focus outline on main body. - Meeting action buttons remain fully visible on mobile devices Task-6232825 ---------------------------------------------- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#266620
**Steps to reproduce:** * Install l10n_fr. * Create an invoice using a tax with the E3 tax grid. * Post the invoice so it is included in the tax report. * Open the French tax report. **Observed Behaviour:** The E3 line is blank even though the amount is present in the report data. The amount is recorded as a negative value, while the report formula expects a positive value, causing it to be deducted from the report total. **Cause:** The E3 tax report expression used the for
Original PR description
**Steps to reproduce:** * Install l10n_fr. * Create an invoice using a tax with the E3 tax grid. * Post the invoice so it is included in the tax report. * Open the French tax report. **Observed Behaviour:** The E3 line is blank even though the amount is present in the report data. The amount is recorded as a negative value, while the report formula expects a positive value, causing it to be deducted from the report total. **Cause:** The E3 tax report expression used the formula E3, which does not account for tax grid amounts stored as negative values. **Fix:** Update the E3 report expression formula from E3 to -E3 so that negative E3 amounts are correctly displayed in the tax report. opw - 6321790 Forward-Port-Of: odoo/odoo#274052
#### Description of the issue this PR addresses: - Tables containing only a `<caption>` (or a `<thead>` without a `<tbody>`) could reach the editor with no `<tbody>`. - Since table width and margin are moved to the `<tbody>` during setup in 19.0–19.2, such tables caused the editor to fail. - Table operations such as resizing and adding rows or columns also expect a `<tbody>` to exist. #### Desired behavior after PR is merged: - Tables without a `<tbody>` are normalized during editor setup
Original PR description
#### Description of the issue this PR addresses: - Tables containing only a `<caption>` (or a `<thead>` without a `<tbody>`) could reach the editor with no `<tbody>`. - Since table width and margin are moved to the `<tbody>` during setup in 19.0–19.2, such tables caused the editor to fail. - Table operations such as resizing and adding rows or columns also expect a `<tbody>` to exist. #### Desired behavior after PR is merged: - Tables without a `<tbody>` are normalized during editor setup. - `<thead>` is converted or merged into `<tbody>`. - A missing `<tbody>` is created when necessary, preventing the editor from crashing. task-6391354 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276588
Before this commit, the res.users model was not being loaded in the POS when reloading data. If user A was logged in and then on the same device user B logged in, it would not load the new user B data, and it causes user B to not be able to go to the backend. opw-6388954 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276546
Original PR description
Before this commit, the res.users model was not being loaded in the POS when reloading data. If user A was logged in and then on the same device user B logged in, it would not load the new user B data, and it causes user B to not be able to go to the backend. opw-6388954 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276546
Before this commit, the journal and the memo of a payment linked to a company-paid expense report could be modified although such payments must be kept consistent with their expense report: a missing comma in the set of protected fields merged 'journal_id' and 'ref' into a single meaningless entry. The memo was also left editable because the set still referred to 'ref', which was renamed to 'memo'. Steps to reproduce: - submit, approve and post an expense paid by company - open the payment
Original PR description
Before this commit, the journal and the memo of a payment linked to a company-paid expense report could be modified although such payments must be kept consistent with their expense report: a missing…
Before this commit, the journal and the memo of a payment linked to a company-paid expense report could be modified although such payments must be kept consistent with their expense report: a missing comma in the set of protected fields merged 'journal_id' and 'ref' into a single meaningless entry. The memo was also left editable because the set still referred to 'ref', which was renamed to 'memo'. Steps to reproduce: - submit, approve and post an expense paid by company - open the payment created for the expense report - edit the memo or the journal and save, then try to edit the date Editing the date is refused with "You cannot do this modification since the payment is linked to an expense report", while the memo and journal changes are silently accepted. Solution: Restore the missing comma and protect the renamed memo field. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277737 Forward-Port-Of: odoo/odoo#277423
Before this commit, a many2one field test could sometimes fail because of an unexpected web_name_search in verifySteps. That extra call followed the `.clear()` of the input, which triggers a debounced search. Depending on the timing, that call sometimes occured before the end of the test (and the destroy of the component). Now, it is always performed. runbot error~944206 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merge
Original PR description
Before this commit, a many2one field test could sometimes fail because of an unexpected web_name_search in verifySteps. That extra call followed the `.clear()` of the input, which triggers a debounced search. Depending on the timing, that call sometimes occured before the end of the test (and the destroy of the component). Now, it is always performed. runbot error~944206 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#277306 Forward-Port-Of: odoo/odoo#276799
In restaurant mode, a direct sale order (no table, no floating order name) has no display name yet when it is sent to the preparation printer. `getName()` returns "Direct sale" in that case, which appeared as the order name on the preparation ticket. Add a `preparationName` getter on `PosOrder` that, for direct sale orders, falls back to `floatingOrderName || pos_reference` so the ticket always shows a meaningful reference. For non-direct-sale orders the getter delegates to `getName()` unchan
Original PR description
In restaurant mode, a direct sale order (no table, no floating order name) has no display name yet when it is sent to the preparation printer. `getName()` returns "Direct sale" in that case, which appeared as the order name on the preparation ticket. Add a `preparationName` getter on `PosOrder` that, for direct sale orders, falls back to `floatingOrderName || pos_reference` so the ticket always shows a meaningful reference. For non-direct-sale orders the getter delegates to `getName()` unchanged. Task-6327397 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#276298 Forward-Port-Of: odoo/odoo#271743
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/2fb92b4523 [REL] 19.2.22 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/f9a1ba8541 [FIX] autofill: hide autofill handler when selection is hidden [Task: 6317808](https://www.odoo.com/odoo/2328/tasks/6317808) https://github.com/odoo/o-spreadsheet/commit/f09540dff1 [FIX] HeaderVisibility: fix `getNextVisibleCellPosition` getter [Task: 6340589](https://www.odoo.com/odoo/
Original PR description
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/2fb92b4523 [REL] 19.2.22 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0)…
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/2fb92b4523 [REL] 19.2.22 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/f9a1ba8541 [FIX] autofill: hide autofill handler when selection is hidden [Task: 6317808](https://www.odoo.com/odoo/2328/tasks/6317808) https://github.com/odoo/o-spreadsheet/commit/f09540dff1 [FIX] HeaderVisibility: fix `getNextVisibleCellPosition` getter [Task: 6340589](https://www.odoo.com/odoo/2328/tasks/6340589) https://github.com/odoo/o-spreadsheet/commit/b393ef986e [FIX] edition: do not change edition if not editing [Task: 6340589](https://www.odoo.com/odoo/2328/tasks/6340589) https://github.com/odoo/o-spreadsheet/commit/3a324a7e75 [FIX] table computed style: fix render table [Task: 6396322](https://www.odoo.com/odoo/2328/tasks/6396322) Co-authored-by: Florian Damhaut (flda) <flda@odoo.com> Co-authored-by: Anthony Hendrickx (anhe) <anhe@odoo.com> Co-authored-by: Alexis Lacroix (laa) <laa@odoo.com> Co-authored-by: Lucas Lefèvre (lul) <lul@odoo.com> Co-authored-by: Adrien Minne (adrm) <adrm@odoo.com> Co-authored-by: Ronak Mukeshbhai Bharadiya (rmbh) <rmbh@odoo.com> Co-authored-by: Dhrutik Patel (dhrp) <dhrp@odoo.com> Co-authored-by: Rémi Rahir (rar) <rar@odoo.com> Co-authored-by: Pierre Rousseau (pro) <pro@odoo.com> Co-authored-by: Vincent Schippefilt (vsc) <vsc@odoo.com> Co-authored-by: Marceline Thomas (matho) <matho@odoo.com>
The test read the field content for the last urgent save right after resolving modifyImagePromise, without waiting for the DOM to actually reflect the new image src. This raced the async update of the editable content, so beforeUnload sometimes ran before the image src were updated, sending stale content and failing intermittently. Wait for the updated image to appear in the DOM before triggering the last beforeUnload, instead of relying on a fixed animationFrame wait. runbot-243773 ---
Original PR description
The test read the field content for the last urgent save right after resolving modifyImagePromise, without waiting for the DOM to actually reflect the new image src. This raced the async update of the editable content, so beforeUnload sometimes ran before the image src were updated, sending stale content and failing intermittently. Wait for the updated image to appear in the DOM before triggering the last beforeUnload, instead of relying on a fixed animationFrame wait. runbot-243773 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Problem: Changing the text alignment of a table header in Studio reports has no effect. Cause: When the alignment is already defined by a CSS class using `!important` (for example, `text-center`), the inline style applied from the toolbar is ignored. Solution: Backport commit 373be20905bcb11f8323a986053e3dc7996ce567. Steps to reproduce: - Open the invoice report. - Change the alignment of a table header. - Observe that the new alignment is not applied. opw-6389158 --- I con
Original PR description
Problem: Changing the text alignment of a table header in Studio reports has no effect. Cause: When the alignment is already defined by a CSS class using `!important` (for example, `text-center`), the inline style applied from the toolbar is ignored. Solution: Backport commit 373be20905bcb11f8323a986053e3dc7996ce567. Steps to reproduce: - Open the invoice report. - Change the alignment of a table header. - Observe that the new alignment is not applied. opw-6389158 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276470
Steps to reproduce: - activate location - create a tracked product A - create a PO with qty=10 with product A - receive them (8 in WH/Stock, 2 in WH/Stock/Shelf 1) - In Reporting/stock filter with "wh/stock" Issue: On hand value will be 0 Cause: "wh/stock did not match _rec_names = 'name' -> WH location is different than "stock" location (who's parent is "WH"). We need to match it with _rec_names_search (1) to match the right location. We fall back on _rec_names in case _rec_name
Original PR description
Steps to reproduce: - activate location - create a tracked product A - create a PO with qty=10 with product A - receive them (8 in WH/Stock, 2 in WH/Stock/Shelf 1) - In Reporting/stock filter with "wh/stock" Issue: On hand value will be 0 Cause: "wh/stock did not match _rec_names = 'name' -> WH location is different than "stock" location (who's parent is "WH"). We need to match it with _rec_names_search (1) to match the right location. We fall back on _rec_names in case _rec_names_search would not be defined (not really necessary in here but meh why not be conservative) (1) https://github.com/odoo/odoo/blob/2bb7493b72b400ed76cc6460c94867fb86de9f3a/addons/stock/models/stock_location.py#L19 opw-6312702 Forward-Port-Of: odoo/odoo#271552
# How to reproduce - Enable Cloudflare Turnstile in Settings > Integrations - Add a CF Site Key & a CF Secret Key. e.g. : - `1x00000000000000000000AA` - `1x0000000000000000000000000000000AA` (See : https://developers.cloudflare.com/turnstile/troubleshooting/testing/) - Go to a Website page with a form - Add `?cf=show` to the URL - Open the browser console - Search the dom for an element with s_turnstile_container - Look for the `data-appearance` attribute # The issue `data-appea
Original PR description
# How to reproduce - Enable Cloudflare Turnstile in Settings > Integrations - Add a CF Site Key & a CF Secret Key. e.g. : - `1x00000000000000000000AA` - `1x0000000000000000000000000000000AA` (See :…
# How to reproduce - Enable Cloudflare Turnstile in Settings > Integrations - Add a CF Site Key & a CF Secret Key. e.g. : - `1x00000000000000000000AA` - `1x0000000000000000000000000000000AA` (See : https://developers.cloudflare.com/turnstile/troubleshooting/testing/) - Go to a Website page with a form - Add `?cf=show` to the URL - Open the browser console - Search the dom for an element with s_turnstile_container - Look for the `data-appearance` attribute # The issue `data-appearance` is set to `interaction-only` but should be `always` according to : https://github.com/odoo/odoo/blob/1e73172b51cd673c3414187af4f98304921ed7b3/addons/website_cf_turnstile/static/src/interactions/turnstile.js#L8-L12 # Cause `appearance` is misspelled in the template : https://github.com/odoo/odoo/blob/1e73172b51cd673c3414187af4f98304921ed7b3/addons/website_cf_turnstile/static/src/interactions/turnstile.xml#L7 Documentation on the Appearance modes for Turnstile : https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/widget-configurations/#appearance-modes opw-6359977 Forward-Port-Of: odoo/odoo#275077
The character-by-character HTML assertion in mass mailing tests fails on modern platforms using libxml2 >= 2.14/2.15 due to upstream updates that align HTML serialization, attribute quote management, and escaping rules more closely with the HTML5 specification. See upstream changes: - https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.14.0 (Attribute escaping optimization) - https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.15.0 (HTML5 spec compliant serialization) This commit fixes
Original PR description
The character-by-character HTML assertion in mass mailing tests fails on modern platforms using libxml2 >= 2.14/2.15 due to upstream updates that align HTML serialization, attribute quote management, and escaping rules more closely with the HTML5 specification. See upstream changes: - https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.14.0 (Attribute escaping optimization) - https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.15.0 (HTML5 spec compliant serialization) This commit fixes this by refactoring the assertions to treat the output HTML structure as a "black box", verifying data integrity and expected content conversions rather than brittle structural layout. runbot-938228 Forward-Port-Of: odoo/odoo#277747 Forward-Port-Of: odoo/odoo#275959
Firefox has a strict limit of ~640,000 characters for history state serialization and throws NS_ERROR_ILLEGAL_VALUE past it. Chrome and Safari throw DataCloneError past their own undocumented limits (~500MB and ~64MB respectively). When a debounced push() exceeded these limits, the error was unhandled and broke navigation. Catch these two specific errors and log them instead of crashing, while still resetting the push state and re-throwing any other unexpected error. opw-6182687 Forward-P
Original PR description
Firefox has a strict limit of ~640,000 characters for history state serialization and throws NS_ERROR_ILLEGAL_VALUE past it. Chrome and Safari throw DataCloneError past their own undocumented limits (~500MB and ~64MB respectively). When a debounced push() exceeded these limits, the error was unhandled and broke navigation. Catch these two specific errors and log them instead of crashing, while still resetting the push state and re-throwing any other unexpected error. opw-6182687 Forward-Port-Of: odoo/odoo#277724
Before this commit, when clicking on refresh and the kyc_status on IAP was 'fail', we put the status on the db to 'fail' and ended the process. This implies creating a new record IAP side even if it is useless and also implies that there could be cases where there would be a mismatch between iap and Odoo. e.g. The client starts a verification process, he ends up refusing to sign the documents. On IAP, the kyc status would be equal to 'fail'. Then the user have a possibility to submit a manual
Original PR description
Before this commit, when clicking on refresh and the kyc_status on IAP was 'fail', we put the status on the db to 'fail' and ended the process. This implies creating a new record IAP side even if it is useless and also implies that there could be cases where there would be a mismatch between iap and Odoo. e.g. The client starts a verification process, he ends up refusing to sign the documents. On IAP, the kyc status would be equal to 'fail'. Then the user have a possibility to submit a manual verification and when submitting it status would go to 'processing'. The problem is that in the meantime (after refusing but before submitting manual verification), if the user clicks on the refresh button it would ends the process on Odoo and then not going to 'success' on the DB even if it is the case on IAP after Support reviewed the request. task-6307255 Forward-Port-Of: odoo/odoo#277045 Forward-Port-Of: odoo/odoo#276191
When creating an activity in a custom app made with studio, no image is shown, and instead the alt text is shown with a missing image. This fixes the issue by showing a placeholder icon if no module is found for the activity group. opw-6282451 Previous behavior: <img width="1315" height="568" alt="image" src="https://github.com/user-attachments/assets/1e4fc1d5-3a35-4193-80fc-f6d161776e2e" /> New behavior: <img width="1315" height="568" alt="image" src="https://github.com/user-attac
Original PR description
When creating an activity in a custom app made with studio, no image is shown, and instead the alt text is shown with a missing image. This fixes the issue by showing a placeholder icon if no module is found for the activity group. opw-6282451 Previous behavior: <img width="1315" height="568" alt="image" src="https://github.com/user-attachments/assets/1e4fc1d5-3a35-4193-80fc-f6d161776e2e" /> New behavior: <img width="1315" height="568" alt="image" src="https://github.com/user-attachments/assets/6ed5ca8b-8481-470f-b7c6-dd59c616125e" /> (Original PR: https://github.com/odoo/odoo/pull/268957 Re-based on 17.0 as its the earliest version affected, so it can be forward-ported to future versions) Forward-Port-Of: odoo/odoo#269654
Documentation and clarification updates
Adds Corvanis corporate CLA entry so legal/cla can validate contributions from Corvanis contributors. This change only adds: - doc/cla/corporate/corvanis.md - No functional code changes. Forward-Port-Of: odoo/odoo#276949
Original PR description
Adds Corvanis corporate CLA entry so legal/cla can validate contributions from Corvanis contributors. This change only adds: - doc/cla/corporate/corvanis.md - No functional code changes. Forward-Port-Of: odoo/odoo#276949
Miscellaneous changes
all_sm is referenced by two branches of the outer UNION, so PostgreSQL materializes it (a CTE used more than once is an optimization fence). Every query on report_stock_quantity therefore builds the forecast for all products/warehouses first and filters afterwards, so predicates like product_id can't reach the stock_move scan. This hurts single-product lookups such as _read_group() in mrp_report_bom_structure._get_stock_availability(), called repeatedly per component while rendering a BoM rep
Original PR description
all_sm is referenced by two branches of the outer UNION, so PostgreSQL materializes it (a CTE used more than once is an optimization fence). Every query on report_stock_quantity therefore builds the…
all_sm is referenced by two branches of the outer UNION, so PostgreSQL materializes it (a CTE used more than once is an optimization fence). Every query on report_stock_quantity therefore builds the forecast for all products/warehouses first and filters afterwards, so predicates like product_id can't reach the stock_move scan.
This hurts single-product lookups such as _read_group() in mrp_report_bom_structure._get_stock_availability(), called repeatedly per component while rendering a BoM report: each call does a full stock_move scan plus two sorts that spill to disk.
Marking all_sm NOT MATERIALIZED lets the planner inline it and push the product_id/warehouse_id filter down to an index scan, removing the full scan, the GENERATE_SERIES expansion and the on-disk sorts. warehouse_cte stays materialized (small and cheap).
Query generated from the _read_group:
```SQL
SELECT MIN("report_stock_quantity"."date")
FROM "report_stock_quantity"
WHERE (
(
(
(
("report_stock_quantity"."state" = 'forecast')
AND ("report_stock_quantity"."date" >= '2026-07-08')
)
AND ("report_stock_quantity"."product_id" = 15743)
)
AND ("report_stock_quantity"."product_qty" >= 1.0)
)
AND ("report_stock_quantity"."warehouse_id" = 4)
)
AND ("report_stock_quantity"."company_id" IN (1))
```
Before:
800 ms by _read_group in _get_stock_availability().
For opening a BoM overview with hundred of components takes 17 sec.
After:
25 ms by _read_group in _get_stock_availability().
Same BoM overview drops to 3 sec to open.
cc @Aurelienvd
I can send you EXPLAIN ANALYZE, but I prefer to not putting them here to avoid data leakage.
Forward-Port-Of: odoo/odoo#277235
Forward-Port-Of: odoo/odoo#275022