Daily updates from Odoo
Friday, August 14, 2026
51 changes · saas-19.4
Resolved issues and error corrections
The attendance Gantt view now keeps today visible when users switch between time scales, such as week and day. This prevents the schedule from jumping away from the current day, making daily planning smoother and less confusing.
Original PR description
**Steps to Reproduce:** 1. Open attendnace Gantt view. 2. Set the scale to Week. 3. Set the scale back to Day. The view loses focus on today. **Reason:** * Before, when changing the scale on Gantt views and shrinking it, the view would always reset to today. * This behaviour was recently changed by the JS framework team to instead anchor the new time period around the date currently centered in the viewport. **Solution:** * If the current range includes today, scale while preserving today in the range. * Otherwise, keep the current behaviour and use the center of the viewport. Task: 6346363
Fixes an issue where enabling Equipment did not refresh linked stock lot information on draft field service planning shifts. This keeps equipment-related inventory details accurate after a recent internal status rename.
Original PR description
After odoo/enterprise#113153 renamed planning.slot states `draft` to `1_draft`, enabling Equipment no longer recomputed lot_ids on draft shifts because set_values/post_init still searched for state `draft`
Fixes an issue that prevented users from downloading the General Ledger report as a CSV when using French. The export now uses the correct translation context, so localized accounting reports download reliably instead of failing with an error.
Original PR description
Currently an exception is generated when the user tries to export (downlaod) a `CSV` file of the `General Ledger` report as the below step: - Install the `accountant` module with demo data - Enable…
Currently an exception is generated when the user tries to export (downlaod) a `CSV` file of the `General Ledger` report as the below step: - Install the `accountant` module with demo data - Enable and change to the `French` language - Go to `Comptabilité` > `Analyse` > `General Ledger` - Click the cog icon in the menu > Click on `CSV` - An error occurs in the log, and nothing is downloaded Error: `TypeError: 'NoneType' object is not subscriptable` This issue occurs after the recent refactoring changes in [1]. When `_generate_csv_lazy_export` is called, it uses the `_()` method for translation, which accesses `self.env`. However, at this point, the cursor is already closed. As a result, when the code at [2] is reached from `ormcache`, it raises the above error because `model.env.transaction.ormcaches__` is `None` (code ref [3]). This commit fixes the above issue by performing the translation using the existing `handler` variable, which contains an environment with the new cursor (see code ref [4]). [1]: https://github.com/odoo/odoo/commit/13c3adf3a8b5ba6325190d6b9aea45fb8a6a8b2f [2]: https://github.com/odoo/odoo/blob/5ef7829895b2e05650da394c1e35dfdc3a23c066/odoo/orm/cache.py#L111 [3]: https://github.com/odoo/odoo/blob/5ef7829895b2e05650da394c1e35dfdc3a23c066/odoo/orm/environments.py#L1012 [4]: https://github.com/odoo/enterprise/blob/912a47b8f0828ef8316b7e4ecdabf8a2f305b313/account_reports/models/account_general_ledger.py#L524 Sentry-7608119520
Australian Single Touch Payroll submissions now check that required payroll details are present before sending data to the ATO. Instead of a system traceback when an empty record is submitted, users receive a clear validation message so they can correct the record.
Original PR description
When submitting payroll data to the ATO from an STP record without any payslips or employees, a traceback is raised. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module -…
When submitting payroll data to the ATO from an STP record without any payslips or employees, a traceback is raised. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module - Switch to ``My australian Company`` - Go to Payroll > Configuration > Settings > In Australian Localization, Set BMS ID > Set STP Responsible and his date of birth - Go to Payroll > Reporting > Single Touch Payroll > Create a new record > Set Payment Date > Submit to ATO > Sign & Submit to ATO Traceback: ```py IndexError: tuple index out of range ``` https://github.com/odoo/enterprise/blob/b0e48baaf99bdc4faefd2ffdd3bd5637fb548593/l10n_au_hr_payroll_account/models/l10n_au_stp.py#L228-L233 The traceback occurs because ``_get_fiscal_year_start()`` assumes that the STP record always contains at least one payslip or one employee. When these recordsets are empty, indexing the first element raises an IndexError. Solution: This commit validates that the required payslips or employees are present before the submission and raises a validation error instead of a traceback. Forward-Port-Of: odoo/enterprise#127733 Forward-Port-Of: odoo/enterprise#124096
This fixes an automated payroll payrun test so it works reliably when confirming payruns and when country-specific payroll modules are installed. The change helps prevent false test failures without changing payroll behavior for end users.
Original PR description
This commit fixes a couple things with this tour: 1. We need to confirm the dialog that appears when we try to confirm the payrun itself 2. Depending on whether or not a particular l10n_XX module is…
This commit fixes a couple things with this tour:
1. We need to confirm the dialog that appears when we try to confirm the payrun itself
2. Depending on whether or not a particular l10n_XX module is installed, the trigger that we were previously using to check whether or not a payslip had been confirmed, `.btn[name='action_payment_report']` might not be there; i.e., l10n_us_hr_payroll, among others: https://github.com/odoo-dev/enterprise/blob/7767024956325d52fb30239967025b04999a9188/l10n_us_hr_payroll_account/views/hr_payslip_run_views.xml#L11-L13
It can be seen there ^ that that button is invisible under a slightly different condition than the base `hr_payroll` version of that button, causing an inconsistency in this test when that module is installed: https://github.com/odoo-dev/enterprise/blob/7767024956325d52fb30239967025b04999a9188/hr_payroll/vie
ws/hr_payslip_run_views.xml#L175
We resolve this by checking for either button in that step: `trigger: ".btn[name='action_paid'], .btn[name='action_payment_report']"`
runbot-243607Fixed an issue that caused audit report PDF exports from Accountant Knowledge to fail on systems using the newer PDF engine. Users can now generate these PDFs reliably, including on newer Python environments.
Original PR description
…ern pypdf backend `export_article_to_pdf` calls `writer.setPageMode("/UseOutlines")` on the `PdfFileWriter` instance to make the outline/bookmarks panel visible by default when the generated PDF is…
…ern pypdf backend
`export_article_to_pdf` calls `writer.setPageMode("/UseOutlines")` on the `PdfFileWriter` instance to make the outline/bookmarks panel visible by default when the generated PDF is opened. the old PyPDF2
`odoo.tools.pdf` picks its backend dynamically it first tries to import PyPDF2==2.12.1 and only falls back to the modern `pypdf` library if PyPDF2 is not importable, which is the case on Python 3.13 per requirements.txt, or on any worker where PyPDF2 failed to install.
The PyPDF2-based writer still exposes `setPageMode`, so the bug was never seen on backends using it. The modern pypdf-based writer replaced that method with a `page_mode` property (getter/setter) and never kept a camelCase alias for it
As a result, any request hitting this code got a beautiful HTTP 500
`AttributeError: 'BrandedFileWriter' object has no attribute 'setPageMode'`
`setPageMode` is not called anywhere else so
this fixes the call site directly instead of adding a new alias to the shared _pypdf.py
opw-6382905
Forward-Port-Of: odoo/enterprise#124480This fixes an issue in Odoo Sign where certain empty values could cause an error instead of being handled normally. Users should see fewer interruptions when preparing or processing signature requests with fields that do not have automatic values.
Original PR description
Forward-Port-Of: odoo/enterprise#127426
Fixes an issue where users without certain accounting permissions could be blocked from confirming sales orders when a Studio approval rule used a related accounting field. Approval checks now run with the necessary access so valid business workflows are not interrupted by unrelated permission limits.
Original PR description
continuation of [PR](https://github.com/odoo/enterprise/pull/121856) Issue: Inside _get_approval_spec filtered_domain is called a few times and due to a related field that calls an access rights group that the user who used the action isnt apart of is blocked by the filtered_domain. To Replicate: 1) Install studio, sale, Accounting and make sure "account_followup" is installed 2) create a related field on the sales.order form related to "customer -> follow up status" 3) Save 4) Create a "Studio Approval Rule" (studio.approval.rule) with a domain using the new related studio field -> method : "action_confirm" -> approver:admin 5)create a test user with no accounting access rights 6) in an incognito browser try and create a sales order, and then confirm it. it will throw the access rights error Solution: Go one up the stack where _get_approval_spec is called and add a syudo for those calls opw-6316069 Forward-Port-Of: odoo/enterprise#127412
Managers without full HR access can now launch appraisal campaigns for employees they oversee. The fix ensures selected employees are read correctly, preventing appraisals from being accidentally created for everyone when access rules hide the selection.
Original PR description
**Issue**: -User without hr rights is not allowed to launch campaigns for employees under him in the hierarchy. -This issue appears only in master, but it discovered another issue from 19.3, where the value for `employee_ids` was not accessed by the normal user. Thus, appraisals are created for all employees in the list, because not selecting an employee means selecting "All Employees". **Solution**: -SUDOing the read to allow the compute to see what the user has selected. Forward-Port-Of: odoo/enterprise#127391
When projects and tasks are created from templates, archived users are now excluded from task assignments linked to project roles. This prevents inactive employees or former team members from being assigned work through sales-created projects.
Original PR description
Steps to reproduce: ------------------------------------------------- 1. Install the `sale_project` module 2. Create a test user with Project User rights 3. Create a Project Role with the Created…
Steps to reproduce:
-------------------------------------------------
1. Install the `sale_project` module
2. Create a test user with Project User rights
3. Create a Project Role with the Created User as a Team Member
4. Create a Template Project as follows:
* Add one task to the template project
* Add the created Project role to the Task
5. Create a Service Type Product with:
* Create on order: Project
* Project Template: Created Template
6. Archive the Created User
7. Create and Confirm the Sale Order with the Created Product
Observation:
-------------------------------------------------
The generated task is assigned to the archived user, although the archived user is no longer part of the Project Role.
Issue:
-------------------------------------------------
While creating Project and Tasks from template, the context disable active record filtering (e.g., `active_test=False`), causing the assignment logic to fetch both active and inactive/archived users linked to the role. https://github.com/odoo/odoo/blob/8ec646e51497b38d34ea59296e0fc8644a50ee3a/odoo/orm/models.py#L4868
After that, during the `copy_data` method, It takes all the users from the roles without checking weather user is active or not
https://github.com/odoo/odoo/blob/8ec646e51497b38d34ea59296e0fc8644a50ee3a/addons/project/models/project_task.py#L890-L904
And even if we pass only Active users from this method, on moving further, it reassigns the users from roles without checking the Active field of the user
https://github.com/odoo/enterprise/blob/5abb147f9bf725daafc202d8259a5bb8a9b78d94/project_enterprise/models/project_task.py#L501-L503
https://github.com/odoo/enterprise/blob/5abb147f9bf725daafc202d8259a5bb8a9b78d94/project_enterprise/models/project_task.py#L544-L553
Due to this, the Archived User is also assigned to the tasks from the project roles
Solution:
-------------------------------------------------
Apply a `filtered('active')` check directly on the project role's users `(role.user_ids)` within the core task-copying logic in both `project` and `project_enterprise` modules. This ensures archived users are universally excluded from task assignments during template copying, regardless of what triggers the template instantiation.
Related Community PR: https://github.com/odoo/odoo/pull/274426
opw-6350841
Forward-Port-Of: odoo/enterprise#125637The Timesheet Assistant now recognizes time spent checking the Discuss inbox and labels the suggestion as "Checking Inbox". This replaces a confusing previous label, making timesheet suggestions easier for users to understand and confirm.
Original PR description
## Previous Behavior When the Timesheet Assistant detected a user spending time in their Discuss inbox, it generated a suggestion labeled "Discussing in/with Inbox". The name of this suggestion was judged to not make much sense. ## New Expected Behavior When the Timesheet Assistant detects a user spending time in their Discuss inbox, it will now generate a suggestion labeled "Checking Inbox" due to a new assistant rule. task-[6420655](https://www.odoo.com/odoo/project/4105/tasks/6420655) Forward-Port-Of: odoo/enterprise#126328
Planning managers without HR access can now change the resource on a planning slot without accidentally publishing it. The fix uses public employee information for the permission check, keeping planning updates aligned with the user's intended action.
Original PR description
For planning manager without HR access, if the user change the resource of the planning slot it will publish it automatically as the employee_ids field cannot be used without HR access. Prefer to use public employee to have better condition without using explicit sudo Caused-by: https://github.com/odoo/enterprise/commit/e88dcd0e545183b3f03e06b62158c52a1e6d2103 Forward-Port-Of: odoo/enterprise#127503
French VAT reimbursement declaration 3519 now includes the bank account holder name in the account details section. This helps meet required filing information and reduces the risk of rejected or incomplete reimbursement declarations.
Original PR description
For reimbursement declarations, the name of the holder of the account is required This commits adds holder's name to the account data zone no-task-id Forward-Port-Of: odoo/enterprise#127708 Forward-Port-Of: odoo/enterprise#127554
Payroll configuration now hides Mexico-specific CFDI settings when users are working in a non-Mexican company. This avoids confusion by showing these localization options only where they are relevant.
Original PR description
Steps to reproduce: 1. Switch to a non-Mexican company. 2. Go to Payroll > Configuration > Settings. 3. The CFDI settings block is visible. Reason: The CFDI block was missing a country check. Solution: Restrict the CFDI block visibility to Mexican companies. Task-6448440 Forward-Port-Of: odoo/enterprise#127022
The Timesheet Assistant now includes very small calendar events by adding their time to a matching larger event instead of ignoring them. This helps suggested timesheets reflect the full amount of time worked and reduces underreported totals.
Original PR description
## Previous Behavior Before this PR: When events were to small to suggestion Timesheet Assistant would completely discard these events. This lead to a suggestion haveing a lower total time than it should. ## New Expected Behavior After this PR: When an event is too small to suggest and shares its name and group with one or more larger event, the duration of the smaller event is added to the last event with the same name and groupe. task-[6452987](https://www.odoo.com/odoo/project/4105/tasks/6452987) Forward-Port-Of: odoo/enterprise#127167
The Point of Sale Urban Piper ticket screen now shows the order information button on mobile devices as well as desktop. This makes order details easier to access for staff using smaller screens, reducing friction during in-store or restaurant operations.
Original PR description
Before this commit: ------------ - The order info button was not visible on the ticket screen in the mobile UI. After this commit: ------------ - Display the order info button in both the mobile and desktop views of the ticket screen. Related: - Community: https://github.com/odoo/odoo/pull/276568 Task-6388045 Forward-Port-Of: odoo/enterprise#124485
This fix ensures signature fields stay in the correct visible position when signing PDFs that were created with unusual page origins. It prevents users from downloading signed documents where signatures or fields appear missing, improving reliability of the Sign workflow.
Original PR description
Steps to reproduce (version 16+): 1) Obtain a pdf with a negative origin point: This can occur when a customer exports a pdf from another software, or it can be made manually using a python script 2) In the sign app, upload the pdf and create a new template, add a signature field to the document. 3) Sign the document. The preview will load correctly and the signature will be visible 4) Download and open the signed pdf. The signature is not on the document Notes: Issue occurs because the signature was added to the pdf outside of the visible area. The preview works because the signature is rendered on top of the unsigned document in the correct location. The issue can be fixed applying a translation to the canvas. Ticket: [6317223](https://www.odoo.com/odoo/project/49/tasks/6317223?debug=assets) Forward-Port-Of: odoo/enterprise#127302 Forward-Port-Of: odoo/enterprise#121960
Before this commit, the Chat action of the meeting view could keep its unread dot instead of showing "1" after "Mark as Unread": FAILED: [14/21] Tour discuss.meeting_view_tour Step .o-mail-Meeting [title='Chat']:has(.badge:contains(1)). Element (.o-mail-Meeting [title='Chat']:has(.badge:contains(1))) has not been found. TIMEOUT step failed to complete within 10000 ms. This happens because a mark as read carries the id of the newest message the client knew when it re
Original PR description
Before this commit, the Chat action of the meeting view could keep its unread dot instead of showing "1" after "Mark as Unread": FAILED: [14/21] Tour discuss.meeting_view_tour Step .o-mail-Meeting…
Before this commit, the Chat action of the meeting view could keep its unread dot instead of showing "1" after "Mark as Unread":
FAILED: [14/21] Tour discuss.meeting_view_tour
Step .o-mail-Meeting [title='Chat']:has(.badge:contains(1)).
Element (.o-mail-Meeting [title='Chat']:has(.badge:contains(1)))
has not been found.
TIMEOUT step failed to complete within 10000 ms.
This happens because a mark as read carries the id of the newest message the client knew when it requested it, and under load it can reach the server after a newer message was posted. The new message separator then moves back before that message, which makes it unread before the user even asks for it. The click on "Mark as Unread" writes the separator the counter is already computed from, so the counter does not change, and the client, which holds the counter it displays while the user reads the thread, never refreshes it.
This commit moves the new message separator forward only, so reading messages never makes another one unread.
https://runbot.odoo.com/odoo/error/945958
Forward-Port-Of: odoo/odoo#281988This PR adapts log levels to avoid spamming sentry if bluetooth adaptor isn't ready
Original PR description
This PR adapts log levels to avoid spamming sentry if bluetooth adaptor isn't ready
Before this commit, `waitStoreFetch` returns before the answer is in the store: right after `waitStoreFetch("channels_as_member")`, the store holds no record for a channel that answer carries, on a hundred runs out of a hundred. A test that then asserts on the fetched data depends on timing. This happens because `listenStoreFetch` steps from the `onRpc` callback, which runs before the route is served. The `microTick` at the end of `waitStoreFetch` is meant to cover the rest of the round trip,
Original PR description
Before this commit, `waitStoreFetch` returns before the answer is in the store: right after `waitStoreFetch("channels_as_member")`, the store holds no record for a channel that answer carries, on a hundred runs out of a hundred. A test that then asserts on the fetched data depends on timing.
This happens because `listenStoreFetch` steps from the `onRpc` callback, which runs before the route is served. The `microTick` at the end of `waitStoreFetch` is meant to cover the rest of the round trip, but the answer only reaches the store six microtasks later.
This commit steps from `Store.fetchStoreData` instead, whose promise resolves once the answer is in the store, and drops the tick. The `onRpc` option keeps its route hooks, as tests use it to delay a request.
Forward-Port-Of: odoo/odoo#282155
Forward-Port-Of: odoo/odoo#281499Steps to reproduce: 1. Install CRM 2. Activate the Arabic language with English 3. Create a lead with a new email, a new company name, and the Arabic language 4. Save and try to send a message from the chatter Issue: - After the message is sent, the language of Lead is changed to EN from Arabic - Contacts created with the English language Cause: - When we send a message from the chatter of a Lead that has an email_from, a partner_name, and the Arabic language, this forces the creati
Original PR description
Steps to reproduce: 1. Install CRM 2. Activate the Arabic language with English 3. Create a lead with a new email, a new company name, and the Arabic language 4. Save and try to send a message from…
Steps to reproduce: 1. Install CRM 2. Activate the Arabic language with English 3. Create a lead with a new email, a new company name, and the Arabic language 4. Save and try to send a message from the chatter Issue: - After the message is sent, the language of Lead is changed to EN from Arabic - Contacts created with the English language Cause: - When we send a message from the chatter of a Lead that has an email_from, a partner_name, and the Arabic language, this forces the creation of a new contact First child contact is created with arabic language, but `parent_name` is present in the creation dictionary, so this triggers `_create_parent_from_name` that builds a dictionary to create the parent company, but it does not pass the language. As a result, the parent company is created with the English language. then `_create_parent_from_name` links the child to this new parent and this linking triggers the `_compute_lang` on the child and overwrites the child's language with the parent's language At last, Lead's own computed field `_compute_lang_id` triggers and sets the language to English Solution: - pass the language in the dictionary to create the parent company opw-6449407 Forward-Port-Of: odoo/odoo#281747
**ISSUE** When running` _cron_migrate_local_to_cloud_storage` manually,` cron._trigger` is called, which schedules the cron to be triggered later by a worker. To check whether the cron is being run manually or not, we check if there is a request. In SaaS, staging, and duplicate databases, the request is only truthy when the cron is run manually and falsy when run by a worker. In a SH production database, however, the request is truthy both when run manually and when run by a worker due to a spe
Original PR description
**ISSUE** When running` _cron_migrate_local_to_cloud_storage` manually,` cron._trigger` is called, which schedules the cron to be triggered later by a worker. To check whether the cron is being run manually or not, we check if there is a request. In SaaS, staging, and duplicate databases, the request is only truthy when the cron is run manually and falsy when run by a worker. In a SH production database, however, the request is truthy both when run manually and when run by a worker due to a specific cron worker configuration in that environment. As a result,` cron._trigger `is called infinitely and nothing gets uploaded to the cloud. **FIX** Instead of calling `cron._trigger()` to reschedule the job, `limit_time_real` is used when `request` is truthy, and `limit_time_real_cron` otherwise. opw-6330674 Forward-Port-Of: odoo/odoo#279581
Before this commit: --- - When a sale order line contained extra attribute addons, those values were not transferred to the POS order line while settling the sales order. After this commit: --- - Preserved extra attribute addons when creating POS order lines from SO. task-6204583 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282160 Forward-Port-Of: odoo/odoo#276143
Original PR description
Before this commit: --- - When a sale order line contained extra attribute addons, those values were not transferred to the POS order line while settling the sales order. After this commit: --- - Preserved extra attribute addons when creating POS order lines from SO. task-6204583 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282160 Forward-Port-Of: odoo/odoo#276143
Steps to reproduce: - 1. In the website editor, open the portal "My Account" page and, in the Customize panel, disable the "Timesheets" option. 2. As a portal user, open My Account > Tasks for a project whose tasks have allocated time and logged timesheets. 3. Look at the task list, then open one of those tasks. Issue: - The task list still shows the per-group "Total: spent / allocated", and the task detail page still shows "Allocated Time", even though timesheets are hidden in the port
Original PR description
Steps to reproduce: - 1. In the website editor, open the portal "My Account" page and, in the Customize panel, disable the "Timesheets" option. 2. As a portal user, open My Account > Tasks for a project whose tasks have allocated time and logged timesheets. 3. Look at the task list, then open one of those tasks. Issue: - The task list still shows the per-group "Total: spent / allocated", and the task detail page still shows "Allocated Time", even though timesheets are hidden in the portal. Fix: - - Add `_show_portal_timesheets()` to the condition of the list "Total" column. - Gate the `portal_my_task_allocated_hours` block on `_show_portal_timesheets()` in the task detail page. task-6140807 Forward-Port-Of: odoo/odoo#272043
As the `requirements.txt` file path changed from `addons/iot_box_image` to `setup/iot_box_builder` the checkout from 19 to saas-19.4 can't find the file (looking at the former path instead of the new one). As a workaround, we add `sentry_sdk` requirement in v19.0. Forward-Port-Of: odoo/odoo#282122 Forward-Port-Of: odoo/odoo#282001
Original PR description
As the `requirements.txt` file path changed from `addons/iot_box_image` to `setup/iot_box_builder` the checkout from 19 to saas-19.4 can't find the file (looking at the former path instead of the new one). As a workaround, we add `sentry_sdk` requirement in v19.0. Forward-Port-Of: odoo/odoo#282122 Forward-Port-Of: odoo/odoo#282001
Steps to reproduce: - make a few sales in the PoS and refund one of them - close the session - select all those orders, including the refund, and create a consolidated invoice Issue: The invoice is refused with "You cannot validate an invoice with a negative total amount. You should create a credit note instead.", while the total of the selected orders is positive. If a cash rounding method is set on the PoS config, no error is raised but the posted document is a credit note carrying a r
Original PR description
Steps to reproduce: - make a few sales in the PoS and refund one of them - close the session - select all those orders, including the refund, and create a consolidated invoice Issue: The invoice is…
Steps to reproduce: - make a few sales in the PoS and refund one of them - close the session - select all those orders, including the refund, and create a consolidated invoice Issue: The invoice is refused with "You cannot validate an invoice with a negative total amount. You should create a credit note instead.", while the total of the selected orders is positive. If a cash rounding method is set on the PoS config, no error is raised but the posted document is a credit note carrying a rounding line equal to twice the order total (a credit note of 20.00 with a 40.00 "Rounding" line for sales of 10.00 + 20.00 and a refund of 10.00). Cause: _prepare_invoice_vals picked the move type from the presence of a refund in the group instead of its net amount: any group holding an order with is_refund set, or a negative amount_total, became an 'out_refund'. _get_invoice_lines_values then negates the quantities of every order whose direction differs from the move type, so the sales end up as negative lines of a credit note and the document totals -20.00 instead of +20.00. account.move refuses to post it. When invoice_cash_rounding_id is set, the cash rounding line is computed to bring the document back to a total valid for its type, so it absorbs the whole sign error and the wrong credit note is posted silently. Fix: Choose the move type from the net amount_total of the group, as was done up to saas-18.3, and keep is_refund only as the tie-break when that net is zero so a lone zero-total refund still gives a credit note. The sign handling of the lines is unchanged: it already keys on each order's own direction, which is what makes a sale a negative line of a credit note and a refund a negative line of an invoice. opw-6452996 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281703
Steps to reproduce the bug: - Enable 2-step delivery (pick + ship) on a warehouse. - Set both rules on the delivery route to "Pull" (instead of the default Pull + Push): - Pick rule (Stock -> Output): action = Pull, procure_method = make_to_stock - Ship rule (Output -> Customers): action = Pull, procure_method = make_to_order - Create a sale order for qty 1 and confirm it. - Validate the Pick transfer. - Return the Pick transfer. - Cancel the sale order. - Set it back to quotati
Original PR description
Steps to reproduce the bug: - Enable 2-step delivery (pick + ship) on a warehouse. - Set both rules on the delivery route to "Pull" (instead of the default Pull + Push): - Pick rule (Stock ->…
Steps to reproduce the bug:
- Enable 2-step delivery (pick + ship) on a warehouse.
- Set both rules on the delivery route to "Pull" (instead of the default Pull + Push):
- Pick rule (Stock -> Output): action = Pull, procure_method = make_to_stock
- Ship rule (Output -> Customers): action = Pull, procure_method = make_to_order
- Create a sale order for qty 1 and confirm it.
- Validate the Pick transfer.
- Return the Pick transfer.
- Cancel the sale order.
- Set it back to quotation and confirm it again.
Problem:
The newly created delivery (ship) move ends up asking for a wrong, inflated quantity instead of the ordered one (e.g. 3 times the ordered qty for the scenario above; the multiplier depends on the number of prior confirm/cancel/return cycles).
`_action_cancel` (addons/sale_stock/models/sale_order.py) only cancels pickings that are not `done`, so after the pick is validated and returned, cancelling the SO only cancels the still-pending ship move. The pick move and its return stay `done` and linked to the sale order line.
`SaleOrderLine._get_outgoing_incoming_moves` determines which rule "started" the pull/push chain by picking the rule of the first surviving (non-cancelled) move, grouped by warehouse: https://github.com/odoo/odoo/blob/d7bad3dc6c068ffe8643ecb01da1865d743bfb8f/addons/sale_stock/models/sale_order_line.py#L338-L347
Once the ship move is cancelled, it is excluded from that computation, so the Pick rule is wrongly identified as the "triggering" rule instead of the Ship rule. The done pick move and its return share that rule, so they both end up wrongly classified as incoming (returned) quantities instead of being excluded from the computation like before the cancellation, corrupting `_get_qty_procurement`. On reconfirm, `_action_launch_stock_rule` computes
`product_qty = product_uom_qty - qty`, inflating the quantity requested on the new ship move.
Solution:
Identify the triggering rule from the sale order line's full move history, including cancelled moves, so cancelling a move later doesn't change which rule is considered to have started the chain.
opw-6364113
Forward-Port-Of: odoo/odoo#281709
Forward-Port-Of: odoo/odoo#280280Steps to reproduce the bug: - Create three storable products C1 ($10), C2 ($20), C3 ($5) - Create a product P1 with a BoM: 1x C1 + 1x C2 - Create a Manufacturing Order for P1 and validate it - Unlock the MO (Settings > Unlock) - Add C3 as an extra component on the unlocked MO - Open the MO overview Problem: The extra move had value=0 after creation, causing the unit_cost in the MO overview to appear as 0. When a move is added to a done picking or MO it is created with state='done' an
Original PR description
Steps to reproduce the bug: - Create three storable products C1 ($10), C2 ($20), C3 ($5) - Create a product P1 with a BoM: 1x C1 + 1x C2 - Create a Manufacturing Order for P1 and validate it - Unlock…
Steps to reproduce the bug: - Create three storable products C1 ($10), C2 ($20), C3 ($5) - Create a product P1 with a BoM: 1x C1 + 1x C2 - Create a Manufacturing Order for P1 and validate it - Unlock the MO (Settings > Unlock) - Add C3 as an extra component on the unlocked MO - Open the MO overview Problem: The extra move had value=0 after creation, causing the unit_cost in the MO overview to appear as 0. When a move is added to a done picking or MO it is created with state='done' and quantity set immediately. This triggers _set_quantity_done, which creates the move line and calls _set_value(correction_quantity=delta). Inside _set_value, for outgoing moves with a correction_quantity, the code computes: previous_qty = move.quantity - correction_quantity Since the move had no prior quantity, previous_qty=0. The original code then computed ratio=0 and applied move.value += 0, leaving value=0 instead of computing it from scratch. Solution: When previous_qty=0, skip the ratio branch and fall through to the existing from-scratch computation (standard_price * _get_valued_qty() for AVCO/standard costing, _run_fifo() for FIFO). opw-6377393 Forward-Port-Of: odoo/odoo#281008 Forward-Port-Of: odoo/odoo#276303
Before this commit, switching the camera input device during a call froze the local preview: the <video> element kept pointing at the old, already stopped MediaStream. `CallParticipantVideo` assigns `srcObject` from `onMounted`/`onPatched`. Those callbacks run outside of any computation, so reading `session.getStream(type)` there subscribes to nothing, and the template does not read the stream either. On top of that, a child is only patched when one of its props changes identity, and switchin
Original PR description
Before this commit, switching the camera input device during a call froze the local preview: the <video> element kept pointing at the old, already stopped MediaStream. `CallParticipantVideo` assigns…
Before this commit, switching the camera input device during a call froze the local preview: the <video> element kept pointing at the old, already stopped MediaStream. `CallParticipantVideo` assigns `srcObject` from `onMounted`/`onPatched`. Those callbacks run outside of any computation, so reading `session.getStream(type)` there subscribes to nothing, and the template does not read the stream either. On top of that, a child is only patched when one of its props changes identity, and switching the camera device keeps the same `session`, `type` and `inset`, and keeps `is_camera_on` true: it only swaps the stream object. Nothing was left to tell the element to update. This commit replaces those lifecycle hooks with an effect, and the owl2 `useRef` with a signal ref, so that both the element and the stream are tracked and the element is updated as soon as the stream is replaced. The effect cleanup still clears `srcObject`, which is what allows the component to be garbage collected once detached. task-6468610 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Fix a series of service fee defects and add the missing coverage. Discounts: - stop duplicating the fee line on every recompute under a global discount: reconciliation is keyed on tax_ids alone, so the discount line's computation_key is stripped to keep one tax group; - recompute the fee when a global discount is applied and when a reward is deactivated: both change the base the fee is carved from without emitting any event (pos_discount, pos_loyalty); - keep a single fee line
Original PR description
Fix a series of service fee defects and add the missing coverage. Discounts: - stop duplicating the fee line on every recompute under a global discount: reconciliation is keyed on tax_ids alone, so…
Fix a series of service fee defects and add the missing coverage. Discounts: - stop duplicating the fee line on every recompute under a global discount: reconciliation is keyed on tax_ids alone, so the discount line's computation_key is stripped to keep one tax group; - recompute the fee when a global discount is applied and when a reward is deactivated: both change the base the fee is carved from without emitting any event (pos_discount, pos_loyalty); - keep a single fee line when a gift card / eWallet is used, and the fee out of the base it is carved from: it is money already paid, and it settles the whole bill, service fee included (pos_loyalty); - keep the fee out of the base a discount on order is taken from, so pricing or scaling it no longer moves the promotion (pos_loyalty); - keep a discount line out of the base the fee is carved from unless the fee is a percentage of the order total after discount: a discount covering the whole order collapsed that base to zero and the fee disappeared from the order (pos_discount, pos_loyalty). Fixed fee: - scale it exactly with its quantity (5 x $2 = $10.00, not 9.99 from per-unit tax rounding), and fix the cent it lost on recompute; - let the cashier price it, not only scale it: the price is read the way the preset's amount is, a target total taxes included, and survives the next recompute. Refunds: - a refund order carries no preset, so recomputing its fee deleted the refunded fee lines. Skip the recompute: the cashier decides whether to give the fee back by selecting the line like any other. Display: - stop qualifying a fixed fee with the preset's `based on` mention, on the orderline and on the receipt: it states which order total a percentage is taken from. Restaurant: - keep the fee pinned to the bottom of the order (the last course); - keep a single fee line when an order is transferred onto a table that already carries one: fee lines never merge, so the source's were copied over and the stale one was left on the order. task-6372687
**Steps to reproduce:** 1. Install Sales and Loyalty modules 2. Create a Discount & Loyalty Program (type: Promotion) and save the form 3. Open the Reward modal and edit any values (e.g., 5% discount instead of 10%), save the new changes in the modal and then save the form 4. Re-open the reward modal **Issue:** The updated value (5% discount) is not saved, and the reward reverts to its previous state (10% discount). This issue will occur for any modifications. **Why this happens:** -
Original PR description
**Steps to reproduce:** 1. Install Sales and Loyalty modules 2. Create a Discount & Loyalty Program (type: Promotion) and save the form 3. Open the Reward modal and edit any values (e.g., 5% discount…
**Steps to reproduce:** 1. Install Sales and Loyalty modules 2. Create a Discount & Loyalty Program (type: Promotion) and save the form 3. Open the Reward modal and edit any values (e.g., 5% discount instead of 10%), save the new changes in the modal and then save the form 4. Re-open the reward modal **Issue:** The updated value (5% discount) is not saved, and the reward reverts to its previous state (10% discount). This issue will occur for any modifications. **Why this happens:** - The write method in `loyalty_program` uses `convert_to_cache` on `reward_ids` to make a constraint check before executing the actual super().write() - A recent commit (9c52f6246d24d02457d34df6b559eecf7ec50687) modified `convert_to_cache` to update the cache for `Command.UPDATE` to fix premature computations during `onchange` - This update alters the real record's cache without marking the fields as dirty - When super().write() executes afterwards, the ORM sees the incoming values already match the cache, assumes no changes occurred, and drops the SQL UPDATE **Fix:** - Restrict the cache mutation to only apply to virtual/draft records - This preserves the intended onchange behavior for NewId records while preventing cache corruption on real database records prior to write opw-6405775
Steps: - Install account_peppol. - Go my account on the portal page. - Select peppol supported county and set `By peppol` for `Receive invoices` field on my/account page. - Select any wrong values for `Peppol e-Address (EAS)` or `Peppol Endpoint` fields Issue: - It allow to save those values on customer even though they are wrong, it should give proper error message according to Peppol validation same as in backend. Cause: - In this PR https://github.com/odoo/odoo/pull/262274 adeptio
Original PR description
Steps: - Install account_peppol. - Go my account on the portal page. - Select peppol supported county and set `By peppol` for `Receive invoices` field on my/account page. - Select any wrong values…
Steps: - Install account_peppol. - Go my account on the portal page. - Select peppol supported county and set `By peppol` for `Receive invoices` field on my/account page. - Select any wrong values for `Peppol e-Address (EAS)` or `Peppol Endpoint` fields Issue: - It allow to save those values on customer even though they are wrong, it should give proper error message according to Peppol validation same as in backend. Cause: - In this PR https://github.com/odoo/odoo/pull/262274 adeption of validation for account details is not properly adapted and because of that it skips those validation and allow user to save wrong details Fix: - Adapt validation for account details saving to have proper error message for wrong values. ### [FIX] account_peppol: fix Peppol fields requirement on address page - Install account_peppol. - Go my account on the portal page. - Select peppol supported county and set `By peppol` for `Receive invoices` field on my/account page. - Don't select any value for any of Peppol related detail (routing_scheme, routing_endpoint or invoice_edi_format). Issue: - Allowed to save `By peppol` for `Receive invoices` field even without setting required details for peppol, it should make peppol related details required and not allow to save that method unless user set valid details for Peppol. Cause: - Since PR https://github.com/odoo/odoo/pull/192183 peppol related details are not added to mandatory because there is not `invoice_sending_method` related details in kwargs since it's moved to res.partner and it also don't have any details in request.params and it does not update required fields dynamically when we change `invoice_sending_method` so current way to make those field required is not working and wrong. Fix: - Instead trying to make fields required on load, which will not work when user change details. Check `peppol` related field requirements on validation of address details and make those fields missing and prevent to save address details for missing values.
Steps to reproduce: - Create a "Buy 2 Get 1 free" program whose rule and reward cover three products having the same price - In the PoS, add one unit of each of the three products -> one free product is given - Add three more units of the second product, 6 units in total Issue: Only one free product is given instead of two, the order total is 50 instead of 40. Cause: `_updateRewardLines` deletes the reward lines and re-applies each claimed reward. Beforehand it merges the claims havin
Original PR description
Steps to reproduce: - Create a "Buy 2 Get 1 free" program whose rule and reward cover three products having the same price - In the PoS, add one unit of each of the three products -> one free product…
Steps to reproduce: - Create a "Buy 2 Get 1 free" program whose rule and reward cover three products having the same price - In the PoS, add one unit of each of the three products -> one free product is given - Add three more units of the second product, 6 units in total Issue: Only one free product is given instead of two, the order total is 50 instead of 40. Cause: `_updateRewardLines` deletes the reward lines and re-applies each claimed reward. Beforehand it merges the claims having the same reward and the same price, which is the case for two free products of the same price even when they were claimed for two different products. The merged claim keeps the `_reward_product_id` of the first line only, with a quantity of two. On re-application, `_computeUnclaimedFreeProductQty` only counts in `available` the quantity of that single product, since the other lines are counted only while a reward line is still in the order and they have all just been deleted. It therefore returns 1 and the second free product is lost. Fix: Only merge claims that were made for the same free product. Gift card/ewallet claims have no `_reward_product_id` and claims of a reward having a single reward product all share the same one, so both keep being merged as before. opw-6430385 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282052
When creating a MO For a product with no variant, it will add an on apply on variant component, even if only one of it's attribute has a values that match with the product on the mo. Steps to reproduce: ------------------- * Create a Product with two never attributes (att1 and att2) * Add values to both attributes * Create a BOM with components with apply on variant for every possibility: - component att1 val1, att2 val1, apply on variant: att1 value 1 att2 value1 - component att1 v
Original PR description
When creating a MO For a product with no variant, it will add an on apply on variant component, even if only one of it's attribute has a values that match with the product on the mo. Steps to…
When creating a MO For a product with no variant, it will add an on apply on variant component, even if only one of it's attribute has a values that match with the product on the mo. Steps to reproduce: ------------------- * Create a Product with two never attributes (att1 and att2) * Add values to both attributes * Create a BOM with components with apply on variant for every possibility: - component att1 val1, att2 val1, apply on variant: att1 value 1 att2 value1 - component att1 val1, att2 val2, apply on variant: att1 value 1 att2 value2 - component att1 val2, att2 val1, apply on variant: att1 value 2 att2 value1 - ... * Add mto and manufacture to the product * Create and confirm a SO for the product variant att1 value 1 and att value 2 -> On the MO every component that as at least one of the values will be present. Observation: ------------- When confirming the SO it will call action_confirm. Since we are in mto, it will create a procurement order of the manufacture type and will create a MO. When creating the workorder, it will call explote on the bom to know all the components: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/mrp/models/mrp_production.py#L626 Each line that does not respect the apply on variant condition will be ignored: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/mrp/models/mrp_bom.py#L450-L451 it will retrieve the line if at least one value from any attribute match: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/mrp/models/mrp_bom.py#L623-L626 opw-6293259 Forward-Port-Of: odoo/odoo#271351
While filtering PDP moves, _get_pdp_receiver_identification_info was still being used, causing a traceback. After discussion with svfu, this function was removed in commit 5c3dde7f36609a74ffed8357c11a648d85942bdd, but this change was overlooked during the port-forwarding. Steps to reproduce: - Install l10n_fr_pdp. - Enable Approved Platform in Demo. - Create a French partner and set the routing to FRCTC. - Try to send an invoice to the customer. task-none Thanks to svfu for writing
Original PR description
While filtering PDP moves, _get_pdp_receiver_identification_info was still being used, causing a traceback. After discussion with svfu, this function was removed in commit 5c3dde7f36609a74ffed8357c11a648d85942bdd, but this change was overlooked during the port-forwarding. Steps to reproduce: - Install l10n_fr_pdp. - Enable Approved Platform in Demo. - Create a French partner and set the routing to FRCTC. - Try to send an invoice to the customer. task-none Thanks to svfu for writing the fix.
Steps to reproduce: - give a user the Point of Sale / User group only, without any accounting access right - open a session, sell a product to a customer and ask for an invoice Issue: The invoice is created and posted, but it is never reconciled with its payment: it stays fully due even though the journals and the accounts are correctly configured. Cause: _reconcile_invoice_payments gathers the lines to reconcile with the rights of the caller and elevates only the final reconcile() cal
Original PR description
Steps to reproduce: - give a user the Point of Sale / User group only, without any accounting access right - open a session, sell a product to a customer and ask for an invoice Issue: The invoice is…
Steps to reproduce:
- give a user the Point of Sale / User group only, without any accounting access right
- open a session, sell a product to a customer and ask for an invoice
Issue:
The invoice is created and posted, but it is never reconciled with its payment: it stays fully due even though the journals and the accounts are correctly configured.
Cause:
_reconcile_invoice_payments gathers the lines to reconcile with the rights of the caller and elevates only the final reconcile() call. The payment moves it reads are linked to the order through account.move.pos_payment_ids, while rule_invoice_pos_user restricts a POS user to the moves matching [('pos_order_ids', '!=', False)], so those moves are not readable by a salesperson. Since saas-19.3, base_user_account_move_line_rule adds [('move_id', 'access', 'read')] on account.move.line, which propagates that restriction to the lines: payment_moves.pos_payment_ids.account_move_id.line_ids silently returns an empty recordset. reconcile() then gets the invoice receivable line alone and has nothing to match it with.
_create_payment_moves does return a sudo recordset, but _generate_pos_order_invoice accumulates it into self.env['account.move'] and the union of two recordsets keeps the env of its left operand, so the payment moves reach the helper back in the salesperson's env.
opw-6439389
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#281512The field pack_lot_ids is not present in the pos.order.line model when pos_stock is not installed, so we need to remove it from the test. runbot-941527 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281930
Original PR description
The field pack_lot_ids is not present in the pos.order.line model when pos_stock is not installed, so we need to remove it from the test. runbot-941527 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281930
### Issue before this commit: Before commit f2965048f60fe6c815b3e50fa714c97a93dfb5d3, company_type allowed manually selecting whether a contact was an individual or a company. After the commit, is_company became a stored computed field derived from the VAT number, with no manual override available in the standard UI, and no exception was added for Spanish DNI/NIE formats. ### Steps to reproduce the issue: 1. Download Accounting and l10n_es 2. Set as VAT of ES company 47857909S (or similar
Original PR description
### Issue before this commit: Before commit f2965048f60fe6c815b3e50fa714c97a93dfb5d3, company_type allowed manually selecting whether a contact was an individual or a company. After the commit,…
### Issue before this commit: Before commit f2965048f60fe6c815b3e50fa714c97a93dfb5d3, company_type allowed manually selecting whether a contact was an individual or a company. After the commit, is_company became a stored computed field derived from the VAT number, with no manual override available in the standard UI, and no exception was added for Spanish DNI/NIE formats. ### Steps to reproduce the issue: 1. Download Accounting and l10n_es 2. Set as VAT of ES company 47857909S (or similar but must be a DNI or NIE format) 3. Create an invoice for a Spanish customer 4. Send the invoice with Facturae 5. Check the XML created and see that the tag <PersonTypeCode> of <SellerParty> has a J (legal entity) rather than an F (individual) ### Cause of the issue: The Spanish localization's _compute_is_company override only adds the check for CIF-formatted VAT numbers (for [legal entities](https://sede.agenciatributaria.gob.es/Sede/ayuda/manuales-videos-folletos/manuales-practicos/guia-practica-cumplimentacion-modelo-censal-036/anexos/anexo-01-solicitud-nif-documentacion-aportar/informacion-sobre-numero-identificacion-fiscal/composicion-nif/personas-juridicas-entidades.html)) but it has no corresponding negative check for DNI or NIE formats (for [standalone individuals](https://sede.agenciatributaria.gob.es/Sede/ayuda/manuales-videos-folletos/manuales-practicos/guia-practica-cumplimentacion-modelo-censal-036/anexos/anexo-01-solicitud-nif-documentacion-aportar/informacion-sobre-numero-identificacion-fiscal/composicion-nif/personas-fisicas.html)). Here the [rules](https://factuo.es/herramientas/verificador-nif) for regex. https://github.com/odoo/odoo/blob/f014e0b7bc3ce56a9931e81339a4f8327a400422/addons/l10n_es/models/res_partner.py#L39-L51 As a result, any standalone partner with a valid non-void VAT inherits is_company = True from the base computation. https://github.com/odoo/odoo/blob/f014e0b7bc3ce56a9931e81339a4f8327a400422/odoo/addons/base/models/res_partner.py#L824-L833 ### Reason to introduce the fix: The Facturae 3.2.2 export directly derives PersonTypeCode (F/J) and the LegalEntity/Individual XML structure from partner.is_company. Since a self-employed individual (autónomo) is required to use their personal DNI/NIE as NIF and is their own commercial partner, the current logic misclassifies them as a legal entity (J), producing a Facturae invoice with an incorrect PersonTypeCode and structure. Explicitly setting is_company = False for DNI/NIE-formatted Spanish VAT numbers restores the ability to correctly represent individual entrepreneurs in Facturae exports. opw-6396314 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277228
When edit_translations is set, convert_to_record wraps translated terms in branding spans. Related (non-stored) fields re-read that already-wrapped value and ran the same wrapping again, producing nested spans. Only wrap terms for stored fields so related Html inherits the source branding unchanged. Also keep data-oe-translation-state in HTML safe_attrs so sanitization does not strip it. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior af
Original PR description
When edit_translations is set, convert_to_record wraps translated terms in branding spans. Related (non-stored) fields re-read that already-wrapped value and ran the same wrapping again, producing nested spans. Only wrap terms for stored fields so related Html inherits the source branding unchanged. Also keep data-oe-translation-state in HTML safe_attrs so sanitization does not strip it. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282143 Forward-Port-Of: odoo/odoo#280397
In commit 004b56a5c31841bc0bf4a9f17902bbff8d0f509d we added warnings to tell French companies to install the PDP module. When working on commit 720294ee523c6f84d0302e6b7fd634069f72dda7 we noticed the problem that the PDP module is not available without rescanning the available modules ("Update Apps List" in debug mode in the "Apps"). This is fixed in this commit: In case the module is not installed we still show the warning but link to the "Update Apps List" wizard. task-None For
Original PR description
In commit 004b56a5c31841bc0bf4a9f17902bbff8d0f509d we added
warnings to tell French companies to install the PDP module.
When working on commit 720294ee523c6f84d0302e6b7fd634069f72dda7
we noticed the problem that the PDP module is not available
without rescanning the available modules ("Update Apps List" in
debug mode in the "Apps").
This is fixed in this commit:
In case the module is not installed we still show the warning
but link to the "Update Apps List" wizard.
task-None
Forward-Port-Of: odoo/odoo#280209In the sampel dashboard the figures are half transparent to indicate that they are just sample data, but they are still interactive. This commit disable all the pointer events on them. Task: [6467022](https://www.odoo.com/web#id=6467022&cids=1&menu_id=4720&action=333&active_id=2328&model=project.task&view_type=form) Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and rea
Original PR description
In the sampel dashboard the figures are half transparent to indicate that they are just sample data, but they are still interactive. This commit disable all the pointer events on them. Task: [6467022](https://www.odoo.com/web#id=6467022&cids=1&menu_id=4720&action=333&active_id=2328&model=project.task&view_type=form) Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282179
Before this commit, a test answering a route with a response of its own, `new Response(stream)`, reads `content-type: application/json` back from it, a header it never set. At the debug log level, the request itself fails: Unexpected token 'o', "[object Rea"... is not valid JSON This happens because the mocked fetch guesses the content type from its result, and a response is neither a string, a `Blob` nor a `FormData`, so it falls back to JSON, on the very headers the response carries.
Original PR description
Before this commit, a test answering a route with a response of its own, `new Response(stream)`, reads `content-type: application/json` back from it, a header it never set. At the debug log level, the request itself fails:
Unexpected token 'o', "[object Rea"... is not valid JSON
This happens because the mocked fetch guesses the content type from its result, and a response is neither a string, a `Blob` nor a `FormData`, so it falls back to JSON, on the very headers the response carries. The response logger then reads the body as text, "[object ReadableStream]" for a stream, and parses it as JSON.
This commit guesses the content type of a raw value only, so a response keeps the headers it was built with.
Forward-Port-Of: odoo/odoo#281968**Description of the issue/feature this PR addresses:** [FIX] html_editor: ensure youtube videos loop correctly When configuring a YouTube video to loop in the website editor, the video currently fails to loop when it finishes playing. This occurs because setting loop=1 in a YouTube iframe URL is not sufficient on its own. The YouTube Iframe API explicitly requires the playlist parameter to be present and set to the exact same video ID for looping to work. See: https://developers.goo
Original PR description
**Description of the issue/feature this PR addresses:** [FIX] html_editor: ensure youtube videos loop correctly When configuring a YouTube video to loop in the website editor, the video currently…
**Description of the issue/feature this PR addresses:** [FIX] html_editor: ensure youtube videos loop correctly When configuring a YouTube video to loop in the website editor, the video currently fails to loop when it finishes playing. This occurs because setting loop=1 in a YouTube iframe URL is not sufficient on its own. The YouTube Iframe API explicitly requires the playlist parameter to be present and set to the exact same video ID for looping to work. See: https://developers.google.com/youtube/player_parameters#loop This commit resolves the issue by intercepting the video options before the URL is generated and automatically injecting the playlist parameter when looping is enabled. The playlist parameter is also registered in the optionsConfig schema to ensure it is properly recognized and encoded into the final URL. **Steps to reproduce:** - Website > Edit > add Youtube video > enable Autoplay and Loop > observe that loop does not work **Current behavior before PR:** - Looping does not work for embedded Youtube videos **Desired behavior after PR is merged:** - Looping works for embedded Youtube videos opw-6411445
**Steps to reproduce:** - Install Accounting and l10n_fr_pdp - Switch to a French company (e.g. FR Company) - Activate Electronic Invoicing in Accounting settings - Create a French contact with a SIREN number **Issue:** In the contact form, the routing ID and endpoint are not set from the provided SIREN. **Cause:** The routing identifier was not computed from the SIREN on purpose. opw-6468656 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/s
Original PR description
**Steps to reproduce:** - Install Accounting and l10n_fr_pdp - Switch to a French company (e.g. FR Company) - Activate Electronic Invoicing in Accounting settings - Create a French contact with a SIREN number **Issue:** In the contact form, the routing ID and endpoint are not set from the provided SIREN. **Cause:** The routing identifier was not computed from the SIREN on purpose. opw-6468656 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Empty CSV cells on a translatable field still produce a dict such as {'en_US': '', 'fr_FR': ''}. That dict is truthy, so `if not value` left it alone and the converter stored empty strings instead of clearing the field. Treat a translation dict whose values are all empty as False, matching how empty cells already work for non-translated fields. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I
Original PR description
Empty CSV cells on a translatable field still produce a dict such as {'en_US': '', 'fr_FR': ''}. That dict is truthy, so `if not value` left it alone and the converter stored empty strings instead of clearing the field.
Treat a translation dict whose values are all empty as False, matching how empty cells already work for non-translated fields.
Description of the issue/feature this PR addresses:
Current behavior before PR:
Desired behavior after PR is merged:
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr**Steps to reproduce:** 1. Install Sales and stock_delivery modules. 2. Create a new Sale Order and add a product to the order lines. 3. Confirm the Sale Order (which locks the order lines and creates a delivery move). 4. Attempt to click on the product name in the order line to open its external form. **Issue:** - The product name is unclickable when the sale order is confirmed. **Expected behavior:** - The product form should remain accessible and clickable **Why this happens:**
Original PR description
**Steps to reproduce:** 1. Install Sales and stock_delivery modules. 2. Create a new Sale Order and add a product to the order lines. 3. Confirm the Sale Order (which locks the order lines and…
**Steps to reproduce:**
1. Install Sales and stock_delivery modules.
2. Create a new Sale Order and add a product to the order lines.
3. Confirm the Sale Order (which locks the order lines and creates a delivery move).
4. Attempt to click on the product name in the order line to open its external form.
**Issue:**
- The product name is unclickable when the sale order is confirmed.
**Expected behavior:**
- The product form should remain accessible and clickable
**Why this happens:**
- Following the recent OWL 3 upgrade (#269532), the framework changed how properties are defined and tracked.
- Inheriting props via `...super.props` inside a `static props` object fails because parent components now define schemas as instance fields.
- The compatibility layer never read `static props`, so extra keys defined in those schemas were not exposed on `this.props`
**Fix:**
- Update the schema definition to use the new OWL 3 instance field syntax (`props = props({...})`) and explicitly import and spread the parent component's exported props object instead of relying on `super.props`.
opw-6447573Steps to reproduce: ------------------------------------------------- 1. Install the `sale_project` module 2. Create a test user with Project User rights 3. Create a Project Role with the Created User as a Team Member 4. Create a Template Project as follows: * Add one task to the template project * Add the created Project role to the Task 5. Create a Service Type Product with: * Create on order: Project * Project Template: Created Template 6. Archive the Created User
Original PR description
Steps to reproduce: ------------------------------------------------- 1. Install the `sale_project` module 2. Create a test user with Project User rights 3. Create a Project Role with the Created…
Steps to reproduce:
-------------------------------------------------
1. Install the `sale_project` module
2. Create a test user with Project User rights
3. Create a Project Role with the Created User as a Team Member
4. Create a Template Project as follows:
* Add one task to the template project
* Add the created Project role to the Task
5. Create a Service Type Product with:
* Create on order: Project
* Project Template: Created Template
6. Archive the Created User
7. Create and Confirm the Sale Order with the Created Product
Observation:
-------------------------------------------------
The generated task is assigned to the archived user, although the archived user is no longer part of the Project Role.
Issue:
-------------------------------------------------
While creating Project and Tasks from template, the context disable active record filtering (e.g., `active_test=False`), causing the assignment logic to fetch both active and inactive/archived users linked to the role. https://github.com/odoo/odoo/blob/8ec646e51497b38d34ea59296e0fc8644a50ee3a/odoo/orm/models.py#L4868
After that, during the `copy_data` method, It takes all the users from the roles without checking weather user is active or not
https://github.com/odoo/odoo/blob/8ec646e51497b38d34ea59296e0fc8644a50ee3a/addons/project/models/project_task.py#L890-L904
And even if we pass only Active users from this method, on moving further, it reassigns the users from roles without checking the Active field of the user
https://github.com/odoo/enterprise/blob/5abb147f9bf725daafc202d8259a5bb8a9b78d94/project_enterprise/models/project_task.py#L501-L503
https://github.com/odoo/enterprise/blob/5abb147f9bf725daafc202d8259a5bb8a9b78d94/project_enterprise/models/project_task.py#L544-L553
Due to this, the Archived User is also assigned to the tasks from the project roles
Solution:
-------------------------------------------------
Apply a `filtered('active')` check directly on the project role's users
`(role.user_ids)` within the core task-copying logic in both `project` and
`project_enterprise` modules. This ensures archived users are universally
excluded from task assignments during template copying, regardless of what
triggers the template instantiation.
Related Enterprise PR: https://github.com/odoo/enterprise/pull/125637
opw-6350841
Forward-Port-Of: odoo/odoo#274426Before this commit, the hoot test "keep banner for messages received while scrolled up" failed at random on runbot: ``` Failed to find 1 of ".o-mail-Thread-banner:has(:text('1 new message'))" (Timeout of 10 seconds). Found 0 instead. ``` This happens because the test waits for the scroll position it sets in the DOM only, while the thread copies that position to the record on the scroll event, one animation frame later. Bob's message can arrive in between, when the record still says "bot
Original PR description
Before this commit, the hoot test "keep banner for messages received while scrolled up" failed at random on runbot:
```
Failed to find 1 of ".o-mail-Thread-banner:has(:text('1 new message'))"
(Timeout of 10 seconds). Found 0 instead.
```
This happens because the test waits for the scroll position it sets in the DOM only, while the thread copies that position to the record on the scroll event, one animation frame later. Bob's message can arrive in between, when the record still says "bottom": the counter the banner reads stays frozen at 0 and the message is marked as read on arrival, so the banner never shows.
This commit waits until the record holds that position before posting.
https://runbot.odoo.com/odoo/error/945967
Forward-Port-Of: odoo/odoo#282333
Forward-Port-Of: odoo/odoo#282218Before this commit: ------------ - The order info button was not visible on the ticket screen in the mobile UI. After this commit: ------------ - Display the order info button in both the mobile and desktop views of the ticket screen. Related: - Enterprise: https://github.com/odoo/enterprise/pull/124485 Task-6388045 Forward-Port-Of: odoo/odoo#276568
Original PR description
Before this commit: ------------ - The order info button was not visible on the ticket screen in the mobile UI. After this commit: ------------ - Display the order info button in both the mobile and desktop views of the ticket screen. Related: - Enterprise: https://github.com/odoo/enterprise/pull/124485 Task-6388045 Forward-Port-Of: odoo/odoo#276568
Description of the issue/feature this PR addresses: Odoo supports WebP image fields, but `base_import` validates remote images with `PIL.Image.open()`. Odoo intentionally leaves Pillow's WebP decoder unloaded, so a valid WebP URL is rejected as an unidentified image. Current behavior before PR: Importing a valid WebP image URL fails with `cannot identify image file`. Oversized and unsupported WebP files are also rejected by Pillow before the import-specific size policy can be applied. Desire
Original PR description
Description of the issue/feature this PR addresses: Odoo supports WebP image fields, but `base_import` validates remote images with `PIL.Image.open()`. Odoo intentionally leaves Pillow's WebP decoder…
Description of the issue/feature this PR addresses: Odoo supports WebP image fields, but `base_import` validates remote images with `PIL.Image.open()`. Odoo intentionally leaves Pillow's WebP decoder unloaded, so a valid WebP URL is rejected as an unidentified image. Current behavior before PR: Importing a valid WebP image URL fails with `cannot identify image file`. Oversized and unsupported WebP files are also rejected by Pillow before the import-specific size policy can be applied. Desired behavior after PR is merged: Use Odoo's existing WebP header parser for dimension validation. Valid WebP URLs import unchanged, unsupported WebP remains rejected, and the existing 42-million-pixel import limit remains enforced. Tests cover valid, unsupported, and oversized WebP URL payloads. The complete `test_base_import` suite passes (56 tests, 0 failures/errors). --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282342 Forward-Port-Of: odoo/odoo#276648
### Issue: When a company is not connected to the French Electronic Invoicing PDP proxy, the generated XML is missing required notes: `PMT`, `PMD` and `AAB` These notes are required by Factur-X rule `BR-FR-05/BT-22` and their absence causes validation errors on the FNFE validator ### Cause: `_l10n_fr_pdp_get_default_notes` only added the notes when the company was using a PDP proxy type Non-PDP users sending invoices via other means were excluded, which contradicts the French e-invoicing
Original PR description
### Issue: When a company is not connected to the French Electronic Invoicing PDP proxy, the generated XML is missing required notes: `PMT`, `PMD` and `AAB` These notes are required by Factur-X rule `BR-FR-05/BT-22` and their absence causes validation errors on the FNFE validator ### Cause: `_l10n_fr_pdp_get_default_notes` only added the notes when the company was using a PDP proxy type Non-PDP users sending invoices via other means were excluded, which contradicts the French e-invoicing requirements ### Steps to reproduce: - Install `l10n_fr_pdp` and switch to the FR company - In Settings, ensure French Electronic Invoicing is not activated - Create and confirm an invoice (any line with tax) - Send the invoice and open the generated XML Before the fix, the `PMT`, `PMD` and `AAB` notes are missing Activating French Electronic Invoicing would include them opw-6392262 opw-6377507 Forward-Port-Of: odoo/odoo#282031 Forward-Port-Of: odoo/odoo#279966