Monday, August 24, 2026
60 changes · saas-19.3
Enhancements to existing features
Mail-related views now load records in smaller batches when a result limit is used, instead of trying to process all matching records at once. This helps users open simple mail and activity views reliably while still respecting security access rules.
Original PR description
When a limit is applied in the search method, fetch the data in small batches like we do in ir.attachment. This allows to search with a limit on views while applying security access. Without this, simple views cannot be opened because the ORM searches for all records before filtering them in memory. Note that this cannot be avoided for group by queries and that if we don't set a limit, we will eventually still fetch everything in smaller batches. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Manual data reloads in Point of Sale now also clear browser local and session storage, not just the main offline database. This helps prevent stale or mismatched data from affecting sales sessions after a reload.
Original PR description
Manual data reloads reset IndexDB but leave local and session storage intact. The goal is to clear them to avoid inconsistent data. task-6456447 Forward-Port-Of: odoo/odoo#283429 Forward-Port-Of: odoo/odoo#281456
HR teams can now see and configure whether each time off type creates a matching Calendar entry. This makes the existing setting easier to manage and helps avoid unexpected calendar events for leave requests.
Original PR description
The `create_calendar_meeting` field on `hr.leave.type` allows users to choose if leave requests created with a given time off type generate a corresponding entry in the Calendar app. However, this field was not displayed on the form view. This commit adds `create_calendar_meeting` to the `hr.leave.type` form view inside the configuration section, along with dedicated help text explaining its behavior. Task: 6445794 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283450
Inventory quantity updates now avoid repeating the same warehouse lookup when processing several products at once. This reduces unnecessary database work during batch operations, helping stock updates run more efficiently without changing user-facing behavior.
Original PR description
When `_inverse_qty_available` processes multiple products, it performs the same warehouse search for every eligible product, resulting in redundant queries during batch operations. Look up the warehouse lazily once and reuse it for all products in the recordset. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283564
Improves the HTML editor so wide tables scroll inside their own area instead of shifting surrounding content. It also makes cursor placement more reliable around tables and blockquotes, helping users continue writing or navigating without layout disruption.
Original PR description
#### Description of the feature this PR addresses: - Resizing a table past the width available to it made the whole editable overflow, the scrollbar appeared on the editable and dragged the…
#### Description of the feature this PR addresses: - Resizing a table past the width available to it made the whole editable overflow, the scrollbar appeared on the editable and dragged the surrounding content sideways. - The no-inline selection handling only knew about the editable root, so any other container that should not hold a collapsed selection needed its own selection logic. - A blockquote could not hold selection placeholders, so an element the cursor cannot be placed on a table wrapper, table of content had no way to be written above, below, or left with the arrow keys. #### After this PR: - An overflowing table gets its own scroll container, added and removed as it is resized, so only the table scrolls. - The element that shouldn't hold direct cursor can now register itself through `is_no_inline_root_predicates` and gets the same selection handling as the editable root. - A `blockquote` is a valid placeholder container, so its blocking elements get a placeholder before and after, like anywhere else. Enterprise PR: https://github.com/odoo/enterprise/pull/128567 task-5123011 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Tables in the Studio report editor now display at their full width instead of being hidden inside a horizontal scroll area. This makes the editor better reflect how printed reports will look, helping users spot layout issues while editing.
Original PR description
The report editor is a preview of the printed report and lays out tables on its own terms: a table too wide has to be visible as such while editing, not hidden behind a scroll container. Opt it out of the table wrapper. Community PR: https://github.com/odoo/odoo/pull/283483 task-5123011
Resolved issues and error corrections
Point of Sale returns now link back to the original sale so returned items use the correct historical cost. This prevents inventory valuation errors and accounting imbalances for products valued with average cost or FIFO methods.
Original PR description
Currently, returning a product via the PoS does not populate the `origin_returned_move_id` on the generated incoming stock move. For products using AVCO or FIFO valuation, this causes the stock valuation engine to fall back to the product's current standard price instead of using the historical cost of the original sale, resulting in stock valuation errors and accounting imbalances. This commit fixes the issue by updating `_prepare_stock_move_vals` to evaluate the `refunded_orderline_id`. It traces the refund back to the original PoS order and dynamically links the original completed outgoing stock move. This ensures the valuation waterfall correctly intercepts the return and applies the original historical cost. opw-6216531 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273847
Code cleanup and technical improvements
Removed unused internal customizations in the GCC invoice module that no longer performed any needed work. This keeps invoice maintenance simpler while preserving existing behavior for users.
Original PR description
Remove create() and _compute_narration() method overrides from l10n_gcc_invoice as they only existed to call _load_narration_translation(), which has already been disabled. The parent class implementations handle all required functionality. Keeps the codebase clean by removing unnecessary method overrides. Forward-Port-Of: odoo/odoo#281565 Forward-Port-Of: odoo/odoo#281395
Documentation and clarification updates
This update records an Individual Contributor License Agreement signature for a contributor. It supports Odoo's legal compliance process by confirming contribution rights before accepting code changes.
Original PR description
This pull request submits my Odoo Individual Contributor License Agreement signature. Forward-Port-Of: odoo/odoo#282045
Miscellaneous changes
This fixes the scheduled email queue process so it correctly records its progress when run automatically. It also adds clearer logging of the email sending limit, helping support teams investigate silent failures linked to large email batches or memory limits.
Original PR description
The changes introduced by https://github.com/odoo/odoo/commit/19d5367862528979abdcd411095f18d36bdbe7b8 aimed at aligning the mailing cron job logic with the new `_commit_progress` system. While doing…
The changes introduced by https://github.com/odoo/odoo/commit/19d5367862528979abdcd411095f18d36bdbe7b8 aimed at aligning the mailing cron job logic with the new `_commit_progress` system.
While doing so, it accidentally added an if condition based on `self.env.get('ir_cron')`, which will always return False and never run the progress commit as intended.
To address this, in this PR:
- we change the condition to `if self.env.context.get('cron_id'):`, the cron_id context variable being set when the method was called from a scheduled action
- additionally we take the occassion to add an info log that outputs the computed send limit at the time the method was triggered. This will make it easier to investigate the logs ad-hoc in situations where the "Mail: Email Queue Manager" cron job fails silently because of a memory limit error. A high send limit (batch_size) increases the chances of memory errors proportionally. Knowing what the exact sending limit was at a given point in time makes investigation easier when trying to build a sequence of past events that could explain issues related to email sending.
OPW-6396087
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#283402
Forward-Port-Of: odoo/odoo#282892Credit card and cash journal statement lists opened from the accounting dashboard now allow users to open individual statements. This removes a navigation blocker and makes it easier for accounting users to review statement details.
Original PR description
Issue: When opening the credit card statements list view from clicking the "Statements" button in the accounting dashboard of a credit card journal, the resulting list view does not allow clicking on any of the items to enter the form view Steps to reproduce: 1. Create a credit card journal and some credit card statements 2. Go to the accounting dashboard, and click on the button with three dots to the upper right of the credit card journal card and click "Statements" 3. Try to click on any of the statements in the list view and it won’t open any of them Cause: The window action for credit card journals (action_credit_statement_tree) was missing the form view in the view_mode Solution: Add form to the view_mode of action_credit_statement_tree. The cash journal bank statements window action (action_view_bank_statement_tree) was also missing the form view, so it was added as well opw-6449315 Forward-Port-Of: odoo/odoo#282816
Odoo now handles empty or malformed uploaded attachments more safely when loading images. This prevents the Media Dialog and Chatter from crashing, so users can continue working even if an attachment upload was interrupted or invalid.
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
across the framework.
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., Helpdesk or Sales Order) and click "Insert Image" to open the Media Dialog.
4. The system attempts to evaluate `image_src` and throws the `TypeError`.
Notes:
A regression test (`test_compute_image_src_empty_checksum`) was added to `test_ir_attachments.py` to ensure this framework guard remains active.
opw-6482674
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThe Inventory Valuation report now shows accounting differences for products that have no stock left, even when multiple valuation accounts are used. This helps finance teams see and balance all relevant inventory accounts without losing the prior performance benefit for zero-quantity products.
Original PR description
## Problem If multiple valuation/variation accounts are used, the Inventory Valuation report will not show the balance of accounts attached to products that have 0 quantity available if a different…
## Problem If multiple valuation/variation accounts are used, the Inventory Valuation report will not show the balance of accounts attached to products that have 0 quantity available if a different account has quantity. ## Solution In order to maintain the performance improvements intended by the commit that introduced the `qty_available != 0` filter, we will avoid calculating `total_value` for products with 0 quantity. We will still run `stock_accounting_value` on these products in order to capture interim accounting value on the Inventory Valuation report. ## Steps to Reproduce (Runbot v19) (defer to the test for more info) 1. Create an extra set of valuation/variation accounts 2. Create a product, avco perpetual accounting the default valuation/variation accounts 3. Create a second product, avco perpetual accounting the new valuation/variation accounts 4. Purchase 1 unit of each of the products and receive, bill both 5. Sell 1 unit of the product attached to the new valuation/variation 6. Go to Accounting > Review > Inventory Valuation, and note that the new valuation/variation accounts are not present. If you click Generate Entry, you will see that these accounts need to be balanced opw-6473319 Forward-Port-Of: odoo/odoo#282819
Message posting now cleans submitted data before a message is accepted, using the current user's permissions as the reference. This helps prevent invalid or inappropriate data from being posted in discussions and improves reliability of mail conversations.
Original PR description
This change sanitizes some post data before allowing the post, making sure the data received by `message_post` is clean based on the current user. part of task-6452761 Forward-Port-Of: odoo/odoo#283677 Forward-Port-Of: odoo/odoo#280894
Point of Sale receipts now show the correct cash rounding line even when a customer overpays, such as using a quick-add payment button. This keeps tickets and payment totals accurate and consistent with normal cash payments.
Original PR description
**Steps to reproduce:** - Make a rounding method, Nearest and 0.05 of rounding - Make a product that costs $4.99, don't set a tax - Go to the PoS - Order the product - Before paying click the +10…
**Steps to reproduce:** - Make a rounding method, Nearest and 0.05 of rounding - Make a product that costs $4.99, don't set a tax - Go to the PoS - Order the product - Before paying click the +10 button, then pay - The rounding line is not present on the ticket **Why the fix:** When making a normal rounded purchase, by just clicking the "Cash" button, the rounding line will be displayed. This is because we do not try to apply the rounding if the rounding of the remaining is not equal to zero. https://github.com/odoo/odoo/blob/995629db3231de944710751c3184bf1b8b1355c7/addons/point_of_sale/static/src/app/models/accounting/pos_order_accounting.js#L118-L123 When we try to over pay, the remaining will be negative by the amount we overpay, so the amount will be set to zero, and the rounding will not be set. We now take the amount we overpay into account, and deduct it from the amount we paid to then correctly compute the remaining amount without having to deal with the amount overpaid. Some tests were not taking the rounding as it was not working correctly, so it has now been changed now that it works as it should. opw-6025807 Forward-Port-Of: odoo/odoo#256117
Company-paid expenses created from a project are no longer mistakenly counted as positive revenue in project margin reports. This keeps Actual Margins accurate by excluding payment settlement lines while still recording the real expense cost.
Original PR description
Steps to reproduce --- 1. Install Sales (with Margins) and Project, and open a billable project linked to a sale order. 2. From the project's Expenses view, create an expense paid by the Company and…
Steps to reproduce --- 1. Install Sales (with Margins) and Project, and open a billable project linked to a sale order. 2. From the project's Expenses view, create an expense paid by the Company and post it. 3. Open the project's Actual Margins: the expense shows under Other Revenues as a positive amount. Issue --- Creating an expense from a project's Expenses view keeps `project_id` in the context until its journal entry is built. For a company-paid expense that entry is a payment, and `AccountMoveLine._compute_analytic_distribution` puts the project's analytic distribution on every line that is not receivable or payable, which also covers the Outstanding Payments liquidity line. An analytic amount is the opposite of the move line balance, so the negative liquidity balance becomes a positive analytic line, classified as Other Revenues, on top of the real cost already booked on the expense account. The receivable/payable filter from b6200026ecf1 narrowed the override introduced in ac1995ad6ddf but ignored the liquidity counterpart of a payment; since only profit and loss lines make up a project margin, restricting the distribution to `income` and `expense` accounts keeps the settlement line out of the report. https://github.com/odoo/odoo/blob/f037dead17eb6a74d1ea9c56b0861b285be17516/addons/sale_project/models/account_move_line.py#L10-L19 opw-6326551 Forward-Port-Of: odoo/odoo#273273
The HTML editor now keeps text background colors when users turn colored text into a list or turn a colored list item back into normal text. This prevents accidental formatting loss while editing content, helping users maintain consistent document and website styling.
Original PR description
Problem: Background color was lost both when converting text with a background color into a list item and when converting a list item with a background color back into a paragraph. Cause: - `insertListAfter` only copied `color` from the font wrapper to `li.style.color`, ignoring `background-color`. - Unwrapping a list item (`ListPlugin`) extracted `color`, `font-size`, and `text-align`, but ignored `backgroundColor`. Solution: - Preserve `background-color` from font wrapper onto `li.style.backgroundColor` when creating a list. - Restore `li.style.backgroundColor` onto a `<font>` wrapper when unwrapping a list item. Steps to reproduce: - Apply background color to a paragraph and toggle list -> background color is lost. - Apply background color to a list item and toggle list off -> background color is lost. opw-6481665 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283158
Restaurant point-of-sale split bills now correctly select the full quantity when a combo includes the same choice multiple times. This helps staff split orders accurately and prevents under-counting combo items on shared bills.
Original PR description
Steps to reproduce: --- - Install `pos_restaurant` demo data. - Open a session for `Restaurant`. - Go to any table. - Add a Sushi Lunch Combo line with the same sushi choice multiple times. - Click the "More" button and select "Split". - Click on any combo product line. Issue: --- - Only one quantity is selected instead of the full combo choice quantity. Cause: --- - Combo child lines were incremented by a fixed value of `1` during split, without considering the quantity ratio between the combo root line and combo child lines. Fix: --- - Compute the selection step based on the combo line quantity relative to the combo root line quantity. - Properly update split quantities for repeated combo choices. - Added test coverage for combo lines with repeated quantities. task-6197879 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282717 Forward-Port-Of: odoo/odoo#264049
The website editor now places drag-and-drop move handles on the correct side when users work in right-to-left languages. This makes block editing more intuitive and prevents misplaced controls for Arabic, Hebrew, and other RTL content.
Original PR description
Problem: In MoveNodePlugin, `setMovableElement` sets the position of the drag-and-drop handler without considering `this.config.direction === "rtl"`. The handler is placed on the left side regardless of text direction. Solution: - In RTL mode, calculate the handle position from the right edge of the element so it is placed on the right side with the same distance as in LTR. - Update hover hooks, editable bounds, and dropzone rectangles for RTL mode. Steps to reproduce: 1. Open the editor in RTL mode. 2. Hover over a movable block element (e.g. `<p>`). => The move handle appears on the left side of the element instead of the right. task-6442717 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283662 Forward-Port-Of: odoo/odoo#281249
This fix ensures customer and pickup details entered during restaurant self-ordering are saved before customers are sent to the online payment page. It prevents draft orders from losing important information when a customer uses the browser Back button after payment navigation.
Original PR description
**Setup** * Increase the debounce time of `debouncedSynchronizeLocalDataInIndexedDB` to **5 seconds** to reproduce the issue deterministically. * Configure a restaurant with **Self Ordering** enabled…
**Setup** * Increase the debounce time of `debouncedSynchronizeLocalDataInIndexedDB` to **5 seconds** to reproduce the issue deterministically. * Configure a restaurant with **Self Ordering** enabled (`QR Menu + Ordering`). * Configure **Mollie** as the **only** online payment method. **Reproduction** 1. Place a **takeout** order through the mobile menu. 2. Select a pickup time, enter the required customer information (including a mobile number), and proceed to the payment page. 3. Verify from the backend that the draft order contains the expected data (customer/partner and `preset_time`). 4. Press the browser **Back** button to return from the payment page. 5. Check the draft order in the backend again. [video](https://drive.google.com/file/d/1kNWpYuo79mYMV3eMelwJ5IDFeWUc7zsD/view) **Observed result** * The draft order loses its previously synced information. In particular, the **partner/customer** data (and other synced fields such as `preset_time`) are removed. **Expected result** * Returning from the payment page should not modify the draft order. All previously synced data should remain intact. **Cause** - When there's only a single payment method, it's [auto-selected](https://github.com/odoo/odoo/blob/161715c850496d3683baa5d1600380470d0b5ff5/addons/pos_self_order/static/src/app/pages/payment_page/payment_page.js#L21-L22) and `checkAndOpenPaymentPage` immediately opens the payment page via[ window.open()](https://github.com/odoo/odoo/blob/161715c850496d3683baa5d1600380470d0b5ff5/addons/pos_online_payment_self_order/static/src/app/pages/payment_page/payment_page.js#L35). - The order's local data is saved to IndexedDB on a 300ms debounce. If the redirect fires before that debounce completes, the save is cancelled, leaving IndexedDB out of sync with the in-memory order **Fix** - Before opening the payment URL, explicitly flush the order to IndexedDB using the `synchronizeLocalDataInIndexedDB`, ensuring the local data is persisted before the page navigates away. opw-6231478 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281906 Forward-Port-Of: odoo/odoo#272724
This fixes an issue where Australian accounting reports could fail if a related reports module had been removed while other accounting modules remained installed. The change keeps specialized report logic tied to the module that provides it, reducing configuration-related failures for Australian localization users.
Original PR description
We had a case where l10n_au and account_reports were installed together, but not l10n_au_reports (manually uninstalled ?). Since the custom engine was used on expressions in l10n_au, this failed. Custom engines should always be used and declared within the same module (or a submodule of the one defining the handler) to avoid such issues. opw-6451274
The restaurant point-of-sale flow now waits for table order syncing to finish before checking for the order badge. This prevents occasional automated test failures and helps ensure table status is shown consistently after a table is selected.
Original PR description
Sometimes, `test_fiskaly_basic_order` test fails with the following error: ``` AssertionError: FAILED: [55/68] Tour FiskalyTour → Step body:has(.pos-leftheader .badge:contains(5)). Element (body:has(.pos-leftheader .badge:contains(5))) has not been found. ``` `FloorScreen.clickTable()` clicks on the table and waits for a badge to appear. The badge is rendered once the table order is synced to the server. If the order is still syncing when the click on the table lands, the badge will not be present and triggers the failure. runbot-940256 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Sales users with access limited to their own documents can now cancel sales orders that include loyalty program activity without hitting an access error. This prevents blocked cancellations while still cleaning up temporary loyalty point records correctly.
Original PR description
Steps to produce: --- - Install `sale_management` and `sale_loyalty` module without demo. - From sales > products > discounts & loyalty, create new loyalty card program and save. - Now create new…
Steps to produce: --- - Install `sale_management` and `sale_loyalty` module without demo. - From sales > products > discounts & loyalty, create new loyalty card program and save. - Now create new product of 100$. - Create a user which have sales rights as `user: own documents only`. - With that user, create new sale order with product and confirm. - Try to cancel the order. Issue: --- - It shows the access error: ```py You are not allowed to delete 'Sale Order Coupon Points - Keeps track of how a sale order impacts a coupon' (sale.order.coupon.points) records. This operation is allowed for the following groups: - Sales/Administrator Contact your administrator to request access if necessary. ``` Root cause: --- - Users with the `Sales: Own Documents Only` access right only have read permissions ([1]). When they cancel a Sales Order, the `_action_cancel` method attempts to clean up the temporary pending points allocated to the order by calling `self.coupon_point_ids.unlink()`. Because this call is executed without elevated privileges, the system blocks the deletion and raises an Access Error Solution: --- - Added `.sudo()` to the `unlink()` call for `coupon_point_ids` in the `_action_cancel` method. This ensures the pending point records are cleaned up with the necessary elevated privileges. [1]https://github.com/odoo/odoo/blob/23af2b443735c6d3a2f64e44f9ea5da45638b052/addons/sale_loyalty/security/ir.model.access.csv#L16 opw-6453016 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284046 Forward-Port-Of: odoo/odoo#281477
Website editors can now directly edit previously locked parts of mega menu templates, such as footer areas and logo containers. This makes menu customization smoother and reduces the need for workarounds when building website navigation.
Original PR description
### Issue: Some elements in mega menu templates are not editable inline in the website builder. ### Steps to reproduce: - Go to Website > Site > Menu Editor and add a mega menu item. - Edit the mega menu and set its template (e.g. 'Thumbnails' or 'Logos'). - Try to inline edit certain sections (e.g. footer or logos container). ### Reason: `BuilderContentEditablePlugin` does not apply `contenteditable="true"` to these elements because they do not match any of the selectors defined in `content_editable_selectors`. ### Fix: Add missing element classes to `content_editable_selectors` so that these elements become editable inline. task-[6116253](https://www.odoo.com/odoo/project/974/tasks/6116253) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#263021
The point of sale product configurator now clears optional product suggestions when a cashier discards the main product. This prevents staff from accidentally adding extras linked to a product that was not actually added to the order.
Original PR description
When discarding the product configurator, we still showed the optional product. We no longer do that as no one wants to add optional products to a not-added product. task-6442422 Forward-Port-Of: odoo/odoo#283378 Forward-Port-Of: odoo/odoo#282916
A mail-related automated test was updated so it passes consistently across different versions of the date formatting library. This reduces false test failures in development and release pipelines without changing product behavior for users.
Original PR description
In more recent versions of babel "10:00 AM" uses a non-breaking white-space instead of a simple space. And vietnamese format loses its first comma. We don't really care about the details in this test, only that the format varies correctly according to the language of the user. Hence the test is made to use a regex that fits both versions so that it can pass in different environments. runbot-946259
The mail compose process now uses the current progress-tracking method instead of an outdated one. This prevents unnecessary warning tracebacks in server logs during automated mail queue processing, helping administrators monitor systems more clearly without changing user-facing behavior.
Original PR description
Since 19.0 `_notify_progress`` is deprecated in favor of `_commit_progress``. See: https://github.com/odoo/odoo/commit/ee337934f9885834d95592946f435c6e1c8ef970 Currently, the mail compose wizard still calls an explicit _notify_progress followed by an explicit commit. This leads to warning tracebacks being dumped into the server logs (for example everytime the "Mail Marketing: Process queue" cron runs). We replace it with an equivalent `_commit_progress` call, which should log the progress and implicitly take care of the cursor commit. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282926
Safari users can now insert a soft line break with Shift+Enter in the HTML editor, such as when editing Knowledge articles. This prevents unintended paragraph splits and makes editing behavior consistent with other browsers.
Original PR description
**Steps to reproduce:** - Use a Mac with Safari - Install Knowledge app - Go to any article - Press Shift+Enter to try to enter a soft line break - Hard split is done instead **Issue:** Shift+Enter causes a `insertParagraph` event instead of `insertLineBreak` in Safari, which triggers the `SplitPlugin` instead of the `LineBreakPlugin`. **Fix:** Check if the browser is Safari and call `insertLineBreak` from the `SplitPlugin` (when needed) by listening to the "keydown" events. (note: I was not able to find any other key combination to properly trigger the `insertLineBreak` event in Safari) opw-6413507 Forward-Port-Of: odoo/odoo#281458
The Point of Sale order details pop-up now closes automatically before staff edit a payment. This prevents the pop-up from blocking or overlapping the payment screen, making the workflow clearer for cashiers.
Original PR description
Steps to reproduce: ------------------------------------ 1. Install the Point of Sale module. 2. Create and pay for an order. 3. Open the Orders screen. 4. Select the paid order and click Order Info. 5. Click Edit Payment. Observation: ------------------------------------ The Order Info dialog remains open while navigating to the payment screen instead of closing first. Issue: ------------------------------------ When the Edit Payment action is triggered from the Order Info dialog, the navigation to the payment screen occurs without closing the dialog, leaving it visible on top of the new screen. Solution: ------------------------------------ Close the Order Info dialog before navigating to the payment screen by calling the closeAll() method of the dialog service.
This fix stops an online sales order from being confirmed when a portal customer reaches payment validation with an empty cart. It prevents accidental creation of invalid orders and keeps checkout records accurate after customers remove all items.
Original PR description
Calling `/shop/payment/validate` as a portal user with an empty cart confirms the empty sale order. Steps to reproduce: - Sign in as a portal user. - Add a product to the cart. - Remove the product. - Go to `/shop/payment/validate`. - The empty sale order is confirmed. opw-6430637 Forward-Port-Of: odoo/odoo#282741 Forward-Port-Of: odoo/odoo#280924
Mobile chat windows now use a configurable display layer instead of a fixed position. This helps other Odoo apps control which elements appear on top, reducing visual conflicts without changing the default chat behavior.
Original PR description
The z-index of chat windows on mobile views was previously fixed at `1020`, preventing other modules from adjusting their stacking order. This commit introduces a configurable z-index for chat windows, defaulting to `1020` while allowing other modules to override it when needed. task-6412411 Forward-Port-Of: odoo/odoo#283671 Forward-Port-Of: odoo/odoo#283178
Users who manually replenish products will now see the expected notification when a purchase order is created. This helps purchasing and inventory teams confirm that their replenishment action succeeded without having to search for the new order manually.
Original PR description
Currently when the user does manual replenishment no notification is displayed. ## Steps to produce: - Install Inventory and Purchase - Create a product `Chocolate Icecream` and Enable `Track…
Currently when the user does manual replenishment no notification is displayed. ## Steps to produce: - Install Inventory and Purchase - Create a product `Chocolate Icecream` and Enable `Track Inventory` - Purchase > Add a Vendor `Ice cream man` - Reordering rules > Create a new reordering rule and save: - Trigger: Manual - Min: 5 - Max:10 - Press the `Order` button ## Observed Behavior: No notification is displayed about the newly created purchase order. ## Root cause: When the Order button is pressed, the `action_replenish` method is called. This method invokes `_procure_orderpoint_confirm` at [1]. The `_procure_orderpoint_confirm` function is responsible for creating procurements from orderpoints. During this process, it retrieves the procurement values using `_prepare_procurement_values` that are later used at [2]. However, `_prepare_procurement_values` only includes the orderpoint in the procurement values when the orderpoint's trigger is set to automatic, and not when it is manual, as shown at [3]. These procurement values are then used by `_run_buy` to create a purchase order and purchase order line at [4]. Since the orderpoint is not linked to the purchase order line in this case, no matching order is found at [5], which leads to the reported issue. **Which commit caused this unintentional behavior?** This behavior was unintentionally introduced by this [commit](https://github.com/odoo/odoo/commit/2a0d2c64d0027f540101447289b4c1a10cb3ecdf) . That commit fixed an issue where purchase order lines were not being merged for temporary manual orderpoints that are created dynamically based on product demand. [1]- https://github.com/odoo/odoo/blob/c076281dedeed2e25844c43c49ec17511434e3fc/addons/stock/models/stock_orderpoint.py#L342-L349 [2]- https://github.com/odoo/odoo/blob/c076281dedeed2e25844c43c49ec17511434e3fc/addons/stock/models/stock_orderpoint.py#L737-L741 [3]- https://github.com/odoo/odoo/blob/c076281dedeed2e25844c43c49ec17511434e3fc/addons/stock/models/stock_orderpoint.py#L687-L701 [4]- https://github.com/odoo/odoo/blob/c076281dedeed2e25844c43c49ec17511434e3fc/addons/purchase_stock/models/stock_rule.py#L156-L165 [5]- https://github.com/odoo/odoo/blob/c076281dedeed2e25844c43c49ec17511434e3fc/addons/purchase_stock/models/stock.py#L276-L296 [6]- https://github.com/odoo/odoo/blob/c076281dedeed2e25844c43c49ec17511434e3fc/addons/stock/models/stock_orderpoint.py#L365 [7]- https://github.com/odoo/odoo/blob/6a84d3e519892be333552e2e0ebf8da87e0a760c/addons/purchase_stock/models/purchase_order_line.py#L380-L384 ## Solution: Instead of removing the orderpoint ID from the procurement values, we reuse the same conditions used to identify temporary orderpoints for cleanup at [6]. Based on this, we determine how purchase order lines should be merged in the `_run_buy` method. With the previous implementation, no orderpoint was included in the procurement values. As a result, the condition at [7] checking for orderpoints always evaluated to True, causing the system to identify an existing purchase order line for the same product as a merge candidate. This solution allows us to retain that fix as well as avoid the error of notifications not showing up. opw-6311520 Forward-Port-Of: odoo/odoo#283747 Forward-Port-Of: odoo/odoo#271993
This change improves how product and web form fields resize on screen, avoiding repeated page recalculations that slowed down large sales orders. For users, sales order views with many lines should open and respond much faster, making daily order entry more usable.
Original PR description
this is more like an experiment, to see if batching read and dom updates would help. this commit changes loading a SO view from 19.8s to 2.6s, so it looks like it helps 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#282788
The web search interface now safely ignores a default filter when it points to a record that no longer exists. This prevents users from seeing a crash when opening affected views, improving reliability without changing normal search behavior.
Original PR description
…'t exist Have a search view with a m2o field Have an action that sets search_default_m2o: [/BAD ID/] Before this commit there was a crash After this commit, we simply ignore the filter. task-6469841 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#282738
This fix keeps linked text visible when users select or edit text that uses a gradient style in the HTML editor. It prevents the selected link text from disappearing, making content editing clearer and less error-prone.
Original PR description
Problem: When text formatted with `.text-gradient` is inside a link with `.o_link_in_selection`, the selected text becomes invisible. `.text-gradient` sets `-webkit-text-fill-color: transparent`, which prevents `color: black !important` on `.o_link_in_selection` from taking effect. Cause: `-webkit-text-fill-color: transparent` from `.text-gradient` overrides standard text `color` rendering, causing the text to stay transparent against the selection highlight background. Solution: Set `-webkit-text-fill-color: black` on `.o_link_in_selection` to ensure text inside gradient links is rendered in black and remains clearly visible when selected. Steps to reproduce: - Add text "ABCD". - Apply gradient color to all text. - Create a link on "BC". - Place cursor/selection inside the new link. - Observe that the text is not visible. opw-6479350 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282952
This fixes an issue where translating text edited inside a related-record dialog could show old or empty content instead of the user's latest changes. Users can now open the translation dialog from these forms and see the current text, while existing editable-list behavior remains unchanged.
Original PR description
Clicking the translate button saves the form's root record before opening the translation dialog, since https://github.com/odoo/odoo/commit/9da52919a03dbcee5209430918195158c0652099. A record opened…
Clicking the translate button saves the form's root record before opening the translation dialog, since https://github.com/odoo/odoo/commit/9da52919a03dbcee5209430918195158c0652099. A record opened in an x2many form dialog keeps its changes for itself until the dialog is saved, see https://github.com/odoo/odoo/blob/242f6d3cf7288853f163ac6986a3b7aa4279efaf/addons/web/static/src/model/relational_model/static_list.js#L193. Its pending changes are not part of the root record changes, so saving the root sends nothing to the server, and the translation dialog then shows the stored terms instead of the current content, or no terms at all when the stored value is empty. The fix changes openTranslationDialog in translation_button.js, the place that decides which record to save. When the record keeps its changes for itself (record._noUpdateParent), the record is saved directly, like the button did before the commit above. The root record is still saved in the other cases, so the editable list case that commit fixed keeps working. Steps to reproduce: 1. Activate a second language in Settings > Translations > Languages 2. Open the Surveys app, open a survey and click a question in the Questions tab 3. In the Description tab, change the description 4. Click the EN button on the description field => the translation dialog shows the terms of the previous description, not the current one Ticket [link](https://www.odoo.com/odoo/project.task/6237291) opw-6237291 Forward-Port-Of: odoo/odoo#269507
Cancelling a payslip now correctly makes related time off available to be recalculated in the next payslip. This prevents approved time off from being accidentally excluded after payroll corrections, improving payroll accuracy.
Original PR description
How to reproduce: - Create a payslip for an employee and validate it - Create a new time off for said employee during the same period as the payslip and validate it - Go back to the payslip, cancel it and reset it to draft - The new time off is not included in the payslip Reason: When a payslip is cancelled, if there are time off during the same period as the payslip, their state is not reset to "to compute in next payslip" and instead stays in "to defer to next payslip", causing the issue How it was fixed: Now, when a payslip is cancelled, the new function "return_time_off_to_normal" will catch all leaves that are in the same time frame as the payslip to reset their state to "to compute in next payslip". Task ID: 6431576 Forward-Port-Of: odoo/enterprise#126868
Point of Sale bills no longer show the self-service invoicing QR code while an order is still in draft. This prevents customers from invoicing unpaid or unfinished orders, reducing payment and order reconciliation issues.
Original PR description
Step to reproduce: - install point_of_sale - have a pos, with `Early Receipt Printing` and `Self-service invoicing` enabled - open a pos ,select a product - from action button, click on "Bill" Observation: - We can see QR code in bill, using which a person can invoice itself, even when order is in draft state. - This cause a lot of anomoly like payment line not visible in pos order, even after successful payment Cause: - Prior to this version, `Qr` related data is shown only when `order.finalized` i.e. `status = draft` . https://github.com/odoo/odoo/blob/6f64942cbbbf2355f7328394a6d484f6828a80f1/addons/point_of_sale/static/src/app/components/receipt/order_receipt.xml#L76 - After commit https://github.com/odoo/odoo/commit/aeaca097ae39b293bff47458ae8af019585f9224 we removed this condition Fix: - The condition is brought back. opw-6427152 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279382
The Attendance location warning dialog now closes correctly when employees choose Discard. This prevents users from getting stuck on the check-in or check-out prompt when browser location access is blocked.
Original PR description
Steps to reproduce: -------------------------------------------- 1. Install Attendance module. 2. Enable `Device & Location Tracking` & `Attendance from Backend` in settings. 3. Block location access…
Steps to reproduce: -------------------------------------------- 1. Install Attendance module. 2. Enable `Device & Location Tracking` & `Attendance from Backend` in settings. 3. Block location access from the browser for this site (Site settings) 4. Try to checkIn/checkOut from the Dot in the systray 5. We'll have one confirmation pop-up asking to Proceed Anyway OR Discard Observation: -------------------------------------------- On clicking the discard button, Nothing happens. Issue: -------------------------------------------- In `confirmChecking()`, the `cancel` callback was defined as an arrow function using an expression body. In JavaScript, an assignment expression returns the assigned value. Since `this._attendanceInProgress` is set to `false`, the callback implicitly returns `false`. `ConfirmationDialog.execButton()` treats a `false` return value as a signal to keep the dialog open (used intentionally to block closing on validation failure) This caused the dialog to never call `this.props.close()`, leaving it permanently open when Discard was clicked. https://github.com/odoo/odoo/blob/5e84fdd99e34836a15cadc4fdf4b6bc449727e58/addons/web/static/src/core/confirmation_dialog/confirmation_dialog.js#L75-L89 Solution: -------------------------------------------- Change the `cancel` callback from an expression body to a block body, A block body arrow function returns `undefined` by default. This ensures `execButton` does not interpret the return value as a 'keep dialog open' signal, and correctly calls `this.props.close()` to dismiss the dialog. opw-6462439 Forward-Port-Of: odoo/odoo#281702
Fixed an issue where some user or contact avatars could fail to load when a record had no valid update date. This prevents a page error and keeps many-to-one avatar fields working reliably in list and kanban views.
Original PR description
Issue: The `Many2OneAvatarField` and `KanbanMany2OneAvatarField` templates were directly calling `value.write_date?.toMillis()`. Optional chaining does not handle the case where `write_date` is `false`, resulting in a `TypeError` because `toMillis()` is not available on a boolean value. Solution: Added a `uniqueId` getter in both `Many2OneAvatarField` and `KanbanMany2OneAvatarField` to safely handle a missing or false `write_date`. The getter calls `toMillis()` only when `write_date` is available and returns `undefined` otherwise. Both templates now use `uniqueId` for the avatar URL. opw-6464172 Forward-Port-Of: odoo/odoo#282659
This fix prevents crashes when users drag unscheduled planning slots onto the calendar after enabling scheduling in Studio. It restores the information Planning needs to calculate slot end times and avoids a separate date-related error, making scheduling more reliable for affected users.
Original PR description
Steps to reproduce: ------------------------- 1. Install `sale_planning` and `web_studio` with demo data. 2. Open the Planning calendar view. 3. Enable the "Scheduling" option from Studio and close…
Steps to reproduce:
-------------------------
1. Install `sale_planning` and `web_studio` with demo data.
2. Open the Planning calendar view.
3. Enable the "Scheduling" option from Studio and close it.
4. Drag an unscheduled slot onto the calendar.
Issues:
-----------
**Issue 1:**
```python
File "/home/odoo/odoo/enterprise/sale_planning/models/planning_slot.py", line 142, in write
self.assign_slot(vals)
File "/home/odoo/odoo/enterprise/sale_planning/models/planning_slot.py", line 159, in assign_slot
new_vals, tmp_sale_order_slots_to_plan, resource = slot._get_sale_order_slots_to_plan(vals, slot_vals_list_per_employee)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo/enterprise/sale_planning/models/planning_slot.py", line 228, in _get_sale_order_slots_to_plan
)._get_resource_work_info(vals, slot_vals_list_per_resource)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo/enterprise/sale_planning/models/planning_slot.py", line 366, in _get_resource_work_info
assert self.env.context.get('default_end_datetime')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError
```
**Issue 2:**
```python
UncaughtPromiseError > TypeError
Uncaught Promise > Cannot read properties of undefined (reading 'endOf')
TypeError: Cannot read properties of undefined (reading 'endOf')
```
Cause:
----------
Since commit 1ce0dc8, the scheduling/unscheduling logic has been moved to the generic calendar implementation. However, the generic scheduling flow does not provide the `default_end_datetime` context required by sale_planning. As a result, sale_planning raises an `AssertionError` while scheduling a slot.
Additionally, when no date is available, attempting to call `endOf()` raises a `TypeError`.
Solution:
------------
Introduce a generic scheduling context hook in the calendar model and override it in Planning to provide the `default_end_datetime context when scheduling a slot.
This restores the context expected by` sale_planning`, prevents the `AssertionError`, and avoids calling `endOf()` on an undefined date to resolve `TypeError`.
**NOTE:**
This issue has already been resolved in the later versions (saas-19.4) as part of the scheduling/unscheduling refactoring. This commit backports the minimal changes required to fix the issue in this version.
References: f0f7b34 & https://github.com/odoo-dev/enterprise/commit/f82d073d17ce61a2ff39496364d3dced814ee90a
Related enterprise pr: https://github.com/odoo/enterprise/pull/127196
opw-6442889
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#281178This update makes an automated test for German point-of-sale certification wait until the product screen is ready before continuing. This reduces random test failures and helps keep release validation stable without changing customer-facing behavior.
Original PR description
we face this error when running tour `FiskalyTour` with linked pr (which is completely independent of this module) and should not fail, but this can be considered as non-deterministic. waiting/confirming that product-screen is shown, before making the next move, solves the issue. build link: https://runbot.odoo.com/runbot/batch/2696526/build/121430872?debug=1 Forward-Port-Of: odoo/enterprise#127902
Fixed an issue in Sales Planning where shifts without a linked sales order line could fail when determining the customer. This helps ensure shifts are saved and displayed reliably, even when some sales details are missing.
Original PR description
Before this commit, when the shift has no SOL set, the `_compute_partner_id` crashes because the value for partner_id field is not set for that shift. This commit fixes the compute method of partner_id to make sure the value is correctly set for all shifts. Forward-Port-Of: odoo/enterprise#128965
This update prevents a rare crash in the Hungarian Intrastat reporting flow when company information is accessed in unusual permission scenarios. Standard users should not encounter this through the normal interface, but the fix makes the module more reliable for future customizations or edge cases.
Original PR description
Due to some trouble with tests, we found that in some cases, this function is called on the root company, and if the user does not have the access rights to read data from the company (users with system rights have them by default), it will cause a crash. This situation is not possible with the standard UI, but we fix it in case it becomes possible in a future version or customization.
This fix prevents the incoming invoices journal from being cleared for companies that must receive Peppol documents as vendor bills rather than through the Documents app. It helps French electronic invoicing users keep required accounting settings intact and ensures incoming documents are routed correctly.
Original PR description
Peppol documents can be received in a journal or in the Documents app (peppol_reception_mode). Some companies cannot use Documents: _peppol_allows_document_reception() returns False and the journal…
Peppol documents can be received in a journal or in the Documents app (peppol_reception_mode). Some companies cannot use Documents: _peppol_allows_document_reception() returns False and the journal stays required. This is the case of French companies (via l10n_fr_pdp). The onchange of the settings and the import did not check this method. So on a French company with the mode set to 'documents': - the Settings cleared the journal on each opening, while it was still required - the incoming documents were saved in Documents instead of vendor bills Steps to reproduce: - Create a Belgian company, with a purchase journal, and register it on Peppol as receiver - Set the reception mode to "Receive in Documents" - Change the fiscal position to France, and install l10n_fr_pdp, the Peppol part is replaced by "French Electronic Invoicing", so the radio button is not visible anymore, but the company still has peppol_reception_mode == 'documents'. - Open the Settings again: the field "Incoming Invoices Journal" is empty. opw-6429691 Forward-Port-Of: odoo/enterprise#126462
This fix keeps restaurant appointment point-of-sale tests reliable after a data reload by preserving the test state during reload checks. It affects only the test setup, so normal business behavior remains unchanged while reducing false test failures.
Original PR description
A recent PR in the community repository introduced a full clear of both `localStorage` and `sessionStorage` when reloading POS data. While this is the intended behavior in production, it breaks the test framework. This commit mocks the `clear` methods directly within the tour steps right before the reload action. This ensures the test survives the page reload and keeps its state, without polluting the core production code with test-specific logic. task-6456447 Forward-Port-Of: odoo/enterprise#128527 Forward-Port-Of: odoo/enterprise#128091
This update fixes an issue where social media users encountered an access error when liking stream posts. Likes are now processed through the proper backend flow, improving the reliability of Facebook and Twitter social stream interactions.
Original PR description
Bug === When a social user like a stream post, an access error is raised because he has no write access on it. Task-6425391 Forward-Port-Of: odoo/enterprise#128780 Forward-Port-Of: odoo/enterprise#125973
Auto-planning for monthly schedules now correctly includes the last day of the selected month. This prevents missing planned work on valid working days, helping sales and planning teams produce complete schedules.
Original PR description
Steps to reproduce: --------------------------- 1. Install `sale_planning` with demo data. 2. Create a SO with a planning product, set the quantity to 100 hours, and confirm the SO. 3. Click the "To…
Steps to reproduce: --------------------------- 1. Install `sale_planning` with demo data. 2. Create a SO with a planning product, set the quantity to 100 hours, and confirm the SO. 3. Click the "To Plan" button, then click "Auto Plan". 4. Make sure the "Month" filter is selected in the scale options and observe the planned slots. Issue: -------- When auto planning slots for a month, the last day of the month is excluded. For example, slots are scheduled only until July 30th, even though July 31st is a working day. Cause: -------- While preparing the context, `stopDate` is set to July 31st at 00:00. It is then passed to [serializeDateTime()](https://github.com/odoo/odoo/blob/dacaad91bba8f959daf5d89a046c5a1c11e48eec/addons/web/static/src/core/l10n/dates.js#L553-L560), which converts the datetime to UTC. Depending on the user's timezone, this can shift the date to the previous day, causing the last day of the month to be excluded. Solution: ------------ Use `localEndOf()` to set `stopDate` to the local end of the selected range before passing it to `serializeDateTime()`. This ensures the last day of the month is preserved during UTC conversion. **NOTE:** Forward-port the solution from the 18.0 version, which was adapted to the publish shift use case in 18.3 and introduced this issue. Add a HOOT test case to prevent this regression in future versions. References: [18](https://github.com/odoo/enterprise/commit/bc3db24f83473d5646f7c2cfca8ed1c5b064ea2e) and [saas-18.3](https://github.com/odoo/enterprise/commit/c81fba31780869940f726b695ad46a87f69798fb) opw-6391495 Forward-Port-Of: odoo/enterprise#128501 Forward-Port-Of: odoo/enterprise#127950
This change prevents Australian reporting from failing when related reporting modules are installed in an unusual combination. It keeps specialized report logic together with the module that provides it, improving reliability for affected Australian accounting setups.
Original PR description
We had a case where l10n_au and account_reports were installed together, but not l10n_au_reports (manually uninstalled ?). Since the custom engine was used on expressions in l10n_au, this failed. Custom engines should always be used and declared within the same module (or a submodule of the one defining the handler) to avoid such issues. opw-6451274
This fix ensures users can create shortcuts for documents that are shared with a group. It also makes ownership access tracking more reliable when group-based document access is created, reducing access-related errors and confusion.
Original PR description
Reproduce: try creating a shortcut for a document shared with a group. \+ increase robustness of logging owner access when creating a documents with an access command regarding a group. Task-6344800
Belgian payroll now prorates fixed monthly salaries using the employee's expected working hours for the full payslip period, rather than a single weekly schedule value. This prevents incorrect salary deductions and ensures employees are paid correctly when they worked more or less than half of the period.
Original PR description
### Problem - Fixed salary payslips were not being prorated correctly. The 50% rule threshold was compared against `hours_per_week` (single week) instead of 50% of the theoretical hours for the…
### Problem
- Fixed salary payslips were not being prorated correctly. The 50% rule threshold was compared against
`hours_per_week` (single week) instead of 50% of the theoretical hours for the payslip period.
This led to incorrect salary deductions in all cases and the wrong computation path being taken when less than
50% of the month was worked.
### Solution
- Fix `_l10n_be_has_enough_paid_hours` to compare paid hours against
50% of theoretical hours instead of `hours_per_week` (which are calculated for the employee's `working schedule`)
### How it works
- For fixed salary (`wage_type = 'monthly'`), the quarterly hourly rule
is applied as follows:
- **Hourly rate** = `fixed_salary × 3 / 13 / theoretical_hours`
- **50% rule**:
- If more than 50% of theoretical hours were worked → deduct absences
from fixed wage
- If less than 50% of theoretical hours were worked → pay only the
hours worked
For variable salary (`wage_type = 'hourly'`), the employee is simply
paid for the number of hours worked during the period.
Task-6260378
Forward-Port-Of: odoo/enterprise#126600Fixed an issue that prevented PDF generation for Colombian electronic vendor bills after the reception and acceptance flow. Businesses using Colombian localization can now print these invoice PDFs without encountering a server error.
Original PR description
**Steps to reproduce:** * Install the **l10n_co_dian** module. * Go to **Settings** and, under **Colombian Electronic Invoicing**: * Disable **Testing Mode**. * Enable **DIAN Demo**. * Create a…
**Steps to reproduce:**
* Install the **l10n_co_dian** module.
* Go to **Settings** and, under **Colombian Electronic Invoicing**:
* Disable **Testing Mode**.
* Enable **DIAN Demo**.
* Create a vendor bill with a tax and confirm it.
* Click **Acknowledge Reception**.
* Click **Receive Goods**.
* Click **Accept**.
* From the gear menu, click **Print → Invoice PDF**.
**Observed behavior:**
* A server error is raised:
```
lxml.etree.XMLSyntaxError: Start tag expected, '<' not found, line 1, column 1
```
* The PDF cannot be generated.
**Cause (two-step):**
1. **ZIP not unwrapped:** The original code called `etree.fromstring(self.l10n_co_dian_attachment_id.raw)` directly for all move types. For vendor bills (`in_invoice`) the attachment is stored as a ZIP file, so `raw` is compressed binary data — not XML. Passing it to `etree.fromstring` directly produces the `XMLSyntaxError` above.
2. **AttachedDocument wrapper not unwrapped:** Once the ZIP is correctly decompressed with `xml_utils._unzip`, the resulting XML is an `AttachedDocument` wrapper, not a plain `Invoice`. The actual invoice XML is embedded as CDATA inside `cac:Attachment/cac:ExternalReference/cbc:Description`. `_get_qr_code_value` expects the inner document and searches for nodes like `cac:AccountingSupplierParty`, `cac:LegalMonetaryTotal`, and `sts:QRCode` — none of which exist on the outer wrapper, so the QR code was blank or the method crashed.
**Fix:**
* In `_l10n_co_dian_get_invoice_report_qr_code_value`, for vendor bills (`in_invoice`/`in_refund` without support document), unzip the attachment and immediately attempt to extract the inner invoice XML from `cbc:Description` using `findtext('.//{*}Description')` (lxml namespace wildcard). If the node is present, parse its text as the actual document; otherwise fall back to the unzipped bytes directly.
**Note:**
* A unit test for the `AttachedDocument` unwrapping path was not added because the test would require a zipped fixture file (the vendor bill attachment is stored as a ZIP) which is not appropriate to commit.
* A regression test was added in `test_accept_by_customer`: after the full commercial event flow the method is called inside a `try/except etree.XMLSyntaxError` block so that any XML parse failure surfaces as a proper test *failure* rather than an unhandled test *error*.
opw-6417422
Forward-Port-Of: odoo/enterprise#126463This fixes the expected labels for two Mexican SAT account groups used in trial balance reporting tests. It helps keep the Mexican reporting validation aligned with the official account naming and prevents related compliance test failures.
Original PR description
Enterprise companion of odoo/odoo#277615 — the forward-port to 19.0 of the `l10n_mx` fix that restores the SAT account group names copied from siblings. The `l10n_mx_reports` trial balance test asserts the full Chart of Accounts XML sent to the SAT with the group names hardcoded in the expected output. Two of them were wrong (copied from sibling groups) and are corrected by the community PR: - SAT group **602** (Gastos de venta): `Cost of sales` → `Selling expenses` (`Cost of sales` is 501.01). - SAT group **614** (Amortización contable): `Accounting depreciation` → `Accounting amortisation` (that name belongs to 613). Without this, `ci/l10n` fails on `TestL10nMXTrialBalanceReport.test_generate_coa_xml` and `...test_generate_coa_xml_with_prefix_7_accounts_having_debit_and_credit_tags`. Same branch name as the odoo PR so the mergebot pairs them. Forward-Port-Of: odoo/enterprise#125207
Splitting a multi-page PDF in Documents now shows the resulting pages in a consistent order. This prevents confusion caused by pages appearing randomly when several files are created at the same time.
Original PR description
steps: - upload a multi-page pdf - split all the pages -> they now show in a random order The issue is that the current documents are sorted by create_date desc, but the split creates all the different documents at the same time so they are sorted in the order they happen to be on the disk. We now add a sort by id to act as a tie-breaker. opw-6176840 Forward-Port-Of: odoo/enterprise#128410 Forward-Port-Of: odoo/enterprise#117255
AI chat windows now display above other chat windows when opened from mobile views. This prevents the AI assistant from being hidden behind existing conversations, making the mobile chat experience more reliable.
Original PR description
AI chats opened on mobile views could appear behind other chats. This was inconsistent with the expected stacking behavior, where newly opened chats should appear on top of existing ones. To reproduce: * Open the chatter of any module. * Open the message composer in fullscreen mode. * Click the AI button. This commit increases the z-index of AI chats on mobile views so they are displayed on top of other chats. task-6412411 Forward-Port-Of: odoo/enterprise#128649 Forward-Port-Of: odoo/enterprise#128346
The LinkedIn social integration now handles cases where LinkedIn returns no account statistics. This prevents refresh operations from failing, improving reliability for users managing LinkedIn accounts in Odoo.
Original PR description
Bug === When the LinkedIn API returns no statistics for the account, the refresh crashes. Task-6425391 Forward-Port-Of: odoo/enterprise#126326
This fix prevents Planning from crashing when users drag unscheduled slots onto the calendar after enabling scheduling options. It restores the expected scheduling information and handles missing dates safely, so planners can continue assigning work without interruption.
Original PR description
Steps to reproduce: ------------------------- 1. Install `sale_planning` and `web_studio` with demo data. 2. Open the Planning calendar view. 3. Enable the "Scheduling" option from Studio and close…
Steps to reproduce:
-------------------------
1. Install `sale_planning` and `web_studio` with demo data.
2. Open the Planning calendar view.
3. Enable the "Scheduling" option from Studio and close it.
4. Drag an unscheduled slot onto the calendar.
Issues:
-----------
**Issue 1:**
```python
File "/home/odoo/odoo/enterprise/sale_planning/models/planning_slot.py", line 142, in write
self.assign_slot(vals)
File "/home/odoo/odoo/enterprise/sale_planning/models/planning_slot.py", line 159, in assign_slot
new_vals, tmp_sale_order_slots_to_plan, resource = slot._get_sale_order_slots_to_plan(vals, slot_vals_list_per_employee)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo/enterprise/sale_planning/models/planning_slot.py", line 228, in _get_sale_order_slots_to_plan
)._get_resource_work_info(vals, slot_vals_list_per_resource)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo/enterprise/sale_planning/models/planning_slot.py", line 366, in _get_resource_work_info
assert self.env.context.get('default_end_datetime')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError
```
**Issue 2:**
```python
UncaughtPromiseError > TypeError
Uncaught Promise > Cannot read properties of undefined (reading 'endOf')
TypeError: Cannot read properties of undefined (reading 'endOf')
```
Cause:
----------
Since commit [1ce0dc8,](https://github.com/odoo/odoo/commit/1ce0dc86f8ae52b21a5a889aacd1efce0e27c722) the scheduling/unscheduling logic has been moved to the generic calendar implementation. However, the generic scheduling flow does not provide the `default_end_datetime` context required by sale_planning. As a result, sale_planning raises an `AssertionError` while scheduling a slot.
Additionally, when no date is available, attempting to call `endOf()` raises a `TypeError`.
Solution:
------------
Introduce a generic scheduling context hook in the calendar model and override it in Planning to provide the `default_end_datetime context when scheduling a slot.
This restores the context expected by` sale_planning`, prevents the `AssertionError`, and avoids calling `endOf()` on an undefined date to resolve `TypeError`.
**Note:**
This issue has already been resolved in the later versions (saas-19.4) as part of the scheduling/unscheduling refactoring. This commit backports the minimal changes required to fix the issue in this version.
References: f82d073 & https://github.com/odoo-dev/odoo/commit/f0f7b342895734d2151c0c106940006e37a5fd86
Related community pr: https://github.com/odoo/odoo/pull/281178
opw-6442889
Forward-Port-Of: odoo/enterprise#127196Projects linked to both standard sales orders and rental orders now show the complete list when users open the Sales button. This keeps the list aligned with the displayed total, preventing rental revenue documents from being overlooked.
Original PR description
Steps to Reproduce --- 1. Install sale_renting_project. 2. Create a Project linked to 1 standard Sales Order and 1 Rental Order. 3. Observe the "Sales" stat button counts 2 Sales. 4. Click the stat button. Only the standard Sales Order is displayed. Issue --- In saas-18.4, the project Sales stat button calls action_view_sos without the from_embedded_action context key. As a result, _get_sale_orders_domain applies the non-rental filter by default, causing rental orders to be excluded from the action even though they are included in the displayed counter. Expected Behavior --- The Sales stat button should display all orders linked to the project, including both standard and rental orders, matching its total counter. Fix --- Return the base project domain unmodified when from_embedded_action is not set in the context. task-6140201 Forward-Port-Of: odoo/enterprise#128468 Forward-Port-Of: odoo/enterprise#121449
This update records the signed contributor license agreement for GitHub user kshitij-nariya. It ensures their future contributions can be accepted and merged under Odoo's contribution rules.
Original PR description
Description of the issue/feature this PR addresses: Signed the Odoo Individual Contributor License Agreement to contribute to the Odoo repository. Current behaviour before PR: The CLA signature is missing for GitHub user `kshitij-nariya`, which will prevent future contributions from being accepted and merged. Desired behaviour after PR is merged: The CLA signature for `kshitij-nariya` is recorded in the repository, allowing future pull requests and contributions to be successfully merged. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282808
Manually merged Weblate translations to fix a merge conflict.
Original PR description
Manually merged Weblate translations to fix a merge conflict.