Daily updates from Odoo
Friday, June 26, 2026
242 changes
16 changes
Enhancements to existing features
The timesheet Assistant Manager now makes more reliable suggestions when helping users fill in timesheets. This reduces incorrect or confusing recommendations and makes the time-entry workflow smoother.
Original PR description
This commit's purpose is to add a few bugprovement to the timesheet assistant manager. Those imp concerns mostly the timesheets suggested by the assistant manager. task-6179842 Forward-Port-Of: odoo/enterprise#118494
This change improves how dialog windows are handled on the web interface by making style checks more targeted. The result is smoother performance during actions like window resizing, scrolling, and table sorting.
Original PR description
Avoid using the :has() selector and use a specific style on the `documentElement` instead to replicate the same behavior. This reduces work during the "Recalculate Style" phase. It lowers recalculation time during window resizes, heavy scrolling, and table sorting by preventing broad selector matches and limiting style checks to elements with the specific class. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272118
Resolved issues and error corrections
This fix lets users record several finished-product serial numbers or lots in a single barcode session during manufacturing. It prevents the last scan from overwriting earlier ones, so production can be validated correctly and the right lot information is saved.
Original PR description
Steps to reproduce ------------------ Serial-tracked finished product: 1. Create a serial-tracked finished product and an un-tracked component. 2. Create a Manufacturing Order with quantity 2 and…
Steps to reproduce ------------------ Serial-tracked finished product: 1. Create a serial-tracked finished product and an un-tracked component. 2. Create a Manufacturing Order with quantity 2 and confirm it. 3. Open the Barcode app, scan the MO, then scan a first serial number SN_X1. 4. Scan a second serial number SN_X2. 5. Validate. Lot-tracked finished product: 1. Create a lot-tracked finished product with a one-component BoM and an existing lot LOT_A. 2. Create a Manufacturing Order and confirm it. 3. Open the Barcode app, scan the MO, then scan the existing lot LOT_A. 4. Scan a different, not-yet-existing lot LOT_B. 5. Validate. Issue ----- Only the last scanned serial is registered on the MO, and validation then fails because the count of producing serials does not match qty_producing for a serial-tracked finished product. updateLine overwrote lot_producing_ids with [args.lot_id] on every scan, so the first serial was dropped when the second one was scanned, and the same branch never staged a freshly typed lot_name, so a brand-new serial typed on a serial-tracked MO was lost before reaching the backend. https://github.com/odoo/enterprise/blob/4a2f1da5466740b7758d1962e5241620845d616b/stock_barcode_mrp/static/src/models/barcode_mrp_model.js#L407 Two behaviours of the shared barcode dispatcher make a single accumulating branch insufficient. The final-product line must keep exposing a producing lot, otherwise the base hasUnassignedQty check counts a scanned serial as zero once a quantity is already set, leaving qty_producing stuck below the demand. https://github.com/odoo/enterprise/blob/f622064871bf55b93890606d16407c50cf4419a6/stock_barcode/static/src/models/barcode_model.js#L1446 But exposing a producing lot makes the dispatcher treat the next serial as a conflicting tracking number, since the base _canOverrideTrackingNumber considers a different lot name non-overridable. https://github.com/odoo/enterprise/blob/f622064871bf55b93890606d16407c50cf4419a6/stock_barcode/static/src/models/barcode_model.js#L796-L798 So the scan is diverted to a new line through the override gate instead of updating the header line. https://github.com/odoo/enterprise/blob/f622064871bf55b93890606d16407c50cf4419a6/stock_barcode/static/src/models/barcode_model.js#L1585 For a lot-tracked finished product the producing lot can be corrected by scanning a different value, but the lot branch only stored a freshly typed value in lot_name and overwrote lot_producing_ids with the single existing lot. https://github.com/odoo/enterprise/blob/4a2f1da5466740b7758d1962e5241620845d616b/stock_barcode_mrp/static/src/models/barcode_mrp_model.js#L404-L407 The header reads its lot from lot_producing_ids whenever that relation is set and only falls back to lot_name when it is empty. https://github.com/odoo/enterprise/blob/4a2f1da5466740b7758d1962e5241620845d616b/stock_barcode_mrp/static/src/components/header.js#L45-L58 The save path only promotes lot_name to a producing lot when lot_producing_ids is empty, so scanning an existing lot then a new one neither displayed nor recorded the new lot and the finished product was produced under the old lot. https://github.com/odoo/enterprise/blob/4a2f1da5466740b7758d1962e5241620845d616b/stock_barcode_mrp/static/src/models/barcode_mrp_model.js#L628 Solution -------- Accumulate scanned serials by appending to lot_producing_ids instead of replacing it, and stage a freshly typed lot_name as a new producing lot when the finished product is tracked by serial, so every serial reaches the backend. Keep the final-product line exposing the last producing lot so each scanned serial is still counted as one unit instead of resetting the quantity to zero once several serials are registered. Override _canOverrideTrackingNumber for the final-product line so a serial scan updates the header line rather than being diverted to a new line, which is the only valid path for the finished product since it is a single header line backed by the lot_producing_ids relation. Persist the producing serials with explicit x2many commands, separating already-existing lots from freshly typed ones, so both are written on the MO. Reject a serial that is already registered on the MO so the same number cannot be produced twice in one session. For a lot-tracked finished product, build a producing lot from the scanned value, using the existing lot or a freshly typed lot name, and store it in lot_producing_ids so the new lot is both displayed and persisted through the same x2many commands as the serial case. Leave the produced quantity unchanged when the scanned lot differs from the one already registered, since replacing the lot is a correction and not an extra unit, and keep incrementing it when the same lot is scanned again. opw-6189620 Forward-Port-Of: odoo/enterprise#116890
When a vendor bill is completed from a purchase order, related invoice details can change. This update ensures early payment discount lines are refreshed or removed correctly so the invoice and journal entries stay aligned.
Original PR description
When a vendor bill is imported and auto-completed from a purchase order, then invoice lines, taxes, fiscal position, and payment terms can change. Existing EPD dynamic lines that lose their epd_key are skipped by sync and keep stale tax tags and amounts, causing mismatches between Invoice Lines and Journal Items. This commit makes EPD sync include keyless existing EPD lines so they are rewritten or removed during dynamic recomputation after PO auto-complete. Journal items remain consistent with the final invoice lines, taxes, and early discount configuration. Ticket [link](https://www.odoo.com/odoo/project.task/6047505) opw-6047505 Forward-Port-Of: odoo/odoo#272267 Forward-Port-Of: odoo/odoo#265539
Installing Stock could previously stop with an error when a database had sales orders in a company that did not yet have a warehouse. This update skips that warehouse check during installation so the module can be installed successfully and existing records are completed without interruption.
Original PR description
Steps to reproduce the bug:
- Have a database with sale_management installed and at least two companies (Company 1 and Company 2)
- Confirm sale orders with storable products under each company
- Install the stock module (which triggers sale_stock as a bridge module)
Problem:
The installation raised a RedirectWarning ("Please create a warehouse for company 2") and aborted. During sale_stock installation, _init_column initialises the new `warehouse_id` column on `sale.order` via SQL. Orders belonging to companies that have no warehouse yet (company 2, since `create_missing_warehouse` only creates one for the first company at that point) remain NULL. The stored-field recompute then calls write(), which fires _check_warehouse. That constraint calls _warehouse_redirect_warning() for each company without a warehouse, raising a RedirectWarning that aborts the install.
opw-6302537
Forward-Port-Of: odoo/odoo#270962
Forward-Port-Of: odoo/odoo#270480This update corrects the color shown in the Timesheets grid when an employee has working hours that include fractions of an hour. It prevents the system from incorrectly marking a row as overtime or under target when the totals are actually correct, improving accuracy and user trust.
Original PR description
## Issue In the Timesheets app, the color of the *Time Spent* cell at the end of a row indicates the current status of the timesheets based on the expected number of working hours. The selected color…
## Issue
In the Timesheets app, the color of the *Time Spent* cell at the end of a row indicates the current status of the timesheets based on the expected number of working hours. The selected color (green/orange/red) is sometimes wrong when an employee has a work schedule with fractional hours.
## Steps to reproduce
1. Install *Timesheets* (`timesheet_grid`)
2. For an employee E, edit the *Standard 40 hours/week* schedule:
- Change *Monday Afternoon* "Work to" column from 17:00 to 17:20.
3. In Timesheets > All Timesheets, go back one week and fill the timesheet for the employee E. We need 8 hours everyday but on Monday, where we need 8 hours and 20 minutes.
4. __The background of the *Time Spent* cell is orange, even though there's no overtime anywhere, and the value in the cell is precisely 40:20, which is the expected amount of hours worked.__
## Cause
When comparing the amount of hours worked and the expected amount of hours, small rounding errors occur. At this point of the execution:
https://github.com/odoo/enterprise/blob/19b7f5a6961dbce7367c07fcc55eea1925832634/timesheet_grid/static/src/views/timesheet_grid/timesheet_grid_renderer.js#L157
We obtain the following values:
```js
> monday = section.cells[1]
> monday.value
8.333333333333336
> workingHours[monday.column.value]
8.333333333333332
> monday.value - workingHours[monday.column.value]
3.552713678800501e-15
```
This small difference differing from 0, the wrong color is selected by `_getSectionTotalCellBgColor`:
https://github.com/odoo/enterprise/blob/19b7f5a6961dbce7367c07fcc55eea1925832634/timesheet_grid/static/src/views/timesheet_grid/timesheet_grid_renderer.js#L160-L172
## Fix
The same issue was fixed elsewhere by https://github.com/odoo/enterprise/commit/3340c0610ae6d7d3087f20da04309512771cc4b7. The same fix is applied here for consistency.
opw-6193181
Forward-Port-Of: odoo/enterprise#121463This fix prevents PoS session closing from failing when the cash difference gain account has a default tax. The system now calculates the tax split correctly up front, so closing cash registers works reliably in countries where these accounts are taxed.
Original PR description
Steps to reproduce ------------------ 1. Set a default tax on the "Cash Difference Gain" account (e.g. a 25% sales tax) -- required in some countries like Denmark (cf 5972690). 2. Open a PoS session,…
Steps to reproduce ------------------ 1. Set a default tax on the "Cash Difference Gain" account (e.g. a 25% sales tax) -- required in some countries like Denmark (cf 5972690). 2. Open a PoS session, count more cash than expected at closing. 3. Try to close the session. -> Error message shows up "The journal entry reached an invalid state..." ... "The journal entry must always have exactly one journal item involving the bank/cash account" What's happening ---------------- PoS creates a bank statement line with the gain account as counterpart, resulting in 2 lines: cash +10, gain -10. Since the gain account has a default tax, `_sync_tax_lines` adds a tax line of -2.5 on top, which makes the move unbalanced by 2.5. Then `_sync_unbalanced_lines` adds a 4th line to fix it, on the line returned by `_get_automatic_balancing_account`, which is `journal.default_account_id`, i.e. the cash account itself for a cash journal. So we end up with 2 lines on that same cash account, which a bank statement line move doesn't allow -> Error. The fix ------- In `_post_statement_difference`, precompute the base and tax split ourselves and build the statement line's `line_ids` directly (e.g. for +10 and a 25% tax: cash +10, gain -8, tax -2). The move is balanced from creation, so `_sync_tax_lines` and `_sync_unbalanced_lines` don't have to touch it. Note that we force the tax computation to be in 'force_price_include' mode, as the counted cash difference is a gross amount (physical money in the drawer). This way the tax is always extracted from the cash amount, regardless of how the tax is configured (included or excluded in price). Same pattern is already used by `hr_expense` (cf `hr_expense.models.account_move_line._compute_totals`). opw-5972690 Forward-Port-Of: odoo/odoo#271921 Forward-Port-Of: odoo/odoo#257892
This change prevents a crash that could happen when loading accounting charts for Spanish templates in certain setup flows. It makes the loading process more robust by avoiding a missing-data lookup, so chart setup and tests complete reliably.
Original PR description
Description of the issue this commit addresses: In single-app and patched chart-template flows, template_data can be provided without a parent key. l10n_es accessed template_data['parent'] in _post_load_data, raising KeyError during chart loading and test setup. --- Desired behavior after this commit is merged: This commit checks ES template ancestry from template_code instead of reading parent from template_data, avoiding KeyError when that key is absent while keeping the post-load logic scoped to ES template chains. --- runbot-[242586](https://runbot.odoo.com/odoo/error/242586) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix removes an unnecessary block that stopped Gemini 3 from being used with tools and structured responses. As a result, AI features can work again for website SEO optimization and for retrying failed AI actions when another provider is unavailable.
Original PR description
Purpose: -------- Gemini models since gemini-3 support requests with tools and structured outputs. The exception in the code is now raised only for gemini-2.5 models. This exception was preventing to use an agent with gemini 3 to optimize SEO in ai_website, or to retry failed ai fields or ai server actions on the saas when the request to openAI failed. Task-6335595
This change cleans up automated Point of Sale test data by removing an unnecessary product tracking setting and consolidating overlapping test cases. It also moves a stock-related test to the Stock POS area so the test suite is better organized and easier to maintain.
Original PR description
*: pos_stock In this commit: --- - Remove the `tracking` field from the HOOT test data. - Remove `test_order_unexisting_lots`, as it is already covered in `pos_stock`. - Move `test_order_existing_lot_gs1_nomenclature` from `point_of_sale` to `pos_stock`, where the stock-related behavior belongs. runbot-941084 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This change lets Odoo keep very small base unit counts without rounding them away, so product reference prices are calculated correctly for large-pack items. It improves pricing accuracy for cases like selling screws in boxes of 10,000 or similar bulk packaging.
Original PR description
**Description of the issue/feature this PR addresses:** The `Product Reference Price` feature in `website_sale` cannot correctly handle products sold in large packs when the reference quantity…
**Description of the issue/feature this PR addresses:** The `Product Reference Price` feature in `website_sale` cannot correctly handle products sold in large packs when the reference quantity requires a very small `base_unit_count`. For example, a product sold as a `box of 10000` screws should be able to use `0.0001` as its `Base Unit Count`, so the reference price can be computed against the box quantity correctly. **Current behavior before PR:** `base_unit_count` uses the default float precision, so values with more than two decimal places are rounded in the product form. When trying to set `Base Unit Count` to `0.0001`, the value is rounded to `0.00` / `0.01`, which makes the Product Reference Price computation incorrect. Steps to reproduce: 1. Go to Settings > Website and enable Product Reference Price. 2. Create or open a product named `Screws`. 3. Set Sales Price to `$ 1.00`. 4. On the product form, set Base Unit Count to `0.0001`. 5. In Custom Unit of Measure, type `box of 10000` and press Create. <img width="1374" height="740" alt="1" src="https://github.com/user-attachments/assets/2d4f7863-b2cd-4c7c-87e1-11526dc50551" /> **Desired behavior after PR is merged:** `base_unit_count` keeps high-precision values such as `0.0001`. This allows `Product Reference Price` to correctly support large-pack scenarios, such as selling screws in a `box of 10000`, by storing `base_unit_count` with unlimited numeric precision. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262579
This update stops popup snippets from being added in places where they should not be available, such as inside other popups. It also ensures the available snippets are refreshed correctly after changes, helping avoid errors and keeping the website editor more reliable.
Original PR description
*: website, website_mass_mailing __Problem__ In some cases, popup snippets can be dropped inside another popup. This shouldn't be possible. Moreover, it produces the following error: `TypeError:…
*: website, website_mass_mailing __Problem__ In some cases, popup snippets can be dropped inside another popup. This shouldn't be possible. Moreover, it produces the following error: `TypeError: Cannot read properties of undefined (reading 'after')`. This can happen in multiple scenarios: - After saving a custom snippet, the snippets are reloaded but `disableUndroppableSnippets` is not called again, although the snippets should be filtered again. - `NewsletterPopupPlugin` registers `.o_newsletter_popup` in the `so_snippet_addition_selector` resource, bypassing the more restrictive `dropzone_selector` of `PopupOptionPlugin`. - Popups are not disabled when the cookie bar is open because we don't take `excludeAncestor` into account in `DisableSnippetsPlugin`. __Fix__ - Trigger an event whenever the snippets are loaded and call `disableUndroppableSnippets` when it is. - Remove the redundant `NewsletterPopupPlugin`. - Filter `dropAreaEls` with `excludeAncestor` in `DisableSnippetsPlugin`. Forward-Port-Of: odoo/odoo#271635 Forward-Port-Of: odoo/odoo#269864
This fix ensures the preview shown for favorite email templates updates correctly when users switch between target models. Previously, the template title changed as expected, but the preview could stay stuck on an older template, which could cause confusion when choosing a mailing layout.
Original PR description
Overview ------ When having a favorite mailing (template) for target model X, and another one for target model Y, and try to create a new mailing for target model X, the theme selector will first…
Overview ------ When having a favorite mailing (template) for target model X, and another one for target model Y, and try to create a new mailing for target model X, the theme selector will first show the template X with the correct title and preview, however when switching to model Y, the theme selector will show the title of the tempalte Y but the preview is always the one of template X. How to reproduce ------ 1. Create a new mailing for a target model X (e.g. `mailing.contact`) 2. Set a content for that mailing (you can choose from the existing themes) 3. Set that mailing as a favorite (using the favorite star button) 4. Create a new mailing for another target model Y. 5. Redo steps 2. and 3. 6. Create a new mailing, and set the target model to X (You should see the mailing X in the theme selector with the correct title and preview) 7. Change the target model to Y. Expected Behavior ------ Both the title and the preview of the mailing X in the theme selector should change into the title and the preivew of mailing Y. Current Behavior ------ The title of the template is changed into the one of Y however the preview remains the one of mailing X. Cause of The Issue ------ After the first mount of the `FavoritePreivew` component, when the template changes in the props, the body content of the preivew is not updated with the new value. Task-6332946 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272065
The Shopee connector now handles customer identifiers that are larger than the older supported range. This prevents errors when creating new contacts and ensures Shopee orders can still be matched to the correct customer.
Original PR description
When the Shopee connector was introduced, Shopee documented `buyer_user_id` as an int32. We therefore store it in an `Integer` field, which maps to a PostgreSQL int32 column. However, feedback showed that Shopee can send ids exceeding the int32 bounds, leading to a traceback when creating new contacts. Shopee has since updated their documentation to confirm the field is actually an int64. Since we are in stable and cannot change the column type, this commit falls back to the `ref` field of the `res.partner` model to store and match Shopee contacts whose identifier doesn't fit within an int32. opw-6325948 See also: - master: https://github.com/odoo/enterprise/pull/121507 - upgrade: https://github.com/odoo/upgrade/pull/10578 Forward-Port-Of: odoo/enterprise#121498
This fix prevents POS down payments from being counted twice when calculating how much is still left to invoice on a sales order. It ensures the final invoice shows the correct remaining amount and avoids negative invoice balances.
Original PR description
Steps to reproduce --- 1. Create and confirm a sale order 2. In the POS, settle it with a down payment and invoice the down payment 3. From the sale order, create and post the final invoice Issue --- The order ends up with a negative amount to invoice. The pos_sale override https://github.com/odoo/odoo/blob/a1bcd917846493d08dd02b63e6110078ff5156a3/addons/pos_sale/models/sale_order.py#L83-L88 always subtracts the amount paid in the POS, which is required before the final invoice because the down payment sits on a separate line the base computation ignores; but once the final invoice is posted that down payment is already deducted through its negated line, so subtracting it again counts it twice and pushes amount to invoice below zero. opw-6261272 Forward-Port-Of: odoo/odoo#269323
This change fixes the Apps > Industries page so filters can be applied again. It improves the way industry listings are prepared in the background, allowing users to narrow down results more easily when browsing apps by industry.
Original PR description
Before this commit, no filter could be applied on Apps > Industries menu, because the module list returned by the appstore was difficult to filter as is. This commit uses the `new` command to create temporary ir.module.module such that any filtering domain can be applied, providing that the filter condition is available from the appstore controller. task-6067092 Forward-Port-Of: odoo/odoo#270005
33 changes
Enhancements to existing features
This update improves how dialog drag behavior is handled in the web client by replacing a broad browser selector with a more targeted approach. The result is less style recalculation work, which helps keep the interface smoother during window resizing, scrolling, and table sorting.
Original PR description
Avoid using the :has() selector and use a specific style on the `documentElement` instead to replicate the same behavior. This reduces work during the "Recalculate Style" phase. It lowers recalculation time during window resizes, heavy scrolling, and table sorting by preventing broad selector matches and limiting style checks to elements with the specific class. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272118
The PDP registration process is more flexible and secure: users can now adjust their contact email during registration, and the connection process includes extra protection to prevent impersonation. In addition, deregistering a participant now clears the KYC status so the process can be restarted if needed.
Original PR description
It seems the readonly can cause some problem because the user might want to change it during the registration. Also adding the hash signed to the connect route to make sure nobody can impersonate the kyc Also clicking on the button_deregister_pdp_participant action will now reset the kyc status so that you can do it again if needed. task-626574 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#268833
The system now records information when a device used for a session does not match the expected fingerprint. This helps teams spot unusual logins or possible account misuse more quickly.
Original PR description
Log device information if fingerprint doesn't match the one currently being used for the current session. Task-6340963
Resolved issues and error corrections
This fix ensures that when manufacturing products are scanned in the Barcode app, every produced serial number or lot is kept and saved instead of only the last one. It prevents validation errors and makes production tracking accurate when a single manufacturing order produces more than one item.
Original PR description
Steps to reproduce ------------------ Serial-tracked finished product: 1. Create a serial-tracked finished product and an un-tracked component. 2. Create a Manufacturing Order with quantity 2 and…
Steps to reproduce ------------------ Serial-tracked finished product: 1. Create a serial-tracked finished product and an un-tracked component. 2. Create a Manufacturing Order with quantity 2 and confirm it. 3. Open the Barcode app, scan the MO, then scan a first serial number SN_X1. 4. Scan a second serial number SN_X2. 5. Validate. Lot-tracked finished product: 1. Create a lot-tracked finished product with a one-component BoM and an existing lot LOT_A. 2. Create a Manufacturing Order and confirm it. 3. Open the Barcode app, scan the MO, then scan the existing lot LOT_A. 4. Scan a different, not-yet-existing lot LOT_B. 5. Validate. Issue ----- Only the last scanned serial is registered on the MO, and validation then fails because the count of producing serials does not match qty_producing for a serial-tracked finished product. updateLine overwrote lot_producing_ids with [args.lot_id] on every scan, so the first serial was dropped when the second one was scanned, and the same branch never staged a freshly typed lot_name, so a brand-new serial typed on a serial-tracked MO was lost before reaching the backend. https://github.com/odoo/enterprise/blob/4a2f1da5466740b7758d1962e5241620845d616b/stock_barcode_mrp/static/src/models/barcode_mrp_model.js#L407 Two behaviours of the shared barcode dispatcher make a single accumulating branch insufficient. The final-product line must keep exposing a producing lot, otherwise the base hasUnassignedQty check counts a scanned serial as zero once a quantity is already set, leaving qty_producing stuck below the demand. https://github.com/odoo/enterprise/blob/f622064871bf55b93890606d16407c50cf4419a6/stock_barcode/static/src/models/barcode_model.js#L1446 But exposing a producing lot makes the dispatcher treat the next serial as a conflicting tracking number, since the base _canOverrideTrackingNumber considers a different lot name non-overridable. https://github.com/odoo/enterprise/blob/f622064871bf55b93890606d16407c50cf4419a6/stock_barcode/static/src/models/barcode_model.js#L796-L798 So the scan is diverted to a new line through the override gate instead of updating the header line. https://github.com/odoo/enterprise/blob/f622064871bf55b93890606d16407c50cf4419a6/stock_barcode/static/src/models/barcode_model.js#L1585 For a lot-tracked finished product the producing lot can be corrected by scanning a different value, but the lot branch only stored a freshly typed value in lot_name and overwrote lot_producing_ids with the single existing lot. https://github.com/odoo/enterprise/blob/4a2f1da5466740b7758d1962e5241620845d616b/stock_barcode_mrp/static/src/models/barcode_mrp_model.js#L404-L407 The header reads its lot from lot_producing_ids whenever that relation is set and only falls back to lot_name when it is empty. https://github.com/odoo/enterprise/blob/4a2f1da5466740b7758d1962e5241620845d616b/stock_barcode_mrp/static/src/components/header.js#L45-L58 The save path only promotes lot_name to a producing lot when lot_producing_ids is empty, so scanning an existing lot then a new one neither displayed nor recorded the new lot and the finished product was produced under the old lot. https://github.com/odoo/enterprise/blob/4a2f1da5466740b7758d1962e5241620845d616b/stock_barcode_mrp/static/src/models/barcode_mrp_model.js#L628 Solution -------- Accumulate scanned serials by appending to lot_producing_ids instead of replacing it, and stage a freshly typed lot_name as a new producing lot when the finished product is tracked by serial, so every serial reaches the backend. Keep the final-product line exposing the last producing lot so each scanned serial is still counted as one unit instead of resetting the quantity to zero once several serials are registered. Override _canOverrideTrackingNumber for the final-product line so a serial scan updates the header line rather than being diverted to a new line, which is the only valid path for the finished product since it is a single header line backed by the lot_producing_ids relation. Persist the producing serials with explicit x2many commands, separating already-existing lots from freshly typed ones, so both are written on the MO. Reject a serial that is already registered on the MO so the same number cannot be produced twice in one session. For a lot-tracked finished product, build a producing lot from the scanned value, using the existing lot or a freshly typed lot name, and store it in lot_producing_ids so the new lot is both displayed and persisted through the same x2many commands as the serial case. Leave the produced quantity unchanged when the scanned lot differs from the one already registered, since replacing the lot is a correction and not an extra unit, and keep incrementing it when the same lot is scanned again. opw-6189620 Forward-Port-Of: odoo/enterprise#116890
The German SKR03 template now points to the correct default accounts for cash discounts. This helps ensure accounting entries are set up properly and reduces the risk of using the wrong account codes during configuration.
Original PR description
The default cash discout accounts referenced in the
German skr03 template used the wrong account codes.
The template has been updated with the right ones.
task-4915939
opw-4909059
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#271886
Forward-Port-Of: odoo/odoo#271024The default cash discount accounts in the German SKR03 template were using incorrect account codes. They have been updated to the right ones so German accounting exports and related reports reflect the proper accounts.
Original PR description
The default cash discount accounts referenced in the German skr03 template used the wrong account codes. The template has been updated with the right ones. task-4915939 opw-4909059 Forward-Port-Of: odoo/enterprise#121692 Forward-Port-Of: odoo/enterprise#121180
The mailing theme selector now updates both the title and the preview when switching between favorite templates for different target models. This prevents users from seeing a mismatched preview and helps them choose the right mailing template more confidently.
Original PR description
Overview ------ When having a favorite mailing (template) for target model X, and another one for target model Y, and try to create a new mailing for target model X, the theme selector will first…
Overview ------ When having a favorite mailing (template) for target model X, and another one for target model Y, and try to create a new mailing for target model X, the theme selector will first show the template X with the correct title and preview, however when switching to model Y, the theme selector will show the title of the tempalte Y but the preview is always the one of template X. How to reproduce ------ 1. Create a new mailing for a target model X (e.g. `mailing.contact`) 2. Set a content for that mailing (you can choose from the existing themes) 3. Set that mailing as a favorite (using the favorite star button) 4. Create a new mailing for another target model Y. 5. Redo steps 2. and 3. 6. Create a new mailing, and set the target model to X (You should see the mailing X in the theme selector with the correct title and preview) 7. Change the target model to Y. Expected Behavior ------ Both the title and the preview of the mailing X in the theme selector should change into the title and the preivew of mailing Y. Current Behavior ------ The title of the template is changed into the one of Y however the preview remains the one of mailing X. Cause of The Issue ------ After the first mount of the `FavoritePreivew` component, when the template changes in the props, the body content of the preivew is not updated with the new value. Task-6332946 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272065
This fix stops popup-related snippets from being offered in places where they should not be used, including after snippet refreshes. It also prevents a browser error that could appear when editing websites, improving reliability while keeping the editing experience consistent.
Original PR description
*: website, website_mass_mailing __Problem__ In some cases, popup snippets can be dropped inside another popup. This shouldn't be possible. Moreover, it produces the following error: `TypeError:…
*: website, website_mass_mailing __Problem__ In some cases, popup snippets can be dropped inside another popup. This shouldn't be possible. Moreover, it produces the following error: `TypeError: Cannot read properties of undefined (reading 'after')`. This can happen in multiple scenarios: - After saving a custom snippet, the snippets are reloaded but `disableUndroppableSnippets` is not called again, although the snippets should be filtered again. - `NewsletterPopupPlugin` registers `.o_newsletter_popup` in the `so_snippet_addition_selector` resource, bypassing the more restrictive `dropzone_selector` of `PopupOptionPlugin`. - Popups are not disabled when the cookie bar is open because we don't take `excludeAncestor` into account in `DisableSnippetsPlugin`. __Fix__ - Trigger an event whenever the snippets are loaded and call `disableUndroppableSnippets` when it is. - Remove the redundant `NewsletterPopupPlugin`. - Filter `dropAreaEls` with `excludeAncestor` in `DisableSnippetsPlugin`. Forward-Port-Of: odoo/odoo#271635 Forward-Port-Of: odoo/odoo#269864
This change stops public holiday work entries from being counted twice when they overlap with worked-time leave. It ensures the holiday is applied first, so payroll work entries stay accurate and employees do not see inflated hours on the same day.
Original PR description
Issue: When work entries are generated from Attendances, a worked-time time off created by the Indian sandwich rule can overlap a public holiday and generate duplicate work entries for the same day.…
Issue: When work entries are generated from Attendances, a worked-time time off created by the Indian sandwich rule can overlap a public holiday and generate duplicate work entries for the same day. Steps to reproduce: - Create an employee with Work Entry Source set to Attendances - Use a flexible working schedule on the employee - Configure a public holiday on a scheduled day with work entry type (Paid time off) - Create a time off type with Count as set to Worked Time - Generate time off for the period so the public holiday entry exists (maybe a day before and a the public holiday and the day after) - Open Payroll > Work Entries (Observe the date of the public holiday will have more than 8h entry) Cause: In `_get_version_work_entries_values()`, calendar leaves are split by `hr_holidays` `time_type` into: - leaves: absences and public holidays - worked_leaves: worked-time time off For attendance-based contracts, both sets were turned into work entries without removing overlap between a public holiday and a worked-time leave on the same period. https://github.com/odoo/odoo/blob/3a088e23d3e563c39cdcb252edc8c7cc74981de4/addons/hr_work_entry/models/hr_version.py#L222-L226 For non-flexible calendar: Public holidays and worked-time leaves are both clipped to the static working schedule (e.g. 8h per working day). overlap was kept in both result sets. https://github.com/odoo/odoo/blob/3a088e23d3e563c39cdcb252edc8c7cc74981de4/addons/hr_work_entry/models/hr_version.py#L260 For flexible calendar: The one-day intervals are kept as the actual interval (often 00:00-23:59 for a public holiday). The worked-time on that day is schedule-shaped (e.g. 8h). Subtracting intervals on a full-day public holiday left a 16h fragment instead of removing the public holiday entry. https://github.com/odoo/odoo/blob/3a088e23d3e563c39cdcb252edc8c7cc74981de4/addons/hr_work_entry/models/hr_version.py#L242-L249 Solution: We need to make regular leaves take priority over worked-time leaves, compute the real regular leave intervals first, then remove those intervals from the worked-time leave intervals before work entries are created: - for fully flexible employees, subtract regular leaves from worked leaves; - for flexible calendars, keep one-day regular leaves as is and subtract them from worked-time leaves - for non-flexible attendance-based calendars, clip regular leaves on the static schedule, then subtract them from worked-time leaves clipped on the same schedule. This means that when a sandwich worked-time leave overlaps a public holiday, the public holiday consumes that period first. The overlapping part is then removed from `real_worked_leaves`, so no second worked-time entry is generated for the same public holiday period. opw-6237163 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#269615 Forward-Port-Of: odoo/odoo#268527
This update prevents public holiday time from being counted twice when an employee has worked-time leave overlapping the holiday. It ensures payroll work entries are generated correctly, avoiding inflated hours and cleaner attendance-to-payroll processing.
Original PR description
Issue: When work entries are generated from Attendances, a worked-time time off created by the Indian sandwich rule can overlap a public holiday and generate duplicate work entries for the same day.…
Issue: When work entries are generated from Attendances, a worked-time time off created by the Indian sandwich rule can overlap a public holiday and generate duplicate work entries for the same day. Steps to reproduce: - Create an employee with Work Entry Source set to Attendances - Use a flexible working schedule on the employee - Configure a public holiday on a scheduled day with work entry type (Paid time off) - Create a time off type with Count as set to Worked Time - Generate time off for the period so the public holiday entry exists (maybe a day before and a the public holiday and the day after) - Open Payroll > Work Entries (Observe the date of the public holiday will have more than 8h entry) Cause: In `_get_version_work_entries_values()`, calendar leaves are split by `hr_holidays` `time_type` into: - leaves: absences and public holidays - worked_leaves: worked-time time off For attendance-based contracts, both sets were turned into work entries without removing overlap between a public holiday and a worked-time leave on the same period. https://github.com/odoo/odoo/blob/3a088e23d3e563c39cdcb252edc8c7cc74981de4/addons/hr_work_entry/models/hr_version.py#L222-L226 For non-flexible calendar: Public holidays and worked-time leaves are both clipped to the static working schedule (e.g. 8h per working day). overlap was kept in both result sets. https://github.com/odoo/odoo/blob/3a088e23d3e563c39cdcb252edc8c7cc74981de4/addons/hr_work_entry/models/hr_version.py#L260 For flexible calendar: The one-day intervals are kept as the actual interval (often 00:00-23:59 for a public holiday). The worked-time on that day is schedule-shaped (e.g. 8h). Subtracting intervals on a full-day public holiday left a 16h fragment instead of removing the public holiday entry. https://github.com/odoo/odoo/blob/3a088e23d3e563c39cdcb252edc8c7cc74981de4/addons/hr_work_entry/models/hr_version.py#L242-L249 Solution: We need to make regular leaves take priority over worked-time leaves, compute the real regular leave intervals first, then remove those intervals from the worked-time leave intervals before work entries are created: - for fully flexible employees, subtract regular leaves from worked leaves; - for flexible calendars, keep one-day regular leaves as is and subtract them from worked-time leaves - for non-flexible attendance-based calendars, clip regular leaves on the static schedule, then subtract them from worked-time leaves clipped on the same schedule. This means that when a sandwich worked-time leave overlaps a public holiday, the public holiday consumes that period first. The overlapping part is then removed from `real_worked_leaves`, so no second worked-time entry is generated for the same public holiday period. opw-6237163 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/enterprise#120300 Forward-Port-Of: odoo/enterprise#119530
The page limit note in the website generator was updated to use more general wording instead of stating a fixed number. This gives the business more flexibility to adjust page limits later without needing another visible wording change.
Original PR description
Page limit note fixed by being more general instead of stating a blatant 200. This gives us more leeway to control the nbr of pages IAP side. Forward-Port-Of: odoo/enterprise#121671
This change corrects the color shown in the Timesheets grid when an employee has a schedule with fractional working hours. It ensures the status color matches the actual expected hours, avoiding misleading orange or red highlights caused by tiny rounding differences.
Original PR description
## Issue In the Timesheets app, the color of the *Time Spent* cell at the end of a row indicates the current status of the timesheets based on the expected number of working hours. The selected color…
## Issue
In the Timesheets app, the color of the *Time Spent* cell at the end of a row indicates the current status of the timesheets based on the expected number of working hours. The selected color (green/orange/red) is sometimes wrong when an employee has a work schedule with fractional hours.
## Steps to reproduce
1. Install *Timesheets* (`timesheet_grid`)
2. For an employee E, edit the *Standard 40 hours/week* schedule:
- Change *Monday Afternoon* "Work to" column from 17:00 to 17:20.
3. In Timesheets > All Timesheets, go back one week and fill the timesheet for the employee E. We need 8 hours everyday but on Monday, where we need 8 hours and 20 minutes.
4. __The background of the *Time Spent* cell is orange, even though there's no overtime anywhere, and the value in the cell is precisely 40:20, which is the expected amount of hours worked.__
## Cause
When comparing the amount of hours worked and the expected amount of hours, small rounding errors occur. At this point of the execution:
https://github.com/odoo/enterprise/blob/19b7f5a6961dbce7367c07fcc55eea1925832634/timesheet_grid/static/src/views/timesheet_grid/timesheet_grid_renderer.js#L157
We obtain the following values:
```js
> monday = section.cells[1]
> monday.value
8.333333333333336
> workingHours[monday.column.value]
8.333333333333332
> monday.value - workingHours[monday.column.value]
3.552713678800501e-15
```
This small difference differing from 0, the wrong color is selected by `_getSectionTotalCellBgColor`:
https://github.com/odoo/enterprise/blob/19b7f5a6961dbce7367c07fcc55eea1925832634/timesheet_grid/static/src/views/timesheet_grid/timesheet_grid_renderer.js#L160-L172
## Fix
The same issue was fixed elsewhere by https://github.com/odoo/enterprise/commit/3340c0610ae6d7d3087f20da04309512771cc4b7. The same fix is applied here for consistency.
opw-6193181
Forward-Port-Of: odoo/enterprise#121463Attachments added to employee records and leave requests now go into the correct folder instead of the Employees root folder. The fix also ensures documents are created properly for sick leave attachments, so records are no longer missed.
Original PR description
Before this commit, when adding an attachment to a leave or a employee version the mixin was configured to create the document in the root folder of Employees which was not very convenient. In addition, when creating a Sick leave with an attachment, no document was ever created. This commit fix both those bugs. Task-6095811 Forward-Port-Of: odoo/enterprise#120539 Forward-Port-Of: odoo/enterprise#112993
This change prevents PoS session closing from failing when the cash difference gain account has a default tax. It now calculates the tax split correctly up front, so cash counts can be posted and closed without accounting errors.
Original PR description
Steps to reproduce ------------------ 1. Set a default tax on the "Cash Difference Gain" account (e.g. a 25% sales tax) -- required in some countries like Denmark (cf 5972690). 2. Open a PoS session,…
Steps to reproduce ------------------ 1. Set a default tax on the "Cash Difference Gain" account (e.g. a 25% sales tax) -- required in some countries like Denmark (cf 5972690). 2. Open a PoS session, count more cash than expected at closing. 3. Try to close the session. -> Error message shows up "The journal entry reached an invalid state..." ... "The journal entry must always have exactly one journal item involving the bank/cash account" What's happening ---------------- PoS creates a bank statement line with the gain account as counterpart, resulting in 2 lines: cash +10, gain -10. Since the gain account has a default tax, `_sync_tax_lines` adds a tax line of -2.5 on top, which makes the move unbalanced by 2.5. Then `_sync_unbalanced_lines` adds a 4th line to fix it, on the line returned by `_get_automatic_balancing_account`, which is `journal.default_account_id`, i.e. the cash account itself for a cash journal. So we end up with 2 lines on that same cash account, which a bank statement line move doesn't allow -> Error. The fix ------- In `_post_statement_difference`, precompute the base and tax split ourselves and build the statement line's `line_ids` directly (e.g. for +10 and a 25% tax: cash +10, gain -8, tax -2). The move is balanced from creation, so `_sync_tax_lines` and `_sync_unbalanced_lines` don't have to touch it. Note that we force the tax computation to be in 'force_price_include' mode, as the counted cash difference is a gross amount (physical money in the drawer). This way the tax is always extracted from the cash amount, regardless of how the tax is configured (included or excluded in price). Same pattern is already used by `hr_expense` (cf `hr_expense.models.account_move_line._compute_totals`). opw-5972690 Forward-Port-Of: odoo/odoo#271921 Forward-Port-Of: odoo/odoo#257892
This change prevents stock installation from failing in databases that use multiple companies when not all companies have a warehouse yet. It ensures the system can complete the setup first, without stopping on a warehouse-related warning during the module install process.
Original PR description
Steps to reproduce the bug:
- Have a database with sale_management installed and at least two companies (Company 1 and Company 2)
- Confirm sale orders with storable products under each company
- Install the stock module (which triggers sale_stock as a bridge module)
Problem:
The installation raised a RedirectWarning ("Please create a warehouse for company 2") and aborted. During sale_stock installation, _init_column initialises the new `warehouse_id` column on `sale.order` via SQL. Orders belonging to companies that have no warehouse yet (company 2, since `create_missing_warehouse` only creates one for the first company at that point) remain NULL. The stored-field recompute then calls write(), which fires _check_warehouse. That constraint calls _warehouse_redirect_warning() for each company without a warehouse, raising a RedirectWarning that aborts the install.
opw-6302537
Forward-Port-Of: odoo/odoo#270962
Forward-Port-Of: odoo/odoo#270480This update ensures taxes defined for every fiscal position remain available even when no specific mapping exists, including tax unit cases. It also keeps related tax information visible in the interface and prevents tax lines from getting out of sync after fiscal position changes, reducing accounting errors and confusion.
Original PR description
A tax created without a fiscal position (empty fiscal_position_ids) is conceptually an "All" tax: it should apply across every fiscal position, including the empty ones used for tax units. Problem…
A tax created without a fiscal position (empty fiscal_position_ids) is conceptually an "All" tax: it should apply across every fiscal position, including the empty ones used for tax units. Problem map_tax drops every tax when the FP has no mapping, including the "All" ones that should pass through. action_open_related_taxes only lists the FP's tax_ids, so "All" taxes are invisible from the FP form. The Taxes stat button is hidden whenever the FP has no tax_ids. action_update_fpos_values invokes the field computes directly, so tax and balance lines fall out of sync after an FP change. Fix map_tax: when the FP has no tax_ids, return the input taxes whose fiscal_position_ids is empty (the "All" ones) instead of an empty recordset. action_open_related_taxes: extend the domain to also include taxes bound to no fiscal position. partner_view: drop the invisible="not tax_ids" guard on the Taxes stat button. action_update_fpos_values: route the deferred computes through _check_balanced and _sync_dynamic_lines so tax lines stay in sync after the update. task-id [6231514](https://www.odoo.com/odoo/project/967/tasks/6231514) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#268273
This update adjusts an automated tax test so it correctly handles taxes that are not linked to any fiscal position. It makes the test match the intended behavior, ensuring valid taxes are not incorrectly excluded and helping prevent false failures in tax reporting checks.
Original PR description
map_tax on an empty fiscal position now preserves taxes with no fiscal_position_ids. Filter those out in test_tax_unit_auto_fiscal_position so the assertion only checks that taxes bound to a fiscal position are dropped by the unit FP. comunity PR: https://github.com/odoo/odoo/pull/268273 task-id 623151 Forward-Port-Of: odoo/enterprise#121525
This fix prevents a down payment taken in Point of Sale from being counted twice when calculating how much is left to invoice on a sales order. As a result, customers will no longer see a negative remaining amount to invoice after the final invoice is posted.
Original PR description
Steps to reproduce --- 1. Create and confirm a sale order 2. In the POS, settle it with a down payment and invoice the down payment 3. From the sale order, create and post the final invoice Issue --- The order ends up with a negative amount to invoice. The pos_sale override https://github.com/odoo/odoo/blob/a1bcd917846493d08dd02b63e6110078ff5156a3/addons/pos_sale/models/sale_order.py#L83-L88 always subtracts the amount paid in the POS, which is required before the final invoice because the down payment sits on a separate line the base computation ignores; but once the final invoice is posted that down payment is already deducted through its negated line, so subtracting it again counts it twice and pushes amount to invoice below zero. opw-6261272 Forward-Port-Of: odoo/odoo#269323
This fix restores filtering on the Apps > Industries page, so users can narrow down the app list by industry again. It matters because the industry catalog now behaves as expected and is easier to browse and find relevant apps.
Original PR description
Before this commit, no filter could be applied on Apps > Industries menu, because the module list returned by the appstore was difficult to filter as is. This commit uses the `new` command to create temporary ir.module.module such that any filtering domain can be applied, providing that the filter condition is available from the appstore controller. task-6067092 Forward-Port-Of: odoo/odoo#270005
This update prevents a crash when a Pine Labs payment is cancelled and the user then clicks Force Cancel. It ensures the POS safely finishes the cancellation flow even if the payment request has already moved to a retry state, improving checkout reliability.
Original PR description
**Step to Reproduce:** 1. Open the POS. 2. Add any product to the order. 3. Proceed to the payment screen and select `Pine Labs` as the payment method. 4. Observe that the Pine Labs terminal does not…
**Step to Reproduce:** 1. Open the POS. 2. Add any product to the order. 3. Proceed to the payment screen and select `Pine Labs` as the payment method. 4. Observe that the Pine Labs terminal does not respond and no payment popup appears on the device. 5. Wait until the payment request is cancelled (either manually or due to timeout). 6. Click the `Force Cancel` button. 7. Observe that the POS throws a traceback. **Video:** https://drive.google.com/file/d/1A3QPdby-J12IWgOX_SfCLrauQ_QnbqvG/view **Issue:** When a Pine Labs payment request is cancelled (either through a cancel request or by timeout), clicking the `Force Cancel` button results in a traceback in the POS. **Reason:** During the cancellation flow, the payment line status is updated to `retry` so that the transaction can be marked as cancelled and retried if necessary. Later, when the user clicks `Force Cancel`, `_paymentCancelRequestHandler()` attempts to retrieve the pending Pine Labs payment line using: ```javascript const line = this.pendingPineLabsPaymentLine(); ``` However, `pendingPineLabsPaymentLine()` only returns payment lines whose status is not `retry`, as defined here: https://github.com/odoo/odoo/blob/19.0/addons/point_of_sale/static/src/app/services/pos_store.js#L1820 Since the payment line was already transitioned to the `retry` state during the cancellation flow, no `payment line` is found and `line` becomes `undefined`. The handler subsequently attempts to update the status of this `undefined` `payment line`, resulting in the traceback when `Force Cancel` is executed. **Solution:** Add a condition in `_paymentCancelRequestHandler()` to verify that a payment line is available before attempting to update its status. If no payment line is found, it indicates that the payment line has already been moved to the `retry` state during a previous cancellation attempt. In such cases we clear `pollingTimeout`, `inactivityTimeout` and reset `this.payment_stopped` to `false`. This prevents the traceback while ensuring that the `Force Cancel` flow properly cleans up the pending payment state. opw-6297135 Forward-Port-Of: odoo/odoo#271397 Forward-Port-Of: odoo/odoo#271241
The Italian withholding tax return now calculates its closing balance independently from the regular tax return. This prevents the withholding return from incorrectly including amounts from other tax returns, so the payable balance shown to users is accurate.
Original PR description
Steps to reproduce: - setup an Italian company - make an invoice (for example in May) with a withholding tax and make a transaction to pay it - generate tax returns (opening date in June so that it generates from May) - validate regular tax return for May - validate withholding tax return for May -> The withholding tax return shows an amount to pay with a balance that is a combination of both the regular tax return and the withholding one, while it should be independent of the regular one. task-6116304 Forward-Port-Of: odoo/enterprise#119375
This update removes a warning generated when Odoo builds API documentation. It helps keep the documentation tools compatible with newer Docutils versions, reducing the risk of future breakage.
Original PR description
Using `Publisher.set_components()` triggers a `PendingDeprecationWarning` stating that the method will be removed in Docutils 2.0. This commit fixes the warning by passing the component names (`reader`, `parser`, and `writer`) directly into the `Publisher` constructor during instantiation, ensuring compatibility with upcoming Docutils versions. runbot-940246 Forward-Port-Of: odoo/odoo#272117
This update corrects an automated test in the French e-invoicing module so it works in environments where only the Invoicing app is installed. It prevents false test failures during builds and makes the module more reliable across different Odoo editions.
Original PR description
The `in_payment` state does not exist in community with only the Invoicing module installed. It is added in `enterprise` in the Accounting module. runbot.build.error-939451 Forward-Port-Of: odoo/odoo#267475
When sending invoices with a custom PDF report, the attached file will now keep the report’s own name instead of being mislabeled like the standard invoice document. This prevents duplicate-looking attachments and makes it easier for customers and teams to identify the correct file.
Original PR description
Steps to reproduce: * Install `l10n_mx_edi` (or `l10n_sa_edi`). * Go to **Accounting → Customers → Invoices**. * Open **Studio** and, from the top bar, go to **Reports**. * Duplicate the standard…
Steps to reproduce: * Install `l10n_mx_edi` (or `l10n_sa_edi`). * Go to **Accounting → Customers → Invoices**. * Open **Studio** and, from the top bar, go to **Reports**. * Duplicate the standard **Invoice PDF** report. * Open the duplicated report and make any modification to it. * Enable **Developer Mode**. * Go to **Settings → Technical → Actions → Reports** and update the custom report's **Printed Report Name**. * Go to **Settings → Technical → Email → Templates** and create a new invoice email template. * Add the custom report to the template's **Dynamic Reports**. * Create and confirm an invoice for a **Mexican company**. * Click **Send** and select the newly created email template. Observed behavior: * The custom report attachment uses the CFDI-based filename instead of its own report name, making it appear as a duplicate of the standard invoice attachment. Cause: * `_get_placeholder_mail_template_dynamic_attachments_data` relied on the `invoice_report` context key to pass the extra report into `_get_invoice_report_filename`. However, localization overrides (e.g. `l10n_mx_edi`, `l10n_sa_edi`) unconditionally return their own filename without checking the context, so the extra report's `print_report_name` was never evaluated. Fix: * Introduce `_get_invoice_mail_template_dynamic_report_filename` on `account.move` that directly evaluates a given report's `print_report_name`, bypassing the localization override chain. * Call this new method in `_get_placeholder_mail_template_dynamic_attachments_data` instead of the context-based `_get_invoice_report_filename` call. This avoids the need to patch every localization override and cleanly separates the concern of naming dynamic report attachments from the main invoice report filename logic. opw-6228268 Forward-Port-Of: odoo/odoo#271489
Employees with flexible schedules can now request a one-day time off on a public holiday when the time off type includes public holidays in its duration. This brings single-day requests in line with multi-day requests and prevents valid requests from being incorrectly rejected.
Original PR description
Currently, flexible employees can request a multi-day leave spanning a public holiday when the leave type includes public holidays in duration. However, requesting the public holiday date alone is…
Currently, flexible employees can request a multi-day leave spanning a public holiday when the leave type includes public holidays in duration. However, requesting the public holiday date alone is rejected. ### **Steps to reproduce:** - Create a public holiday. - Create a time off type with "Public Holiday Included" enabled. - Select/create an employee with a flexible work schedule and its time zone must be same as admin. - Request a time off on the public holiday date only. ### **Observed Behavior:** The request is rejected because its duration is computed as 0 days. ### **Expected Behavior:** The request should be allowed and count as 1 day, consistent with the multi-day request behavior. ### **Root Cause:** At [1], a dedicated duration computation path is used for single-day leaves of flexible employees. This logic always retrieves overlapping public holidays and computes the leave duration based on the remaining intervals. As a result, a leave requested entirely on a public holiday is computed as 0 days, even when `include_public_holidays_in_duration` is enabled. [1]- https://github.com/odoo/odoo/blob/242f6d3cf7288853f163ac6986a3b7aa4279efaf/addons/hr_holidays/models/hr_leave.py#L436-L444 ### **Fix:** This commit ensures that the `include_public_holidays_in_duration` setting is taken into account when computing single-day leave durations for flexible employees **opw-6284768** Forward-Port-Of: odoo/odoo#271795 Forward-Port-Of: odoo/odoo#269743
This fix ensures that when a payroll warning uses a domain condition, the default field updates correctly if the selected model changes. It prevents invalid conditions from being saved, avoiding the soft-lock error users could hit when leaving the Payroll app.
Original PR description
Previously when we create a domain-based payroll warning and add a condition, the domain condition is prefilled with the default field of the current selected model. However, if we change the model and try to add a condition, the domain default field does not get updated to match the selected model. When we save the warning record and leave the Payroll app, we'd get a soft-lock error message indicating a domain condition has an invalid field. To fix this, we made sure every time there's a change to the warning model, the domain default condition is reset to match the model. Task-5913501
This update prevents errors when Shopee sends customer identifiers that are larger than the system’s standard number range. For affected records, Odoo now uses an alternate customer reference field so contacts can still be created and matched correctly.
Original PR description
When the Shopee connector was introduced, Shopee documented `buyer_user_id` as an int32. We therefore store it in an `Integer` field, which maps to a PostgreSQL int32 column. However, feedback showed that Shopee can send ids exceeding the int32 bounds, leading to a traceback when creating new contacts. Shopee has since updated their documentation to confirm the field is actually an int64. Since we are in stable and cannot change the column type, this commit falls back to the `ref` field of the `res.partner` model to store and match Shopee contacts whose identifier doesn't fit within an int32. opw-6325948 See also: - master: https://github.com/odoo/enterprise/pull/121507 - upgrade: https://github.com/odoo/upgrade/pull/10578 Forward-Port-Of: odoo/enterprise#121498
This change stops the message recipient dropdown from offering a “Create” action when there is no meaningful text entered. It prevents accidental creation of empty contact records that appear as “Unnamed” and can later cause issues in Contacts.
Original PR description
The chatter recipients input always added a "Create" option to its autocomplete dropdown, even when the field held no text. The feature that introduced this input,…
The chatter recipients input always added a "Create" option to its autocomplete dropdown, even when the field held no text. The feature that introduced this input, https://github.com/odoo/odoo/commit/3b985d2c4239fe702c1a56bef04fc112af39e954, wired that option to create a res.partner straight away. Selecting "Create" with an empty input therefore created a partner with no name, displayed everywhere as "Unnamed". The email popover that opens for a recipient without an address then offered a Discard button, but the empty partner was already saved. The same sequence could be repeated to accumulate nameless contacts, which later raise a missing name error when opened in the Contacts app. Only add the "Create" option when the typed term resolves to a name or an email, in getAutoCompleteSources of recipients_input.js. An input with no usable text has nothing to create from, which matches the standard many2one autocomplete that only offers creation once text is entered. Steps to reproduce: 1. Open any record with a chatter 2. Click "Send message" 3. In the recipients field type a character then delete it, leaving the field empty with the dropdown still open 4. Click the "Create" option 5. On the "What's the email address of Unnamed?" popover, click Discard => A blank "Unnamed" contact is created, and repeating the steps creates more Ticket [link](https://www.odoo.com/odoo/action-4043/5942428) opw-5942428 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#250973
Attachments can now only be detached in cases where they are meant to be regenerated, such as outgoing invoice documents. This prevents incoming bill attachments from being removed by mistake, while keeping the special Italian tax integration flow working correctly for bulk exports.
Original PR description
The feature introduced in odoo/enterprise#78429 allows users to detach attachments from moves, primarily to facilitate the regeneration and re-sending of outgoing XMLs (e.g., sales invoices) without needing to delete the original attachment. However, detaching should not apply to incoming XML attachments on bills that originate from EDI import, as these attachments are the received source document and are never regenerated by the system. Detaching them inadvertently prevents their inclusion in bulk XML exports. An exception exists for Italy: businesses need to send Tax Integration XMLs back to the SdI. In this specific case, detaching the Tax Integration XML is appropriate and ensures the bulk export finds the latest, correct attachment. Ticket [link](https://www.odoo.com/odoo/project.task/5062132) opw-5062132 Forward-Port-Of: odoo/odoo#270896 Forward-Port-Of: odoo/odoo#239701
This update corrects several emoji-related issues in the editor, including removing leftover search text when an emoji is selected and improving backspace behavior on mobile devices. It helps ensure emoji replacement works more reliably and that the cursor stays in the right place for users typing on phones and tablets.
Original PR description
**Issue 1:** Step to reproduce: - Type ':wave' to open suggestion list - Now click on any emoji from the suggestion list Description of the issue: - The selected emoji gets inserted, but the…
**Issue 1:** Step to reproduce: - Type ':wave' to open suggestion list - Now click on any emoji from the suggestion list Description of the issue: - The selected emoji gets inserted, but the `searchNode` `:wave` does not get removed and remains beside the inserted emoji Cause: - When the user clicks an emoji from the suggestion list, focus shifts to the suggestion list item. As a result, `selection.extend()` is unable to properly select the searchNode in the editable area. Because the `searchNode` is not selected, `deleteSelection()` fails to remove it before inserting the emoji. Solution: - Added the `user-select-none` class to the suggestion list to prevent selection/focus shift on emoji click, ensuring the searchNode is properly selected and replaced by the selected emoji **Issue 2:** Steps to reproduce: - Open a To-do on a mobile device. - Type `:p` to create an emoji. - Press Backspace. Issue: - When using the SwiftKey keyboard, pressing Backspace after an emoji can result in an incorrect cursor position. Cause: - When Backspace is pressed, a selection snapshot is cached during the `keydown` event. - Later, `deleteBackward` converts the emoji back to its corresponding expression (:p) by triggering an undo operation, but the cached selection does not get updated. As a result, the previously cached selection is reused, causing the cursor to be placed incorrectly. Solution: - After performing the undo, update the cached selection to match the new cursor position. - This ensures that the latest selection is used instead of the outdated selection captured during `keydown`. **Issue 3:** Steps to reproduce: - Open a To-do on a mobile device. - Type `:p` to create an emoji. - Press Backspace. Issue: - Pressing Backspace on an emoji does not revert it to its matching expression (`:p`). Cause: - On mobile devices, `event.key` can be undefined in keydown. As a result, `deleteBackward` is triggered through the `beforeinput` event, which correctly reverts the emoji to its matching expression. However, after that, the `input` event is triggered and converts the expression back into the emoji again, making it appear as if the emoji was not reverted. Solution: - When the event type is `deleteContentBackward`, skip converting the expression back into an emoji and return early. task-6201173
This fix makes website popups respond correctly even when the show/hide toggle is clicked very quickly. It prevents the popup from getting stuck in the wrong visible state, which also avoids related errors when creating nested popups.
Original PR description
__To reproduce__ 1. Drop a popup on the website. 2. Click twice rapidly on the popup show/hide toggle in the sidebar. => The popup visibility will be in an inconsistent state compared to the toggle's…
__To reproduce__ 1. Drop a popup on the website. 2. Click twice rapidly on the popup show/hide toggle in the sidebar. => The popup visibility will be in an inconsistent state compared to the toggle's eye icon. __Reason__ Bootstrap ignores any call to show/hide if the popup is still transitioning. __Fix__ - Set `_isTransitioning` to `false` to trick Bootstrap into firing the event regardless of its current state. - When hide/show are triggered in quick succession, the modal can enter an inconsistent state with `.show` class but `display: none` style (hide removes `.show` immediately, show restores it with `display: block`, then hide applies `display: none` after animation). Dispatching `transitionend` event before resetting `_isTransitioning` ensures Bootstrap completes its state transitions. __Note__ This commit also fixes `custom_popup_snippet`, which fails non-deterministically with the following error: `TypeError: Cannot read properties of undefined (reading 'after')` This error occurs when trying to add a popup inside another popup that never closes due to this bug. runbot-939039
We fixed an unstable automated test in the chat experience so it no longer depends on a very brief screen state that could be missed. This makes the test results more consistent and reduces false failures during continuous integration runs.
Original PR description
The hoot `:text('X')` pseudo-class matches an element only when its whole inline text equals "X". `.o-mail-ChatWindow:text('slytherins')` therefore matched the chat window only during the brief frame where it showed nothing but its title, before the thread body (start message, composer) was rendered. Catching that frame is a race, so the assertion times out intermittently on runbot.
Assert against the title element itself: match with `.o-mail-ChatWindow-displayName:text('X')`. This is exact and no longer depends on the rest of the window being empty.
https://runbot.odoo.com/odoo/error/939914
Forward-Port-Of: odoo/odoo#272380This update corrects how Philippine tax reports identify transactions when grouped taxes are used. It ensures lines are included under the right tax tags, so report totals are more accurate and fewer transactions are missed.
Original PR description
When using group taxes, the base invoice lines only store the parent tax in the `account_move_line_account_tax_rel` table. Because of this, if a child tax within the group contains a specific tax report tag, the generic report query would previously fail to pick up those base lines. This commit updates the SQL join conditions in `l10n_ph_generic_report.py` to also match `account_tax.id` against the child taxes of the linked parent tax using the `account_tax_filiation_rel` table. This ensures that base lines are correctly reported under the tags of their respective child taxes. Task-6278098 Forward-Port-Of: odoo/enterprise#121876 Forward-Port-Of: odoo/enterprise#121596
15 changes
Enhancements to existing features
This update makes the contact email editable during registration, which helps users correct it if needed. It also strengthens the connection process to prevent impersonation and resets the KYC status when a participant is deregistered, so the registration can be started again cleanly.
Original PR description
It seems the readonly can cause some problem because the user might want to change it during the registration. Also adding the hash signed to the connect route to make sure nobody can impersonate the kyc Also clicking on the button_deregister_pdp_participant action will now reset the kyc status so that you can do it again if needed. task-626574 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#268833
Resolved issues and error corrections
This update prevents chat thread messages from getting stuck in an empty state after a reload. It ensures the conversation view refreshes correctly so users can see messages reliably.
Original PR description
The Thread component mirrors `thread.isLoaded` into the `state.mountedAndLoaded` flag that gates whether the real messages (as opposed to the empty phantom placeholder) are rendered. The mirroring…
The Thread component mirrors `thread.isLoaded` into the `state.mountedAndLoaded` flag that gates whether the real messages (as opposed to the empty phantom placeholder) are rendered. The mirroring effect both read `mountedAndLoaded` as a dependency and wrote it. `useEffect` records its dependency array before running the body, so right after the effect sets `mountedAndLoaded` to true the recorded dependencies still hold the pre-write pair `[isLoaded=true, mountedAndLoaded=false]`; that update only settles on a later, microtask-deferred patch. When a second reload runs `reset()` in that window, it drives `mountedAndLoaded` back to false while `isLoaded` stays true. The settling patch then computes the very `[true, false]` pair that was already recorded, so the effect never re-runs: `mountedAndLoaded` is stranded at false and no message is ever rendered. Depend on a monotonic `resetCount` bumped by `reset()` instead of on `mountedAndLoaded` itself. It is never written by the effect, so the recorded dependencies can no longer match the current ones after a reset and the effect always re-runs to re-sync `mountedAndLoaded` with `isLoaded`. `reset()` keeps clearing `mountedAndLoaded` as before (the false dip is needed for the reload scroll handshake), so the behaviour is otherwise unchanged. https://runbot.odoo.com/odoo/error/940032
This fix prevents the product page from switching to an unrelated item when a product recommendation block is placed above the variant selector. It ensures the page always uses the main product’s information, so customers see the correct image and price when choosing variants.
Original PR description
When a "Products" snippet is dropped above the variant selector on a product page, selecting a variant displays one of the snippet's products instead of the chosen variant (its image/price take over…
When a "Products" snippet is dropped above the variant selector on a product page, selecting a variant displays one of the snippet's products instead of the chosen variant (its image/price take over the page).
Steps to reproduce
===================
1. Create a product with 2+ variants and publish it.
2. Edit the product page, drag any block above the variant selector and add the "Products" dynamic snippet, then save.
3. Select a variant. => The page shows the snippet's first product instead of the variant.
Root cause
==========
`ProductPage._getCombinationInfo` reads the product ids from `parent.querySelector('button[name="add_to_cart"]')`, with `parent` being the whole `.js_product`. `querySelector` returns the first match in DOM order, and the dynamic "Products" snippet's cards reuse the same `button[name="add_to_cart"]` markup with their own product ids. When the snippet sits above the variants, its button comes first, so `/website_sale/get_combination_info` is called with the snippet product's ids and the page is updated with that product's data.
The interaction was introduced in saas-19.1 (See [1]) and the lookup switched from the unique `#add_to_cart` id to the by-name selector in (See [2]), which is what started matching the snippet's cards.
Fix
===
Pick the first `add_to_cart` button that is not inside a product card (`.oe_product_cart`), i.e. the main product's button.
[1]: https://github.com/odoo/odoo/commit/4682748e6e3c#diff-7e1a99da9e95d0c4df79ee4d7aa718e46bcb8b7f1ed78cde58782e075c833cd1R326
[2]: https://github.com/odoo/odoo/commit/1c732cf75a4a4faa960d6a98f08ae9dbe99b2b69#diff-7e1a99da9e95d0c4df79ee4d7aa718e46bcb8b7f1ed78cde58782e075c833cd1R329
opw-6248285
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThis update prevents down payments made through Point of Sale from being counted twice when creating the final customer invoice. As a result, the remaining amount to invoice stays accurate and no longer drops below zero in this scenario.
Original PR description
Steps to reproduce --- 1. Create and confirm a sale order 2. In the POS, settle it with a down payment and invoice the down payment 3. From the sale order, create and post the final invoice Issue --- The order ends up with a negative amount to invoice. The pos_sale override https://github.com/odoo/odoo/blob/a1bcd917846493d08dd02b63e6110078ff5156a3/addons/pos_sale/models/sale_order.py#L83-L88 always subtracts the amount paid in the POS, which is required before the final invoice because the down payment sits on a separate line the base computation ignores; but once the final invoice is posted that down payment is already deducted through its negated line, so subtracting it again counts it twice and pushes amount to invoice below zero. opw-6261272 Forward-Port-Of: odoo/odoo#269323
The Apps > Industries page can now be filtered properly. This fixes an issue where the available app list could not be narrowed down by filter, making it harder to find relevant apps.
Original PR description
Before this commit, no filter could be applied on Apps > Industries menu, because the module list returned by the appstore was difficult to filter as is. This commit uses the `new` command to create temporary ir.module.module such that any filtering domain can be applied, providing that the filter condition is available from the appstore controller. task-6067092 Forward-Port-Of: odoo/odoo#270005
The Unit Cost History report now shows quantities using the product’s own unit of measure, instead of incorrectly using the move’s unit. This prevents inflated quantities and added values in the report when materials are consumed in a different unit than the product is tracked in.
Original PR description
**Issue** The quantity displayed in the Unit Cost History report can be incorrect when the move UoM differs from the product UoM. **Steps to reproduce** - Create an AVCO product Comp tracked in tons…
**Issue** The quantity displayed in the Unit Cost History report can be incorrect when the move UoM differs from the product UoM. **Steps to reproduce** - Create an AVCO product Comp tracked in tons with a unit price of 100. - Create another product with a BoM consuming 100kg of Comp - Create, confirm and produce a MO for that product - Open the Unit Cost History for Comp -> Quantity is incorrect (100 instead of 0.1). As a consequence, the computed added value displayed in the report is also incorrect (10000 instead of 10). **Cause** The quantity and added value fields come from the `stock.avco.report` model, which is defined by this SQL view: https://github.com/odoo/odoo/blob/aef190dbff365f4fe5d92a2c41c35f92b66ce5fd/addons/stock_account/report/stock_avco_audit_report.py#L36-L39 The view uses the `quantity` field of `stock.move`: https://github.com/odoo/odoo/blob/aef190dbff365f4fe5d92a2c41c35f92b66ce5fd/addons/stock_account/report/stock_avco_audit_report.py#L48 without converting it in the right uom opw-6271229 Forward-Port-Of: odoo/odoo#269846
This change prevents a crash in the Point of Sale when a Pine Labs payment is cancelled and the user clicks Force Cancel afterward. It improves the cancellation flow so the POS cleans up correctly instead of showing an error.
Original PR description
**Step to Reproduce:** 1. Open the POS. 2. Add any product to the order. 3. Proceed to the payment screen and select `Pine Labs` as the payment method. 4. Observe that the Pine Labs terminal does not…
**Step to Reproduce:** 1. Open the POS. 2. Add any product to the order. 3. Proceed to the payment screen and select `Pine Labs` as the payment method. 4. Observe that the Pine Labs terminal does not respond and no payment popup appears on the device. 5. Wait until the payment request is cancelled (either manually or due to timeout). 6. Click the `Force Cancel` button. 7. Observe that the POS throws a traceback. **Video:** https://drive.google.com/file/d/1A3QPdby-J12IWgOX_SfCLrauQ_QnbqvG/view **Issue:** When a Pine Labs payment request is cancelled (either through a cancel request or by timeout), clicking the `Force Cancel` button results in a traceback in the POS. **Reason:** During the cancellation flow, the payment line status is updated to `retry` so that the transaction can be marked as cancelled and retried if necessary. Later, when the user clicks `Force Cancel`, `_paymentCancelRequestHandler()` attempts to retrieve the pending Pine Labs payment line using: ```javascript const line = this.pendingPineLabsPaymentLine(); ``` However, `pendingPineLabsPaymentLine()` only returns payment lines whose status is not `retry`, as defined here: https://github.com/odoo/odoo/blob/19.0/addons/point_of_sale/static/src/app/services/pos_store.js#L1820 Since the payment line was already transitioned to the `retry` state during the cancellation flow, no `payment line` is found and `line` becomes `undefined`. The handler subsequently attempts to update the status of this `undefined` `payment line`, resulting in the traceback when `Force Cancel` is executed. **Solution:** Add a condition in `_paymentCancelRequestHandler()` to verify that a payment line is available before attempting to update its status. If no payment line is found, it indicates that the payment line has already been moved to the `retry` state during a previous cancellation attempt. In such cases we clear `pollingTimeout`, `inactivityTimeout` and reset `this.payment_stopped` to `false`. This prevents the traceback while ensuring that the `Force Cancel` flow properly cleans up the pending payment state. opw-6297135 Forward-Port-Of: odoo/odoo#271397 Forward-Port-Of: odoo/odoo#271241
When a pricelist uses a fixed price, Odoo now hides the extra price badge for product variants in both Sales and Website Sales. This avoids showing an additional price that does not actually affect the final price, making pricing information clearer for users and customers.
Original PR description
Issue: --- If pricelist.compute_price is fixed, extra price of variant is not taken into calculation, but it's shown in extra price badge. Steps to reproduce: --- 1- Create a product template with two variants. 2- Apply extra price for each attribute values. 3- Apply a pricing with a fixed price for the product on a pricelist. 4- Create a SO and apply the pricelist. Add the product to SOL. 5- Open product configurator on SOL. - As you see, the extra price is shown but it's not effective. 6- Open the product in website with the pricelist. - Here also the extra price is shown but it's not effective. Cause: --- This is caused because there is no mechanism to hide extra price having pricelist.compute_price == fixed. Fix: --- We need to fix the issue both in sale and website_sale separately by having a flag to ensure extra price badge is hidden if compute_price is fixed. opw-6276208 Forward-Port-Of: odoo/odoo#270140
This change updates the internal documentation generation process to avoid a warning from a third-party library. It helps ensure the feature continues to work smoothly with newer library versions and reduces the risk of future compatibility issues.
Original PR description
Using `Publisher.set_components()` triggers a `PendingDeprecationWarning` stating that the method will be removed in Docutils 2.0. This commit fixes the warning by passing the component names (`reader`, `parser`, and `writer`) directly into the `Publisher` constructor during instantiation, ensuring compatibility with upcoming Docutils versions. runbot-940246 Forward-Port-Of: odoo/odoo#272117
This update corrects an automated test for the French e-invoicing feature so it no longer expects a payment status that is only available in the Enterprise accounting app. It helps ensure the Community version builds and tests successfully when only Invoicing is installed.
Original PR description
The `in_payment` state does not exist in community with only the Invoicing module installed. It is added in `enterprise` in the Accounting module. runbot.build.error-939451 Forward-Port-Of: odoo/odoo#267475
This fix prevents contact creation errors when Shopee sends buyer identifiers that are larger than the previous system limit. If an ID does not fit in the usual field, it is now stored in an alternate contact reference so Shopee customers can still be matched correctly.
Original PR description
When the Shopee connector was introduced, Shopee documented `buyer_user_id` as an int32. We therefore store it in an `Integer` field, which maps to a PostgreSQL int32 column. However, feedback showed that Shopee can send ids exceeding the int32 bounds, leading to a traceback when creating new contacts. Shopee has since updated their documentation to confirm the field is actually an int64. Since we are in stable and cannot change the column type, this commit falls back to the `ref` field of the `res.partner` model to store and match Shopee contacts whose identifier doesn't fit within an int32. opw-6325948 See also: - master: https://github.com/odoo/enterprise/pull/121507 - upgrade: https://github.com/odoo/upgrade/pull/10578 Forward-Port-Of: odoo/enterprise#121498
This fix stops the messaging recipient picker from offering a Create action when there is no meaningful text entered. It prevents accidental creation of blank “Unnamed” contacts, avoiding clutter and later errors when those contacts are opened.
Original PR description
The chatter recipients input always added a "Create" option to its autocomplete dropdown, even when the field held no text. The feature that introduced this input,…
The chatter recipients input always added a "Create" option to its autocomplete dropdown, even when the field held no text. The feature that introduced this input, https://github.com/odoo/odoo/commit/3b985d2c4239fe702c1a56bef04fc112af39e954, wired that option to create a res.partner straight away. Selecting "Create" with an empty input therefore created a partner with no name, displayed everywhere as "Unnamed". The email popover that opens for a recipient without an address then offered a Discard button, but the empty partner was already saved. The same sequence could be repeated to accumulate nameless contacts, which later raise a missing name error when opened in the Contacts app. Only add the "Create" option when the typed term resolves to a name or an email, in getAutoCompleteSources of recipients_input.js. An input with no usable text has nothing to create from, which matches the standard many2one autocomplete that only offers creation once text is entered. Steps to reproduce: 1. Open any record with a chatter 2. Click "Send message" 3. In the recipients field type a character then delete it, leaving the field empty with the dropdown still open 4. Click the "Create" option 5. On the "What's the email address of Unnamed?" popover, click Discard => A blank "Unnamed" contact is created, and repeating the steps creates more Ticket [link](https://www.odoo.com/odoo/action-4043/5942428) opw-5942428 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#250973
Invoices sent with a custom attached report will now use that report’s own file name instead of inheriting the standard invoice naming used by certain localizations. This prevents duplicate-looking attachments and makes customer emails easier to understand.
Original PR description
Steps to reproduce: * Install `l10n_mx_edi` (or `l10n_sa_edi`). * Go to **Accounting → Customers → Invoices**. * Open **Studio** and, from the top bar, go to **Reports**. * Duplicate the standard…
Steps to reproduce: * Install `l10n_mx_edi` (or `l10n_sa_edi`). * Go to **Accounting → Customers → Invoices**. * Open **Studio** and, from the top bar, go to **Reports**. * Duplicate the standard **Invoice PDF** report. * Open the duplicated report and make any modification to it. * Enable **Developer Mode**. * Go to **Settings → Technical → Actions → Reports** and update the custom report's **Printed Report Name**. * Go to **Settings → Technical → Email → Templates** and create a new invoice email template. * Add the custom report to the template's **Dynamic Reports**. * Create and confirm an invoice for a **Mexican company**. * Click **Send** and select the newly created email template. Observed behavior: * The custom report attachment uses the CFDI-based filename instead of its own report name, making it appear as a duplicate of the standard invoice attachment. Cause: * `_get_placeholder_mail_template_dynamic_attachments_data` relied on the `invoice_report` context key to pass the extra report into `_get_invoice_report_filename`. However, localization overrides (e.g. `l10n_mx_edi`, `l10n_sa_edi`) unconditionally return their own filename without checking the context, so the extra report's `print_report_name` was never evaluated. Fix: * Introduce `_get_invoice_mail_template_dynamic_report_filename` on `account.move` that directly evaluates a given report's `print_report_name`, bypassing the localization override chain. * Call this new method in `_get_placeholder_mail_template_dynamic_attachments_data` instead of the context-based `_get_invoice_report_filename` call. This avoids the need to patch every localization override and cleanly separates the concern of naming dynamic report attachments from the main invoice report filename logic. opw-6228268 Forward-Port-Of: odoo/odoo#271489
The Italian Ri.Ba. payment flow now checks that the company SIA code is exactly 5 digits long. This prevents batch payment validation from crashing during XML generation when the code was entered with too many characters.
Original PR description
Currently, the sia_code field on res.company lacks length validation. For Italian Ri.Ba (CBI) exports, this field MUST be exactly 5 characters. If a user enters more (e.g., during initial setup), the Batch Payment validation (specifically the XML file generation) crashes with a traceback. Steps to Reproduce: - Set Company SIA Code to 6+ characters - Create multiple payments with Ri.Ba. method - Create a Ri.Ba Batch Payment - Click 'Validate' Ticket [link](https://www.odoo.com/odoo/project.task/6031062) opw-6031062 Forward-Port-Of: odoo/enterprise#121610
This fix prevents a recursion error when opening or processing very large invoices with many section lines. It keeps parent-line updates limited to the current compute batch, avoiding repeated recomputations and improving reliability for complex invoices.
Original PR description
Since PR #223686, `parent_id` became a non-stored field. On complex invoices with many sections, assigning `parent_id` to lines outside the current compute batch in `_compute_parent_id` triggers unwanted cascading recomputes. **Steps to reproduce:** 1. Create an invoice with 200+ sections and at least one product per section. 2. Read `parent_id` for any line. 3. "RecursionError: maximum recursion depth exceeded" is raised. **Fix:** Only assign `parent_id` to lines within the protected compute batch. opw-6302149 Forward-Port-Of: odoo/odoo#271350
3 changes
Resolved issues and error corrections
Shopee can send customer identifiers that are larger than the previous limit, which could cause an error when creating new contacts. This update safely stores and matches those larger identifiers in an alternate contact reference field so Shopee orders and customers continue to sync properly.
Original PR description
When the Shopee connector was introduced, Shopee documented `buyer_user_id` as an int32. We therefore store it in an `Integer` field, which maps to a PostgreSQL int32 column. However, feedback showed that Shopee can send ids exceeding the int32 bounds, leading to a traceback when creating new contacts. Shopee has since updated their documentation to confirm the field is actually an int64. Since we are in stable and cannot change the column type, this commit falls back to the `ref` field of the `res.partner` model to store and match Shopee contacts whose identifier doesn't fit within an int32. opw-6325948 See also: - master: https://github.com/odoo/enterprise/pull/121507 - upgrade: https://github.com/odoo/upgrade/pull/10578 Forward-Port-Of: odoo/enterprise#121498
This update ensures the company SIA code used for Italian Ri.Ba. exports is exactly 5 characters long. It prevents batch payment validation from failing with an error when the code is too long, making the payment export process more reliable.
Original PR description
Currently, the sia_code field on res.company lacks length validation. For Italian Ri.Ba (CBI) exports, this field MUST be exactly 5 characters. If a user enters more (e.g., during initial setup), the Batch Payment validation (specifically the XML file generation) crashes with a traceback. Steps to Reproduce: - Set Company SIA Code to 6+ characters - Create multiple payments with Ri.Ba. method - Create a Ri.Ba Batch Payment - Click 'Validate' Ticket [link](https://www.odoo.com/odoo/project.task/6031062) opw-6031062 Forward-Port-Of: odoo/enterprise#121610
This change fixes an error that could appear when opening a billing target in the Timesheets app. It ensures the required employee leave information is available, so users can view billing targets without the page failing.
Original PR description
Prerequisites to reproduce: - Enable `Billing Rate Indicators` in timesheets. - Change timesheet access of user to `User: all timesheets` - Remove Employee access Steps to Reproduce: - In Timesheets app, from configuration go to `Billing Time Targets` - Click on view button on any row Issue: - A traceback breaking the flow. Reason: - We use `hr_presence_status` widget which requires `leave_date_to` and `current_leave_id` field, change made from odoo/odoo@0496ed1 and https://github.com/odoo/odoo/commit/4b5089694436aa00254666e10cd2106b21adfe2b - Thus unavailability of field causing the traceback. Fix: - Add a related field for leave_date_to from which we get the value. Forward-Port-Of: odoo/enterprise#121571
10 changes
Enhancements to existing features
This update makes PDP registration more flexible by allowing the contact email to be changed during signup. It also strengthens protection against identity misuse during the connection process and lets users restart the KYC verification if a deregistration is needed.
Original PR description
It seems the readonly can cause some problem because the user might want to change it during the registration. Also adding the hash signed to the connect route to make sure nobody can impersonate the kyc Also clicking on the button_deregister_pdp_participant action will now reset the kyc status so that you can do it again if needed. task-626574 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#268833
Resolved issues and error corrections
This change prevents an error that could happen when users add properties to a record, especially when related fields need extra loading time. The interface now waits for the required data before showing the properties form, making the action more reliable and avoiding interruptions.
Original PR description
Description of the issue/feature this PR addresses: This error occurs when a model has properties and a `computed` field or `onchange` method depends on them. `record.update()` is asynchronous. When…
Description of the issue/feature this PR addresses: This error occurs when a model has properties and a `computed` field or `onchange` method depends on them. `record.update()` is asynchronous. When an onchange or computed field is triggered, an additional request is sent to the server, increasing the time required to complete the update. See: https://github.com/odoo/odoo/blob/727fe7412bb37c1664106625e248264d2aab6809/addons/web/static/src/model/relational_model/record.js#L1207-L1211 However, `PropertiesField` is rendered before the `update` is completed. See: https://github.com/odoo/odoo/blob/727fe7412bb37c1664106625e248264d2aab6809/addons/web/static/src/views/fields/properties/properties_field.js#L86 As a result, the property labels are not yet available and the following traceback is raised: `TypeError: Cannot read properties of undefined (reading 'getRootNode') ` After this commit, the update is awaited before rendering PropertiesField, ensuring that the property labels are available. **Steps to reproduce:** 1. Install the example module. [project_task_property.zip](https://github.com/user-attachments/files/29138424/project_task_property.zip) 2. Open or create a project task. 3. From the Action menu, click `Add Properties`. The error is raised. <img width="1520" height="956" alt="image" src="https://github.com/user-attachments/assets/a3051ddf-5af0-4d3a-8ff7-c3fb4f7a69d2" /> TT63331 @Tecnativa @pedrobaeza --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271894 Forward-Port-Of: odoo/odoo#271082
This update prevents a POS error when a Pine Labs payment is cancelled and the cashier clicks Force Cancel. The POS now handles this case safely, so the payment screen closes cleanly instead of showing a traceback.
Original PR description
**Step to Reproduce:** 1. Open the POS. 2. Add any product to the order. 3. Proceed to the payment screen and select `Pine Labs` as the payment method. 4. Observe that the Pine Labs terminal does not…
**Step to Reproduce:** 1. Open the POS. 2. Add any product to the order. 3. Proceed to the payment screen and select `Pine Labs` as the payment method. 4. Observe that the Pine Labs terminal does not respond and no payment popup appears on the device. 5. Wait until the payment request is cancelled (either manually or due to timeout). 6. Click the `Force Cancel` button. 7. Observe that the POS throws a traceback. **Video:** https://drive.google.com/file/d/1A3QPdby-J12IWgOX_SfCLrauQ_QnbqvG/view **Issue:** When a Pine Labs payment request is cancelled (either through a cancel request or by timeout), clicking the `Force Cancel` button results in a traceback in the POS. **Reason:** During the cancellation flow, the payment line status is updated to `retry` so that the transaction can be marked as cancelled and retried if necessary. Later, when the user clicks `Force Cancel`, `_paymentCancelRequestHandler()` attempts to retrieve the pending Pine Labs payment line using: ```javascript const line = this.pendingPineLabsPaymentLine(); ``` However, `pendingPineLabsPaymentLine()` only returns payment lines whose status is not `retry`, as defined here: https://github.com/odoo/odoo/blob/19.0/addons/point_of_sale/static/src/app/services/pos_store.js#L1820 Since the payment line was already transitioned to the `retry` state during the cancellation flow, no `payment line` is found and `line` becomes `undefined`. The handler subsequently attempts to update the status of this `undefined` `payment line`, resulting in the traceback when `Force Cancel` is executed. **Solution:** Add a condition in `_paymentCancelRequestHandler()` to verify that a payment line is available before attempting to update its status. If no payment line is found, it indicates that the payment line has already been moved to the `retry` state during a previous cancellation attempt. In such cases we clear `pollingTimeout`, `inactivityTimeout` and reset `this.payment_stopped` to `false`. This prevents the traceback while ensuring that the `Force Cancel` flow properly cleans up the pending payment state. opw-6297135 Forward-Port-Of: odoo/odoo#271397 Forward-Port-Of: odoo/odoo#271241
The disconnect button for French electronic invoicing was renamed to use the correct wording. This makes the interface clearer and avoids confusion with Peppol terminology.
Original PR description
The name of the disconnect button for the France e-invoicing was incorrect as it referenced peppol and was fixed in this pr to be called Disconnect French electronic invoicing task-6266337 Forward-Port-Of: odoo/odoo#268536
This update fixes a test used for French PDP documents so it works in databases where only the Invoicing app is installed. It prevents build failures in standard community setups by avoiding a state that is only available with the full Accounting app.
Original PR description
The `in_payment` state does not exist in community with only the Invoicing module installed. It is added in `enterprise` in the Accounting module. runbot.build.error-939451 Forward-Port-Of: odoo/odoo#267475
The Shopee connector now handles buyer identifiers that are larger than the previously expected limit, avoiding errors when creating customer records. This ensures Shopee orders continue to sync correctly even when Shopee sends very large buyer IDs.
Original PR description
When the Shopee connector was introduced, Shopee documented `buyer_user_id` as an int32. We therefore store it in an `Integer` field, which maps to a PostgreSQL int32 column. However, feedback showed that Shopee can send ids exceeding the int32 bounds, leading to a traceback when creating new contacts. Shopee has since updated their documentation to confirm the field is actually an int64. Since we are in stable and cannot change the column type, this commit falls back to the `ref` field of the `res.partner` model to store and match Shopee contacts whose identifier doesn't fit within an int32. opw-6325948 See also: - master: https://github.com/odoo/enterprise/pull/121507 - upgrade: https://github.com/odoo/upgrade/pull/10578 Forward-Port-Of: odoo/enterprise#121498
The chatter recipient picker will no longer offer the option to create a new contact when there is no real name or email entered. This avoids accidentally saving empty contacts that later appear as “Unnamed” and can cause problems in the Contacts app.
Original PR description
The chatter recipients input always added a "Create" option to its autocomplete dropdown, even when the field held no text. The feature that introduced this input,…
The chatter recipients input always added a "Create" option to its autocomplete dropdown, even when the field held no text. The feature that introduced this input, https://github.com/odoo/odoo/commit/3b985d2c4239fe702c1a56bef04fc112af39e954, wired that option to create a res.partner straight away. Selecting "Create" with an empty input therefore created a partner with no name, displayed everywhere as "Unnamed". The email popover that opens for a recipient without an address then offered a Discard button, but the empty partner was already saved. The same sequence could be repeated to accumulate nameless contacts, which later raise a missing name error when opened in the Contacts app. Only add the "Create" option when the typed term resolves to a name or an email, in getAutoCompleteSources of recipients_input.js. An input with no usable text has nothing to create from, which matches the standard many2one autocomplete that only offers creation once text is entered. Steps to reproduce: 1. Open any record with a chatter 2. Click "Send message" 3. In the recipients field type a character then delete it, leaving the field empty with the dropdown still open 4. Click the "Create" option 5. On the "What's the email address of Unnamed?" popover, click Discard => A blank "Unnamed" contact is created, and repeating the steps creates more Ticket [link](https://www.odoo.com/odoo/action-4043/5942428) opw-5942428 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#250973
Employees can now submit expenses even when they do not have a manager assigned. They can also continue to add attachments and reply in the expense chatter after submission, which helps them provide missing proof or answer follow-up questions without needing edit access.
Original PR description
# [FIX] hr_expense: Submitting an expense without a manager doesn't work If a user tries to submit an expense without having a manager, this will fail with "You are neither a Manager nor a HR Officer". To fix this, we are not going to check when the manager is the user that expense is linked to. --------- # [FIX] hr_expense: Employee cant use chatter on his own expenses An employee that created his expense was only able to add attachments and post message in the chatter when the expense was in draft. After this, it will still be able to attach attachment and post message without having the right to edit the expense. This is better as the employee will be able to answer questions that have been asked or add more proof if required. [task-4966942](https://www.odoo.com/odoo/all-tasks/4966942) Forward-Port-Of: odoo/odoo#224575
The company SIA code used for Italian Ri.Ba. payments is now validated to be exactly 5 digits. This prevents batch payment validation from failing later with an error when the code is too long.
Original PR description
Currently, the sia_code field on res.company lacks length validation. For Italian Ri.Ba (CBI) exports, this field MUST be exactly 5 characters. If a user enters more (e.g., during initial setup), the Batch Payment validation (specifically the XML file generation) crashes with a traceback. Steps to Reproduce: - Set Company SIA Code to 6+ characters - Create multiple payments with Ri.Ba. method - Create a Ri.Ba Batch Payment - Click 'Validate' Ticket [link](https://www.odoo.com/odoo/project.task/6031062) opw-6031062 Forward-Port-Of: odoo/enterprise#121610
This update makes Odoo correctly find invoice XML files whether they are directly in the ZIP or inside nested ZIP files. It prevents errors when sending invoices to Viettel S-Invoice, so invoice delivery completes more reliably.
Original PR description
Description of the issue/feature this PR addresses: The actual XML extraction hardcoded the double-zipped case by reading only the first entry of the outer zip (`zip_file.infolist()[0]`), assuming it…
Description of the issue/feature this PR addresses: The actual XML extraction hardcoded the double-zipped case by reading only the first entry of the outer zip (`zip_file.infolist()[0]`), assuming it was always a nested zip containing the XML. This made it fail when: - The XML was directly in the outer zip (single-zipped). - The zip contained multiple files and the first nested zip didn't hold the XML. Current behavior before PR: After sending an Invoice to Viettel S-Invoice, the e-Invoicing platform would return a ZIP containing one XML file. The XML File being double-unzipped, a traceback is raised. Desired behavior after PR is merged: The fix rewrites _recursive_zip_xml_file_data to actually be recursive. Invoices can be sent to Viettel S-Invoice without raising a traceback. opw-[6249929](https://www.odoo.com/odoo/project.task/6249929?debug=1) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272121 Forward-Port-Of: odoo/odoo#268482
12 changes
New functionality added to Odoo
This update adds an MCP server so Odoo can connect to AI clients like Gemini CLI, Claude Code, and n8n. It lets approved users read data, generate summaries, and create or update records through their normal Odoo permissions, enabling more advanced automated workflows.
Original PR description
[ADD] ai_mcp: add Odoo MCP server Purpose: To give users the ability to connect odoo to any MCP client (Gemini CLI, Claude Code, n8n, etc) and to make them able to define complex automations using…
[ADD] ai_mcp: add Odoo MCP server
Purpose:
To give users the ability to connect odoo to any MCP client (Gemini CLI, Claude Code, n8n, etc) and to make them able to define complex automations using LLMs.
Capabilities:
- Read: The MCP server provides search and read_group tools to allow MCP clients to read data and generate summaries/analytics.
- Write: The MCP server provides the write tool to allow MCP clients to create and update records in the database.
How to use
- The user has to generate an API key which is used to authenticate the user so that the MCP server can execute tools based on user permissions.
- Login into Odoo with your username and password.
- Click on the user image on the top right.
- Go to My preferences and then select the Security tab.
- Click on Add Api Key to generate the API key. Choose the scope as MCP.
- To connect to the MCP server, you will add the following to the MCP client config. Replace the database_url with the url of your Odoo database and api_key with the API key generated in step 1. The structure can change a bit based on the MCP client but you will always need the URL and headers.
```json
{
"mcpServers": {
"Odoo": {
"type": "http",
"url": "<database_url>/mcp",
"headers": {
"Authorization": "Bearer <api_key>"
}
}
}
}
```
This commit introduces a dedicated bearer_mcp auth method on the MCP HTTP route that validates API keys strictly against scope='mcp', preventing RPC-scoped tokens from accessing the MCP server and vice versa.
This commit also adds an access check to _ai_tool_get_fields to make sure that the current user has access to the model before retrieving the fields.
Community PR: https://github.com/odoo/odoo/pull/268589
Upgrade PR: https://github.com/odoo/upgrade/pull/10432
task-6139938Enhancements to existing features
The Korean Balance Sheet and Profit & Loss reports have been rebuilt to match the new chart of accounts. This helps ensure financial statements stay accurate and consistent with the latest accounting structure.
Original PR description
Rebuild the Korean Balance Sheet and Profit & Loss on top of the new chart of accounts. Community PR: https://github.com/odoo/odoo/pull/268170 Upgrade PR: https://github.com/odoo/upgrade/pull/10397 task-6246407
The manufacturing shop floor and barcode screens now use the same updated wording as the main manufacturing flow, replacing “Close Production” with “Produce” where appropriate. This keeps the user experience consistent and makes the action clearer for operators, especially when completing work orders or handling backorders.
Original PR description
~~Now that we distinguish 'Close Production' and 'Produce Partially' (qv odoo/odoo#260322), we need to adapt the logic to the barcode module as well. This is mostly just a matter of attaching the `skip_backorder` and `close_production` context parameters passed to the action, with the rest being cosmetic changes and adjustments to tests that expect the consumption warning wizard or a different button.~~ ~~Now that the original spec was scrapped, we just rename 'Close Production' to 'Produce' and implement a separate backorder wizard for workorders.~~ Scratch that. We go back to using the same wizard, just a different form view. Task ID: [5901969](https://www.odoo.com/odoo/my-tasks/5901969)
The Belgian payroll rules were updated to reflect the new 2024 economic unemployment daily compensation amount. This keeps payroll calculations aligned with the latest official values and helps ensure correct employee compensation handling.
Original PR description
Update 2024 economic unemployment daily compensation salary rule parameter value to 2.0 task-6334026
The payroll rules for the Belgian mobility contribution are now calculated with dynamic parameters, which makes the calculation more accurate and easier to maintain. The DMFA PDF report was also aligned with the XML version by adding the missing occupation information, helping ensure consistency in submitted payroll documents.
Original PR description
This fix allows the mobility contribution 869 rule to be calculated using dynamic parameters Add the missing occupation informations in the dmfa pdf exaclty as dmfa xml Task Id: 6259967
When a quotation is created from a planning slot linked to a project, the related project is now selected automatically. This ensures the correct cost allocation is applied without extra manual steps, saving time and reducing the chance of errors.
Original PR description
When a quotation is created from a planning slot linked to a project, the analytic distribution is not set automatically and the user has to select it manually. This commit sets the project by default so that the analytic distribution of the selected project is automatically applied. task-4644787
The softphone contact list is now cleaner and easier to use, with better search results and no unnecessary grouping by first letter. Users can also search contacts by email correctly, and the keypad’s extended search view now matches the main address book experience, including highlighted matches and editable searches. This makes finding the right contact faster and less confusing.
Original PR description
[IMP] voip: remove grouping by initial in softphone contacts listing This commit keeps the alphabetical / phone sort, but no useless groups anymore. Idea: it was only to have a "pretty" listing but…
[IMP] voip: remove grouping by initial in softphone contacts listing
This commit keeps the alphabetical / phone sort, but no useless groups
anymore. Idea: it was only to have a "pretty" listing but it will
prevent more advanced sorting to make sense in the future (e.g. showing
most called contacts first). This also simply improves Owl performance
as a bonus.
[IMP] voip: use AddressBook for keypad "more" searches
Before this commit, the keypad component was implementing its own
contact searches, with unsorted results. Indeed, with the demo data,
search "m" would for example have "Mitchell Admin" first, because it
was loaded first by discuss for the presence status, then the rest of
the contacts having "m" in their name.
The "more" keypad search view now uses the AddressBook component,
sharing the UI and its features.
The keypad "more" view had 2 extra differences though:
- Search match highlighting
- T9 searches
Those 2 features are now added in the AddressBook component.
Bonus: while in the "more" keypad view, you can now edit the search.
[IMP] voip: (really) allow contact search by email
Before this commit, when a contact was searched in the softphone,
contacts were loaded in the store based on their name, phone... and
email. But then the softphone filtered the store contacts by name and
phone... but not email. This lead to this weird behavior:
- Have a contact zzz with email yyy@example.com
- Have 50 contacts alphabetically before zzz
- Search "y" => You don't see zzz
- Remove the "y" search
=> You see 13 contacts + zzz (because it was loaded before)... if you
scroll, contacts will appears between the 13 contacts and zzz.
Now, you will at least see zzz during the "y" search making the last
step less confusing, and allowing to actually take profit of the search
by email that is already done loading-wise.
Note that this is also a first step towards fixing problems introduced
by [1] a long time ago, when the softphone used the Store to gather the
loaded contacts, while before the tab components themselves were in
charge of loading and displaying the loaded contacts.
[1]: https://github.com/odoo/enterprise/commit/bbdb033031720365c448c6f3de40906ee0c4243e
task-5871346Resolved issues and error corrections
Reporting menu items that were previously visible with only the Invoicing app are now available only when the Accounting app is installed. This keeps the Invoicing experience simpler and ensures users see only the reports relevant to their setup.
Original PR description
The invoicing app provides access to many reports which are not needed for the purposes related to invoicing. These reports have been moved to only be accessible if the accounting app is installed instead of being available by default with just the invoicing app. task-6298711
The Total Comprehensive Income line in Hong Kong financial reports was not appearing in some cases when it should have been shown. This update corrects the display logic so the line appears whenever comprehensive income is present, helping ensure reports are complete and easier to read.
Original PR description
The Total Comprehensive Income line was not displayed in all expected cases due to a faulty visibility check. Rework the check expressions so the line shows whenever there is comprehensive income. task-6340607
This fix updates the sales subscription test flow so it works whether or not quotation templates are available. It prevents automated tests from breaking after the way new quotations are opened was changed, helping maintain stable validation of the sales process.
Original PR description
Commit odoo/odoo@00545bd introduced support for creating quotations from sale order templates through the `New` button. When accessible templates are available, clicking `New` opens a dropdown instead of directly opening the form view. This change could break existing tours relying on the previous behavior, as they would now need to archive all accessible sale order templates before creating a quotation. To avoid this requirement and keep tours working regardless of template availability, this commit updates the `createSalesOrder` tour util to handle both cases: opening the form view directly or selecting the default quotation entry from the dropdown. runbot error-940295 See Also: - https://github.com/odoo/odoo/pull/271236
Code cleanup and technical improvements
This change removes a tour setting that was no longer being used in several automated tours. It does not affect onboarding tours or user-facing behavior, but helps keep the code simpler and easier to maintain.
Original PR description
`tooltipPosition` is ignored by the tour engine and has no effect on automatic tours. Onboarding tours are left unchanged.
This change updates the equity screens to use the newer form binding syntax required by the latest UI framework version. It helps keep the interface compatible and reduces the risk of issues during future upgrades, without changing the business process itself.
Original PR description
As part of the migration from `owl 2` to `owl 3`, this commit replaces uses of `t-custom-model` with `t-model` or `t-model.proxy`.
4 changes
Resolved issues and error corrections
This change fixes an issue that could stop AI-assisted field population from working in Studio forms. It ensures the system receives the field information in the expected format, preventing the error and allowing users to complete the action successfully.
Original PR description
**STEPS TO REPRODUCE** 1. Add an AI Studio field in the employee appraisal form view (can be a regular text field or other) 2. Add `employee_feedback` to the prompt using '/' 3. Click the AI button to populate the field 4. Error occurs: `TypeError: unsupported operand type(s) for +: 'OrderedSet' and 'list'` **CAUSE** In any model, the read function expects the argument `fields` to be a list. When using AI fields in Studio, the fields argument is stored as an OrderedSet instead of a list, causing errors when performing operations. opw-5954203
This update fixes a timing issue that could add an extra minute to shifts planned on round-the-clock schedules. As a result, allocated time now matches the intended shift length, improving the accuracy of planning reports and employee schedules.
Original PR description
**Problem:** On a round-the-clock (0h-24h) working schedule, shifts created from a shift template that spans more than one day get one extra minute added to their allocated time: an 8-hour shift…
**Problem:** On a round-the-clock (0h-24h) working schedule, shifts created from a shift template that spans more than one day get one extra minute added to their allocated time: an 8-hour shift shows 08:01. **Steps to reproduce:** 1. Create a working schedule with a 00:00 -> 24:00 attendance for every day (24h/day, "Full Day"). 2. Assign an employee to that schedule. 3. Create a multi-day-span shift template (e.g. 16:00 -> 00:00, 2 days). 4. Plan a shift for that employee using the template. 5. Observe the Allocated Time shows one minute more than expected (08:01). **Current behavior:** Allocated Time is one minute too long (e.g. 08:01 instead of 08:00), which throws off the customer's planning reports. **Expected behavior:** Allocated Time matches the template duration exactly (08:00). **Cause of the issue:** In `_calculate_start_end_dates`, the end of a multi-day-span shift is computed with `resource.calendar_id.plan_days(...)`. On a 0h-24h calendar each day ends at `time.max` (23:59:59.999999), so `plan_days` returns an end datetime carrying those stale seconds. The following `end.replace(hour=..., minute=...)` overwrites only the hour and minute, leaving `second=59, microsecond=999999`. The slot is therefore ~1 minute longer than intended, and `allocated_hours` rounds that up to 08:01. **Fix:** Resetting seconds and microseconds when rebuilding the end datetime keeps the slot aligned to the template's whole-minute boundary, regardless of how the underlying calendar represents the end of day. The hour/minute already come from the template, so the leftover sub-minute precision from `plan_days` is never meaningful and is what produces the drift. opw-6265238
This update corrects how the current year’s earnings are classified and makes the Luxembourg balance sheet report calculate the carried-forward result more simply. It helps ensure the report shows the right figures for year-end financial statements.
Original PR description
This commit addresses the account type for the current year earnings and simplifies the calculation for the "Result brought forward" line in the Luxembourg balance sheet reports.
Modifications:
* Changed the account type of account 142 ("Result for the financial year") from `equity_unaffected` to standard `equity`.
* Simplified the formula for the Balance Sheet line "Profit or loss brought forward" (codes `LU_BS_319` and `LU_BSABR_319`).
* The new formula simply targets the `14` accounts while explicitly excluding `142`.
Community PR: odoo/odoo#272362
Ticket [link](https://www.odoo.com/odoo/project.task/6059571)
opw-6059571This change fixes an access error that could block database owners from synchronizing their databases. By applying the correct permissions check earlier in the process, the synchronization flow now continues without interruption.
Original PR description
The aim of this commit is to allow the databases_user to synchronize their databases. Context: The commit https://github.com/odoo/odoo/commit/846eb51a02baaf2e4f6e6780f8d0ceb23322c38b introduced a change of behavior in stable that performs some more check on access rights. Before this commit: The checks introduced by the commit resulted in an access error. There wasn't any groups on the action itself resulting in a check of the access right "write" on the model. As the model is `project.project` and a databases_user might not be granted write access on the project itself, it resulted in an access error. After this commit: The flow continues smoothly. As the action has now a group set on it, this is checked first and match the proper access right. opw-6329058
3 changes
Enhancements to existing features
This change makes KSeF bill retrieval more resilient when one bill causes an error, so the whole import process does not get blocked. It also helps users keep track of bills that need manual follow-up and improves handling of edge cases between companies and date limits.
Original PR description
### Commit 1: We fetch and store bills if we're able to parse and store them correctly. but in case we make a mistake 1. The cron gets stuck trying to fetch the problematic bill. 2. Users have no…
### Commit 1: We fetch and store bills if we're able to parse and store them correctly. but in case we make a mistake 1. The cron gets stuck trying to fetch the problematic bill. 2. Users have no clue that there is a bill on KSeF that they have to fetch manually. --- 1. Save the bill on a savepoint, to make sure one problematic bill doesn't affect others 2. Create all bills as draft first so that users have a reference to fallback to in case the have to do manual fetching. --- task-6310321 --- ### Commit 2: Issues: 1. For a db with company_1 and company_2, when company_1 sends an invoice to company_2 via KSeF (out_invoice with a ksef number), company_2 in the same database can't fetch the corresponding bill because there is a move with the same KSeF number. 2. The date difference between `from` and `to` in the `dateRange` must not exceed 3 months as explained in the documentation https://api.ksef.mf.gov.pl/docs/v2/index.html#tag/Pobieranie-faktur/paths/~1invoices~1query~1metadata/post Fixes: 1. Change the unique constraint and the domain to allow same KSeF number per different companies. 2. Minimize the `to` parameter with `from` + 2 months. 3. Increase the TIMEOUT to 30 seconds as 10 seconds is too small. task-6260645 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Resolved issues and error corrections
Swiss invoices will now generate a payment reference even when the customer is outside Switzerland or Liechtenstein. This ensures the invoice PDF still displays the payment communication and bank details, making payment easier and avoiding missing information on the document.
Original PR description
Issue: When an invoice (sales journal) uses "Switzerland" localization and the invoice is issued to a customer outside Switzerland/Liechtenstein, no payment reference is generated. This causes the…
Issue: When an invoice (sales journal) uses "Switzerland" localization and the invoice is issued to a customer outside Switzerland/Liechtenstein, no payment reference is generated. This causes the invoice PDF to hide payment communication and bank account details. Other localizations like Belgian companies, uses Belgian references, the reference is always generated regardless of customer country. Steps to reproduce: - Configure a Swiss company with a QR IBAN bank account - Set the sales journal Communication Standard to Switzerland - Create and confirm an invoice for a non swiss customer (US, BE) - Observe in the pdf and in the other info tab -> no payment reference or payment details Cause: `get_l10n_ch_qrr_number()` was using on `l10n_ch_is_qr_valid()`, which conflicts QR-bill printability (partner country, currency) with payment reference generation. When the customer is outside CH/LI, `l10n_ch_is_qr_valid()` is False and no QRR reference is generated. Solution: Decouple QRR reference generation from QR bill printability. The Swiss communication standard now generates a QRR format reference when a QR-IBAN is configured, regardless of customer's country or currency. opw-6222417 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
When a customer adds an online payment option to an order that was already synchronized, the system now sends the updated order information again. This ensures the customer is charged the correct, latest amount after changes like increasing the order total.
Original PR description
When an online payment line is added, the order is synced to the server so the customer can pay it online. This sync was only performed when the order did not yet exist on the server (string id). As a result, once an order had already been synced, modifying it (e.g. increasing the amount) and adding the online payment line again did not push the new amount to the server. opw-6314690 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
4 changes
Enhancements to existing features
This change lets operators adjust how quickly unused database connections are closed in Odoo. It helps reduce memory use in environments with limited resources by allowing idle connections to be cleared more aggressively when needed.
Original PR description
In memory-scarce environments, the default 10-minute idle timeout may keep too many backend connections alive. Allow operators to override it via the ODOO_DB_MAX_IDLE_TIMEOUT environment variable to evict idle connections more aggressively. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Resolved issues and error corrections
This change fixes a flaky chat window test by avoiding a click that could accidentally close the window while dismissing a menu. It makes the test more reliable without changing the intended user experience.
Original PR description
The "folded chat window should hide member-list and settings buttons" test flakily failed: the header click meant to dismiss the open actions menu also folded the chat window. The header both folds the window (onClickHeader) and serves as the outside click that closes the actions menu. onClickHeader only skipped folding while state.actionsMenuOpened was set, but that flag was kept in sync with deferred timing and could still read false when the dismiss click was processed, so the window folded. Snapshot whether the menu is open on the header pointerdown, which fires before the click that closes the dropdown, and skip folding on the matching click. This is deterministic, with no reliance on timers or event-loop ordering, and lets onActionsMenuStateChanged be a plain synchronous setter. runbot error: https://runbot.odoo.com/odoo/error/224155
When opening a customer from an invoice, the page title and breadcrumb will now show only the customer’s name instead of including the full multi-line address. This makes the interface cleaner and avoids oversized, hard-to-read breadcrumbs.
Original PR description
- Create a new Invoice; - Assign a Customer with a multiline address; - Click on the internal link (arrow icon) of the Customer field. Before this commit, the form view title and the breadcrumb would contain not only the customer's name but also their full address. This resulted in an excessively large and unreadable breadcrumb. Now, only the name is retained. This commit applies the same behavior already used in many2one fields: the display name is split by line breaks, and only the first line is kept for the title and breadcrumb. task-id 6329662
This fix restores the UNSPSC product code 10171500, so it now appears in the product accounting list as expected. This helps users classify products correctly, especially for organic fertilizers and plant nutrients.
Original PR description
The code 10171500 - Organic fertilizers and plant nutrients wasn't appearing. In the file that has the unspsc product codes this one was set to False. Steps to reproduce: - Activate module product_unspsc. - Go to product > accounting. - Verify that this code is not listed. Ticket [link](https://www.odoo.com/odoo/project.task/4461974) opw-4461974