Wednesday, August 12, 2026
28 changes · saas-19.2
Enhancements to existing features
Before this commit, when importing and invoice/bill, we predicted the invoice line account based on previous invoices/bills. If the predicted account had default tax, it was ignored during tax matching. With this commit, first checks whether the predicted account has a default tax. If it finds one that matches the tax percentage from the imported XML, that tax is applied. Otherwise, or if the account has no default tax, the existing tax matching logic is used. task-6345661 Forward-Po
Original PR description
Before this commit, when importing and invoice/bill, we predicted the invoice line account based on previous invoices/bills. If the predicted account had default tax, it was ignored during tax matching. With this commit, first checks whether the predicted account has a default tax. If it finds one that matches the tax percentage from the imported XML, that tax is applied. Otherwise, or if the account has no default tax, the existing tax matching logic is used. task-6345661 Forward-Port-Of: odoo/odoo#281424 Forward-Port-Of: odoo/odoo#279940
Resolved issues and error corrections
This update adds a safeguard to verify that Indian GSTR-1 reports choose the correct tax rate group when GST and CESS taxes are used together. It helps reduce the risk of incorrect tax reporting in scenarios involving combined Indian indirect taxes.
Original PR description
This PR adds a test case to ensure that the correct tax rate group is selected in the GSTR-1 report when a combination of GST and CESS taxes is used. Community PR - https://github.com/odoo/odoo/pull/280571
Miscellaneous changes
- Compute the standard durations for all French leaves in a single `_get_durations()` call instead of recomputing them for each leave. - Reuse the precomputed duration mapping while calculating the French legal duration for each leave. - Keep the existing French-specific duration calculation unchanged, including public holidays, company calendar, date extension, and half-day handling. This avoids repeated ORM computations when processing multiple French leaves in a batch an
Original PR description
- Compute the standard durations for all French leaves in a single `_get_durations()` call instead of recomputing them for each leave. - Reuse the precomputed duration mapping while calculating the…
- Compute the standard durations for all French leaves in a single `_get_durations()` call instead of recomputing them for each leave. - Reuse the precomputed duration mapping while calculating the French legal duration for each leave. - Keep the existing French-specific duration calculation unchanged, including public holidays, company calendar, date extension, and half-day handling. This avoids repeated ORM computations when processing multiple French leaves in a batch and significantly improves the performance of leave duration computation. Performance testing was performed using the `hr.leave.employee.report` introduced in 19.1, which calls `_get_durations()` on a large batch of virtual leaves. Performance testing on a database containing 677 leaves, including 298 French leaves: | Metric | Before | After | |------------------------------------|-----------------|-------------| | Standard duration computations | 298 | 1 | | Total `_get_durations()` | >169s (timeout) | ~24s | not specific to the employee report and benefits any caller that invokes _get_durations() on a larger batch. **opw-6421323** --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281165
Users can now open Bank Matching from a working file return even when no bank journal is selected. This prevents an error screen and lets staff continue reconciling bank statement lines from that workflow.
Original PR description
When accessing the reconciliation widget from the working file check, there is no journal to be selected, hence no journal in the context. This was tracebacking since we were trying to send a read query to the server with an undefined id. To reproduce: * create a bank statement line without reconciling * set up the return on the misc journal * open the return, then "Bank Matching" Forward-Port-Of: odoo/enterprise#127421
This update corrects a small issue in the Swiss payroll transmission process where the current date could be calculated without the proper context. It helps avoid errors during payroll-related submissions and keeps Swiss payroll workflows running reliably.
Original PR description
Fix https://github.com/odoo/enterprise/pull/126718 Forward-Port-Of: odoo/enterprise#127535
This fix prevents an error when a product on a confirmed delivery is later changed into a kit. Kenyan OSCU stock reporting now uses the actual component moves processed, so deliveries can be completed without interruption.
Original PR description
When a stock move's product is turned into a kit after the transfer was confirmed, it explodes it into its component moves and unlinks the original one: https://github.com/odoo/odoo/blob/f59783d43f891fea14d03f67d7c017d7ffbbe5a7/addons/mrp/models/stock_move.py#L358-L363 https://github.com/odoo/odoo/blob/f59783d43f891fea14d03f67d7c017d7ffbbe5a7/addons/mrp/models/stock_move.py#L400 The `_action_done()` override of `l10n_ke_edi_oscu` localisation called `super()` first and then used `self.filtered(...)` on the pre-explosion recordset, which could still reference the now-deleted move, raising a `MissingError`: https://github.com/odoo/enterprise/blob/ee7e6894ed313db844aeff5ba5e19de3ad94898e/l10n_ke_edi_oscu_stock/models/stock_move.py#L96-L99 Use the `super()` return value instead, which reflects the moves that were actually processed. runbot-243291 Forward-Port-Of: odoo/enterprise#127027
This fixes an issue where Swiss payroll settings could assign a Swiss contract type to employees outside Switzerland. The change prevents incorrect contract information from appearing and keeps automated checks stable across versions.
Original PR description
[FIX] l10n_ch: fix default contract type This task is runbot error fix that occured from 19.0 to 19.2 Bug reproduction: 1 - Go to version 19.0, install l10n_ch_hr_payroll_account 2 - Execute…
[FIX] l10n_ch: fix default contract type
This task is runbot error fix that occured from 19.0 to 19.2
Bug reproduction:
1 - Go to version 19.0, install l10n_ch_hr_payroll_account 2 - Execute test_version_timeline_auto_save_tour tour test 3 - It fails in .o_arrow_button_wrapper[data-tooltip^='Contract:'] step
Bug cause:
1 - When l10n_ch_hr_payroll_account is installed:
1.1 - contract type becomes "Permanent contract with monthly salary"
1.2 - the employee is not swiss but it has this CH contract type
2 - data-tooltip starts with Permanent contract instead of contract
2.1 - Tour fails
3 - contract_type_id is overwritten in swiss modules
3.1 - Default is assigned without looking to the country of self.env
Bug solution:
1 - If the country is not swiss, the default is assigned as False
1.1 -> fixed in l10n_ch_hr_payroll/hr_version
1.2 instead of assigning swiss contract type to the non-swiss emp.
Note: This is fix from saas-18.4 to master.
task-6392040
runbot error: https://runbot.odoo.com/odoo/runbot.build.error/941358
Forward-Port-Of: odoo/enterprise#126520Currently, the is_base_affected condition is only checked on the group tax. However, this condition should also be checked on the child taxes to ensure proper matching. Without checking the child taxes, incorrect matches can occur when the parent tax has is_base_affected set to True, while one of its child taxes has it set to False. Since the parent and child tax configurations are not necessarily synchronized, relying only on the parent tax can lead to incorrect matching. This fix ensures
Original PR description
Currently, the is_base_affected condition is only checked on the group tax. However, this condition should also be checked on the child taxes to ensure proper matching. Without checking the child taxes, incorrect matches can occur when the parent tax has is_base_affected set to True, while one of its child taxes has it set to False. Since the parent and child tax configurations are not necessarily synchronized, relying only on the parent tax can lead to incorrect matching. This fix ensures that is_base_affected is validated at both the parent and child tax levels, preventing such incorrect matches. Enterprise PR - https://github.com/odoo/enterprise/pull/126770
When several xmlids point to the same record, PostgreSQL's UPDATE ... FROM can match multiple source rows to one target and pick an arbitrary value. Aggregate translations per res_id in import order so the later entry wins Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281686 Forward-Port-Of:
Original PR description
When several xmlids point to the same record, PostgreSQL's UPDATE ... FROM can match multiple source rows to one target and pick an arbitrary value. Aggregate translations per res_id in import order so the later entry wins Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281686 Forward-Port-Of: odoo/odoo#277818
Steps to reproduce: 0. Create an employee with a fixed working schedule and an overtime ruleset, then enable Absence Management in attendances 1. Go to Attendances and make sure that the employee has no attendances recorded for the previous working day 2. Run the "Attendance: Detect Absences for employees" scheduled action 3. Observe the absence attendance created on the previous working day, along with the amount of overtime hours calculated 4. Create an attendance on the day that the ab
Original PR description
Steps to reproduce: 0. Create an employee with a fixed working schedule and an overtime ruleset, then enable Absence Management in attendances 1. Go to Attendances and make sure that the employee has…
Steps to reproduce: 0. Create an employee with a fixed working schedule and an overtime ruleset, then enable Absence Management in attendances 1. Go to Attendances and make sure that the employee has no attendances recorded for the previous working day 2. Run the "Attendance: Detect Absences for employees" scheduled action 3. Observe the absence attendance created on the previous working day, along with the amount of overtime hours calculated 4. Create an attendance on the day that the absence was recorded 5. Observe that the overtime hours on the absence attendance are not updated 5a. If a full day attendance is recorded on that day, the overtime hours on the absence attendance should change to 0, since we've now recorded hours worked for the day When an absence attendance is created from the Absence Management feature, overtime hours are calculated to represent the time the employee was unjustifiably absent on a given day. If an attendance is later created on the day the absence was recorded, the overtime hours should update to reflect the hours the employee actually worked. Changes were introduced in [this PR](https://github.com/odoo/odoo/pull/272447) that broke this functionality due to the use of `pytz`, which incorrectly calculated timezone offsets. This caused absence attendances to not be picked up by `_get_overtimes_to_update_domain()`, and overtime was not correctly updated. This commit ensures that we get proper time calculations with respect to the employees timezone. [opw-6380343](https://www.odoo.com/odoo/my-tasks/6380343?debug=assets) Forward-Port-Of: odoo/odoo#281613 Forward-Port-Of: odoo/odoo#279556
The selection options for l10n_id_coretax_add_info_07/08 and l10n_id_coretax_facility_info_07 were swapped: the "additional information" fields showed facility stamp text and vice versa. Also add the UoM codes and new kode faktur 07 additional info/facility stamp options published by DJP on 2026-01-26. task-6434742 Forward-Port-Of: odoo/odoo#281096
Original PR description
The selection options for l10n_id_coretax_add_info_07/08 and l10n_id_coretax_facility_info_07 were swapped: the "additional information" fields showed facility stamp text and vice versa. Also add the UoM codes and new kode faktur 07 additional info/facility stamp options published by DJP on 2026-01-26. task-6434742 Forward-Port-Of: odoo/odoo#281096
Before this commit it was possible to assign an arbitrary account_move to a pos.order by sending it in the order data. This commit prevents that by removing the account_move from the order data before creating the pos.order. Forward-Port-Of: odoo/odoo#280279
Original PR description
Before this commit it was possible to assign an arbitrary account_move to a pos.order by sending it in the order data. This commit prevents that by removing the account_move from the order data before creating the pos.order. Forward-Port-Of: odoo/odoo#280279
`#right-elements` (tax totals block) is floated (`float-end`). Per CSS spec, an `auto` margin on a floated element always resolves to 0, so the `ms-auto` class added by 9767e8f5c1da5a9c9e38472ad576ffa3c4e32075 is a no-op, leaving no gutter before adjacent content such as the legal notes paragraph. Partial revert of 9767e8f5c1da5a9c9e38472ad576ffa3c4e32075 Steps to reproduce: ------------------- * On a tax, set a multi-line paragraph in Legal Notes (Advanced Options tab) * Apply it on an
Original PR description
`#right-elements` (tax totals block) is floated (`float-end`). Per CSS spec, an `auto` margin on a floated element always resolves to 0, so the `ms-auto` class added by…
`#right-elements` (tax totals block) is floated (`float-end`). Per CSS spec, an `auto` margin on a floated element always resolves to 0, so the `ms-auto` class added by 9767e8f5c1da5a9c9e38472ad576ffa3c4e32075 is a no-op, leaving no gutter before adjacent content such as the legal notes paragraph. Partial revert of 9767e8f5c1da5a9c9e38472ad576ffa3c4e32075 Steps to reproduce: ------------------- * On a tax, set a multi-line paragraph in Legal Notes (Advanced Options tab) * Apply it on an invoice line and print/preview the invoice PDF > Observation: the legal notes text touches/overlaps the tax totals table, with no spacing. Why the fix: ------------ `ms-5` gives `#right-elements` a real left margin, restoring the spacing lost when `ms-auto` (a no-op on floats) replaced it. BEFORE: <img width="596" height="753" alt="Screenshot 2026-08-05 at 10 52 00" src="https://github.com/user-attachments/assets/c596d6e9-4b61-434c-9b38-3ff0797e7fa7" /> AFTER: <img width="494" height="596" alt="Screenshot 2026-08-05 at 10 51 44" src="https://github.com/user-attachments/assets/f9a1792d-22c2-4586-9a75-53c4695f17e4" /> opw-6384085 Forward-Port-Of: odoo/odoo#280654
Description of the issue/feature this PR addresses: the contents of _t() calls in our data are extracted by the translation process. Having _t squished means that a part of the unsquishing logic would need to be implemented in the translation extraction process, which would be tedious to maintain. Task-6452075 --- 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: the contents of _t() calls in our data are extracted by the translation process. Having _t squished means that a part of the unsquishing logic would need to be implemented in the translation extraction process, which would be tedious to maintain. Task-6452075 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
l10n_vn_pos_symbol carries groups='base.group_system,point_of_sale.group_pos_manager', but _prepare_invoice_vals reads it while an ORDINARY salesperson closes an order: _process_saved_order calls _generate_pos_order_invoice as the acting user, with no sudo anywhere on the way. So on a Vietnamese POS with auto-send to SInvoice enabled, a user in point_of_sale.group_pos_user alone hit Access Denied by ACLs for operation: read, model: pos.config, fields: l10n_vn_pos_symbol and the order nev
Original PR description
l10n_vn_pos_symbol carries groups='base.group_system,point_of_sale.group_pos_manager', but _prepare_invoice_vals reads it while an ORDINARY salesperson closes an order: _process_saved_order calls…
l10n_vn_pos_symbol carries groups='base.group_system,point_of_sale.group_pos_manager', but _prepare_invoice_vals reads it while an ORDINARY salesperson closes an order: _process_saved_order calls _generate_pos_order_invoice as the acting user, with no sudo anywhere on the way. So on a Vietnamese POS with auto-send to SInvoice enabled, a user in point_of_sale.group_pos_user alone hit
Access Denied by ACLs for operation: read, model: pos.config, fields: l10n_vn_pos_symbol
and the order never finished syncing - the receipt screen's Done button stayed disabled and the checkout dead-ended.
This is reachable from the module's own test suite, which is what makes it more than theoretical: point_of_sale's start_pos_tour logs in as `pos_user` (group_pos_user, NOT group_pos_manager - that is `pos_admin`), so test_l10n_vn_edi_pos_refund_reason_tour exercises exactly the unprivileged path.
Reading the config as sudo is the right resolution rather than widening the field's groups: the salesperson is never shown the symbol or allowed to change it, it is only stamped onto the invoice their own sale produces, which is what a per-POS configuration field is for. Both symbols are read through the same sudo recordset so the company-level fallback keeps working identically.
Reproduced and verified on v18_full (5-repo addons path):
before - FAILED: [13/36] Tour L10nVnEdiPosRefundReasonTour -> "go to next screen from
receipt"; 1 failed, 0 error(s) of 1 tests
after - tour succeeded for both tours in the class; 0 failed, 0 error(s) of 2 tests,
and no ACL line left in the log
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#281621
Forward-Port-Of: odoo/odoo#281119Steps to reproduce: - a Basque company with TicketBAI enabled - one PoS config opened on two different devices (browsers) - make a sale from the first device - make a sale from the second device Issue: The second order is rejected by TicketBAI with the error 5040, the invoice number is already registered for that issuer, series and year. Cause: The invoice number sent to TicketBAI is the pos.order name. That name is built by _get_order_name_from_pos_reference out of the last part of
Original PR description
Steps to reproduce: - a Basque company with TicketBAI enabled - one PoS config opened on two different devices (browsers) - make a sale from the first device - make a sale from the second device…
Steps to reproduce: - a Basque company with TicketBAI enabled - one PoS config opened on two different devices (browsers) - make a sale from the first device - make a sale from the second device Issue: The second order is rejected by TicketBAI with the error 5040, the invoice number is already registered for that issuer, series and year. Cause: The invoice number sent to TicketBAI is the pos.order name. That name is built by _get_order_name_from_pos_reference out of the last part of pos_reference only, which is the receipt counter each device keeps in its own browser local storage and which restarts at 1. Both devices therefore name their first order "<config> - 000001", and _get_tbai_seq_from_name derives the same SerieFactura and NumFactura for the two of them. Fix: Send pos_reference instead. It is the number printed on the customer receipt and it also holds the device identifier, allocated by the device sequence of the config, which is what makes it unique. The device part ends up as the series and the counter as the number, so the numbering stays sequential inside the series of each device, and the series still starts with the year the duplicate check is made on. Both stay well below the 20 characters SerieFactura and NumFactura are limited to. The name of the refunded document is taken from the same helper, so a credit note cannot reference a number that was never registered. The pos.order name itself is not unique on any version from 19.0 on, but it cannot be changed in stable. opw-6442837 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280621
The test "Image cropper Enter saves and Escape closes in website builder" fails indeterministically on runbot. The error seems to have appeared just after the merging of [1], which introduced a speed-up in test execution. The failure is caused by an image being "invisible" when queried by `contains()`. The most likely cause is that the image is not yet fetched by the time the test runs. The image source is replaced with a `base64` `data:` URL, so that no fetching is required for this
Original PR description
The test "Image cropper Enter saves and Escape closes in website builder" fails indeterministically on runbot. The error seems to have appeared just after the merging of [1], which introduced a speed-up in test execution. The failure is caused by an image being "invisible" when queried by `contains()`. The most likely cause is that the image is not yet fetched by the time the test runs. The image source is replaced with a `base64` `data:` URL, so that no fetching is required for this test. [1]: https://github.com/odoo/odoo/pull/279584 runbot-944664 Forward-Port-Of: odoo/odoo#280333
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/685ffdada8 [REL] 19.2.25 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/9e09359384 [FIX] functions: omit functions from the squisher [Task: 6452075](https://www.odoo.com/odoo/2328/tasks/6452075) 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-authore
Original PR description
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/685ffdada8 [REL] 19.2.25 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/9e09359384 [FIX] functions: omit functions from the squisher [Task: 6452075](https://www.odoo.com/odoo/2328/tasks/6452075) 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>
Automatically update the ruff config to the latest version generated on runbot
Original PR description
Automatically update the ruff config to the latest version generated on runbot
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#278158 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#278158 Forward-Port-Of: odoo/odoo#270720
We now dpkg configure before every upgrade to ensure the IoT Box is ready to upgrade properly and `apt` commands won't fail. Forward-Port-Of: odoo/odoo#281693
Original PR description
We now dpkg configure before every upgrade to ensure the IoT Box is ready to upgrade properly and `apt` commands won't fail. Forward-Port-Of: odoo/odoo#281693
Steps to reproduce the bug: - Enable 2-step delivery (pick + ship) on a warehouse. - Set both rules on the delivery route to "Pull" (instead of the default Pull + Push): - Pick rule (Stock -> Output): action = Pull, procure_method = make_to_stock - Ship rule (Output -> Customers): action = Pull, procure_method = make_to_order - Create a sale order for qty 1 and confirm it. - Validate the Pick transfer. - Return the Pick transfer. - Cancel the sale order. - Set it back to quotati
Original PR description
Steps to reproduce the bug: - Enable 2-step delivery (pick + ship) on a warehouse. - Set both rules on the delivery route to "Pull" (instead of the default Pull + Push): - Pick rule (Stock ->…
Steps to reproduce the bug:
- Enable 2-step delivery (pick + ship) on a warehouse.
- Set both rules on the delivery route to "Pull" (instead of the default Pull + Push):
- Pick rule (Stock -> Output): action = Pull, procure_method = make_to_stock
- Ship rule (Output -> Customers): action = Pull, procure_method = make_to_order
- Create a sale order for qty 1 and confirm it.
- Validate the Pick transfer.
- Return the Pick transfer.
- Cancel the sale order.
- Set it back to quotation and confirm it again.
Problem:
The newly created delivery (ship) move ends up asking for a wrong, inflated quantity instead of the ordered one (e.g. 3 times the ordered qty for the scenario above; the multiplier depends on the number of prior confirm/cancel/return cycles).
`_action_cancel` (addons/sale_stock/models/sale_order.py) only cancels pickings that are not `done`, so after the pick is validated and returned, cancelling the SO only cancels the still-pending ship move. The pick move and its return stay `done` and linked to the sale order line.
`SaleOrderLine._get_outgoing_incoming_moves` determines which rule "started" the pull/push chain by picking the rule of the first surviving (non-cancelled) move, grouped by warehouse: https://github.com/odoo/odoo/blob/d7bad3dc6c068ffe8643ecb01da1865d743bfb8f/addons/sale_stock/models/sale_order_line.py#L338-L347
Once the ship move is cancelled, it is excluded from that computation, so the Pick rule is wrongly identified as the "triggering" rule instead of the Ship rule. The done pick move and its return share that rule, so they both end up wrongly classified as incoming (returned) quantities instead of being excluded from the computation like before the cancellation, corrupting `_get_qty_procurement`. On reconfirm, `_action_launch_stock_rule` computes
`product_qty = product_uom_qty - qty`, inflating the quantity requested on the new ship move.
Solution:
Identify the triggering rule from the sale order line's full move history, including cancelled moves, so cancelling a move later doesn't change which rule is considered to have started the chain.
opw-6364113
Forward-Port-Of: odoo/odoo#280280Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions 3. Create invoice with ar_001 partner 4. Confirm the invoice 5. Try to create credit note → Error: KeyError: 'en_US' Root Cause: The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB di
Original PR description
Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings >…
Steps to Reproduce the Error (Odoo SaaS 19.2):
1. Install l10n_gcc_invoice localization & Accounting
2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions
3. Create invoice with ar_001 partner
4. Confirm the invoice
5. Try to create credit note → Error: KeyError: 'en_US'
Root Cause:
The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB dict directly into cache, bypassing ORM field conversion. When Odoo 19.2's improved ORM conversion runs, it creates nested JSON in narration instead of a flat structure.
Timeline:
- bedf1cb66fbb: Workaround added to prevent T&C duplication in preview
- 75f050b9650d: Root cause fixed in report template (conditional display) → Made _load_narration_translation() redundant
- 4e4156536bc9: Odoo 19.2 improved ORM conversion → Now conflicts with the redundant workaround, causing nested JSON
How It Breaks:
1. Invoice creation: _load_narration_translation() injects raw dict into cache
2. ORM writes: nested JSON stored: {ar_001: {en_US: ., ar_001: Arabic}}
3. Credit note creation: copy_translations() expects flat structure → Crashes: KeyError: 'en_US'
Why It's Safe to Remove:
Report template already prevents T&C duplication (commit 75f050b9650d). Removing the workaround restores proper credit note creation without breaking T&C display.
Changes:
- Remove moves._load_narration_translation() in create()
- Remove out self.filtered('id')._load_narration_translation() in _compute_narration()
opw : 6284943
Forward-Port-Of: odoo/odoo#271037Before this commit, a call test where a participant card appears while in a call fails with: Unimplemented server route: /mail/rtc/channel/upgrade_connection The client sends that request a few seconds later, so only a test still running by then fails, as `Adjust view: switching between Tiled and Spotlight` does on master under load. This happens because the other participants of a test call are only records, so their peer connection negotiates no transceiver, and asking it to downl
Original PR description
Before this commit, a call test where a participant card appears while in a call fails with:
Unimplemented server route: /mail/rtc/channel/upgrade_connection
The client sends that request a few seconds later, so only a test still running by then fails, as `Adjust view: switching between Tiled and Spotlight` does on master under load.
This happens because the other participants of a test call are only records, so their peer connection negotiates no transceiver, and asking it to download the video of the card schedules a connection recovery instead. Recovering without a TURN server, which a test never has, asks the server to move the call to an SFU with that route, and the mock server implements join_call and leave_call only.
This commit registers the route with an empty handler, as no test has an SFU server to join.
Forward-Port-Of: odoo/odoo#281736Previously, refreshing the PoS caused categories with sequence = 0 to fall back to ID-based sorting from IndexedDB. Sequence-based ordering was already fixed in this [pr](https://github.com/odoo/odoo/pull/207172), but the fallback for sequence 0 still sorted by ID. This change ensures categories with sequence = 0 follow the expected ordering when refreshing. Task-6185359 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merge
Original PR description
Previously, refreshing the PoS caused categories with sequence = 0 to fall back to ID-based sorting from IndexedDB. Sequence-based ordering was already fixed in this [pr](https://github.com/odoo/odoo/pull/207172), but the fallback for sequence 0 still sorted by ID. This change ensures categories with sequence = 0 follow the expected ordering when refreshing. Task-6185359 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273954
Before this commit, some layouts had the customer address on the right (light, boxed, bold, striped) and some had it on the left (bubble, wave, folder). For the latter, when an information_block with the address existed, it would be inserted before the address pushing it further right. This was inconsistent since the address position should not depend on whether an information_block is present or not. The customer address must stay in a fixed place to match the transparent window of the
Original PR description
Before this commit, some layouts had the customer address on the right (light, boxed, bold, striped) and some had it on the left (bubble, wave, folder). For the latter, when an information_block with…
Before this commit, some layouts had the customer address on the right (light, boxed, bold, striped) and some had it on the left (bubble, wave, folder). For the latter, when an information_block with the address existed, it would be inserted before the address pushing it further right. This was inconsistent since the address position should not depend on whether an information_block is present or not. The customer address must stay in a fixed place to match the transparent window of the envelope when sending a physical letter by snailmail. This commit fixes this issue by ensuring that in all cases the customer address position stays fixed regardless of the presence or absence of the information_block and regardless of the layout used for the letter. It also fixes the addresses displayed on the sale order report: 1) If invoicing address = partner address != shipping address or invoicing address != partner address = shipping address then the three addresses would be printed, even though 2 addresses are identical. 2) The shipping address and the invoicing address are now printed horizontally rather than vertically to get rid of the resulting large blank block under the partner address in that case. backport of: https://github.com/odoo/odoo/pull/276622 task-6340467 Forward-Port-Of: odoo/odoo#273640
Steps to reproduce: ------------------- 1. Install `hr` module 2. Create two employees (e.g., emp1 and emp2) and assign emp1 as the manager of emp2 → emp2 is now a direct subordinate of emp1 3. In the employee list view, apply the custom filter "Direct subordinates is set" (child_ids != False) → emp1 appears in the results as expected 4. Archive emp2 5. Apply the same filter again → emp1 still appears in the results even though it has no active subordinates Issue
Original PR description
Steps to reproduce: ------------------- 1. Install `hr` module 2. Create two employees (e.g., emp1 and emp2) and assign emp1 as the manager of emp2 → emp2 is now a direct subordinate of emp1 3. In…
Steps to reproduce: ------------------- 1. Install `hr` module 2. Create two employees (e.g., emp1 and emp2) and assign emp1 as the manager of emp2 → emp2 is now a direct subordinate of emp1 3. In the employee list view, apply the custom filter "Direct subordinates is set" (child_ids != False) → emp1 appears in the results as expected 4. Archive emp2 5. Apply the same filter again → emp1 still appears in the results even though it has no active subordinates Issue: ------ When an employee (e.g., `emp2`) is archived, their manager (`emp1`) should no longer appear in the "Direct subordinates is set" (child_ids != False) filter — since `emp1` no longer has any active subordinates. However, `emp1` still appears in the search results after `emp2` is archived, because the underlying EXISTS subquery checks all subordinates regardless of their active state. Cause: -------- Before this commit 5ef007a, `osv.expression`, filtering on a One2many field would automatically search against [active co-records ](https://github.com/odoo/odoo/blob/5f65e92d7fa341193df53f5aba1620b596f9a1ec/odoo/osv/expression.py#L1260-L1265)only by default. After that commit, the `condition_to_sql` method in `_RelationalMulti` constructs the comodel with [active_test=False](https://github.com/odoo/odoo/blob/463ca4cf867812890c17d1e1abf7640b04f70ad0/odoo/orm/fields_relational.py#L672-L686) when resolving relational field conditions. This causes the EXISTS subquery generated for `child_ids != False` to compare against all subordinates. (including archived ones rather than active ones only). Solution: --------- Added a callable `domain` attribute on the `child_ids` field definition so that only active subordinates are considered by default. This ensures [get_comodel_domain()](https://github.com/odoo/odoo/blob/2d8b24a791b6fe6bb214c32d4fb58b3d46eca70b/odoo/orm/fields_relational.py#L75-L85) returns a server-side domain that filters out archived subordinates, making the `child_ids != False` filter behave as expected. **NOTE:** > The ORM uses the **active_test** flag when doing searches. Having in [1, 2, 3] in domains bypasses the search method because we suppose that we already searched to find these ids. For hierarchical resolution, we bypass rights and active_test. The result is that inactive records are considered in the result. confirmed with the framework team, and it is intended behaviour. However, this is not the expected behaviour for the direct subordinates case in `hr`. The fix is therefore applied at the field level by explicitly declaring a domain on `child_ids` to filter out archived subordinates. ORM commit: https://github.com/odoo-dev/odoo/commit/12eae5c85fa7facb299f0f1bf1fdd62e3ff82aa5 opw-6193104 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281222 Forward-Port-Of: odoo/odoo#266658
During the backport we discovered a programming error in `_get_peppol_document_params`. The super function can return `None` values for both `edi_user` and `document`. This can lead to a traceback when the variables are used. We do not have any known issues in 18.0 or higher versions. (Probably because the move send was heavily refactored.) But better safe than sorry. It could maybe happen with the batch sending or in case the "surrounding" logic is refactored in the future. task-None
Original PR description
During the backport we discovered a programming error in `_get_peppol_document_params`. The super function can return `None` values for both `edi_user` and `document`. This can lead to a traceback when the variables are used. We do not have any known issues in 18.0 or higher versions. (Probably because the move send was heavily refactored.) But better safe than sorry. It could maybe happen with the batch sending or in case the "surrounding" logic is refactored in the future. task-None Forward-Port-Of: odoo/odoo#279317