Friday, September 4, 2026
64 changes · saas-19.4
Enhancements to existing features
The forum sitemap now loads only the information it needs instead of full post content, avoiding very large memory spikes. This should reduce repeated sitemap failures on high-traffic sites like odoo.com and make sitemap generation more reliable.
Original PR description
On odoo.com, /sitemap.xml fails dozens of times a day with a 500 `MemoryError` before finally succeeding and being cached. The primary cause is the loading of all forum posts. With this commit, we…
On odoo.com, /sitemap.xml fails dozens of times a day with a 500 `MemoryError` before finally succeeding and being cached. The primary cause is the loading of all forum posts. With this commit, we avoid fetching all fields and specifically the `content` field which is html which can contain embeded images in base64. | | Peak memory | |--------|--------| | Before | 1.7GB | | After | 610MB | ### Before <img width="2505" height="400" alt="sitemap-forum-posts-before" src="https://github.com/user-attachments/assets/0ce3aca9-52ed-46a6-ac9b-245c754a08a7" /> ### After <img width="1864" height="291" alt="image" src="https://github.com/user-attachments/assets/6686b0fc-d0ce-4dc2-b2ff-d34e37695104" /> Another approach could be to load posts in batch and free the memory between each batch. It has been measured and yield very similar results in practice. I chose this approach because it matches the future behavior in version 20.0 (see https://github.com/odoo-dev/odoo/commit/fe186b07475cf15a50558d9bdacd0599c17c39be) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286154
The website import form now points users to official documentation instead of older help links. This should make it easier for users to find clear guidance on creating API keys and using the import tool correctly.
Original PR description
Update the import form links to use the documentation instead. This is important as it gives better info about creating API keys to use the tool correctly.
This update adjusts French accounting localization so Monaco is handled in the European Union VAT grouping while also keeping a separate EU group without Monaco where needed. It also adds localization packages for French overseas territories, helping businesses apply the right country-specific accounting and tax setup.
Original PR description
[[IMP] l10n_fr,l10n_fr_account: European union vat](https://github.com/odoo/odoo/commit/9870a204bb64bdf8a11e433eef3a9e9f8f3fad86)
This commit will add Monaco to the European union vat country group and
create a new country group that is the same than the european union but
without monaco
task-6321652
[[ADD] l10n_{gf,gp,mq,re,yt}: new localization](https://github.com/odoo/odoo/commit/58518e1d7df773a70c595bd3842a33ac6be611bb)
Like Monaco, we need to add new localization package for
the drom countries
task-6321652
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#284404The Apps screen now includes an “Others” section for apps that do not fit the Official or Industries categories. This makes the app catalog clearer and helps users find all available apps without misclassification or hidden entries.
Original PR description
This commit adds an `others` section in the `apps` module to show apps that don't belong in the `official` or `industries` sections. task-6522903
The AI update tool now blocks requests that try to update records without specifying a clear filter. This reduces the risk of accidental mass updates while still allowing intentional updates to all records when an explicit matching rule is provided.
Original PR description
The llm can hallucinate and call the update tool with an empty domain which will result in performing the updates on all the records of a certain model. To prevent hallucinations and at the same time allow the llm to update all the records if it actually needs to, an error is thrown if the domain is empty stating that updating with an empty domain is prohibited and a domain that matches all records should be used instead. This will make the llm conscious about passing a domain that actually matches all records and not just use an empty domain. Note: the update tool was already throwing an error if the domain is empty but only if tool_request_confirmation is False. If the confirmation is True, which is the case in mcp, the domain would be accepted and the updates would go through.
Resolved issues and error corrections
This fixes the Mexican accounting setup so accumulated depreciation and amortization accounts are classified correctly. Businesses using fixed assets such as vehicles will now see depreciation amounts computed and reflected properly in journal entries and asset balances.
Original PR description
Issue: When creating an asset using an "154.01.01 Vehicles", the depreciation values of the journal entries created are zero Steps to reproduce: 1. Install l10n_mx and enter a Mexican company 2.…
Issue: When creating an asset using an "154.01.01 Vehicles", the depreciation values of the journal entries created are zero Steps to reproduce: 1. Install l10n_mx and enter a Mexican company 2. Create an asset and setting the fixed asset account as 154.01.01 Vehicles 3. Click on "Compute Depreciation" and in the "Depreciation Board" page, all the journal entries created will not have any depreciation values Cause: In the l10n_mx chart of accounts, all accumulated depreciation accounts are set as "expense_depreciation" whereas they should be asset accounts because accumulated depreciation accounts are used to credit asset accounts to decrease asset values. If an account of type "expense_depreciation" is used, then when the depreciation account is credited and the expense account is debited, all financial events will occur within expense accounts, which is why no depreciation values were recorded as the asset balances stay the same. Additionally, the "asset_depreciation_account_id" field on "account.account" has a domain restricting selection to "account_type" of "asset_fixed" or "asset_non_current" Solution: Change the "account_type" of l10n_mx accumulated depreciation accounts from "expense_depreciation" to "asset_fixed" and l10n_mx accumulated amortization accounts from "expense_depreciation" to "asset_non_current" Updrade PR: [odoo/upgrade/pull#10936](https://github.com/odoo/upgrade/pull/10936) opw-6359618 Forward-Port-Of: odoo/odoo#284309 Forward-Port-Of: odoo/odoo#278185
This update fixes several issues in the stock allocation report, including incorrect allocation quantities, mobile display problems, label printing layout, and repeated-click errors. It also makes allocation easier to use from forecast reports and stops the report from opening automatically during operation validation, reducing interruptions for warehouse users.
Original PR description
This PR fixes issues with [the recently merged](https://github.com/odoo/odoo/pull/264299) allocation report. Main changes are: - Add specific design for mobile device; - Don't allocate already reserved quantity; - Allocation report won't open itself automatically when validating an operation from the Barcode app, no matter the configuration (a setting is planned to be added in `master` to let the possibility if the user wants); - Add the possibility to allocate from the forecast report. For more details on these changes or other fixes, check the corresponding commit's message. _________ **Enterprise PR:** odoo/enterprise#122258 task-4894566
This fix makes employee records with the same name appear in a consistent order when partner time off information is prepared. It prevents intermittent test and build failures and helps ensure the correct return date is associated with the main user.
Original PR description
Before this commit, TestPartner.test_res_partner_to_store fails on the all-modules and per-country builds: AssertionError: '2024-06-06' != '2024-06-07' : Return date is the return date of the main…
Before this commit, TestPartner.test_res_partner_to_store fails on the all-modules and per-country builds: AssertionError: '2024-06-06' != '2024-06-07' : Return date is the return date of the main user of the partner This happens because the test reads the first entry of the hr.employee list, which holds one employee per user of the partner: back on the 7th for the main user, on the 6th for the other. This comes from "[FIX] hr*: load out-of-office dates from all user employees", which added the employees of the partner to the payload, where it held those of the main user only. The problem is that the list keeps the order of employee_ids, which is 'name' with no tiebreaker, and both employees are named test1, as an employee takes the name of its user and creating the second user renames the partner. Postgres is then free to return either one first, and the failing builds get the second one. This commit fixes the issue by ordering the employees on 'name, id', so that employees sharing a name keep a stable order instead of the one the database picks. The test asserts the whole hr.employee list, one entry per user of the partner, rather than its first entry alone, and that assertion pins the order. https://runbot.odoo.com/odoo/error/945994 Forward-Port-Of: odoo/odoo#286750 Forward-Port-Of: odoo/odoo#286236
This fix prevents Italian electronic invoices from listing unrelated down payment documents when generating linked invoice details. It helps ensure credit notes and final invoices reference only the relevant prior document, reducing confusion and improving compliance data accuracy.
Original PR description
Steps to reproduce: - Create a sale order with a down payment term. - Invoice the down payment (down payment invoice A). - Credit that down payment invoice directly (credit note A), without…
Steps to reproduce: - Create a sale order with a down payment term. - Invoice the down payment (down payment invoice A). - Credit that down payment invoice directly (credit note A), without reconciling it with anything else. - Generate the FatturaPA XML for credit note A. - Observe that DatiFattureCollegate lists both down payment invoice A and credit note A itself, instead of only down payment invoice A. On an order with several down payment invoices/credit notes over time, every one of them is listed instead of just the document the current credit note actually reverses. Cause of the issue: _l10n_it_edi_export_data built downpayment_moves from self.invoice_line_ids._get_downpayment_lines().move_id with no filtering. _get_downpayment_lines() (sale override) returns every invoice line ever created against the same down payment sale order line, across the whole life of the order, not just the invoice the current document actually relates to. The template renders DatiFattureCollegate for every one of those moves unconditionally, on top of the already-correct reversed_entry_id/reconciled_moves fallback, including the current document itself. Solution: Restrict downpayment_moves to lines with a negative price_subtotal, mirroring the existing down payment deduction-line detection a few lines above, and explicitly exclude the current document. This limits DatiFattureCollegate's down payment entries to the case they are meant for: a final invoice actually deducting a previously invoiced down payment. opw-6429716 Forward-Port-Of: odoo/odoo#285555 Forward-Port-Of: odoo/odoo#279938
The barcode workflow now prints labels for the allocated products instead of printing the related operation report. This prevents warehouse users from receiving the wrong printout and adds a clearer way to view allocation details when needed.
Original PR description
Before this commit, the print button on barcode line printed the allocated operation's report instead of the allocated products' labels. This commit fixes that. _________________ **Community PR**: odoo/odoo#272722 [task-4894566](https://www.odoo.com/odoo/966/tasks/4894566)
Downloading spreadsheets as Excel files now works when they contain inserted images. The export process uses the same authorized image access as the web interface, preventing failed downloads for users.
Original PR description
Since https://github.com/odoo/enterprise/pull/97488, the images are shared across spreadsheets and the attachments are no longer related to a specific record. Due to the management of the…
Since https://github.com/odoo/enterprise/pull/97488, the images are shared across spreadsheets and the attachments are no longer related to a specific record. Due to the management of the IrAttachment access rights, it means that those attachments are not accessible by anyone by default and we rely on the access_token to display them in the webclient. However, the method that builds the final xlsx file fetches the images from the server and did not use the access token, meaning that it could never access the attachment. Such situation raised a UserError that was caught by the webclient. How to reproduce: - As admin, create a spreadsheet and insert an image inside of it - try to download the spreadsheet as an xlsx file counterpart of https://github.com/odoo/enterprise/pull/126384 Task-6432724 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#285981 Forward-Port-Of: odoo/odoo#279788
An older Point of Sale data cleanup workaround was removed because a newer fix handles the issue more precisely. This reduces the risk of removing more checkout data than intended while keeping stale loyalty reward lines cleaned up.
Original PR description
This fix is no longer required(https://github.com/odoo/odoo/pull/202752) as this one (https://github.com/odoo/odoo/pull/257043) is cleaner and less aggressive (it will only delete stale reward lines). This is the relevant part of the new fix to delete the previous one: https://github.com/odoo/odoo/pull/257043/changes#diff-18cef42f8c39513a82387e9cb81bc732b252304cd15b5b2f7b0b4623ac20cb41R100-R104 opw-6447092 Forward-Port-Of: odoo/odoo#286072 Forward-Port-Of: odoo/odoo#285376
This update fixes outdated internal documentation about how temporary records are accessed. It clarifies that standard access rights and record rules apply, helping developers and administrators avoid misunderstandings when configuring permissions.
Original PR description
Since 6d8688bb124d, TransientModel records use the regular access rights mechanisms instead of being implicitly restricted to their creator. The docstring was not updated with that change and has therefore incorrectly documented creator-only access since 14.0. Forward-Port-Of: odoo/odoo#286374 Forward-Port-Of: odoo/odoo#286251
When a contact with multiple linked active users is mentioned, all of those users now receive the notification immediately instead of only seeing it after reloading. Related performance test expectations were updated to reflect the extra work needed to notify everyone correctly.
Original PR description
Before this commit, mentioning a partner that has two users notified only one of them. The other user saw the mention on reload only. This commit raises the query counts of the activity tests: the fix in odoo resolves each notified partner to its active users, which costs one query per post with an inbox recipient. https://github.com/odoo/odoo/pull/283836 Forward-Port-Of: odoo/enterprise#129969
When a contact with multiple user accounts is mentioned, all active linked users now receive the live notification immediately. This prevents some users from missing mention alerts until they reload the page, improving reliability of team communication.
Original PR description
Before this commit, mentioning a partner that has two users notified only one of them. The other user saw the mention on reload only. This happens because the notification is sent on the single user that _notify_get_recipients picks for a partner, and since "[REF] bus, mail: use user rather than partner as bus target" a user is its own bus channel, so the other users of that partner are no longer reached. The notification record is stored per partner, which is why a reload shows it. This commit fixes the issue by sending to every active user of the notified partner. https://github.com/odoo/enterprise/pull/129969 Forward-Port-Of: odoo/odoo#283836
DHL shipping in Odoo no longer automatically requests a carrier pick-up when creating shipments. This avoids extra scheduling steps and DHL errors when pick-up windows are not configured, making DHL behave more like other shipping carriers.
Original PR description
Before this commit, the DHL REST module had the pick-up request set, which led to an unnatural use flow, needing to set up an scheduled date for pick-up, and several errors from DHL when these were not properly configured. This feature was unique to this module among the shipping carriers as we don't normally request pick-up for packages and leave it to user to decide how to do it. This commit removes the request for pick up and the logic that was needed to make it work. This will make the behavior consistent with other carriers in Odoo, and avoids the need to set scheduled pick-up windows and having to deal with unnecessary errors. opw-6148927 Forward-Port-Of: odoo/enterprise#123773
Employees in Belgium can now combine a company car with public transport or bicycle commuting without those options being automatically removed. This ensures all eligible transport reimbursements are correctly included in payroll calculations.
Original PR description
When configuring transport modes on an employee contract version profile, selecting a company car automatically reset public transport (bus, tram, metro) kilometers to zero and disabled the bicycle option. This prevented employees who use multiple transport modes (e.g., combining a company car with public transport or a company bicycle) from having multiple transportation reimbursements calculated on their payslip. Remove the automatic field resets for public transport and bicycle options in `_onchange_transport_mode` and remove `_onchange_has_bicycle`, allowing these transport modes to co-exist with a company car. task-6514557 Forward-Port-Of: odoo/enterprise#129972
This update adds test coverage to ensure spreadsheets exported to Excel keep embedded images working correctly. It helps prevent regressions when users share or export spreadsheet documents that include visual content.
Original PR description
Counterpart of https://github.com/odoo/odoo/pull/279788 Task-6432724 Forward-Port-Of: odoo/enterprise#130172 Forward-Port-Of: odoo/enterprise#126384
Fixes an issue where event visitors could see outdated booth options after switching booth categories. This prevents confusion during booth registration and helps the event booth booking flow complete reliably without requiring a page reload.
Original PR description
Before this commit, the "Get A Booth" page of an event could keep listing the booths of the category checked on load after the visitor picks another one. Only a page reload brought the right ones…
Before this commit, the "Get A Booth" page of an event could keep listing the booths of the category checked on load after the visitor picks another one. Only a page reload brought the right ones back. The tour webooth_exhibitor_register timed out on that list: FAILED: [5/13] Tour webooth_exhibitor_register -> Step Choose Booth (trigger: .o_wbooth_booths div:contains(OpenWood Demonstrator 2) input:not(:visible)). TIMEOUT step failed to complete within 10000 ms. This happens because the page fetches the booths of the category checked on load, and clicking another category fetches its booths while that first answer is still on its way. The answer coming back last fills the list, and the widget caches it under the category active on arrival, so the booths of the first category land in the cache of the clicked one. This commit fixes the issue by caching an answer under the category it was asked for, and by filling the list only while that category is still the chosen one. https://runbot.odoo.com/odoo/error/110527 https://runbot.odoo.com/odoo/error/161834 Forward-Port-Of: odoo/odoo#286552 Forward-Port-Of: odoo/odoo#286266
Changing Peppol reception to receive documents no longer triggers an error for Belgian companies using Peppol. This helps users complete Peppol setup smoothly and avoids disruption when configuring incoming electronic invoices.
Original PR description
Steps to reproduce: - Install `documents_account_peppol` and `l10n_be` module - Switch to BE Company > `Activate Peppol` - Change `Peppol Reception Mode` -> `Receive as Documents` Traceback: `AttributeError: 'res.company' object has no attribute '_peppol_allows_document_reception'` Problem: Changing the `Peppol Reception Mode` to `Receive as Documents` causes an `AttributeError` because `_compute_peppol_purchase_journal_required()` calls `_peppol_allows_document_reception()` on `config.company_id`, but the method is defined on `res.config.settings`. Cause: The method is available on the `res.config.settings`, not on the `res.company`. Solution: Add `_peppol_allows_document_reception()` method in `res.company` and call company's method from the `res.config.settings` method. opw-6470552 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix ensures French VAT credits from a previous period are included in the next tax closing journal entry. It helps companies keep tax returns compliant with French accounting requirements and prevents missing carryover amounts in accounting records.
Original PR description
### Issue before this commit: When generating a tax closing entry for France, the VAT credit carryover from the previous period is missing from the journal entry lines. ### Steps to reproduce the…
### Issue before this commit: When generating a tax closing entry for France, the VAT credit carryover from the previous period is missing from the journal entry lines. ### Steps to reproduce the issue: 1. Download Accounting and l10n_fr 2. Go to Vendor > Bills 3. Create a vendor bill with date in June and price > 0 (ex. 1000$) and the 20% G tax that produce a 200$ VAT tax 4. Go to Customers > Invoices 5. Create an invoice with price > 0 (ex. 9000$), the date in July and the 20% G tax that will produce a 1800$ VAT tax 6. Go to Tax Return and validate all opened months up to July and see that for June the balance is -200$ 9. Then go to View Entries of July using the 3 dots next to the "submit" button and see that there is no mentioning of the 200$ carry over of credit from the month before ### Cause of the issue: The issue stems from a structural change in the core code where the logic to evaluate and balance the tax receivable account was removed from the _add_tax_group_closing_items method. Consequently, the VAT closing entry now only processes the current period's taxes and there is no reporting of any carried-forward VAT credits. ### Reason to introduce the fix: French accounting rules strictly require the carried-forward VAT credit to be explicitly integrated into the current period's tax closing entry. opw-6438648 Forward-Port-Of: odoo/enterprise#130377 Forward-Port-Of: odoo/enterprise#129181
The GSTR-2B return workflow now shows the correct option to fetch GSTR-2B data instead of an irrelevant Submit button. This restores the intended process and prevents reconciliation from being blocked after recent tax return changes.
Original PR description
On GSTR-2B returns, do not show the 'Submit' button instead show the 'Fetch GSTR-2B' button once all the checks pass. Clicking it fetches the GSTR-2B data. After the recent tax returns refactor (https://github.com/odoo-dev/enterprise/commit/603443c5a45609145de8be288eadc9e06e63e1f3), GSTR-2B returns wrongly showed a 'Submit' button that is not part of their flow, and there was no longer any way to move the return forward and fetch its GSTR-2B data, blocking the reconciliation. task-6529017
The UK CIS report now correctly includes payment information for receipts that have CIS tax applied. This ensures businesses get a more complete and accurate view of CIS-related supplier activity, not just vendor bills.
Original PR description
With the l10n_uk_reports_cis module installed: - Create a vendor bills and add a CIS tax --> This vendor's bills appear correctly in the report. - Create a receipt and add a CIS tax --> This type of bill appears in the report, but the payment is not showing up. opw-6282548 Forward-Port-Of: odoo/enterprise#129395 Forward-Port-Of: odoo/enterprise#124043
Electronic invoice imports no longer fail when an invoice line has a 100% discount together with tax included in the price. This prevents import errors for valid supplier/customer documents and improves reliability of accounting workflows.
Original PR description
Due to the following commit: 01efd8cfcce3269ca6b88d549a670b08a90298cb, a division by zero error is raised when a 100% discount is used with a price-included tax. When the discount is 100%, it is impossible to retrieve the original tax amount before discount using a simple multiplication as the current raw_tax_amount_currency is zero. In that case, we need to recompute taxes using the original unit price before discount. opw-6242701 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282430
Planning managers who do not have HR permissions can now publish scheduled slots successfully. The system uses accessible employee information where possible so employees still receive their planning notifications.
Original PR description
Steps: - As a planning manager without HR right - Schedule planning slots - Publish them Actual result: - employee_ids is empty as user don't have access HR - nothing is sent Expected result: - Planning publication is well sent Similar to: https://github.com/odoo/enterprise/pull/127503 Forward-Port-Of: odoo/enterprise#130298
This fixes an issue where some applied website editor options were not recognized when their priority value was below zero. It helps ensure the correct option remains selected in composite editing actions, improving reliability for users editing web pages.
Original PR description
The function `useSelectableComponent` looked for the selected option by searching for the option with the highest priority among the options that are applied. The search for highest priority implicitely excluded options with negative priority. This case happens with `composite` action when the inner actions have no definition of `getPriority`. This commit initialize the "highest priority found so far" as `-Infinity` instead of 0. task-5245362 Forward-Port-Of: odoo/odoo#286652 Forward-Port-Of: odoo/odoo#286503
Automated accounting-related processes can now generate required reports even when they run on behalf of users without accounting permissions. This prevents setup or localization workflows, such as tax or trade reporting, from failing unnecessarily.
Original PR description
This was spotted in a dev branch for master, where we set a default account_opening_date on every company, hence trying to directly create the returns for it. Some modules need to call reports for that (like intrastat l10n), and do it in sudo(). However, even in sudo, a user without the accounting rights still doesn't have the proper group, and it raises an exception. We hence adapt the condition. Forward-Port-Of: odoo/enterprise#130448
The demo payment provider now handles refunds correctly after a manually captured payment. This prevents demo transactions from getting stuck in an authorized refund state with negative amounts, making payment testing more reliable.
Original PR description
Issue: --- When using manual capture, you can refund the transaction but it will be only authorized, and you'll then be blocked with a negative authorized amount and the impossibility to refund it. This seems to be specific to demo payment provider. Steps: 1- Enable manual capture on demo provider. 2- Buy a product from shop and checkout and pay. 3- Capture the payment in backend. Then click on post process. 4- Try refund. opw-6413515 Forward-Port-Of: odoo/odoo#286625 Forward-Port-Of: odoo/odoo#282315
Website building blocks now display with better contrast when a dark color palette is selected, making previews and placed content easier to read. This also speeds up the snippet picker by reusing prepared dark preview versions instead of recalculating them each time.
Original PR description
Fix some snippets in dark palettes task-6485048
Fixed an issue where creating or editing technical views could fail even when the chosen model and view layout were valid. The system now applies the selected model before validating the view, preventing false validation errors and making view setup more reliable.
Original PR description
**Problem:** Creating a view from Settings > Technical > User Interface > Views fails with a validation error, even though both the model and the architecture are valid. **Steps to reproduce:** 1. Go…
**Problem:**
Creating a view from Settings > Technical > User Interface > Views fails with a validation error, even though both the model and the architecture are valid.
**Steps to reproduce:**
1. Go to Settings > Technical > User Interface > Views
2. Click New
3. Set the View Name and pick a model in "Model of the view"
4. Set the View Architecture to `<list><field name="name"/></list>`
5. Save
**Current behavior:**
The record cannot be saved:
Error while validating view near:
<list __validate__="1"><field name="name"/></list>
Model not found: False
Duplicating an existing view and editing the copy works, so the issue only shows up on brand new records.
**Expected behavior:**
The view is saved, and validated against the model that was picked.
**Cause of the issue:**
The form edits `model_id`, a non-stored `Many2one` whose inverse `_inverse_compute_model_id` is what actually fills the stored `model` field. The architecture is edited through `arch_base`, whose inverse chain ends in `_inverse_arch` writing `arch_db`; `write` then runs `_check_xml`, which validates the architecture against `view.model`.
Both values therefore reach the record through inverse methods, so the order those run in decides whether `model` is set by the time the architecture is validated. That order became deterministic in this version: the ORM sorts inverse groups by `(field.write_sequence, field index)`. Both fields keep the default `write_sequence` of 0, which leaves the declaration order to break the tie, and `arch` is declared well before `model_id` — so the architecture is validated while `model` is still empty.
The same ordering also breaks a plain edit: changing the model and the architecture of an existing view in a single save validates the new architecture against the previous model.
**Fix:**
`write_sequence` is the ORM's hook for exactly this kind of ordering dependency, so a negative one on `model_id` states the real constraint — the model has to be known before anything is validated against it — rather than leaving it to where the fields happen to sit in the class. It also covers the write path, which a create-only workaround would miss.
opw-6467991This fix ensures accounting records correctly flag a numbering gap when a previously posted journal entry is reset to draft and a later entry is posted. This helps businesses keep audit trails and journal sequencing accurate without changing already assigned document numbers.
Original PR description
To reproduce: * create and post 2 journal entries in the same journal * reset to draft the entry with the highest number * create and post a third entry in the same journal The draft entry is not flagged as having made a gap, because at the time of resetting it to draft, it was the last entry and therefore didn't really make a gap. 3 options to solve were considered: * flag all moves when reseting to draft even if they were the last of the chain * if we reset the last move of the sequence to draft, also remove its sequence and put it back to `/` * when posting, check if the previous number was draft. If it was the case, flag it. The last options was taken in this fix to avoid changing the previous behavior while fixing the current issue. Forward-Port-Of: odoo/odoo#286204
Updates the spreadsheet engine and dashboard components to fix several user-facing issues with charts, pivots, printing, dark mode, and mobile display. This improves spreadsheet stability, visual consistency, and usability across devices.
Original PR description
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/7660254439 [REL] 19.4.11 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0)…
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/7660254439 [REL] 19.4.11 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/a510812a88 [FIX] carousel: cannot add non-existing chart to carousel [Task: 6455790](https://www.odoo.com/odoo/2328/tasks/6455790) https://github.com/odoo/o-spreadsheet/commit/c875c44655 [FIX] Fonts: fix linux font on css variable [Task: 6452045](https://www.odoo.com/odoo/2328/tasks/6452045) https://github.com/odoo/o-spreadsheet/commit/ae830f0ff5 [FIX] svg: remove unused commented SVGs [Task: 6317134](https://www.odoo.com/odoo/2328/tasks/6317134) https://github.com/odoo/o-spreadsheet/commit/6970933bb4 [FIX] chart: fix funnel chart show value [Task: 6475094](https://www.odoo.com/odoo/2328/tasks/6475094) https://github.com/odoo/o-spreadsheet/commit/06d1c65ec7 [FIX] pivot: unbounded ranges in the pivot side panel [Task: 6478220](https://www.odoo.com/odoo/2328/tasks/6478220) https://github.com/odoo/o-spreadsheet/commit/c95922a0d1 [FIX] figure: color of snap lines in dark mode [Task: 6515587](https://www.odoo.com/odoo/2328/tasks/6515587) https://github.com/odoo/o-spreadsheet/commit/95b0854895 [FIX] chart: consistency in the background color for xlsx export [Task: 6507087](https://www.odoo.com/odoo/2328/tasks/6507087) https://github.com/odoo/o-spreadsheet/commit/583393936f [FIX] chart_menu: align chart menu items tag and style [Task: 6469005](https://www.odoo.com/odoo/2328/tasks/6469005) https://github.com/odoo/o-spreadsheet/commit/41874ca9de [FIX] composer: crash when hovering a composer token [Task: 5153319](https://www.odoo.com/odoo/2328/tasks/5153319) https://github.com/odoo/o-spreadsheet/commit/1bedab5196 [FIX] evaluation: wrong dependencies invalidation with spread formulas [Task: 5103328](https://www.odoo.com/odoo/2328/tasks/5103328) https://github.com/odoo/o-spreadsheet/commit/037f4f8aa5 [FIX] print: figure border wrong render [Task: 6458624](https://www.odoo.com/odoo/2328/tasks/6458624) https://github.com/odoo/o-spreadsheet/commit/44c8d0b2a8 [FIX] chart: fix bubble chart show value [Task: 6475014](https://www.odoo.com/odoo/2328/tasks/6475014) 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>
Bills created from employee expenses in Mexico now correctly show their CFDI XML attachments when available. This ensures users can access required tax documents directly in Odoo and supports related SAT validation checks for these receipts.
Original PR description
**Current behavior:** Currently, account moves created from expenses (type receipt) don't include the XML when it is a CFDI. Causing users cannot see their attachment even though it is created on DB. https://docs.google.com/videos/d/1eFSAA-wvUzPDwIJDeiS2dkne94lGM7QBxRfjN3HxaLw/play **Versions:** 19+ **Fix:** Implementing a new helper to identify those moves that can actually hold a CFDI document (for now, all `is_invoice()` documents + vendor bill receipt, `in_receipt`), so now, we include 'in_receipts' in _compute_l10n_mx_edi_cfdi_state_and_attachment, _compute_l10n_mx_edi_document_ids, _compute_l10n_mx_edi_update_sat_needed and l10n_mx_edi_cfdi_try_sat. As these documents might need to fetch SAT services as well. Task-id: [6397080](https://www.odoo.com/odoo/project/49/tasks/6397080) Forward-Port-Of: odoo/enterprise#130045 Forward-Port-Of: odoo/enterprise#126493
The French VAT reporting flow now checks for duplicate XML declarations before sending them to Aspone. This avoids rejected submissions and prevents unnecessary paid service calls.
Original PR description
When sending an xml to aspone, they will check if a duplicate declaration exist, and if it's the case, then they will refuse it. Since contacting aspone cost us money we will block the sending before that. task-6420220 Forward-Port-Of: odoo/enterprise#130406 Forward-Port-Of: odoo/enterprise#127953
Reference fields now show a placeholder in the record selector, making it clearer that users must choose both a model and a specific record. This helps prevent incomplete links from being saved and later disappearing after the page is refreshed.
Original PR description
Steps to reproduce: 1. Install Sign. 2. Open the form view of a document. 3. Select a model in the "Link to" (Reference) field, but leave the record empty. 4. Save and refresh the page. Issue: -…
Steps to reproduce:
1. Install Sign.
2. Open the form view of a document.
3. Select a model in the "Link to" (Reference) field, but leave the record empty.
4. Save and refresh the page.
Issue:
- After refreshing, the selected model is cleared because the reference value is invalid.
Cause:
- A reference field is only valid when it contains both a model and a record ID. However, the record selector has no placeholder, making it easy to overlook and save an incomplete value.
Solution:
- Add a default placeholder to the record selector of reference fields to make it more visible.
<table>
<tr>
<th>Before</th>
</tr>
<tr>
<td>
<img src="https://github.com/user-attachments/assets/3ba34b77-f901-4d3e-9768-5acaf2e673b8" alt="Before" width="100%">
</td>
</tr>
<tr>
<th>After</th>
</tr>
<tr>
<td>
<img src="https://github.com/user-attachments/assets/1fe54b89-221f-4d28-bd2b-0a3c706d5746" alt="After" width="100%">
</td>
</tr>
</table>
opw-6426339
Forward-Port-Of: odoo/odoo#280266Corrects a rounding mismatch that could cause Mexican electronic payment complements for USD invoices paid in MXN to be rejected by the certification provider. This helps businesses successfully validate and send affected CFDI payment documents, especially for partial payments or payments made with exchange-rate differences.
Original PR description
**Steps to reproduce:** * Install the **l10n_mx** localization. * Enable **USD** and fetch the latest currency exchange rate from the settings. * Configure **Quadrum** as the **PAC** in the settings.…
**Steps to reproduce:**
* Install the **l10n_mx** localization.
* Enable **USD** and fetch the latest currency exchange rate from the settings.
* Configure **Quadrum** as the **PAC** in the settings.
* Create and sign a USD invoice with **16% IVA** (e.g. 4,500 USD + 720 USD tax = 5,220 USD total).
* Send the invoice to **CFDI**.
* Register a **partial MXN payment** that does not convert to a round USD amount (e.g. 30,000 MXN = 1,762.45 USD).
* Send the payment complement to the PAC by clicking **Update Payments** on the invoice.
**Observed behavior:**
The PAC rejects the CFDI with error **CRP20268**:
> El campo BaseP que corresponde a Traslado, no es igual a la suma de
> los importes de las bases registrados en los documentos relacionados
> donde el impuesto del documento relacionado sea igual al campo
> ImpuestoP de este elemento y la TasaOCuotaDR del documento
> relacionado sea igual al campo TasaOCuotaP de este elemento.
**Cause:**
* The SAT validator enforces a strict arithmetic relationship between three fields that are printed in the payment complement XML:
```
BaseP == round(BaseDR / EquivalenciaDR, 6)
```
* When `percentage_paid` is a non-terminating decimal (which happens for any partial MXN payment against a USD invoice), the internal `raw_base` float carries more precision than the 6-decimal-place `BaseDR` that is actually written to the XML:
```
percentage_paid = 1762.45 / 5220 = 0.33763409961685825...
raw_base = 4500 × 0.33763... = 1519.353448275862...
BaseDR (XML) = float_round(raw_base, 6) = 1519.353448
```
* The old code then used `raw_base` (the unrounded internal value) as the dividend when computing BaseP:
```
BaseP (old) = float_round(1519.353448275862... / 0.0587483333, 6)
= 25862.068980 ← written to <TrasladoP BaseP="...">
```
* The PAC performs the same division using only what it can read from the XML. The already-rounded BaseDR:
```
BaseP (PAC) = round(1519.353448 / 0.0587483333, 6)
= 25862.068975
```
* The 6th-decimal mismatch (25862.068980 ≠ 25862.068975) triggers CRP20268 and the document is rejected.
* The same issue occurs with a full MXN payment on a different date than the invoice when multiple invoice lines cause the rounded aggregate to diverge from the sum of per-line raw values.
**Fix:**
In `_l10n_mx_edi_add_payment_cfdi_values` (`account_move.py`), the block that builds the BaseP aggregation list was changed from iterating over raw per-`base_line` amounts to building a single synthetic entry per invoice using the already-rounded document-level `BaseDR` values (`tax_details['base']`) as the dividend:
- Before : wrong: raw_base ≠ BaseDR printed in the XML
'raw_base': tax_details['raw_base'] / inv_rate
- After : correct: 'base' == BaseDR, the exact value in the XML
'raw_base': tax_details['base'] / inv_rate
This guarantees that Odoo and the PAC divide the identical value, producing the identical 6-decimal result.
The `base_line_cfdi_values_mx_curr_list` path (used only for the `Totales` summary fields rounded to 2 dp) is left unchanged because the CRP20268 rule does not apply to that block.
opw-6468077
Forward-Port-Of: odoo/enterprise#128357This fixes a spelling mistake in the Instagram video embed option shown while editing a page. Users will now see the provider name spelled correctly, improving polish and avoiding confusion in the editor.
Original PR description
Steps to reproduce: - Edit existing page. - Paste any Instagram reel. - In powerbox Instagram entry is listed as "Embed Intagram Video". Introduced by https://github.com/odoo/odoo/commit/2bae2abd4db704451234b115eb4942dcae7d8afa This commit fixes typo.
This fixes a crash that could occur when generating electronic invoice data in Odoo Community Edition without the enterprise accounting add-on installed. The system now checks whether optional deferred billing date fields are available before using them, helping invoices process reliably across editions.
Original PR description
The fields `deferred_start_date` and `deferred_end_date` are created by the enterprise addon `account_accountant`, so not having it installed, this crashes with:
```
File "/opt/odoo/auto/addons/account_edi_ubl_cii/models/account_edi_cii.py", line 684, in <listcomp>
billing_start_dates += [move_line.deferred_start_date for move_line in invoice.invoice_line_ids if move_line.deferred_start_date]
AttributeError: 'account.move.line' object has no attribute 'deferred_start_date'
```
This PR protects the access to these fields checking first if they exist.
Bug introduced in the refactoring in #261572.
@Tecnativa TT64359
Forward-Port-Of: odoo/odoo#286245The HTML editor now properly clears file-related event handlers when an editor instance is closed. This prevents small memory leaks that could build up over repeated editing sessions, helping keep the editor stable and responsive.
Original PR description
FilePlugin registered its click, keydown and pointerdown handlers with raw `addEventListener`, so they were never removed when the plugin was destroyed. The pointerdown one is bound to the document, which outlives the editable, leaking a handler per editor instance. Use `addDomListener` so Plugin.destroy() removes them. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286144
Custom website snippets with very large responsive text now display correctly in the snippets dialog. This makes previews more reliable for website editors without affecting how snippets appear when placed on a page.
Original PR description
Steps to reproduce: - Go to the website editor. - Add a snippet with editable text to the page. - Select the text and set its font size to 144. - Save the edited block as a custom snippet. - Open the…
Steps to reproduce: - Go to the website editor. - Add a snippet with editable text to the page. - Select the text and set its font size to 144. - Save the edited block as a custom snippet. - Open the snippets dialog. - Go to the Custom category. => The custom snippet preview shows the text too large. Before this commit, responsive font sizes using `clamp()` with a `vw` term were rendered too large in the block dialog. The `vw` value was based on the full preview iframe width, while snippets were displayed inside columns. After this commit, the block dialog adjusts `vw` values on cloned `.o_rfs` preview content only, so the preview matches its column width without changing the snippet dropped on the page. task-6303725 | BEFORE (font size -> 144) | AFTER (font size -> 144) | | ------------- | ------------- | | <img width="416" height="409" alt="image" src="https://github.com/user-attachments/assets/e0eb0a4e-eb7b-4ee6-b080-536ea2a75c68" /> | <img width="421" height="272" alt="image" src="https://github.com/user-attachments/assets/6468a234-0966-45c9-9435-e97d9752b794" /> | Forward-Port-Of: odoo/odoo#273257
Changing Peppol Reception Mode to Receive as Documents no longer triggers an error for Belgian companies using document-based Peppol reception. This keeps the Peppol activation and configuration flow working as expected, avoiding disruption when users update reception settings.
Original PR description
Steps to reproduce: - Install `documents_account_peppol` and `l10n_be` module - Switch to `BE` Company > `Activate Peppol` - Change `Peppol Reception Mode` -> `Receive as Documents` Traceback: `AttributeError: 'res.company' object has no attribute '_peppol_allows_document_reception'` Problem: Changing the `Peppol Reception Mode` to `Receive as Documents` causes an `AttributeError` because `_compute_peppol_purchase_journal_required()` calls `_peppol_allows_document_reception()` on `config.company_id`, but the method is defined on `res.config.settings`. Cause: The method is available on the `res.config.settings`, not on the `res.company`. Solution: Call `_peppol_allows_document_reception()` directly on the `res.config.settings`. opw-6470552
This change removes sample scheduling data that could fail to load when an optional planning feature was not installed. It helps ensure the helpdesk field service module can be installed reliably without requiring unrelated optional modules.
Original PR description
…ct on helpdesk intervention Before this commit, `project_id` field in `planning.slot` only exists if `project_forecast` module is installed. However, when `helpdesk_planning_field_service_sale_timesheet` is installed, we cannot guarranty `project_forecast` module is also installed since it is not in the dependencies of `helpdesk_planning_field_service_sale_timesheet` module. This commit just removes the demo data inside `helpdesk_planning_field_service_sale_timesheet` module.
This fixes an online store product page issue where multi-checkbox attribute options could become selected automatically after refreshing the page. Customers now see only the options they intentionally choose, reducing confusion and preventing unintended product configurations.
Original PR description
**Steps to reproduce:** 1. Create a product. 2. Add two attributes: multi-checkbox and any single-select type (e.g. Radio). 3. Publish the product and open its page on eCommerce. 4. Verify that no…
**Steps to reproduce:**
1. Create a product.
2. Add two attributes: multi-checkbox and any single-select type (e.g. Radio).
3. Publish the product and open its page on eCommerce.
4. Verify that no multi-checkbox option is selected by default.
5. Refresh the page twice.
**Issue:**
On the second page refresh, the first option of the multi-checkbox attribute is automatically selected, and the URL is updated with its parameter.
**Cause:**
- `_prepare_product_values` construct attribute combinations by mapping requested `attribute_values` query parameters line by line.
- When URL query parameters were present (e.g., set after the first refresh), the fallback logic `or ptal.product_template_value_ids.filtered('ptav_active')[:1]` treated unselected `multi_checkbox` attribute lines as missing required selections rather than empty selections, forcing them to default to their first active option.
**Fix:**
If no selection is provided for `multi_checkbox` line, return an empty recordset instead of falling back to the first active option.
opw-6494697
Forward-Port-Of: odoo/odoo#286492
Forward-Port-Of: odoo/odoo#284798This fixes a broken layout in the inventory report by removing extra table columns that no longer matched the report header. Users should see inventory report tables display correctly again, improving readability and reducing confusion.
Original PR description
This reverts commit 43add3f72f29c35280869010b897c3c5656f5120. It was adding too many columns in table body after columns were removed from the header in 19.0. opw-6307728 Forward-Port-Of: odoo/odoo#286294
Fixed an issue where creating a time off request could fail when a leave type counted calendar days and no employee had been selected yet. This prevents an error screen during leave management and keeps the request form usable.
Original PR description
BUG :
- choose a US company
- in sick leave timeoff type , make to count days as "calendar days"
- open management and try to create a leave -> traceback
REASON :
- when you open the timoff form view for the first time , the employee_id in empty this causes work_time_per_day_mapped to be empty, => work_time_per_day_mapped[leave.date_from, leave.date_to, include_public, calendar] this fails because there is no entry in the dict
FIX:
- add a safeguard at line 653 , to prevent the computations when the leave has no employees , in this case we should fall back to the else in line 739, this acts as way to prevent tracebacks, during calculation , because in the database itself you could never have a leave with no employee assigned to it.
task-6411996The website shop editor no longer crashes when users choose the Grid catalog preset in the Products Design panel. This keeps product page customization usable and avoids disruption while editing the online store.
Original PR description
Steps to reproduce: 1. Open the website editor on /shop. 2. Select the products grid and expand Products Page in the sidebar. 3. Click the Design button to open the Products Design sliding panel. 4. Click the 4th preset (Grid catalog) in the Preset picker. Before this pr: - The page crashed with a render loop error. After this pr: - presets can be picked normally, no crash. The preset list was being drawn twice at once, and both copies were registering under the same internal ID. Now each copy gets its ownnsuffixed ID, so they don't clash anymore. Also removed a redundant duplicate t-if on BuilderSelectItem already covered by its parent t-if. Also removed a dead label.translate="Presets" attribute that ProductsDesignPanelPresets never reads. opw-6478531 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The certificate setup screen no longer shows an error as soon as a key file is added without a password. Users now only see the warning when they actually entered an incorrect password, reducing confusion during certificate configuration.
Original PR description
When adding a key file without entering a password, an error banner is immediately displayed, incorrectly suggesting that the password may be invalid. Only show the error banner when a password was provided and is incorrect. Also refactored the compute function to avoid repeated try-except blocks. task-6299175 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286307 Forward-Port-Of: odoo/odoo#283589
This update corrects Belgian payroll certificate handling when an employee contract has no end date. It helps prevent errors or incorrect occupation attestations for ongoing contracts.
Original PR description
A check was missing if the contract end date was false Forward-Port-Of: odoo/enterprise#130346
This fix prevents installation errors when the Restaurant point of sale app is installed alongside an older Point of Sale version. It makes the receipt template update rely on a stable element, reducing manual upgrade steps and avoiding disruptions for customized setups.
Original PR description
The template for the preparation tickets was using an xpath targeting a newly added div element. This raised an error when installing the `pos_restaurant` module while an old version of `point_of_sale` was still in place, since the customer would need to manually upgrade `point_of_sale` first to have that new div element available. We now use receipt-header as the xpath target, which was always present in the template. We also refill `pos_self_order.pos_order_change_receipt` to prevent breaks with custo. --- Report: https://github.com/odoo/odoo/pull/267161#discussion_r3758115362 Forward-Port-Of: odoo/odoo#281768
Portal users who follow a project can now open the tasks they are allowed to view without seeing an incorrect “not found” message. This makes task access from project links consistent with the task list in the portal, reducing confusion for external users and customers.
Original PR description
Before this commit, the portal user could have a request not found when he wants to access to a task from a project he follows even if he can access to the task in /my/tasks route. This commit makes sure the read access are checked instead of checking if the user can access to the task thanks to the token since the token if the one of the project. Forward-Port-Of: odoo/odoo#285878
This fix ensures that when an employee has multiple contracts and payslips in the same month, the canteen cost is applied to the first payslip that includes a paid amount. This helps Belgian payroll remain accurate and avoids assigning the cost to an unpaid or inappropriate payslip.
Original PR description
In case of multiple contracts for a single month (and then multiple payslips), the canteen cost must appear in the first payslip that have a paid amount. Forward-Port-Of: odoo/enterprise#130109
Fixed an issue where Belgian payroll could incorrectly pay a public holiday when an employee's guaranteed sick pay period had already ended. The change ensures sickness certificates are checked by local calendar date, so payroll results are accurate when certificates start on the same day as a public holiday.
Original PR description
Steps to reproduce: - Employee on full-time sickness certified month by month (one hr.leave per medical certificate), guaranteed salary period already exhausted. - Compute payroll for the month whose public holiday falls on the first day of a new certificate. - Public holiday work entry stays paid, every other day that month is correctly unpaid. Cause: the 30-day lookback compared exact datetimes instead of calendar dates, so a certificate starting the same day as the holiday but later in clock-time got excluded. Also ignored timezone: date_from is stored in UTC and needs localizing before taking .date(). Fix: compare local calendar dates via hr.leave's own request_date_from/request_date_to instead of raw UTC datetimes. Added a regression test for the split-certificate case. Task 6512860 Forward-Port-Of: odoo/enterprise#129889
This update adds test coverage to ensure timesheet assistant suggestions are correctly matched with helpdesk tickets and calendar entries. It helps reduce the risk of incorrect timesheet suggestions reaching users in future updates.
Original PR description
task: 6475133 Forward-Port-Of: odoo/enterprise#130157
This fixes an issue where additional deliveries on an existing sales order could create incorrect or even negative cost entries when average costing is used. Costs are now based on the actual value of stock movements, helping invoices reflect more accurate margins and inventory costs.
Original PR description
## HOW TO REPRODUCE: - Create a product AVCO Perpetual - Receive 10 units with a unit price of $10 => Product average price is now $10 - Create a Sale Order for 10 units, confirm, deliver and invoice…
## HOW TO REPRODUCE:
- Create a product AVCO Perpetual
- Receive 10 units with a unit price of $10 => Product average price is now $10
- Create a Sale Order for 10 units, confirm, deliver and invoice => COGS are at $100
- Receive 1 unit with a price of $5 => Product average price is now $5
- Update SO and add 1 unit, deliver and invoice this new unit => New invoice COGS is $-45
This is because Odoo computes the COGS for the whole SO, and decided that the value of the deliveries is the `quantity * standard_price`, which would means `11 units * $5 = $55`. Because the 1st invoice has a COGS balance of $ 100, the 2nd invoice is set to $ -45.
This behavior is inconsistent with how it was done in previous versions. Furthermore, if we added the +1 unit in a new invoice, the COGS would have been $ 5, for a total products COGS of $ 105.
- - -
With this fix, the COGS are computed using the average of the move value. So if the first move value is $100, and the second is $5, then the global COGS for the sale order should be $105. Because the first invoice COGS are already at $100, the second invoice COGS must be $5.
OPW-6442049
---
## TEST RESULT WITHOUT FIX:
```
2026-08-21 08:00:11,722 28203 INFO oes_test_19.0 odoo.addons.sale_stock.tests.test_anglo_saxon_valuation: Starting TestAngloSaxonValuation.test_cogs_average_multiple_invoices_and_deliveries ...
2026-08-21 08:00:13,055 28203 INFO oes_test_19.0 odoo.addons.sale_stock.tests.test_anglo_saxon_valuation: ======================================================================
2026-08-21 08:00:13,055 28203 ERROR oes_test_19.0 odoo.addons.sale_stock.tests.test_anglo_saxon_valuation: FAIL: TestAngloSaxonValuation.test_cogs_average_multiple_invoices_and_deliveries
Traceback (most recent call last):
File "/home/odoo/Odoo/src/19.0/odoo/addons/sale_stock/tests/test_anglo_saxon_valuation.py", line 1935, in test_cogs_average_multiple_invoices_and_deliveries
self.assertRecordValues((cogs_line_1 | cogs_line_2), [
File "/home/odoo/Odoo/src/19.0/odoo/odoo/tests/common.py", line 727, in assertRecordValues
self.assertSequenceEqual(expected_reformatted, record_reformatted, seq_type=list)
AssertionError: Lists differ: [{'ac[142 chars]it': 5.0}, {'account_id': 3566, 'debit': 5.0, 'credit': 0.0}] != [{'ac[142 chars]it': 45.0}, {'account_id': 3566, 'debit': 45.0, 'credit': 0.0}]
First differing element 2:
{'account_id': 3536, 'debit': 0.0, 'credit': 5.0}
{'account_id': 3536, 'debit': 0.0, 'credit': 45.0}
[{'account_id': 3536, 'credit': 100.0, 'debit': 0.0},
{'account_id': 3566, 'credit': 0.0, 'debit': 100.0},
- {'account_id': 3536, 'credit': 5.0, 'debit': 0.0},
+ {'account_id': 3536, 'credit': 45.0, 'debit': 0.0},
? +
- {'account_id': 3566, 'credit': 0.0, 'debit': 5.0}]
+ {'account_id': 3566, 'credit': 0.0, 'debit': 45.0}]
? +
```
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#283778Product image thumbnails now remain consistently sized and centered when auto-cropping is disabled. This improves the product page presentation and keeps thumbnail click areas predictable, especially for products with mixed portrait and landscape images.
Original PR description
Steps to reproduce: =================== 1. Add several images to a product, one of them much wider than tall. 2. On the product page, set the image ratio to "Disabled". 3. Move the thumbnails below…
Steps to reproduce: =================== 1. Add several images to a product, one of them much wider than tall. 2. On the product page, set the image ratio to "Disabled". 3. Move the thumbnails below the image. => The wide thumbnail sits at the top of its slot, with blank space under it. Root cause: =========== Thumbnails are given a fixed width of 64px and take their height from `aspect-ratio: var(--o-wsale-product-image-ratio)` [1]. With cropping disabled that variable is `auto`, so each thumbnail keeps the shape of its own image and they no longer share a height. They sit in a flex row, which stretches every slot to the height of the tallest one. The image inside keeps its own height and stays at the top of the slot, so a wide image leaves the rest of its slot empty. The slots are only stretched when the images differ in height, which is why the problem needs cropping to be disabled, and why it does not appear when every image is a landscape one. - [1] sized the thumbnails from the image ratio. Fix: ==== Center the thumbnails in the row so each one keeps the height of its own image instead of being stretched to the tallest. Their width stays at 64px, so a row of wide images still takes the same space as before and none of them is pushed out of the container. [1]: 670b1daa2254 opw-6472484 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283246
French PDP invoice exports now automatically include the due date when an invoice is marked as paid. This helps businesses comply with France's latest e-invoicing validation rules and avoids rejected invoice files.
Original PR description
According the schematron v1.4, the cbc:DueDate is required when the move is PAID. "[BR-FR-CO-09/BT-23] : Si le cadre de facturation (BT-23) est B2, S2 ou M2, alors la date d’échéance (BT-9) doit être renseignée et correspondre à la date de paiement." no-task --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286263
This fixes when remaining hours are recalculated on sales order lines for timesheet-based services. It helps keep service delivery and project hour information accurate when units of measure or availability values change.
Original PR description
The dependencies of _compute_remaining_hours do not match the fields actually used for the computation: it lists analytic_line_ids, which it never uses, and omits both remaining_hours_available, and product_uom. _compute_remaining_hours_available has the same issue: it uses product_uom but only depends on product_id.service_policy. analytic_line_ids, on the other hand, can be dropped: qty_delivered already depends on it, along with its so_line, unit_amount, product_uom_id and project_id, so the timesheet flow keeps triggering the recomputation. This PR fixes the dependencies for both aforementioned compute methods. Task-4748521 Forward-Port-Of: odoo/odoo#285685 Forward-Port-Of: odoo/odoo#284750
This fix makes Odoo's internal sequence tests use the same timezone setting as the application itself. It prevents false test failures around midnight in Belgium, improving release reliability without changing user-facing behavior.
Original PR description
## Issue By default in Odoo, `datetime.now()` returns the UTC time, which is two hours behind the local time in Belgium. This leads to two tests failing when executed between 00:00 and 02:00 Belgian…
## Issue By default in Odoo, `datetime.now()` returns the UTC time, which is two hours behind the local time in Belgium. This leads to two tests failing when executed between 00:00 and 02:00 Belgian time: `test_ir_sequence_interpolation_dict` and `test_ir_sequence_iso_directives`. The `_interpolate_dict` method (responsible for interpolating the prefix/suffix from the sequences) specifies the tzinfo when calling `datetime.now()`: https://github.com/odoo/odoo/blob/9c67949be529eb86886b3d5bde08e81e048ecfe7/odoo/addons/base/models/ir_sequence.py#L211-L212 Since this is not the case in the tests, the tests evaluate the date using UTC. This creates a two hours difference between the time expected and the time actually used by `next_by_code`. The tests thus fail between 00:00 and 02:00 because the evaluate dates from both `datetime.now` calls differ, leading to a mismatch in the expected prefixes. ## Fix We force the `env.tz` on the `datetime.now()` call, to mimic the behavior from the `_interpolate_dict`. runbot-242662 Forward-Port-Of: odoo/odoo#284955
This update corrects how Adyen payment information is read from incoming payment data. It helps ensure payment transactions use the right values, reducing the risk of failed or incorrectly processed payments.
Original PR description
opw-6512723 Forward-Port-Of: odoo/odoo#286391 Forward-Port-Of: odoo/odoo#284773
Financial reports no longer show the unallocated earnings or losses line when it has a zero balance in every column. This removes unnecessary clutter and makes reports easier to review without changing any underlying figures.
Original PR description
… zero The unallocated earnings/losses line was displayed even when its balance was zero in every column group, cluttering the report with uninformative rows. We therefore filter out lines whose balance is zero across all column groups. Forward-Port-Of: odoo/enterprise#129666 Forward-Port-Of: odoo/enterprise#129129
The website translation endpoint now bypasses website-specific routing because it already receives the requested language directly. This prevents unexpected language redirects and cookie conflicts when translations are loaded, helping pages show the correct language more reliably.
Original PR description
/website/translations does not require request.website or language redirection logic as `lang` is passed explicitly. Drop `website=True` to prevent unexpected language redirects and cookie conflicts. Backport of 4faddd8b44 (odoo/odoo#269325). runbot-231758 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284856 Forward-Port-Of: odoo/odoo#281738
Refund payslips are now recalculated accurately whenever worked days or payroll lines are recomputed, not only during a reset. This helps prevent incorrect payroll refund amounts and improves reliability for payroll teams.
Original PR description
Instead of only resetting correctly the refund payslip in the reset, ensure that anytime we recompute worked days or lines, the refund is correctly computed. Forward-Port-Of: odoo/enterprise#129332
This fixes an issue in the HTML editor where pressing Enter in a bullet list item containing a table did not split the bullet correctly. Users can now edit text before or after tables in lists more naturally, without accidentally keeping everything in one bullet or moving content out of the list incorrectly.
Original PR description
### Steps to reproduce: - Insert a bullet list - Inside of the list, insert a table - Write before and/or after the table (in the same list item) - Press enter before and/or after the inserted text - Notice that the bullet is not split like in a normal list ### Root Cause: - On Enter, list plugin checked whether the list item contained unsplittable element. Since the table was inside the list item, it always treated the list item as unsplittable, even when the cursor was outside the table. As a result, the list item could never be split. ### Solution: - Instead of checking the whole list item, walk up from the split target to the list item and look for an unsplittable element along the way. This allows the list item to split normally when the cursor is outside the unsplittable. task-6449843 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286028 Forward-Port-Of: odoo/odoo#280903
After selecting a suggested partner, the form now correctly returns to its saved state instead of continuing to show inactive Save and Discard buttons. This avoids user confusion by making the screen status match the fact that the enriched partner record has already been saved.
Original PR description
Steps to reproduce: 1) open partner form view 2) type in the name field 3) select a suggestion from the autocomplete dropdown Issue: The record is enriched and saved, but the form still displays the save/discard buttons, and clicking them does nothing. The record dirty indicator is driven by 2 signals 1) `model.root.dirty`, which is cleared by save() call earlier in the onSelect() 2) the state `fieldIsDirty` of the `FormStatusIndicator` The second indicator is set to true when the user types in an input field, and selecting an option never clears it. The `setDirty` prop no longer exists, and therefore was deadcode. This commit emits `FIELD_IS_DIRTY` bus event, which is the only way to update the second indicator. With that, the indicator goes back to saved state once the record is updated. task-6475332 Forward-Port-Of: odoo/odoo#286651 Forward-Port-Of: odoo/odoo#285897