Daily updates from Odoo
Friday, July 24, 2026
322 changes
3 changes
Resolved issues and error corrections
### Issue before this commit: Sending a TicketBAI invoice to a customer with a Spanish address and a VAT number starting with 'N' (Non-resident entity) resulted in a rejection with error B4_2000027. The XML incorrectly generated the national <DesgloseFactura> tag instead of the required <DesgloseTipoOperacion> tag. ### Steps to reproduce the issue: 1. Download Accounting, l10n_es and l10n_es_edi_tbai 2. Change name to ES Company into “NOMBRE APELLIDOUNO APELLIDODOS” (this is to make sure t
Original PR description
### Issue before this commit: Sending a TicketBAI invoice to a customer with a Spanish address and a VAT number starting with 'N' (Non-resident entity) resulted in a rejection with error B4_2000027.…
### Issue before this commit: Sending a TicketBAI invoice to a customer with a Spanish address and a VAT number starting with 'N' (Non-resident entity) resulted in a rejection with error B4_2000027. The XML incorrectly generated the national <DesgloseFactura> tag instead of the required <DesgloseTipoOperacion> tag. ### Steps to reproduce the issue: 1. Download Accounting, l10n_es and l10n_es_edi_tbai 2. Change name to ES Company into “NOMBRE APELLIDOUNO APELLIDODOS” (this is to make sure the certificate for Ticketbai works) 3. Go to Settings → Spain Localization → set Tax Agency for = Bizkaia 4. Change VAT number for customer Mulhacén Digital S.L. into N0011452J (must be a foreign entity ID) 5. Go to Settings > Technical > System Parameters and set the parameter 'l10n_es_edi_tbai.epigrafe' to 165360 6. Create a new invoice for that client and try to send it to TicketBAI 7. Error: B4_1000002: Todos los registros incluidos en la petición son incorrectos. B4_2000027: La factura contiene un Tipo de desglose incorrecto. Ha de ser a nivel de operación cuando la factura es completa y, además, existe destinatario extranjero (tipo IDOtro o que sea NIF que empiece por N) o la Clave de IVA es 02. ### Cause of the issue: The _l10n_es_is_foreign() method evaluated these customers as domestic because their country was set to Spain and their VAT did not start with "ESN". It failed to recognize a standalone "N" prefix as a valid foreign identifier. https://github.com/odoo/odoo/blob/75ae45861e2f417aa2b90bdb2b2869718e091c09/addons/l10n_es/models/res_partner.py#L7-L10 ### Reason to introduce the fix: Adding the 'N' prefix to the _l10n_es_is_foreign() check ensures the system correctly treats these entities as foreign for tax purposes. This generates the correct XML structure automatically, without forcing users to unnaturally prepend "ES" to a legally valid NIF. opw-6326359 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277816 Forward-Port-Of: odoo/odoo#275231
Issue: - After confirming a sale order with a reward applied (e.g. an ewallet reward), unlocking it, and editing it so the reward line's cost changes (e.g. adding a product and re-claiming the reward), the coupon's point balance updates correctly. - However, the corresponding loyalty.history record's used value is never refreshed, so it keeps showing the old cost instead of the new one. Steps to reproduce: - Enable Loyalty and Lock Confirmed Sales in Sales settings. - Create an ewallet ty
Original PR description
Issue: - After confirming a sale order with a reward applied (e.g. an ewallet reward), unlocking it, and editing it so the reward line's cost changes (e.g. adding a product and re-claiming the…
Issue: - After confirming a sale order with a reward applied (e.g. an ewallet reward), unlocking it, and editing it so the reward line's cost changes (e.g. adding a product and re-claiming the reward), the coupon's point balance updates correctly. - However, the corresponding loyalty.history record's used value is never refreshed, so it keeps showing the old cost instead of the new one. Steps to reproduce: - Enable Loyalty and Lock Confirmed Sales in Sales settings. - Create an ewallet type loyalty.program and generate an ewallet for a partner with e.g. 1000 points. - Create a sale order for that partner, add a product worth 100, and claim the ewallet reward (reward line created with points_cost = 100). - Confirm the order. loyalty.history shows used = 100 (correct), card balance shows 900 (correct). - Unlock the order, add a second product worth 100, and claim the reward again (same reward line updates to points_cost = 200). - Lock the order again. - Check the loyalty.card: balance is correctly 800. - Check loyalty.history for that order: used still shows 100 instead of 200. Fix: - Updated _update_loyalty_history() in sale_order.py to create a new history line if none exists for the given card and order combination. - Updated write() in sale_order_line.py to correctly sync history lines when a reward line is modified on a confirmed order, handling both same-coupon updates via delta and coupon changes by subtracting the old coupon cost and adding the new one separately. - Added test_loyalty_history_created_on_post_confirm_reward to verify that a history line is created when a reward is claimed on a confirmed order where no history line existed before. - Added test_loyalty_history_updated_on_points_cost_write to verify that history.used is updated by the correct delta when points_cost changes on a reward line of a confirmed order. Impact: - Ensures a coupon's usage history stays accurate after a confirmed order is unlocked and edited. - Prevents the loyalty.history used field from silently going stale while the actual point balance is correct. - Not scoped to ewallet specifically — since points_cost semantics are the same across program types, this also corrects the same class of staleness for other reward types (discount, gift_card, etc.) when a reward line's cost changes post-confirmation. Forward-Port-Of: odoo/odoo#277450 Forward-Port-Of: odoo/odoo#273688
Documentation and clarification updates
Signing the Odoo Individual Contributor License Agreement v1.0. Adds `doc/cla/individual/dsonnet.md`. --- I confirm I have read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270526
Original PR description
Signing the Odoo Individual Contributor License Agreement v1.0. Adds `doc/cla/individual/dsonnet.md`. --- I confirm I have read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270526
3 changes
Resolved issues and error corrections
The test read the field content for the last urgent save right after resolving modifyImagePromise, without waiting for the DOM to actually reflect the new image src. This raced the async update of the editable content, so beforeUnload sometimes ran before the image src were updated, sending stale content and failing intermittently. Wait for the updated image to appear in the DOM before triggering the last beforeUnload, instead of relying on a fixed animationFrame wait. runbot-243773 ---
Original PR description
The test read the field content for the last urgent save right after resolving modifyImagePromise, without waiting for the DOM to actually reflect the new image src. This raced the async update of the editable content, so beforeUnload sometimes ran before the image src were updated, sending stale content and failing intermittently. Wait for the updated image to appear in the DOM before triggering the last beforeUnload, instead of relying on a fixed animationFrame wait. runbot-243773 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278032
Code cleanup and technical improvements
Description of the issue/feature this PR addresses: - In 49f01db, `getDefaultValueFromGlobalFilter` was introduced to support `GlobalFilterInput`. - `GlobalFilterInput` no longer relies on this function, so remove the unused function. Task: [6388147](https://www.odoo.com/odoo/project/2328/tasks/6388147) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Description of the issue/feature this PR addresses: - In 49f01db, `getDefaultValueFromGlobalFilter` was introduced to support `GlobalFilterInput`. - `GlobalFilterInput` no longer relies on this function, so remove the unused function. Task: [6388147](https://www.odoo.com/odoo/project/2328/tasks/6388147) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Miscellaneous changes
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
Original PR description
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
1 change
Resolved issues and error corrections
Scenario: - create a website with main language different than en_US - create a website.page with some content - translate that page into English (en_US) - do some change in that page in original language => those changes are saved as delayed translations in en_US - from the backend, do a change in the corresponding view and save Result: the delayed changes in translation are lost and removed from all languages (even from the main website language). Cause: the backend view is displayed and sa
Original PR description
Scenario: - create a website with main language different than en_US - create a website.page with some content - translate that page into English (en_US) - do some change in that page in original language => those changes are saved as delayed translations in en_US - from the backend, do a change in the corresponding view and save Result: the delayed changes in translation are lost and removed from all languages (even from the main website language). Cause: the backend view is displayed and saved in en_US without the delayed changes. So if we modify the view and save, the view without the delayed change will be synced to all other languages which removes the delayed changes. opw-5938871 opw-6360011 Forward-Port-Of: odoo/odoo#277070
22 changes
Enhancements to existing features
Before this commit, when an authentication process was ongoing it was not very clear to the user This commit adds a banner to warn the user to not cancel the ongoing process or it will be aborted. task-6372665 Forward-Port-Of: odoo/odoo#277074 Forward-Port-Of: odoo/odoo#275230
Original PR description
Before this commit, when an authentication process was ongoing it was not very clear to the user This commit adds a banner to warn the user to not cancel the ongoing process or it will be aborted. task-6372665 Forward-Port-Of: odoo/odoo#277074 Forward-Port-Of: odoo/odoo#275230
In some cases, you want to redirect a record with ModelConverter, whatever the slug value. E.g. /shop/old-name-1 => /shop/alt-product-10 /shop/new-name-1 => /shop/alt-product-10 /fr/shop/nom-1 => /shop/alternatif-product-10 /de/shop/produktname-1 => /de/shop/produktname-10 In this case, adding only one redirect /shop/1 => /shop/10 covers the need to support all the translated slugs and the old name that we remember. On odoo.com we have this need e.g. when we archive a
Original PR description
In some cases, you want to redirect a record with ModelConverter, whatever the slug value.
E.g. /shop/old-name-1 => /shop/alt-product-10
/shop/new-name-1 => /shop/alt-product-10
/fr/shop/nom-1 => /shop/alternatif-product-10
/de/shop/produktname-1 => /de/shop/produktname-10
In this case, adding only one redirect /shop/1 => /shop/10 covers the need to support all the translated slugs and the old name that we remember.
On odoo.com we have this need e.g. when we archive a Job Position, we create a redirect, but in some cases the job position is translated or has been renamed and we don't remember all the old urls. With this change, we will be able to redirect all old urls, translated urls, ... with only one redirect.
/jobs/10 -> /explore-more-opportunities-with-us
task-6391567
Forward-Port-Of: odoo/odoo#276515Resolved issues and error corrections
### Description of the issue/feature this PR addresses: - Opening Studio on a form containing a Many2many field using the many2many_tags_email widget crashes with an OWL prop validation error. - **Steps to reproduce:** 1. Open any form view (e.g., Contacts) and enter `Studio`. 2. Create a new `Many2many` custom field on a model such as `res.partner`. 3. Set the field's widget to `many2many_tags_email` and save the customization. 4. Exit Studio and populate the field with one or more
Original PR description
### Description of the issue/feature this PR addresses: - Opening Studio on a form containing a Many2many field using the many2many_tags_email widget crashes with an OWL prop validation error. -…
### Description of the issue/feature this PR addresses: - Opening Studio on a form containing a Many2many field using the many2many_tags_email widget crashes with an OWL prop validation error. - **Steps to reproduce:** 1. Open any form view (e.g., Contacts) and enter `Studio`. 2. Create a new `Many2many` custom field on a model such as `res.partner`. 3. Set the field's widget to `many2many_tags_email` and save the customization. 4. Exit Studio and populate the field with one or more related records. 5. Open Studio again on the same form view. This results in the following error: ```.js Error: Invalid props for component 'RecipientTag': 'onDelete' is undefined (should be a value) ``` ### Current behavior before PR: - When opening Studio on a form containing a `Many2many` field with the `many2many_tags_email` widget, the field is rendered with `onDelete` set to undefined by `Many2ManyTagsField`. Starting from `saas-19.1`, the `many2many_tags_email` widget uses the new [RecipientTag] component, which requires onDelete to be defined. As a result, Owl's prop validation fails when RecipientTag receives `onDelete = undefined`, causing Studio to crash with an I nvalid props for component 'RecipientTag' error. ### Desired behavior after PR is merged: - RecipientTag should allow onDelete to be optional so that it can also be used when the parent field does not provide a delete callback. This prevents the Owl prop validation error when opening Studio, while keeping the existing delete functionality unchanged for editable fields where onDelete is available. opw:6395209 [RecipientTag]: https://github.com/odoo/odoo/blob/saas-19.1/addons/mail/static/src/core/web/recipient_tag.js --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/c88086079f [REL] 19.1.29 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/e8dafa04d1 [FIX] autofill: hide autofill handler when selection is hidden [Task: 6317808](https://www.odoo.com/odoo/2328/tasks/6317808) https://github.com/odoo/o-spreadsheet/commit/33ef954e9f [FIX] HeaderVisibility: fix `getNextVisibleCellPosition` getter [Task: 6340589](https://www.odoo.com/odoo/
Original PR description
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/c88086079f [REL] 19.1.29 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0)…
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/c88086079f [REL] 19.1.29 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/e8dafa04d1 [FIX] autofill: hide autofill handler when selection is hidden [Task: 6317808](https://www.odoo.com/odoo/2328/tasks/6317808) https://github.com/odoo/o-spreadsheet/commit/33ef954e9f [FIX] HeaderVisibility: fix `getNextVisibleCellPosition` getter [Task: 6340589](https://www.odoo.com/odoo/2328/tasks/6340589) https://github.com/odoo/o-spreadsheet/commit/d262fe5e19 [FIX] edition: do not change edition if not editing [Task: 6340589](https://www.odoo.com/odoo/2328/tasks/6340589) Co-authored-by: Florian Damhaut (flda) <flda@odoo.com> Co-authored-by: Anthony Hendrickx (anhe) <anhe@odoo.com> Co-authored-by: Alexis Lacroix (laa) <laa@odoo.com> Co-authored-by: Lucas Lefèvre (lul) <lul@odoo.com> Co-authored-by: Adrien Minne (adrm) <adrm@odoo.com> Co-authored-by: Ronak Mukeshbhai Bharadiya (rmbh) <rmbh@odoo.com> Co-authored-by: Dhrutik Patel (dhrp) <dhrp@odoo.com> Co-authored-by: Rémi Rahir (rar) <rar@odoo.com> Co-authored-by: Pierre Rousseau (pro) <pro@odoo.com> Co-authored-by: Vincent Schippefilt (vsc) <vsc@odoo.com> Co-authored-by: Marceline Thomas (matho) <matho@odoo.com>
Steps: - Install sale app. - Create SO for portal user. - Login with portal user. - Vat field is not editable and warning is wrong. Issue: - Before https://github.com/odoo/odoo/pull/211043 and recent fix https://github.com/odoo/odoo/pull/275207 portal user can edit their Vat number even if they have confirmed documents (invoice or SO) if Vat field is not set. Since `is_company` refactoring having set parent_name on address create related company and making `is_commercial_address` False a
Original PR description
Steps: - Install sale app. - Create SO for portal user. - Login with portal user. - Vat field is not editable and warning is wrong. Issue: - Before https://github.com/odoo/odoo/pull/211043 and recent fix https://github.com/odoo/odoo/pull/275207 portal user can edit their Vat number even if they have confirmed documents (invoice or SO) if Vat field is not set. Since `is_company` refactoring having set parent_name on address create related company and making `is_commercial_address` False and because that `Vat` field became reaonly and after recent fix `is_commercial_address` was set from `can_edit_vat` and validation done based on `can_edit_vat` before that `Vat` was editable if they have confirmed documents Fix: - Only make `Vat` readonly if Vat is set and is not individual address
**Description of the issue/feature this PR addresses:** [FIX] account: prevent access error for branch users When a user restricted to a branch company opens the accounting dashboard, they may encounter an AccessError preventing the app from loading. This occurs because the dashboard logic attempts to read the `fiscalyear_lock_date` from the journal's company. In a branch setup, this configuration often belongs to the parent company, which the user typically does not have read acc
Original PR description
**Description of the issue/feature this PR addresses:** [FIX] account: prevent access error for branch users When a user restricted to a branch company opens the accounting dashboard, they may…
**Description of the issue/feature this PR addresses:** [FIX] account: prevent access error for branch users When a user restricted to a branch company opens the accounting dashboard, they may encounter an AccessError preventing the app from loading. This occurs because the dashboard logic attempts to read the `fiscalyear_lock_date` from the journal's company. In a branch setup, this configuration often belongs to the parent company, which the user typically does not have read access to. The system then blocks the action and gives an AccessError. This commit resolves the issue by adding `.sudo()` when reading the `fiscalyear_lock_date`. This safely bypasses the record rule restriction, allowing the dashboard to fetch the necessary accounting configuration without requiring the user to have broad access to the parent company. **Steps to reproduce:** - As Mitchell Admin: - Settings > Users & Companies > Companies > My Company (San Francisco) > Branches > create a branch - Settings > Users & Companies > Users > Marc Demo > Access Rights > change “Companies” and “Default Company” to only the newly created branch - As Marc Demo: - Attempt to access Accounting app > observe Access Error **Current behavior before PR:** - Users belonging to only a branch company are unable to access the Accounting dashboard **Desired behavior after PR is merged:** - Users belonging to only a branch company are able to access the Accounting dashboard opw-6369616
The footer slideout state was computed only once during interaction setup. If the main content height changed afterward, e.g. in edit mode: dropping or removing snippets, or resizing the window, the effect could remain enabled/disabled even though the content had become taller/shorter than the viewport. Steps to reproduce: - Go into edit mode - Add two snippets on the page - On the footer, set the "Slideout Effect" option to "Slide Hover" - Remove one snippet - Half of the footer is
Original PR description
The footer slideout state was computed only once during interaction setup. If the main content height changed afterward, e.g. in edit mode: dropping or removing snippets, or resizing the window, the effect could remain enabled/disabled even though the content had become taller/shorter than the viewport. Steps to reproduce: - Go into edit mode - Add two snippets on the page - On the footer, set the "Slideout Effect" option to "Slide Hover" - Remove one snippet - Half of the footer is hidden by the hover effect, which should not happen task-6117257 Forward-Port-Of: odoo/odoo#277614 Forward-Port-Of: odoo/odoo#275291
**Steps to reproduce:** * Install l10n_fr. * Create an invoice using a tax with the E3 tax grid. * Post the invoice so it is included in the tax report. * Open the French tax report. **Observed Behaviour:** The E3 line is blank even though the amount is present in the report data. The amount is recorded as a negative value, while the report formula expects a positive value, causing it to be deducted from the report total. **Cause:** The E3 tax report expression used the for
Original PR description
**Steps to reproduce:** * Install l10n_fr. * Create an invoice using a tax with the E3 tax grid. * Post the invoice so it is included in the tax report. * Open the French tax report. **Observed Behaviour:** The E3 line is blank even though the amount is present in the report data. The amount is recorded as a negative value, while the report formula expects a positive value, causing it to be deducted from the report total. **Cause:** The E3 tax report expression used the formula E3, which does not account for tax grid amounts stored as negative values. **Fix:** Update the E3 report expression formula from E3 to -E3 so that negative E3 amounts are correctly displayed in the tax report. opw - 6321790 Forward-Port-Of: odoo/odoo#274052
Before this commit, the res.users model was not being loaded in the POS when reloading data. If user A was logged in and then on the same device user B logged in, it would not load the new user B data, and it causes user B to not be able to go to the backend. opw-6388954 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276546
Original PR description
Before this commit, the res.users model was not being loaded in the POS when reloading data. If user A was logged in and then on the same device user B logged in, it would not load the new user B data, and it causes user B to not be able to go to the backend. opw-6388954 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276546
iOS devices currently display the first letter of the website name instead of a favicon when creating a shortcut. This commit adds the `apple-touch-icon` link tag referencing the favicon to ensure the icon displays correctly. This commit is a backport of [1], which was merged in master(saas-19.2). task-5427275 [1]: https://github.com/odoo/odoo/commit/2506fdfc49f1515aea7e715e9f6d66418a093401 Forward-Port-Of: odoo/odoo#277723
Original PR description
iOS devices currently display the first letter of the website name instead of a favicon when creating a shortcut. This commit adds the `apple-touch-icon` link tag referencing the favicon to ensure the icon displays correctly. This commit is a backport of [1], which was merged in master(saas-19.2). task-5427275 [1]: https://github.com/odoo/odoo/commit/2506fdfc49f1515aea7e715e9f6d66418a093401 Forward-Port-Of: odoo/odoo#277723
Before this commit, the journal and the memo of a payment linked to a company-paid expense report could be modified although such payments must be kept consistent with their expense report: a missing comma in the set of protected fields merged 'journal_id' and 'ref' into a single meaningless entry. The memo was also left editable because the set still referred to 'ref', which was renamed to 'memo'. Steps to reproduce: - submit, approve and post an expense paid by company - open the payment
Original PR description
Before this commit, the journal and the memo of a payment linked to a company-paid expense report could be modified although such payments must be kept consistent with their expense report: a missing…
Before this commit, the journal and the memo of a payment linked to a company-paid expense report could be modified although such payments must be kept consistent with their expense report: a missing comma in the set of protected fields merged 'journal_id' and 'ref' into a single meaningless entry. The memo was also left editable because the set still referred to 'ref', which was renamed to 'memo'. Steps to reproduce: - submit, approve and post an expense paid by company - open the payment created for the expense report - edit the memo or the journal and save, then try to edit the date Editing the date is refused with "You cannot do this modification since the payment is linked to an expense report", while the memo and journal changes are silently accepted. Solution: Restore the missing comma and protect the renamed memo field. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277737 Forward-Port-Of: odoo/odoo#277423
Steps to reproduce: - activate location - create a tracked product A - create a PO with qty=10 with product A - receive them (8 in WH/Stock, 2 in WH/Stock/Shelf 1) - In Reporting/stock filter with "wh/stock" Issue: On hand value will be 0 Cause: "wh/stock did not match _rec_names = 'name' -> WH location is different than "stock" location (who's parent is "WH"). We need to match it with _rec_names_search (1) to match the right location. We fall back on _rec_names in case _rec_name
Original PR description
Steps to reproduce: - activate location - create a tracked product A - create a PO with qty=10 with product A - receive them (8 in WH/Stock, 2 in WH/Stock/Shelf 1) - In Reporting/stock filter with "wh/stock" Issue: On hand value will be 0 Cause: "wh/stock did not match _rec_names = 'name' -> WH location is different than "stock" location (who's parent is "WH"). We need to match it with _rec_names_search (1) to match the right location. We fall back on _rec_names in case _rec_names_search would not be defined (not really necessary in here but meh why not be conservative) (1) https://github.com/odoo/odoo/blob/2bb7493b72b400ed76cc6460c94867fb86de9f3a/addons/stock/models/stock_location.py#L19 opw-6312702 Forward-Port-Of: odoo/odoo#271552
# How to reproduce - Enable Cloudflare Turnstile in Settings > Integrations - Add a CF Site Key & a CF Secret Key. e.g. : - `1x00000000000000000000AA` - `1x0000000000000000000000000000000AA` (See : https://developers.cloudflare.com/turnstile/troubleshooting/testing/) - Go to a Website page with a form - Add `?cf=show` to the URL - Open the browser console - Search the dom for an element with s_turnstile_container - Look for the `data-appearance` attribute # The issue `data-appea
Original PR description
# How to reproduce - Enable Cloudflare Turnstile in Settings > Integrations - Add a CF Site Key & a CF Secret Key. e.g. : - `1x00000000000000000000AA` - `1x0000000000000000000000000000000AA` (See :…
# How to reproduce - Enable Cloudflare Turnstile in Settings > Integrations - Add a CF Site Key & a CF Secret Key. e.g. : - `1x00000000000000000000AA` - `1x0000000000000000000000000000000AA` (See : https://developers.cloudflare.com/turnstile/troubleshooting/testing/) - Go to a Website page with a form - Add `?cf=show` to the URL - Open the browser console - Search the dom for an element with s_turnstile_container - Look for the `data-appearance` attribute # The issue `data-appearance` is set to `interaction-only` but should be `always` according to : https://github.com/odoo/odoo/blob/1e73172b51cd673c3414187af4f98304921ed7b3/addons/website_cf_turnstile/static/src/interactions/turnstile.js#L8-L12 # Cause `appearance` is misspelled in the template : https://github.com/odoo/odoo/blob/1e73172b51cd673c3414187af4f98304921ed7b3/addons/website_cf_turnstile/static/src/interactions/turnstile.xml#L7 Documentation on the Appearance modes for Turnstile : https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/widget-configurations/#appearance-modes opw-6359977 Forward-Port-Of: odoo/odoo#275077
The character-by-character HTML assertion in mass mailing tests fails on modern platforms using libxml2 >= 2.14/2.15 due to upstream updates that align HTML serialization, attribute quote management, and escaping rules more closely with the HTML5 specification. See upstream changes: - https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.14.0 (Attribute escaping optimization) - https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.15.0 (HTML5 spec compliant serialization) This commit fixes
Original PR description
The character-by-character HTML assertion in mass mailing tests fails on modern platforms using libxml2 >= 2.14/2.15 due to upstream updates that align HTML serialization, attribute quote management, and escaping rules more closely with the HTML5 specification. See upstream changes: - https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.14.0 (Attribute escaping optimization) - https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.15.0 (HTML5 spec compliant serialization) This commit fixes this by refactoring the assertions to treat the output HTML structure as a "black box", verifying data integrity and expected content conversions rather than brittle structural layout. runbot-938228 Forward-Port-Of: odoo/odoo#277747 Forward-Port-Of: odoo/odoo#275959
Steps to produce: 1) Install Manufacturing & enable "Work Order Dependencies" in the settings 2) Make a new BOM with 2 operations 3) Check "Operation Dependencies" in the miscellaneous tab on the BOM's form view. 4) Configure the first sequential operation to be blocked by the second 5) Make and confirm an MO using this BOM 6) Uncheck "Operation Dependencies" on the BOM 7) Press "Plan" on the MO, a validation error is thrown stating "You cannot create cyclic dependency." Issue occur
Original PR description
Steps to produce: 1) Install Manufacturing & enable "Work Order Dependencies" in the settings 2) Make a new BOM with 2 operations 3) Check "Operation Dependencies" in the miscellaneous tab on the…
Steps to produce: 1) Install Manufacturing & enable "Work Order Dependencies" in the settings 2) Make a new BOM with 2 operations 3) Check "Operation Dependencies" in the miscellaneous tab on the BOM's form view. 4) Configure the first sequential operation to be blocked by the second 5) Make and confirm an MO using this BOM 6) Uncheck "Operation Dependencies" on the BOM 7) Press "Plan" on the MO, a validation error is thrown stating "You cannot create cyclic dependency." Issue occurs because after the MO is confirmed the blocked_by_workorder_ids field for mrp.workorder records is set based on the order manually configured on the BOM (operation 1 is blocked by operation 2). After the BOM is edited to have allow_operation_dependencies = false, then Odoo uses the default sequential ordering when planning the operations (operation 2 is blocked by operation 1). Since the old ordering is never cleared, a cycle is created unintentionally. This PR resolves this issue by clearing the blocked_by_workorder_ids field on mrp.workorder records. opw-6334271 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275154
Firefox has a strict limit of ~640,000 characters for history state serialization and throws NS_ERROR_ILLEGAL_VALUE past it. Chrome and Safari throw DataCloneError past their own undocumented limits (~500MB and ~64MB respectively). When a debounced push() exceeded these limits, the error was unhandled and broke navigation. Catch these two specific errors and log them instead of crashing, while still resetting the push state and re-throwing any other unexpected error. opw-6182687 Forward-P
Original PR description
Firefox has a strict limit of ~640,000 characters for history state serialization and throws NS_ERROR_ILLEGAL_VALUE past it. Chrome and Safari throw DataCloneError past their own undocumented limits (~500MB and ~64MB respectively). When a debounced push() exceeded these limits, the error was unhandled and broke navigation. Catch these two specific errors and log them instead of crashing, while still resetting the push state and re-throwing any other unexpected error. opw-6182687 Forward-Port-Of: odoo/odoo#277724
Before this commit, when clicking on refresh and the kyc_status on IAP was 'fail', we put the status on the db to 'fail' and ended the process. This implies creating a new record IAP side even if it is useless and also implies that there could be cases where there would be a mismatch between iap and Odoo. e.g. The client starts a verification process, he ends up refusing to sign the documents. On IAP, the kyc status would be equal to 'fail'. Then the user have a possibility to submit a manual
Original PR description
Before this commit, when clicking on refresh and the kyc_status on IAP was 'fail', we put the status on the db to 'fail' and ended the process. This implies creating a new record IAP side even if it is useless and also implies that there could be cases where there would be a mismatch between iap and Odoo. e.g. The client starts a verification process, he ends up refusing to sign the documents. On IAP, the kyc status would be equal to 'fail'. Then the user have a possibility to submit a manual verification and when submitting it status would go to 'processing'. The problem is that in the meantime (after refusing but before submitting manual verification), if the user clicks on the refresh button it would ends the process on Odoo and then not going to 'success' on the DB even if it is the case on IAP after Support reviewed the request. task-6307255 Forward-Port-Of: odoo/odoo#277045 Forward-Port-Of: odoo/odoo#276191
hash_sign has become very used all over the place, so more and more tokens depend on `database.secret`, increasing the impact of that secret needing one day to be rotated or being compromised. To avoid making `database.secret` a single point of failure, we would like `hash_sign` to support a custom secret supplied by caller. task-6391264 Forward-Port-Of: odoo/odoo#276698 Forward-Port-Of: odoo/odoo#276474
Original PR description
hash_sign has become very used all over the place, so more and more tokens depend on `database.secret`, increasing the impact of that secret needing one day to be rotated or being compromised. To avoid making `database.secret` a single point of failure, we would like `hash_sign` to support a custom secret supplied by caller. task-6391264 Forward-Port-Of: odoo/odoo#276698 Forward-Port-Of: odoo/odoo#276474
## Problem When a `web_read_group` call is made with some condition on the active field, the active test is bypassed by adding `['active', 'in', [True, False]]` to the domain. This will cause a search to fail if the model's active field is not called `active` (like in a studio model). ## Solution We will change the domain to `[self._active_name, 'in', [True, False]]` to properly handle customizations. ## Steps to replicate (Runbot v19) 1. Create a new model with Studio - enable Pipeline
Original PR description
## Problem When a `web_read_group` call is made with some condition on the active field, the active test is bypassed by adding `['active', 'in', [True, False]]` to the domain. This will cause a search to fail if the model's active field is not called `active` (like in a studio model). ## Solution We will change the domain to `[self._active_name, 'in', [True, False]]` to properly handle customizations. ## Steps to replicate (Runbot v19) 1. Create a new model with Studio - enable Pipeline and Archiving 2. Open the kanban view and add 'Archived' to the filter 3. Traceback opw-6403422 Forward-Port-Of: odoo/odoo#277666
When creating an activity in a custom app made with studio, no image is shown, and instead the alt text is shown with a missing image. This fixes the issue by showing a placeholder icon if no module is found for the activity group. opw-6282451 Previous behavior: <img width="1315" height="568" alt="image" src="https://github.com/user-attachments/assets/1e4fc1d5-3a35-4193-80fc-f6d161776e2e" /> New behavior: <img width="1315" height="568" alt="image" src="https://github.com/user-attac
Original PR description
When creating an activity in a custom app made with studio, no image is shown, and instead the alt text is shown with a missing image. This fixes the issue by showing a placeholder icon if no module is found for the activity group. opw-6282451 Previous behavior: <img width="1315" height="568" alt="image" src="https://github.com/user-attachments/assets/1e4fc1d5-3a35-4193-80fc-f6d161776e2e" /> New behavior: <img width="1315" height="568" alt="image" src="https://github.com/user-attachments/assets/6ed5ca8b-8481-470f-b7c6-dd59c616125e" /> (Original PR: https://github.com/odoo/odoo/pull/268957 Re-based on 17.0 as its the earliest version affected, so it can be forward-ported to future versions) Forward-Port-Of: odoo/odoo#269654
# Problem Cost of production in the inventory valuation report does not respect 'As of' date, and will show current costs of production regardless of the specified date. # Solution `_get_report_data` in `mrp_account` is just missing the date enforcement when calling `_get_location_valuation_vals`, so we will simply pass this in. # Steps to reproduce (runbot v19) - FIFO Perpetual component with non-zero value - Manufactured product that consumes the above component 1. Set a cost of pro
Original PR description
# Problem Cost of production in the inventory valuation report does not respect 'As of' date, and will show current costs of production regardless of the specified date. # Solution `_get_report_data` in `mrp_account` is just missing the date enforcement when calling `_get_location_valuation_vals`, so we will simply pass this in. # Steps to reproduce (runbot v19) - FIFO Perpetual component with non-zero value - Manufactured product that consumes the above component 1. Set a cost of production account on the production location 2. Create and confirm an MO for the manufactured product 3. Go to Accounting > Review > Inventory Valuation, and set the At Date to something far in the past, befroe any move history in the db. Note the Cost of Production accounts have data that does not apply to this period opw-6229088 Forward-Port-Of: odoo/odoo#269911
Documentation and clarification updates
Adds Corvanis corporate CLA entry so legal/cla can validate contributions from Corvanis contributors. This change only adds: - doc/cla/corporate/corvanis.md - No functional code changes. Forward-Port-Of: odoo/odoo#276949
Original PR description
Adds Corvanis corporate CLA entry so legal/cla can validate contributions from Corvanis contributors. This change only adds: - doc/cla/corporate/corvanis.md - No functional code changes. Forward-Port-Of: odoo/odoo#276949
4 changes
Resolved issues and error corrections
#### Description of the issue this PR addresses: - Blockquotes currently display their border on the left side. #### Desired behavior after PR is merged: - Update the styling so the border is displayed on the right side for RTL content. task-6296519 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#269529
Original PR description
#### Description of the issue this PR addresses: - Blockquotes currently display their border on the left side. #### Desired behavior after PR is merged: - Update the styling so the border is displayed on the right side for RTL content. task-6296519 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#269529
**Steps to reproduce:** - Create two companies - Create aliases for each company - Receive a bounced email on the alias of the second company - Recipient of the bounce email will be from the first company **Issue:** `self.env.company` is used in `message_route` for catchall mails without checking if it corresponds to the received domain, making it defaults to the 'main' company instead. **Fix:** Try to find the company of the given mail address using the `'mail.alias.domain'` and app
Original PR description
**Steps to reproduce:** - Create two companies - Create aliases for each company - Receive a bounced email on the alias of the second company - Recipient of the bounce email will be from the first company **Issue:** `self.env.company` is used in `message_route` for catchall mails without checking if it corresponds to the received domain, making it defaults to the 'main' company instead. **Fix:** Try to find the company of the given mail address using the `'mail.alias.domain'` and apply it on the body rendering and `_routing_create_bounce_email` function. similar fix in `account` module: https://github.com/odoo/odoo/commit/b7e0d8914d35af12a96593e484889e48c0613078 opw-5180433 Forward-Port-Of: odoo/odoo#244296
Before this commit, the default einvoice format was changed only when the partner was french and had a vat number, but we want to ease that condition and do it only if the partner is french. task-6303174 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270720
Original PR description
Before this commit, the default einvoice format was changed only when the partner was french and had a vat number, but we want to ease that condition and do it only if the partner is french. task-6303174 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270720
When matching Purchase Order lines with Vendor Bill lines from the Bill Matching view, if a PO and its vendor bill each contain several lines for the same product, all bill lines of that product get matched to the first PO line only. The remaining PO line(s) stay unmatched and are then added back to the bill as new (duplicate) lines. Steps: - Create a purchase order with two lines for the same product and confirm - Create a draft bill with the same configuration and same partner - From the PO,
Original PR description
When matching Purchase Order lines with Vendor Bill lines from the Bill Matching view, if a PO and its vendor bill each contain several lines for the same product, all bill lines of that product get…
When matching Purchase Order lines with Vendor Bill lines from the Bill Matching view, if a PO and its vendor bill each contain several lines for the same product, all bill lines of that product get matched to the first PO line only. The remaining PO line(s) stay unmatched and are then added back to the bill as new (duplicate) lines. Steps: - Create a purchase order with two lines for the same product and confirm - Create a draft bill with the same configuration and same partner - From the PO, click on "Bill matching" button - Select the 4 lines and click on the "Match" button -> On the purchase order, first line has qty_invoiced == 2 and the second one 0 -> On the bill, there is an additional line with 0 quantity This is because we only match the first order line in case of having more than one line with the same product. Then we add the remaining order lines to the bill. With this commit we match each line that need to be matched and we add lines to the bill only if all order lines have been invoiced. opw-6279755 Forward-Port-Of: odoo/odoo#269496
52 changes
New functionality added to Odoo
Mexican payroll now supports calculating the legally required seventh day payment proportionally for weekly and 14-day pay schedules. This helps employers pay rest-day compensation more accurately when employees have absences or different weekly rest-day arrangements.
Original PR description
By Mexican labor law, employees are entitled to at least one paid rest day per week (commonly known as the Seventh Day). Depending on the contract, some schedules provide two rest days. There are two…
By Mexican labor law, employees are entitled to at least one paid rest day per week (commonly known as the Seventh Day). Depending on the contract, some schedules provide two rest days. There are two ways to pay this concept: * Fixed amount: The employee receives the full daily salary regardless of absences (already supported). * Prorated amount: Applies strictly to weekly and 14-days schedule pays. The payment is proportional to the actual time worked during the period (new feature). The prorated seventh day is calculated using the following formula: `accrued_days * work_rate * daily_salary` Where: * Accrued days: Actual days/hours worked in the period. * Work rate: A proportional factor based on the rest days and working days per week: `rest_days / working_days_per_week`. Rest days are dynamically calculated using the `hours_per_day` and `hours_per_week` fields from the `resource_calendar_id`. * Daily salary: Retrieved from the `l10n_mx_daily_salary` field. EXAMPLE 1: WEEKLY SCHEDULE WITH 1 REST DAY For a wage of 7,000 MXN weekly (daily wage = 1,000 MXN), the rate is `1/6 = 0.16666`. The payment depends on the worked days: | Worked Days | Seventh Day Amount Paid | | ----------- | ---------------------------------- | | 1 | 1 * 0.16666 * 1,000 = 166.67 MXN | | 2 | 2 * 0.16666 * 1,000 = 333.33 MXN | | 3 | 3 * 0.16666 * 1,000 = 500.00 MXN | | 4 | 4 * 0.16666 * 1,000 = 666.67 MXN | | 5 | 5 * 0.16666 * 1,000 = 833.33 MXN | | 6 | 6 * 0.16666 * 1,000 = 1,000.00 MXN | EXAMPLE 2: WEEKLY SCHEDULE WITH 2 REST DAYS For the same daily wage, but with a 5-day workweek, the rate is 2/5 = 0.4. | Worked Days | Seventh Day Amount Paid | | ----------- | -------------------------------- | | 1 | 1 * 0.40000 * 1,000 = 400.00 MXN | | 5 | 5 * 0.40000 * 1,000 = 2,000.00 MXN | * Add test_cfdi_nomina_con_septimo_dia test target: master task-5259458
A new timesheet add-on introduces AI assistant support to help users refine timesheet descriptions. The assistant rules were also simplified so messaging-related work is categorized more consistently across tools like Discord, Google Chat, and Odoo Discuss.
Original PR description
- added new module to support ai assistant capabilities - changed the assistant rules task-6376442
Enhancements to existing features
The Chile and Mexico e-invoicing checkout flows now pass the current order into checkout step preparation. This helps ensure category-based extra checkout steps are applied correctly for localized online sales.
Original PR description
Pass `order` to `_get_checkout_step_values` in l10n-specific checkout controllers to support the extra-step category restriction. Community PR: https://github.com/odoo/odoo/pull/258042
Payroll users can now correct an entire validated or paid pay run in one action instead of manually reverting and recreating each payslip. The system creates a linked correction pay run with the necessary reversal and draft corrected payslips, improving efficiency and traceability at batch level.
Original PR description
There was previously no way to correct a complete pay run once it was validated or paid. Users had to manually revert and recreate payslips one by one, with no traceability at the batch level. Add a "Correct" action on validated (or paid) pay runs. Triggering it: - Creates a new pay run covering the same period, structure, and company as the original. - Reuses the existing per-payslip refund/correction logic (_action_refund_payslips/_action_correct_payslips) to generate, for each original payslip, a reverted payslip (validated) and a draft corrected payslip, both linked to their origin. - Moves all reverted and corrected payslips into the new pay run and routes the user directly to its Payslips step. Task: 6352855
Users can now create batch payments from the payment wizard even when the payment method is not SEPA. SEPA payments keep the existing flow, ISO payments can generate downloadable XML without initiation, and other methods can still be grouped into batches.
Original PR description
Since the new payment initiation features, we added a wizard in the payment list view to allow users to create a batch or start a payment initiation. But this was only possible for SEPA payments. This commit allows users to create batch payments from this wizard with any payment methods. This works like so: - If SEPA payment -> same as before - If any ISO payment -> Not allowed to initiate the payment but can download XML - If any other methods -> Just allowed to create a batch without XML task-6272798 Forward-Port-Of: odoo/enterprise#120976
Clicking a phone number now follows the company’s mobile calling preference when VoIP cannot place the call. Users may see the softphone to check connectivity, open the native phone dialer, or choose between options, reducing confusion and accidental duplicate actions.
Original PR description
…ability When the user clicks a phone number in a PhoneField widget but VoIP is not available (canCall = false), the behavior now depends on the how_to_call_on_mobile setting: - "voip": show the softphone so the user can check the connection - "phone": fall back to the base class default (native dialer) - "ask": show a selection dialog for the user to choose We also backport the code to prevent double click from [1]. [1]: https://github.com/odoo/enterprise/commit/fa6c8747d69ffee25a7f308d26baca8500226784 Forward-Port-Of: odoo/enterprise#123065
This update adjusts how product tags are managed in the AI website sales tools after related product page changes. It helps keep product editing and website product options working reliably as the underlying layout evolves.
Original PR description
**Purpose:** The template for the parent view "product.product_template_form_view" was modified with the product tags moving to another page. Then the field "l10n_pe_edi_tariff_fraction" cannot depend on the product tags position anymore. Task-5215982 See also: - https://github.com/odoo/odoo/pull/237565
When a user selects a project in the timesheet timer, Odoo now automatically fills in the task they most recently logged time on for that project. For Helpdesk projects, the same behavior applies to the most recent ticket, helping users start timers faster while still allowing easy changes.
Original PR description
When selecting a project in the timesheet timer, the task on which the user most recently logged time for that project is now prefilled, as they are most likely to keep logging time on it. If not, selecting a different task only requires one click. For Helpdesk projects, where the timer shows the ticket field instead of the task field, the most recently timesheeted ticket is prefilled in the same way. task-6359030 Forward-Port-Of: odoo/enterprise#124010
Self-order kiosk orders that will be paid at the counter are no longer sent to the Belgian blackbox before payment is completed. This prevents premature fiscal registration and supports mixed self-order payment flows more reliably.
Original PR description
This commits adapts the code in confirmation_page.js to not send the order to the blackbox from the kiosk if the order is not in paid state. task-id: 5960666 Forward-Port-Of: odoo/enterprise#123699 Forward-Port-Of: odoo/enterprise#117585
Uruguayan e-invoicing now lets users mark products as non-billable directly on the product record. This helps businesses report items such as manual rounding adjustments correctly to the tax authority using the required non-billable indicators.
Original PR description
Purpose: In UY e-invoicing, the DGI defines indicators 6 (positive non-billable) and 7 (negative non-billable). Currently, Odoo only supports down payment flows utilizing these indicators. However, indicators 6 and 7 are commonly used for other business cases, such as manual rounding adjustments. To support other flows outside of down payment, an explicit product-level flag is added to represent non-billable items/services in UY. Users will be able to set a product as non-billable in the Accounting tab. When an invoice containing non-billable products is sent to the DGII, it will be sent with the appropriate indicators, 6 or 7 and aggregated into MontoNf node of the CFE document. task-5904238
The automated clickbot now also verifies that screens meant to work offline still behave correctly when the network is unavailable. Several dashboards and views now open faster by showing cached information first, helping users avoid waiting while fresh data loads.
Original PR description
The clickbot only ever exercised the app while online. It now also checks that the views marked as available offline still work correctly once the network is cut, catching regressions that only show up in offline mode. task-id 6366264
The Employee Gantt view in Manufacturing now shows only employees who are currently assigned to active work orders or who worked on one in the last 30 days. This reduces clutter and helps planners focus on the employees most relevant to current production work.
Original PR description
Before, in Employee Gantt in MRP module, all employees of the company were shown, even if they have never done a work order. Now, the following employees are visible: - Employees currently assigned to any work order (not done, not cancelled) - Employee assigned to any work order in the last 30 days task-6276316
Event staff can now print attendee badges in A4 PDF format directly from the registration desk. The update also extends badge printing support to Point of Sale, making on-site event check-in and badge handling more flexible.
Original PR description
This PR adds the support for A4 pdf badge printing through the registration desk. Requested for OXP in Kenya See https://github.com/odoo/odoo/pull/275021 Forward-Port-Of: odoo/enterprise#123799 Forward-Port-Of: odoo/enterprise#123478
Spreadsheet users can now retrieve the visible label of a global filter, such as a customer name, instead of only its internal ID. This makes spreadsheet reports easier to read and share when filter values need to be displayed in a business-friendly way.
Original PR description
Before this commit: If you use ODOO.FILTER.VALUE and have a customer set in the global filter, it returns the id of the customer. That can be useful in some cases but in others you might simply want the label. Task: 6167605 Forward-Port-Of: odoo/enterprise#124746 Forward-Port-Of: odoo/enterprise#115984
Localized bank account details are now shown in a more consistent position across several country-specific modules. This keeps important banking and partner information grouped logically, making forms easier to review and maintain.
Original PR description
Since we have partner_id now on top of holder_name, we want to anchor localization specific fields on top of partner_id instead of holder_name. task-6275796
Resolved issues and error corrections
This update standardizes how Odoo decides whether a database save can happen during key accounting, localization, and social workflows. It helps prevent unintended saves during tests or sensitive actions such as bank statement imports, reducing the risk of inconsistent results or failed processes.
Original PR description
…flag The aim of this commit is to allow forbidding a commit in specific condition and uniformize the way we check if a commit can be done. Context: There are a few places where checking the module.current_test flag isn't enough. For example, some test monkey patch it for specific reason and some business flow like the import of a csv of bank statement can't afford a commit. task-id: None
The report layout now keeps the chatter panel visible at the right edge of the screen, even when financial reports are very wide. This helps users continue discussions and collaboration without needing to scroll horizontally across large reports.
Original PR description
Issue: - When reports are large/wide, the chatter component is pushed beyond the visible viewport, appearing only at the absolute right edge of the overflowing report rather than the right edge of the screen. Fix: - Updated the layout container to prevent the chatter from shrinking or overflowing with the report block, ensuring the main report scrolls independently while the chatter stays pinned to the screen viewport. Impact: - Keeps the chatter panel fully visible on the right side of the screen, allowing users to communicate without scrolling horizontally on wide reports. task-[6376792](https://www.odoo.com/odoo/project/967/tasks/6376792) Forward-Port-Of: odoo/enterprise#125126 Forward-Port-Of: odoo/enterprise#123734
This fix moves the express mention to the correct section of the French VAT report file sent to Aspone. It helps ensure submitted VAT declarations follow the expected format and are less likely to be rejected or mishandled.
Original PR description
in this commit: https://github.com/odoo/enterprise/commit/93c1a4fe15d1f09e4c3df3a5db0e06006121c027 we added a way to have an express mention in the xml sent to aspone. But we placed it in the "T-IDENTIF" zone, but this zone doesn't accept express mention. It should be located in the form it self. task-6253745 Forward-Port-Of: odoo/enterprise#124471 Forward-Port-Of: odoo/enterprise#123235
When a spreadsheet cannot be opened because its underlying model fails to load, Odoo now stops the follow-up synchronization step that depended on that missing data. Users still receive the intended error notification, but avoid an additional technical crash message.
Original PR description
Current behavior before PR: - In 4204ceb, model creation errors were caught and a notification was shown to the user. - However, syncSheetFromRouter() was still called afterward. Since it relies on model getters, it raise a traceback when no model existed. Desired behavior after PR is merged: - Call syncSheetFromRouter() only after the model has been created successfully. - This prevents accessing model getters when model creation fails and avoids the resulting traceback. Task: [6355245](https://www.odoo.com/odoo/project/2328/tasks/6355245) Forward-Port-Of: odoo/enterprise#124961 Forward-Port-Of: odoo/enterprise#122650
Belgian annual statement XBRL exports now preserve required true/false and unit values instead of translating them when the user language is Dutch. This prevents affected filings from being rejected by the National Bank of Belgium validator.
Original PR description
Steps to reproduce: - Set the user language to Dutch. - Go to Accounting > Reporting > Annual Statements. - Generate the XBRL export for a report other than the "company, abridged" (acon) balance…
Steps to reproduce:
- Set the user language to Dutch.
- Go to Accounting > Reporting > Annual Statements.
- Generate the XBRL export for a report other than the "company,
abridged" (acon) balance sheet/P&L combination, e.g. an association
(asso_a/asso_f) or "company, full"/"company, capital" report.
- Open the file: the `<met:bln1>` boolean facts are exported as
"onwaar" instead of "false", which is not a valid XBRL boolean
lexical value and gets rejected by the NBB validator.
Cause of the issue:
QWeb templates translate static text nodes by default. The base
module ships a generic `msgid "false" -> msgstr "onwaar"` translation,
used elsewhere in the UI, which silently hijacks the literal
"false"/"true" and unit tokens ("iso4217:EUR", "pure") in the XBRL
data templates whenever the file is generated in Dutch.
Solution:
Add `t-translation="off"` on the `<met:bln1>` boolean facts and the
`<measure>` unit tokens in the 5 remaining XBRL templates,
so these fixed-vocabulary XBRL values are never subject to translation
opw-6395785
Forward-Port-Of: odoo/enterprise#124945The appointment link copy confirmation now appears only after the copy action has actually been attempted. This prevents automated appointment CRM flows from moving ahead too early, making related tests and user interactions more reliable.
Original PR description
Prior to this commit, the success notification for copying an appointment link to the clipboard was triggered synchronously, while the actual `navigator.clipboard.writeText` execution was deferred inside a `setTimeout`. This caused a race condition (depending on the browser's cpu load) during tours (e.g., `appointment_crm_meeting_tour`). The tour would proceed and restore the mocked clipboard object (`oldWriteText`) before the deferred `setTimeout` block had a chance to execute. This commit fixes the issue by moving the notification logic inside the `setTimeout` callback. The tour is also updated to wait explicitly for the success notification before cleaning up the clipboard mock and proceeding to discard the slots. runbot-241004 Forward-Port-Of: odoo/enterprise#124439
Resetting a submitted tax return no longer changes the company-wide tax lock date, so closed periods are not unintentionally reopened for everyone. The update also supports companies that set the tax lock date before submitting a return, helping larger teams keep accounting periods controlled during VAT filing.
Original PR description
To reproduce the issue: 1) Initialize a company in Belgium, create the tax returns 2) Submit the VAT return from January 3) Open the lock date wizard. The tax lock date is January 31st. 4) Add a lock…
To reproduce the issue:
1) Initialize a company in Belgium, create the tax returns 2) Submit the VAT return from January
3) Open the lock date wizard. The tax lock date is January 31st. 4) Add a lock date exception removing the tax lock date just for you, for 5 min. 5) Reset January's return
6) Reopen the lock date wizard.
====> Your exception is still there, but the tax lock date for everyone has been reset to December 31st.
This is plain wrong. Resetting a return should not automatically reopen the period for everyone. Lock dates exceptions/modifications are anyway required to reset the return ; they should pilot the whole flow. Nothing being magically hidden from the user means there can't be someone else mistakenly encoding something into the reopened period.
Another fix was required to make this one work: setting the tax lock date before submitting the return should work. In bigger environments, users might want to do that as a first step to reduce the number of people encoding data before actually doing the submission of the return. Therefore, the case where the tax lock date is already set at the date_to of the return when submitting it was supposed to be already supported, and allow the creation of the closing entry for that return, despite it being on the tax lock date. The test ensuring this was however badly written, and the feature didn't work: the closing was created at a later date than the lock date automatically, due to the Bills' Algorithm.
Forward-Port-Of: odoo/enterprise#124872
Forward-Port-Of: odoo/enterprise#124811Odoo now places certificates from emSigner correctly in signed PDF documents after recent changes on the emSigner side. This prevents visibly misaligned certificates and helps keep signed documents professional and readable.
Original PR description
Before: - Certificate added by emSigner was misaligned in the signed PDF after recent UI changes. After: - Updated coordinates to ensure the emSigner certificate is properly aligned and displayed correctly in Odoo. task-6105264 Forward-Port-Of: odoo/enterprise#113402
VoIP call recordings made from Apple mobile devices will no longer produce silent audio files. The recording settings were adjusted for Apple browsers so businesses can reliably review recorded calls when call recording is enabled.
Original PR description
Before this commit, recording a VoIP phone call from an Apple mobile device generated a silent audio file. This issue happened because the configured 8000 `audioBitsPerSecond` value was too low. Apple mobile browsers strictly respect this value, while other browsers ignore it and default to a higher bitrate to 128000. Increasing `audioBitsPerSecond` to 32000 on WebKit browsers fixes the issue on Apple mobile devices. How to reproduce: - Set up a DIDWW user. - Enable call recording. - Make a call. - Open the call and play the recording. opw-6046534 Forward-Port-Of: odoo/enterprise#124433 Forward-Port-Of: odoo/enterprise#117885
Fixed an issue where the payroll dashboard could crash after users dismissed the final warning on an empty dashboard. The screen now handles upcoming pay run dates correctly, allowing payroll teams to continue using the dashboard without interruption.
Original PR description
Steps to reproduce:- 1. Set schedule on payroll dashboard. 2. Dismiss every warning. 3. On dismissing last warning throws a traceback. Root cause:- `DashboardEmptyScreen` passed the raw closing_date value straight from the RPC response into formatDateLabel, which calls date.diff(...) assuming a Luxon DateTime. The RPC layer serializes it as a plain ISO string, so formatDateLabel crashed with "date.diff is not a function" any time the empty-dashboard screen rendered with upcoming pay runs. Fix:- added new method `formatClosingDate` to format `closingDate` seperately. task-6395553
Businesses can once again add comments when submitting Belgian VAT return XML files. This restores a previously available option that had been removed by mistake, helping teams include required context with filings.
Original PR description
This feature had been mistakenly removed. Forward-Port-Of: odoo/enterprise#124865
Shop Floor now places manufacturing orders with scheduled work ahead of orders that have no planned start time. This makes the work center view match the standard work order list and helps teams focus on jobs that are ready to proceed.
Original PR description
## Problem In shop floor, MOs with unplanned work orders get sorted before MOs that have planned operations, which contradicts the normal nulls last sorting for work orders. ## Solution We will…
## Problem In shop floor, MOs with unplanned work orders get sorted before MOs that have planned operations, which contradicts the normal nulls last sorting for work orders. ## Solution We will update the sorting logic in the MrpDisplay component to more gracefully handle falsy date_start values, sorting them to the end. ## Steps to reproduce (runbot 19) 1. Create 2 MOs with an operation (work order) involving a work center, we'll call them A and B. 2. Open Shop Floor and open the work center that the MOs' work orders belong to, and note they are ordered A, B (this is fine, neither are planned so the precedence falls back to id 3. Go back to MO B and plan it. This should give it precedence in Shop Floor 4. Under the work center in Shop Floor, note that the MOs are still ordered A, B, despite B's work order having a start date and A's work order not having one To further motivate this being unintended, you can go to Manufacturing > Operations > Work Orders, and you'll see MO B's work order sitting at the top of the list. opw-6303323 Forward-Port-Of: odoo/enterprise#123983 Forward-Port-Of: odoo/enterprise#121693
Barcode delivery operations now correctly warn users when the same package is scanned more than once, even when multiple packages are part of the transfer. This prevents duplicated package contents from being processed and avoids incorrect negative stock quantities.
Original PR description
Steps to reproduce --- 1. Enable Packages and turn on "Move Entire Packages" on the delivery operation type. 2. Create a storable product P and add 2 units in different package in stock: 1 in…
Steps to reproduce --- 1. Enable Packages and turn on "Move Entire Packages" on the delivery operation type. 2. Create a storable product P and add 2 units in different package in stock: 1 in PACK001, 1 in PACK002 3. In the Barcode app > Operations > Delivery > New 4. Scan a first package PACK001, then a second different package PACK002 5. Scan the first package PACK001 again. Issue --- Re-scanning an already scanned package is meant to be rejected with a "This package is already scanned." warning, but the rejection stops working as soon as a second package is present in the transfer, so the package content gets added a second time and, once validated, the source quant goes negative (the package ends up holding a negative and a positive quant of the same product). Commit 23613c63947 added a canPackSomeLines flag that is set to true for every package line that is not the scanned one, so any other package in the transfer makes the alreadyDonePackId && !canPackSomeLines guard false and silently skips the warning. The scanned package already exposes whether it had something left to pack through scannedPackages, so gating the warning on that flag instead keeps the check working regardless of how many other packages are in the transfer. https://github.com/odoo/enterprise/blob/3cc1a162e61662814b0e52c0c720831952d208a8/stock_barcode/static/src/models/barcode_picking_model.js#L1976-L2006 opw-6279105 Forward-Port-Of: odoo/enterprise#125229 Forward-Port-Of: odoo/enterprise#121755
This fix keeps embedded views aligned correctly when they appear at the top of a Knowledge article. It prevents a visual spacing issue caused by editor selection placeholders, preserving the intended layout for users editing Knowledge content.
Original PR description
This commit updates the embedded view top-alignment selector to account for selection placeholders introduced by https://github.com/odoo/odoo/commit/edf7f7bb0c62978640c181eccb4934855d5d872d. This preserves the intended top-alignment behavior when an embedded view is the first editable element in the knowledge editor. Task-5951196 Forward-Port-Of: odoo/enterprise#125080
This fix prevents the report editor from continuing to run after its display frame has been removed. It reduces crashes and test failures during report preview or editing, making the Studio report editing experience more reliable.
Original PR description
In the ReportEditorIframe component, the iframe may be removed at some point, to be replaced by another one. The problem is that the editor is destroyed only when the new iframe is loaded, so there…
In the ReportEditorIframe component, the iframe may be removed at some point, to be replaced by another one. The problem is that the editor is destroyed only when the new iframe is loaded, so there is a period of time in which the previous editor is alive, but the iframe is destroyed. It can causes issues with plugins, which assumes that we have a valid editable zone. For example, here is a common traceback:
test_print_preview (odoo.addons.web_studio.tests.test_report_editor.TestReportEditorUIUnit.test_print_preview)
Error received after termination: TypeError: Cannot read properties of null (reading 'getComputedStyle')
at http://127.0.0.1:8069/web/assets/e9a3359/web.assets_web.min.js:16264:290
at Array.filter (<anonymous>)
at ToolbarPlugin.getFilteredTargetedNodes (http://127.0.0.1:8069/web/assets/e9a3359/web.assets_web.min.js:16264:201)
at ToolbarPlugin._updateToolbar (http://127.0.0.1:8069/web/assets/e9a3359/web.assets_web.min.js:16259:83)
at http://127.0.0.1:8069/web/assets/e9a3359/web.assets_web.min.js:5325:117
The fix is to subscibe to the removal of the iframe, and destroy immediately the editor.Shopee order lines now show the SKU for the specific product variant instead of the general product template when variants are used. This makes order details clearer for sales and fulfillment teams and reduces confusion when reviewing Shopee orders.
Original PR description
Currently, _prepare_order_lines_values resolves SKU as `item_sku or model_sku`. Shopee always sends item_sku (product.template SKU), so when a listing has variants the order line description shows the template SKU ([item_sku]) even though the correct variant is linked via `model_sku`. task_id: 6335110 Forward-Port-Of: odoo/enterprise#124428 Forward-Port-Of: odoo/enterprise#124031
This fixes how the point-of-sale barcode lookup feature checks whether a user may create new products. The permission is now evaluated immediately and consistently, helping avoid incorrect product creation options appearing during POS workflows.
Original PR description
Replace the asynchronous `allowProductCreation` method with the `hasProductCreationAccess` getter to evaluate product creation permissions synchronously and ensure consistent behavior. Task-6361787 Related PR: https://github.com/odoo/odoo/pull/274420 Forward-Port-Of: odoo/enterprise#125237 Forward-Port-Of: odoo/enterprise#123073
AI tool failures caused by invalid automated inputs are now logged without long error tracebacks, reducing noise in system logs. Detailed traceback information remains available in debug logs for teams that need to investigate issues.
Original PR description
Tool failures from bad LLM arguments were logged at ERROR level with a full traceback, polluting the logs. I have changed the logger to log error not exception so we get rid of the traceback error added another debug logger to show the traceback also task-6250418 Forward-Port-Of: odoo/enterprise#124241 Forward-Port-Of: odoo/enterprise#120281
Delivery guides in Chilean localization no longer fail when a kit includes components measured differently from the kit product. The system now prices those component lines using their own product pricing, preventing unit conversion errors and allowing users to print delivery guides as expected.
Original PR description
When a kit is delivered, each component move is linked to the kit's sale order line. Pricing the delivery guide in "sale order" mode converted the component quantity into the kit's sale UoM. For a component sold in a different UoM category than the kit, this cross-category conversion raises a UserError. Steps to reproduce: - Create a BoM for a kit product with a component in a different UoM category - Create a customer with Delivery Guide Price = "From Sale Order" - Sold the kit in a sale order and deliver it - On the delivery, print the delivery guide -> error This fix makes the guide price for a component move to be "product" if the component's product is different from the related sale line product, avoiding the cross-category UoM conversion. opw-6327895 Forward-Port-Of: odoo/enterprise#125199 Forward-Port-Of: odoo/enterprise#122776
The asset Related Entries button is now labeled Related Items and opens directly as a list instead of leading users into an unhelpful journal item form. This makes reviewing the accounting items linked to an asset simpler and less confusing.
Original PR description
If you create an asset and confirm it, you can see the Related Entries using the smart button Related Entries. The list view that opens is clickable, but it opens a quite useless form view of the Journal Items. - Rename breadcrumb button to Related Items - Make it behave like action_account_moves_all, to not open form view Ticket: [6385260](https://www.odoo.com/odoo/project/967/tasks/6385260) Forward-Port-Of: odoo/enterprise#124672
This fixes an issue where companies using the Peru localization could be blocked from creating certificates when the Chile localization was also installed. The Chile-specific serial number requirement now applies only where appropriate, preventing unnecessary setup errors for other Latin American localizations.
Original PR description
With a l10n_pe company and having a l10n_cl company installed: - Try to create a certificate in the settings, there is a missing field error. The template certificate_certificate_view_form have a required subject_serial_number field in l10n_cl but it shouldn't in other latam localization. opw-6274126 Forward-Port-Of: odoo/enterprise#120211
The draft button in Uruguay electronic invoicing now returns a valid response when called remotely. This prevents an error that could interrupt users or integrations when resetting an invoice to draft.
Original PR description
Calling the method in RPC causes an error: ``` TypeError: cannot marshal None unless allow_none is enabled ``` Forward-Port-Of: odoo/enterprise#125285 Forward-Port-Of: odoo/enterprise#124653
Fixed an issue where closing a POS session could calculate a customer's remaining invoice amount incorrectly after a partial settlement. This prevents the POS from hiding settlement options or proposing and charging too much for outstanding invoices.
Original PR description
`pos_amount_unsettled` is a stored computed field defined as the invoice's residual minus the settle lines belonging to sessions that are not yet closed. Its compute method filters the lines on…
`pos_amount_unsettled` is a stored computed field defined as the invoice's residual minus the settle lines belonging to sessions that are not yet closed. Its compute method filters the lines on `order_id.session_id.state`, but that state is not in the compute dependencies. When closing a session holding a settle order, `_validate_session()` first reconciles the settle payment with the invoice (which lowers `amount_residual_signed` and flags the field for recomputation) and only then writes `state = 'closed'` on the session. If the pending recomputation is executed in that window (any flush of `account.move` does it: recomputing the field for any other flagged record drags the whole queue along), the settle line is deducted from the already reconciled residual, i.e. counted twice, and the field is stored as `residual - settled` instead of `residual`. Since the session state is not a dependency, writing `state = 'closed'` does not flag the field again and the wrong value is never corrected. The partner's `invoices_amount_due` then goes negative, which hides the "Settle invoices" option in the POS partner list and inflates the "Settle due amount" proposal (`remainingDue = total_due - pos_orders_amount_due - invoices_amount_due`): a customer owing e.g. 500 is proposed, and charged, 700. Steps to reproduce: 1. Post a customer invoice of 1000. 2. In the POS, select the customer > Settle invoices, pick the invoice, set the amount to 700 and pay in cash. 3. Close the session. The issue only occurs when the pending recomputation runs during the closing, which depends on the other operations performed by it (not deterministic in real usage; the regression test forces it with a flush after the reconciliation). 4. The invoice's "Amount To Pay In POS" shows -400 instead of 300 and the POS proposes to settle 700 instead of 300. Add the session state to the compute dependencies so that the field is recomputed once the session is closed, yielding the correct amount regardless of any intermediate recomputation. opw-6375095 Forward-Port-Of: odoo/enterprise#123783
Automated barcode tests for scrap operations were adjusted so entered quantities are kept correctly during screen updates. This reduces random test failures and helps keep inventory and manufacturing barcode workflows stable.
Original PR description
These barcode scrap tours randomly trigger "You can only enter positive quantities." on runbot: the quantity set with a raw input.value is dropped when the field re-renders before the scrap is saved, so it scraps 0. Dispatching an input event keeps the typed value. error-238911 Forward-Port-Of: odoo/enterprise#124952
Product managers can now use barcode lookup to automatically fill product details without needing full administrator access. This keeps product creation workflows efficient while avoiding unnecessary elevation of user permissions.
Original PR description
Currently when a user with a product manager rights that is not admin tries to look up the product with barcode information is not auto filled. ## Steps to replicate: - Install stock with demo data -…
Currently when a user with a product manager rights that is not admin tries to look up the product with barcode information is not auto filled. ## Steps to replicate: - Install stock with demo data - Barcode Database > Setup barcode lookup credentials - Users > Marc Demo > Give Marc Demo > Master Data > Products > Create - Login as `Marc Demo` - Products > Barcode: `850049670180` > Click anywhere else ## Observed Behaviour: Information on the product template is not autofilled, as it would be when using a System Admin user(Mitchell Admin). ## Root cause: This issue occurs because barcode lookup is gated behind a check for System Admin rights. Although users in the Product Manager group have permission to create products, they do not satisfy this condition, so the barcode lookup never executes at [1]. [1]- https://github.com/odoo/enterprise/blob/c66995fda83e19b28a38312af8efdc1601881cf0/product_barcodelookup/models/product_template.py#L17-L22 ## Why this is an issue: The original restriction (task [2] and commit [3]) was intended to limit barcode lookup to users who can create products, preventing unnecessary API calls. This was a valid assumption in 17.3-18.0, where creating products in POS required System Admin rights but now after commit [4] this is no longer the case. In v18, task [5] introduced the Product Manager group, making product creation independent of System Admin rights or module rights. Later, v18.3 exposed these Master Data access rights to non-debug users through commit [6]. As a result, there are users who are legitimately responsible for product creation and maintenance (regardless of POS usage) they can no longer use barcode lookup unless they are also granted full System Admin privileges, which provides broader access than required. ## Solution: Remove the group-based permission check so that access is determined solely by product edit permissions. This ensures that only users with the ability to modify products can use the API call, preserving the original security intent. As a result, users no longer need unnecessary administrative privileges toperform barcode lookups. [2]: https://www.odoo.com/odoo/project/49/tasks/3911024 [3]: https://github.com/odoo/enterprise/commit/444df3e48cb8d479d3b5d4a03a4bfefa48650910 [4]: https://github.com/odoo/odoo/commit/821bbc4504fd80a508e2412c7490ee60dd03f7b8 [5]: https://github.com/odoo/odoo/commit/d4886faf12ccaf63d5e899c20df2543d1ce046ab [6]: https://github.com/odoo/odoo/commit/e74eaf628498155243db73ea229eaf5e74c24f2a opw-6290999 Forward-Port-Of: odoo/enterprise#121915
Fixes an issue where testing a bank statement CSV import could fail because temporary records from the trial run were no longer available. This helps users validate bank statement imports reliably before applying them.
Original PR description
odoo/odoo#255059 made execute_import's savepoint flushing, so a dryrun rollback now properly invalidates the ORM cache instead of leaving it. That exposed a pre-existing bug here: we created the statement with line_ids pointing at .line records dryrun had already rolled back, raising "Record does not exist or has been deleted". To fix this issue we run as dryrun as False to allow the execute_import's savepoint do the work and rollbacked in finally. Steps to reproduce: - Just import a account.bank.statement.line OPW-6410352 Forward-Port-Of: odoo/enterprise#125389
Fixed an issue where importing a Chilean electronic tax document file containing multiple documents could put all invoice lines and references onto the first vendor bill. Each document is now handled separately, helping avoid incorrect bill totals and reconciliation problems.
Original PR description
When importing an EnvioDTE XML containing several DTEs (journal upload or incoming DTE mail server), one vendor bill is created per DTE, but the first bill receives the invoice lines and references…
When importing an EnvioDTE XML containing several DTEs (journal upload or incoming DTE mail server), one vendor bill is created per DTE, but the first bill receives the invoice lines and references of ALL the DTEs in the file, causing the total amount mismatch.
Cause: `_split_xml_into_new_attachments()` creates new attachments for the documents beyond the first one but leaves the original `file_data['xml_tree']` untouched; the decoder must scope itself to the first document (as l10n_it_edi and l10n_es_edi_facturae do), which `_l10n_cl_import_dte()` never did.
e.g. l10n_es_edi_facturae:633:
```python
# Only decode the first invoice of the Factura-e file.
tree = tree.xpath('//Invoice')[0]
```
Fix: scope the tree to the first DTE node before filling the bill. Kept behind a `len > 1` guard so files with a bare <DTE> root (matched by `xpath('//ns0:DTE')` but not by `findall('.//ns0:DTE')`) keep working.
Introduced in: https://github.com/odoo/enterprise/pull/75327.
opw-6378954
Forward-Port-Of: odoo/enterprise#124691Budget reports no longer time out when opened from budget records on databases with large accounting and purchasing volumes. The change makes report loading much faster by applying budget filters earlier, restoring usability for finance teams working with large budgets.
Original PR description
**Description** Opening the Budget Report from any budget record times out on databases with significant data volume. The request to `budget.report/formatted_read_grouping_sets` consistently times…
**Description**
Opening the Budget Report from any budget record times out on databases
with significant data volume. The request to
`budget.report/formatted_read_grouping_sets` consistently times out,
making the Budget Report completely unusable.
**Root cause:**
`budget.report` is an SQL view that consists of 5 UNION ALL branches.
When the list view loads, the ORM translates the `budget_analytic_id`
domain into a WHERE clause on the outer query wrapping the full UNION
ALL subquery. PostgreSQL cannot push this filter through a UNION ALL as
it's a hard optimization barrier. It must fully materialize the subquery
regardless of which budget is being viewed.
**Fix:**
Override _search on budget.report to extract budget_analytic_id and
budget_line_id conditions from the incoming domain using the Domain API.
budget_line_id is rewritten as Domain('id', op, value) so _to_sql()
correctly emits bl.id in the raw SQL. The resulting domain is injected
in context under budget_line_domain and read in _get_bl_query,
_get_aal_query (base module), and _get_pol_query (purchase module) to
filter budget_line rows inside each branch's LEFT JOIN ON clause.
This also removes the budget_report_budget_line_ids context key from
budget_line._compute_all, unifying both filters under one mechanism.
---
On customer DB (568k `account_analytic_line`, 27k `budget_line`,
116k confirmed `purchase_order_line`, 114k posted vendor bill lines
with purchase link):
| Budget | Before | After |
|---|---|---|
| 8 lines, 730d span | timeout | 2.27s |
| 14 lines | timeout | 2.39s |
| 14 lines, 1095d span | timeout | 1.63s |
- Before: https://explain.dalibo.com/plan/ehed5eb8de251426
- After: https://explain.dalibo.com/plan/db8aef35cag9hg6f
opw-6098047
Forward-Port-Of: odoo/enterprise#120707
Forward-Port-Of: odoo/enterprise#114692This fix ensures Colombian city postal codes with fewer digits are formatted correctly before being sent to the Envia delivery service. It helps prevent delivery failures for affected Colombian locations such as Antioquia, improving reliability for shipments to and from those cities.
Original PR description
Issue ----- Delivery does not always work from/to some cities in Colombia, like Antioquia. Cause ----- There was an oversight in fix 7654c55 where only 5 digit postal codes taken from the colombian…
Issue ----- Delivery does not always work from/to some cities in Colombia, like Antioquia. Cause ----- There was an oversight in fix 7654c55 where only 5 digit postal codes taken from the colombian localisation were padded in https://github.com/odoo/enterprise/blob/390acf532e8932fd9b9a708382a5e36cdbb35754/delivery_envia/models/envia_request.py#L726-L727 However, some of the colombian cities listed in `l10n_co_edi/data/res.city.csv` have 4 digit codes (like `SANTA FÉ DE ANTIOQUIA`, code `5042`). https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/l10n_co_edi/data/res.city.csv#L12 These 4 digit codes have to be right-padded to 5 characters before the left-padding to match the official colombian zip codes. See colombian gov official document (PDF download) where the code is actually `05042`. https://www.dane.gov.co/files/censo2005/provincias/subregiones.pdf ----- Ticket: opw-6248252 Forward-Port-Of: odoo/enterprise#123344 Forward-Port-Of: odoo/enterprise#120164
This fixes how the French VAT report fills the BA zone so it uses the required free-text field format instead of a numeric value. The change helps ensure generated VAT reports comply with the expected French reporting structure and reduces filing errors.
Original PR description
The value inside the BA zone needs to be a "TexteLibre1" and not a value no task id Forward-Port-Of: odoo/enterprise#125335
The timesheet percentage now stays current as users add, edit, or remove timesheet entries. This avoids confusion from outdated percentages remaining visible until the page is reloaded.
Original PR description
Issue: The percentage is only updated after reloading the page. Cause: The percentage computation is performed inside `loadTimesheets`, which is only called when the timesheets are loaded. Fix: Move the percentage computation into a helper function and invoke it whenever a timesheet is added, updated, or removed. task-6401186 Forward-Port-Of: odoo/enterprise#125312 Forward-Port-Of: odoo/enterprise#125074
Applying engineering change orders with attached documents now uses the correct attachment reference, preventing errors during the Apply Changes step. This helps manufacturing and PLM users complete product revision updates reliably when documents are involved.
Original PR description
When applying an ECO, `action_apply` copies each ECO document onto the product template and fills `origin_attachment_id` with `attach.id`. That field is a many2one to `ir.attachment`, but `attach` is a `product.document`. Steps to reproduce: - Create an `mrp.eco` record and start a new revision - Upload a document on the ECO, note its product.document id - Make sure no ir.attachment exists with that same id - Move the ECO to its final stage and hit "Apply Changes" - Observe the error The very same change was already applied on master by 3a39186f883, but was never backported. opw-6387343 Forward-Port-Of: odoo/enterprise#124950
The employee Documents button now correctly counts and opens signed contract documents, even when they are linked through employee contract versions. This helps HR users reliably find completed employee contract paperwork from the employee record.
Original PR description
[FIX] documents_{hr|sign}: employee docs button for signed contracts Bug reproduction: 1 - In saas-19.4, install documents_hr and hr_contract_salary with demo data 2 - As Mitchell Admin, go to…
[FIX] documents_{hr|sign}: employee docs button for signed contracts
Bug reproduction:
1 - In saas-19.4, install documents_hr and hr_contract_salary with demo data
2 - As Mitchell Admin, go to Employees, open one, click on "Offers - New"
3 - Select employee_contract.pdf as PDF Template
4 - Use the button "Salary configurator" to fill in the configurator, review it and sign it.
5 - Go back to the backend, find the contract in Sign and sign it.
6 - Go back to the Employee form view, the Documents stat button shows 0 document when it should be 1.
7 - Click the stat button and you see 0 documents in Documents when there should be one.
Bug cause:
1 - The document is created for the employee in documents app
but smart button cannot open those
2 - The res_model of the documents.document is hr.version for signed doc
-> it is not hr.employee
3 - In current implementation:
3.1 -> only hr.employee's documents appear after that smart button
Bug solution:
1 - _compute_document_count is reimplemented:
-> to count also documents with res_model as hr.version
2 - override _get_documents_domain:
-> to add version domain as an alternative with OR
-> to get documents with res_model='hr.version'
Test:
1 - Unit test is added
2 - Create documents with the archived versions of the employee
-> and observe the document count of the employee
Note:
-> Also, we changed the final document name in documents of the employee
task-6373620
Forward-Port-Of: odoo/enterprise#123763Users can now rename Studio fields with labels written in Arabic or other non-Latin scripts without triggering an invalid field name error. This prevents a confusing failure when creating or editing fields for multilingual users, while keeping the existing technical field name when a safe new one cannot be generated.
Original PR description
Steps: - Install web_studio - Add any field (example char field) to any view - Rename it in arabic, example `السَّلَامُ عَلَيْكُمْ` - Error Custom field names cannot contain double underscores Webclient (view_editor_model) escape every non-alphabetic chars, so new label value contains nothing but a space which will be replaced by a _ this new label value will be concatenated to `x_studio_`. Resulting to the string `x_studio__`. A solution should be to prevent changing the technical name if the new label value (escaped) is empty. opw-6311027 Forward-Port-Of: odoo/enterprise#125299 Forward-Port-Of: odoo/enterprise#121343
Account reports opened from the VAT return check screen no longer fail after a browser refresh. This prevents users from losing access to the report view due to missing page information in the refreshed URL.
Original PR description
Opening an account report through the VAT return button on an account.return.check record returns an inline client action whose report_id only exists in context. On refresh, Odoo will throw an error because it will try to rebuild the action context based off of the URL which is deficient. This will not effect reports opened via the menu since those follow a different pathway. This fix anchors the inline action to the "path" property stored on the client action. A helper method was added for deriving the action_id from a given report. opw-6366964 Forward-Port-Of: odoo/enterprise#125246 Forward-Port-Of: odoo/enterprise#124560
The My Planning calendar now visually marks draft planning entries with the expected hatched style. This helps users quickly distinguish draft plans from confirmed ones and reduces confusion when reviewing schedules.
Original PR description
Issue: Calendar entries appear plain even when they should appear hatched. (ex. while in draft status) Steps to reproduce: If you create any planning and set it to draft. Then go to Planning > Planning > My Planning, the newly created plan should be in hatched but it becomes plain. Cause: In the view planning.slot.my.calendar there was missing the element that causes the views to become hatched when in draft status. Solution: Added said element. opw-6260055 Forward-Port-Of: odoo/enterprise#119153
Code cleanup and technical improvements
This change updates several Odoo Enterprise apps to work with the newer web interface framework. It is mainly an internal compatibility cleanup that helps keep fields, widgets, and patched components working reliably without changing business workflows.
Original PR description
Owl 3 turns a component's `props` into an instance field built by `useProps(schema)`, so the static `SomeComponent.props` attribute no longer resolves. The web components whose schema was read from here now export it as a const, so spread that const instead:
static props = { ...Many2OneField.props }
props = useProps({ ...many2OneFieldProps })
The owl2 descriptors used by the overriding components are translated to the new `t.*` schema at the same time, and subclasses that only re-declared the parent schema without adding anything simply drop their declaration and inherit it.
Patches that used to extend a component's props through `patch(Comp, {props})` now extend the exported schema directly, since patching the static attribute no longer has any effect.7 changes
Resolved issues and error corrections
Fixes an error that could appear when editing analytic distribution information on employee records with analytic accounting enabled. The change stops tracking a field type that the system cannot safely track, improving stability for payroll accounting users.
Original PR description
This commit partially reverts [1] To reproduce the issue: 1. Enable analytic accounting 2. Try to edit the analytic distribution field on an Employee Error: a traceback appears Commit [1] makes a JSON field tracked, which is forbidden: https://github.com/odoo/odoo/blob/2aa35eb9c7a709126dca65e81ca6e823706fbb19/addons/mail/models/mail_tracking_value.py#L172 We cancel the tracking part of [1] so the production versions will follow the code on master: the field `analytic_distribution` will be both whitelisted and untracked, as done by [2]. [1] https://github.com/odoo/enterprise/commit/88a3e70bba20c2d508f8970d31ce6ee7afd11ee4 [2] https://github.com/odoo/enterprise/commit/55bec464e3861d5023f7e78588142ddc22d500d8 opw-6405122 opw-6416523 opw-6412398 opw-6411399 opw-...
The Stripe expense cardholder field has been corrected so it uses the standard selection behavior. This ensures filters set in the view are properly applied, helping users see only the relevant cardholders when entering expenses.
Original PR description
After https://github.com/odoo/odoo/issues/196785; the standard way to build a custom m2o field in JS is to call a method from the Many2one module, instead of extending an object from it. This commit solves issues regarding domain in the view not being passed to the widget opw-6399906
This update prevents an error that could occur when multiple equity transactions were processed at the same time. It improves reliability for users working with cap tables and equity transaction records.
Original PR description
When the ``_compute_security_price`` method is called on multiple records, a traceback will appear. Traceback: ```py ValueError: Expected singleton: equity.transaction(1, 2) ``` https://github.com/odoo/enterprise/blob/314a79b774f30dc9377b2971492576c4b84483e1/equity/models/equity_transaction.py#L218 The method filters newly created records using ``self._origin.id``. Since ``self`` is the whole recordset, accessing ``self._origin.id`` on multiple records raises a singleton error. sentry-7626410485
This fix prevents a test helper for appointment CRM flows from affecting later steps unexpectedly. It keeps automated validation more reliable, reducing false failures or hidden side effects in quality checks.
Original PR description
Capturing `oldWriteText` at module import and relying on a subsequent tour step to restore it can cause state leakage if the subsequent step doesn't exactly target a resulting effect of the mocked `writeText` call. Refactor the tour step to capture `writeText` dynamically and restore the original method on first call. runbot-241004
Deleting a middle quality check in a manufacturing work order now keeps the remaining checks properly connected. This prevents later quality checks from disappearing on the shop floor, helping operators continue inspections without missing required steps.
Original PR description
Steps to reproduce the bug: - Create a BOM for product P1 with one work order WO1 - Create 3 quality points linked to WO1 via the `operation_id` field - Confirm a manufacturing order for P1: - 3…
Steps to reproduce the bug:
- Create a BOM for product P1 with one work order WO1
- Create 3 quality points linked to WO1 via the `operation_id` field
- Confirm a manufacturing order for P1:
- 3 quality checks A → B → C are generated
- Open the shop floor for the work order:
- Observe that all 3 quality checks are displayed
- Delete quality check B (the middle one)
- come back to the shop floor for the work order:
- Observe that quality check C is no longer displayed in the shop floor
Problem:
After deleting check B, check C disappeared from the shop floor. Quality checks are stored as a doubly-linked list via the `next_check_id` and `previous_check_id` fields on `quality.check`. The shop floor JS (`mrp_display_record.js`) traverses this list starting from the check with no `previous_check_id`, then follows `next_check_id` until the chain ends. When check B was deleted, it nullified the FK references pointing to it, leaving check A with `next_check_id = False` and check C with `previous_check_id = False`. The traversal from A therefore stopped immediately, and C was never reached.
No `unlink` override existed on `quality.check` to repair the chain before deletion.
Solution:
Added an `unlink` override that, before deleting each check, reconnects its predecessor and successor: if the deleted check has both a previous and a next, `prev.next_check_id` is set to `next` and `next.previous_check_id` is set to `prev`, preserving a valid chain for the remaining checks.
opw-6369298This fixes an issue where Avalara tax fields could disappear on customer or vendor contacts in Canada when using a US company setup. Businesses using Avalara can now see and maintain the correct tax codes, partner codes, and exemption details for affected contacts.
Original PR description
**Steps to reproduce:**
- Install Accounting and account_avatax
- Use a US company (by default)
- Create a contact with Canada as country
**Issue:**
In "Sales & Purchase" tab, all the fields from avatax module are not displayed (i.e. "Avalara Code", "Avalara Partner Code", "Avalara Exemption").
**Cause:**
The `invisible` property of those fields is using `fiscal_country_codes` char field.
If no company is set on the record, `fiscal_country_codes` will contain the country code of the selected companies in addition to the country code of the record.
In this case, the value of `fiscal_country_codes` will be `US,CA` string, which triggers `fiscal_country_codes not in ('US', 'CA')` invisible condition.
opw-6328395
Forward-Port-Of: odoo/enterprise#124619Trash cleanup now skips deleted document records whose attachments are still needed by signed documents. This prevents the automated cleanup job from failing and helps keep the database trash clearing normally for all users.
Original PR description
### Before this PR sign.document.attachment_id is an ondelete='restrict' foreign key. When a trashed documents.document shares its attachment with a sign.document, the trash autovacuum _gc_clear_bin unlinks the document, cascades to the ir.attachment, and hits that constraint: ``` update or delete on table "ir_attachment" violates foreign key constraint "sign_document_attachment_id_fkey" on table "sign_document" ``` The autovacuum aborts on the first such record, so the trash stops being cleared for every user on the database. The existing override already skips documents whose res_model is sign.request or sign.document. It misses the shared-attachment case: a document can hold that attachment while its own res_model stays empty or points elsewhere, so the res_model filter never catches it. ### After this PR No error raised during garbage collector because trashed attachment linked to a sign.document are not catched by garbage collector
7 changes
Resolved issues and error corrections
**Description of the issue/feature this PR addresses:** [FIX] website_sale: preserve parent company link on address update When a portal user linked to a company (B2B) edits their address during website checkout, the backend partner form subsequently loses the visual link to their parent company and incorrectly displays a "Create company" button instead. This occurs because the checkout form submits the company name as a raw text string (`company_name`). This string gets passed in t
Original PR description
**Description of the issue/feature this PR addresses:** [FIX] website_sale: preserve parent company link on address update When a portal user linked to a company (B2B) edits their address during…
**Description of the issue/feature this PR addresses:**
[FIX] website_sale: preserve parent company link on address update
When a portal user linked to a company (B2B) edits their address during
website checkout, the backend partner form subsequently loses the visual
link to their parent company and incorrectly displays a "Create company"
button instead.
This occurs because the checkout form submits the company name as a raw
text string (`company_name`). This string gets passed in the payload and
is written to the contact's record. In the backend `res.partner` form
view, the presence of data in the `company_name` field triggers UI
modifiers that hide the `parent_id` relational field and switch to the
B2C company creation flow.
This commit resolves the issue by conditionally removing `company_name`
from the payload if the user already has a `parent_id`. This ensures the
raw text is safely ignored for B2B users, keeping the backend UI intact
while preserving the expected behavior for unlinked B2C users.
opw-6374326
**Steps to Reproduce:**
- Contacts > New
- Set type to “Company”, any name, any Tax ID
- (On same page) > Contacts & Addresses > Add
- Set type to “Contact”, set any name/email
- Access the previously created (individual) contact > settings/gear icon > grant portal access > Grant Access
- Access the (individual) contact user form > settings/gear icon > Change Password > (any)
- Log in as portal user > add item to cart > checkout > Modify address and save
- Access the created (individual) contact again
- Observe “Create company” button despite partner_id being set. In addition, the company name is shown correctly, but no link appears
**Current behavior before PR:**
- When a portal user linked to a company edits their address during website checkout, the backend partner form stores the company_name field and hides the link to the parent company while displaying a "Create company" button
**Desired behavior after PR is merged:**
- Portal users linked to a company should be able to edit their address without losing UI links to the parent company in the partner form### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/6a6cc73650 [REL] 18.0.76 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/5832d8abe3 [FIX] HeaderVisibility: fix `getNextVisibleCellPosition` getter [Task: 6340589](https://www.odoo.com/odoo/2328/tasks/6340589) https://github.com/odoo/o-spreadsheet/commit/c93ad33981 [FIX] edition: do not change edition if not editing [Task: 6340589](https://www.odoo.com/odoo/2328/tasks/
Original PR description
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/6a6cc73650 [REL] 18.0.76 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0)…
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/6a6cc73650 [REL] 18.0.76 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/5832d8abe3 [FIX] HeaderVisibility: fix `getNextVisibleCellPosition` getter [Task: 6340589](https://www.odoo.com/odoo/2328/tasks/6340589) https://github.com/odoo/o-spreadsheet/commit/c93ad33981 [FIX] edition: do not change edition if not editing [Task: 6340589](https://www.odoo.com/odoo/2328/tasks/6340589) Co-authored-by: Florian Damhaut (flda) <flda@odoo.com> Co-authored-by: Anthony Hendrickx (anhe) <anhe@odoo.com> Co-authored-by: Alexis Lacroix (laa) <laa@odoo.com> Co-authored-by: Lucas Lefèvre (lul) <lul@odoo.com> Co-authored-by: Adrien Minne (adrm) <adrm@odoo.com> Co-authored-by: Ronak Mukeshbhai Bharadiya (rmbh) <rmbh@odoo.com> Co-authored-by: Dhrutik Patel (dhrp) <dhrp@odoo.com> Co-authored-by: Rémi Rahir (rar) <rar@odoo.com> Co-authored-by: Pierre Rousseau (pro) <pro@odoo.com> Co-authored-by: Vincent Schippefilt (vsc) <vsc@odoo.com> Co-authored-by: Marceline Thomas (matho) <matho@odoo.com>
Version: -------- - 18.0+ Steps to reproduce: ------------------- - Install `stock` module - Configure a multi-company environment with a `Main Company` and a `Secondary Company` - Go to the setting enable Lots & Serial Numbers and switch into `Secondary Company` - Create a warehouse for the Secondary Company - In the Secondary Company, create a lot-tracked storable product - Create and validate a delivery for that product - Open the Traceability Report - Print the report Is
Original PR description
Version: -------- - 18.0+ Steps to reproduce: ------------------- - Install `stock` module - Configure a multi-company environment with a `Main Company` and a `Secondary Company` - Go to the setting…
Version:
--------
- 18.0+
Steps to reproduce:
-------------------
- Install `stock` module
- Configure a multi-company environment with a `Main Company`
and a `Secondary Company`
- Go to the setting enable Lots & Serial Numbers and switch into
`Secondary Company`
- Create a warehouse for the Secondary Company
- In the Secondary Company, create a lot-tracked storable product
- Create and validate a delivery for that product
- Open the Traceability Report
- Print the report
Issue:
------
The report header always displays the Main Company, even though the
traceability report belongs entirely to the Secondary Company.
Cause:
------
https://github.com/odoo/odoo/blob/2d54db3ac0b6d807e580315e2633f3e2b10a700c/addons/stock/static/src/client_actions/stock_traceability_report_backend.xml#L9
Clicking Print calls onClickPrint(), which builds the PDF URL and
downloads it with download() (a plain XMLHttpRequest POST), landing on
the `type='http'` route `/stock/<output_format>/<report_name>`
https://github.com/odoo/odoo/blob/3bd6b10c3f9ad8d93062b6b46490500edb8c9697/addons/stock/static/src/client_actions/stock_traceability_report_backend.js#L125-L134
That controller calls stock.traceability.report.get_pdf() without ever setting
`company_id` in the rendering context.
https://github.com/odoo/odoo/blob/3bd6b10c3f9ad8d93062b6b46490500edb8c9697/addons/stock/controllers/main.py#L23
Inside `get_pdf()`, the report header is rendered by passing an `rcontext`
dict to `web.internal_layout`.
That template resolves the company to display using the following priority:
https://github.com/odoo/odoo/blob/3bd6b10c3f9ad8d93062b6b46490500edb8c9697/addons/web/views/report_templates.xml#L805-L816
1. `company_id` — an explicit company record in the render context
2. `o.company_id` — the company of the document object `o`
3. `res_company` — the fallback, injected by `_render_template()` as
`self.env.company`
Because `get_pdf()` never sets `company_id` or `o` in `rcontext`, the
template always falls through to `res_company`.
https://github.com/odoo/odoo/blob/3bd6b10c3f9ad8d93062b6b46490500edb8c9697/odoo/addons/base/models/ir_actions_report.py#L770
This is populated by `ir.actions.report._render_template()`
as `self.env.company`, which resolves to the first company in
the user's `allowed_company_ids` list — typically the main company
regardless of which company owns the lot,
picking, or stock moves being printed.
As a result, the report content belongs to the secondary company while the
header always shows the main company.
Fix:
----
Resolve the company from the record on which the traceability report is
opened (using `active_model` and `active_id`) and pass it explicitly as
`company_id` when rendering the report.
`web.internal_layout` already gives precedence to an explicit
`company_id` over the default `res_company`, ensuring the report header
always displays the company that owns the traced record.
When the record has no company set, the header falls back to
`res_company`. Since the print request is a raw `type='http'` download
that never receives the company switcher's context, `user.context`
(holding `allowed_company_ids`) is now forwarded in the download POST
and merged into the environment by the controller - as done in
`web/controllers/report.py` - so the fallback resolves to the currently
active company instead of the user's default one.
<details>
<summary>Click here to see the results:</summary>
<p><strong>Before:</strong></p>
<div class="image-row">
<img src="https://github.com/user-attachments/assets/7e3a5d65-9114-4bce-9139-a88cff7c261f" />
</div>
<p><strong>After:</strong></p>
<div class="image-row">
<img src="https://github.com/user-attachments/assets/0a105f80-b6ae-400d-a787-fb8706d5f519" />
</div>
</details>
---
opw-6345446
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prCurrentyl the unsupported models will be checked like the following ```sql ia.res_model NOT IN ARRAY['model1', 'model2'] ``` This causes a syntax error. Use `ANY` to avoid the issue ```sql ia.res_model != ANY(ARRAY['model1', 'model2']) ``` Reproduce in Odoo shell ```python from odoo.tools import SQL query = SQL(""" SELECT ia.id FROM ir_attachment ia WHERE ia.res_model NOT IN %(unsupported_models)s LIMIT 1; """, unsupported_models=self.env['ir.atta
Original PR description
Currentyl the unsupported models will be checked like the following
```sql
ia.res_model NOT IN ARRAY['model1', 'model2']
```
This causes a syntax error. Use `ANY` to avoid the issue
```sql
ia.res_model != ANY(ARRAY['model1', 'model2'])
```
Reproduce in Odoo shell
```python
from odoo.tools import SQL
query = SQL("""
SELECT ia.id
FROM ir_attachment ia
WHERE ia.res_model NOT IN %(unsupported_models)s
LIMIT 1;
""",
unsupported_models=self.env['ir.attachment']._get_cloud_storage_unsupported_models(),
)
```
opw-6404861Issue: Compare to lot and serial number package are not multi company. It means that the package don't pass from a company to the other. So when a company deliver to another. The delivery will create a quant with the package. However the receipt in the other company will create a new quant without package (or a new package). It means that the quants are never reconcile and it could become difficult to understand what remains in intercompany location and what are artifact from past movements.
Original PR description
Issue: Compare to lot and serial number package are not multi company. It means that the package don't pass from a company to the other. So when a company deliver to another. The delivery will create a quant with the package. However the receipt in the other company will create a new quant without package (or a new package). It means that the quants are never reconcile and it could become difficult to understand what remains in intercompany location and what are artifact from past movements. In order to fix it, we introduce a new system parameter to directly unpack after the delivery. This way the receipt is always without source package and will automatically decrease the quant. opw-6376983
**STEP TO REPRODUCE** 1. Install l10n_fr_pdp and select the french company. 2. Go on a contact form, under invoicing, select 'by Approved Platform' for invoice sending. 3. Click on the eInvoice format selection, and notice the format 'France E-invoicing (UBL 2.1)' is not there. Note: with other invoice sending values, it shows up. **CAUSE** In the `_get_ubl_cii_formats_info()` override in `l10n_fr_pdp`, we declare the ubl_21_fr format as not being usable with the peppol invoice sending me
Original PR description
**STEP TO REPRODUCE** 1. Install l10n_fr_pdp and select the french company. 2. Go on a contact form, under invoicing, select 'by Approved Platform' for invoice sending. 3. Click on the eInvoice format selection, and notice the format 'France E-invoicing (UBL 2.1)' is not there. Note: with other invoice sending values, it shows up. **CAUSE** In the `_get_ubl_cii_formats_info()` override in `l10n_fr_pdp`, we declare the ubl_21_fr format as not being usable with the peppol invoice sending method. However, the Approved Platform invoice sending (used to send ubl_21_fr) *is* the peppol invoice sending method in disguise. (we reused the peppol invoice sending method because pdp and peppol are very similar). opw-6387796
Currently, sending a simplified invoice (`TD07`) to the Italian Tax Agency fails when an invoice line contains multiple taxes. **Steps to reproduce:** - Install the `l10n_it_edi_withholding` module and switch to an IT Company. - Create a new customer and set only the country to Italy and the Tax ID. - Create a new invoice for that customer. - Add a line with `22%` and `4% INPS` taxes. - Go to the `Electronic Invoicing` tab, set the `Document Type` to `TD07 - Simplified invoice`, and c
Original PR description
Currently, sending a simplified invoice (`TD07`) to the Italian Tax Agency fails when an invoice line contains multiple taxes. **Steps to reproduce:** - Install the `l10n_it_edi_withholding` module…
Currently, sending a simplified invoice (`TD07`) to the Italian Tax Agency fails when an invoice line contains multiple taxes. **Steps to reproduce:** - Install the `l10n_it_edi_withholding` module and switch to an IT Company. - Create a new customer and set only the country to Italy and the Tax ID. - Create a new invoice for that customer. - Add a line with `22%` and `4% INPS` taxes. - Go to the `Electronic Invoicing` tab, set the `Document Type` to `TD07 - Simplified invoice`, and confirm the invoice. - Try to `Send To Tax Agency`. **Error:** `Node: <Natura t-if="line.tax_ids.l10n_it_exempt_reason" t-out="line.tax_ids.l10n_it_exempt_reason"/>` `ValueError: Expected singleton: account.tax(102, 3)` **Root Cause:** At [1], the code accesses `line.tax_ids.l10n_it_exempt_reason`, but when an invoice contains multiple taxes, causing an error. **Fix:** This commit prevents the error and ensures the user can send a simplified invoice by applying a fix similar to [2]. [1]: https://github.com/odoo/odoo/blob/230483ffd7d8674cd6bf98a4ffb6591f755422e0/addons/l10n_it_edi/data/invoice_it_simplified_template.xml#L14 [2]: https://github.com/odoo/odoo/blob/230483ffd7d8674cd6bf98a4ffb6591f755422e0/addons/l10n_it_edi/data/invoice_it_template.xml#L28-L181 Ticket [link](https://www.odoo.com/odoo/project.task/6354138) Ticket [link](https://www.odoo.com/odoo/project.task/6379377) opw-6354138 opw-6379377 Forward-Port-Of: odoo/odoo#273823
1 change
Resolved issues and error corrections
## Description When validating an invoiced order in PoS Restaurant, an intermittent `undefined: Backend Invoice` error can occur if the user validates the order before the draft synchronization has completed. This issue is difficult to reproduce consistently because it depends on network latency and the timing of user interactions. ### Steps to Reproduce 1. Open a PoS Restaurant session. 2. Add products to an order. 3. Click **Order** to start synchronizing the draft order. 4. Imm
Original PR description
## Description When validating an invoiced order in PoS Restaurant, an intermittent `undefined: Backend Invoice` error can occur if the user validates the order before the draft synchronization has…
## Description
When validating an invoiced order in PoS Restaurant, an intermittent `undefined: Backend Invoice` error can occur if the user validates the order before the draft synchronization has completed.
This issue is difficult to reproduce consistently because it depends on network latency and the timing of user interactions.
### Steps to Reproduce
1. Open a PoS Restaurant session.
2. Add products to an order.
3. Click **Order** to start synchronizing the draft order.
4. Immediately click **Payment**.
5. Enable **Invoice** (select a customer if needed).
6. Click **Validate** before the draft synchronization finishes.
7. Under slow or unstable network conditions, the payment validation may fail with:
```
undefined: Backend Invoice
```
## Root Cause
During payment validation, `_finalizeValidation()` calls `push_single_order()` to synchronize the current order before creating the invoice.
In PoS Restaurant, `sendDraftToServer()` synchronizes draft orders asynchronously without acquiring `pushOrderMutex`, while `push_single_order()` performs synchronization while holding the mutex. Although both methods share the `syncingOrders` set, they are not synchronized through the same locking mechanism, allowing them to race.
The race happens as follows:
1. `sendDraftToServer()` starts synchronizing the draft order and adds its ID to `syncingOrders`.
2. Before it finishes, the user clicks **Validate**.
3. `_finalizeValidation()` calls `push_single_order()`, which invokes `_save_to_server()`.
4. Since the order is already in `syncingOrders`, `_save_to_server()` skips it and returns an empty array (`[]`).
5. The existing code only checks `!syncOrderResult`. Since an empty array is truthy in JavaScript, execution continues.
6. `_finalizeValidation()` then accesses `syncOrderResult[0]?.account_move`, where `syncOrderResult[0]` is `undefined`, resulting in the `undefined: Backend Invoice` error.
## Fix
Check that the synchronization result is both defined **and non-empty** before accessing its first element.
### Before
```javascript
if (!syncOrderResult) {
return;
}
```
### After
```javascript
if (!syncOrderResult || !syncOrderResult.length) {
return;
}
```
If `push_single_order()` returns an empty array, `_finalizeValidation()` exits early instead of attempting to access `syncOrderResult[0]`, preventing the exception.
This patch does **not** remove the underlying race condition; it simply handles the empty synchronization result safely.
## Notes
* This issue only affects **17.0**, where synchronization relies on `createFromUi()`.
* In **18.0**, the synchronization flow was redesigned around `syncFromUi()` and local model updates, so this specific race condition no longer occurs.
## Reproduction Videos
The issue is timing-dependent and requires slow network conditions together with rapid user interactions. After multiple attempts, it was successfully reproduced several times on Runbot.
1. [Reproduction Attempt 1](https://drive.google.com/file/d/1-KmaTiCErwv_OsWxYdmCvRUSI9oY3FOF/view?usp=sharing)
2. [Reproduction Attempt 2](https://drive.google.com/file/d/1MSG57nhZXfrAv1wuEkRbsmLstW5Hk9jg/view?usp=sharing)
3. [Reproduction Attempt 3](https://drive.google.com/file/d/1fXdyfNKUgJLTrrDZTi_FXuCmupBL3x-f/view?usp=sharing)
opw-6367134