Daily updates from Odoo
Friday, August 7, 2026
44 changes · saas-19.3
Resolved issues and error corrections
Changing a payslip to a payroll structure that does not use worked day lines now clears old worked day entries correctly, preventing inaccurate payslip data. Belgian payroll reporting was also adjusted so off-cycle payslips without worked days are still included correctly in DMFA remuneration calculations.
Original PR description
hr_payroll: Previously, changing to a structure with `use_worked_day_lines = False` (e.g., 13th month) caused `valid_slips` to be empty and return early, leaving stale worked day lines on the payslip. This commit resets the worked_days_lines before filtering for valid payslips. l10n_be_hr_payroll: After fixing the payroll bug and clearing worked_days_lines correctly, the DMFA report fails to correctly consider remunerations since the off-cycle payslips do not have worked_days_lines anymore. This commit backports a fix from odoo/enterprise#106689 to not skip remunerations for payslips with no worked days lines. task-6401942 Forward-Port-Of: odoo/enterprise#124986
Timesheet assistant suggestions now use the intended duration provided by each event instead of estimating it from start and end times. This ensures planning shifts suggest the allocated working hours, while calendar events continue to use their own duration, reducing incorrect timesheet entries.
Original PR description
*_: project_timesheet_forecast, timesheet_grid, timesheet_grid_calendar Previously, the timesheet assistant derived suggested entry durations from an event's start and stop datetimes. This worked for calendar events but produced incorrect suggestions for planning shifts whenever the allocated working hours differed from the overall scheduled time window. This commit introduces an explicit ``duration`` field in assistant events and updates all providers to supply it. Planning slots now use their allocated hours as the event duration, while calendar events expose their existing duration value. The assistant now consistently relies on this field instead of computing the duration from the event time range. As a result, suggested timesheet durations accurately reflect the intended working time for both planning shifts and calendar events. task-6366593 Forward-Port-Of: odoo/enterprise#126865 Forward-Port-Of: odoo/enterprise#125108
This fix prevents Instagram post synchronization from failing when a post does not include a media URL. Users can open Social Marketing and let auto-sync run without seeing an error caused by missing Instagram media links.
Original PR description
The fix introduced in https://github.com/odoo/enterprise/commit/9e9c99712ad4b9d58dc7601da41a852e457ad097 didn't account for the fact that `post.get('media_url') ` could return a None value, which in…
The fix introduced in https://github.com/odoo/enterprise/commit/9e9c99712ad4b9d58dc7601da41a852e457ad097 didn't account for the fact that `post.get('media_url') ` could return a None value, which in turn would raise en error when trying to concatenate the value later.
This in turn:
- will block syncing of instagram instagram posts
- will raise a traceback when you open the Social Marketing module and the auto-sync kicks in.
### Example traceback
```
Traceback (most recent call last):
[...]
File "/home/odoo/src/enterprise/saas-19.2/social_instagram/models/social_stream.py", line 86, in _fetch_stream_data
return self._fetch_instagram_posts()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/saas-19.2/social_instagram/models/social_stream.py", line 64, in _fetch_instagram_posts
values['message'] = (values['message'] + "\n" + post.get('media_url')).strip()
~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
TypeError: can only concatenate str (not "NoneType") to str
```
### Solution:
Fallback to an empty string if `post.get('media_url')` yields a None value.
OPW-6449357
Forward-Port-Of: odoo/enterprise#127049
Forward-Port-Of: odoo/enterprise#126987Google Reserve availability responses now prevent open spots from exceeding total spots, even when appointment settings are configured inconsistently. This avoids sending confusing or invalid availability data in rare edge cases.
Original PR description
This commit makes sure that we never send more "spots_open" than there are "spots_total" when Google Reserve asks for availabilities. This could happen in very rare case when customers create configurations that do not make sense (for example a table of 6 but no management of capacities and configuring 125 spots per resource). Task-6449615 Forward-Port-Of: odoo/enterprise#126855
Dutch SBR tax return exports now use the Tax Unit VAT number when a tax unit is selected, instead of incorrectly using the company’s Omzetbelastingnummer. This prevents rejected filings for companies reporting as part of a fiscal unity while keeping the company-level number for standalone company returns.
Original PR description
**Steps to reproduce:** * Install the **Netherlands - SBR** (`l10n_nl_reports_sbr`) and **Netherlands - SBR OB Nummer** (`l10n_nl_reports_sbr_ob_nummer`) modules. * Create two companies with Dutch…
**Steps to reproduce:** * Install the **Netherlands - SBR** (`l10n_nl_reports_sbr`) and **Netherlands - SBR OB Nummer** (`l10n_nl_reports_sbr_ob_nummer`) modules. * Create two companies with Dutch localization. * Go to **Accounting → Configuration → Tax Units** and create a Tax Unit with its own **Tax ID** (e.g. `NL826317558B01`), adding both companies. * On the main company form, fill in the **Omzetbelastingnummer** field (e.g. `123456782B90`). * Go to **Accounting → Reporting → Tax Return**, select the Tax Unit in the filter, and click **XBRL → Download XBRL File**. **Observed behavior:** * The `<xbrli:identifier>` in the exported XBRL file contains the company's **Omzetbelastingnummer** (`123456782B90`) instead of the Tax Unit's VAT (`826317558B01`). * The tax authority rejects the return because the identifier does not match the fiscal unity registration. **Cause:** * `_get_sbr_identifier()` in `l10n_nl_reports_sbr_ob_nummer` unconditionally returns `self.env.company.l10n_nl_reports_sbr_ob_nummer` before consulting the Tax Unit. * The `super()` call, which correctly routes to `tax_unit.vat` via `report.get_vat_for_export()`, is only reached when the company field is empty — so the Tax Unit's VAT is never used when a company OB-number is set. **Fix:** * When a Tax Unit is active in the report options, delegate immediately to `super()._get_sbr_identifier()`, which resolves `tax_unit.vat` through the existing `get_vat_for_export()` logic. * The company-level `l10n_nl_reports_sbr_ob_nummer` override is preserved as a fallback for the `company_only` (no Tax Unit) case. opw-6350840 Forward-Port-Of: odoo/enterprise#126999 Forward-Port-Of: odoo/enterprise#125167
This fixes an issue where payroll payment reports could fail around midnight when the server and user time zones calculated dates differently. Payroll date defaults are now calculated consistently across affected country payroll modules, reducing false payment date errors in automated runs and user workflows.
Original PR description
### Steps to reproduce: - Set the environment timezone (`env.tz`) to a timezone ahead of UTC (e.g., Europe/Brussels) - Run the enterprise tests (L10n standalone, Single app, or Multi l10n) during the…
### Steps to reproduce: - Set the environment timezone (`env.tz`) to a timezone ahead of UTC (e.g., Europe/Brussels) - Run the enterprise tests (L10n standalone, Single app, or Multi l10n) during the late evening in UTC (e.g., 23:00 UTC) > UserError: The Payment Date cannot be later than the Value Date, please make sure that the correct dates are set ### Cause of Issue: In the payroll payment report wizards, a race condition occurs around midnight due to mismatched timezone context evaluations between different date fields. The `effective_date` field (defined in the base hr_payroll module) derives its default value using `fields.Date.context_today`, which correctly applies the client's timezone offset to the current server time. https://github.com/odoo/enterprise/blob/54b7035b4cb6b9427092a3eebe73f2bee7f2ae09/hr_payroll/wizard/hr_payroll_payment_report_wizard.py#L23-L26 However, `l10n_sa_wps_value_date` (and similar date fields in other localizations like AU, HK, AE) derives its default value using `fields.Date.today()`, which strictly relies on the server's UTC time. https://github.com/odoo/enterprise/blob/54b7035b4cb6b9427092a3eebe73f2bee7f2ae09/l10n_sa_hr_payroll/wizard/hr_payroll_payment_report_wizard.py#L13-L14 When the nightly Runbot builds execute late at night UTC time, the environment timezone frequently crosses midnight into "tomorrow" while the server time is still on "today". Because of this offset, `effective_date` rolls over to tomorrow, but `l10n_sa_wps_value_date` evaluates as today + 1 day (which is also tomorrow). The validation check `effective_date >= l10n_sa_wps_value_date` evaluates to True. https://github.com/odoo/enterprise/blob/54b7035b4cb6b9427092a3eebe73f2bee7f2ae09/l10n_sa_hr_payroll/wizard/hr_payroll_payment_report_wizard.py#L93-L94 ### Fix: Standardize the default date computations to ensure they are all evaluated within the same timezone context and prevent the midnight timezone rollover discrepancy. runbot-937793 Forward-Port-Of: odoo/enterprise#126718 Forward-Port-Of: odoo/enterprise#125364
This fix ensures payroll worked day calculations consider inactive or archived employee contract versions when needed. It helps prevent missing or incorrect payslip work day entries in cases involving archived payroll data.
Original PR description
Forward-Port-Of: odoo/enterprise#114877
Bulk product imports could fail when changing subscription billing settings because a required helper was missing. This fix restores that missing logic so subscription-related product updates can complete reliably.
Original PR description
The port https://github.com/odoo/enterprise/commit/68640b5bddf51a8cbf58d3af3628cd4b57e08913 added a call to self._get_confirmed_order_lines() in product.template.write() (on import, when recurring_invoice changes), but the helper itself was never ported to 19.0. Importing products in bulk then fails with AttributeError: 'product.template' object has no attribute '_get_confirmed_order_lines'. Restores the method from master (PR https://github.com/odoo/enterprise/pull/117046) at the end of the ProductTemplate class. Forward-Port-Of: odoo/enterprise#122745 Forward-Port-Of: odoo/enterprise#122146
Fixed an issue in the timesheet grid where using Ctrl-click on a suggestion opened a new browser window instead of adding the suggestion to the form. This prevents accidental navigation and makes entering timesheets more reliable for users who use keyboard shortcuts.
Original PR description
Currently, when a user use ctrl + click on a suggestion, instead of adding it to the view form, it opens a new window. This is due to the default behavior when ctrl+click is used on a link. Using a button instead of an a href="#" solves this issue. Forward-Port-Of: odoo/enterprise#126240
Automatic fields in salary contract and signing documents now keep valid zero or numeric values instead of replacing them with blanks. Decimal values are also rounded properly, improving accuracy in generated documents.
Original PR description
Before this commit, falsy values were always set to '' even when they corresponded to numbers. Moreover, floats values were not rounded. Forward-Port-Of: odoo/enterprise#121640
Legal PDFs for Uruguayan electronic delivery guides now correctly add a separate addenda page when the notes are too long for the standard box. This prevents important delivery information from being omitted in printed legal documents.
Original PR description
**Description** When printing the legal PDF of a CFE, the report can request a dedicated addenda page (`adenda=true` report parameter) when the addenda does not fit in the small box of the standard…
**Description** When printing the legal PDF of a CFE, the report can request a dedicated addenda page (`adenda=true` report parameter) when the addenda does not fit in the small box of the standard report (roughly 6 lines of 140 characters). `l10n_uy_edi_document._get_report_params()` computed the addenda by calling `self.move_id._l10n_uy_edi_get_addenda()` directly. For e-remito EDI documents created from stock pickings, `move_id` is not set, so the addenda was always empty and the dedicated addenda page was never requested for delivery guides. **Changes** - Resolve the addenda from the document origin record: reuse the existing `_get_origin_record()` abstraction. Add it on `l10n_uy_edi.document` (returns the move) and let `l10n_uy_edi_stock` extend it to fall back to `picking_id`; `_get_report_params()` now reads the addenda through it. - Remove a no-op `_get_pdf()` override in `l10n_uy_edi_stock`. - Add a unit test covering the dedicated addenda page threshold (6 lines x 140 chars) for delivery guides. **Note** This PR replaces branch `adhoc-dev:18.0-t-stock-edi-addenda-fix-kz` (original authorship preserved); resubmitted from a new branch to keep follow-up and tracking with the current maintainer. Forward-Port-Of: odoo/enterprise#124539
The payroll payslip and pay run lists now always show the warnings column instead of hiding it behind an optional menu with a blank label. This removes a confusing interface issue and makes payroll warnings easier for users to notice.
Original PR description
Currently, in the payslip and payrun view, we can see empty label in optional dropdown. Having empty label isn't UX friendly. This empty label is refered to payslip warnings. In this PR expected to change visibility of warning fields, The visibility must be always visible and the field is no longer optional. This condition applies to PayRun and Paylist ListViews. task-6424657 Forward-Port-Of: odoo/enterprise#125860
The accounting reconciliation flow now correctly shows the "to review" button after actions such as setting an account, using reconciliation models, or handling payable and receivable items. This helps users consistently flag entries for review and reduces missed follow-up during bank statement reconciliation.
Original PR description
This commit will allow to have the "to review" button when using different action: - Set account - Reco model - Payable and receivable task-6409437
A display issue in the Timesheet leaderboard has been fixed so users can now see the intended helpful tip. This improves guidance for employees using timesheets without changing their workflow.
Original PR description
The tip inside the timesheet leaderboard was never visible due to incorrect function arguments assignment. This commit fixes the issue. task-6448478 Forward-Port-Of: odoo/enterprise#126792
Users can now regain access to shared Documents folders when they are re-invited after a previous invitation expired. This prevents a misleading success message where access appeared to be granted but the person or group still could not access the folder.
Original PR description
Sharing a folder with a portal user with an expiration date cannot be done again after the access has expired. The sharing dialog reports success, but the user does not get access and is no longer…
Sharing a folder with a portal user with an expiration date cannot be done again after the access has expired. The sharing dialog reports success, but the user does not get access and is no longer listed. ### Steps to reproduce - In Documents, share a folder with a portal user and set an expiration date. - Wait until the expiration date has passed. - Share the same folder with the same user again from the invite box. => The dialog says the member was added, but the user has no access and does not appear under "People with access". ### Cause The invite box has no expiration field. When re-inviting a user, it updates the existing `documents.access` record and passes `None` for the expiration, which keeps the old `expiration_date`. If that date is already in the past, the user remains expired even though the invite reports success. ### Fix Pass `False` instead of `None` when inviting a member so the existing record's expiration date is cleared. Re-inviting an expired user now restores access. Setting an expiration from the "People with access" list is unchanged. opw-6387559 Forward-Port-Of: odoo/enterprise#127050 Forward-Port-Of: odoo/enterprise#125140
Dutch VAT correction filings are now sent with the correct OBSUP message type instead of being treated as regular VAT reports. This prevents routing errors when submitting corrections through Digipoort and helps ensure amended VAT filings reach the right destination.
Original PR description
Description of the issue this commit addresses: VAT corrections are sent to Digipoort as regular VAT reports, causing routing errors. --- Desired behavior after this commit is merged: This commit sends VAT corrections using the OBSUP message type. --- opw-6353166 Forward-Port-Of: odoo/enterprise#127235
This update fixes an issue where a specific Swiss payroll value was not being properly recorded during ELM transmission processing. This helps ensure payroll transmission logs are more complete and reliable for audit and troubleshooting purposes.
Original PR description
Forward-Port-Of: odoo/enterprise#127241
Issue: The `shape_color_sync_with_theme_color` tour failed randomly at its last step i.e after changing a theme preset color, the image shapes of the saved (custom) snippet sometimes still had the old color. This happened because `updateContent` called its callback without awaiting it, so the re-processing of the custom snippet images ran in the background after the color change operation had already completed. At normal flow this operation finishes before the previews are looked at, but
Original PR description
Issue: The `shape_color_sync_with_theme_color` tour failed randomly at its last step i.e after changing a theme preset color, the image shapes of the saved (custom) snippet sometimes still had the old color. This happened because `updateContent` called its callback without awaiting it, so the re-processing of the custom snippet images ran in the background after the color change operation had already completed. At normal flow this operation finishes before the previews are looked at, but the tour reaches the `Custom` snippets category within milliseconds and could assert the colors before the re-processing was done - making the outcome depend purely on timing. Fix: Awaiting the callback ensures the custom snippets content is fully updated before the operation completes, so by the time the loading indicator disappears the previews are guaranteed to be in sync. runbot-[944175](https://runbot.odoo.com/odoo/error/944175) Forward-Port-Of: odoo/odoo#276862
Before this PR, the tour could fail non-deterministically because it waited for `o_we_ui_loading` to disappear. However, this class was added with a delay in `operation.js` file, allowing the next tour step to run before the loader was shown. After this PR, the tour waits for `o_loading_screen`, which is added immediately and remains until the operation finishes. This ensures the tour waits correctly before proceeding. runbot-[941508](https://runbot.odoo.com/odoo/error/941508) Forward-Por
Original PR description
Before this PR, the tour could fail non-deterministically because it waited for `o_we_ui_loading` to disappear. However, this class was added with a delay in `operation.js` file, allowing the next tour step to run before the loader was shown. After this PR, the tour waits for `o_loading_screen`, which is added immediately and remains until the operation finishes. This ensures the tour waits correctly before proceeding. runbot-[941508](https://runbot.odoo.com/odoo/error/941508) Forward-Port-Of: odoo/odoo#277869 Forward-Port-Of: odoo/odoo#277651
[*] = html_builder Steps to reproduce: 1. Go to the Website app and drop any snippet. 2. Apply a background or image shape. 3. If a background shape is applied, click the **Flip Shape** option. 4. Go to the **Theme** tab and change the color palette. Issue: The shape color is not updated after changing the color palette. Reason: In the [commit](https://github.com/odoo/odoo/commit/aec8918018b92cbb5cb3dd761824d4), an edge case was left uncovered where applied background/image shap
Original PR description
[*] = html_builder Steps to reproduce: 1. Go to the Website app and drop any snippet. 2. Apply a background or image shape. 3. If a background shape is applied, click the **Flip Shape** option. 4. Go to the **Theme** tab and change the color palette. Issue: The shape color is not updated after changing the color palette. Reason: In the [commit](https://github.com/odoo/odoo/commit/aec8918018b92cbb5cb3dd761824d4), an edge case was left uncovered where applied background/image shapes were not re-rendered after changing the theme color palette, so its color was not refreshed to match newly selected palette. Forward-Port-Of: odoo/odoo#278325 Forward-Port-Of: odoo/odoo#273337
### Current behavior: When exporting a quotation PDF from the Sales Order a multi-word product name, e.g. "Pick Up", is split into 2 lines ### Expected behavior: When exporting a quotation PDF from the Sales Order a multi-word product name, e.g. "Pick Up", should stay on a single line when there is enough horizontal space in the Description column ### Steps to reproduce: 1. Sales > new Sales Order 2. Add a product whose name has at least two words, e.g. "Pick Up" 3. Export the Sales O
Original PR description
### Current behavior: When exporting a quotation PDF from the Sales Order a multi-word product name, e.g. "Pick Up", is split into 2 lines ### Expected behavior: When exporting a quotation PDF from…
### Current behavior: When exporting a quotation PDF from the Sales Order a multi-word product name, e.g. "Pick Up", is split into 2 lines ### Expected behavior: When exporting a quotation PDF from the Sales Order a multi-word product name, e.g. "Pick Up", should stay on a single line when there is enough horizontal space in the Description column ### Steps to reproduce: 1. Sales > new Sales Order 2. Add a product whose name has at least two words, e.g. "Pick Up" 3. Export the Sales Order report to PDF 4. Observe the second word is pushed to a new line, even with free horizontal space ### Cause of the issue: Commit https://github.com/odoo/odoo/commit/6d695e53743a58560a00c163b3ac16ee1f149761 added a `d-flex` in 19.3 to keep product image and name on the same line. The `o_product_name_cell` uses default shrink wrap. Under wkhtmltopdf's old QtWebKit engine the shrink-wrapped width is computed marginally short of the real text width; this margin is font-metric dependent, so with the slightly wider font like Open Sans the last word crosses the boundary and wraps onto a new line, even though the surrounding cell has room. ### Fix: - Add the Bootstrap `flex-grow-1` utility class to the o_product_name_cell div so it grows to fill the remaining width of the flex row - The image keeps its fixed 48px width and stays on the same line - Small UI change, so no unit test. Only manual test: Before: <img width="357" height="211" alt="image" src="https://github.com/user-attachments/assets/29458867-c7d0-4cc8-8397-4c97b7a2b91d" /> After: <img width="342" height="196" alt="image" src="https://github.com/user-attachments/assets/9a1ca99c-916f-4179-b9b9-67879885e9d8" /> opw-6434410
Task-6429727 Forward-Port-Of: odoo/odoo#280446 Forward-Port-Of: odoo/odoo#279204
Original PR description
Task-6429727 Forward-Port-Of: odoo/odoo#280446 Forward-Port-Of: odoo/odoo#279204
Before this commit, this test was sometimes failing. `edit("...")` validates the value by default (i.e. is followed by enter). It may happen that the dropdown is already open when doing so, and in this case, the first value is selected. However, it may often happen that it isn't open yet, so nothing happens. To turn tests more robust, we typically turn off the auto confirm and call runAllTimers() to ensure the dropdown is open, then select the value. That's also what we did here. runbot er
Original PR description
Before this commit, this test was sometimes failing. `edit("...")` validates the value by default (i.e. is followed by enter). It may happen that the dropdown is already open when doing so, and in this case, the first value is selected. However, it may often happen that it isn't open yet, so nothing happens.
To turn tests more robust, we typically turn off the auto confirm and call runAllTimers() to ensure the dropdown is open, then select the value. That's also what we did here.
runbot error-944120
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#280384Since https://github.com/odoo/odoo/pull/239898 Opening a livechat session in debug mode as a user without livechat access throws a traceback: `Invalid props for component BadgeTag: onDelete is not a function` This happens because `null` is passed to the `onDelete` prop, while the component validation expects a function. This commit fixes the issue. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280910 Forward-Por
Original PR description
Since https://github.com/odoo/odoo/pull/239898 Opening a livechat session in debug mode as a user without livechat access throws a traceback: `Invalid props for component BadgeTag: onDelete is not a function` This happens because `null` is passed to the `onDelete` prop, while the component validation expects a function. This commit fixes the issue. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280910 Forward-Port-Of: odoo/odoo#280679
During the forward port of #278378, the dynamic NSI file path variable was overwritten by an old hardcoded one, breaking the IoT package build. Forward-Port-Of: odoo/odoo#280885
Original PR description
During the forward port of #278378, the dynamic NSI file path variable was overwritten by an old hardcoded one, breaking the IoT package build. Forward-Port-Of: odoo/odoo#280885
A `product.pricelist.item` targeting a product or a template that is not loaded in the PoS was applied to every product of the session. `computeRuleIndexes` deduced which kind of rule an item was from the many2one that resolved to a live record. That getter returns `undefined` when the targeted record is not in the local store, so such an item fell through every branch and ended up in the global rules, overriding the price of unrelated products. The targeted record is legitimately absent i
Original PR description
A `product.pricelist.item` targeting a product or a template that is not loaded in the PoS was applied to every product of the session. `computeRuleIndexes` deduced which kind of rule an item was from the many2one that resolved to a live record. That getter returns `undefined` when the targeted record is not in the local store, so such an item fell through every branch and ended up in the global rules, overriding the price of unrelated products. The targeted record is legitimately absent in two cases: the product was archived and removed by `filter_local_data` while the rule itself was kept, and, on an incremental reload, the item domain drops its product and category filters, so items of products that were never loaded in this PoS might be sent to the client. opw-6344491 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280742 Forward-Port-Of: odoo/odoo#279491
Before this commit, it was possible that get_limited_partners_loading returned a partner if a module that overrode the method was installed. runbot-944636 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280800 Forward-Port-Of: odoo/odoo#280628
Original PR description
Before this commit, it was possible that get_limited_partners_loading returned a partner if a module that overrode the method was installed. runbot-944636 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280800 Forward-Port-Of: odoo/odoo#280628
### Steps to reproduce: - Create 3 AVCO products: Super Kit, Kit, Comp - Super Kit BoM: 2 x Kit - Kit BoM: 1 x Comp - Create and confirm a purchase order for 1 X Super Kit at 100 - Validate the receipt of 2 Comp - Go to the valuation > Both units of Comp are valued at 100 for a total of 200 ### Cause of the issue: The issue has been introduced by: https://github.com/odoo/odoo/pull/158849/changes/713701a5035d342263e3fef2a2819b5696b6d063 To be more precise, the price unit of each u
Original PR description
### Steps to reproduce: - Create 3 AVCO products: Super Kit, Kit, Comp - Super Kit BoM: 2 x Kit - Kit BoM: 1 x Comp - Create and confirm a purchase order for 1 X Super Kit at 100 - Validate the…
### Steps to reproduce: - Create 3 AVCO products: Super Kit, Kit, Comp - Super Kit BoM: 2 x Kit - Kit BoM: 1 x Comp - Create and confirm a purchase order for 1 X Super Kit at 100 - Validate the receipt of 2 Comp - Go to the valuation > Both units of Comp are valued at 100 for a total of 200 ### Cause of the issue: The issue has been introduced by: https://github.com/odoo/odoo/pull/158849/changes/713701a5035d342263e3fef2a2819b5696b6d063 To be more precise, the price unit of each unit of Comp is expected to be computed by the `_get_price_unit`. This method used to rely on the `product_qty` appropriately: https://github.com/odoo/odoo/pull/158849/changes/713701a5035d342263e3fef2a2819b5696b6d063#diff-687527af1723e60816358020c4d83687479df62ca0cfd71079f0a82afb4b3efeL27 However, backorder adapt the move demand and hence did not provide the appropriate demand in this flow that computation logic was changed to rely on the `bom` and `bom_line` quantities: https://github.com/odoo/odoo/blob/29977a6a80442af49ecefa7fef54f085483d8f77/addons/purchase_mrp/models/stock_move.py#L20-L40 This new computation is not correct in case of nested boms since the `bom_line` only carries the unit demand on the last explosion stage. ### Additional issue: If nested kit boms lead to the creation of 2 moves with the same `cost_share` and `bom_line_id`, these moves will be merged without summing their `cost_share` leading to an under pricing of the kit since its related `stock_move`'s `cost_share` will not sum up to 100 percents anymore. This issue is tested in `test_avco_purchase_nested_kit_explode_cost_share_backorder_2` and fixed similarly to demand merging: https://github.com/odoo/odoo/blob/613f3cb7b2f4813ce6c8f53718a6cca841b081ad/addons/stock/models/stock_move.py#L1122-L1134 ### Note: We also modify the test `test_valuation_with_backorder` to be understandable and to make appropriate asserts. opw-6253776 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280744 Forward-Port-Of: odoo/odoo#276242
Currently, users encounter a traceback when attempting to print the traceability report for a manufacturing order. ## Steps to produce: - Install Manufacturing without demo data. - Enable Lots & Serial Numbers in Settings. - Create two products: Car and Engine. - Configure Engine to use Unique Serial Number tracking (Inventory →Traceability). - Set the on-hand quantity of Engine to 1 with serial number 0001. - Create a BoM for Car using Engine as a component. - Create and confirm a man
Original PR description
Currently, users encounter a traceback when attempting to print the traceability report for a manufacturing order. ## Steps to produce: - Install Manufacturing without demo data. - Enable Lots &…
Currently, users encounter a traceback when attempting to print the traceability report for a manufacturing order. ## Steps to produce: - Install Manufacturing without demo data. - Enable Lots & Serial Numbers in Settings. - Create two products: Car and Engine. - Configure Engine to use Unique Serial Number tracking (Inventory →Traceability). - Set the on-hand quantity of Engine to 1 with serial number 0001. - Create a BoM for Car using Engine as a component. - Create and confirm a manufacturing order for Car. - Click `Consumed` for the component and click Produce All. - Navigate to Lots & Serial Numbers → Engine → 0001 → Traceability. - Click the arrow next to the manufacturing order reference, then click Print. ## Observed Behavior: An `Arbitrary Uncaught Python Exception` traceback is raised, resulting in a 404 error. ## Root Cause: This issue occurs because, when the user clicks the arrow button in the traceability report, the template [1] invokes the `onClickUpDownStream` function. This function adds the URL `/stock/output_format/stock/active_id` to the context , as shown in [2]. Later, when the user clicks the Print button, `onClickPrint()` [3] constructs the print URL using the `controllerUrl` value by replacing the active model and active ID placeholders with values from the context. However, the URL stored in the context contains `/active_id` instead of `:active_id`. As a result, the placeholder replacement does not occur, leaving the URL unchanged. This causes the print action to use an invalid URL, ultimately resulting in a 404 error. As shown in [4], `controllerUrl` is assigned directly from the context. [1]: https://github.com/odoo/odoo/blob/a398ade607940a281552f8cba2c1cf80bb0e77f6/addons/stock/static/src/client_actions/stock_traceability_report_backend.xml#L52-L56 [2]: https://github.com/odoo/odoo/blob/a398ade607940a281552f8cba2c1cf80bb0e77f6/addons/stock/static/src/client_actions/stock_traceability_report_backend.js#L105-L118 [3]: https://github.com/odoo/odoo/blob/a398ade607940a281552f8cba2c1cf80bb0e77f6/addons/stock/static/src/client_actions/stock_traceability_report_backend.js#L120-L131 [4]: https://github.com/odoo/odoo/blob/a398ade607940a281552f8cba2c1cf80bb0e77f6/addons/stock/static/src/client_actions/stock_traceability_report_backend.js#L53-L55 ## Solution: Pass the correct URL in the context so that the active ID placeholder can be replaced correctly during the print action. This ensures that the generated print URL is valid, allowing the user to print the report without encountering any errors. opw-6372834 Forward-Port-Of: odoo/odoo#279844 Forward-Port-Of: odoo/odoo#276449
Sending marketing cards from an event can target the wrong event when the selected campaign was designed on a record belonging to another event. ### Steps to reproduce 1. Create a marketing card campaign on model "Event Track". Its "Preview On" record belongs to event A. 2. Open event B and click "Send Cards". 3. Select the campaign. The recipient domain initially targets event B, but after selecting the campaign it is rebuilt using event A from the preview record. The mailing there
Original PR description
Sending marketing cards from an event can target the wrong event when the selected campaign was designed on a record belonging to another event. ### Steps to reproduce 1. Create a marketing card…
Sending marketing cards from an event can target the wrong event when the selected campaign was designed on a record belonging to another event. ### Steps to reproduce 1. Create a marketing card campaign on model "Event Track". Its "Preview On" record belongs to event A. 2. Open event B and click "Send Cards". 3. Select the campaign. The recipient domain initially targets event B, but after selecting the campaign it is rebuilt using event A from the preview record. The mailing therefore sends cards to the wrong event. ### Cause "Send Cards" opens a `mailing.mailing` form. The event the action was started from is only stored in the context through `default_mailing_domain`; it is not stored on the mailing record. Selecting a campaign recomputes `mailing_domain`, which rebuilds it from the target model default domain, so the event the domain carried is lost. The current code then rebuilds the event restriction using `card_campaign_id.preview_record_ref.event_id`, but this record only represents the campaign preview. It does not represent the event the user is sending cards for, and campaigns can be reused across events. ### Fix Read the event out of the mailing domain before the super call rebuilds it, and restrict the rebuilt domain to that event. The event then stays with the mailing on any later recompute, without the caller having to pass it. When the domain restricts no event, which is the case when the mailing is created directly from a campaign, fall back to the preview record event. opw-6431427
Issue: The MyInvois payload computed `cbc:PrepaidAmount` as `amount_total - amount_residual`, treating every reconciled payment as a prepayment. A payment made on or after the invoice date is an ordinary settlement, not a deposit, but the code recognized it as one anyway. The values reported for `PrepaidAmount` were wrong regardless of the invoice date, and for a fully paid invoice this also collapsed `PayableAmount` to 0.00, which LHDN rejects. Root Cause: LHDN only considers a reconciled
Original PR description
Issue: The MyInvois payload computed `cbc:PrepaidAmount` as `amount_total - amount_residual`, treating every reconciled payment as a prepayment. A payment made on or after the invoice date is an…
Issue: The MyInvois payload computed `cbc:PrepaidAmount` as `amount_total - amount_residual`, treating every reconciled payment as a prepayment. A payment made on or after the invoice date is an ordinary settlement, not a deposit, but the code recognized it as one anyway. The values reported for `PrepaidAmount` were wrong regardless of the invoice date, and for a fully paid invoice this also collapsed `PayableAmount` to 0.00, which LHDN rejects. Root Cause: LHDN only considers a reconciled payment a genuine deposit if it was received before the invoice date. The code applied no date condition at all, so any payment reconciled against the invoice was added to `PrepaidAmount` and reduced `PayableAmount` accordingly. Fix: Only sum reconciled payment partials whose date is strictly earlier than the invoice date as prepaid, so regular payments are no longer misclassified as deposits. As a safety net, if the valid prepaid sum still covers the full invoice amount (e.g. a full advance payment), reset it to 0 so `PayableAmount` always reflects the full amount_total instead of being reported as 0. Also omit the `PrepaidPayment` node entirely when there is no genuine prepayment, rather than emitting it with a 0.00 amount. [Task-6404296](https://www.odoo.com/odoo/my-tasks/6404296) Forward-Port-Of: odoo/odoo#280569 Forward-Port-Of: odoo/odoo#278010
Steps to reproduce: - From the website editor, open the Theme tab. - Upload a custom font. - Open the media dialog and go to the "Documents" tab. Issue: The uploaded font files appeared in the Documents tab. When a zip file was uploaded, every font it contained appeared individually, along with the generated "CSS font face" attachment. Cause: Fonts uploaded through `/website/theme_upload_font` are created as public attachments. The Documents tab of the media dialog lists every public
Original PR description
Steps to reproduce: - From the website editor, open the Theme tab. - Upload a custom font. - Open the media dialog and go to the "Documents" tab. Issue: The uploaded font files appeared in the…
Steps to reproduce: - From the website editor, open the Theme tab. - Upload a custom font. - Open the media dialog and go to the "Documents" tab. Issue: The uploaded font files appeared in the Documents tab. When a zip file was uploaded, every font it contained appeared individually, along with the generated "CSS font face" attachment. Cause: Fonts uploaded through `/website/theme_upload_font` are created as public attachments. The Documents tab of the media dialog lists every public attachment that is not an image or an asset, so the font files (mimetype `font/...`), their font face declaration (mimetype `text/css`) and googleFontMetadata (server caches it as public attachment) were listed. Fix: Exclude those attachments from the Documents tab domain: - whose mimetype starts with `font/`, - whose description matches the font face declarations created in `snippets.options.js`. - whose name equals "googleFontMetadata". task-[4771523](https://www.odoo.com/odoo/project/974/tasks/4771523) Forward-Port-Of: odoo/odoo#280563 Forward-Port-Of: odoo/odoo#275838
Microsoft issues a new refresh token on every access token refresh (rolling 90-day sliding window). The previous code discarded it, causing users to be forced to re-authenticate every 90 days once the original token expired. Closes #253543 Forward-Port-Of: odoo/odoo#280535 Forward-Port-Of: odoo/odoo#268284
Original PR description
Microsoft issues a new refresh token on every access token refresh (rolling 90-day sliding window). The previous code discarded it, causing users to be forced to re-authenticate every 90 days once the original token expired. Closes #253543 Forward-Port-Of: odoo/odoo#280535 Forward-Port-Of: odoo/odoo#268284
**Steps to reproduce:** - Install l10n_pl_edi and enable Allow KSeF integration from **Accounting** settings. - Switch to a Polish company. - Create an EU customer with a valid VAT number. - Create a sale order containing a service product taxed with 0% Steel (or any tax that has a tag of K11). - Confirm the sale order and create a down payment invoice. - Send the invoice to KSeF and inspect the generated XML. **Observed behavior:** The generated KSeF XML does not contai
Original PR description
**Steps to reproduce:** - Install l10n_pl_edi and enable Allow KSeF integration from **Accounting** settings. - Switch to a Polish company. - Create an EU customer with a valid VAT number. - Create a…
**Steps to reproduce:** - Install l10n_pl_edi and enable Allow KSeF integration from **Accounting** settings. - Switch to a Polish company. - Create an EU customer with a valid VAT number. - Create a sale order containing a service product taxed with 0% Steel (or any tax that has a tag of K11). - Confirm the sale order and create a down payment invoice. - Send the invoice to KSeF and inspect the generated XML. **Observed behavior:** The generated KSeF XML does not contain the `P_13_8` field. **Cause:** For invoices involving the tax of tag `K11` (mainly these taxes are used for the supplies that are outside the territory of Poland), the value corresponding to `P_13_8` was not being assigned during XML generation, causing the tag to be omitted from the exported KSeF document. **Fix:** Populate the value of `P_13_8` during KSeF XML generation for invoices, ensuring the field is correctly included in the exported XML. This PR updates the computation of tag `P_13_10` with its test case to ensure consistency with the expected reporting logic, where the tag is computed solely from `K_31`. Here is the [Documentation](https://ksef.podatki.gov.pl/media/gtjhkeek/information-sheet-on-the-fa-3-logical-structure-04032026.pdf) link for the reference of the Ksef structure. **opw**-6294181 Forward-Port-Of: odoo/odoo#280830 Forward-Port-Of: odoo/odoo#276887
_track_finalize() can browse records into self that get dropped from trackings when _mail_track() raises MissingError (e.g. deleted mid-transaction), so indexing trackings[move.id] could KeyError. Iterate trackings.items() instead, since it's the authoritative set of records with tracking data. runbot-944656
Original PR description
_track_finalize() can browse records into self that get dropped from trackings when _mail_track() raises MissingError (e.g. deleted mid-transaction), so indexing trackings[move.id] could KeyError. Iterate trackings.items() instead, since it's the authoritative set of records with tracking data. runbot-944656
The getter `getLoadedDataSources` was filtering out datasources that are not 'ready' but they should actually filter out datasources that were already loaded (so ready) but invalid. Task: 6387729 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#279153 Forward-Port-Of: odoo/odoo#276255
Original PR description
The getter `getLoadedDataSources` was filtering out datasources that are not 'ready' but they should actually filter out datasources that were already loaded (so ready) but invalid. Task: 6387729 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#279153 Forward-Port-Of: odoo/odoo#276255
When there is no default confirmation template, An error is raised: AttributeError: 'bool' object has no attribute 'exists'. This happens because default_template is False, So calling default_template.exists() results in the error. The issue occurs during the upgrade process. ``` File "/home/odoo/src/odoo/19.0/odoo/orm/models.py", line 3142, in _init_column value = field.default(self) File "/home/odoo/src/odoo/19.0/addons/website_sale/models/website.py", line 52, in _default_confi
Original PR description
When there is no default confirmation template,
An error is raised:
AttributeError: 'bool' object has no attribute 'exists'. This happens because default_template is False,
So calling default_template.exists() results in the error. The issue occurs during the upgrade process.
```
File "/home/odoo/src/odoo/19.0/odoo/orm/models.py", line 3142, in _init_column
value = field.default(self)
File "/home/odoo/src/odoo/19.0/addons/website_sale/models/website.py", line 52, in _default_confirmation_email_template
if default_template.exists():
AttributeError: 'bool' object has no attribute 'exists'
```
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#240874
Forward-Port-Of: odoo/odoo#237686The test `editing s_popup, then closing it, then undo show it again` had a few fails in CI: the `fa-eye` was not set as expected. This commit adds a `waitSidebarUpdated` call just before to ensure owl has no pending rendering when checking the eye. runbot-242292 Forward-Port-Of: odoo/odoo#263490
Original PR description
The test `editing s_popup, then closing it, then undo show it again` had a few fails in CI: the `fa-eye` was not set as expected. This commit adds a `waitSidebarUpdated` call just before to ensure owl has no pending rendering when checking the eye. runbot-242292 Forward-Port-Of: odoo/odoo#263490
Currently, people can get infinite loop in the cron that fetches messages from the ppf, as we don't catch the exception that may happen. At least catch them, so we can send an ack opw-6440955 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281170
Original PR description
Currently, people can get infinite loop in the cron that fetches messages from the ppf, as we don't catch the exception that may happen. At least catch them, so we can send an ack opw-6440955 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281170
Sometimes the default_state remains in the context from a past action and when the subcontractor fills its components consumptions it will directly modify the quant's quantity. This trigger the automatic rules and generate an unwanted picking opw-6109661 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:
Original PR description
Sometimes the default_state remains in the context from a past action and when the subcontractor fills its components consumptions it will directly modify the quant's quantity. This trigger the automatic rules and generate an unwanted picking opw-6109661 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#280930 Forward-Port-Of: odoo/odoo#280733
This commit will remove the condition about the review state to place the move in to review. We want to place the move in the state "to_review" as soon as a user with not enough access right modify the move. task-6409437 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
This commit will remove the condition about the review state to place the move in to review. We want to place the move in the state "to_review" as soon as a user with not enough access right modify the move. task-6409437 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
**Steps to reproduce:** 1. Install Accounting and l10n_be and switch to the Belgian company 2. In the settings, set the discount account (`708000`) on Customer Invoices under "Default Accounts" and enable analytic accounting 3. Go to [Accounting -> Configuration -> Analytic Accounts] and create 4 new accounts with "Project" plan (i.e 1,2,3,4) 4. Create a new invoice with two lines, each having 2 of the analytic accounts with 50% each. 5. Set the price to 1000 and a 10% discount for each lin
Original PR description
**Steps to reproduce:** 1. Install Accounting and l10n_be and switch to the Belgian company 2. In the settings, set the discount account (`708000`) on Customer Invoices under "Default Accounts" and…
**Steps to reproduce:** 1. Install Accounting and l10n_be and switch to the Belgian company 2. In the settings, set the discount account (`708000`) on Customer Invoices under "Default Accounts" and enable analytic accounting 3. Go to [Accounting -> Configuration -> Analytic Accounts] and create 4 new accounts with "Project" plan (i.e 1,2,3,4) 4. Create a new invoice with two lines, each having 2 of the analytic accounts with 50% each. 5. Set the price to 1000 and a 10% discount for each line then save. 6. Edit the second line and set the discount to 20%. 7. Open the Journal Items tab **Issue:** - When an invoice contains multiple lines with analytic distributions, changing the discount percentage on any line other than the first fails to correctly update the analytic distribution percentages on the corresponding discount journal items. - The analytic account distribution splits the percentage evenly across both accounts event if they are not split 50/50 **Why this happens:** - This occurred because `_compute_discount_allocation_needed` iterated over `self` to populate target changes. When only one line was modified, `self` contains that line only which is correctly updated with the new analytic distribution. Later in the execution in `_sync_dynamic_line`, particularly in https://github.com/odoo/odoo/blob/5a14360705a55f4d91edf39c936d7a5d8573044b/addons/account/models/account_move.py#L2263-L2274 The first line in `computed_needed` is what gets set in res, and subsequent lines only modify the field if it's monetary. So if the second invoice line is the one updated, it will never override the `analytic_distribution` with the updated values, leaving stale values in that field. - The code iterated directly over `line.analytic_distribution` dictionary keys (the account IDs) rather than its `.items()`. This caused it to ignore the individual percentage value splits (e.g. 60/40), accumulating the un-weighted full discount amount to each account ID. https://github.com/odoo/odoo/blob/5a14360705a55f4d91edf39c936d7a5d8573044b/addons/account/models/account_move_line.py#L1044-L1052 **Fix:** - Change the processing loop inside `_compute_discount_allocation_needed` from `self` to `self.move_id.line_ids` to calculate the correct `analytic_distribution` across all records. - Applying the factored weight ratio (`amount * (percentage / 100.0)`) to `distribution_totals` opw-6362084 Forward-Port-Of: odoo/odoo#280302 Forward-Port-Of: odoo/odoo#275070
### Issue before this commit: When generating ZUGFeRD or Factur-X electronic invoices, including an HTML hyperlink (such as an email or website) in the document layout caused the final PDF to fail PDF/A validation. Portals would reject the file with the error: "An annotation dictionary does not contain the key F". ### Steps to reproduce the issue: 1. Download Accounting and l10n_de 2. Go to Contacts > set Tax ID for company Bloem GmbH and also for DE company 3. Activate ZUGFeRD from setti
Original PR description
### Issue before this commit: When generating ZUGFeRD or Factur-X electronic invoices, including an HTML hyperlink (such as an email or website) in the document layout caused the final PDF to fail…
### Issue before this commit: When generating ZUGFeRD or Factur-X electronic invoices, including an HTML hyperlink (such as an email or website) in the document layout caused the final PDF to fail PDF/A validation. Portals would reject the file with the error: "An annotation dictionary does not contain the key F". ### Steps to reproduce the issue: 1. Download Accounting and l10n_de 2. Go to Contacts > set Tax ID for company Bloem GmbH and also for DE company 3. Activate ZUGFeRD from settings 4. Go to settings and click on Configure Document Layout and insert something like <a href="mailto:info@company.de_skr03example.com"> info@company.de_skr03example.com</a> into the footer 5. Create an invoice to Bloem GmbH and send it through ZUGFeRD 6. Download PDF and upload it on https://www.portinvoice.com/ 7. See error: An annotation dictionary does not contain the key F. With the exception of annotation dictionaries whose subtype value is Popup, all annotation dictionaries must contain the key F. ### Cause of the issue: The underlying PDF generation engine creates hyperlinks as PDF annotations but omits the /F (Flags) key. During Odoo's PDF/A conversion process, these annotations were left unmodified. This violates the strict PDF/A specification, which mandates that all non-Popup annotations must explicitly define the /F key. ### Reason to introduce the fix: This fix ensures full PDF/A compliance by iterating through all page annotations and injecting the missing /F key for any annotation that is not a Popup. This allows users to safely include clickable links in their invoice templates without breaking electronic document validation. opw-6388212 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279024
In _validate_amount(), setting a "Percentage of balance" line to 0 raises "Statement line percentage can't be 0", and setting a "Percentage of statement line" to 0 raises "Balance percentage can't be 0". Align each error message with the amount type being validated. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280399 Forward-Port-Of: odoo/odoo#269393
Original PR description
In _validate_amount(), setting a "Percentage of balance" line to 0 raises "Statement line percentage can't be 0", and setting a "Percentage of statement line" to 0 raises "Balance percentage can't be 0". Align each error message with the amount type being validated. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280399 Forward-Port-Of: odoo/odoo#269393