Daily updates from Odoo
Monday, July 20, 2026
173 changes
14 changes
Enhancements to existing features
The French balance sheet report now presents establishment costs before fixed assets and includes several previously missing impairment accounts in tangible fixed asset lines. This improves the accuracy and alignment of statutory French financial reporting.
Original PR description
Move establishment costs before fixed assets in the French balance sheet, and include the missing 2912, 2913, 2914, and 2915 impairment accounts in the relevant tangible fixed asset amortization/provision lines. task-6226138 Forward-Port-Of: odoo/enterprise#124562 Forward-Port-Of: odoo/enterprise#117689
Resolved issues and error corrections
The payroll payslip list now handles the Off-Cycle filter correctly in debug mode. This prevents an error from appearing when viewing payslips without an associated pay run, improving reliability for payroll users.
Original PR description
Before this commit, when the user is in debug mode, goes to payslips list view and applies `Off-Cycle` filter, a traceback is occured saying `Invalid props for component 'PayslipActionHelper': 'payrunId' is not a number`.
The reason is because we search the id of the payrun by parsing the domain applied to fetch payslips displayed inside the list view but `Off-Cycle` filter will apply the following domain: `[('payslip_run_id', '=', False)]` and so False is given to PayslipActionHelper but it is not a number.
This commit makes sure to set undefined to payrunId prop of PayslipActionHelper when `payrun_id` found is falsy.
runbot-error-241053
Forward-Port-Of: odoo/enterprise#124854Polish currency rate imports no longer shift the National Bank of Poland rate date by an extra day. This prevents rates from being dated incorrectly now that the system already selects the previous day's rate as required.
Original PR description
In Poland, it is mandatory to use the previous day's currency rate. We used to achieve this by shifting the rate's date by one day. Since https://github.com/odoo/odoo/pull/231948, we already use the previous day's rate, so the shift is no longer needed. See: https://www.odoo.com/mail/message/1118975071 Forward-Port-Of: odoo/enterprise#123849
Timesheet Assistant rule types now use updated colors so users can recognize different event types more quickly. This small visual fix improves readability and reduces confusion when reviewing timesheet-related suggestions.
Original PR description
This commit updates the color of AW rule types to help the user to quickly recognize the type of events based on the color. task-6186073
A subscription commission test now removes currency rate records across companies with the needed permissions, preventing demo data from other companies from affecting the result. This keeps commission calculations reliably tested when demo data is installed.
Original PR description
Steps to reproduce: 1- Initialize a new database with demo data 2- Run the test `test_sub_commission_no_currency_rate` Issue: `AssertionError: 0 != 10 : Regular invoice, 10 percent of 100` Why this happens: The test used to delete all rows in the res_currency_rate table for the current company only. When we load the database with demo data, the query in `_get_subscription_currency_rates` would find entries for the other companies and wouldn't resort to the default. Later when joining, it would find no rates for the current company and the test fails. runbot-243440 Forward-Port-Of: odoo/enterprise#116197
VoIP call screens now hide related record buttons when a call is not linked to a customer or contact, preventing unexpected errors. Subscription buttons are also shown consistently with the customer view, improving behavior across sales, CRM, helpdesk, and recruitment call workflows.
Original PR description
Same as in [1], we don't show smart buttons when no partner to prevent unexpected errors. Also remove `invisible="subscription_count == 0"` to make it same as smart button on res.partner. [1]: 0fbb730e02de22b196a45455f801e96321a75167 Forward-Port-Of: odoo/enterprise#124579
Users can no longer trigger a server error by creating a new unmatched name directly from the commission adjustments list. The change keeps sales commission adjustment entry stable by requiring selection of existing commission users instead of allowing an invalid quick-create action.
Original PR description
Steps to reproduce: - Go to Sales > Commission > Adjustments - In Add to/Reduce From, type a name with no match - Click Create '<name>' -> server crashes (RPC_ERROR) Cause: `sale.commission.plan.user._rec_name` is a Many2one (`user_id`). Default `name_create` wrote the typed text into that integer column, which Postgres rejected. Fix: - Disable quick-create on `add_user_id`/`reduce_user_id` in the Adjustments list view Version: saas-18.3 to master opw-6384909 Forward-Port-Of: odoo/enterprise#124431
AI-generated answers that include web citations now keep their original spacing, lists, and paragraph breaks. This prevents cited answers from appearing merged together, making responses easier for users to read and trust.
Original PR description
AI responses containing web citations lost their original formatting when a citation appeared at the end of a line, causing lists and paragraphs to be merged together. This commit limits the citation parser to ignore only horizontal whitespace around citations, preserving line breaks in the rendered response. task-6391187 Forward-Port-Of: odoo/enterprise#124457
### Issue: The 'Schedule an appointment' and 'Next Events' CTA buttons were not updated even when their conditions were satisfied. ### Steps to reproduce: - Install only Website. - In the configurator, choose 'Schedule Appointments' as the main objective. - Complete the setup and create the website. - The CTA button remains 'Contact Us' instead of 'Schedule an appointment'. ### Reason: The `get_cta_data()` method is overridden in specific modules to update the CTA button base
Original PR description
### Issue: The 'Schedule an appointment' and 'Next Events' CTA buttons were not updated even when their conditions were satisfied. ### Steps to reproduce: - Install only Website. - In the configurator, choose 'Schedule Appointments' as the main objective. - Complete the setup and create the website. - The CTA button remains 'Contact Us' instead of 'Schedule an appointment'. ### Reason: The `get_cta_data()` method is overridden in specific modules to update the CTA button based on conditions. However, it is called before those modules are installed, so the overridden logic is never executed. ### Fix: Ensure that `get_cta_data()` is called and the CTA button is updated after the required modules are installed. task-[6383681](https://www.odoo.com/odoo/project/974/tasks/6383681) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#261781
This PR hides the Upgrade button for modules imported via file, as these modules cannot be upgraded without re-importing a file. Displaying the upgrade button in such cases could lead to confusion or unexpected behavior. Task: 4643890 Forward-Port-Of: odoo/odoo#213122
Original PR description
This PR hides the Upgrade button for modules imported via file, as these modules cannot be upgraded without re-importing a file. Displaying the upgrade button in such cases could lead to confusion or unexpected behavior. Task: 4643890 Forward-Port-Of: odoo/odoo#213122
Steps to reproduce: --- Case 1: 1. Add a carousel at the top of the page. 2. Apply the parallax effect to all slides. 3. Reload the page and navigate to the second slide without scrolling. 4. Scroll slightly and observe the jump in background position. 5. Scroll back to the top and notice the changed background position. Case 2: 1. Add a carousel to the page. 2. Apply the parallax effect to each slide. 3. Add text over the carousel and enable animation on appearance and on eve
Original PR description
Steps to reproduce: --- Case 1: 1. Add a carousel at the top of the page. 2. Apply the parallax effect to all slides. 3. Reload the page and navigate to the second slide without scrolling. 4. Scroll…
Steps to reproduce: --- Case 1: 1. Add a carousel at the top of the page. 2. Apply the parallax effect to all slides. 3. Reload the page and navigate to the second slide without scrolling. 4. Scroll slightly and observe the jump in background position. 5. Scroll back to the top and notice the changed background position. Case 2: 1. Add a carousel to the page. 2. Apply the parallax effect to each slide. 3. Add text over the carousel and enable animation on appearance and on every time. 4. Slide between images and observe the bouncing effect. https://github.com/user-attachments/assets/d11ee430-8b95-4903-b001-1b9ba8ee58cd Why this change? --- When the parallax effect is applied to carousel slides, only the first slide is initialized with the correct [parallaxHeight](https://github.com/odoo/odoo/blob/616e82d7b3a53b1facf481e783baed3e99393d3c/addons/website/static/src/interactions/parallax/parallax.js#L49). The remaining slides are initialized while hidden, resulting in a computed height of 0. When scrolling, the background height is recalculated with the correct value, producing a visible jump effect. Additionally, when text or any animated content is added on top of the carousel (especially animations triggered on appearance or on every slide change), a [resize event](https://github.com/odoo/odoo/blob/616e82d7b3a53b1facf481e783baed3e99393d3c/addons/website/static/src/interactions/animation.js#L111) is triggered on each transition. This causes `updateBackgroundHeight()` to run again. Since hidden slides were initialized with height 0 and later receive their actual height, the recalculation produces a noticeable bouncing effect. After this commit: --- The parallax computation now relies on the parent element’s `getBoundingClientRect().height` when used inside a carousel. Since the carousel slide height is already defined and consistent, this ensures correct initialization even when the slide is not yet visible. OPW: 5909351 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#250290
Steps to reproduce --- 1. Install a carrier that requires a positive package shipping weight (e.g. UPS) and enable Packages. 2. From the Barcode app, process a delivery and Put in Pack the products. 3. Validate the transfer. Issue --- Validation is refused because the package has no positive shipping weight, even though its computed weight is correct. The package shipping weight is only set in `_post_put_in_pack_hook` from `context['weight']`, which is filled exclusively by the put i
Original PR description
Steps to reproduce --- 1. Install a carrier that requires a positive package shipping weight (e.g. UPS) and enable Packages. 2. From the Barcode app, process a delivery and Put in Pack the products.…
Steps to reproduce --- 1. Install a carrier that requires a positive package shipping weight (e.g. UPS) and enable Packages. 2. From the Barcode app, process a delivery and Put in Pack the products. 3. Validate the transfer. Issue --- Validation is refused because the package has no positive shipping weight, even though its computed weight is correct. The package shipping weight is only set in `_post_put_in_pack_hook` from `context['weight']`, which is filled exclusively by the put in pack wizard. Flows that bypass the wizard, like the Barcode app, never provide that key, so the stored `shipping_weight` stays 0 while carriers reading it directly reject the delivery. The Barcode app suppresses the wizard through the `barcode_view` context, so its put in pack goes straight to the hook without any weight. https://github.com/odoo/enterprise/blob/6b18215bfa98ef636b63f4fafbba1d25264f4883/stock_barcode/models/stock_move_line.py#L193-L196 This handling was centralized in this hook by 9a2ff6f4033e, so every wizard-bypassed pack leaves the field empty. Defaulting it to the package computed weight via `_get_weight` when the context did not provide one makes the stored value correct for any carrier, independently of the flow that created the package. https://github.com/odoo/odoo/blob/4235b48c86077bd5bceb9e817cc45b2eec8697e8/addons/stock_delivery/models/stock_move.py#L111-L115 opw-6297689 Forward-Port-Of: odoo/odoo#273876 Forward-Port-Of: odoo/odoo#272510
When sending a batch of invoice, we first generate an unique PDF file regrouping every invoice. When at least one invoice needs more than one page to be rendered entirely, the number of pages will be greater than the number of invoices. In this case, we use <hX> tags to split invoices: https://github.com/odoo/odoo/blob/5ba945cdba6be3ff8838e56784ade16c6200de84/odoo/addons/base/models/ir_actions_report.py#L916-L923 This tag is added for PDF files, using the invoice's title: https://g
Original PR description
When sending a batch of invoice, we first generate an unique PDF file regrouping every invoice. When at least one invoice needs more than one page to be rendered entirely, the number of pages will be…
When sending a batch of invoice, we first generate an unique PDF file regrouping every invoice. When at least one invoice needs more than one page to be rendered entirely, the number of pages will be greater than the number of invoices. In this case, we use <hX> tags to split invoices: https://github.com/odoo/odoo/blob/5ba945cdba6be3ff8838e56784ade16c6200de84/odoo/addons/base/models/ir_actions_report.py#L916-L923 This tag is added for PDF files, using the invoice's title: https://github.com/odoo/odoo/blob/5ba945cdba6be3ff8838e56784ade16c6200de84/addons/web/views/report_templates.xml#L627 In some localization modules, this title shouldn't be displayed and it is removed. Example for Chile: https://github.com/odoo/odoo/blob/5ba945cdba6be3ff8838e56784ade16c6200de84/addons/l10n_cl/views/report_invoice.xml#L149 In this case, no `<h3>` tag will be added and an error is raised as we cannot separate invoices. We propose to add an empty `<h3>` tag if the document title is not defined. opw-6281187 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277131 Forward-Port-Of: odoo/odoo#269100
Features or functions removed from Odoo
Description of the issue/feature this PR addresses: Removed obsolete code checking "this.config.self_ordering_mode !== 'qr_code'". Since "qr_code" is not a valid value of the "self_ordering_mode" selection field. The condition is always true. Forward-Port-Of: odoo/odoo#276321 Forward-Port-Of: odoo/odoo#273245
Original PR description
Description of the issue/feature this PR addresses: Removed obsolete code checking "this.config.self_ordering_mode !== 'qr_code'". Since "qr_code" is not a valid value of the "self_ordering_mode" selection field. The condition is always true. Forward-Port-Of: odoo/odoo#276321 Forward-Port-Of: odoo/odoo#273245
22 changes
Enhancements to existing features
Adds an automatic cleanup script for the Belgian POS blackbox module so copied or neutralized databases no longer keep device IP addresses or establishment identifiers. This helps prevent test or staging environments from accidentally retaining production point-of-sale configuration details.
Original PR description
Add a `neutralize.sql` file to the `l10n_be_pos_blackbox` module to reset the blackbox `local_ip` and the config's `l10n_be_pos_id` and `establishment_number`. FW of PR: https://github.com/odoo/enterprise/pull/124258
The French balance sheet report now presents establishment costs before fixed assets and includes additional impairment accounts in tangible fixed asset provision lines. This improves report accuracy and alignment with expected French accounting presentation.
Original PR description
Move establishment costs before fixed assets in the French balance sheet, and include the missing 2912, 2913, 2914, and 2915 impairment accounts in the relevant tangible fixed asset amortization/provision lines. task-6226138 Forward-Port-Of: odoo/enterprise#124562 Forward-Port-Of: odoo/enterprise#117689
Resolved issues and error corrections
This fix updates the project forecasting screen so its subtask button correctly connects to the current subtask action. It prevents the button customization from targeting an outdated control, helping users access subtasks reliably.
Original PR description
Issue --- The inherited xpath still targets the old action-based subtask button Fix --- Update the inherited xpath to target action_open_subtasks. task-5966684 Forward-Port-Of: odoo/enterprise#124063 Forward-Port-Of: odoo/enterprise#123035
Polish currency rates from NBP are no longer shifted by an extra day because the system already applies the required previous-day rate. This prevents rates from being dated too far back and helps ensure currency conversions use the correct official rate.
Original PR description
In Poland, it is mandatory to use the previous day's currency rate. We used to achieve this by shifting the rate's date by one day. Since https://github.com/odoo/odoo/pull/231948, we already use the previous day's rate, so the shift is no longer needed. See: https://www.odoo.com/mail/message/1118975071 Forward-Port-Of: odoo/enterprise#123849
AI-generated answers with web citations now keep their original line breaks and spacing. This prevents lists and paragraphs from being merged together, making cited AI responses easier to read and understand.
Original PR description
AI responses containing web citations lost their original formatting when a citation appeared at the end of a line, causing lists and paragraphs to be merged together. This commit limits the citation parser to ignore only horizontal whitespace around citations, preserving line breaks in the rendered response. task-6391187
This fix stops the spreadsheet view from continuing a synchronization step when the spreadsheet model fails to load. Users will still receive the intended notification, but the system will avoid an additional traceback that could disrupt the experience.
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)
The Commission Adjustments screen no longer offers a quick-create option that could crash when entering a new unmatched user name. This helps sales teams avoid errors while managing commission adjustments.
Original PR description
Steps to reproduce: - Go to Sales > Commission > Adjustments - In Add to/Reduce From, type a name with no match - Click Create '<name>' -> server crashes (RPC_ERROR) Cause: `sale.commission.plan.user._rec_name` is a Many2one (`user_id`). Default `name_create` wrote the typed text into that integer column, which Postgres rejected. Fix: - Disable quick-create on `add_user_id`/`reduce_user_id` in the Adjustments list view Version: saas-18.3 to master opw-6384909 Forward-Port-Of: odoo/enterprise#124431
This PR hides the Upgrade button for modules imported via file, as these modules cannot be upgraded without re-importing a file. Displaying the upgrade button in such cases could lead to confusion or unexpected behavior. Task: 4643890 Forward-Port-Of: odoo/odoo#213122
Original PR description
This PR hides the Upgrade button for modules imported via file, as these modules cannot be upgraded without re-importing a file. Displaying the upgrade button in such cases could lead to confusion or unexpected behavior. Task: 4643890 Forward-Port-Of: odoo/odoo#213122
Steps to produce: --- - Install the `Sales` module. - Go to Invoicing > Configuration > Accounting > Taxes. - Open the 0% Exports tax and set a value in the `Label on Invoices.` Field under the Advanced Options tab. - Create a sale order with multiple sections, apply the 0% Exports tax to the order lines, and enable `Hide Composition` on one of the sections. - Preview the sale order. Issue: --- - The tax displayed in a collapsed section summary differs from the tax shown on regular or
Original PR description
Steps to produce: --- - Install the `Sales` module. - Go to Invoicing > Configuration > Accounting > Taxes. - Open the 0% Exports tax and set a value in the `Label on Invoices.` Field under the…
Steps to produce: --- - Install the `Sales` module. - Go to Invoicing > Configuration > Accounting > Taxes. - Open the 0% Exports tax and set a value in the `Label on Invoices.` Field under the Advanced Options tab. - Create a sale order with multiple sections, apply the 0% Exports tax to the order lines, and enable `Hide Composition` on one of the sections. - Preview the sale order. Issue: --- - The tax displayed in a collapsed section summary differs from the tax shown on regular order lines for the same tax. Root cause: --- - At [1], `_get_grouped_section_summary()` only returns `tax_labels`, which are then used when rendering the collapsed section summary. As a result, the invoice label is displayed instead of the actual tax name. Solution: --- - Add `tax_names` to the values returned by `_get_grouped_section_summary()` and use them when rendering the collapsed section summary, ensuring consistent tax information across the preview. - Also removed the unnecessary fallback in the return statement, as `res` is always populated. [1]https://github.com/odoo/odoo/blob/be0bf1365e054521ece224f5e3a4b7cbce402315/addons/sale/models/sale_order_line.py#L1572-L1604 Before: --- <img width="1068" height="156" alt="image" src="https://github.com/user-attachments/assets/8030c35e-5c73-4fed-9feb-c4729add7894" /> After: --- <img width="1057" height="143" alt="image" src="https://github.com/user-attachments/assets/336030ed-68b2-4d14-b26f-ff391257d6d4" /> opw-6294141 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270544
Steps to reproduce: --- Case 1: 1. Add a carousel at the top of the page. 2. Apply the parallax effect to all slides. 3. Reload the page and navigate to the second slide without scrolling. 4. Scroll slightly and observe the jump in background position. 5. Scroll back to the top and notice the changed background position. Case 2: 1. Add a carousel to the page. 2. Apply the parallax effect to each slide. 3. Add text over the carousel and enable animation on appearance and on eve
Original PR description
Steps to reproduce: --- Case 1: 1. Add a carousel at the top of the page. 2. Apply the parallax effect to all slides. 3. Reload the page and navigate to the second slide without scrolling. 4. Scroll…
Steps to reproduce: --- Case 1: 1. Add a carousel at the top of the page. 2. Apply the parallax effect to all slides. 3. Reload the page and navigate to the second slide without scrolling. 4. Scroll slightly and observe the jump in background position. 5. Scroll back to the top and notice the changed background position. Case 2: 1. Add a carousel to the page. 2. Apply the parallax effect to each slide. 3. Add text over the carousel and enable animation on appearance and on every time. 4. Slide between images and observe the bouncing effect. https://github.com/user-attachments/assets/d11ee430-8b95-4903-b001-1b9ba8ee58cd Why this change? --- When the parallax effect is applied to carousel slides, only the first slide is initialized with the correct [parallaxHeight](https://github.com/odoo/odoo/blob/616e82d7b3a53b1facf481e783baed3e99393d3c/addons/website/static/src/interactions/parallax/parallax.js#L49). The remaining slides are initialized while hidden, resulting in a computed height of 0. When scrolling, the background height is recalculated with the correct value, producing a visible jump effect. Additionally, when text or any animated content is added on top of the carousel (especially animations triggered on appearance or on every slide change), a [resize event](https://github.com/odoo/odoo/blob/616e82d7b3a53b1facf481e783baed3e99393d3c/addons/website/static/src/interactions/animation.js#L111) is triggered on each transition. This causes `updateBackgroundHeight()` to run again. Since hidden slides were initialized with height 0 and later receive their actual height, the recalculation produces a noticeable bouncing effect. After this commit: --- The parallax computation now relies on the parent element’s `getBoundingClientRect().height` when used inside a carousel. Since the carousel slide height is already defined and consistent, this ensures correct initialization even when the slide is not yet visible. OPW: 5909351 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#250290
Rather than assign `log_target` and blow up if the third branch is taken, use a `defaultdict` and just increment the count in each branch on hit. The continue in the third branch is not strictly necessary, but that way it protects us if anyone decides to add post-processing which also doesn't account for the third branch. Forward-Port-Of: odoo/odoo#276757 Forward-Port-Of: odoo/odoo#276481
Original PR description
Rather than assign `log_target` and blow up if the third branch is taken, use a `defaultdict` and just increment the count in each branch on hit. The continue in the third branch is not strictly necessary, but that way it protects us if anyone decides to add post-processing which also doesn't account for the third branch. Forward-Port-Of: odoo/odoo#276757 Forward-Port-Of: odoo/odoo#276481
Steps to Reproduce --- - Create a normal parent task with one normal sub-task and one template sub-task. - Open the parent task form view and observe the Sub-tasks stat button count and notebook tab, check the subtask view as well. - Create a template parent task with one normal sub-task and one template sub-task, then repeat the same checks. Issue --- - Task templates are handled like regular subtasks in the subtask count, notebook, and subtask view, without taking the parent task t
Original PR description
Steps to Reproduce --- - Create a normal parent task with one normal sub-task and one template sub-task. - Open the parent task form view and observe the Sub-tasks stat button count and notebook tab,…
Steps to Reproduce --- - Create a normal parent task with one normal sub-task and one template sub-task. - Open the parent task form view and observe the Sub-tasks stat button count and notebook tab, check the subtask view as well. - Create a template parent task with one normal sub-task and one template sub-task, then repeat the same checks. Issue --- - Task templates are handled like regular subtasks in the subtask count, notebook, and subtask view, without taking the parent task type into account. Current Behaviour --- - For a normal parent task, both the normal sub-task and the template sub-task are counted and shown in the opened subtask view and notebook. - For a template parent task, the same filtering is applied, even though template subtasks should remain accessible in that context. Expected Behaviour --- - For a normal parent task, only real sub-tasks should be counted and shown in the subtask view and notebook, and on the project kanban card. - For a template parent task, template subtasks should remain available in the subtask view and notebook according to the parent template context. - In the project kanban card, tasks must not be counted when their parent task is a template, even if the child task itself is not a template. Fix --- - Apply template-aware filtering to subtask counting,project kanban task count and subtask view behavior, depending on whether the parent task is a normal task or a template task. task-5966684 Forward-Port-Of: odoo/odoo#275901 Forward-Port-Of: odoo/odoo#252403
Steps to reproduce --- 1. Install a carrier that requires a positive package shipping weight (e.g. UPS) and enable Packages. 2. From the Barcode app, process a delivery and Put in Pack the products. 3. Validate the transfer. Issue --- Validation is refused because the package has no positive shipping weight, even though its computed weight is correct. The package shipping weight is only set in `_post_put_in_pack_hook` from `context['weight']`, which is filled exclusively by the put i
Original PR description
Steps to reproduce --- 1. Install a carrier that requires a positive package shipping weight (e.g. UPS) and enable Packages. 2. From the Barcode app, process a delivery and Put in Pack the products.…
Steps to reproduce --- 1. Install a carrier that requires a positive package shipping weight (e.g. UPS) and enable Packages. 2. From the Barcode app, process a delivery and Put in Pack the products. 3. Validate the transfer. Issue --- Validation is refused because the package has no positive shipping weight, even though its computed weight is correct. The package shipping weight is only set in `_post_put_in_pack_hook` from `context['weight']`, which is filled exclusively by the put in pack wizard. Flows that bypass the wizard, like the Barcode app, never provide that key, so the stored `shipping_weight` stays 0 while carriers reading it directly reject the delivery. The Barcode app suppresses the wizard through the `barcode_view` context, so its put in pack goes straight to the hook without any weight. https://github.com/odoo/enterprise/blob/6b18215bfa98ef636b63f4fafbba1d25264f4883/stock_barcode/models/stock_move_line.py#L193-L196 This handling was centralized in this hook by 9a2ff6f4033e, so every wizard-bypassed pack leaves the field empty. Defaulting it to the package computed weight via `_get_weight` when the context did not provide one makes the stored value correct for any carrier, independently of the flow that created the package. https://github.com/odoo/odoo/blob/4235b48c86077bd5bceb9e817cc45b2eec8697e8/addons/stock_delivery/models/stock_move.py#L111-L115 opw-6297689 Forward-Port-Of: odoo/odoo#273876 Forward-Port-Of: odoo/odoo#272510
When sending a batch of invoice, we first generate an unique PDF file regrouping every invoice. When at least one invoice needs more than one page to be rendered entirely, the number of pages will be greater than the number of invoices. In this case, we use <hX> tags to split invoices: https://github.com/odoo/odoo/blob/5ba945cdba6be3ff8838e56784ade16c6200de84/odoo/addons/base/models/ir_actions_report.py#L916-L923 This tag is added for PDF files, using the invoice's title: https://g
Original PR description
When sending a batch of invoice, we first generate an unique PDF file regrouping every invoice. When at least one invoice needs more than one page to be rendered entirely, the number of pages will be…
When sending a batch of invoice, we first generate an unique PDF file regrouping every invoice. When at least one invoice needs more than one page to be rendered entirely, the number of pages will be greater than the number of invoices. In this case, we use <hX> tags to split invoices: https://github.com/odoo/odoo/blob/5ba945cdba6be3ff8838e56784ade16c6200de84/odoo/addons/base/models/ir_actions_report.py#L916-L923 This tag is added for PDF files, using the invoice's title: https://github.com/odoo/odoo/blob/5ba945cdba6be3ff8838e56784ade16c6200de84/addons/web/views/report_templates.xml#L627 In some localization modules, this title shouldn't be displayed and it is removed. Example for Chile: https://github.com/odoo/odoo/blob/5ba945cdba6be3ff8838e56784ade16c6200de84/addons/l10n_cl/views/report_invoice.xml#L149 In this case, no `<h3>` tag will be added and an error is raised as we cannot separate invoices. We propose to add an empty `<h3>` tag if the document title is not defined. opw-6281187 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277131 Forward-Port-Of: odoo/odoo#269100
Before this commit vat_label on address always changed to `Tax Identification Number` when l10n_my_edi_pos installed regardless of which company set website/user. Cause: In this PR https://github.com/odoo/odoo/pull/247156 in xpath replaced vat label with `Tax Identification Number` so vat_label is no longer calculated based on company or selected country. Fix: - Only set that label for MY country.
Original PR description
Before this commit vat_label on address always changed to `Tax Identification Number` when l10n_my_edi_pos installed regardless of which company set website/user. Cause: In this PR https://github.com/odoo/odoo/pull/247156 in xpath replaced vat label with `Tax Identification Number` so vat_label is no longer calculated based on company or selected country. Fix: - Only set that label for MY country.
Current behavior before PR: - Updating a chart granularity was overriding searchParams from `definition.searchParams` instead of `definition.dataSource.searchParams.` - Since `definition.searchParams` is undefined, all existing search parameters, such as domain, were lost. Desired behavior after PR is merged: - Read searchParams from definition.dataSource.searchParams before updating the granularity. - This preserves the existing search parameters while updating only the group
Original PR description
Current behavior before PR: - Updating a chart granularity was overriding searchParams from `definition.searchParams` instead of `definition.dataSource.searchParams.` - Since `definition.searchParams` is undefined, all existing search parameters, such as domain, were lost. Desired behavior after PR is merged: - Read searchParams from definition.dataSource.searchParams before updating the granularity. - This preserves the existing search parameters while updating only the groupBy value. Task: [6377572](https://www.odoo.com/odoo/project/2328/tasks/6377572) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
### [FIX] web: fix mocked dates in tests Dates are mocked in all unit tests by default; either to a default static value, or to one defined in the test/suite. To do so, the `window.Date` constructor is overridden to have the arguments auto-filled with the current mock date paramters. Before this commit, an additional offset was always added to the given arguments to reflect: - the time elapsed from the beginning of the test; - any virtual offset added by a helper such as 'advanceTime
Original PR description
### [FIX] web: fix mocked dates in tests Dates are mocked in all unit tests by default; either to a default static value, or to one defined in the test/suite. To do so, the `window.Date` constructor…
### [FIX] web: fix mocked dates in tests Dates are mocked in all unit tests by default; either to a default static value, or to one defined in the test/suite. To do so, the `window.Date` constructor is overridden to have the arguments auto-filled with the current mock date paramters. Before this commit, an additional offset was always added to the given arguments to reflect: - the time elapsed from the beginning of the test; - any virtual offset added by a helper such as 'advanceTime'. The issue is that the spec of the Date constructor wants that the returned date object has to match all given arguments, and any omitted argument will be defaulted to the current date/time. This was not the case in tests, as the offset was always added, regardless of the given arguments. With this commit: only the arguments that are NOT given and that have been defaulted to current (mocked) date/time will be offset by the adequate value. Furthermore: as these mocked parameters are meant to reflect UTC values, the offset now also considers the *actual* browser offset to generate a local date from the mock date parameters. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277041 Forward-Port-Of: odoo/odoo#275391
In the Outlook calendar sync, it's possible to have the same attendee twice. That's because the normalized email wasn't used to check for preexisting attendee. To reproduce, sync event with the organizer, also an attendee, using high case in the email such as: ORGANIZER: Mike@organizer.com ATTENDEE: Mike@organizer.com ATTENDEE: John@attendee.com opw-6186606 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272258 For
Original PR description
In the Outlook calendar sync, it's possible to have the same attendee twice. That's because the normalized email wasn't used to check for preexisting attendee. To reproduce, sync event with the organizer, also an attendee, using high case in the email such as: ORGANIZER: Mike@organizer.com ATTENDEE: Mike@organizer.com ATTENDEE: John@attendee.com opw-6186606 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272258 Forward-Port-Of: odoo/odoo#268201
Steps to reproduce: ------------------------------------ 1. Install barcode_gs1_nomenclature Module. 2. Go to Inventory > Configuration > Barcode Nomenclature. 3. Open any barcode nomenclature. Observation: ------------------------------------ The "Is GS1 Nomenclature" field is visible in the list header. Issue: ------------------------------------ The field uses the invisible attribute, which hides the field values but does not hide the corresponding list header, resulting in an e
Original PR description
Steps to reproduce: ------------------------------------ 1. Install barcode_gs1_nomenclature Module. 2. Go to Inventory > Configuration > Barcode Nomenclature. 3. Open any barcode nomenclature. Observation: ------------------------------------ The "Is GS1 Nomenclature" field is visible in the list header. Issue: ------------------------------------ The field uses the invisible attribute, which hides the field values but does not hide the corresponding list header, resulting in an empty header column. Solution: ------------------------------------ Replace the 'invisible' attribute with 'column_invisible' so that both the field values and the corresponding list header are hidden. opw-6390731 Forward-Port-Of: odoo/odoo#276532
Before this commit, when logging in as Demo user with a direct chat, logging out + logging in with Mitchell Admin would crash with the following error: ``` TypeError: can't access property "imStatusUI", this.channel.correspondent is undefined ``` This happens because this attempts to restore the direct chat in chat window. Normally this shouldn't happen thanks to being unable to fetch inaccessible channels, however Mitchell Admin is the admin of DB thus can fetch the channel data. The cr
Original PR description
Before this commit, when logging in as Demo user with a direct chat, logging out + logging in with Mitchell Admin would crash with the following error: ``` TypeError: can't access property…
Before this commit, when logging in as Demo user with a direct chat, logging out + logging in with Mitchell Admin would crash with the following error: ``` TypeError: can't access property "imStatusUI", this.channel.correspondent is undefined ``` This happens because this attempts to restore the direct chat in chat window. Normally this shouldn't happen thanks to being unable to fetch inaccessible channels, however Mitchell Admin is the admin of DB thus can fetch the channel data. The crash comes from computation of `correspondent` that is `undefined` because it can't determine a correspondent from the Point of view of Mitchell Admin, and the template isn't defensive against missing a `correspondent` in a direct chat. One solution could have been to support opening of direct chat, but this implies fixing a lot of complex issues, such as: - Mitchell Admin can't use composer because this attempts to add a member but there's a contraint for direct chat to have at most 2 members - This direct chat looks like a group chat without a name, we can guess this is a direct chat only because of broken avatar and the start message in message list stating this is a direct chat - Several other actions show weird behavior, like "Invite People" ignoring people in the chat This commit fixes the issue by ignoring the restore of chat in chat hub for direct chats that current user is not a member.
The `account_journal_type.bank` KPI (surfaced by the Databases app as `account_journal_type_bank`, tooltip "Draft entries in journal Bank") is meant to report journal entries in bank journals that still need attention: drafts, posted-but-unchecked entries, and posted bank entries that are not yet reconciled. The "not yet reconciled" case was implemented as: ```LEFT JOIN account_bank_statement_line st_line ON move.statement_line_id = st_line.id AND (st_line.id IS NULL O
Original PR description
The `account_journal_type.bank` KPI (surfaced by the Databases app as `account_journal_type_bank`, tooltip "Draft entries in journal Bank") is meant to report journal entries in bank journals that…
The `account_journal_type.bank` KPI (surfaced by the Databases app as `account_journal_type_bank`, tooltip "Draft entries in journal Bank") is meant to report journal entries in bank journals that still need attention: drafts, posted-but-unchecked entries, and posted bank entries that are not yet reconciled.
The "not yet reconciled" case was implemented as:
```LEFT JOIN account_bank_statement_line st_line
ON move.statement_line_id = st_line.id
AND (st_line.id IS NULL OR NOT st_line.is_reconciled)```
`st_line.id IS NULL` does not only match unreconciled bank transactions, it also matches any posted move booked directly in a bank journal that never originated from an imported bank statement line (manual entries, bank fees, opening balances, ...). Those moves have no `statement_line_id` by design and can never be reconciled, so they were counted as "pending" forever, permanently inflating the KPI for any database with such entries.
Only require an actual bank statement line before flagging it as unreconciled, matching the logic already used for the "to reconcile" count on the journal dashboard (account_journal_dashboard.py).
opw-6199785
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#275597Login uniqueness is enforced by a `UNIQUE (login)` constraint that Postgres compares byte for byte, so signing up with foo@example.com and then Foo@example.com produces two separate accounts pointing at the same real mailbox. https://github.com/odoo/odoo/blob/66a6c16551041543b5addfe846f15e769b4e9afe/odoo/addons/base/models/res_users.py#L274 Even if the DB constraint did catch an exact-case duplicate and `_signup_create_user` re-raised it as a `SignupError`, the controller's friendly "already re
Original PR description
Login uniqueness is enforced by a `UNIQUE (login)` constraint that Postgres compares byte for byte, so signing up with foo@example.com and then Foo@example.com produces two separate accounts pointing…
Login uniqueness is enforced by a `UNIQUE (login)` constraint that Postgres compares byte for byte, so signing up with foo@example.com and then Foo@example.com produces two separate accounts pointing at the same real mailbox. https://github.com/odoo/odoo/blob/66a6c16551041543b5addfe846f15e769b4e9afe/odoo/addons/base/models/res_users.py#L274 Even if the DB constraint did catch an exact-case duplicate and `_signup_create_user` re-raised it as a `SignupError`, the controller's friendly "already registered" branch only triggers when the duplicate lookup finds a row, and that lookup goes through `_get_login_domain` with an exact `=` operator. Case variants would fall into the generic "Could not create a new account" branch instead. https://github.com/odoo/odoo/blob/66a6c16551041543b5addfe846f15e769b4e9afe/addons/auth_signup/controllers/main.py#L68-L75 https://github.com/odoo/odoo/blob/66a6c16551041543b5addfe846f15e769b4e9afe/odoo/addons/base/models/res_users.py#L749-L750 `_signup_create_user` now refuses creation when a user with the same email already exists, applying to both b2c free signup and token-based invitations. It raises `UserError` directly so the controller's `except UserError` surfaces the message without a redundant lookup. The check uses `_get_email_domain`, whose base implementation is switched from `=` to `=ilike` over a value escaped via `tools.escape_psql` so `%` and `_` are matched literally rather than as wildcards. Its only existing caller is `reset_password`, which already wants case-insensitive matching. Steps to reproduce: 1. In Settings, set Customer Account to "Free sign up" and save. 2. Log out, then on the login page click "Don't have an account?". 3. Register with foo@example.com. 4. Log out again and click "Don't have an account?". 5. Register with Foo@example.com. => Two distinct user accounts are created for the same mailbox. opw-6199441 Forward-Port-Of: odoo/odoo#273071 Forward-Port-Of: odoo/odoo#263864
9 changes
Enhancements to existing features
The French balance sheet report now places establishment costs before fixed assets and includes additional impairment accounts in the relevant tangible fixed asset lines. This improves report consistency and helps ensure fixed asset values are presented more completely for French reporting.
Original PR description
Move establishment costs before fixed assets in the French balance sheet, and include the missing 2912, 2913, 2914, and 2915 impairment accounts in the relevant tangible fixed asset amortization/provision lines. task-6226138 Forward-Port-Of: odoo/enterprise#124562 Forward-Port-Of: odoo/enterprise#117689
Resolved issues and error corrections
The restaurant appointment point-of-sale test was adjusted to avoid repeating a data reload step that could cause false test failures. This improves test reliability without changing the normal user experience, since users are not expected to perform these immediate back-to-back reloads.
Original PR description
The `RestaurantAppointmentTour` performed two consecutive "Reload Data" actions. The first reload starts synchronizing data from the server to IndexedDB. If the second reload is triggered before the synchronization completes, it deletes the IndexedDB while it is still in use, causing the synchronization process to crash. This race condition can be reproduced locally by running the tour with `cpu_throttling` enabled. In practice, users never trigger two consecutive reloads, so the second reload step in the tour is unnecessary. Remove it to avoid the artificial race condition while preserving the intended test coverage. Task-[6364951](https://www.odoo.com/odoo/project/1737/tasks/6364951) Runbot Error-[941343](https://runbot.odoo.com/odoo/error/941343), [941344](https://runbot.odoo.com/odoo/error/941344), [941345](https://runbot.odoo.com/odoo/error/941345)
Users can no longer trigger a server error by typing an unknown name in the Add to or Reduce From fields on commission adjustments. The change removes an unsupported quick-create option, keeping the adjustment workflow stable and avoiding confusing error messages.
Original PR description
Steps to reproduce: - Go to Sales > Commission > Adjustments - In Add to/Reduce From, type a name with no match - Click Create '<name>' -> server crashes (RPC_ERROR) Cause: `sale.commission.plan.user._rec_name` is a Many2one (`user_id`). Default `name_create` wrote the typed text into that integer column, which Postgres rejected. Fix: - Disable quick-create on `add_user_id`/`reduce_user_id` in the Adjustments list view Version: saas-18.3 to master opw-6384909 Forward-Port-Of: odoo/enterprise#124431
Polish currency rates from NBP are no longer shifted by an extra day because the system already uses the required previous day's rate. This prevents rates from being dated too far back and helps Polish accounting use the correct exchange rate dates.
Original PR description
In Poland, it is mandatory to use the previous day's currency rate. We used to achieve this by shifting the rate's date by one day. Since https://github.com/odoo/odoo/pull/231948, we already use the previous day's rate, so the shift is no longer needed. See: https://www.odoo.com/mail/message/1118975071 Forward-Port-Of: odoo/enterprise#123849
This PR hides the Upgrade button for modules imported via file, as these modules cannot be upgraded without re-importing a file. Displaying the upgrade button in such cases could lead to confusion or unexpected behavior. Task: 4643890 Forward-Port-Of: odoo/odoo#213122
Original PR description
This PR hides the Upgrade button for modules imported via file, as these modules cannot be upgraded without re-importing a file. Displaying the upgrade button in such cases could lead to confusion or unexpected behavior. Task: 4643890 Forward-Port-Of: odoo/odoo#213122
Steps to reproduce: --- Case 1: 1. Add a carousel at the top of the page. 2. Apply the parallax effect to all slides. 3. Reload the page and navigate to the second slide without scrolling. 4. Scroll slightly and observe the jump in background position. 5. Scroll back to the top and notice the changed background position. Case 2: 1. Add a carousel to the page. 2. Apply the parallax effect to each slide. 3. Add text over the carousel and enable animation on appearance and on eve
Original PR description
Steps to reproduce: --- Case 1: 1. Add a carousel at the top of the page. 2. Apply the parallax effect to all slides. 3. Reload the page and navigate to the second slide without scrolling. 4. Scroll…
Steps to reproduce: --- Case 1: 1. Add a carousel at the top of the page. 2. Apply the parallax effect to all slides. 3. Reload the page and navigate to the second slide without scrolling. 4. Scroll slightly and observe the jump in background position. 5. Scroll back to the top and notice the changed background position. Case 2: 1. Add a carousel to the page. 2. Apply the parallax effect to each slide. 3. Add text over the carousel and enable animation on appearance and on every time. 4. Slide between images and observe the bouncing effect. https://github.com/user-attachments/assets/d11ee430-8b95-4903-b001-1b9ba8ee58cd Why this change? --- When the parallax effect is applied to carousel slides, only the first slide is initialized with the correct [parallaxHeight](https://github.com/odoo/odoo/blob/616e82d7b3a53b1facf481e783baed3e99393d3c/addons/website/static/src/interactions/parallax/parallax.js#L49). The remaining slides are initialized while hidden, resulting in a computed height of 0. When scrolling, the background height is recalculated with the correct value, producing a visible jump effect. Additionally, when text or any animated content is added on top of the carousel (especially animations triggered on appearance or on every slide change), a [resize event](https://github.com/odoo/odoo/blob/616e82d7b3a53b1facf481e783baed3e99393d3c/addons/website/static/src/interactions/animation.js#L111) is triggered on each transition. This causes `updateBackgroundHeight()` to run again. Since hidden slides were initialized with height 0 and later receive their actual height, the recalculation produces a noticeable bouncing effect. After this commit: --- The parallax computation now relies on the parent element’s `getBoundingClientRect().height` when used inside a carousel. Since the carousel slide height is already defined and consistent, this ensures correct initialization even when the slide is not yet visible. OPW: 5909351 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#250290
Add a regression test ensuring that setting a relative date global filter on a dynamic Odoo pivot does not crash while the pivot table is reloading. Task: 6306263 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Add a regression test ensuring that setting a relative date global filter on a dynamic Odoo pivot does not crash while the pivot table is reloading. Task: 6306263 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Rather than assign `log_target` and blow up if the third branch is taken, use a `defaultdict` and just increment the count in each branch on hit. The continue in the third branch is not strictly necessary, but that way it protects us if anyone decides to add post-processing which also doesn't account for the third branch. Forward-Port-Of: odoo/odoo#276757 Forward-Port-Of: odoo/odoo#276481
Original PR description
Rather than assign `log_target` and blow up if the third branch is taken, use a `defaultdict` and just increment the count in each branch on hit. The continue in the third branch is not strictly necessary, but that way it protects us if anyone decides to add post-processing which also doesn't account for the third branch. Forward-Port-Of: odoo/odoo#276757 Forward-Port-Of: odoo/odoo#276481
Steps to reproduce --- 1. Install a carrier that requires a positive package shipping weight (e.g. UPS) and enable Packages. 2. From the Barcode app, process a delivery and Put in Pack the products. 3. Validate the transfer. Issue --- Validation is refused because the package has no positive shipping weight, even though its computed weight is correct. The package shipping weight is only set in `_post_put_in_pack_hook` from `context['weight']`, which is filled exclusively by the put i
Original PR description
Steps to reproduce --- 1. Install a carrier that requires a positive package shipping weight (e.g. UPS) and enable Packages. 2. From the Barcode app, process a delivery and Put in Pack the products.…
Steps to reproduce --- 1. Install a carrier that requires a positive package shipping weight (e.g. UPS) and enable Packages. 2. From the Barcode app, process a delivery and Put in Pack the products. 3. Validate the transfer. Issue --- Validation is refused because the package has no positive shipping weight, even though its computed weight is correct. The package shipping weight is only set in `_post_put_in_pack_hook` from `context['weight']`, which is filled exclusively by the put in pack wizard. Flows that bypass the wizard, like the Barcode app, never provide that key, so the stored `shipping_weight` stays 0 while carriers reading it directly reject the delivery. The Barcode app suppresses the wizard through the `barcode_view` context, so its put in pack goes straight to the hook without any weight. https://github.com/odoo/enterprise/blob/6b18215bfa98ef636b63f4fafbba1d25264f4883/stock_barcode/models/stock_move_line.py#L193-L196 This handling was centralized in this hook by 9a2ff6f4033e, so every wizard-bypassed pack leaves the field empty. Defaulting it to the package computed weight via `_get_weight` when the context did not provide one makes the stored value correct for any carrier, independently of the flow that created the package. https://github.com/odoo/odoo/blob/4235b48c86077bd5bceb9e817cc45b2eec8697e8/addons/stock_delivery/models/stock_move.py#L111-L115 opw-6297689 Forward-Port-Of: odoo/odoo#273876 Forward-Port-Of: odoo/odoo#272510
17 changes
Resolved issues and error corrections
The planning kanban card now shows allocated time in a simpler, consistent format such as (4h30). Removing the separate percentage display fixes uneven spacing and makes schedules easier to scan.
Original PR description
Currently, the allocated hours and allocated percentage are misaligned in the planning kanban card, causing them to appear uneven or have inconsistent spacing. This fix removes the allocated percentage and formats the allocated hours to display like (4h30). task-5085363 Forward-Port-Of: odoo/enterprise#98776
Philippine check printing now rounds the cents portion of amounts in words to two decimal places, even when the currency is configured with more precision. This prevents checks from showing incorrect fractional text such as 1268/100 instead of 13/100, reducing confusion and payment errors.
Original PR description
Current behavior: --- When paying with checks, if the currency has more than 2 decimals, the decimal amount is printed with more than 2 decimals. Steps to reproduce: --- 1. Switch to PH company 2. Set setting Check Layout as "Print Check - PH" 3. In the PHP currency, change rounding factor to 0.0001 4. In Decimal accuracy > product price, set 4 digits 5. Create a new Vendor Payment, payment method Check, amount 100.1268 PHP 6. Results: One Hundred and 1268/100, should be 13/100 Expected behavior: --- The xx/100 part of amount in words text in the check should always be rounded to 2 decimals. opw-6302337 Forward-Port-Of: odoo/enterprise#122581 Forward-Port-Of: odoo/enterprise#121913
Users can no longer trigger a server error by creating a new entry directly from the Add to or Reduce From fields in Sales Commission Adjustments. The change disables that shortcut so adjustments can be edited safely without interrupting the workflow.
Original PR description
Steps to reproduce: - Go to Sales > Commission > Adjustments - In Add to/Reduce From, type a name with no match - Click Create '<name>' -> server crashes (RPC_ERROR) Cause: `sale.commission.plan.user._rec_name` is a Many2one (`user_id`). Default `name_create` wrote the typed text into that integer column, which Postgres rejected. Fix: - Disable quick-create on `add_user_id`/`reduce_user_id` in the Adjustments list view Version: saas-18.3 to master opw-6384909 Forward-Port-Of: odoo/enterprise#124431
This PR hides the Upgrade button for modules imported via file, as these modules cannot be upgraded without re-importing a file. Displaying the upgrade button in such cases could lead to confusion or unexpected behavior. Task: 4643890 Forward-Port-Of: odoo/odoo#213122
Original PR description
This PR hides the Upgrade button for modules imported via file, as these modules cannot be upgraded without re-importing a file. Displaying the upgrade button in such cases could lead to confusion or unexpected behavior. Task: 4643890 Forward-Port-Of: odoo/odoo#213122
Steps to produce: --- - Install the `Sales` module. - Go to Invoicing > Configuration > Accounting > Taxes. - Open the 0% Exports tax and set a value in the `Label on Invoices.` Field under the Advanced Options tab. - Create a sale order with multiple sections, apply the 0% Exports tax to the order lines, and enable `Hide Composition` on one of the sections. - Preview the sale order. Issue: --- - The tax displayed in a collapsed section summary differs from the tax shown on regular or
Original PR description
Steps to produce: --- - Install the `Sales` module. - Go to Invoicing > Configuration > Accounting > Taxes. - Open the 0% Exports tax and set a value in the `Label on Invoices.` Field under the…
Steps to produce: --- - Install the `Sales` module. - Go to Invoicing > Configuration > Accounting > Taxes. - Open the 0% Exports tax and set a value in the `Label on Invoices.` Field under the Advanced Options tab. - Create a sale order with multiple sections, apply the 0% Exports tax to the order lines, and enable `Hide Composition` on one of the sections. - Preview the sale order. Issue: --- - The tax displayed in a collapsed section summary differs from the tax shown on regular order lines for the same tax. Root cause: --- - At [1], `_get_grouped_section_summary()` only returns `tax_labels`, which are then used when rendering the collapsed section summary. As a result, the invoice label is displayed instead of the actual tax name. Solution: --- - Add `tax_names` to the values returned by `_get_grouped_section_summary()` and use them when rendering the collapsed section summary, ensuring consistent tax information across the preview. - Also removed the unnecessary fallback in the return statement, as `res` is always populated. [1]https://github.com/odoo/odoo/blob/be0bf1365e054521ece224f5e3a4b7cbce402315/addons/sale/models/sale_order_line.py#L1572-L1604 Before: --- <img width="1068" height="156" alt="image" src="https://github.com/user-attachments/assets/8030c35e-5c73-4fed-9feb-c4729add7894" /> After: --- <img width="1057" height="143" alt="image" src="https://github.com/user-attachments/assets/336030ed-68b2-4d14-b26f-ff391257d6d4" /> opw-6294141 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270544
Steps to reproduce: --- Case 1: 1. Add a carousel at the top of the page. 2. Apply the parallax effect to all slides. 3. Reload the page and navigate to the second slide without scrolling. 4. Scroll slightly and observe the jump in background position. 5. Scroll back to the top and notice the changed background position. Case 2: 1. Add a carousel to the page. 2. Apply the parallax effect to each slide. 3. Add text over the carousel and enable animation on appearance and on eve
Original PR description
Steps to reproduce: --- Case 1: 1. Add a carousel at the top of the page. 2. Apply the parallax effect to all slides. 3. Reload the page and navigate to the second slide without scrolling. 4. Scroll…
Steps to reproduce: --- Case 1: 1. Add a carousel at the top of the page. 2. Apply the parallax effect to all slides. 3. Reload the page and navigate to the second slide without scrolling. 4. Scroll slightly and observe the jump in background position. 5. Scroll back to the top and notice the changed background position. Case 2: 1. Add a carousel to the page. 2. Apply the parallax effect to each slide. 3. Add text over the carousel and enable animation on appearance and on every time. 4. Slide between images and observe the bouncing effect. https://github.com/user-attachments/assets/d11ee430-8b95-4903-b001-1b9ba8ee58cd Why this change? --- When the parallax effect is applied to carousel slides, only the first slide is initialized with the correct [parallaxHeight](https://github.com/odoo/odoo/blob/616e82d7b3a53b1facf481e783baed3e99393d3c/addons/website/static/src/interactions/parallax/parallax.js#L49). The remaining slides are initialized while hidden, resulting in a computed height of 0. When scrolling, the background height is recalculated with the correct value, producing a visible jump effect. Additionally, when text or any animated content is added on top of the carousel (especially animations triggered on appearance or on every slide change), a [resize event](https://github.com/odoo/odoo/blob/616e82d7b3a53b1facf481e783baed3e99393d3c/addons/website/static/src/interactions/animation.js#L111) is triggered on each transition. This causes `updateBackgroundHeight()` to run again. Since hidden slides were initialized with height 0 and later receive their actual height, the recalculation produces a noticeable bouncing effect. After this commit: --- The parallax computation now relies on the parent element’s `getBoundingClientRect().height` when used inside a carousel. Since the carousel slide height is already defined and consistent, this ensures correct initialization even when the slide is not yet visible. OPW: 5909351 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#250290
Rather than assign `log_target` and blow up if the third branch is taken, use a `defaultdict` and just increment the count in each branch on hit. The continue in the third branch is not strictly necessary, but that way it protects us if anyone decides to add post-processing which also doesn't account for the third branch. Forward-Port-Of: odoo/odoo#276757 Forward-Port-Of: odoo/odoo#276481
Original PR description
Rather than assign `log_target` and blow up if the third branch is taken, use a `defaultdict` and just increment the count in each branch on hit. The continue in the third branch is not strictly necessary, but that way it protects us if anyone decides to add post-processing which also doesn't account for the third branch. Forward-Port-Of: odoo/odoo#276757 Forward-Port-Of: odoo/odoo#276481
Steps to reproduce: 1. Drop the Website Form snippet. 2. Add a checkbox field. 3. Change the label position to Top. > The Default Value option disappears. Cause: The `applyTo` selector relied on the `.col-sm` wrapper, which is only present for left/right label positions. As a result, it did not match checkbox fields with Top or None labels. This commit fix the applyTo selector so the Default Value option is displayed for checkbox fields regardless of the selected label position.
Original PR description
Steps to reproduce: 1. Drop the Website Form snippet. 2. Add a checkbox field. 3. Change the label position to Top. > The Default Value option disappears. Cause: The `applyTo` selector relied on the `.col-sm` wrapper, which is only present for left/right label positions. As a result, it did not match checkbox fields with Top or None labels. This commit fix the applyTo selector so the Default Value option is displayed for checkbox fields regardless of the selected label position. task-6373796 Forward-Port-Of: odoo/odoo#275823
### [FIX] web: fix mocked dates in tests Dates are mocked in all unit tests by default; either to a default static value, or to one defined in the test/suite. To do so, the `window.Date` constructor is overridden to have the arguments auto-filled with the current mock date paramters. Before this commit, an additional offset was always added to the given arguments to reflect: - the time elapsed from the beginning of the test; - any virtual offset added by a helper such as 'advanceTime
Original PR description
### [FIX] web: fix mocked dates in tests Dates are mocked in all unit tests by default; either to a default static value, or to one defined in the test/suite. To do so, the `window.Date` constructor…
### [FIX] web: fix mocked dates in tests Dates are mocked in all unit tests by default; either to a default static value, or to one defined in the test/suite. To do so, the `window.Date` constructor is overridden to have the arguments auto-filled with the current mock date paramters. Before this commit, an additional offset was always added to the given arguments to reflect: - the time elapsed from the beginning of the test; - any virtual offset added by a helper such as 'advanceTime'. The issue is that the spec of the Date constructor wants that the returned date object has to match all given arguments, and any omitted argument will be defaulted to the current date/time. This was not the case in tests, as the offset was always added, regardless of the given arguments. With this commit: only the arguments that are NOT given and that have been defaulted to current (mocked) date/time will be offset by the adequate value. Furthermore: as these mocked parameters are meant to reflect UTC values, the offset now also considers the *actual* browser offset to generate a local date from the mock date parameters. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277041 Forward-Port-Of: odoo/odoo#275391
**Steps to reproduce:** 1. Create a Sales Order. 2. Create a 50% down payment invoice. 3. Create a credit note for the down payment invoice. 4. Reset the credit note to Draft and cancel it. 5. Create the final invoice from the Sales Order. **Issue:** The final invoice is generated for 100% of the order amount, acting as if the down payment invoice does not exist. **Expected behavior:** The final invoice should only include the remaining 50% of the order amount because a valid 50% do
Original PR description
**Steps to reproduce:** 1. Create a Sales Order. 2. Create a 50% down payment invoice. 3. Create a credit note for the down payment invoice. 4. Reset the credit note to Draft and cancel it. 5. Create…
**Steps to reproduce:** 1. Create a Sales Order. 2. Create a 50% down payment invoice. 3. Create a credit note for the down payment invoice. 4. Reset the credit note to Draft and cancel it. 5. Create the final invoice from the Sales Order. **Issue:** The final invoice is generated for 100% of the order amount, acting as if the down payment invoice does not exist. **Expected behavior:** The final invoice should only include the remaining 50% of the order amount because a valid 50% down payment invoice still exists. **Why this happens:** - The `price_unit` on the Sales Order's down payment line is manually updated during `action_post()` based on the sum of posted invoices minus posted credit notes. - When the credit note is posted, `price_unit` drops to 0. However, when that credit note is subsequently reset to draft and cancelled, it triggers `button_cancel()` which only refreshed the line's display name and failed to recalculate `price_unit`. As a result, `price_unit` remained at 0 even though the credit note was no longer active, causing the final invoice to deduct nothing. opw-6373578 Forward-Port-Of: odoo/odoo#277043 Forward-Port-Of: odoo/odoo#275684
In the Outlook calendar sync, it's possible to have the same attendee twice. That's because the normalized email wasn't used to check for preexisting attendee. To reproduce, sync event with the organizer, also an attendee, using high case in the email such as: ORGANIZER: Mike@organizer.com ATTENDEE: Mike@organizer.com ATTENDEE: John@attendee.com opw-6186606 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272258 For
Original PR description
In the Outlook calendar sync, it's possible to have the same attendee twice. That's because the normalized email wasn't used to check for preexisting attendee. To reproduce, sync event with the organizer, also an attendee, using high case in the email such as: ORGANIZER: Mike@organizer.com ATTENDEE: Mike@organizer.com ATTENDEE: John@attendee.com opw-6186606 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272258 Forward-Port-Of: odoo/odoo#268201
Before this commit, two issues affected custom snippet saves. First, the new builder allowed saving the Alternative Products block from product pages as a custom snippet. This block is generated from the current product alternatives, so it is page-specific content. Second, a block saved as a custom snippet could keep `oe_unremovable` or `oe_unmovable` on its root. A saved custom snippet is meant to become a normal reusable block. Once the user drops it on another page, they should be able
Original PR description
Before this commit, two issues affected custom snippet saves. First, the new builder allowed saving the Alternative Products block from product pages as a custom snippet. This block is generated from the current product alternatives, so it is page-specific content. Second, a block saved as a custom snippet could keep `oe_unremovable` or `oe_unmovable` on its root. A saved custom snippet is meant to become a normal reusable block. Once the user drops it on another page, they should be able to remove it or move it like any other block. After this commit, builder plugins can declare selectors that cannot be saved as custom snippets, and `website_sale` uses this to exclude the Alternative Products block. The saved copy also drops `oe_unremovable` and `oe_unmovable` on its root before calling `ir.ui.view.save_snippet`. task-6296872 Forward-Port-Of: odoo/odoo#275303
Currently, we only load the XML data from the exported POS order in the field `l10n_jo_edi_pos_computed_xml` when`l10n_jo_edi_pos_error` is False. It should be the opposite. The field `l10n_jo_edi_pos_computed_xml` is only used when we call `download_l10n_jo_edi_pos_computed_xml()` from the anchor "Download XML" , and that anchor is only visible when `l10n_jo_edi_pos_error` is True. If the request succeeds, then the XML file will be stored in the field `l10n_jo_edi_pos_xml_attachment_i
Original PR description
Currently, we only load the XML data from the exported POS order in the field `l10n_jo_edi_pos_computed_xml` when`l10n_jo_edi_pos_error` is False. It should be the opposite. The field `l10n_jo_edi_pos_computed_xml` is only used when we call `download_l10n_jo_edi_pos_computed_xml()` from the anchor "Download XML" , and that anchor is only visible when `l10n_jo_edi_pos_error` is True. If the request succeeds, then the XML file will be stored in the field `l10n_jo_edi_pos_xml_attachment_id` anyway. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276918
Steps to reproduce 1. Set the user timezone to one with a positive UTC offset, e.g. Europe/Brussels. 2. Open Payroll > Work Entries in pivot view and apply the built-in "Current Month" filter. 3. Expand an employee row and group by Date > Day. Expected: only days of the current month are visible (April 1..30 at the time of writing). Actual: the last day of the previous month (March 31) is included and the last day of the current month (April 30) is missing — the whole window
Original PR description
Steps to reproduce 1. Set the user timezone to one with a positive UTC offset, e.g. Europe/Brussels. 2. Open Payroll > Work Entries in pivot view and apply the built-in "Current Month" filter. 3.…
Steps to reproduce 1. Set the user timezone to one with a positive UTC offset, e.g. Europe/Brussels. 2. Open Payroll > Work Entries in pivot view and apply the built-in "Current Month" filter. 3. Expand an employee row and group by Date > Day. Expected: only days of the current month are visible (April 1..30 at the time of writing). Actual: the last day of the previous month (March 31) is included and the last day of the current month (April 30) is missing — the whole window is shifted one day earlier. Issue The relative-date DSL added in https://github.com/odoo/odoo/commit/d1ea43f6721116914762ea323d8a5987f043e87f operates on a tz-aware datetime starting from `now` when no explicit anchor is given. With the filter at https://github.com/odoo/odoo/blob/d58f4ed332af35f6de26a93f07adf05368731e20/addons/hr_work_entry/views/hr_work_entry_views.xml#L190-L192, `=1d` resets the clock to 00:00 and the day to the 1st in the user's timezone, evaluating to `2026-04-01 00:00:00+02:00` for Brussels. `parse_date` then normalizes that to UTC-naive `2026-03-31 22:00:00` (see https://github.com/odoo/odoo/blob/d58f4ed332af35f6de26a93f07adf05368731e20/odoo/tools/date_utils.py#L196-L199). When the ORM compares this to the `fields.Date` column `date` it truncates via `datetime.date()` (see https://github.com/odoo/odoo/blob/d58f4ed332af35f6de26a93f07adf05368731e20/odoo/orm/fields_temporal.py#L138-L158), yielding `2026-03-31`. The effective domain becomes `[2026-03-31, 2026-04-30)` instead of `[2026-04-01, 2026-05-01)`, which is why March 31 leaks in and April 30 disappears. Solution Anchor the filter to `today` instead of the implicit `now`. The DSL documents `today` as a starting point that yields a `date` value (see https://github.com/odoo/odoo/blob/d58f4ed332af35f6de26a93f07adf05368731e20/odoo/tools/date_utils.py#L108-L144), so `today =1d` resolves to the first of the month as a calendar date end-to-end and never goes through the tz-aware datetime → UTC-naive roundtrip that was silently shifting the window. opw-6123753 Forward-Port-Of: odoo/odoo#260727
Steps to reproduce: ------------------------------------ 1. Install barcode_gs1_nomenclature Module. 2. Go to Inventory > Configuration > Barcode Nomenclature. 3. Open any barcode nomenclature. Observation: ------------------------------------ The "Is GS1 Nomenclature" field is visible in the list header. Issue: ------------------------------------ The field uses the invisible attribute, which hides the field values but does not hide the corresponding list header, resulting in an e
Original PR description
Steps to reproduce: ------------------------------------ 1. Install barcode_gs1_nomenclature Module. 2. Go to Inventory > Configuration > Barcode Nomenclature. 3. Open any barcode nomenclature. Observation: ------------------------------------ The "Is GS1 Nomenclature" field is visible in the list header. Issue: ------------------------------------ The field uses the invisible attribute, which hides the field values but does not hide the corresponding list header, resulting in an empty header column. Solution: ------------------------------------ Replace the 'invisible' attribute with 'column_invisible' so that both the field values and the corresponding list header are hidden. opw-6390731 Forward-Port-Of: odoo/odoo#276532
**Steps to reproduce:** - Install the `accountant` and `sale_management` modules. - Create and confirm a SO with a product whose `Invoicing Policy` is set to `Ordered quantities`. - Click `Create Invoices` > select `Regular invoice` > `Create Draft`. (leave the invoice in the draft state). - Navigate to Accounting > Review > Invoiced Not Delivered. - Select the newly created invoice and click `Create Accrual Entries`. **Error:** `ZeroDivisionError: division by zero` **Root Ca
Original PR description
**Steps to reproduce:** - Install the `accountant` and `sale_management` modules. - Create and confirm a SO with a product whose `Invoicing Policy` is set to `Ordered quantities`. - Click `Create…
**Steps to reproduce:** - Install the `accountant` and `sale_management` modules. - Create and confirm a SO with a product whose `Invoicing Policy` is set to `Ordered quantities`. - Click `Create Invoices` > select `Regular invoice` > `Create Draft`. (leave the invoice in the draft state). - Navigate to Accounting > Review > Invoiced Not Delivered. - Select the newly created invoice and click `Create Accrual Entries`. **Error:** `ZeroDivisionError: division by zero` **Root Cause:** At [1], `processed_qty` is initialized with `0`. If all the selected invoices are in the draft state, the code never enters the for loop, so `processed_qty` remains 0. Later, it attempts to divide the `amount` by `processed_qty`, causing an error. **Fix:** This commit prevents errors when creating accrual entries for draft invoices. [1]: https://github.com/odoo/odoo/blob/a7d285a833f5b1d47a11a1b8ec31e3730c1c854c/addons/account/wizard/accrued_orders.py#L258-L265 opw-6332652 Forward-Port-Of: odoo/odoo#273330
**Issue 1:** Steps to reproduce: - Install the `l10n_ar` module. - Go to Customers and create a new customer with the country set to Argentina. - Set `Identification Type` to `CUIL` and `Identification Number` to `1234567890a`. **Error:** `ValueError: invalid literal for int() with base 10: '1234567890a'` **Issue 2:** - Set `Identification Type` to any type other than `CUIT`, `DNI`, or `CUIL`. - Set `Identification Number` to `1234567890a`. **Observation:** All non-digit chara
Original PR description
**Issue 1:** Steps to reproduce: - Install the `l10n_ar` module. - Go to Customers and create a new customer with the country set to Argentina. - Set `Identification Type` to `CUIL` and…
**Issue 1:** Steps to reproduce: - Install the `l10n_ar` module. - Go to Customers and create a new customer with the country set to Argentina. - Set `Identification Type` to `CUIL` and `Identification Number` to `1234567890a`. **Error:** `ValueError: invalid literal for int() with base 10: '1234567890a'` **Issue 2:** - Set `Identification Type` to any type other than `CUIT`, `DNI`, or `CUIL`. - Set `Identification Number` to `1234567890a`. **Observation:** All non-digit characters are stripped, and the identification number is silently changed to `1234567890`. **Expected behaviour:** Any Identification Type other than CUIT (80), CUIL (86), and DNI (96) should be kept unchanged without stripping alphabetic characters. **Root Cause:** At [1], `_get_id_number_sanitize` sanitizes identification numbers based on the selected Identification Type. - For `CUIT` and `CUIL`, `stdnum.ar.cuit.compact()` only removes separators (e.g., spaces and dashes). If the identification number contains alphabetic characters, they are preserved and called `int()` on the resulting value, raising a `ValueError`. - For all other identification types, valid alphanumeric values are unintentionally modified by stripping non-digit characters. **Fix:** This commit validates identification numbers before sanitization for `CUIT` (80), `CUIL` (86), and `DNI` (96), ensuring only valid numeric identification numbers are converted. For all other identification types, it preserves alphanumeric characters by removing only non-alphanumeric separators. [1]: https://github.com/odoo/odoo/blob/08b75d753c638e9d2d7418b55e9107bda471cb31/addons/l10n_ar/models/res_partner.py#L124-L136 Related enterrpise PR: https://github.com/odoo/enterprise/pull/123729 opw-6333998 Forward-Port-Of: odoo/odoo#272651
2 changes
Resolved issues and error corrections
Commission adjustment screens no longer allow quick creation in the Add to or Reduce From fields, avoiding a server error when users type a new unmatched name. This keeps the adjustment workflow stable and prevents interruptions for sales commission administrators.
Original PR description
Steps to reproduce: - Go to Sales > Commission > Adjustments - In Add to/Reduce From, type a name with no match - Click Create '<name>' -> server crashes (RPC_ERROR) Cause: `sale.commission.plan.user._rec_name` is a Many2one (`user_id`). Default `name_create` wrote the typed text into that integer column, which Postgres rejected. Fix: - Disable quick-create on `add_user_id`/`reduce_user_id` in the Adjustments list view Version: saas-18.3 to master opw-6384909 Forward-Port-Of: odoo/enterprise#124431
Philippine check printing now rounds the cents portion of written payment amounts to two decimals, even when the currency is configured with more precision. This prevents checks from showing incorrect fractional amounts such as 1268/100 instead of 13/100.
Original PR description
Current behavior: --- When paying with checks, if the currency has more than 2 decimals, the decimal amount is printed with more than 2 decimals. Steps to reproduce: --- 1. Switch to PH company 2. Set setting Check Layout as "Print Check - PH" 3. In the PHP currency, change rounding factor to 0.0001 4. In Decimal accuracy > product price, set 4 digits 5. Create a new Vendor Payment, payment method Check, amount 100.1268 PHP 6. Results: One Hundred and 1268/100, should be 13/100 Expected behavior: --- The xx/100 part of amount in words text in the check should always be rounded to 2 decimals. opw-6302337 Forward-Port-Of: odoo/enterprise#122581 Forward-Port-Of: odoo/enterprise#121913
6 changes
Resolved issues and error corrections
Philippine check printing now rounds the fractional amount in words to two decimal places, even when the currency is configured with more precision. This prevents checks from showing incorrect cent values such as 1268/100 instead of 13/100, reducing confusion and payment errors.
Original PR description
Current behavior: --- When paying with checks, if the currency has more than 2 decimals, the decimal amount is printed with more than 2 decimals. Steps to reproduce: --- 1. Switch to PH company 2. Set setting Check Layout as "Print Check - PH" 3. In the PHP currency, change rounding factor to 0.0001 4. In Decimal accuracy > product price, set 4 digits 5. Create a new Vendor Payment, payment method Check, amount 100.1268 PHP 6. Results: One Hundred and 1268/100, should be 13/100 Expected behavior: --- The xx/100 part of amount in words text in the check should always be rounded to 2 decimals. opw-6302337 Forward-Port-Of: odoo/enterprise#122581 Forward-Port-Of: odoo/enterprise#121913
Users can now turn an AI provider on or off without removing the saved API key. This makes AI configuration easier to manage and avoids unnecessary re-entry of credentials when temporarily disabling a provider.
Original PR description
Prior to this fix, user had to delete the API key set in order to disable the corresponding provider option in the ai config view. With this PR, we all allow the enable/disable provider option independently from the API key value. task: 6331248
Invoice dashboard data, specifically DSO, was incorrectly aligned due to a mismatch in the fiscal year structure. Task-6049887 Forward-Port-Of: odoo/odoo#261037
Original PR description
Invoice dashboard data, specifically DSO, was incorrectly aligned due to a mismatch in the fiscal year structure. Task-6049887 Forward-Port-Of: odoo/odoo#261037
Currently, we only load the XML data from the exported POS order in the field `l10n_jo_edi_pos_computed_xml` when`l10n_jo_edi_pos_error` is False. It should be the opposite. The field `l10n_jo_edi_pos_computed_xml` is only used when we call `download_l10n_jo_edi_pos_computed_xml()` from the anchor "Download XML" , and that anchor is only visible when `l10n_jo_edi_pos_error` is True. If the request succeeds, then the XML file will be stored in the field `l10n_jo_edi_pos_xml_attachment_i
Original PR description
Currently, we only load the XML data from the exported POS order in the field `l10n_jo_edi_pos_computed_xml` when`l10n_jo_edi_pos_error` is False. It should be the opposite. The field `l10n_jo_edi_pos_computed_xml` is only used when we call `download_l10n_jo_edi_pos_computed_xml()` from the anchor "Download XML" , and that anchor is only visible when `l10n_jo_edi_pos_error` is True. If the request succeeds, then the XML file will be stored in the field `l10n_jo_edi_pos_xml_attachment_id` anyway. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276918
Steps to reproduce: ------------------------------------ 1. Install barcode_gs1_nomenclature Module. 2. Go to Inventory > Configuration > Barcode Nomenclature. 3. Open any barcode nomenclature. Observation: ------------------------------------ The "Is GS1 Nomenclature" field is visible in the list header. Issue: ------------------------------------ The field uses the invisible attribute, which hides the field values but does not hide the corresponding list header, resulting in an e
Original PR description
Steps to reproduce: ------------------------------------ 1. Install barcode_gs1_nomenclature Module. 2. Go to Inventory > Configuration > Barcode Nomenclature. 3. Open any barcode nomenclature. Observation: ------------------------------------ The "Is GS1 Nomenclature" field is visible in the list header. Issue: ------------------------------------ The field uses the invisible attribute, which hides the field values but does not hide the corresponding list header, resulting in an empty header column. Solution: ------------------------------------ Replace the 'invisible' attribute with 'column_invisible' so that both the field values and the corresponding list header are hidden. opw-6390731 Forward-Port-Of: odoo/odoo#276532
Steps to reproduce: ================== 1. Add a Donation snippet on a page 2. Click "Donate Now" 3. Switch the website language on the payment page => Configured amounts/descriptions disappear Cause: ====== The donation snippet posts its configuration (prefilled amounts, display options, descriptions) in the request body. If the user switches the website language on the payment page, it triggers a page reload via a GET request which drops the original form body (this also applies to
Original PR description
Steps to reproduce: ================== 1. Add a Donation snippet on a page 2. Click "Donate Now" 3. Switch the website language on the payment page => Configured amounts/descriptions disappear Cause:…
Steps to reproduce: ================== 1. Add a Donation snippet on a page 2. Click "Donate Now" 3. Switch the website language on the payment page => Configured amounts/descriptions disappear Cause: ====== The donation snippet posts its configuration (prefilled amounts, display options, descriptions) in the request body. If the user switches the website language on the payment page, it triggers a page reload via a GET request which drops the original form body (this also applies to a simple page refresh). As a result, the kwargs were empty and the page fell back to the default free-amount input, losing the configured options. Solution: ========= Implement Post/Redirect/Get: on POST, redirect to /donation/pay with the options in the query string so any later GET (language switch, refresh, iframe src reload) re-renders a fully configured page without losing data. Alternative Solution: ===================== We could also store the options in the session, but the current solution is much simpler and avoids session pollution. opw-6282391 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271460
19 changes
Enhancements to existing features
This update aligns the naming used for a Mexican electronic invoicing method in the website sales flow. It helps keep the checkout and invoicing experience consistent with related Odoo changes, with minimal visible impact for users.
Original PR description
see community for reference: https://github.com/odoo/odoo/pull/276851
Obox can now send service failure messages to the Odoo database, where they are stored as logs. This helps users in debug mode and support teams see when an Obox service has failed, making diagnosis easier.
Original PR description
This PR adds a controller which allows the obox to contact the db to send a message. The db then creates an `obox.log` record which is visible in debug mode to the user. This is currently used to notify the databse when a service fails on the obox Obox PR: https://github.com/odoo/obox/pull/192
Updated accounting-related test cases to reflect the current way invoice and bill due dates are calculated. This helps keep automated quality checks reliable by expecting due dates to follow invoice dates and payment terms instead of defaulting to today.
Original PR description
Before this commit: Several tests still relied on the previous behavior where the Due Date was automatically set to Today's Date by default. Since the due date computation was updated, these assumptions caused the tests to fail. With this change: Updated the affected test cases to match the new due date computation. Tests now expect the Due Date to be computed based on the Invoice/Bill Date and selected Payment Terms. Where no Payment Terms are configured, tests now expect the Due Date to match the Invoice/Bill Date. task-6309674 Related - [odoo/community](https://github.com/odoo/odoo/pull/271831/)
WhatsApp conversation threads now display their associated avatar in the discussion view. This makes it easier for users to recognize and distinguish WhatsApp channels at a glance.
Original PR description
Purpose of this commit: Show thread avatar for channel type whatsapp Before <img width="462" height="134" alt="image" src="https://github.com/user-attachments/assets/72bc9bab-877d-4a42-aa3e-a7cfb12c6065" /> After <img width="624" height="107" alt="image" src="https://github.com/user-attachments/assets/ba6fe94a-7751-42e9-a1cc-4976c3d5eaa5" /> task-6398499
The French balance sheet report now places establishment costs before fixed assets and includes additional impairment accounts for tangible fixed assets. This improves the accuracy and presentation of French financial statements for reporting users.
Original PR description
Move establishment costs before fixed assets in the French balance sheet, and include the missing 2912, 2913, 2914, and 2915 impairment accounts in the relevant tangible fixed asset amortization/provision lines. task-6226138 Forward-Port-Of: odoo/enterprise#124562 Forward-Port-Of: odoo/enterprise#117689
Resolved issues and error corrections
This fixes an error that could occur when opening a planning calendar popover in Field Service. The calendar now includes the needed user information so users can view planning details without hitting an unexpected crash.
Original PR description
add the user_ids field to the calendar view because its needed in a popover task: 6358644 Forward-Port-Of: odoo/enterprise#122684
Polish currency rate imports now avoid applying an extra one-day date shift. This prevents rates from being dated too far back now that the system already uses the previous day's rate as required.
Original PR description
In Poland, it is mandatory to use the previous day's currency rate. We used to achieve this by shifting the rate's date by one day. Since https://github.com/odoo/odoo/pull/231948, we already use the previous day's rate, so the shift is no longer needed. See: https://www.odoo.com/mail/message/1118975071 Forward-Port-Of: odoo/enterprise#123849
The Sendcloud delivery test suite was corrected so it runs in regular CI instead of only nightly checks. This helps catch delivery integration issues earlier, including corrected expectations for multi-package weight handling.
Original PR description
Test class was tagged as external although calls are mocked. This means errors were only caught in nightly and not by CI. Removing the tag requires fixing some of the tests. For `test_multicollo`, we send the average weight of packages instead of the total since 97f82442c9fee7dcb3e8c5e9bacddcd6bb864e11. Forward-Port-Of: odoo/enterprise#121665 Forward-Port-Of: odoo/enterprise#111660
VoIP call screens now hide related record shortcuts when a call is not linked to a customer or contact, preventing errors from unexpected clicks. Subscription shortcuts are also shown consistently with the customer page behavior.
Original PR description
Same as in [1], we don't show smart buttons when no partner to prevent unexpected errors. Also remove `invisible="subscription_count == 0"` to make it same as smart button on res.partner. [1]: 0fbb730e02de22b196a45455f801e96321a75167 Forward-Port-Of: odoo/enterprise#124925 Forward-Port-Of: odoo/enterprise#124579
Fixed an issue where using the Off-Cycle filter in the payslips list could trigger an error in debug mode. The payroll screen now handles payslips without a pay run correctly, improving reliability for payroll users.
Original PR description
Before this commit, when the user is in debug mode, goes to payslips list view and applies `Off-Cycle` filter, a traceback is occured saying `Invalid props for component 'PayslipActionHelper': 'payrunId' is not a number`.
The reason is because we search the id of the payrun by parsing the domain applied to fetch payslips displayed inside the list view but `Off-Cycle` filter will apply the following domain: `[('payslip_run_id', '=', False)]` and so False is given to PayslipActionHelper but it is not a number.
This commit makes sure to set undefined to payrunId prop of PayslipActionHelper when `payrun_id` found is falsy.
runbot-error-241053
Forward-Port-Of: odoo/enterprise#124897
Forward-Port-Of: odoo/enterprise#124854AI-generated answers with web citations now preserve their original line breaks and spacing. This prevents lists and paragraphs from being accidentally merged, making cited responses easier to read and understand.
Original PR description
AI responses containing web citations lost their original formatting when a citation appeared at the end of a line, causing lists and paragraphs to be merged together. This commit limits the citation parser to ignore only horizontal whitespace around citations, preserving line breaks in the rendered response. task-6391187 Forward-Port-Of: odoo/enterprise#124457
The timesheet grid now uses updated colors for attendance/work rule types. This makes it easier for users to quickly recognize different event types at a glance.
Original PR description
This commit updates the color of AW rule types to help the user to quickly recognize the type of events based on the color. task-6186073 Forward-Port-Of: odoo/enterprise#124838
Code cleanup and technical improvements
The Point of Sale code was updated as part of Odoo's OWL 3 migration, replacing older internal reference patterns with the newer approach. This is an internal modernization that helps keep PoS screens and related localizations maintainable without changing day-to-day user workflows.
Original PR description
pos*: pos_enterprise, l10n_at_pos, l10n_ke_edi_oscu_pos As part of the OWL 3 migration, this commit replaces `useRef` and `t-custom-ref` usages with `t-ref` and signal-based references across the PoS codebase. Task-6343663 Related Community PR: https://github.com/odoo/odoo/pull/272698
The grid view editing logic was updated to use newer platform APIs, replacing deprecated internals. This keeps spreadsheet-like grid inputs working reliably while reducing future maintenance risk as the web framework evolves.
Original PR description
Replaced two `useLayoutEffect` calls in `useInputHook` with OWL3 native APIs (`useListener`, `onMounted`, `onPatched`), since `useLayoutEffect` is deprecated in OWL3. The caller `GridCell` was…
Replaced two `useLayoutEffect` calls in `useInputHook` with OWL3 native APIs (`useListener`, `onMounted`, `onPatched`), since `useLayoutEffect` is deprecated in OWL3. The caller `GridCell` was updated to use `signal.ref()` instead of the compat `useRef`. The first effect attached `input`/`change`/`keydown` listeners to `inputRef.el` — a textbook `useListener` case. However, the compat `useRef` from `@web/owl2/utils` silently untracks the underlying signal on `.el` access, so `useListener(() => inputRef.el, ...)` never re-ran after mount and no listeners were attached. The fix passes the signal ref directly (`useListener(inputRef, ...)`) and upgrades the caller to use `signal.ref()` passed explicitly to the hook. The second effect (bare `useLayoutEffect` re-syncing the DOM value on every render) maps directly to `onMounted` + `onPatched`. The `useLayoutEffect` refactored in this PR had test coverage — below are some tests that failed when the effect was commented out, and are now passing: - `@web_grid/grid_view/grid_view_desktop/editing a value` - `@web_grid/grid_view/grid_view_desktop/Edition navigate with tab/shift+tab and enter key` - `@web_grid/grid_cells/float_time_grid_cell/FloatTimeGridCell in grid view` see commented-out runbot build: https://runbot.odoo.com/runbot/batch/2624595/build/116553684
This change modernizes how scrolling behavior is connected in the Gantt and grid views. It should help keep these views aligned with the latest web framework patterns without changing the visible user experience.
Original PR description
The web `virtual_grid_hook` now attaches its scroll listener via `useListener` on a signal ref instead of `useLayoutEffect` on a compat `useRef`. This PR feeds it a signal ref from both enterprise callers:
- **web_gantt**: `scrollRef` becomes a `signal.ref` bound with `t-ref`; its own scroll `useLayoutEffect` becomes a `useListener` and all `.el` reads become calls. Layout's `contentRef` (now a signal, per the community PR) is adapted to an `{ el }` object ref for the draggable hooks (`useGanttDraggable`/`useGanttSchedulable`), which require an object ref.
- **web_grid**: `contentRef` prop type is now a function (signal) ref.This change keeps Enterprise list views in Web Studio and Data Cleaning compatible with an underlying platform update. It is an internal refactor with no expected change to day-to-day user workflows, helping prevent display or interaction issues after the core update.
Original PR description
That PR migrates the base `web.ListRenderer` `table` ref from the OWL2 compat `useRef`/`t-custom-ref='table'` to a native OWL3 `signal(null)` bound with `t-ref="this.tableRef"`. This PR updates the enterprise modules that still consume the old compat surface: - **web_studio** `ListEditorRenderer`: retargeted both xpath inheritors `//*[@t-custom-ref='table']` → `//*[@t-ref='this.tableRef']`, and `onTableHover` reads `this.tableRef()` instead of `this.tableRef.el`. - **data_cleaning** `DataMergeListRenderer.onGroupRowMouseEnter`: reads `this.tableRef()` instead of `this.tableRef.el`. Companion PR to odoo/odoo#272009.
Spreadsheet autofill for list and pivot data has been reorganized to align with the underlying spreadsheet engine. This is an internal cleanup that should preserve existing behavior while making the feature easier to maintain and slightly more efficient.
Original PR description
### [MOV] spreadsheet_edition: move list/pivot autofill plugins to helpers The list/pivot plugins were transformed into helpers in the last commit, this commit renames the files. ### [REF] spreadsheet_edition: make autofill plugin into a store The o-spreadsheet commit transformed the autofill plugin into a store. This made the necessary adaptations in odoo. Moslty, the list/pivot autofill plugin were changed into helpers that can be called from the autofill process (they had no state nor command handling). Also changed a bit the autofill helpers so we don't re-compile the cell formula when we already have a compiled formula. Task: [6395361](https://www.odoo.com/web#id=6395361&cids=1&menu_id=4720&action=333&active_id=2328&model=project.task&view_type=form)
This update modernizes part of the grid view code to stay compatible with the next version of Odoo's interface framework. It preserves the expected keyboard navigation behavior, including correctly focusing the toggle button when users enter edit mode.
Original PR description
Replaced `useLayoutEffect` with `signal.ref` + `useEffect` because `useLayoutEffect` is deprecated in OWL3. The commented-out effect focused the toggle button when its DOM element became available, using an explicit dep array `[this.buttonRef.el]`. That dep only worked because the compat `useRef().el` getter untracks its underlying signal. Converting `buttonRef` to a real `signal.ref(HTMLButtonElement)` makes `useEffect` auto-subscribe to the ref signal: when edit mode is entered (button rendered under `t-if`) the ref updates, the effect re-runs, and the button is focused — no explicit dep array needed. The useLayoutEffect refactored in this PR had test coverage — below are some tests that failed when the effect was commented out, and are now passing: - `@web_grid/grid_cells/float_toggle_grid_cell/FloatToggleGridCell: keyboard navigation` see commented-out runbot build: https://runbot.odoo.com/runbot/batch/2624596/build/116553766
The accounting reports code was updated to use the newer supported framework approach, reducing the risk of issues when Odoo moves to OWL3. A new automated test was added to confirm report filters continue to update correctly when switching reports.
Original PR description
Replaced `useLayoutEffect` with `useEffect` from `@odoo/owl` because `useLayoutEffect` is deprecated in OWL3. `useEffect` auto-tracks reactive reads inside the callback, so reading `this.controller.cachedFilterOptions?.report_id` directly in the effect body is sufficient to re-run when the report changes — no explicit dependency array is needed. When commenting out the useLayoutEffect there was no error, the code we refactored had NO TEST coverage. A test was written to ensure our fix was correct, and it was tested against the previous useLayoutEffect: - Passed with previous useLayoutEffect. - Failed with previous useLayoutEffect commented. - Passed with our OWL3 replacement.
6 changes
Enhancements to existing features
This update adds a cleanup script for the Belgian POS blackbox module. It helps prevent copied or test databases from retaining device network details and Belgian POS identifiers that should be reset before reuse.
Original PR description
Add a `neutralize.sql` file to the `l10n_be_pos_blackbox` module to reset the blackbox `local_ip` and the config's `l10n_be_pos_id` and `establishment_number`.
Resolved issues and error corrections
The Commission Adjustments screen no longer offers a quick-create option that could crash the system when users entered an unmatched name. This prevents interruptions for sales teams managing commission adjustments and keeps the workflow stable.
Original PR description
Steps to reproduce: - Go to Sales > Commission > Adjustments - In Add to/Reduce From, type a name with no match - Click Create '<name>' -> server crashes (RPC_ERROR) Cause: `sale.commission.plan.user._rec_name` is a Many2one (`user_id`). Default `name_create` wrote the typed text into that integer column, which Postgres rejected. Fix: - Disable quick-create on `add_user_id`/`reduce_user_id` in the Adjustments list view Version: saas-18.3 to master opw-6384909 Forward-Port-Of: odoo/enterprise#124431
Philippine check printing now rounds the cents portion of written payment amounts to two decimals, even when the currency is configured with more precision. This prevents confusing or incorrect wording on checks and helps printed payments match standard check formatting.
Original PR description
Current behavior: --- When paying with checks, if the currency has more than 2 decimals, the decimal amount is printed with more than 2 decimals. Steps to reproduce: --- 1. Switch to PH company 2. Set setting Check Layout as "Print Check - PH" 3. In the PHP currency, change rounding factor to 0.0001 4. In Decimal accuracy > product price, set 4 digits 5. Create a new Vendor Payment, payment method Check, amount 100.1268 PHP 6. Results: One Hundred and 1268/100, should be 13/100 Expected behavior: --- The xx/100 part of amount in words text in the check should always be rounded to 2 decimals. opw-6302337 Forward-Port-Of: odoo/enterprise#122581 Forward-Port-Of: odoo/enterprise#121913
Planning kanban cards now move overflowing content onto the next line instead of squeezing or cutting it off. This makes schedule information easier to read when entries contain longer text.
Original PR description
Wrap the kanban card content onto the next line when it does not fit on a single line. task-5085363
This fixes a failing automated test in the AI module by ensuring the test data matches the expected Gemini embedding response format. The change helps keep quality checks reliable and prevents unrelated demo data from causing false failures during validation.
Original PR description
_cron_generate_embedding retrieves all the sources that don't have an embedding and generate embeddings for those using the model from the provider of the agent configured on the source. The agent configured on the demo sources has OpenAI as the provider and these sources don't have embeddings. When _cron_generate_embedding runs in the test case, it retrieves these demo sources + the source defined in the test case (Which relies on embeddings from Google) and generates the embeddings but then fails. This happens because the _request method is mocked to return the response in Google's format as the test case is specific to Gemini models. runbot.build.error-944173
The point of sale barcode lookup flow now uses the standard permission check when deciding whether a user can create products. This avoids inconsistent behavior and helps ensure only authorized users see or use product creation options.
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#124527 Forward-Port-Of: odoo/enterprise#123073
1 change
Resolved issues and error corrections
Issue: In a multi-company environment, when an attachment is uploaded in the chatter, the resulting `ir.attachment` record incorrectly sets the company_id to the current user's default company. This occurs regardless of the active company or the company associated with the record the attachment is linked to. Steps to reproduce: In a multi-company setup, activate only Company B. Open any chatter and attach a file. Navigate to Settings > Technical > Data Structure > Attachments. Current b
Original PR description
Issue: In a multi-company environment, when an attachment is uploaded in the chatter, the resulting `ir.attachment` record incorrectly sets the company_id to the current user's default company. This…
Issue: In a multi-company environment, when an attachment is uploaded in the chatter, the resulting `ir.attachment` record incorrectly sets the company_id to the current user's default company. This occurs regardless of the active company or the company associated with the record the attachment is linked to. Steps to reproduce: In a multi-company setup, activate only Company B. Open any chatter and attach a file. Navigate to Settings > Technical > Data Structure > Attachments. Current behaviour: The created attachment has its company_id set to the user's default company, rather than the currently active company, or the company of the record, even when the record has a company_id field. This behavior introduces inconsistencies in data visibility, particularly when attachments appear to belong to a company different from the one associated with the related business record. Behaviour After Fix: If the related record (i.e., the model the attachment is linked to) contains a company_id field, its value will be used as the attachment's company_id otherwise, the attachment's company_id will be set to the currently active company's id. This logic ensures proper alignment between attachments and their related business records and also maintaining consistency in multi-company scenarios. task-4563173 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
4 changes
Resolved issues and error corrections
Steps to reproduce: - Go to the Website app and enter Edit mode. - Drop an 'Embed Code' snippet onto the page. - Paste an external embed code (e.g., an Instagram iframe or YouTube video). - Change the alignment of the snippet to 'Center' or 'Right' using the editor options. Observation: The embedded content remains left-aligned regardless of the alignment option selected. Cause: Embedded elements (like iframes or injected scripts) do not inherently respect the parent's 'text-align' prope
Original PR description
Steps to reproduce: - Go to the Website app and enter Edit mode. - Drop an 'Embed Code' snippet onto the page. - Paste an external embed code (e.g., an Instagram iframe or YouTube video). - Change…
Steps to reproduce: - Go to the Website app and enter Edit mode. - Drop an 'Embed Code' snippet onto the page. - Paste an external embed code (e.g., an Instagram iframe or YouTube video). - Change the alignment of the snippet to 'Center' or 'Right' using the editor options. Observation: The embedded content remains left-aligned regardless of the alignment option selected. Cause: Embedded elements (like iframes or injected scripts) do not inherently respect the parent's 'text-align' properties, and standard auto-margins fail if the injected element behaves as an inline block without a defined width. Solution: Update '000.scss' to apply Flexbox properties to the '.s_embed_code_embedded' wrapper. By using 'align-items' (center, flex-start, flex-end) corresponding to the parent snippet's alignment classes, the embedded content is forced to respect the chosen UI alignment. Additionally, apply 'max-width: 100%' to child elements to ensure responsiveness and prevent overflow. opw-5429966
Issue: Negative discount raises error on file validation Steps to reproduce: - Create an invoice for a customer using UBL BIS 3 - Add a line with a negative discount - Confirm and Send Current Behavior: - in the UBL, Charge indicator is set to false - UBL File raises error: [PEPPOL-EN16931-R040]-Allowance/charge amount must equal base amount * percentage/100 if base amount and percentage exists it happens as amount is negative whereas percentage and base amount are positive Expec
Original PR description
Issue: Negative discount raises error on file validation Steps to reproduce: - Create an invoice for a customer using UBL BIS 3 - Add a line with a negative discount - Confirm and Send Current Behavior: - in the UBL, Charge indicator is set to false - UBL File raises error: [PEPPOL-EN16931-R040]-Allowance/charge amount must equal base amount * percentage/100 if base amount and percentage exists it happens as amount is negative whereas percentage and base amount are positive Expected behavior: - Charge indicator is set to true - UBL File is valid opw-6352183
Reverse charge taxes (Inversione Contabile) should have the translated code ending with 'IC' (the acronym), not 'CI'. Suggested by partner: eLBati task-none
Original PR description
Reverse charge taxes (Inversione Contabile) should have the translated code ending with 'IC' (the acronym), not 'CI'. Suggested by partner: eLBati task-none
Scenario: - go with a portal user that has a company on /my - change the commercial_partner_id of that user - refresh /my with portal user Result: you see a "403: Forbidden" error because you do not have read access to your own res.partner record. Cause: ir.rule domain are cached, so the "res_partner: portal/public: read access on my commercial partner" ir.rule domain: [('id', 'child_of', user.commercial_partner_id.id)] is cached (until the cache is cleared or odoo instance is restarted) w
Original PR description
Scenario:
- go with a portal user that has a company on /my
- change the commercial_partner_id of that user
- refresh /my with portal user
Result: you see a "403: Forbidden" error because you do not have read
access to your own res.partner record.
Cause: ir.rule domain are cached, so the "res_partner: portal/public: read
access on my commercial partner" ir.rule domain:
[('id', 'child_of', user.commercial_partner_id.id)]
is cached (until the cache is cleared or odoo instance is restarted)
with the wrong commercial_partner_id.
Fix: in master, adding a domain operator 'expr' to dynamically
interpret an expression in a domain is being considered. For stable this
PR is modifying the ir.rule to ensure the portal user still has access
to its own user.
opw-5258358