Friday, September 11, 2026
25 changes · saas-19.1
Resolved issues and error corrections
Fixes an issue where saving an employee attendance could fail when overlapping Planning slots had different allocation percentages. This makes attendance and overtime recalculations more reliable while still allowing Planning conflicts to be handled separately.
Original PR description
### Analysis Planning schedule computation may merge intervals coming from two different sources. Fully allocated Planning slots reuse intervals from the employee working schedule, whose payload is a…
### Analysis
Planning schedule computation may merge intervals coming from two different sources.
Fully allocated Planning slots reuse intervals from the employee working schedule, whose payload is a `resource.calendar.attendance` recordset. Partial allocations, however, create synthetic intervals using a `resource.calendar` recordset.
When such Planning slots overlap, these intervals are merged into the same `Intervals` instance. This can raise a `TypeError` while sorting or merging the interval payloads, since recordsets from different models cannot be combined.
This can surface during attendance creation or deletion when overtime recomputation requests the employee Planning schedule.
### Steps to reproduce:
1. Install the following applications/modules:
- Attendances
- Planning
- Payroll / Work Entries
- `hr_work_entry_planning_attendance`
2. Create an employee with:
- Work Entry Source: Planning
- A flexible working schedule
- An employee version covering the test date
3. Create two published Planning slots for the same employee on the same day
and with overlapping times:
- Slot 1: 08:00–17:00, Allocated Percentage = 100%
- Slot 2: 08:00–17:00, Allocated Percentage = 99%
4. Create a completed attendance for the same employee on that day, for
example:
- Check In: 08:00
- Check Out: 17:00
5. Save the attendance.
Current behavior:
Attendance creation crashes while recomputing overtime/schedules with a
TypeError caused by mixing `resource.calendar` and
`resource.calendar.attendance` recordsets inside an `Intervals` instance.
Depending on the exact interval boundaries, the error can be:
```
TypeError: '<' not supported between instances of
'resource.calendar.attendance' and 'resource.calendar'
```
or:
```
TypeError: inconsistent models in:
resource.calendar() | resource.calendar.attendance(...)
```
Expected behavior:
The attendance should be created successfully. Conflicting Planning slots
may still be reported as a Planning conflict, but attendance schedule
recomputation must not crash with an internal TypeError.
### Fix
This commit creates the partial-allocation intervals with an empty `resource.calendar.attendance` recordset instead. This keeps the interval payload model consistent with the working schedule intervals.
opw-6511903
Forward-Port-Of: odoo/enterprise#130820The Contracts page no longer offers a Kanban view option because that view is not available or needed. This prevents users from selecting a view that would not work, making navigation clearer and avoiding confusion.
Original PR description
We don't have a Kanban view for contracts, but we still allow users to select that view type. After discussion with the team, we've deemed that view unnecessary. Instead of implementing the Kanban view, we'll just remove that option from the "Employee Records" (Contracts) page. opw-6475797 Forward-Port-Of: odoo/odoo#284829
This fixes a crash when exporting the Peruvian Inventory and Balance General Ledger report. Users can now generate the report successfully while keeping the required SUNAT file format.
Original PR description
### Description of the issue/feature this PR addresses: This PR fixes a server crash in the Peruvian localization (l10n_pe_reports_lib) that occurs when generating the "Inventory and Balance" General…
### Description of the issue/feature this PR addresses: This PR fixes a server crash in the Peruvian localization (l10n_pe_reports_lib) that occurs when generating the "Inventory and Balance" General Ledger report. The crash is triggered by strict validation rules within Python's csv module, which rejects the custom line terminator used to fulfill the SUNAT PLE formatting requirements. ### Current behavior before PR: When a user attempts to generate and export the "Inventory and Balance" report, the server crashes with a ValueError: bad delimiter or lineterminator value. This happens because the csv.DictWriter is initialized with lineterminator='|\n' to ensure every row ends with a pipe. Python's underlying csv implementation rejects this, as it expects standard line endings (\r, \n, or \r\n) and throws an error if the delimiter character (|) is included in the terminator string. ### Desired behavior after PR is merged: The "Inventory and Balance" report generates successfully without server errors. The code now uses the standard lineterminator='\n' to satisfy Python's validation rules. To maintain the mandatory trailing pipe (|) at the end of each row required by SUNAT, a dummy empty column (['']) is appended to the field names with restval=''. This prompts the writer to naturally append the final pipe as a column delimiter before the newline, resulting in the exact |\n output format required, safely and reliably. opw-6509674 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/enterprise#129636
This fix stops Odoo from automatically saving and closing an editable list row when users open a mobile file picker inside a form. It prevents in-progress edits, such as adding course resources, from being silently lost on mobile devices and tablets.
Original PR description
The form view autosaves on 'visibilitychange' (e.g. when the user switches tab/app) to avoid losing unsaved changes. On mobile, opening the native file picker for a binary field also fires 'visibilitychange', which triggered this autosave. When that binary field was part of an editable x2many list, the autosave forced the row out of edition before the file could be selected, silently discarding the edition in progress. Skip the autosave when a x2many field of the root record currently has a row in edition. Can be reproduced in eLearning > course > content > Additional Resources, on mobile devices (must force "desktop mode" in the browser), and on tablets. opw~6517735 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#287730 Forward-Port-Of: odoo/odoo#287581
This fixes an issue where mobile users could not see the search field options on the Point of Sale Orders screen. Staff can now search orders by details such as date or customer on small screens, improving usability for mobile PoS workflows.
Original PR description
Steps to reproduce: - Open a PoS session on a small screen (mobile app or mobile browser) - Register at least one order, so the order list is not empty - Go to the Orders screen and type a term in…
Steps to reproduce: - Open a PoS session on a small screen (mobile app or mobile browser) - Register at least one order, so the order list is not empty - Go to the Orders screen and type a term in the search bar Issue: On a desktop the search bar drops down the list of fields to search on (Reference, Receipt Number, Invoice Number, Date, Customer). On a small screen that list never shows up, so the search silently falls back to the first field and there is no way to search by Date or by Customer. Cause: The list is rendered, but painted behind the order list. Under the media-breakpoint-down(sm) block of ticket_screen.scss the order list becomes `position: sticky; z-index: 1`, so a sibling rule raised `.search .fields` to `z-index: 2` to keep the dropdown on top. The `z-1` utility class put on that dropdown in 07f743843830 compiles to `z-index: 1 !important` and overrides the rule. Both elements end up at `z-index: 1` in the same stacking context, and the order list wins the paint order because it comes later in the DOM. Fix: Drop the `z-1` utility and declare `z-index: 2` on `.fields` in the search bar's own stylesheet, which makes the small-screen override in ticket_screen.scss redundant. The stacking of the dropdown now lives in a single place, next to the rest of its styling, so a utility class added to that element cannot silently disable it again. A tour clicks its target element directly and so cannot see a purely visual overlap, which is why the existing MobileTestUi runs of TicketScreen.search() never caught this. The added assertion checks that a suggestion is the topmost element at its own center. opw-6540466 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286983
Empty or interrupted attachment uploads no longer cause the media dialog or chatter to crash. The system now handles missing file checksums safely, so users can continue working even when malformed or zero-byte attachments exist.
Original PR description
Problem: Interrupted uploads or malformed email payloads can create 0-byte binary `ir.attachment` records where the `checksum` is `False`. Accessing the computed `image_src` field on these records…
Problem:
Interrupted uploads or malformed email payloads can create 0-byte binary `ir.attachment` records where the `checksum` is `False`. Accessing the computed `image_src` field on these records triggers a `TypeError: 'bool' object is not subscriptable` when attempting to slice `attachment.checksum[:8]`. This crashes the Media Dialog and Chatter.
Purpose:
Add a fallback boolean guard to `attachment.checksum` inside `_compute_image_src` so that empty attachments evaluate safely to a string ('0') instead of raising a traceback, allowing the UI to render gracefully.
Steps to Reproduce on Runbot:
1. Go to Settings > Technical > Database Structure > Attachments.
2. Create a new record: Name: `test.png`, Type: `File` (Binary), File Content: [leave empty], Is public document: Checked.
3. Open any record with a Chatter (e.g., Contact or CRM Lead) and click "Insert Image" to open the Media Dialog.
4. The system attempts to evaluate `image_src` and throws the `TypeError`.
Notes:
A test (`test_compute_image_src_empty_checksum`) was added to `test_ir_attachment.py`
opw-6482674
Forward-Port-Of: odoo/odoo#287639
Forward-Port-Of: odoo/odoo#287444The Timesheets Assistant sample data now uses regular project tasks instead of task templates. This helps generated sample activities appear with the right task links, making demos and onboarding data more accurate.
Original PR description
The Timesheets Assistant sample data generator searches project.task with `is_template != False`, so it collects template tasks instead of regular ones and the generated activity never links to a task. Task-6566451
The WhatsApp disconnect option is now only shown where it can be safely used, preventing manually configured accounts from appearing connected while incoming messages have actually stopped. This also avoids access errors for regular internal users opening WhatsApp account settings.
Original PR description
`show_disconnect` was true for any account holding a token, so the Disconnect button showed on manually configured accounts as well. Pressing it unsubscribes the webhook on Meta first, then clears the token, and that write is rejected on a manual account since the credentials are required there. Odoo rolls back, Meta does not, so the account keeps looking configured while incoming messages stop. The compute also read `token`, restricted to WhatsApp administrators, while every internal user has read access on `whatsapp.account`, so opening the account form as a regular user raised an AccessError. The button is now shown only for administrators on onboarded accounts, and `button_disconnect` checks write access, since hiding a button does not stop an RPC call and the request to Meta happens before the write that would have been refused. Task-6544628 Forward-Port-Of: odoo/enterprise#130759
The project overview now shows the upcoming milestone based on the milestone deadline rather than creation order. This keeps the project list aligned with the milestone list and helps users see the correct next deliverable.
Original PR description
Issue: The project list could display the first created unreached milestone as the next milestone, even when another milestone had an earlier deadline. This made the project overview inconsistent…
Issue: The project list could display the first created unreached milestone as the next milestone, even when another milestone had an earlier deadline. This made the project overview inconsistent with the milestone list. Steps to reproduce: - Create a project with milestones enabled. - Create MS1, then MS2. - Give MS1 a later deadline than MS2. - Open the project list and display the Next Milestone column. Cause: `_compute_next_milestone_id()` aggregated unreached milestones as an `id:recordset` and selected its first element. The ORM orders that aggregate by database ID, so creation order was used instead of the milestone model's deadline order. https://github.com/odoo/odoo/blob/765174be270813442df6c497456fe2864517da0b/addons/project/models/project_project.py#L209-L218 https://github.com/odoo/odoo/blob/765174be270813442df6c497456fe2864517da0b/odoo/models.py#L364-L377 Solution: Retrieve unreached milestones through their normal ordered search before grouping them per project. This preserves batched computation while ensuring that the selected record follows the established milestone order. opw-6496938 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#287355 Forward-Port-Of: odoo/odoo#285933
German point-of-sale sessions using Fiskaly no longer fail to close when an order customer is an address contact without its own name. The export now uses the displayed customer name or a safe fallback, helping businesses complete session closing and required compliance exports reliably.
Original PR description
Steps to reproduce: - German PoS with Fiskaly TSS configured - Set a customer that is an address contact (type invoice/delivery/other) on an order; such a contact has no name of its own, it is…
Steps to reproduce: - German PoS with Fiskaly TSS configured - Set a customer that is an address contact (type invoice/delivery/other) on an order; such a contact has no name of its own, it is displayed with its parent's - Close the session Issue: Closing crashes with "TypeError: 'bool' object is not subscriptable" and the session cannot be closed at all. Cause: _get_dsfinvk_cash_point_closing_data builds the DSFinV-K buyer block from partner.name, which is only guarded by "if partner := o.partner_id". res.partner.name is not required: the res_partner_check_name constraint only enforces it for type='contact', so an address contact stores NULL there and partner.name reads as False, which cannot be sliced. Fix: Fall back on complete_name - what the UI displays for those contacts, "Parent Company, Delivery" - and on a literal when even that is empty, since the buyer name is mandatory in the export. Reading name first leaves the exported value untouched for every partner that has one. opw-6518336 Forward-Port-Of: odoo/enterprise#129709
This fix ensures Kenya OSCU invoice numbering is only rolled back when a new number was actually used. It prevents duplicate invoice numbers from being reused after failed eTIMS submissions, reducing errors and compliance disruption.
Original PR description
Followup of d722a68d97d, we should only decrement the OSCU invoice sequence if a new OSCU invoice number was consumed, otherwise it would possibly lead to sending invoice with a duplicate invoice…
Followup of d722a68d97d, we should only decrement the OSCU invoice sequence if a new OSCU invoice number was consumed, otherwise it would possibly lead to sending invoice with a duplicate invoice number to eTIMS. Use case: 1/ We try sending a newly posted invoice to eTIMS, but eTIMS is unreachable: * we allocated a new OSCU invoice number (for ex. `1800`) * we try sending the invoice to eTIMS but fail with a connection error (error code: `CON`) We keep the consumed invoice number. 2/ We try a second time, this time eTIMS is reachable: * as invoice already has a number (for ex. 1800), we check if it exists on eTIMS (that's not the case, error code: `001`) * So we continue and try sending the invoice to eTIMS, this time we get another error, like missing customer information. Here, in that specific conditions, we will decrease the OSCU invoice sequence (back to `1799`) while we haven't consumed any new number. 3/ We fix the previous error (missing customer information) and then successfully send the invoice to eTIMS. 4/ We then try sending another invoice that have no OSCU invoice number yet, as the sequence has been decreased, we will get the OSCU invoice number `1800` again and trying to send it to eTIMS will return an error: `Invoice number already exists`. opw-6490273
This fix prevents test logins from unnecessarily rotating password hashes and session IDs during automated runs. It reduces random test failures caused by overlapping requests seeing inconsistent session states, improving confidence in test results without changing normal user behavior.
Original PR description
The test harness patches the CryptContext object to spend less time hashing to decrease total test runtime. Because the hash parameters have changed, every first login (per transaction) per user will result in a hash rotation. The session_id is also rotated when the password hash rotates. When multiple requests are sent to the server while a session rotation is underway, the session datastore holds either a valid, or expired, or logged-out user session. This is a source of indeterminism in tests that can be prevented by always returning None value for replacement hash. REF Runbot; https://runbot.odoo.com/odoo/error/242811 REF Runbot; https://runbot.odoo.com/odoo/error/233722 Forward-Port-Of: odoo/odoo#287350 Forward-Port-Of: odoo/odoo#285710
The quotation document form now clearly shows that an attachment must be added before saving. This prevents confusion when users create quote documents, because the required step is shown on the upload field instead of a locked name field.
Original PR description
When trying to save an empty quotation document from the form view, the save is blocked because the `name` field is required. However, `name` is readonly when no attachment has been selected. As a result, the form doesn't display the required-field decoration on that field, which is confusing. The attachment field should be marked as required in the view instead. This makes it clear that an attachment must be selected first, after which the `name` field becomes available and can be filled in. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#287400
This fix ensures product identifiers sent to Google Analytics match the identifiers used in Google Merchant Center feeds. This helps businesses get more consistent advertising and ecommerce reporting for website shop products.
Original PR description
Commit d0bf183b053eb0133e6f7e5e04481ca07bff6bb3 fixes a mismatch between GA4 `item_id` and GMC `id` but was missing the fix in `_get_google_analytics_data` method opw-6443326 Forward-Port-Of: odoo/odoo#287590
This fix helps the HTML editor recover correctly when it detects outdated content during collaborative editing. Users are less likely to remain stuck with stale text after another save has happened, improving content reliability.
Original PR description
Before this commit, an editor recovering from a stale document could stop on this error and keep the stale content:
```
Error: Concurency detected while recovering from a stale document. The
last history id of the server is different from the history id received
by the html_field_write event.
at CollaborationOdooPlugin.resetFromServerAndResyncWithPeers
```
This happens because the recovery compares the history id of the record with the one the html_field_write event carried. A write keeps only the last step id in the field, so an event handled after a later write names an id the record no longer holds. As a result, the recovery stops there and the document stays stale.
This commit fixes the issue by taking the history id read from the record as the new server reference, so the editor converges on the document the server holds.
https://runbot.odoo.com/odoo/error/944595
Forward-Port-Of: odoo/odoo#287408This fix prevents an error that could appear when users ask the AI assistant to open another view while a full email composer is still open. The system now avoids refreshing a record that has already been closed, making navigation smoother and preventing unnecessary error popups.
Original PR description
Asking the AI agent to navigate to a different view calls doAction with clearBreadcrumbs, which tears down the current form view (and its chatter) before the still-open full mail composer dialog is…
Asking the AI agent to navigate to a different view calls doAction with clearBreadcrumbs, which tears down the current form view (and its chatter) before the still-open full mail composer dialog is closed. Closing that dialog then calls the chatter's onCloseFullComposerCallback, which reloads the parent record through reloadParentView(). However at that point the chatter no longer exists, so the reload's RPC call gets rejected with "Component is destroyed", and nothing is left to catch it.
How to reproduce:
- Open "Ask AI" from the top bar.
- Open an opportunity in CRM, then open the mail composer (click either 'Send message' or 'Log Note'), then click the enlarge button so it opens as a full composer dialog.
- Ask the agent (the one you pre-opened) to open another view, e.g. "show me all my contacts in the US", "show me the contact view of Abigail Peterson"
Current behavior:
The requested view opens correctly, but an UncaughtPromiseError ("Component is destroyed") is raised.
Expected behavior:
Switching views while a full composer dialog is open should not raise any error. The chatter's parent record should simply not be reloaded if the chatter has already been destroyed by the time its full composer dialog closes.
task: 6365003
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#287125This fixes an error that could appear when the AI assistant opened another view while a full email composer was still open. Users can now switch views smoothly without seeing a disruptive error message.
Original PR description
Asking the AI agent to navigate to a different view calls doAction with clearBreadcrumbs, which tears down the current form view (and its chatter) before the still-open full mail composer dialog is…
Asking the AI agent to navigate to a different view calls doAction with clearBreadcrumbs, which tears down the current form view (and its chatter) before the still-open full mail composer dialog is closed. Closing that dialog then calls the chatter's onCloseFullComposerCallback, which reloads the parent record through reloadParentView(). However at that point the chatter no longer exists, so the reload's RPC call gets rejected with "Component is destroyed", and nothing is left to catch it.
How to reproduce:
- Open "Ask AI" from the top bar.
- Open an opportunity in CRM, then open the mail composer (click either 'Send message' or 'Log Note'), then click the enlarge button so it opens as a full composer dialog.
- Ask the agent (the one you pre-opened) to open another view, e.g. "show me all my contacts in the US", "show me the contact view of Abigail Peterson"
Current behavior:
The requested view opens correctly, but an UncaughtPromiseError ("Component is destroyed") is raised.
Expected behavior:
Switching views while a full composer dialog is open should not raise any error. The chatter's parent record should simply not be reloaded if the chatter has already been destroyed by the time its full composer dialog closes.
community: https://github.com/odoo/odoo/pull/287125
task: 6365003
Forward-Port-Of: odoo/enterprise#131112Time off measured in hours now correctly ignores non-working periods in employee schedules. This prevents leave balances from being overstated when a multi-day absence includes partial non-working days, improving payroll and HR accuracy.
Original PR description
When computing the amount of hours used by a time off, if a time off entry was set in the working schedule it would not be taken into account and the amount of hours used would be wrong. Steps to reproduce: ------------------- * Open any working schedule WS and make sure that the friday has morning set as working time and afternoon as non-working time * Make sure the time off type is configured to use hours and not days * Create a time off of 2 days that includes a friday > Observation: The amount of hours used is 16 hours instead of 12 hours Why the fix: ------------ When now filter out the non working period when computing the work intervals. opw-6469587 Forward-Port-Of: odoo/odoo#285955
French PDP Flow 10 responses are now processed instead of only being saved as files. Rejected reports show their rejection details, move to the correct status, and can be corrected and resent manually with a new transmission reference.
Original PR description
Flow 10 PPF responses were stored as attachments without being processed. Consequently, rejected reports remained marked as sent, the rejection reason was not shown to users, and corrected reports could not be submitted again. Process the PPF response codes, update the flow state, and log the returned details in the chatter. Keep response attachments separate from the outgoing payload and allow rejected reports to be manually resent with their original moves and a new transmission identifier. no task id Forward-Port-Of: odoo/odoo#287338
Downloaded signed PDFs now correctly align multiline Arabic text entered in right-to-left text areas. This improves document readability and ensures signed forms match the intended layout for Arabic-speaking users.
Original PR description
Issue: ---------------------------------------- Arabic text in a rigth-to-left text area is not aligned in the downloaded PDF documents. Steps to reproduce: ---------------------------------------- -…
Issue: ---------------------------------------- Arabic text in a rigth-to-left text area is not aligned in the downloaded PDF documents. Steps to reproduce: ---------------------------------------- - Create a template with a rigth-to-left textarea., Make it fillable by the user. - Click "Sign Now" - Enter multiline arabic text - Validate and download PDF - The lines aren't aligned in the PDF Cause: ---------------------------------------- We compute the empty space before the line with `stringWidth()` on the line but this method doesn't do text-shaping on arabic text. We then do the text-shaping using `reshape_text()` and draw the line. the text shpaing "merged" some caracters making `stringWidth()` return a higher number than the actual drawned line. Solution: ---------------------------------------- Call `reshape_text()` before `stringWidth()`. Before: <img width="937" height="247" alt="image" src="https://github.com/user-attachments/assets/8a43a677-fd29-4d8e-a1cd-419b358667b9" /> After: <img width="896" height="213" alt="image" src="https://github.com/user-attachments/assets/cf8d0ebe-e363-4e07-9eb5-e4963e5ca137" /> opw-6438643x Forward-Port-Of: odoo/enterprise#130991 Forward-Port-Of: odoo/enterprise#130672
Image upload fields now apply the Android camera workaround only in Chromium-based Android browsers that need it. This prevents unnecessary document picker options in other environments, especially the native app, while keeping camera access available where Android would otherwise hide it.
Original PR description
Since Android 14, Chromium sends a file input accepting only images straight to the photo picker, which has no "Camera" entry. The image fields work around it by appending `dummy/allowAndroidCamera`…
Since Android 14, Chromium sends a file input accepting only images straight to the photo picker, which has no "Camera" entry. The image fields work around it by appending `dummy/allowAndroidCamera` to their accept attribute: a mimetype which is not an image is enough to get the generic chooser, and its camera, back. https://issues.chromium.org/issues/40937303 That invalid mimetype was appended for everyone, while only the browsers based on Chromium on Android need it: - the issue is an Android one, the desktop file dialogs are not concerned - the native app builds its own file chooser out of the accept attribute, and the invalid mimetype makes it offer the document picker on a field which only accepts images - Firefox and Safari are not based on Chromium and are not affected The workaround is now limited to the browsers needing it, and the expression moved from the template to a getter, since it is no longer a simple concatenation. Code made by Claude Supervised by RFR --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286270 Forward-Port-Of: odoo/odoo#285643
This fixes an issue where spreadsheet formulas could fail after changing locale settings, such as French decimal formatting, when reading a single related invoice total. Users can now calculate with those values normally instead of seeing errors caused by numbers being treated as text.
Original PR description
Steps to reproduce:
- insert a sale.order list into a spreadsheet
- change the locale to FR_fr
- add the formula in A1: =ODOO.LIST(1, 1, "invoice_ids.amount_total"
- in A2: =A1+1 => error
The value for the "amount_total" is stringified
to something like "4.5" because of the `[].join(",")` but "4.5" is not interpreted as a number in the FR locale where the decimal separator is "," and it should be "4,5"
With this commit, when there's a single record in the x2many, we fallback on the "normal" case and return the real value.
When there are multiple values, we volontarily keep the current behavior. We can't "just format it" because we join with "," and it wouldn't work if "," is also the decimal separator. This is a known and accepted limitation, especially in stable
Task: 6307092
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#270279This fix prevents spreadsheet actions from converting multi-value linked records into plain text. Business users benefit from more reliable spreadsheet behavior when working with document-related data and filters.
Original PR description
See community PR task-6307092 Forward-Port-Of: odoo/enterprise#120701
Point of Sale register closing messages now include cash in/out movements made by POS managers who do not have accounting access. This prevents misleading closing differences in session records when the cash counted by the user was actually correct.
Original PR description
Steps to reproduce: - Give a user PoS Administrator rights and no Accounting rights. - As that user, open a session with cash control, sell something paid in cash and do a Cash Out. - Close the…
Steps to reproduce: - Give a user PoS Administrator rights and no Accounting rights. - As that user, open a session with cash control, sell something paid in cash and do a Cash Out. - Close the register. The closing popup shows the expected cash (opening + cash payments - cash out); enter exactly that amount, the popup shows no difference. - Open the closed session: its chatter says "Closing difference: -X", X being the cash out amount, and "Closing expected" is the amount before the cash out. Issue: The closing control data agrees with the user, but the closing message records a cash difference equal to the cash out. Cause: `_compute_cash_balance` sums `statement_line_ids` with the rights of the current user. Cash moves are `account.bank.statement.line` records, which `_inherits` `account.move`, so the account.move record rules apply to them too. For a PoS user the only such rule is `rule_invoice_pos_user` (`pos_order_ids != False`), and a cash move has no PoS order: unless the user is in `account.group_account_invoice`, their own cash moves are filtered out and `cash_register_balance_end` ignores them, while `get_closing_control_data` sums the lines in sudo. Since da8be203ec32 PoS managers can create cash moves without any accounting group, which made this visible: in 18.0 cash in/out required `account.group_account_invoice`, whose `account_move_see_all` rule makes every move readable. The values stored at closing are right by accident: `_validate_session` reads the lines in sudo just before, and the one2many cache is shared between the sudo and non-sudo environments of the same transaction. The message posted by `update_closing_control_state_session` runs in its own transaction and gets the filtered sum. Fix: Read the cash lines in sudo in `_compute_cash_balance`, as `get_closing_control_data`, `get_cash_in_out_list` and `_validate_session` already do. Users with accounting rights see all lines already, so nothing changes for them. opw-6521591 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286308
The Point of Sale product configurator no longer shows extra-price badges when a fixed pricelist means those extras will not actually be charged. This prevents cashiers and customers from seeing misleading price information during checkout.
Original PR description
Steps to reproduce: - Create a pricelist "TAKEAWAY" with a fixed price of 10.00 on a product whose sales price is 20.00 - Create a preset "TAKEOUT" and set its pricelist to "TAKEAWAY" - Add to that…
Steps to reproduce: - Create a pricelist "TAKEAWAY" with a fixed price of 10.00 on a product whose sales price is 20.00 - Create a preset "TAKEOUT" and set its pricelist to "TAKEAWAY" - Add to that product an attribute with variant creation "Never", with a value carrying an extra price of 1.00 - In the POS, switch to the preset "TAKEOUT" and click the product Issue: The configurator advertises the attribute value with a "+ $ 1.00" badge, but that extra is charged nowhere: the title of the popup and the resulting order line both stay at the 10.00 of the pricelist. Cause: A fixed pricelist rule replaces the whole price of the product, the attribute extra prices included: _compute_price on product.pricelist.item returns fixed_price and never reaches _compute_base_price, the only place where _get_attributes_extra_price is taken into account. getPrice is a faithful port of that and overwrites `basePrice + price_extra` with rule.fixed_price. The configurator, however, rendered its badges out of value.price_extra alone, without ever asking what the pricelist of the order does with it. Fix: Only advertise an extra price when the price of the product actually reflects it, the way website_sale already does with the show_extra_price of _get_additionnal_combination_info. Asking getPrice covers more than a fixed rule: a rule based on another pricelist recurses with no extra either, and a full discount leaves nothing of it. Combo items keep their badges, since computeComboItems adds their extras on top of the combo price, like _get_combo_item_display_price does. opw-6528187 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286475