Wednesday, September 9, 2026
47 changes · saas-19.3
Enhancements to existing features
Event badges now better support folded A4 printing by keeping QR codes visible and showing ticket instructions when available. Event agenda and session favorite messages are simplified, with clearer star-based favorite actions and fewer unnecessary labels on attendee badges.
Original PR description
Several diff for OXP [IMP] event: improve A4 foldable badge -> required for oxp kenya - if you have ticket instruction, use it on badge + add qr code always visible [IMP] event: don't show tag (question reply) if only one choice -> fix case of "yes, agree" show on badge as tag "yes" [IMP] website_event_track: typo and make it less verbose -> FP quick pass usability [IMP] website_event_track: replace fa-bell by fa-star -> why ? not sure better after... but FP request -> + add menu whishlist directly in event sub menu ## deploy ``` views = [ 'website_event_track.agenda_main_track', 'website_event_track.track_card', 'website_event_track.tracks_search', 'website_event_track.event_track_aside_other_track', 'website_event_track.track_widget_reminder', ] from odoo.upgrade import util for xmlid in views: util.update_record_from_xml(env.cr, xmlid) ```
Italian electronic invoices now handle cash rounding lines more safely when generating XML. This avoids changing shared tax calculation logic, reducing the risk of side effects in other accounting processes.
Original PR description
Remove the override of `_prepare_product_base_line_for_taxes_computation` since it's a low level method used by a lot of flows. Instead, we just add the 0% exempt tax on the line on-the-fly at the generation of the xml. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#287016
Improves how Odoo updates records arranged in parent-child trees, avoiding slow full-table scans on large datasets. This can significantly speed up operations such as stock transfer validation and updates to partners, locations, categories, and menus when many related records exist.
Original PR description
Our customer has 1.7M packages and very slow validate: the transfer took 8.6s, and 5.35s of it was the single `UPDATE` that `_parent_store_update` runs to move `parent_path` over a subtree. It looks…
Our customer has 1.7M packages and very slow validate: the transfer took 8.6s, and 5.35s of it was the single `UPDATE` that `_parent_store_update` runs to move `parent_path` over a subtree.
It looks for the descendants with `LIKE concat(node.parent_path, '%')`. The pattern comes from a column, so Postgres cannot use the index on `parent_path` and scans the whole table. The change asks for the same rows as a range, which the index does serve:
AND child.parent_path >= node.parent_path
AND child.parent_path < left(node.parent_path, -1) || '0'
`parent_path` always ends with `/` and `0` is the next character, so that closes the range on the subtree. Same rows, same order, one line of SQL.
On a table of 302000 rows, moving 62 nodes, both forms return the same 9362 rows: 3302ms before, 223ms after. On the customer database a single parent write went from 0.82s to nothing measurable.
-- before
Update on stock_package child (actual time=3175.525..3175.527)
-> Nested Loop (actual time=7.171..2987.424 rows=9362)
Join Filter: ((child.parent_path)::text ~~ concat(node.parent_path, '%'))
Rows Removed by Join Filter: 18714638
-> Seq Scan on stock_package child (rows=302000)
-> Materialize (rows=62 loops=302000)
Execution Time: 3301.796 ms
-- after
Update on stock_package child (actual time=223.040..223.041)
-> Nested Loop (actual time=7.874..22.389 rows=9362)
-> Index Scan using stock_package_pkey on stock_package node (rows=62)
-> Index Scan using stock_package__parent_path_index on stock_package child
Index Cond: ((parent_path >= node.parent_path) AND (parent_path < left(node.parent_path, -1) || '0'))
Execution Time: 223.041 ms
This is not about only `stock.package`. Every model on `_parent_store` pays it once the table grows, `res.partner` and `stock.location` included.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#287180Reconciled bank statement lines now use the account name when the related move name is just a placeholder slash. This makes accounting records easier to understand and avoids showing unhelpful placeholder text to users.
Original PR description
This commit will treat move with "/" as their name as empty, and put the name of the account in the reconciled line name task-6424612 Forward-Port-Of: odoo/enterprise#127842
Resolved issues and error corrections
This fixes an issue where Odoo could mark a chatter message as edited even when the user only opened edit mode and saved without changes. The change makes the comparison ignore hidden email-formatting comments, keeping the message history more accurate and reducing confusion for users.
Original PR description
Steps to reproduce: ------------------------------------- 1. Open the chatter of any record 2. Open the full composer for the Log Note 3. Add some text and paste some images > Post the log note 4.…
Steps to reproduce: ------------------------------------- 1. Open the chatter of any record 2. Open the full composer for the Log Note 3. Add some text and paste some images > Post the log note 4. Click on the Edit option 5. Save the message without editing anything Observation: ------------------------------------- You will notice that the (edited) label appears even though the message wasn't edited at all, only the edit mode was made active. Issue: ------------------------------------- When a message is posted via the mail composer, the email conversion pipeline injects MSO conditional comments like `<!--<![endif]-->` and `<!--[if mso]>...<![endif]-->` into the HTML body. These comments are added by the `_hideForOutlook` and `createMso` https://github.com/odoo/odoo/blob/083e091eaa7d983f6c826c02b0d0652a821227fb/addons/mail/static/src/views/web/fields/html_mail_field/convert_inline.js#L1978-L1988 https://github.com/odoo/odoo/blob/083e091eaa7d983f6c826c02b0d0652a821227fb/addons/mail/static/src/views/web/fields/html_mail_field/convert_inline.js#L1699-L1707 functions to ensure Outlook compatibility, they wrap responsive elements so that Outlook receives simplified table-based fallbacks while modern clients see the original layout. The stored message body on the server retains these comments. When a user clicks "Edit" on such a message, the body is loaded into the OdooEditor. The browser's DOM parser treats `<!--<![endif]-->` as standard HTML comment nodes, which are not preserved in `innerHTML` serialization. So the editor returns the body without these comments, even if the user made no changes. The `edit()` method in then compares `updatedBodyEl.innerHTML` (from editor, no comments) against `messageBodyEl.innerHTML` (from server, has comments), finds a difference, and sends a update to the backend, which stamps the message with the (edited) label. Solution: ------------------------------------- Before comparing innerHTML, strip all HTML comment nodes from both the original and updated body elements. This is done on throwaway DOM elements created solely for comparison. The actual body sent to the server (`body` parameter) is never modified. Note: ------------------------------------- An alternative approach would be to strip comments at the string level using a regex (`html.replace(/<!--[\s\S]*?-->/g, '')`) before creating the DOM elements. This is valid since HTML comment syntax `(<!--...-->)` is strictly defined and no nesting is allowed, so the regex is reliable. opw-6328529 Forward-Port-Of: odoo/odoo#274927
Saving Point of Sale settings now assigns manager employees from the correct company instead of accidentally using employees from the user's currently active company. This prevents cross-company employee links in multi-company setups, while single-company setups are unchanged.
Original PR description
Steps to reproduce: - multi-company database, PoS Manager user with an employee in each company - current company set to company A - open the settings of a PoS configuration belonging to company B…
Steps to reproduce: - multi-company database, PoS Manager user with an employee in each company - current company set to company A - open the settings of a PoS configuration belonging to company B and save Issue: The advanced_employee_ids of company B's PoS now also contains the manager's employee of company A, an employee from another company. Cause: res.config.settings.create() appends the PoS managers' employees with `_get_group_pos_manager().user_ids.employee_id`. res.users.employee_id is computed for the current company (self.env.company), not for the company of the pos.config being edited, so the employees of the active company are linked instead of the PoS company's. pos.config.write() already resolves them with `with_company(config.company_id)` since fccccf6cabe5, but the settings path was left unscoped. Fix: Resolve employee_id with `with_company(config.company_id)` in the settings create, as done in pos.config.write(). Single-company databases are unaffected. opw-6544518 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes an internal test issue where large user ID numbers could be displayed differently than expected in message tracking checks. The change helps keep the test suite stable and prevents false failures in full test runs.
Original PR description
When calling message_post() with custom tracking_values, the new_value field is rendered verbatim by the QWeb template into the message body. Automatic tracking (mail_track_mixin) already formats integers via formatLang before setting new_value, but the test was passing a raw integer (self.env.uid), causing a mismatch with the formatted value expected by assertTrackingValueInBody. This only manifests when uid >= 1000.
Step to reproduce:
- Create a db with test_mail installed
- run `psql <db_name> -c "SELECT setval('res_users_id_seq', 1234, true);"` (to forcefully increment the sequence)
- launch the test_track_multi_models test
The test will fail due to this sequence increment when the test suite in ran fully (without splits like on runbot).The Timesheet Assistant now updates immediately when a timesheet date is changed from a linked task. This avoids showing outdated information and removes the need for users to refresh the page manually.
Original PR description
Steps to Reproduce: - Install timesheet_grid and activate Timesheet Assistant - Open a timesheet and click the task external link - Change the timesheet date from the task form and save Issue: When the timesheet date is changed from the task, the assistant still shows the old date until the page is refreshed Fix: Reload assistant timesheets after the linked task is saved and refresh or clear the selected timesheet based on the new date task-6454988
This fix prevents Saudi ZATCA invoices from being submitted more than once when users only have read-only access to journals. The system now records the successful submission correctly, reducing duplicate government filings and related operational risk.
Original PR description
**Steps to reproduce:** This issue is hard to reproduce because it requires a live ZATCA connection: - As a user with read-only permission on journals, send an invoice to ZATCA. - You get an access error on the journal, and the invoice is unchanged (You can try sending it again to ZATCA). **Issue:** What happens is: - A user with read-only permission on journals sends an invoice to ZATCA. - If ZATCA responds with a 200 (successfully submitted), we try to write on the field `journal.l10n_sa_latest_submission_hash` - With no write permissions, the write fails and all changes are rolled back (on odoo, not on ZATCA) - We can send the invoice again to ZATCA, resulting in duplicates. **Solution:** - Added a sudo when writing on the field: `journal.l10n_sa_latest_submission_hash` opw-6320179 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286570 Forward-Port-Of: odoo/odoo#278728
Signed quotation PDFs are now posted in a way that customers can still see them but cannot edit or delete them from the portal communication history. This prevents the signed document from being lost before an order is confirmed, especially when payment is pending by wire transfer.
Original PR description
Issue: A customer who signs a quotation can delete the chatter entry containing the generated signed PDF. For quotations awaiting a wire transfer, this can remove the only retrievable snapshot of the…
Issue: A customer who signs a quotation can delete the chatter entry containing the generated signed PDF. For quotations awaiting a wire transfer, this can remove the only retrievable snapshot of the signed quotation before the order is confirmed. Steps to reproduce: - Create a quotation requiring an online signature and payment. - Sign it from the customer portal and select wire transfer. - Delete the "Order signed by ..." entry from the portal communication history. Cause: The signing endpoint posts the generated PDF as a regular customer authored comment. Portal chatter allows customers to update their own comments, and deleting one clears its attachments, so the signed PDF is physically removed. https://github.com/odoo/odoo/blob/e479111294b11058038defc31505cc81ac1f1821/addons/sale/controllers/portal.py#L348-L358 Solution: Classify the signed document entry as an automated comment. This keeps it visible and attributed to the customer while ensuring that both the portal interface and backend message rules treat its content and attachment as immutable. Regular customer comments keep their existing behavior. opw-6466029 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283595
This fixes an issue in the website editor where clicking inside a navigation link could unexpectedly move the text cursor to the start of the link. Editors can now place the cursor where intended, making menu and link text edits smoother and less frustrating.
Original PR description
Problem: Clicking inside a navigation link in website builder causes the caret to jump to the start of the link element. Cause: `LinkPlugin` unconditionally reset the selection to the start of non-editable link elements, ignoring whether the anchor node was inside an editable child element. Solution: Do not reset selection if the anchor node is inside a `contenteditable` element. Steps to reproduce: - Open website builder. - Click inside a navbar link to place the caret. => Caret no longer jumps to the start of the link. opw-6535386 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#287301 Forward-Port-Of: odoo/odoo#286527
This fix lets calendar views apply the right filtering rules when used across different Odoo apps. It helps ensure users see the correct calendar records for their specific workflow, reducing display inconsistencies.
Original PR description
Add an override for computing the domain of the calendar views to use in different modules opw-6509233 Forward-Port-Of: odoo/odoo#286993
The Planning calendar now shows the Open Shifts filter again when Field Service Planning is installed. This helps users quickly find unassigned work without losing the calendar behavior required by Field Service.
Original PR description
## Steps to reproduce: - Install planning_field_service module - Navigate to Planning calendar view - Notice the side panel filters doesn't have Open shifts filter ## Cause: When installing field service we remove the writable filters in the calendar views of planning ## Fix: We add a read filter to the calendar view instead of the write filter that we remove upon field service installation. Backport of https://github.com/odoo-dev/enterprise/commit/1ab617f1b0cddc9132964979812573286a6148d9 opw-6509233 Forward-Port-Of: odoo/enterprise#130288
This update keeps PDF-related features working reliably across supported Odoo environments by aligning with the PDF library version used on Ubuntu Jammy. It also adds compatibility for newer library versions, reducing the risk of errors when generating or handling PDFs.
Original PR description
Align pypdf usage with the PyPDF2 1.26 API used on Ubuntu Jammy, Odoo 17.0's main supported Ubuntu version, and add the missing compatibility mapping for newer pypdf versions. Forward-Port-Of: odoo/enterprise#130971
This fixes an issue where a measure defined by a report could disappear from the Measures menu after users deselected it and refreshed or filtered the pivot view. Business users can now reliably reselect report measures, helping reporting views stay consistent during analysis.
Original PR description
TL;DR - we lose the measures from arch after a reload, if removed from activeMeasures Step to reproduce: - install pos, create few orders - go to reporting> orders> switch to pivot view - click the…
TL;DR - we lose the measures from arch after a reload, if removed from activeMeasures Step to reproduce: - install pos, create few orders - go to reporting> orders> switch to pivot view - click the `Measures` dropdown, `Order` is already selected - untick it, then apply some filter so that view reloads (ex order date) - reopen `Measures` dropdown, notice `Order` is missing form measures Cause: - view `view_report_pos_order_pivot` has `<field name="order_id" type="measure"/>` in its pivot view https://github.com/odoo/odoo/blob/f5c68cf0eb2ce6ec96dd4006b28466044af10e33/addons/point_of_sale/views/pos_order_report_view.xml#L10 - `order_id` is M2O field - Measure is compute from present `activeMeasure` and fields of type `["integer", "float", "monetary"]` https://github.com/odoo/odoo/blob/f5c68cf0eb2ce6ec96dd4006b28466044af10e33/addons/web/static/src/views/utils.js#L89-L120 - when the view is first loaded, `activeMeasure` all the fields with `type="measure"` which is directly passed to pivot's model as a metadata https://github.com/odoo/odoo/blob/f5c68cf0eb2ce6ec96dd4006b28466044af10e33/addons/web/static/src/views/pivot/pivot_arch_parser.js#L59-L60 https://github.com/odoo/odoo/blob/f5c68cf0eb2ce6ec96dd4006b28466044af10e33/addons/web/static/src/views/pivot/pivot_view.js#L41 - when we toggled the `order_id` from measure and reloaded, `order_id` is popped from `activeMeasure` and as it's field type is `many2one` it is not considered for `measures` in `computeReportMeasures` Fix: - maintain the measures from arch separately and feed it to `computeReportMeasures` opw-6416196 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286013 Forward-Port-Of: odoo/odoo#278850
Facebook and LinkedIn mentions in social posts are now detected more reliably and linked to the right profiles. Facebook post text is also kept unchanged after publishing, preventing malformed mentions when posts are duplicated.
Original PR description
This commit fixes an issue with the mention regexes for social_facebook as they weren't properly replaced by the initial mechanism. The initial mechanism was introduced by [1]. Now, we check every possible mention and if it is indeed a known mention, then we replace it by the correct link to their profile. [1]: https://github.com/odoo/enterprise/commit/4dacc5fce72687680080f75feef875fbfb3dbd15 task-6026857
The French 2033 B fiscal declaration now includes all required operating expense lines in its total. This helps businesses using the French reports see a more accurate accounting income calculation and avoid understated expenses in the report.
Original PR description
**Steps to reproduce:** - Install the `l10n_fr_reports` module and switch to the FR Company. - Navigate to Invoicing > Reporting > Fiscal Declaration and select `2033 B`. - Observe the formula of `A…
**Steps to reproduce:** - Install the `l10n_fr_reports` module and switch to the FR Company. - Navigate to Invoicing > Reporting > Fiscal Declaration and select `2033 B`. - Observe the formula of `A - Accounting income` > `Operating expenses (II)`. **Observation:** The formula does not include the balances of `FR_2033_B_c244`, `FR_2033_B_c250`, and `FR_2033_B_c252`. **Root Cause:** At [1], the formula for `Operating expenses (II)` is missing the balances of fields `244, 250, and 252`, even though these lines are part of the operating expenses section. **Fix:** This commit ensures that `Operating expenses (II)` displays the correct total balance. **Reference**: <img width="1422" height="490" alt="6482797" src="https://github.com/user-attachments/assets/95b35ac7-f410-413b-8ef9-29f97f16c35a" /> [1]: https://github.com/odoo/enterprise/blob/54bfcbee37a241ae70b9bebb9cf23d76172e18fe/l10n_fr_reports/data/fiscal_declaration/report_2033_B_simplified_profit_loss.xml#L302 opw-6482797
On mobile, opening a full-screen image preview now hides the editor toolbar so the preview controls remain accessible. The change also dismisses the keyboard when the preview opens, making image viewing and actions smoother for users.
Original PR description
When displaying the full screen image preview lightbox on mobile, the toolbar remains displayed. Because of this, the toolbar of the lightbox cannot be accessed. This commit hides the toolbar when a lightbox is displayed. task-6370220 Forward-Port-Of: odoo/odoo#286346 Forward-Port-Of: odoo/odoo#274949
Checkout now correctly allows carts that include free promotional reward items, even when the website blocks regular zero-priced products. This prevents customers from being sent back to the cart unnecessarily when a valid free gift promotion is applied.
Original PR description
As of commit b8e790b2, a cart containing a product priced at 0 while the website forbids the sale of zero-priced products is no longer payable: the customer is redirected back to the cart with a warning. Reward lines were caught by that new rule. A promotion offering a free gift whose product has no sale price adds a reward line priced at 0 to the cart, so the whole cart became unpayable even though nothing was wrong with it. This commit excludes reward lines from the zero-priced rule, the same way delivery lines already are. opw-6526396 Forward-Port-Of: odoo/odoo#287028 Forward-Port-Of: odoo/odoo#286464
Users can now download files opened from the Discuss file viewer without seeing an error. The change fixes a request mismatch so attachments from channel conversations download reliably while preserving the correct file name.
Original PR description
Description of the issue/feature this PR addresses: Downloading an attachment from the file viewer fails with a `405 Method Not Allowed` error when the attachment belongs to a Discuss channel. I've…
Description of the issue/feature this PR addresses:
Downloading an attachment from the file viewer fails with a `405 Method Not Allowed` error when the attachment belongs to a Discuss channel.
I've already submitted a ticket to Odoo: #6430586
Steps to reproduce (on a 18.0 runbot):
1. open Discuss and send an image in a channel
2. click the image to open the file viewer
3. click the download button (either the one in the header or the one in the bottom
toolbar)
The server rejects the request:
```
POST /discuss/channel/1/image/519861?filename=image.png&unique=32647b0f&download=true 405
```
and the user gets a `RPC_ERROR: Arbitrary Uncaught Python Exception` dialog reporting `405 Method Not Allowed`.
Cause: `download()` always issues a POST request, while the routes serving the attachments of a discuss channel only allow GET:
* `/discuss/channel/<int:channel_id>/attachment/<int:attachment_id>`
* `/discuss/channel/<int:channel_id>/image/<int:attachment_id>`
so the request never reaches the controller. Downloading the very same attachment from the attachment card in the conversation still works, because that one is a plain anchor navigation (GET).
This is a regression from fb152985f4b8 ("[FIX] web: download FileViewer files via blob helper"), which routed the file viewer download through `download()` in order to honor the filename sent by the server in the `Content-Disposition` header.
Only 18.0 is affected: saas-18.1 and saas-18.2 do not have the commit that introduced the regression, and from saas-18.3 on, the `urlRoute` override was dropped and channel attachments are served through the standard `/web/content` and /web/image` routes, which are not restricted to GET.
The download is still sent with POST on those branches though, hence forward-porting this up to master.
Current behavior before PR:
Downloading a Discuss channel attachment from the file viewer raises a 405 error and the file is not downloaded. Images and other file types are equally affected.
Desired behavior after PR is merged:
The file is downloaded, keeping the filename advertised by the server. The download is performed with a GET request through `downloadFile()`, which still goes through the blob helper, so the fix of fb152985f4b8 is preserved. This is already the way a file is downloaded from its url in `readonly_file.js`.
Added a test that downloads an image attachment of a channel from the file viewer and asserts the request is a GET on the channel attachment route. It fails before this fix with `POST /discuss/channel/1/image/1`.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#287172
Forward-Port-Of: odoo/odoo#279232This fixes cases where pasted or inserted tables with merged or missing cells could disrupt editor tools. The editor now normalizes those tables into a complete grid, helping table menus and editing actions work consistently.
Original PR description
Description of the issue this PR addresses: We don't support colspan/rowspan in the editor, so tables containing them can break other functionality that assumes a rectangular grid (equal cell count per row). This PR expand any rowspan/colspan into individual cells on insert. opw-6347233 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284159 Forward-Port-Of: odoo/odoo#281114
This fixes a timing issue in German point-of-sale certification where a restaurant table could be blocked while a fiscal certification request was still processing. Staff now only enter the table after that request is complete, making table opening more reliable during sales.
Original PR description
In this commit: ------------------ - The API call is triggered when an order is updated in Fiskaly. - Previously, the request could be awaited while opening a table, blocking the table from opening before the product screen was ready. - Now, the request is awaited before allowing the table click, ensuring the table opens only after the request is completed. Task: 6522079 Forward-Port-Of: odoo/enterprise#130785 Forward-Port-Of: odoo/enterprise#130132
A flaky automated test for accounting reports was corrected so it waits for the report to fully load before navigating. This reduces random test failures and helps keep validation of financial reporting features more dependable.
Original PR description
The issue appeared 1 every 3 run, the reason was because it didn't wait the report to be opened and clicked on the breadcrumb. So it clicked the breadcrumb of the return and not the one of the report. The fix is to add a step in between checking the report is loaded. Runbot error: https://runbot.odoo.com/odoo/error/944180
Corrected formatting in the Mail and Taiwan ECPay module descriptions so they display properly on the Apps page. This prevents confusing raw text or incorrectly formatted lists from appearing to users and reduces unnecessary rendering errors in logs.
Original PR description
Two module manifests hold a `description` whose reStructuredText does not parse. Both are rendered by `ir.module.module._get_desc` (these modules have no `static/description/index.html`, so the RST…
Two module manifests hold a `description` whose reStructuredText does not parse. Both are rendered by `ir.module.module._get_desc` (these modules have no `static/description/index.html`, so the RST path is the one used on the Apps page). ### `mail` The line introducing the list of email-enabled documents is followed by a row of dashes. In reStructuredText an underline directly below a line of text makes it a section title, so docutils treats a 102-character sentence as a heading, then fails on the indented list that follows without a blank line: ``` <string>:38: (ERROR/3) Unexpected indentation. <string>:43: (WARNING/2) Block quote ends without a blank line; unexpected unindent. ``` These are logged every time the description is rendered, and the bullet list ends up rendered as a block quote instead of a list. The dashes are dropped, since the line is a regular sentence and not a section title, and the list is surrounded by blank lines. ### `l10n_tw_edi_ecpay` The whole description is indented, which makes reStructuredText read it as a block quote. A section title is not allowed inside a block quote: ``` <string>:3: (SEVERE/4) Unexpected section title. ``` At SEVERE level this reaches the default `halt_level`, so rendering raises instead of returning a document and `_get_desc` falls back to showing the raw description in a `<pre>` block. The indentation is removed. --- Checked by rendering the `description` of every manifest under `addons/` and `odoo/addons/` with the same docutils settings `_get_desc` uses: these were the only two that reported anything, and both are clean after the change. Forward-Port-Of: odoo/odoo#285323 Forward-Port-Of: odoo/odoo#284360
Fixed a spelling mistake in the Helpdesk “Auto Assignment” group name. This improves clarity for users and keeps the Helpdesk settings text professional and consistent.
Original PR description
This commit fixes the typo in the "Auto Assignment" group. task-6542450 Forward-Port-Of: odoo/enterprise#130880 Forward-Port-Of: odoo/enterprise#130841
This fixes an issue where approved Time Off accrual allocations could fail after a first milestone was added to an initially empty accrual plan. The change ensures the allocation has a valid starting reference date, so employees can save Time Off requests without encountering an error.
Original PR description
## Steps to Reproduce: - Install the Time Off module. - Create an Accrual Plan without any milestones. - Create an Accrual Allocation using the newly created accrual plan. - Approve the allocation. -…
## Steps to Reproduce: - Install the Time Off module. - Create an Accrual Plan without any milestones. - Create an Accrual Allocation using the newly created accrual plan. - Approve the allocation. - Add a milestone to the accrual plan. - Create a new Time Off request after the allocation start date. - Save the record. ## Error: `TypeError - '>' not supported between instances of 'datetime.date' and 'bool'` ## Cause: `lastcall` is initialized by method `_add_lastcalls()`, which is only called at create and write. When an accrual allocation is created with an accrual plan that has no milestones, `_add_lastcalls()` returns early because `level_ids` is empty, leaving `lastcall` set to `False`. - [1] If a milestone is added later, `lastcall` is compared with `first_level_start_date`, resulting in a comparison between boolean and datetime, which raises an error. ## Fix: When `lastcall` is not set, default it to `first_level_start_date`. [1] - https://github.com/odoo/odoo/blob/27036bea232572ba692fbb95387911eb453266bf/addons/hr_holidays/models/hr_leave_allocation.py#L703-L706 sentry-7615375197 Forward-Port-Of: odoo/odoo#282074 Forward-Port-Of: odoo/odoo#280674
Kit sales now correctly exclude deliveries completed after the selected accrual date when calculating delivered quantities. This prevents orders from appearing as ready to invoice too early, improving accuracy in period-end invoicing and revenue accruals.
Original PR description
When selling a kit, the qty_delivered_at_date was not ignoring moves that were done after the accrual_entry_date. Steps to reproduce: ------------------- * Create a kit with any component and make it's invoice policy "Delivered quantities" * Create a sale order for this kit and confirm it, change the order date to any date in the past * Validate the picking * Go check the "Invoiced to be issued" * Change the accrual_entry_date to a date before the picking was validated > Observation: The order still appears opw-6290222 Forward-Port-Of: odoo/odoo#285932 Forward-Port-Of: odoo/odoo#274745
Fixes an issue where reconciliation entries could receive different labels depending on whether they were created by a user or by the automatic reconciliation process. Labels are now applied using the company's language, helping keep accounting records consistent and easier to understand.
Original PR description
### Problem `label` on `account.reconcile.model.line` is a **translatable** field, but its value is written onto the journal item created when the model is applied (`account.move.line.name`). That…
### Problem
`label` on `account.reconcile.model.line` is a **translatable** field, but its value is
written onto the journal item created when the model is applied (`account.move.line.name`).
That means the label is read in the language of whoever applies the model:
- a user working in another language writes the translated value;
- the auto-reconciliation cron writes the **source** value, since it runs as OdooBot.
So the very same reconcile model ends up writing two different labels on the journal items,
depending on who applied it.
### How it shows up
It becomes visible when a reconcile model is created by **duplicating** an existing one and
the label is then edited while working in a non-source language. The translation holds the
new text, while the source value silently keeps the label of the original model — and the
source value is exactly the one the cron writes. The result is a set of journal items where
some carry the intended label and some carry the label of an unrelated model.
### Fix
The journal item belongs to the company, so the label is read in the **company** language
via a small `_get_aml_label()` helper, instead of the language of the current environment.
It falls back to the current behaviour when the company has no language set.
`_prepare_aml_vals()` is the only place in 18.0 that reads `self.label` for the journal item.
### Test
Adds `TestBankRecWidget.test_auto_reconcile_model_label_uses_company_lang`: a reconcile model
whose line label is translated in the company language, applied by the auto-reconciliation
cron running in the source language, and asserts the journal item carries the company-language
label.
```
odoo -d <db> -u account_accountant --test-enable --stop-after-init \
--test-tags /account_accountant:TestBankRecWidget.test_auto_reconcile_model_label_uses_company_lang
```
Without the fix the test fails with `[{'name': 'Frais bancaires'}] != [{'name': 'Bank fees'}]`;
with the fix it passes. The full `account_accountant` suite was also run on a clean 18.0
database: 203 tests, 0 failed, 0 errors.
Forward-Port-Of: odoo/enterprise#130719
Forward-Port-Of: odoo/enterprise#128433Helpdesk users can now create tickets for teams with automatic assignment without being blocked by Time Off access restrictions. The assignment process still checks who is unavailable, but does so as a system decision so regular helpdesk work is not interrupted.
Original PR description
Before this commit, a helpdesk user creating a ticket on a team that assigns tickets automatically got "You are not allowed to access 'Time Off' (hr.leave) records". This happens because picking the next assignee reads hr.leave as the acting user, to skip the members who are off, and a plain helpdesk user has no access to Time Off. This commit reads the employees of the members and their leaves in sudo, as whom to assign is a system decision. https://runbot.odoo.com/odoo/error/947053 Forward-Port-Of: odoo/enterprise#130796
The accounting logo now appears correctly in tax return activities, making these items easier to recognize for users. This fixes a minor visual issue and improves consistency in the accounting workflow.
Original PR description
Before PR: - Accounting logo was not visible in Tax return activities. After PR: - Accounting logo is visible in Tax return activities. task-6463584 Forward-Port-Of: odoo/enterprise#130721 Forward-Port-Of: odoo/enterprise#129501
Dropshipped purchases no longer change the average cost of products that never enter stock. This prevents misleading inventory valuations and negative stock valuation balances after related sales, purchases, invoices, and bills are completed.
Original PR description
stock_*: stock_account, stock_dropshipping, stock_landed_costs **Problem:** dropship moves impact the average cost of products which can lead to negative balance in stock valuation account **Steps to…
stock_*: stock_account, stock_dropshipping, stock_landed_costs **Problem:** dropship moves impact the average cost of products which can lead to negative balance in stock valuation account **Steps to reproduce:** On a new db with no demo data and stock_dropshipping, sale_management and accountant module installed (bug also reproducible in runbot with same steps, but it's easier to see the negative impact on accounting on a new db) : 1) enable dropshipping 2) create a storable product with average perpetual category 3) in the purchase tab set a vendor with a price of 10 4) in the inventory tab select the dropship route 5) create PO for 1 unit @ 5, validate receipt and confirm bill 6) confirm a SO for 1 unit of the product 7) confirm linked PO and validate dropship move 8) confirm invoice and vendor bill -> see how the standard price is now 7.5 9) remove dropship route from the inventory tab of the product 10) confirm a SO for 1 unit of the product 11) validate delivery and confirm invoice 12) open 'inventory valuation' view **Current behavior:** the initial balance of stock valuation is -2.5 **Expected behavior:** it should be 0 (there shouldn't be a negative initial balance if all invoices and bills are confirmed) **Cause of the issue:** The issue happens after step 8) The problem is that the dropship has an impact on the average price of the product but not on the accounting. Before the dropship we have 1 unit in stock @ 5 and the stock valuation account has a balance of 5 (from the bill), so all is good. The dropship then changes the standard price to 7.5. That's because currently, in _run_average_batch() the dropship move first impacts average cost like an incoming move with a value of 10 (at this point we have 1 move @ 10 and 1 @ 5 so average cost is 7.5) https://github.com/odoo/odoo/blob/bcaa8b6b00fa1f16513d680c5187fd424bc7cf8c/addons/stock_account/models/product.py#L493-L500 https://github.com/odoo/odoo/blob/bcaa8b6b00fa1f16513d680c5187fd424bc7cf8c/addons/stock_account/models/product.py#L505-L510 and then it impacts the value as a regular outgoing move (meaning it leaves the inventory at the average cost of 7.5) and does not impact the average cost (which is the basic behaviour of outgoing moves) https://github.com/odoo/odoo/blob/bcaa8b6b00fa1f16513d680c5187fd424bc7cf8c/addons/stock_account/models/product.py#L515-L517 https://github.com/odoo/odoo/blob/60b5b99d569dbe183ef9c980217ccfe9bf243756/addons/stock_account/models/product.py#L522 Therefore after step 8), the standard price is 7.5 and we have a unit in stock so, in the inventory valuation view the ending stock is 7.5$. But the dropship did not impact the stock valuation account so the initial balance is still 5$ and we have lines with credits and debits of 2.5$ in the the stock variation section. After steps 9 to 12, both the initial balance and ending stock decrease by 7.5 (which is expected), leading to a negative initial balance in stock valuation. **fix:** We don't take into account the stock move from dropships in the avco computation **tests:** The fix requires modifications in a few tests: - test_dropship_bill_standard_price_update checks that the bill of a dropship move impacts the standard price, so we delete this test - test_lot_normal_3, the asserts on the total_value still make sense but not those on standard_price - test_dropship_kit_bom_updates_component_standard_price test_average_cost_dropship_in_negative_quantity, test_out_move_validate_as_stock_user: standard price should not be impacted by dropship Task 6515358 Forward-Port-Of: odoo/odoo#285576
Depreciation models can no longer be deleted while they are linked to assets that are still running, paused, or closed. This prevents accounting assets from losing required setup information and becoming impossible to manage later.
Original PR description
**Steps to reproduce:** * Install the **Accounting** (`account`). * Create a **Depreciation Model** (e.g. Linear, 5 years). * Create an asset, assign the depreciation model, and confirm it. * Go to…
**Steps to reproduce:** * Install the **Accounting** (`account`). * Create a **Depreciation Model** (e.g. Linear, 5 years). * Create an asset, assign the depreciation model, and confirm it. * Go to **Accounting → Configuration → Depreciation Models** and delete the model used by the running asset. * Try to **Reset to Draft** on **asset**. **Observed behavior:** * The depreciation model is deleted silently. * The asset's `model_id` FK becomes `NULL`, causing all related fields (`method`, `method_number`, `method_period`, `journal_id`, etc.) to become empty. * Any subsequent attempt to cancel, reset to draft, or delete the asset fails with a **missing required field** error, leaving the asset permanently unmanageable. **Cause:** * `account.depreciation.model` had no `@api.ondelete` guard — deletion was entirely unprotected, unlike `write()` which already blocks edits on models used by running assets. * `model_id` on `account.asset` had no `ondelete` constraint, so the database silently NULLed the FK on model deletion. **Fix:** * Add an `@api.ondelete(at_uninstall=False)` method `_unlink_if_no_running_assets()` on `account.depreciation.model` that raises a `UserError` listing the affected asset names when a deletion is attempted while any linked asset is in `open`, `paused`, or `close` state — mirroring the protection already present in `write()`. opw-6233210 Forward-Port-Of: odoo/enterprise#126979
French invoices now show the VAT-on-debits mention only when it applies to service taxes with a non-zero VAT amount. This avoids confusing or unnecessary wording on export invoices and ensures service invoices display the correct legal note.
Original PR description
**Purpose** Follow-up to fix two issues reported in #277109 regarding the "TVA exigible d'après les débits" mention on French invoices. **Fixes Applied** 1. **Tax Scope Mismatch:** Changed `t.tax_scope == 'consu'` to `t.tax_scope == 'service'`. To trigger the exigibility mention on a service product, the user will configure a proper "service" scoped tax, not a goods tax. 2. **International/Export Invoices:** Added a check for `amount != 0`. Previously, the mention would print on international export invoices if the applied 0% tax had exigibility set to `on_invoice`. This hides the redundant mention for 0% exports. Forward-Port-Of: odoo/odoo#277468
SEPA direct debit XML files will no longer include an extra identifier field for countries where banks may reject it. The field is now limited to Nordea-related countries where it is required, improving payment file acceptance without changing normal workflows.
Original PR description
### Issue: An unexpected `<SchmeNm><Cd>CUST</Cd></SchmeNm>` node was added inside `<InitgPty><Id><OrgId><Othr>` for all countries Some Italian banks reject SDD files containing this node ### Cause:…
### Issue: An unexpected `<SchmeNm><Cd>CUST</Cd></SchmeNm>` node was added inside `<InitgPty><Id><OrgId><Othr>` for all countries Some Italian banks reject SDD files containing this node ### Cause: https://github.com/odoo/enterprise/commit/3c3c64b511d07fc1ba33c30363972f5b0f7283d6 added `<SchmeNm><Cd>CUST</Cd></SchmeNm>` unconditionally for all countries The original fix was intended for Nordea (Sweden) only, which requires this node explicitly The assumption that other countries would accept it was incorrect ### Steps to reproduce: - Install `account_sepa_direct_debit` and `l10n_it` - Switch to the IT company - In Settings, set SEPA Direct Debit Creditor Identifier to `BE30ZZZ300D000000042` - Create and confirm a Payment (Method: SEPA Direct Debit, any customer and amount) - Create and validate a Batch Payment with that payment - Open the generated PAIN008 XML Before the fix, `<SchmeNm><Cd>CUST</Cd></SchmeNm>` is present opw-6530996 Forward-Port-Of: odoo/enterprise#130304
Fixes an issue where refreshing India's GST connection token could incorrectly replace the stored token with an empty or unrelated value. The refresh now only extends the existing token's validity, helping avoid unnecessary GST reporting connection problems.
Original PR description
Previously, `_cron_refresh_gst_token` updated the value of `l10n_in_gstr_gst_token` when refreshing the GST token using `response.get('txn')`.
However, the response received during a token refresh is: `{'status_cd': '1', 'status_desc': 'If previous Auth Token is found'}`
The GST token itself remains unchanged during a refresh; only its validity is extended. Therefore, writing `l10n_in_gstr_gst_token` with `response.get('txn')` is unnecessary and incorrect.
This commit removes that write operation.
Forward-Port-Of: odoo/enterprise#130726
Forward-Port-Of: odoo/enterprise#130313Cancelled point-of-sale orders and order lines in the German certification flow are now saved and marked as cancellations when sent to Fiskaly. This helps ensure compliant fiscal reporting and avoids mismatches for cancelled sales.
Original PR description
In this commit: --------------- - We now store cancelled retail orders on the server and send the `storno` flag as `true` for cancelled lines and orders to ensure proper handling in Fiskaly. task: 6326042 Relataed PR: https://github.com/odoo/odoo/pull/277648 Forward-Port-Of: odoo/enterprise#130175 Forward-Port-Of: odoo/enterprise#120410
Users sending Colombian DIAN support documents now see a clear message when the required operation mode is not configured. This replaces a confusing server error and helps businesses quickly fix their DIAN setup before resubmitting documents.
Original PR description
**Steps to reproduce:** * Install `l10n_co_dian`. * Configure a company with the Colombian localization. * Set up a DIAN operation mode for Electronic Invoices only (no Support Documents mode). *…
**Steps to reproduce:** * Install `l10n_co_dian`. * Configure a company with the Colombian localization. * Set up a DIAN operation mode for Electronic Invoices only (no Support Documents mode). * Create a vendor bill marked as a Support Document and click **Send to DIAN**. **Observed behavior:** * A cryptic server error is raised: *"TypeError: unsupported operand type(s) for +: 'int' and 'str'"* * No actionable information is shown to the user. **Cause:** * `_add_document_config_vals` assigns `vals['l10n_co_dian_operation_mode']` via `.filtered()`, which returns an empty recordset when no matching operation mode exists. * Accessing a `Char` field on an empty recordset returns `False` (a `bool`, which is a subclass of `int` in Python). * Concatenating `False` with strings in the `sha384` hash calculation raises the `TypeError`. * The missing-mode guard only existed in the commercial events path, not in the main invoice export path. **Fix:** * Raise a descriptive `UserError` that tells the user which mode is missing and where to configure it. opw-6499321 Forward-Port-Of: odoo/enterprise#128935
Completing a field service shift now correctly recalculates the allocated hours linked to that work. This helps ensure planning, timesheet, and sales information stay consistent for accurate reporting and billing.
Original PR description
This reverts commit b642ea4d5d2c0b4bd83c70103f7e8dfa6ef736dd. opw-6542896 Forward-Port-Of: odoo/enterprise#130832
Fixed an issue where changes made to loyalty program rewards could appear to save but then revert when reopened. This ensures promotion and discount updates are preserved, reducing confusion for sales and loyalty program users.
Original PR description
**Steps to reproduce:** 1. Install Sales and Loyalty modules 2. Create a Discount & Loyalty Program (type: Promotion) and save the form 3. Open the Reward modal and edit any values (e.g., 5% discount…
**Steps to reproduce:** 1. Install Sales and Loyalty modules 2. Create a Discount & Loyalty Program (type: Promotion) and save the form 3. Open the Reward modal and edit any values (e.g., 5% discount instead of 10%), save the new changes in the modal and then save the form 4. Re-open the reward modal **Issue:** The updated value (5% discount) is not saved, and the reward reverts to its previous state (10% discount). This issue will occur for any modifications. **Why this happens:** - The write method in `loyalty_program` uses `convert_to_cache` on `reward_ids` to make a constraint check before executing the actual super().write() - A recent commit (https://github.com/odoo/odoo/commit/9c52f6246d24d02457d34df6b559eecf7ec50687) modified `convert_to_cache` to update the cache for `Command.UPDATE` to fix premature computations during `onchange` - This update alters the real record's cache without marking the fields as dirty - When super().write() executes afterwards, the ORM sees the incoming values already match the cache, assumes no changes occurred, and drops the SQL UPDATE **Fix:** - Restrict the cache mutation to only apply to virtual/draft records - This preserves the intended onchange behavior for NewId records while preventing cache corruption on real database records prior to write opw-6527124 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286435
Portal users can now update their electronic invoicing format even after adding a company name to their address. This prevents the field from appearing empty later and helps ensure invoice delivery preferences are retained correctly.
Original PR description
Steps: - Install accounting app. - Login with portal user and set `Company name` on `my/address`. - Try to edit `Electronic Format` field on my details. Issue: - `Electronic Format` field stays empty. Cause: - Since [PR](https://github.com/odoo/odoo/pull/211043) when user set `Company name` on the portal it'll create parent company and since `Electronic Format` is computed from `commercial_partner_id`, so when I update `Electronic format` field on `my/address` it'll set that value on `invoice_edi_format_store` on current address and now when I re-open `my/address` it'll compute `invoice_edi_format` from `commercial_partner_id`'s `invoice_edi_format_store` which is 'none' and it'll set `invoice_edi_format` to False and there is no way portal user can update that company's record Fix: - Update inverse of `Electronic Format` field to properly store invoice_edi_format_store value on commercial partner. Forward-Port-Of: odoo/odoo#286599 Forward-Port-Of: odoo/odoo#277527
Fixes an issue in mail messages where a contact selected by mistake could remain as a hidden recipient after the mention was corrected to a longer name. This prevents unintended notifications and helps ensure only visibly mentioned contacts are contacted.
Original PR description
When a user mentions the wrong partner and corrects it by continuing to type, e.g. picking "John" by mistake, typing further so the text becomes "@ John Doe" and picking "John Doe" in the suggestion…
When a user mentions the wrong partner and corrects it by continuing to type, e.g. picking "John" by mistake, typing further so the text becomes "@ John Doe" and picking "John Doe" in the suggestion popup, the discarded first pick stays in the composer's mentioned partners. On post, mentions are validated by searching the body for "@<name>", and "@ John" is found inside "@ John Doe", so the partner the user tried to replace is kept in the recipients and gets notified even though no mention of them remains visible in the message. Validate mentions from the longest mention text to the shortest, counting the occurrences of each text and blanking them out before looking for shorter ones. A partner whose mention text only appears inside a longer mention is dropped, while distinct partners sharing the same name each consume one occurrence. Steps to reproduce: - Create contacts "John" and "John Doe" - On any record, open the chatter and type "@John", pick "John" by mistake, then keep typing " Doe" and pick "John Doe" in the suggestion popup to correct it - Send the message => The message is also sent to "John" although only "@John Doe" appears in the body. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#287122 Forward-Port-Of: odoo/odoo#284239
The manufacturing accounting WIP report now avoids a harmless warning that appeared during automated report tests with demo data. This keeps test results cleaner and helps reduce noise for teams monitoring system quality.
Original PR description
Runbot was showing warnings when running the test_reports test with the mrp_account and project_timesheet_forecast modules installed with demo data.
```
Unknown directives or unused attributes: {'data-oe-demo'} from <t t-out="', '.join(docs.account_id.mapped('name'))" data-oe-demo="Acme Corp."/>
```
**Root cause:**
Since data-oe-demo is an html attribute usage of it within `<t>` tag raises a warning after this [commit](
https://github.com/odoo/odoo/commit/ae4824640665fc639e03a13c341f18e73060349e) in saas-19.1.
**Solution:**
Usage of span tag instead of <t> tag ensures the same behaviour without the warning.
[runbot-939604](https://runbot.odoo.com/odoo/error/939604)
Forward-Port-Of: odoo/odoo#285666Peruvian electronic invoices now include cash rounding in the final payable amount sent to SUNAT. This prevents mismatches between the displayed rounding amount and the total amount due, helping ensure compliant invoice XML generation.
Original PR description
Steps to reproduce ------------------ 1. On a peruvian company, set a cash rounding method on an invoice 2. Post the invoice and generate the SUNAT UBL 2.1 XML -> the rounding is in…
Steps to reproduce ------------------ 1. On a peruvian company, set a cash rounding method on an invoice 2. Post the invoice and generate the SUNAT UBL 2.1 XML -> the rounding is in `PayableRoundingAmount` but `PayableAmount` still has the amount before rounding! Why it's happening ------------------ The generic code computes `PayableAmount` from `amount_residual`, and Peru overrides it to be the total tax included of the XML minus the prepaid amounts, because the residual can not be used there. Then odoo/odoo@b847552872ad changed the meaning of the totals. The cash rounding line is not part of the base lines anymore, its amount is kept aside in `cash_rounding_base_amount_currency` and the totals do not contain it anymore. The generic code stays correct because `amount_residual` already has the rounding inside but the Peru total using `tax_inclusive_amount_currency` is now the amount before rounding and this is what ends up in the `PayableAmount`! The fix ------- Add the cash rounding amount when computing the `PayableAmount`. opw-6509677 Forward-Port-Of: odoo/enterprise#130732 Forward-Port-Of: odoo/enterprise#129983
This fix ensures that changes to default values in website form fields are properly remembered by the editor's undo history. Business users editing website forms or translations can now undo value changes reliably, avoiding mismatches between what they see and what is saved on the page.
Original PR description
The `value` property of the elements is not tracked by the history plugin, because `MutationObserver` does not produce mutations for that. This commit uses custom mutations when the `value` is changed, to restore the previous value on undo. Steps to reproduce: - Open website builder - Add a form - Set a "Default Value" on a text field - Press enter (to end preview) - Undo (with the button, or with focus out of the option's input) - Bug: The value shown in the page did not revert with undo Similar bug in translate mode task-6229671 Forward-Port-Of: odoo/odoo#286889 Forward-Port-Of: odoo/odoo#281232
The restaurant point-of-sale order tracking test now waits until payment validation and backend synchronization are complete before finishing. This prevents false test failures where updated order quantities or edit status had not yet been saved.
Original PR description
The order tracking tour only waited for the feedback screen to be shown after validating the payment. Since order validation is performed asynchronously while the feedback screen is displayed, the tour could finish before the updated order was synced to the backend. This caused the Python test to still see the original quantity and `is_edited` set to false. To fix we wait for the feedback screen continue button to be enabled, which ensures order validation and synchronization have completed before the tour ends. [error-940386](https://runbot.odoo.com/odoo/error/940386) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282726
Product identifiers sent to Google Analytics now match the identifiers used in Google Merchant Center feeds. This helps Google Ads correctly connect Shopping ad clicks with purchases, improving attribution and reducing matching warnings.
Original PR description
**Issue:** When google analytics (GA) and google merchant center (GMC) are setup, Google Ads diagonistic reports that item IDs cannot be matched to Merchant Center. **Why this happens:** `order_lines_2_google_api` sets `product.barcode or product.id` for `item_id`, while `product.feed._prepare_gmc_items` defaults to `product.default_code or product.id` for the feed's `id` field. Google Ads/Analytics attribution relies on GA4's `item_id` matching GMC's `id` for the same product to connect Shopping ad clicks to purchase events. **References:** https://support.google.com/merchants/answer/6324405?sjid=15224664355638221483-NC https://support.google.com/google-ads/answer/14943675?hl=en opw-6443326 Forward-Port-Of: odoo/odoo#285010
This fixes an issue that prevented users from creating assets without depreciation directly from vendor bills. Businesses can now record these asset purchases correctly without being blocked by unnecessary account requirements.
Original PR description
This commit fixes the ability to create no depreciation assets from vendor bills. Previously, a condition on the depreciation account and expense account restricted the asset creation. backport of https://github.com/odoo/enterprise/pull/123070 task-6283929 opw-6540498 Forward-Port-Of: odoo/enterprise#130653