Monday, August 24, 2026
56 changes · master
New functionality added to Odoo
Belgian payroll now supports the NSSO deduction for subsidized contract workers and includes it in DMFA reporting. This helps employers calculate the monthly deduction and report the totals per employee more accurately in the payroll declaration.
Original PR description
Implements the NSSO subsidized contract workers deduction (ACS) and DMFA reporting - New salary rule for montly deduction computation. - New method `_is_eligible_for_acs_deduction` on `hr.version` to check eligibility. - Moving mu and deduction 3000 computation to `L10n_BeDmfa` class methods. - New model `l10n_be.dmfa.acs.reduction.line` storing total deduction per employee per dmfa. - Dedicated tab on DMFA form view. - Deduction computation and display on DMFA report using target group deduction. Task:6173205
Enhancements to existing features
In editable lists configured to add new rows at the top, the “Add a line” button now appears at the top as well. This makes it clearer where new entries will be inserted and improves consistency across related sales, stock, project, and general list views.
Original PR description
Previously, when using editable="top", clicking "Add a line" created the new record at the top, but the "Add a line" button is at the bottom of the list, making the UI inconsistent. After this change, the "Add a line" button is positioned at the top of the list, and new records are inserted directly below it. This makes it clearer where new lines will be created and provides a more intuitive editing experience. task-6234437 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Resolved issues and error corrections
This fix prevents the timesheet assistant from accidentally changing event data and resolves errors that could appear when removing or viewing certain timesheets. Users should experience fewer interruptions and more dependable timesheet handling.
Original PR description
## [FIX] timesheet_grid: avoid altering consumedEvents Before this commit, the objects inside consumedEvents attribute are altered because we keep the reference of those objects. This commit avoid altering the consumed events. ## [FIX] timesheet_grid: use recordsByStart instead of records Forward-Port-Of: odoo/enterprise#128036 Forward-Port-Of: odoo/enterprise#127698
This change lets Odoo population scenarios combine several reusable data blueprints instead of copying the same setup repeatedly. It makes demo, benchmark, and test data easier to maintain across areas like accounting, sales, stock, products, and projects while reducing inconsistencies when shared datasets change.
Original PR description
Population scenarios often reuse independent datasets, such as a product catalog, partners, or warehouses. Blueprint inheritance can extend one definition, but it cannot combine several definitions into a new scenario. This currently requires copying operations between blueprints, making them harder to maintain and reuse. Add an `<import>` element that expands another XML blueprint in place. Imports can be customized through XPath specifications and namespaced to avoid ID conflicts, including when the same blueprint is imported more than once. task-6314573 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Grouped list counts are moved back next to the group name after earlier design experiments proved less suitable. This restores a more familiar layout while keeping subtle visual improvements to group header spacing and background color.
Original PR description
After some experiments with the position and design of the grouped list Count, it has been decided to revert its position, ie: next to the group name. The previous redesigns (#235250 #255332 #266360) were reverted. Only some changes on the group header height and bg color were added back from #235250. task-6452702 part-of: task-5221260
Sales teams can now configure products directly inside quotation templates, including attribute choices, custom values, and optional extras. This makes reusable quote templates more accurate and reduces manual rework when creating customer quotations.
Original PR description
Before this commit: Quotation template lines only stored a product variant (product_id), with no support for no-variant attributes, custom attribute values, or the product configurator dialog. After this commit: Quotation template lines can now use the product configurator, just like regular sale order lines like pick attribute values, custom values, and extra options directly when adding a product to a template. - Prices are hidden in the configurator for templates, including for optional lines. - Matrix/grid-configured products open the regular configurator dialog on templates. - Attribute selections carry over in both directions from a template into a new quotation, and from a quotation line back into a template. - Template description translations stay in sync across languages. task-6128596
This update refreshes U.S. payroll tax settings for Kentucky, Utah, and Kansas so payroll calculations align with corrected 2026 state requirements. It updates unemployment wage caps, Utah withholding table values, and Kansas allowance handling to help ensure more accurate employee pay and tax withholding.
Original PR description
Purpose: Some values and data need to be updated as a follow-up to this PR: https://github.com/odoo/enterprise/pull/125937. Kentucky: - 2026 SUI cap = 12,000 Utah: - 2026 SUI cap = 50,700 - Allowance and threshold tables values for single are corrected to be 2 and 36 respectively. Kansas: - Income tax formula for Kansas already includes the filer and/or spouse in the allowances. Correct the formula to only apply the allowance to the dependents. task-6467500
Users can again access document folder actions from menus, making it easier to share or export live folder views into spreadsheets and knowledge articles. The update also improves linked and embedded folder sharing while protecting access tokens from being exposed through Knowledge search state.
Original PR description
Also impacted: test_documents_full It is convenient to export a dynamic view of a folder in both spreadsheet and knowledge links settings. * Care is taken to avoid leaking access folders tokens through the search panel/model's state in knowledge. * We also enable sharing folders shared via link through embedded views as it enables benefitting from the power of them vs. adding the link to the folder in the article. * As with other actions initiated on shortcuts, the "real" operation is done on the target. Sharing the target is simpler than patching a folder "child_of" to return the target children (shortcut as documents_unique_folder_id is not supported). Task-5180137 Forward-Port-Of: odoo/enterprise#128882 Forward-Port-Of: odoo/enterprise#122481
Website editors can now place content in dedicated areas on product pages, choosing whether it appears on every product page or only on the current one. Terms and conditions content is moved into the new editing area automatically, and empty placeholder lines are cleaned up to prevent unwanted spacing.
Original PR description
This commit adds different drop zones on the product page. We introduce zones where elements dropped inside will be displayed across all product pages, as well as zones where elements dropped inside will only be visible on the current product page. We also remove the terms and conditions option from the edit settings, and thanks to the upgrade script, we move them to the new dropzone if the option was enabled. If a page with the `o_drop_inner_empty` class is saved and contains an empty `<p>` tag, we remove it to avoid unwanted whitespace. Currently, a hint is displayed, but there is no way to delete the empty line. Upgrade PR: https://github.com/odoo/upgrade/pull/10116 task-6147939
Activity assignment emails are now grouped so a user receives one message per record instead of separate emails for every activity. This reduces inbox clutter and mail server load, while also ensuring scheduled activities use a valid compatible activity type.
Original PR description
Previously, when a plan scheduled multiple activities assigned to a user, the system sent a separate email notification for each individual activity. This resulted in excessive email spam for the…
Previously, when a plan scheduled multiple activities assigned to a user, the system sent a separate email notification for each individual activity. This resulted in excessive email spam for the assignee and unnecessarily increased mail server costs.
This commit improves the mail notification flow by grouping activities by user and record before dispatching. Instead of sending one email per activity, it now sends a single consolidated email per user per record, listing all assigned activities with their summaries and deadlines.
[IMP] {test_}mail: ensure activity type consistency by falling back to default type
Although unrelated to this PR, the TODO regarding activity type model consistency has been resolved by always resetting to a default compatible type when the activity type is not consistent (not present or not compatible).
We also remove the invalid activity type from the activity values if present, to prevent the incompatible type from being restored.
Task-6255045The website configurator no longer uses a moving background that could slow down some devices. Keeping the background fixed helps the page feel more responsive and improves the setup experience for users.
Original PR description
Background animation in the configurator caused performance issues on some devices and could make the page feel laggy. This commit removes the animation and keeps the background fixed. task-6497101 <img width="1911" height="921" alt="image" src="https://github.com/user-attachments/assets/951bf4db-6c22-440d-8148-6626ebda3fdf" /> --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Users can now find relevant ADEME emission factors more easily by filtering by location and seeing more recent factors first. The update also improves how dates, locations, units, and currencies from the ADEME database are interpreted, reducing irrelevant or confusing results.
Original PR description
Purpose: Today, it is complex for the user to find the relevant emission factors to use. For instance, when searching for "electricity", 406 records are found, many of which have the same name but…
Purpose: Today, it is complex for the user to find the relevant emission factors to use. For instance, when searching for "electricity", 406 records are found, many of which have the same name but different emission values. To improve the user experience, we should be able to filter by country and have the most recent factors shown first in the list view. In this commit, we add some flexibility on the validity dates given by the ADEME database. For instance, the following format dates are now parsed correctly: - 2026 - déc-18 - 31-mars-21 - Année 2008 Additionally, the location and sub-location are now taken into account (for the ADEME database) and stored in new fields (country_ids, state_ids). Some parsing and mapping were required to map those locations/sub-locations to existing records in the DB (a new CSV data file was added for this purpose). We also added a new filter to filter on factors that are relevant compared to the user's location (it compares the user's company's country to the ones of the factors). We also handle more units of measure and currencies, and we ignore some unknown units that are not relevant for the user. task-6109010
Financial reports now avoid unnecessary database work when preparing ledger queries. This reduces server resource usage significantly on large databases and should make affected reports load faster without changing report results.
Original PR description
Prior to this commit, the financial engine's query generation included redundant joins to `account_move` (INNER JOIN) and `res_partner` (LEFT JOIN). Neither table is utilized in the SELECT, WHERE,…
Prior to this commit, the financial engine's query generation included redundant joins to `account_move` (INNER JOIN) and `res_partner` (LEFT JOIN). Neither table is utilized in the SELECT, WHERE, GROUP BY, or ORDER BY clauses of these financial reports. These joins have been removed based on the following justifications: 1. account_move (INNER JOIN): Because `move_id` is a NOT NULL foreign key constraint on the line table, orphan lines cannot exist and the join acts as a no-op. Furthermore, the filter on entry state utilizes `parent_state` which is already denormalized on `account_move_line`. Removing this INNER JOIN allows the planner to avoid a massive, resource-heavy Nested Loop over the parent table's primary key index. 2. res_partner (LEFT JOIN): While PostgreSQL's optimizer was already utilizing "Left Join Elimination" to strip this out of the execution plan at runtime, removing it from the query builder cleans up the codebase and prevents unnecessary overhead in the query construction phase. Benchmarks on large database shows a large performance optimization: - Shared Hit Blocks: ~940,000 -> ~51,800 (a ~94.5% memory page reduction) Before Plan: https://explain.dalibo.com/plan/e3e2193968bf2a18 After Plan: https://explain.dalibo.com/plan/1dgdh22f68d89aca
Odoo can now receive payment status updates from the Odoo Fin proxy through a webhook. This helps keep online payment records and batch payments more current while avoiding duplicate refresh jobs.
Original PR description
This commit adds a webhook to allow Odoo Fin proxy to communicate with the Odoo database that a payment status has been updated. Once the call received, the code is making sure first that we have an associated client_id and at least a payment or a batchpayment with the payment identifier. This is also make sure that the cron is not already triggered to avoid multiple calls as the cron will fetch the status for all payments and batches. task-6377052
Leave types that deduct extra hours can now let employees take time off even when their extra-hours balance is not yet sufficient. This gives businesses more flexibility to manage time off policies while still tracking the resulting negative overtime balance.
Original PR description
When "Deduct Extra Hours" is checked on a leave type, add a new "Allow Negative?" checkbox that allows employees to take time off even if they don't have enough extra hours accumulated yet. task-5017245
Repeated copies of the same attachment, such as email signature images, are now grouped into one preview in the chatter attachment box. Users can expand the group to view, download, or remove individual copies, making important files easier to find while preserving access to every attachment.
Original PR description
Signature images ride along with every mail, so the same picture ends up attached to a record over and over. The attachment box lists every one of them, burying the files users actually came for.…
Signature images ride along with every mail, so the same picture ends up attached to a record over and over. The attachment box lists every one of them, burying the files users actually came for. This is a recurring complaint from the support team. Attachments holding the same content are now shown as a single preview carrying a counter on its bottom end corner. Clicking the counter unfolds the copies, each with its date, so that any of them can still be downloaded or removed on its own. Removing the preview itself removes the whole group, as that is what it stands for. Copies are matched on their checksum, and only grouped in the chatter attachment box: on a message the attachments are part of what the author wrote, so hiding some of them would drop information. task-6428149 https://github.com/odoo/enterprise/pull/126070 <img width="643" height="614" alt="image" src="https://github.com/user-attachments/assets/bb44d1bd-952e-409e-ae91-029ce88c87bb" /> --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Binary files can now carry their filename directly, making attachment names easier to preserve and reducing the need for separate filename fields. File previews and reads avoid sending unnecessary encoded content, which can improve performance and browser caching across affected apps.
Original PR description
Add `filename` to `BinaryValue`. We can now write a dict {file_name, content} on binary fields. For attachments, the file name is stored in ir.attachment.name.
We remove the need to have "bin_size" context value and don't transfer base64-encoded data for `web_read`.
odoo/enterprise#118187
odoo/documentation#18337
task-6303991
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThe Point of Sale product configuration window now shows product reference codes again, helping staff identify the right item more easily. Searching by a variant reference now opens the matching product variant, reducing selection mistakes during checkout.
Original PR description
We reintroduce the default code on the product configuration modal, and ensure that searching for a variant reference opens the right variant. task-6463377 Forward-Port-Of: odoo/odoo#283846 Forward-Port-Of: odoo/odoo#282707
Belgian payroll reporting now supports the Employee Participation declaration alongside the existing 273S flow. This gives payroll teams a more complete 273.XX reporting process for meeting Belgian compliance requirements.
Original PR description
Task: 6361345
Duplicate attachments, such as repeated email signature images, are now grouped into one preview in the chatter attachment box. Users can expand the group to view, download, or remove individual copies, making important files easier to find while preserving access to every attachment.
Original PR description
Signature images ride along with every mail, so the same picture ends up attached to a record over and over. The attachment box lists every one of them, burying the files users actually came for. This is a recurring complaint from the support team. Attachments holding the same content are now shown as a single preview carrying a counter on its bottom end corner. Clicking the counter unfolds the copies, each with its date, so that any of them can still be downloaded or removed on its own. Removing the preview itself removes the whole group, as that is what it stands for. Copies are matched on their checksum, and only grouped in the chatter attachment box: on a message the attachments are part of what the author wrote, so hiding some of them would drop information. task-6428149
This update modernizes how Odoo handles binary file information, such as file names, checksums, and whether full file data is loaded. It also updates related settings and tests across several apps to keep file handling consistent and reduce unnecessary data loading.
Original PR description
odoo/odoo#266082
Belgian payroll payslips now include more detailed explanations for additional salary rules, making payroll calculations easier to understand. The underlying explanation logic was also simplified, improving maintainability without changing the payroll outcome.
Original PR description
- Add detailed explanations for additional salary rules on the payslip. - Refactor existing explanations to stop using `localdict` for passing values. Pass it directly via functions such as `result` and `rate` Task ID: 6450081
Draft payslips are now recomputed when they overlap with a salary adjustment. This helps payroll teams avoid outdated calculations and reduces the risk of incorrect payments before payslips are finalized.
Original PR description
…ustment task-6479469
Online stores can now set a minimum quantity that shoppers must buy for specific products. Product pages and carts automatically enforce the minimum, including when the same product appears in different units of measure, helping businesses protect pricing, packaging, or fulfillment requirements.
Original PR description
Add support for a minimum quantity on eCommerce products. The product page now initializes the quantity to the configured minimum and prevents decreasing below it. The cart also blocks quantity reductions that would violate the constraint. The minimum quantity is computed across all instances of the same product in the cart, including different UoMs converted to the product's base UoM. Changing the UoM automatically adjusts the quantity if needed. Removing one UoM while another remains in the cart increases the remaining quantity to preserve the constraint. Enterprise: https://github.com/odoo/enterprise/pull/122657 task-6354127
Manufacturing orders now handle expected work order durations more accurately for full production runs. The update also prevents production quantities from being changed too early and makes it easier to recover cancelled backorder steps, reducing disruption on the shop floor.
Original PR description
Some more improvements to refine the production process: - Allow computation of workorders' expected duration for a full production. - Remove writing into `qty_produced` while setting workorders states, unless its being marked as done. Task: 6421044 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278809
Rental products can now require a minimum total rental amount before customers can add them to the cart. This helps businesses enforce rental sales rules consistently by checking rental duration and quantity together, and by preventing cart changes that would fall below the required minimum.
Original PR description
Extend the minimum quantity feature to rental products. The constraint is based on `periodicity × quantity ≥ minimum quantity`. The product page disables Add to Cart until the constraint is satisfied, while taking existing cart lines into account. The cart prevents quantity reductions and date changes that would break the constraint. As for regular products, the minimum is evaluated across all cart lines and remaining quantities are automatically adjusted when needed after removing a line. Community: https://github.com/odoo/odoo/pull/273732 task-6354127
Frontdesk now checks that email, SMS, and WhatsApp notification templates are properly set before those alerts can be enabled. It also prevents templates in active use from being deleted, reducing missed visitor notifications and setup mistakes.
Original PR description
Improve the validation of Frontdesk host notification templates: - Ensure Email, SMS, and WhatsApp notification templates are configured whenever their corresponding notification is enabled. - Prevent deletion of notification templates that are currently used by Frontdesk stations. Fix: - Update the `mail_template_id` domain to use `frontdesk.visitor` instead of `frontdesk.frontdesk`, since the email template is related to the visitor model. TaskId-6416010
Belgian payroll now helps ensure eligible employees receive a prorated 13th month payment when they leave the company. A dedicated employee-page action appears only when the employee qualifies, reducing manual work and improving payroll accuracy around departures.
Original PR description
When a Belgian employee leaves the company (fired or resigned) and has worked long enough (6 months for fired employee and 3 years for resigned employee), they are owed a partial 13th month payment. This commit adds a "13th Month" button on the employee's page, which only shows up when the employee actually qualifies, and creates a payslip with the correct partial amount for the months they worked. Also fixes a case where that amount could come out wrong if the payslip was generated before the departure date was officially confirmed. task-6439087
Payroll run cards now adapt better across desktop, narrow layouts, and phones, keeping key actions easier to access and preventing crowded content from overflowing. Metrics and step actions have been simplified so users can scan payroll runs more clearly and act faster.
Original PR description
The pay run card laid its name, kpis, steps and action buttons out on a single row. Below the xl breakpoint the buttons collapsed into the overflow menu, and on narrower screens the kpis and the…
The pay run card laid its name, kpis, steps and action buttons out on a single row. Below the xl breakpoint the buttons collapsed into the overflow menu, and on narrower screens the kpis and the steps were squeezed until they spilled out of the card. Keep the action buttons rendered inline at every size: only the remaining actions, the deletion and the smart buttons stay in the ellipsis menu. Fold the kpis and the steps away once the card can no longer hold everything on one row. A chevron at the bottom of the card unfolds them into a row of their own, kpis on the left and steps on the right, and the fold is driven by a container query so a card narrowed by the open chatter behaves like a narrow screen. Only the standalone card above a payslip list folds; the pay runs kanban lists many cards at once and keeps them inline. On phones the kpis are dropped altogether, the steps stay on show, and the action buttons and the overflow menu dock to a bar at the bottom of the screen. Restyle the metrics: drop the icons, mute the labels and enlarge the amounts, keeping the currency symbol and the whole units at full size with the decimals small and muted. A field renders an amount as a single string, so a payrun_kpi widget splits it; the Belgian and Saudi metrics reuse the same markup and follow. Show only the step's own action inline. `is_priority` raises the inline budget from one button to two rather than marking a button prominent, and "Add Employees" was the only flagged button in the version, time, attendance and payslip steps, so it was buying the second slot that Continue and Validate sat in. Drop its flag and anchor the inherited buttons on it rather than on the deletion, leaving each step's own action first and "Add Employees" in the ellipsis menu. Keep the pay run name's underline hidden until the card is hovered, so the card reads as a title rather than as a form. task-6361830
Clicking a chatter notification now opens the related record form immediately instead of first opening a chat window. This reduces extra steps for users and helps them get to the relevant business information faster.
Original PR description
Before this commit: Clicking on a chatter notification in the systray would open the chat window, requiring users to click Open Form View to access the related record. After this commit: Clicking on a chatter notification now opens the corresponding form view directly, reducing the number of clicks and enhancing user efficiency. task-4681025 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Turkish payroll rules have been updated with the 2026 payroll parameters, including clearer naming for the minimum net wage and configurable SSI contribution settings. This helps payroll teams calculate employee contributions more accurately within the current legal framework.
Original PR description
- Update the Turkish payroll rule parameters for 2026. - Rename the minimum wage parameter to 'Turkiye Minimum Net Wage'. - Add configurable parameters for the SSI minimum contribution base and employee contribution rate. - Update the SSI contribution computation to account for both the minimum and maximum contribution bases. **task-6397284** Forward-Port-Of: odoo/enterprise#128658 Forward-Port-Of: odoo/enterprise#125985
This update refines several VoIP screens and messages to make call-related workflows clearer for users. It replaces a log wizard label with an icon, renames the main outgoing number setting to a more understandable term, and improves the wording of tracking emails.
Original PR description
see commit titles task-6487015
Loading indicators now appear without shifting button content or making the page feel jumpy. This improves visual stability and polish when users click actions that need time to complete.
Original PR description
The helper function `addLoadingEffect` disables the button and adds an inline font-awesome icon as a spinner. This can cause elements to shift on the page. Additionnally, the font-awesome icon has a…
The helper function `addLoadingEffect` disables the button and adds an inline font-awesome icon as a spinner. This can cause elements to shift on the page. Additionnally, the font-awesome icon has a very light imbalance that makes it wiggle instead of staying centered. Instead, we want to leave the layout as unaltered as possible while keeping the loading behavior. | Snippet | Before | After | | --- | --- | --- | | Button | <img width="174" height="74" alt="image" src="https://github.com/user-attachments/assets/b88dd91c-4d49-485e-8d10-b1a9afe37901" /> | <img width="168" height="131" alt="image" src="https://github.com/user-attachments/assets/88261d9b-19d2-42bf-8a2f-ea57c55954db" /> | | Accordion | <img width="633" height="89" alt="image" src="https://github.com/user-attachments/assets/9eeaf7d4-1933-4322-9e70-1d3c93ffa7d3" /> | <img width="650" height="134" alt="image" src="https://github.com/user-attachments/assets/2ee590cb-7b63-4d6c-bbae-472616530921" /> | | Carousel indicator | <img width="228" height="87" alt="image" src="https://github.com/user-attachments/assets/39fd0685-0517-456a-a1fd-6914f9ee4dbc" /> | <img width="194" height="99" alt="image" src="https://github.com/user-attachments/assets/2eaf1da3-d6eb-4ce3-8088-188c03508e92" /> | task-5221179
India withholding reports now use the shared withholding framework instead of older country-specific rules. This keeps reporting aligned with the latest accounting logic and reduces inconsistencies after the India-specific implementation was removed.
Original PR description
Update report domains to align with the generic withholding framework after removing the India-specific withholding implementation. com:https://github.com/odoo/odoo/pull/273075 upg:https://github.com/odoo/upgrade/pull/10681 task-6324221
The spreadsheet component has been updated to a newer version, bringing general improvements to the spreadsheet experience in Odoo. This helps keep spreadsheet features current and supports better reliability for users working with spreadsheet-based data.
Original PR description
Task: [6219600](https://www.odoo.com/odoo/project/2328/tasks/6219600) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Timesheet suggestions now handle away-from-keyboard periods more reliably, so breaks and inactive time are less likely to be missed or overwritten. This helps employees and managers get a more accurate view of working time when using ActivityWatch-based timesheet assistance.
Original PR description
## Previous Behavior Before this Commit 1. When key and non‑key events were merged to build the final suggestion timeline, key events always took priority over AFK events, even when the key event was…
## Previous Behavior Before this Commit 1. When key and non‑key events were merged to build the final suggestion timeline, key events always took priority over AFK events, even when the key event was not “always active.” This caused AFK events to be incorrectly overridden. 2. During event normalization, certain events were lost entirely, resulting in important events not being counted. 3. When merging two event timelines, zero‑duration gaps were treated as valid, preventing proper merging of surrounding events. 4. ActivityWatch sometimes produced empty gaps instead of AFK events, causing breaks to go unrecorded. ## New Expected Behavior After this Commit 1. Events now follow the updated priority system: a. Always‑active key events b. Always‑active non‑key events c. Non‑key AFK events d. Other key events e. Other non‑key events 2. Events are now shortened or split so that the latest event always has priority, while minimizing unnecessary event removal. 3. Zero‑duration gaps are skipped when merging event lists. 4. Any gap larger than 3 minutes, between the first and last event and containing no events is automatically filled with an AFK event. ## Additional Notes Because point 4 introduces additional AFK events, several tests were updated to reflect the new behavior. task-[6455412](https://www.odoo.com/odoo/project/4105/tasks/6455412) Forward-Port-Of: odoo/enterprise#128039 Forward-Port-Of: odoo/enterprise#127811
Inventory move lines now keep the transfer's original scheduled date after validation instead of switching to the processing date. This makes Moves History filtering, grouping, and sorting by Scheduled Date match the date shown on the transfer, improving reporting accuracy.
Original PR description
### Problem `stock.move.line.scheduled_date` is related to `move_id.date`, and `stock.move.date` only holds the scheduled date **until the move is done** — at validation it is overwritten with the…
### Problem `stock.move.line.scheduled_date` is related to `move_id.date`, and `stock.move.date` only holds the scheduled date **until the move is done** — at validation it is overwritten with the processing date, as its own help states. So on a done move line the field returns the effective date under a "Scheduled Date" label. It shows up in Moves History (Inventory > Reporting), which lists done lines by default: filtering, grouping or sorting by "Scheduled Date" silently uses the effective date, and it contradicts the "Scheduled Date" displayed on the transfer, which does survive the validation (`stock.picking._compute_scheduled_date` ignores done moves). **Steps to reproduce** 1. Create a receipt scheduled tomorrow and validate it today. 2. Inventory > Reporting > Moves History, group by "Scheduled Date". 3. The line falls under today instead of tomorrow, while the transfer form still shows tomorrow. ### Fix Follow `picking_id.scheduled_date`, which keeps the scheduled date once the transfer is done. The field is only displayed in `stock.view_move_line_tree_detailed`, and every action using that view (`stock.action_get_picking_type_operations`, the Prepare Wave actions and the Add to Wave wizard) already restricts the lines to those belonging to a transfer, so no view loses a value it used to show. I hereby agree to the terms of the CLA available at: https://www.odoo.com/cla
Users who manually replenish stock will now see the expected notification when a purchase order is created. This makes the replenishment process clearer and helps teams confirm that their order action was successful without having to search for the purchase 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#283853 Forward-Port-Of: odoo/odoo#271993
Fixes an error that occurred when users clicked the Recorded button on field service interventions. Users can now reliably view the timesheets logged for an intervention without needing an extra project planning integration installed.
Original PR description
**Problem:** Clicking the "Recorded" smart button on a field service intervention raises an AttributeError instead of listing the timesheets logged on it. **Steps to reproduce:** 1. Install the field…
**Problem:** Clicking the "Recorded" smart button on a field service intervention raises an AttributeError instead of listing the timesheets logged on it. **Steps to reproduce:** 1. Install the field service billing feature (Planning > Configuration > Settings > Field Service > "Invoice your time and materials to your customers") without installing Project's planning integration 2. Set the project in Planning > Configuration > Settings > Field Service 3. Create an intervention and assign a resource to it 4. Click the "Recorded" smart button **Current behavior:** 'super' object has no attribute 'action_open_timesheets' **Expected behavior:** The timesheets logged on the intervention are listed. **Cause of the issue:** `action_open_timesheets` on `planning.slot` is defined in two modules only: `project_timesheet_forecast` provides the base implementation, and `planning_field_service_sale_timesheet` extends it through `super()`. Since `59a04091c403` dropped `project_timesheet_forecast_sale` from the dependencies of `planning_field_service_sale_timesheet`, nothing guarantees the base implementation is part of the model's inheritance chain anymore: `project_timesheet_forecast` is auto installed only together with `project_forecast`, which no module of the field service stack depends on. The smart button is rendered by `planning_field_service_sale_timesheet` itself, so it stays visible in such an installation while the `super()` call has nothing to resolve to. **Fix:** That same commit already made the field service module self-sufficient for `_get_timesheetable_project`, `_compute_allow_timesheets` and `_compute_allow_billable`, leaving the project forecast flavour to the `project_timesheet_forecast_field_service_sale` bridge, and `action_open_timesheets` is the only method that was left relying on the other stack. Building the action from the module's own hooks preserves that separation, whereas depending on `project_timesheet_forecast` again would pull Project back into every field service installation, which is precisely what that commit set out to avoid. opw-6391972 Forward-Port-Of: odoo/enterprise#126489
Odoo now correctly detects when an internal stock transfer leaves a replenished source location short of stock. This ensures the Replenishment report creates the needed reordering suggestion, helping businesses avoid missed restocking actions after moving inventory between internal locations.
Original PR description
Steps to reproduce: ------------------- 1. Install `stock` module. 1. Enable the "Storage Locations" from setting. 2. Create an internal location and enable `replenish_location` on it and set…
Steps to reproduce:
-------------------
1. Install `stock` module.
1. Enable the "Storage Locations" from setting.
2. Create an internal location and enable `replenish_location` on it and set warehouse(WH) as Parent.
3. Create a storable product track by quantity with no on-hand quantity.
4. Create an internal transfer from the warehouse stock location to the new internal location.
5. Confirm the transfer.
6. Open the Replenishment report.
Issue:
------
No manual reordering rule is created for the product at the source location, although
the confirmed transfer makes its forecasted quantity negative.
If `replenish_location` is disabled on the destination, the expected reordering rule is created.
Cause:
------
When both the source and destination have `replenish_location=True`, Odoo considers both locations
inside the same replenishment area. Therefore, the internal transfer is not counted as either
incoming or outgoing, and no replenishment is created for the source location.
Code Flow:
Opening the Replenishment report calls
`stock.warehouse.orderpoint.action_open_orderpoints()`, which delegates the report preparation to `_get_orderpoint_action()`:
https://github.com/odoo/odoo/blob/12a66c6931d81e1cce18f676836aca0b32090d16/addons/stock/models/stock_orderpoint.py#L324-L326
`_get_orderpoint_action()` first obtains every location that must be monitored for replenishment through `_get_orderpoint_locations()`:
https://github.com/odoo/odoo/blob/12a66c6931d81e1cce18f676836aca0b32090d16/addons/stock/models/stock_orderpoint.py#L520
`_get_orderpoint_locations()` returns all locations whose `replenish_location` field is enabled:
https://github.com/odoo/odoo/blob/12a66c6931d81e1cce18f676836aca0b32090d16/addons/stock/models/stock_orderpoint.py#L799-L800
All these locations are passed together to
`product.product._get_domain_locations_new()`:
https://github.com/odoo/odoo/blob/12a66c6931d81e1cce18f676836aca0b32090d16/addons/stock/models/product.py#L396-L464
This method treats the provided locations and their descendants as a set. Its move domains are equivalent to:
- incoming: destination is inside the set and source is outside;
- outgoing: source is inside the set and destination is outside.
Consider the following sibling locations:
WH
├── Stock
└── Replenish Location
and the transfer:
Stock -- 3 units --> Replenish Location
When `replenish_location` is disabled on the destination, the considered location set contains only `Stock`:
considered location set = {Stock}
The source is inside the set and the destination is outside:
source inside = True
destination outside = True
The transfer therefore matches the outgoing domain:
source inside AND destination outside
True AND True
= True
It is included in `moves_out`, and the preliminary forecast for `Stock` becomes:
0 on hand + 0 incoming - 3 outgoing = -3
https://github.com/odoo/odoo/blob/12a66c6931d81e1cce18f676836aca0b32090d16/addons/stock/models/stock_orderpoint.py#L552
The negative quantity is detected and a manual orderpoint is created.
When `replenish_location` is enabled on the destination, both sibling locations belong to the considered location set:
considered location set = {Stock, Replenish Location}
Both ends of the transfer are now inside:
source inside = True
destination inside = True
destination outside = False
source outside = False
The transfer matches neither aggregate domain:
incoming:
destination inside AND source outside
True AND False
= False
outgoing:
source inside AND destination outside
True AND False
= False
The transfer is considered internal to the considered location set and is therefore absent from both `moves_in` and `moves_out`:
https://github.com/odoo/odoo/blob/12a66c6931d81e1cce18f676836aca0b32090d16/addons/stock/models/stock_orderpoint.py#L530-L540
This aggregate treatment conflicts with the next step, where `_get_orderpoint_action()` computes the quantity separately for each replenishment location:
https://github.com/odoo/odoo/blob/12a66c6931d81e1cce18f676836aca0b32090d16/addons/stock/models/stock_orderpoint.py#L549-L552
When `Stock` is evaluated separately, the internal transfer has already been discarded. Its calculated outgoing quantity is consequently zero:
0 on hand + 0 incoming - 0 outgoing = 0
As the quantity is not negative, the product is not scheduled for the final `virtual_available` computation and no manual orderpoint is created.
Fix:
----
Also retrieve moves whose source and destination are both inside the aggregate replenishment-location set.
Include these internal moves in both the incoming and outgoing grouped queries. The existing per-location path filtering then assigns each side correctly:
- the source replenishment location counts the move as outgoing;
- the destination replenishment location counts it as incoming.
For the reported transfer, this produces:
Stock:
0 on hand + 0 incoming - 3 outgoing = -3
Replenish Location:
0 on hand + 3 incoming - 0 outgoing = 3
This is correct because the report creates replenishment propositions per location, even though the initial move query is performed for all replenishment locations together.
---
opw-6462608
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#282168The accounting app now correctly blocks fiscal year periods that fully contain an existing fiscal year. This helps prevent duplicate or conflicting accounting periods, reducing the risk of reporting and closing errors.
Original PR description
Before this commit: - The current constraint for overlap check allows if we define a new, larger fiscal year that completely swallows an existing smaller one (e.g., creating Aug 2025 - Nov 2026 when Sept 2025 - Oct 2026 already exists). After this commit: - The constrain domain was changed to consider the above missed case.
Customers can now redeem more than one eligible reward from the same loyalty coupon when they have enough points. This removes an incorrect block that prevented combining rewards such as a discount and a free product, improving checkout flexibility and loyalty campaign value.
Original PR description
Steps to produce: --- - Install the `website_sale_loyalty` module. - Navigate to Discount & Loyalty and create a new coupon program. - Keep the existing `10% Discount reward` and add a second reward…
Steps to produce: --- - Install the `website_sale_loyalty` module. - Navigate to Discount & Loyalty and create a new coupon program. - Keep the existing `10% Discount reward` and add a second reward of type `Free Product`. Select a product for the free product reward. - Generate a coupon and set its balance to `2` coupon points. - Open the website and add a product to the shopping cart. - Apply the generated coupon code. - Attempt to redeem both rewards (the 10% discount and the free product reward) using the same coupon. Issue: --- - When trying to apply the second reward, it shows `This program is already applied to this order.` Root cause: --- - Once a program was applied to the order, subsequent rewards from the same program were blocked, regardless of whether the customer had enough points to claim them. Solution: --- - If a reward from an already-applied program is still claimable (i.e, the customer has sufficient points), allow it to be applied to the order. opw-6247206 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Employees on flexible schedules without a set average daily hour value will now have full-day leave recorded correctly. This prevents leave requests from being saved as zero-duration, improving accuracy in absence tracking and payroll-related records.
Original PR description
…duration leave When a flexible schedule has no average_hour_per_day set (hours_per_day=0), _get_hours_for_date computed [12-0, 12, 12+0] = (12.0, 12.0), producing a zero-duration leave (date_from == date_to). Treat hours_per_day=0 like a fully flexible employee and return (0, 24) so the leave spans the full day. Task-6488608
Belgian payroll now correctly recognizes a full working day when an employee follows a schedule where some days have fewer contracted hours than others. This prevents payslips from incorrectly showing full days as half-day attendances, improving payroll accuracy for affected work schedules.
Original PR description
Bug: - Create a working sched were one day has less working hours than the rest. - when generating a payslip for an employee linked to that working sched , you'll have half-day attendances even…
Bug: - Create a working sched were one day has less working hours than the rest. - when generating a payslip for an employee linked to that working sched , you'll have half-day attendances even though he worked all his days Reason : - in _get_work_hours_split_half , when building work_data, we compare the duration worked by the employee that day not against the contractual amount of that that but instead we use self.resource_calendar_id.hours_per_day or the max hours per day on that working day , so the day with the least contractual hours on that working sched for exemple will fail this condition " float_compare(duration_sum, number_of_hours_full_day, 2) != -1" even if the employee worked that whole day. Fix: - for fixed scheds : we builed hours_per_dayofweek where we store the hours for each day of the week , later on , we check the weekday and retreive the corresponding official working hours on that day. - for variable scheds: because in this case each day can have its own officil working hours , we fetch the official hours of a certain date right before the logic that determines if it's a full or half a day. task - 6377396 Forward-Port-Of: odoo/enterprise#124100
This fixes an issue where AI assistants could attach request details to the wrong part of a resumed conversation. It prevents confusing or blank replies in Discuss and helps both Google Gemini and OpenAI produce responses based on the right user message.
Original PR description
`_append_context_part` puts the context of the current request on the last entry of the history, whatever that entry happens to be. That is the user's message on a normal turn, but a turn resumed from a `user_input_request` carries the answer back as a tool response, so the context landed on that instead: Google then received a turn mixing a `functionResponse` with a text part, which Gemini answers with a lone newline, posted as the agent's reply and shown in Discuss as a removed message. OpenAI appended it to the output of the tool call instead, making the model read the current context as part of what the tool returned. Both providers now walk back to the last message of the user and attach the context there, leaving tool responses untouched. A normal turn is unchanged, that message being the last entry already.
Shopfloor users can now finish the final work order in continuous production after entering produced quantities. The update also corrects displayed produced quantities when assigning serial numbers, reducing confusion and preventing blocked manufacturing steps.
Original PR description
Previously there was a limitation for continuous production in shopfloor, that blocked the user from marking a workorder as done after registering a quantity. This commit fixes it by assigning the production's `quantity_producing` to the work order's `qty_produced` if it is the final work order. This unblocks the user and allows them to complete the work order. Forward-Port-Of: odoo/enterprise#125787
Manufacturing change orders can now be created successfully from incoming emails sent to configured ECO aliases, even when no product is included in the email. This prevents bounced messages and ensures teams can capture change requests through email as intended.
Original PR description
Steps to reproduce --- 1. In Settings > Technical > Email > Alias Domains, create an alias domain (e.g. `example.com`). 2. Open the ECO Types configuration, pick a type (e.g. "BOM Updates"), and set…
Steps to reproduce --- 1. In Settings > Technical > Email > Alias Domains, create an alias domain (e.g. `example.com`). 2. Open the ECO Types configuration, pick a type (e.g. "BOM Updates"), and set its Email Alias to `bom-updates`. 3. Send an email to `bom-updates@example.com` with any subject and body. 4. The gateway fails to open the change order: the sender receives a bounce and no `mrp.eco` appears under that ECO type. Issue --- `product_tmpl_id` on `mrp.eco` is defined with `required=True`: https://github.com/odoo/enterprise/blob/79f9ff2ccea3153c457e286bbbca27794ccfdb57/mrp_plm/models/mrp_eco.py#L261-L266 That constraint was added by ac635694 ([IMP] mrp_plm: ux improvements), which tightened the form UX but did not account for the mail gateway, which opens change orders without a product. A change order can be created from an incoming email: the alias declared on `mrp.eco.type` routes the message to `mrp.eco`, and `_alias_get_creation_values` injects only `type_id` into the creation values: https://github.com/odoo/enterprise/blob/79f9ff2ccea3153c457e286bbbca27794ccfdb57/mrp_plm/models/mrp_eco.py#L55-L61 The gateway then builds the record with `message_new`, called from `_message_route_process`: https://github.com/odoo/odoo/blob/c6ef99510adcb079f34657aa66dcf191928e3355/addons/mail/models/mail_thread.py#L1553-L1575 https://github.com/odoo/odoo/blob/c6ef99510adcb079f34657aa66dcf191928e3355/addons/mail/models/mail_thread.py#L1402-L1413 An email carries no product, so those creation values have no `product_tmpl_id`. `required=True` is enforced only by the database `NOT NULL` constraint, so on any database where that constraint is present the gateway `create` raises and the incoming request is lost. A product is not actually needed until the change order starts its revision, where `product_tmpl_id` is first read to copy the BoM and gather its documents: https://github.com/odoo/enterprise/blob/79f9ff2ccea3153c457e286bbbca27794ccfdb57/mrp_plm/models/mrp_eco.py#L755-L777 opw-6351438
This fixes how Indian localization classifies purchase entries for imported goods and services, especially credit and debit notes. It helps keep GST reporting aligned with the correct treatment for reverse charge services and moves invalid import-without-RCM cases out of scope.
Original PR description
Previously:
1.`purchase_cdnur_regular` section was assigned to credit/debit notes of:
- import of goods
- import of services without RCM However:
- import of goods should be handled through bill of supply
- import of services without RCM is not possible Therefore, with this commit, such journal items are moved to `purchase_out_of_scope`.
2.`purchase_imp_services` section included import of services both with and
without RCM. Since import of services without RCM is not possible, those
journal items are now moved to `purchase_out_of_scope`.
3.Credit/debit notes of import of services with RCM were previously moved to
`purchase_out_of_scope`, which was incorrect. With this commit, they are now
correctly moved to `purchase_imp_services`.
task-6330737
Forward-Port-Of: odoo/odoo#276721
Forward-Port-Of: odoo/odoo#272453Restaurant point-of-sale orders now keep combo meal items assigned to the correct course when a combo is split into individual items. Courses are also cleaned up automatically when all related items are removed, helping staff keep orders clearer and reducing kitchen confusion.
Original PR description
Following this commit: ==== - When a combo is broken down, its items are assigned to their respective courses. - Remove a course when all its items are deleted from the cart. task-6121521 Forward-Port-Of: odoo/odoo#283143 Forward-Port-Of: odoo/odoo#260276
Indian GST purchase reports now better reflect legal reporting requirements for imported goods and services. Imports of services are no longer shown in GSTR-2B, and GSTR-3B reporting has been adjusted to match the latest section rules.
Original PR description
As per the law, import of services is not required to be shown in GSTR-2B. Therefore, the related report lines are removed in this commit. Additionally, GSTR-3B reporting is now handled according to the updated section changes for import of goods and services. task-6330737 Forward-Port-Of: odoo/enterprise#124550 Forward-Port-Of: odoo/enterprise#121925
WhatsApp messages using templates with many mixed placeholders now send each value to the correct spot. This prevents customers from receiving messages with mismatched details when templates include 10 or more variables.
Original PR description
**Issue**:
Sending a WhatsApp template with 10 or more variables can assign values to the wrong placeholders when the body contains mixed variable types, such as free text, field, or user name variables.
Templates containing only free-text variables are not affected.
**Reason**:
Meta consumes template parameters positionally, but for mixed variable types, Odoo built the parameter list using the template variable recordset order.
That order can differ from the numeric placeholder order, notably placing {{10}}, {{11}}, {{12}}... before {{1}}
when sending the message, as the payload parameters are not ordered by their numeric placeholder index.
**Fix:**
Sort body variables by their numeric placeholder index before preparing the Meta payload.
Task-6401501
Forward-Port-Of: odoo/enterprise#128492
Forward-Port-Of: odoo/enterprise#125671German DATEV exports now handle bank settlements involving three different currencies by splitting them into compliant accounting legs. This prevents export issues and ensures each DATEV line uses only one foreign currency while leaving normal transactions unchanged.
Original PR description
Issue: - DATEV does not support multiple foreign currencies on a single journal line. - This can occur when reconciling a bank transaction where: - the payer uses one currency (C1), - the bank…
Issue: - DATEV does not support multiple foreign currencies on a single journal line. - This can occur when reconciling a bank transaction where: - the payer uses one currency (C1), - the bank journal is held in another currency (C2), - the company uses a third currency (C3). - The existing export logic could not represent the bank liquidity and foreign AR/AP currencies separately in such cases. Fix: - Detect 3-currency cases from bank statement transactions and their liquidity line. - Use the DATEV clearing account (1360 SKR03 / 1460 SKR04) to split the transaction into two logical legs: - Bank → Clearing (bank journal currency) - AR/AP → Clearing (payer currency) - Emit the liquidity leg only once when multiple foreign AR/AP lines are reconciled against the same bank transaction. - Keep regular 1- and 2-currency transactions on the existing export path. Impact: - Correctly represents 3-currency bank settlements in DATEV. - Keeps each exported line in a single foreign currency. - Leaves manual entries and payment transactions outside this specific handling, as the scenario is specific to the bank liquidity line. taskID-5457547 Forward-Port-Of: odoo/enterprise#128876 Forward-Port-Of: odoo/enterprise#109010
Barcode deliveries now use the real storage location of a scanned serial number when it was not already reserved. This prevents inventory from being deducted from the wrong parent location, keeping stock counts accurate across warehouse sublocations.
Original PR description
Steps to reproduce --- 1. Enable Storage Locations and Lots/Serial Numbers. 2. Set the delivery operation type's "Source Location" to "Do not scan". 3. Create a serial-tracked product with a serial…
Steps to reproduce --- 1. Enable Storage Locations and Lots/Serial Numbers. 2. Set the delivery operation type's "Source Location" to "Do not scan". 3. Create a serial-tracked product with a serial stored in a sublocation (e.g. WH/Stock/Section 2). 4. Confirm a sale order for it, open the delivery in Barcode, and scan an unreserved serial. Issue --- Scanning the unreserved serial creates a new move line that falls back to _defaultLocation() because the decoded scan carries no source location (the operation type does not require scanning one) and never carries the serial's quant location. https://github.com/odoo/enterprise/blob/f42cfa7265ce32bd95f7f805cf4fb54d8b79cce1/stock_barcode/static/src/models/barcode_model.js#L937-L944 For a delivery, that default resolves to the picking's own source location (the parent WH/Stock), so the line is sourced from the parent instead of the sublocation where the serial physically sits. https://github.com/odoo/enterprise/blob/f42cfa7265ce32bd95f7f805cf4fb54d8b79cce1/stock_barcode/static/src/models/barcode_picking_model.js#L1542-L1544 On validation the unit is deducted from the parent location instead of the sublocation, leaving a stale quant of the serial in the sublocation and a negative quant at the parent. opw-5864414 Forward-Port-Of: odoo/enterprise#128523 Forward-Port-Of: odoo/enterprise#121375
Point of Sale now correctly validates negative orders that were manually paid with standard methods such as card payments. This prevents users from being wrongly blocked by a customer selection popup when the first payment option is Customer Account.
Original PR description
Validating a negative order manually paid with a standard method (e.g., Card) mistakenly triggers the fast payment fallback. The system wrongly assumed any single negative payment line was an auto-generated unsettled due. As a result, if the first configured payment method is "Customer Account", validation is incorrectly blocked by a popup asking for a customer. This commit restricts the fast payment trigger for negative amounts to only apply when the existing line is specifically a 'pay_later' type. task-6443347 Forward-Port-Of: odoo/odoo#282844 Forward-Port-Of: odoo/odoo#281238
Users on the Android mobile app can now download images and other files opened from Odoo without seeing an unsupported download error. The change sends eligible file downloads through the mobile app's supported download path, improving a visible workflow in Discuss and file viewing.
Original PR description
Steps to reproduce: - send an image in a Discuss channel - click the image to open the file viewer - click the download button => Android shows "The Odoo Mobile Apps only supports file downloads…
Steps to reproduce: - send an image in a Discuss channel - click the image to open the file viewer - click the download button => Android shows "The Odoo Mobile Apps only supports file downloads using the HTTP protocol." downloadFile()'s GET-by-URL case fetches the URL via XHR, then saves the Blob response by clicking a hidden <a download> anchor on a blob: URL. Android's DownloadManager only accepts http(s) URLs, so it rejects that blob: URL instead of downloading anything. Patch downloadFile._download to hand the URL directly to a new mobile.methods.saveFile bridge method when available, the same way download._download already delegates to mobile.methods.downloadFile. Blob/string content downloads aren't handled here — the only such call site (spreadsheet JSON export) is debug-mode only, so this is left as a console.warn for now. Related to odoo/odoo@e83fd8c08c879f5e262d39f24edcb3f81238ea82 Code made by Claude Changes supervised by HUVW Forward-Port-Of: odoo/enterprise#128471 Forward-Port-Of: odoo/enterprise#127693
Products with a base price of zero but paid attribute options are now correctly recognized as having a sellable price. This prevents shoppers from being blocked when adding these configured products to their website cart while zero-price sale prevention is enabled.
Original PR description
Steps to reproduce: --- - Install `website_sale` module. - Enable `Product Variants` and `Prevent Sale of Zero Priced Product` in settings. - Create new attribute > set `Variant Creation` as `Never`…
Steps to reproduce: --- - Install `website_sale` module. - Enable `Product Variants` and `Prevent Sale of Zero Priced Product` in settings. - Create new attribute > set `Variant Creation` as `Never` and also add value with extra price. - Create a product with sales price = 0, assign the attribute, and publish it. - As a public user (incognito), try to add the product to the cart. Issue: --- - In terminal error `The given product does not exist therefore it cannot be added to cart` is raised. Root cause: --- - In `_is_add_to_cart_allowed()`[1], the method calls `_get_contextual_price()` [2] to check if the product's price is zero when `prevent_zero_price_sale` is enabled. - However, `_get_contextual_price()` is called without the no-variant attribute values in the context, so it does not account for their `price_extra`. For a product with list price as 0 and attribute with extra price, the price is incorrectly computed as 0, causing `_is_add_to_cart_allowed()` to return `False`. Solution: --- - Before calling `_is_add_to_cart_allowed()`, set the product's context with the no-variant attribute values via `_get_product_price_context()`, so that `_get_contextual_price()` correctly includes the price extra in its computation. [1]https://github.com/odoo/odoo/blob/bbafbbd8950ec7123ab652851ede5479484eee26/addons/website_sale/controllers/cart.py#L117-L120 [2]https://github.com/odoo/odoo/blob/bbafbbd8950ec7123ab652851ede5479484eee26/addons/website_sale/models/product_product.py#L149-L150 opw-6365566 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283491 Forward-Port-Of: odoo/odoo#278620