Monday, September 7, 2026
26 changes · saas-19.4
Enhancements to existing features
The Belgian salary configurator now prevents employees or candidates from choosing both a company car rental option and reimbursement for using a private car. When one option is selected, the other is reset and disabled, reducing incorrect benefit selections and payroll inconsistencies.
Original PR description
In order to safe gaurd from employees (or candidates) from selecting both options for renting a company car and getting reimbursed for their private cars, the salary configurator now resets and disables one of the benefits if the other is selected. Task: 6515172 Forward-Port-Of: odoo/enterprise#130299
Swiss QR invoices can now be created even when the company or customer address is missing a street or building number, because those details are not required for valid Swiss QR invoices. Users will see an informational warning in the Send & Print flow and can review affected customers, while other invoices in a batch continue processing instead of being blocked.
Original PR description
In Switzerland, the street and building number is not required to generate a valid QR invoice. To minimize friction, errors are no longer raised if they are missing from the address of the company or the customer during the creation of the QR Code. Instead, an info banner is now displayed in the Send & Print popup indicating to the user that the addresses of some of the customers are missing and allow the user to browse through those customers. task-4349496 opw-4317153 Forward-Port-Of: odoo/odoo#271534
Resolved issues and error corrections
This change rolls back a previous database connection handling update because it caused connection usage to spike on the real-time server. Reverting it helps reduce the risk of service slowdowns or outages for users relying on live updates and messaging.
Original PR description
This reverts commit 11e76ba8042648596dc0a7c731a78dd786e36884 and PR #285423 The connection usage on the gevent server is spiking.
Fixed an issue where the AI image editor did not receive the product image or product details when launched from product media dialogs. This helps AI-generated or enhanced images use the actual product as context instead of asking users for information or inventing the product appearance.
Original PR description
When opening the media dialog from a product image (avatar) edit button, the `ImageFieldWithMediaDialog` (patched by the `ai`) attempts to pass `record`, `originalRecordModel`, and `originalRecordId` as props However, since these props are not declared in `mediaDialogProps`, so prop validation filters them out of `this.props`. Thus they are `undefined` in the MediaDialog. Thus they are not passed to the AI chat launcher. Thus ai has to ask user about product name. This commit registers these props on the `mediaDialogProps` schema in the `ai module patch, preventing Owl from stripping them. task-6365588 **Community counterpart: https://github.com/odoo/odoo/pull/273676**
This fixes an issue where Ecuadorian electronic invoicing withholding tax totals could disappear from the tax totals widget. Users can now see the expected withholding totals reliably, avoiding confusion when reviewing tax information.
Original PR description
TaxTotalsComponent now declares its totals as a computed, so formatData runs inside that computed's own getter. TaxTotalsComponentForWithhold still overrides formatData to assign this.totals directly, which overwrites the computed from within it: the getter returns undefined, so the table's t-if hides it and the widget renders empty, and every later read raises "this.totals is not a function" because this.totals is now a plain object. From: odoo/odoo#270245.
Customers can now start a product return from an order page opened through a secure shared link, without needing to sign in. This removes a blocker where the Return button did nothing, improving the self-service returns experience.
Original PR description
Accessing an order on the website without connecting (only with the access token) doesn't allow the user to return the order (nothing happens when click on the "Return" button) Steps to reproduce: 1.…
Accessing an order on the website without connecting (only with the access token) doesn't allow the user to return the order (nothing happens when click on the "Return" button) Steps to reproduce: 1. Install Sales and Inventory 2. Go to Settings > Inventory > Operations and enable "Allow Spontaneous Returns" 3. Go to Sales and create a new quotation for customer "Acme Corporation" with product "Acoustic Bloc Screens" and confirm it 4. Go to the related delivery, set the quantity to 1 and validate it 5. Go back to the sale order and click the "Preview" smart button 6. Copy the url (/my/orders/<id>?access_token=...) and open it in an incognito window 7. Click the return button on the order page 8. Nothing happens Issue: The route to `my_order_return_data` requires the user to be logged in Solution: Make the routes `my_order_return_data` and `order_return_label` public For 19.4: access `return.reason` records with sudo (should be removed in master) For master: add read right on `return.reason` for public users opw-6487767
The map-based address lookup now matches each address component by its label instead of assuming MapBox returns items in a fixed order. This prevents incorrect addresses or lookup failures when some address details are missing or returned differently, improving reliability for users who rely on location-based address filling.
Original PR description
The reverse-geocoding call to MapBox asked for five types of information (street, city, postcode, region, country) and read them back from the response by fixed position in the array. MapBox doesn't always return every requested type, or in the same order; if one is missing, every field after it shifts by one position, so the address ended up built from the wrong data, or the code crashed reading a feature that wasn't there. Each field is now looked up by its own type tag instead of its position in the array, so it's matched correctly regardless of order, and a genuinely missing type just resolves to nothing instead of corrupting the rest of the address. task-6542378
Users assigned to tasks in invite-only projects can now open their assigned task links without being added as project followers. This preserves project privacy while removing an access error that blocked normal task work.
Original PR description
Issue: Internal users assigned to a task in an "Invited internal users" project can read the task but may receive an access error when opening it. Adding them as project followers avoids the error…
Issue: Internal users assigned to a task in an "Invited internal users" project can read the task but may receive an access error when opening it. Adding them as project followers avoids the error but also exposes the project's other tasks. Steps to reproduce: - Set a project's visibility to "Invited internal users". - Assign an internal Project user to one of its tasks. - Keep the user out of the project's followers. - Open the assigned task through its access link. Cause: The task form loads feature flags whose computations read their values from the parent project. These computations run as the assignee, who can read the assigned task but not the invited-only project, causing a project access error. Additionally, the project many2one widget declares `is_template` as a related field. This makes web_read request `project_id.is_template` even though the widget uses the task's own `is_template` value. https://github.com/odoo/odoo/blob/8c1e139a8ffca9e9a82e90eb4a8a03a56b4aa660/addons/project/models/project_task.py#L277 https://github.com/odoo/odoo/blob/8c1e139a8ffca9e9a82e90eb4a8a03a56b4aa660/addons/project/models/project_task.py#L295 https://github.com/odoo/odoo/blob/8c1e139a8ffca9e9a82e90eb4a8a03a56b4aa660/addons/project/static/src/components/project_many2one_field/project_many2one_field.js#L36-L39 Solution: We need to compute the inherited task feature flags with elevated access so their values do not depend on the assignee's access to the parent project. declare `is_template` as a dependency of the current task instead of a related field of `project_id`. The task form therefore no longer reads the inaccessible project while its access restrictions remain intact. opw-6475880 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
French PDP Flow 10 reports now trim and normalize key invoice details before submission and block entries with invalid identifiers or address data. This helps prevent a single bad invoice value from causing an entire e-invoicing report to be rejected.
Original PR description
Some Flow 10 values are generated without applying the length and format constraints expected by the PPF. Long free-text values, oversized VAT numbers, and invalid address data can therefore cause an entire report to be rejected. Limit product names and invoice notes to their allowed lengths and normalize country codes. Validate the declarant SIREN, VAT number lengths, and address values before sending so affected journal entries are marked as errors and excluded from the report. No Task id Forward-Port-Of: odoo/odoo#286817 Forward-Port-Of: odoo/odoo#286536
Publicly shared spreadsheets now hide internal Odoo-only actions and side panels that could appear to outside viewers and cause a crash. This makes shared spreadsheets safer and more reliable for public users, while restoring support for map-based charts in public views.
Original PR description
Task: 6449019
Users managing bank reconciliation models can now see the correct models for journals that use a foreign currency. This prevents missing model entries caused by currency labels being included in the search, making reconciliation setup more reliable.
Original PR description
### Issue before this commit: When clicking "Manage Models" from a bank statement line, the associated reconciliation models are not displayed when belonging to a foreign currency journal. ### Steps…
### Issue before this commit: When clicking "Manage Models" from a bank statement line, the associated reconciliation models are not displayed when belonging to a foreign currency journal. ### Steps to reproduce the issue: 1. Download Accounting 2. Go to Currencies and activate another currency like EUR 3. Go to Journals and create a new one with bank type and curency EUR 4. Go to dashboard > new test bank journal created > 3 dots in the upper-right corner > Models > create a new one (ex Tester) setting the new test bank created as journal 5. Go to test bank journal and create a new bank matching 6. After the line is created click the 3 dots and go to Manage Models 7. See that the new model Tester created does not appear ### Cause of the issue: Foreign currency journals append their currency to the display_name (e.g., "Bank (EUR)"). The JS search framework passes this full decorated string into the search domain. The backend then attempts to match "Bank (EUR)" exactly in the database name and code fields, which fails because the database name is "Bank" without the currency added. https://github.com/odoo/odoo/blob/9c67949be529eb86886b3d5bde08e81e048ecfe7/addons/account/models/account_journal.py#L1095-L1100 ### Reason to introduce the fix: The filter is not working correctly. In this case it's better to change it to a domain instead of a default filter. opw-6481970 Forward-Port-Of: odoo/enterprise#129992
This fix prevents AI-powered SEO updates from crashing when an AI agent uses certain document sources, such as generated PDFs linked to business records. Users can now run “Update With AI” more reliably when documents are included in the agent’s knowledge sources.
Original PR description
### Problem When an AI agent includes a document source whose underlying `ir.attachment` has `res_field` set (e.g., an invoice PDF generated from a Sale Order), triggering **Update With AI** from…
### Problem
When an AI agent includes a document source whose underlying `ir.attachment`
has `res_field` set (e.g., an invoice PDF generated from a Sale Order),
triggering **Update With AI** from **Website → Site → Optimize SEO**
raises a `KeyError` in `_build_rag_context`.
### Steps to Reproduce
1. Open the **AI** app.
2. Configure the **Odoo Agent**.
3. Add a source → **Add From Documents**.
4. Select a document whose underlying `ir.attachment` has `res_field` set
(e.g., an invoice PDF generated from a Sale Order).
5. Go to **Website → Site → Optimize SEO**.
6. Click **Update With AI**.
7. Observe the following error:
```
KeyError: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
```
[Video](https://drive.google.com/file/d/1AAg0AvC3TRQzMLhI9hWFuSarOTHzQE-b/view?usp=sharing)
### Root Cause
In `ai/models/ai_agent.py`, `_build_rag_context()` retrieves the
`ai.agent.source` records corresponding to the embeddings by searching on the
attachment checksum:
```python
agent_sources = self.env["ai.agent.source"].search([
("attachment_id.checksum", "in", embeddings_attachment_checksums),
("agent_id", "=", self.id),
])
```
This domain traverses `attachment_id.checksum`, which internally calls
`ir.attachment._search()`.
As part of the standard attachment search behavior,
`ir.attachment._search()` automatically injects a
`('res_field', '=', False)` filter unless:
- `skip_res_field_check=True` is set in the context,
- the domain explicitly references `id` or `res_field`, or
- `bypass_access` is enabled.
```python
domain = Domain(domain)
if (
not self.env.context.get("skip_res_field_check")
and not any(d.field_expr in ("id", "res_field") for d in domain.iter_conditions())
and not bypass_access
):
disable_binary_fields_attachments = True
domain &= Domain("res_field", "=", False)
```
[Reference](https://github.com/odoo/odoo/blob/19.0/odoo/addons/base/models/ir_attachment.py#L630)
Because of this implicit filter, attachments with `res_field` set are excluded
from the search. Consequently, `agent_sources` does not contain all the sources
corresponding to the retrieved embeddings.
Later, `_build_rag_context()` builds a checksum-to-source mapping:
```python
source_map = {
source.attachment_id.checksum: source
for source in agent_sources
}
for embedding in similar_embeddings:
checksum = embedding.attachment_id.checksum
agent_source = source_map[checksum]
```
Since `source_map` is built from the incomplete `agent_sources` recordset, it is
missing entries for attachments filtered by `ir.attachment._search()`.
However, `similar_embeddings` still contains embeddings for those attachments.
As a result, the lookup:
```python
agent_source = source_map[checksum]
```
raises a `KeyError`.
### Solution
Bypass the implicit `res_field` filter when searching `ai.agent.source`:
```python
agent_sources = (
self.env["ai.agent.source"]
.with_context(skip_res_field_check=True)
.search([
("attachment_id.checksum", "in", embeddings_attachment_checksums),
("agent_id", "=", self.id),
])
)
```
This ensures that all `ai.agent.source` records matching the requested
attachment checksums are returned, including those referencing attachments with
`res_field` set. As a result, `source_map` contains all expected entries and
`_build_rag_context()` no longer raises a `KeyError`.
opw-6379816
Forward-Port-Of: odoo/enterprise#127725
Forward-Port-Of: odoo/enterprise#125780This fixes an error that could block HR users from exporting time entries when an employee has multiple versions of the same contract. The export now correctly includes all relevant contract versions, helping payroll teams complete time entry exports without interruption.
Original PR description
## Steps to Reproduce: - Install the hr_work_entry module. - Create an employee. - Payroll tab > create a contract by setting only the start date (leave the end date empty). - From the contract…
## Steps to Reproduce:
- Install the hr_work_entry module.
- Create an employee.
- Payroll tab > create a contract by setting only the start date (leave the end date empty).
- From the contract version timeline (navigation bar), click the "+" button and create a new version.
- Open the cog menu (gear icon) and click 'Export Time Entries'.
## Error:
`ValueError - Expected singleton: hr.version(257, 258)`
## Cause:
Method `_get_contract_versions()` returns multiple versions for the given period.
for example:
`contract_dict = {datetime.date(2026, 8, 1): hr.version(1, 2)}`
The code assumes each value is a singleton and builds the recordset using `c.id`,
`[c.id for c in contract_dict.values()]`
Since `c` contains multiple records, accessing the ID will raise an error.
## Fix:
Instead of accessing `id`, it will access `ids`, and it returns the list of all records (`[1, 2]`).
`chain.from_iterable()` flattens this list into one iterable sequence `(1, 2, ...)`, and
then it will convert into a list and be passed to `browse()` to fetch the corresponding recordset.
sentry-7623869169French point-of-sale invoice downloads now avoid showing a pro-forma invoice when customer e-invoicing data has validation issues. The sale can continue and a regular invoice is printed, while no external e-invoicing submission is attempted until the data issue is resolved.
Original PR description
## Steps to reproduce: - Create a customer with France E-Invoicing (UBL2.1) as eInvoice format in a French company - Go to the PoS, select that partner - Make a sale and ask for an invoice - The…
## Steps to reproduce: - Create a customer with France E-Invoicing (UBL2.1) as eInvoice format in a French company - Go to the PoS, select that partner - Make a sale and ask for an invoice - The downloaded invoice will be a pro-forma invoice ## Why the fix: The pro-forma should not be used here, it is because it is used as a fallback when we get an error while trying to print the invoice. https://github.com/odoo/odoo/blob/4a508586970e44367bbdbbb3cbe88ffb5a1eadb7/addons/account/models/account_move.py#L6187-L6204 As we get an error while trying to send the data with this setup, it goes to the fallback and prints a pro-forma invoice, even though this should not be the case, a regular invoice would do. This happens because when an error is found, we do not populate invoice_pdf_report_id, so it goes to the fallback. We now check if there are any errors in the order, and if there are and the customer requests an ubl_21_fr invoice, we just print the invoice as it is, without going to the pro-forma fallback, as this is not the intended flow. With this fix, we now have the same flow as we do in the sales module, that allows the sale even if the customer has missing data. It will just print the invoice and allow the sale but won't send anything to external entities. opw-6428369 Forward-Port-Of: odoo/odoo#281420
This fixes a mobile editing issue where users could not drag and drop table cells from the table menu. The change prevents the browser's touch handling from interrupting the action, making table editing more reliable on phones and tablets.
Original PR description
Steps to Reproduce - Insert a table inside a Todo item. - Long-press the table menu to open the drag-and-drop overlay. - Try to drag and drop table cells. Issue: - Table cells cannot be dragged and dropped on mobile devices. Cause: - On mobile devices, the browser fires `pointercancel`/`pointerleave` during a drag operation, which ends the drag operation prematurely. As a result, subsequent `pointermove` events are not triggered causing the drag-and-drop operation to fail. Solution: - Add `touch-action: none` to the table menu element. This prevents the browser default touch handling from interfering with the drag operation, allowing `pointermove` events to continue and drag-and-drop to work correctly on mobile devices. task-6201176 Forward-Port-Of: odoo/odoo#283866 Forward-Port-Of: odoo/odoo#267680
This fix prevents FedEx shipment validation from failing when a main customer contact has no phone number but the related delivery address does. Odoo now uses an available phone number from the parent or child contact, helping deliveries proceed without manual contact data workarounds.
Original PR description
Issue ----- Users cannot deliver to a contact's delivery address if the contact address itself doesn't have a phone number. Steps to reproduce ----- - Setup Fedex - Create a contact with no phone number - Create a delivery address for the contact (with phone number) - Create a SO with the contact using Fedex & confirm - Change the partner on the picking to use the delivery address - Validate the picking > Error: missing phone number Cause ----- To populate the `soldTo` part of thepayload, we call `_get_contact_from_partner` with the contact specified on the SO https://github.com/odoo/enterprise/blob/8e60f910a52e3b836e997e54a0b704e5786a28f2/delivery_fedex_rest/models/delivery_fedex.py#L171 https://github.com/odoo/enterprise/blob/8e60f910a52e3b836e997e54a0b704e5786a28f2/delivery_fedex_rest/models/fedex_request.py#L447-L452 The phone number is then taken directly from the contact. ----- Ticket: opw-6427962 Forward-Port-Of: odoo/enterprise#127434
Belgian CodaBox SODA imports now use the last actual SODA import date when checking for new statements. This prevents statements generated earlier in the same accounting period from being skipped, helping payroll accounting stay complete and up to date.
Original PR description
Before v19.1, we used to set the date on the journal entry based on the generation date of the SODA statement during the import. So it was possible to use the last date found in the salary journal as a `date_from` filter when fetching new SODA statements. Starting from v19.1, we now set the date on the journal entry as the last day of the accounting period referenced in the SODA file. However, we didn't change the fetching logic accordingly. If a SODA statement is generated on July 7 for the accounting period of July, the date on the journal entry would be July 31 and, consequently, any other SODA statement generated in-between those dates would be filtered out during the fetch. Ticket: opw-6214589 Forward-Port-Of: odoo/enterprise#130183
This fix adds checks before sending Turkish Nilvera e-invoices so users are warned when invoice lines are missing required tax information. It also avoids unnecessary warnings for note or section lines, helping prevent rejected submissions while reducing false alerts.
Original PR description
Nilvera does not accept invoices with lines that do not have taxes, so we added a valiation check for sending the invoice to warn the user. Additionally, we raise a warning when a line does not have a product and has an empty CTSP. However, if the line is a note or section, this warning should not be triggered. task-6404409 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284969 Forward-Port-Of: odoo/odoo#284377
Credit notes created from existing Turkish customer invoices now use the proper sales return account configured on the journal, instead of incorrectly keeping the original sales account. This improves accounting accuracy for Turkish sales returns while leaving cancellation reversals unchanged so they still fully offset the original invoice.
Original PR description
The Turkish chart of accounts keeps sales and sales returns on separate accounts, and the sales journal carries the account to use for returns. A credit note typed in by hand already lands on it, but one created from an existing customer invoice did not. Reversing an invoice copies `account_id` over from the invoice line, and since that field is a stored compute without depends, nothing ever recomputes it, so the return kept the sales account. Set the journal account on the copied product lines instead. Reversals made to cancel an entry are left alone, as those have to mirror the original move exactly for the two to net out, and a plain duplicate is untouched. Task-6438412 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284808 Forward-Port-Of: odoo/odoo#282858
This fixes an issue where customers paying with Razorpay FPX could encounter an error when returning from checkout because payment amount details were missing from the redirect response. Odoo now uses the full payment information already retrieved from Razorpay, allowing the transaction to continue reliably.
Original PR description
Issue: --- Paying with Razorpay using FPX raises `KeyError: 'amount'` when the customer returns from checkout. Steps to reproduce: 1- Enable Razorpay with FPX as a payment method. 2- Pay an order using FPX. Cause: --- In FPX, Razorpay returns without `amount`/`currency`. `_apply_updates` fetches the full payment from the API to determine the state, but that fetched entity is local to the method and never reused for amount validation, so `_process` still calls `_validate_amount` / `_extract_amount_data` with the original, amount-less redirect data. This issue is introduced after c34992ffd94ba4594731400839332b677fdc2b32, which removed the check in `_extract_amount_data` that returned `None` (skip validation) when `amount`/`currency` were absent. opw-6467815 Forward-Port-Of: odoo/odoo#286476
Stripe SEPA payments now use the company name rather than the order reference for the bank statement description. This prevents payments from failing when an order reference contains only numbers, improving checkout reliability for affected customers.
Original PR description
**Steps to reproduce:** 1. Install Sales, l10n_be, payment_stripe and switch to belgian company 2. Switch the admin user's company to the belgian one, and update their contact address to be in…
**Steps to reproduce:** 1. Install Sales, l10n_be, payment_stripe and switch to belgian company 2. Switch the admin user's company to the belgian one, and update their contact address to be in Belgium 3. Enable stripe payment provider 4. Add SEPA payment method in stripe configuration 5. Create a sale order with a name that doesn't include any characters (numbers only), confirm, click preview and attempt to make a payment using SEPA **Issue:** `The statement descriptor must contain at least one Latin character.` **Cause:** The previous fix (4fde0232b821c9a1d46d589ff14495f4e19029f4) passed the order reference directly, assuming it will contain characters. The intended behavior is to actually have the company name used in the statement descriptor field: https://support.stripe.com/questions/what-is-a-statement-descriptor-and-how-do-i-update-it This was the existing behavior before the fix, so will revert back to it. opw-6497127 Forward-Port-Of: odoo/odoo#286620 Forward-Port-Of: odoo/odoo#286287
This fix prevents Belgian SODA payroll imports from carrying lines from one imported file into the next when multiple files are uploaded together. It helps ensure accounting entries remain accurate and avoids duplicate or incorrect lines during batch imports.
Original PR description
Due to this commit: https://github.com/odoo/enterprise/commit/93c05b380e3c939e3c0b44eafcd7a41e86042d2d When importing 2 sodas from drag and drop. Due to the placement of the line_ids variable, the second move would have the line of first. By placing the variable in the loop we don't have that problem anymore task-6528101 Forward-Port-Of: odoo/enterprise#130190
Colombian withholding reports now correctly reduce the taxable base when a vendor bill is partially credited. This prevents credit notes from being counted in the wrong direction, giving businesses more accurate retention certificates and tax reporting figures.
Original PR description
**STEP TO REPRODUCE** 1. install l10n_co_reports and account_accountant 2. Create a bill, with a line with a retention tax (3.50% RteFte). 3. Create a partial credit note (unit price less than what's on the bill). 4. Goes to the report 'Certificado de Renteciòn en Fuente', and notice the Monto del Pago Sujeto Retenciòn is not correct. **CAUSE** The sql query multiply tax_base_amount by -1 if debit > 0, which means (because we are dealing with vendor bills) the line is from a credit note, but tax_base_amount is already a signed value so credit notes ends up contributing to the tax base amount while they should reduce it. opw-6235830 Forward-Port-Of: odoo/enterprise#130340 Forward-Port-Of: odoo/enterprise#119716
Timesheet weekly overtime now uses the employee schedule's Total hours instead of the Full Time Equivalent value. This makes overtime shown in My Timesheets consistent with Planning and other timesheet views, especially for flexible schedules.
Original PR description
# How to reproduce - Set the current employee's schedule to one with : - Schedule Type : Flexible - Total : a different amount than "Full Time Equivalent" - Go to My Timesheets - Add a new line with…
# How to reproduce
- Set the current employee's schedule to one with :
- Schedule Type : Flexible
- Total : a different amount than "Full Time Equivalent"
- Go to My Timesheets
- Add a new line with some Time Spent > 0
- Hover the bottom right cell of the grid (this is the total overtime for the week)
# The issue
The computation of the overtime for the week is based on "Full Time Equivalent" instead of "Total". This is inconsistent with the Planning app and the All Timesheets view.
# Cause
This [PR] introduced the usage of `full_time_required_hours` to compute the total overtime. This field was used because `hours_per_week` ("Total") was thought to be computed using `resource.calendar.attendance`. However, that is not the case when the schedule is flexible : https://github.com/odoo/odoo/blob/46d3fee5812b8406aac2244baa76b0daeef358c2/addons/resource/models/resource_calendar.py#L220 https://github.com/odoo/odoo/blob/46d3fee5812b8406aac2244baa76b0daeef358c2/addons/resource/models/resource_calendar.py#L163-L166
[PR]: https://github.com/odoo/enterprise/pull/81057
opw-6303520
Forward-Port-Of: odoo/enterprise#130087
Forward-Port-Of: odoo/enterprise#125510This fixes an issue where manually created quantity-based quality checks could block warehouse processing when only part of a quantity failed inspection. The system now keeps the needed quality check details and correctly separates failed units, allowing the picking to continue.
Original PR description
Version: -------- - 19.0+ Steps to reproduce: ------------------- - Install `quality_control` module - Create a picking order with a product - From the gear menu, create an on-demand Quality Check -…
Version:
--------
- 19.0+
Steps to reproduce:
-------------------
- Install `quality_control` module
- Create a picking order with a product
- From the gear menu, create an on-demand Quality Check
- Set the check to *Control per Quantity* and back to the picking
- Set the done quantity to 10
- Open the Quality Check wizard
- Try to fail 3 units
Issue:
------
Validating the partial failure raises a `ValidationError`:
- Missing required value for the field 'Team' (team_id)
The quality check split is not performed and the picking cannot be processed.
Cause:
--------
Quality checks created on-demand from the picking (via the gear menu) have
no associated `quality.point` or `stock.move.line` — only
`picking_id` is set at creation time.
https://github.com/odoo/enterprise/blob/7d40d6b787511bf2fcbf581859ed2cd38ba3f658/quality_control/models/quality.py#L457
In `_move_to_failure_location()`, the `move_line` branch assumes
`check.move_line_id` is populated. Since it is empty for on-demand
checks, the split logic operates on an empty recordset.
The new quality check for the split is then created via:
https://github.com/odoo/enterprise/blob/7d40d6b787511bf2fcbf581859ed2cd38ba3f658/quality_control/models/quality.py#L493
At this point both `failed_move_line` (a copy of the empty move line) and
`check.point_id` are empty. `_get_check_values(False)` cannot derive
fields normally sourced from the quality point (`team_id`, `company_id`,
`measure_on`, `test_type_id`, etc.), causing the `ValidationError` on record creation.
Fix:
----
- If the quality check is not linked to a move line, find the matching move line
from the picking before splitting the failed quantity.
https://github.com/odoo/enterprise/blob/7d40d6b787511bf2fcbf581859ed2cd38ba3f658/quality_control/models/stock_move_line.py#L94-L97
- `_get_check_values()` normally takes values from a Quality Point.
Since on-demand quality checks do not have one, fill the missing
values (`team_id`, `measure_on`) from the original quality check instead.
This allows manually created quantity-based quality checks to be
split correctly after a partial failure.
---
opw-6428749
Forward-Port-Of: odoo/enterprise#130275
Forward-Port-Of: odoo/enterprise#126505Closing a Point of Sale session could fail when orders included both a tracked product and a kit containing that same product. The fix correctly adds quantities across multiple matching order lines, allowing affected sessions to close reliably.
Original PR description
**Step to reproduce :** 1. Create Product A and enable lot tracking for it. 2. Create a Kit product and add Product A as one of its components. 3. Go to PoS and create orders using: - Product A - The…
**Step to reproduce :** 1. Create Product A and enable lot tracking for it. 2. Create a Kit product and add Product A as one of its components. 3. Go to PoS and create orders using: - Product A - The Kit product - A combination of Product A and the Kit product 4. Create three different orders with these combinations. 5. Try to close the PoS session. **Issue :** An error occurs when attempting to close the PoS session. The issue is in the pos_mrp module, specifically in the _get_lot_line_qty method. When accessing the following line: `lines_data[move.bom_line_id.bom_id.product_tmpl_id.product_variant_id.id]['order_lines'].qty` we expect order_lines to contain a single record. However, in this scenario, multiple order lines can be returned for the same product. As a result, accessing .qty directly on order_lines raises a singleton error. **Solution :** With this fix, we first retrieve the quantity from each order line and thensum the quantities together. This ensures that multiple matching order lines are handled correctly and prevents the singleton error when closing the PoS session. opw-6442765 Forward-Port-Of: odoo/odoo#285612 Forward-Port-Of: odoo/odoo#281622