Thursday, September 17, 2026
19 changes · saas-19.2
Resolved issues and error corrections
This fix prevents customers from using on-site payment options when an order involves gift cards or eWallets in unsupported delivery or collection scenarios. It helps avoid checkout flows that the business does not support, reducing failed or inconsistent payment handling.
Original PR description
We don't want to support gift cards and eWallets in certain conditions opw-6483282 Forward-Port-Of: odoo/odoo#287928 Forward-Port-Of: odoo/odoo#286946
This fixes an issue where Dutch-language users saw custom time-off hours reset to 12:00 AM and could not change them. Time-off entries now recognize Dutch time formatting, so employees and managers can enter custom hours reliably.
Original PR description
When a user's language is set to Dutch, the custom hours field on a time off record displays "12:00 AM" and cannot be modified: any value entered resets to that default. float_time_selection.js assumed an English time format, handling only "h" and "m" tokens. Dutch formats hours with "u" (uur), so the input never matched and fell back to midnight. Steps to reproduce: - Set the user's language to Dutch / Nederlands in Preferences - Go to Time Off > Management > Time Off and create a record - Pick a Time Off Type with Duration Type set to Custom Hours - Select a period and save - The hours display as 12:00 AM and cannot be changed opw-6382902 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Fixed an issue where the Planning Analysis report could crash when users grouped results by customer after installing Sales Planning with Field Service Planning. This keeps reporting usable and lets teams analyze planned work by customer without interruption.
Original PR description
Currently, when both `sale_planning` and `planning_field_service` are installed, grouping the Planning Analysis report by Customer raises a ValueError and crashes the view. ### **Steps to…
Currently, when both `sale_planning` and `planning_field_service` are installed, grouping the Planning Analysis report by Customer raises a ValueError and crashes the view. ### **Steps to reproduce:** 1) Install `sale_planning` and `planning_field_service`. 2) Go to Planning > Reporting > Planning Analysis. 3) Click on any month to drill down. 4) Group by Customer. Error: ``` ValueError: Cannot convert planning.analysis.report.partner_id to SQL because it is not stored ``` ### **Root Cause:** Both `sale_planning` and `planning_field_service` extend `planning.analysis.report` and define `partner_id` differently. **sale_planning** Defination: https://github.com/odoo/enterprise/blob/778309d6f575be2074ea48aa253433563de1aa7c/sale_planning/report/planning_analysis_report.py#L13 **planning_field_service** Defination: https://github.com/odoo/enterprise/blob/778309d6f575be2074ea48aa253433563de1aa7c/planning_field_service/report/planning_analysis_report.py#L7 Because they don't depend on each other, they load alphabetically, meaning `sale_planning` (which defines it as a non-stored computed field) overrides `planning_field_service` (which expects it to be stored). Thus, the ORM treats `partner_id` as non-stored. When the web client attempts to group by this non-stored field via `_read_group` or `_read_grouping_sets`, the ORM fails to convert it to SQL and raises a ValueError. ### **Fix:** This commit overrides `_read_group` and `_read_grouping_sets`. If `partner_id` is non-stored and present in the `groupby` lists, we dynamically replace it with `sale_order_id.partner_id` (which is a valid stored column in the SQL view). We also apply this same remapping to the `order` parameter. This prevents the SQL conversion crash while successfully returning the grouped results. ### **Note:** As an alternative approach, the same fix can be applied once, at a lower level, by overriding `_read_group_groupby` and `_read_group_orderby` instead of `_read_group` and `_read_grouping_sets` separately. Both `_read_group` and `_read_grouping_sets` internally call these two helper methods to convert each groupby spec to SQL, so patching them there would cover every calls from a single pair of overrides, instead of duplicating the remap logic per entry point. But I chose to apply the following solution because we already have a reference of such a fix in the `project` module (**personal_stage_type_id** remapping, [commit](https://github.com/odoo/odoo/pull/163300/changes/191ac027dd1e5133b0bcc72ab44358431c508a1c#diff-93ba226020add6481cfeab916e69980a59163e2925a5c2c9a3bc0aaceb484cdfR1987-R1998)), and it's more consistent to follow that established pattern. **opw-6346701**
This fix lets managers with Time Off approval rights approve employee leave requests even when the leave overlaps with a completed payslip. It removes an access error that blocked normal approvals for managers who do not have Payroll permissions.
Original PR description
### Steps to reproduce: - Create two employees: Employee A (Manager) and Employee B (Employee subordinate to A) - Create a user for Employee A and grant Time Off approval rights, but no Payroll…
### Steps to reproduce: - Create two employees: Employee A (Manager) and Employee B (Employee subordinate to A) - Create a user for Employee A and grant Time Off approval rights, but no Payroll access - Create a payslip for Employee B for the current month - Validate and mark the payslip as Paid - Log in as Employee B and submit a Time Off request for the current month - Log in as Employee A and open Employee B's Time Off request to approve it > AccessError: You do not have enough rights to access the field "payslip_state" on Time Off (hr.leave). Please contact your system administrator. ### Cause of Issue: When a leave overlaps with a validated payslip and no waiting payslip is found, the `hr_payroll` override of `_action_validate()` attempts to set the leave's `payslip_state` to `blocked`. However, the `payslip_state` field is restricted to users with Payroll access (`hr_payroll.group_hr_payroll_user`). Because the manager approving the leave only has Time Off approval rights, the write operation fails with an access rights error. ### Fix: Use `sudo()` to bypass the AccessError, since it's the common approach in this module opw-6501386
Opening records with search panel filters linked to archived or restricted items no longer causes the page to crash. The system now ignores hidden values that cannot be shown in the filter list, keeping affected views usable for users.
Original PR description
Opening a view whose search panel has a `select="multi"` field of type many2many crashes when a record is only linked to comodel records the user cannot see: File "/addons/web/models/models.py", line…
Opening a view whose search panel has a `select="multi"` field of type many2many crashes when a record is only linked to comodel records the user cannot see: File "/addons/web/models/models.py", line 1496, in _search_panel_domain_image id_, display_name = group_id_name(group[field_name]) TypeError: cannot unpack non-iterable bool object Steps to reproduce: - On a db with Social Marketing installed, social accounts are automatically created per website - Open Social Marketing > Posts - Create a new Post with an social account - Open Settings > Social Accounts > the chosen social account - Archive it - Get back to the Post created above => crash `_search_panel_domain_image` restricts the domain with `(field_name, '!=', False)`, which is evaluated on the comodel with sudo and active_test=False, while the group by of the same query joins the comodel through `_search`, which applies record rules and active_test. A record whose values are all archived or hidden by a record rule therefore passes the condition but ends up in a group with no value, which the image loop unpacks as a tuple. This commit skips those groups: their values have no place in the range anyway. Seen on runbot, where `runbot.build.error.trigger_ids` points at `runbot.trigger` records that are archived or restricted by the project group rule. Forward-Port-Of: odoo/odoo#288503
Fixes an issue where Helpdesk teams linked to more than one community forum could hit an error instead of seeing the forum selection page. This ensures customers can use the Ask the Community option reliably, including when eLearning forum integration is installed.
Original PR description
### Steps to Reproduce: 1) Install `website_helpdesk_slides_forum` module 2) On a Helpdesk team, link 2 (or more) forums under `Commnity Forums`. 3) Click on website smart button and then click `Ask…
### Steps to Reproduce: 1) Install `website_helpdesk_slides_forum` module 2) On a Helpdesk team, link 2 (or more) forums under `Commnity Forums`. 3) Click on website smart button and then click `Ask the community` button. ### Error: ``` odoo.addons.base.models.ir_qweb.QWebException: Error while render the template KeyError: '_forums' Template: website_helpdesk_slides_forum.helpdesk_forums ``` ### Root Cause: https://github.com/odoo/enterprise/blob/1bdd673c5fd19e335dc0948d2beed7a282e5e172/website_helpdesk_forum/controllers/website_forum.py#L18-L22 On clicking the "Ask the Community" button calls the `helpdesk_forums` controller. A single forum redirects straight to it. Several forums get rendered through `get_template_xml_id()`, with only `forums` in context. `get_template_xml_id()` is overridden in `WebsiteSlidesForumHelpdesk`, which points to : https://github.com/odoo/enterprise/blob/1bdd673c5fd19e335dc0948d2beed7a282e5e172/website_helpdesk_slides_forum/views/helpdesk_templates.xml#L3-L5 a primary copy of the inner partial `forum_all_all_entries`. That partial needs `_forums` (and, once extended by website_slides_forum, courses_discussions too), both only ever set by the page template's own t-call: [Reference](https://github.com/odoo/odoo/blob/23af2b443735c6d3a2f64e44f9ea5da45638b052/addons/website_forum/views/forum_forum_templates_forum_all.xml#L18-L19) Since `helpdesk_forums` is rendered directly instead of going through `website_forum.forum_all`, `_forums` is never set, hence `KeyError` occurs. The base `website_helpdesk_forum` module has the same root cause one level up, surfacing as a different error: https://github.com/odoo/enterprise/blob/1bdd673c5fd19e335dc0948d2beed7a282e5e172/website_helpdesk_forum/controllers/website_forum.py#L24-L25 `website_helpdesk_forum.forum_all` does not exist anywhere in the codebase. A team with multiple forums, without `website_helpdesk_slides_forum` installed, hits ``` ValueError: View 'website_helpdesk_forum.forum_all' in website 1 not found ``` Instead of a listing page. ### Fix: - Both `get_template_xml_id()` implementations now return the real, working `website_forum.forum_all` page template, which already sets `_forums/courses_discussions` through its own `t-call` and wraps the result in website.layout. - `helpdesk_forums()`'s render values are now built through an overridable `_get_helpdesk_forums_render_values()` hook instead of a hardcoded dict, so subclasses can extend the context. - `website_helpdesk_slides_forum` uses that hook to set `hide_forum_slides_link=True`, and adds one small non-primary view inheriting `website_slides_forum.forum_all_all_entries` that conditions the `/slides` promo link (not the "Course" badge, which doesn't navigate anywhere) on `not` `hide_forum_slides_link`. This targets the link element itself rather than a `t-call` site in `forum_all`, so it correctly applies whether `website_slides_forum` groups a given forum as "regular" or "course-linked". **opw-6332175** Forward-Port-Of: odoo/enterprise#131638 Forward-Port-Of: odoo/enterprise#124104
Fully prepaid Argentine invoices that net to zero will no longer be rejected because of zero VAT details being sent to ARCA. The fix prevents all-zero VAT aliquots from being included, allowing valid $0 final invoices to be approved.
Original PR description
## Description of the issue When an Argentinian invoice contains advance-payment deduction lines that exactly cancel the product lines (net taxable base = 0 for a given VAT aliquot), the invoice is…
## Description of the issue
When an Argentinian invoice contains advance-payment deduction lines that exactly cancel the product lines (net taxable base = 0 for a given VAT aliquot), the invoice is rejected by the ARCA (AFIP) WSFE web service with:
> **Error 10018**: "Si ImpIva es igual a 0 el objeto Iva y AlicIva son obligatorios. Id iva = 3 (iva 0)"
This is the standard "100% down payment" flow: the customer is invoiced an advance for the full amount, and the final invoice deducts that advance, resulting in a $0 invoice that must still be validated against ARCA.
This is a forward-port to 19.0 of #270846 (same fix, targeted at 18.0, closed unmerged). The bug is still present in 19.0: `_get_vat()` in `addons/l10n_ar/models/account_move.py` evaluates its filter on the raw unrounded aggregated floats.
## Steps to reproduce
1. On a company with the Argentinian localization (`l10n_ar_edi`) configured for electronic invoicing (WSFE), create a sale order with one or more product lines taxed at IVA 21% (e.g. total $121,000).
2. Create a **down payment invoice for 100%** of the order and validate it against ARCA (this one succeeds).
3. Create the final invoice from the sale order: it contains the product lines (positive) and the down-payment deduction line (negative), both at IVA 21%. Total to pay: **$0.00**.
4. Confirm the invoice and send it to ARCA.
5. **Current behavior (bug):** ARCA rejects the request with error 10018. Inspecting the generated WSFE request shows `ImpNeto=0.0`, `ImpIVA=0.0`, `ImpTotal=0.0` and an `Iva` block containing an all-zero aliquot, e.g. `{'AlicIva': [{'Id': '5', 'BaseImp': 0.0, 'Importe': 0.0}]}` — instead of `Iva: null`.
6. **Expected behavior (after fix):** no zero-amount aliquot is sent (`Iva` is `null`) and ARCA approves the $0 invoice.
## Root cause
In `_get_vat()`, the positive product lines and the negative down-payment deduction line share the same VAT aliquot, so the aggregation by `vat_afip_code` nets the group to zero. However, floating-point accumulation in the aggregated tax details leaves a tiny residual (~1e-12) in `base_amount_currency` / `tax_amount_currency`. The filter condition checks the **raw unrounded** values:
```python
if grouping_key['vat_afip_code'] not in (False, '0', '1', '2') and (values['base_amount_currency'] or values['tax_amount_currency']):
```
The ~1e-12 residual is truthy in Python, so the aliquot entry is kept — even though both `BaseImp` and `Importe` are rounded to `0.00` two lines below when building the entry. The WSFE request therefore carries a non-null `Iva` block with all-zero amounts, which ARCA rejects with error 10018.
## Fix
Round `BaseImp` and `Importe` to 2 decimals **before** evaluating the filter condition, so an aliquot whose amounts cancel out is excluded from the `Iva` array (the same rounded values are then reused when building the entry, keeping the sent amounts unchanged for every other case):
```python
base_imp = float_round(amount_sign * values['base_amount_currency'], precision_digits=2)
importe = float_round(amount_sign * values['tax_amount_currency'], precision_digits=2)
if grouping_key['vat_afip_code'] not in (False, '0', '1', '2') and (base_imp or importe):
```
Behavior is unchanged for every invoice whose aliquots round to a non-zero base or tax amount.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#286005Planning views now calculate each assigned resource's hours separately when a shift has multiple people or resources. This prevents inflated progress bars and incorrect allocated hours or break times, giving managers a more reliable view of workloads and schedules.
Original PR description
# [FIX] planning: split gantt progress bar hours per resource Issue: ---------------------------------------- On the planning gantt view, when a shift is assigned to several resources, the progress…
# [FIX] planning: split gantt progress bar hours per resource Issue: ---------------------------------------- On the planning gantt view, when a shift is assigned to several resources, the progress bar of each individual resource shows the sum of all resources' allocated hours instead of that resource's own hours. Steps to reproduce: ---------------------------------------- - Give two employees working calendars with a different number of daily hours (e.g. 8h and 4h) - Create one shift covering both calendars' full working hours and assign both employees to it - Open the gantt view and check the progress bar of each employee for that shift Cause: ---------------------------------------- `_gantt_progress_bar_group_by_field()` computes one duration per shift via `_get_duration_over_period()`, which already sums the working hours of every resource assigned to the shift. That same total is then added to the progress bar of each resource. Solution: ---------------------------------------- Add `_get_working_hours_over_period_per_resource()` and `_get_duration_over_period_per_resource()`, which returns the results into a dict per resource. `_get_working_hours_over_period()` then calls `_get_working_hours_over_period_per_resource()` and sums the values. `_gantt_progress_bar_group_by_field()` now calls this per-resource breakdown when grouping by `resource_ids`. # [FIX] planning_field_service: fix break_time computation Issue: ---------------------------------------- When adding multiple resources to a slot, we can break the Steps to reproduce first issue: ---------------------------------------- - Create a slot for a resource working 8 hours per day - Add another resource working 4 hours per day - Remove the resource working 4 hours - The allocated hours show "9h 36m" instead of 8h Cause: ---------------------------------------- `_get_in_schedule_break_time()` can return negative values, so it breaks the computation of `allocated_percentage` which then impacts the future allocated percentages. Solution: ---------------------------------------- Add a `max(..., 0)` to `_get_in_schedule_break_time()`. Steps to reproduce second issue: ---------------------------------------- - Create a slot for a resource working 8 hours per day - Add another resource working 4 hours per day - The break time is 0, it should be 4h Cause: ---------------------------------------- The calculation of `break_time` with multiple resources was supposed to be fixed in 583ccb226970787b9dbd4cb03ccbfd43849fb8c7 but the value is never used. Using it fixes the case for multiple resources having the same work schedule but not all case: In our case it will output 12 allocated hours and 2 hours of breaktime instead of 4. This is because the breaktime hours are only from one resources but they still get divided by the number of resources. Solution: ---------------------------------------- We should instead multiply the duration by the number of resources to get the correct number of break hours. This ensures that `allocated_hours + break_time` equals the total duration of the shift. Same in `_get_in_schedule_break_time()`. opw-6500685
Fixed an issue that could prevent Arabic-English invoice PDFs from being generated when invoices included section or note lines. This helps businesses using GCC localization reliably preview and print invoices without server errors.
Original PR description
## Problem When rendering PDF invoices that contain **section** or **note** lines, the `l10n_gcc_invoice.arabic_english_invoice` QWeb template raises: ``` TypeError: argument of type 'bool' is not…
## Problem When rendering PDF invoices that contain **section** or **note** lines, the `l10n_gcc_invoice.arabic_english_invoice` QWeb template raises: ``` TypeError: argument of type 'bool' is not iterable ``` This happens because `account.move.line` records of type `line_section` or `line_note` have `name = False`. The template evaluates `arabic_name not in line.name` (and the same for `english_name`), which fails because Python cannot apply the `in` operator on a boolean value. ## Fix Add a `line.name and` guard before each `not in` check: ```xml <!-- Before --> <span t-if="arabic_name not in line.name" .../> <span t-if="(english_name != arabic_name) and (english_name not in line.name)" .../> <!-- After --> <span t-if="line.name and arabic_name not in line.name" .../> <span t-if="line.name and (english_name != arabic_name) and (english_name not in line.name)" .../> ``` ## Steps to reproduce 1. Install `l10n_gcc_invoice` on an Odoo 16.0 instance. 2. Create a customer invoice and add a **Section** line. 3. Print/preview the invoice PDF. 4. Observe `Internal Server Error` / `TypeError: argument of type 'bool' is not iterable`. Forward-Port-Of: odoo/odoo#278887 Forward-Port-Of: odoo/odoo#267147
Swiss payroll users can now manually enter an hourly salary factor on a draft ELM payslip and save it without the value being reset. This prevents payroll corrections from being lost and reduces the need for duplicate data entry.
Original PR description
**Steps to reproduce:** 1. Create a draft Swiss ELM payslip for an hourly-paid employee with no automatic hourly work-entry/input 2. In the Wages tab, manually update the `Factor` (`rate`) field of the `Hourly Salary` line 3. Save the payslip **Issue:** The manually entered `Factor` is reset to `0.00` **Cause:** - `l10n_ch_swiss_wage_ids` is a stored computed field without explicit `readonly=False`, causing manual modifications to the line values to be discarded during field recomputation on save. opw-6536243 Forward-Port-Of: odoo/enterprise#131636 Forward-Port-Of: odoo/enterprise#130824
Correcting a pre-filled bill date from the OCR attachment preview now works reliably. Users can click a different detected date and have the vendor bill field update instead of losing focus and hiding the OCR suggestions.
Original PR description
**Steps to reproduce:** 1. Upload a vendor bill with OCR digitization (pdf in ticket attachments) 2. Make sure the Bill Date field already has a value 3. Click into the Bill Date field so the OCR…
**Steps to reproduce:** 1. Upload a vendor bill with OCR digitization (pdf in ticket attachments) 2. Make sure the Bill Date field already has a value 3. Click into the Bill Date field so the OCR boxes appear on the attachment preview 4. Click on a different date box in the attachment to correct the value **Issue:** The field is not updated with the clicked box's value. Instead, the field simply loses focus and the OCR boxes disappear, as if the user had clicked outside the field. This only happens when the date field already has a value; it works fine when the field is empty. **Cause:** - When a date field has a value, the date widget renders it as a button and only swaps in the real `<input>` once focused [1] - Removing the button triggers `onBlurFieldWidget`, and when the datepicker is focused, it triggers `onFocusFieldWidget` once again: https://github.com/odoo/odoo/blob/89650a5f44b5835028dba57a9ff6fa30515bc5ec/addons/web/static/src/views/fields/datetime/datetime_field.js#L204-L214 - The datetime picker's popover uses `useClickAway`, which reacts to `pointerdown` on `window` to detect clicks outside itself and close the popover. - Clicking a box in the attachment preview is therefore caught by this listener before anything else: it closes the popover, removing the currently focused DOM node and firing a `focusout`. - `ExtractMixinFormRenderer` reacted to that `focusout` by resetting the active field and destroying the box overlay. Since the box's own value-selection ran on `click`, the last event in the `pointerdown → mousedown → mouseup → click` sequence, the reset had already been done, so the click was lost. **Fix:** - Apply the box's selection on `pointerdown` instead of `click`, so it runs synchronously in the same event dispatch that triggers the popover's close logic, guaranteeing it executes before any asynchronous re-render can remove the field's state. - Remove the legacy `pointerdown` listener in `ExtractMixinFormRenderer.`. Because our box now listens to `pointerdown`, it was intercepting the event and breaking selection for images [1] - https://github.com/odoo/odoo/pull/218387 opw-6511803 Forward-Port-Of: odoo/enterprise#130192
EU OSS sales are now reported in the French e-invoicing flow as non-French VAT while keeping the correct destination VAT on invoices and accounting entries. This prevents valid OSS transactions from being rejected by French reporting checks and preserves validation for unsupported tax rates.
Original PR description
OSS sales are taxed in the customer's Member State but are not subject to French VAT. They must therefore be reported under TNT1, while the Flow 10 Schematron only accepts French VAT rates. Identify taxes generated for the EU OSS scheme through their OSS tag. Keep the destination VAT on the invoice and in accounting, but report the taxable base under TNT1 with a zero tax rate and amount. Continue rejecting unsupported rates for regular taxes and invalid OSS rates. no task id Forward-Port-Of: odoo/odoo#288013
New Singapore companies will now be created with the correct accounting configuration so purchase price differences are recorded properly. This helps ensure vendor bills reflect the expected price difference entries when purchased goods are billed at a different price than their standard product price.
Original PR description
Singaporean companies didn't have the anglo saxon accounting enabled. Price difference account was then not hit when buying a product with a different price than the one in the product page. Steps to reproduce: ------------------- * Create a product P * Set the costing method to "Standard Price" and the inventory valuation to "Perpetual (automated)" * Make sure a price difference account is set in the product category * Create a RFQ for P and set a different price than the one in the product page * Confirm the RFQ and receive the product * Create a vendor bill for the RFQ and validate it > Observation: If you check the lines in the bill there is no price difference account hit. Why the fix: ------------ We set anglo saxon accounting to True so that all new companies have the correct setup. opw-6525817 Forward-Port-Of: odoo/odoo#288261
Renewal and upsell quotations no longer fail when the original cancelled subscription has no recurring plan or next invoice date. This prevents a blocking error during confirmation, helping teams continue subscription changes smoothly.
Original PR description
## Steps to Reproduce: - Install the Subscriptions module with demo data. - Create a quotation containing a subscription product. - Set a recurring plan and confirm the quotation. - Create an upsell…
## Steps to Reproduce: - Install the Subscriptions module with demo data. - Create a quotation containing a subscription product. - Set a recurring plan and confirm the quotation. - Create an upsell quotation or a renewal quotation. - Cancel the original subscription. - Remove the recurring plan from the cancelled subscription. - Open either the upsell or renewal quotation and confirm it. ## Error: `TypeError - '>=' not supported between instances of 'datetime.date' and 'bool'` ## Cause: Since Commit https://github.com/odoo/enterprise/commit/315be581a4212b46191e0c4f82b02a2c3fde51dc#diff-07cf1dda5423f99452a763a54fb6e7fdbb861e19b1a9dca00cab093a832490a9, `plan_id` is no longer required when a subscription is in the cancelled state. During the confirmation of an upsell or renewal quotation, the parent subscription's next invoice date is used for several date validations. However, if the parent subscription is cancelled and its plan is removed, the `next_invoice_date` is computed as False. Comparing a date object with a boolean value leads to an error. ## Fix: This commit adds an extra check before using the next invoice date. sentry-7661150764 Forward-Port-Of: odoo/enterprise#128093
Ship-later POS orders that trigger inter-company purchases now keep custom product attribute details through to the related sale order and delivery. This prevents missing descriptions on delivery slips, helping teams fulfill customized products accurately across companies.
Original PR description
*= sale_purchase_inter_company_rules Step to reproduce: - install `sale_purchase_stock_inter_company_rules` and pos with demo - from setting : - enable Multi-Step Routes - enable all options for…
*= sale_purchase_inter_company_rules
Step to reproduce:
- install `sale_purchase_stock_inter_company_rules` and pos with demo
- from setting :
- enable Multi-Step Routes
- enable all options for Inter-Company Transactions (for both companies)
- go to routes, un-archive MTO route
- create a product "A" with routes "MTO" and "buy"
- make the product available for pos (add into `Misc` category)
- create a attribute with custom attribute value and link it to "A"
- in vendor list, add "My Company (Chicago)" as vendor
- switch to Chicago company, for same product add some other vendor
- switch back to "My Company (San Francisco)"
- for pos, in setting enable "Allow Ship Later"
- open Furniture pos, create a order with Product "A"
- go to payment page and select "Ship Later" and pay
- a RFQ is created for this pos order, open and confirm it
- switch to "My Company (Chicago)"
- open sale order (remove "my quotation" filter)
- notice a quotation created from company 1, confirm it.
- open linked delivery slip
Observation:
- the delivery slip will not have description (custom value for attribute for A
is lost)
Cause:
- when preparing vals for SO for inter-company transaction from
`_prepare_sale_order_line_data` we never considered order from pos
- hence in this case, order lines never had custom attributed linked to them
- the description is computed from the attributes from SO
- SO never had them to begin with
Fix
- we introduced a method `_get_pcavs_from_pos_order` which fetch such attributes from pos order too
- to accomplish this we introduce a new module As there is no dependency with purchase and pos
opw-6213076
Forward-Port-Of: odoo/enterprise#131626
Forward-Port-Of: odoo/enterprise#119233Inter-company purchase transfers created from sales orders now keep their stock lines unpicked until warehouse staff process them. This prevents barcode users from seeing lines as already completed, reducing confusion and supporting the intended receiving workflow.
Original PR description
Issue ----- When confirming a SO, the corresponding PO picking should not have its' MLs set as `picked` to allow treating the transfer in the barcode app. Steps to reproduce ----- - Create 2 companies A & B - Settings > Inter-Company Transactions - Create Purchase Orders - Set the created PO to be "Validated" by default - Create a SO from company A to B - Validate the OUT picking in company A - Open the PO in company B - Go to its' picking and open it in barcode > The line is already picked ----- Ticket: opw-6481828 Forward-Port-Of: odoo/enterprise#131391
Spanish website checkouts now allow consumer customers to complete their address without entering a VAT number. This avoids blocking B2C sales and prevents business-only fields from being forced onto customer checkout forms.
Original PR description
Steps: - Install l10n_es and website_sale module. - set up Spain as website country. - Go to checkout page. - Fill address without vat. Issue: - It won't allow save address and process with checkout because vat is required even if we make `b2b_fields` non required or hide b2b_fields from address page they are still visible and don't allow to save address. Casue: - In PR https://github.com/odoo/odoo/pull/184734 they made vat required for Spain website considering EDI but it does not make sense to always ask for vat even website is not b2b and in other PR they made b2b_fields always visible which make b2c website will always display those fields which is wrong. Fix: - Remove hook to make vat required and always display b2b_fields. opw-6446240 opw-6520397 Forward-Port-Of: odoo/odoo#286450
This fix ensures manufactured products are placed in their intended storage locations after components are unreserved and re-reserved. It prevents lot-tracked finished goods from ending up in the wrong warehouse location when putaway rules are configured.
Original PR description
Currently, when the user re-reserves a component and produces an MO for a lot-tracked product, putaway rules stop working. ## Steps to produce: - Install the Manufacturing application. - Go to…
Currently, when the user re-reserves a component and produces an MO for a lot-tracked product, putaway rules stop working. ## Steps to produce: - Install the Manufacturing application. - Go to Settings and enable Lots & Serial Numbers and Storage Locations. - Create a product named 'Laptop' and set it to be tracked by Lots. - Create a product named 'Graphics card' with some quantity on hand. - Create a Bill of Materials (BoM) for the Laptop with Graphics card as a component. - Create a location named 'Laptop Shelf' with 'WH/Stock' as its parent location. - Create a putaway rule: - When a product arrives in: WH/Stock - Product: Laptop - Store to: WH/Stock/Laptop Shelf - Create and confirm a Manufacturing Order (MO) for the Laptop. - Unreserve the components, open Details, and re-add the Graphics card. - Click Produce All and check the on-hand quantity list view of the Laptop. ## Issue: The Laptop is stored in WH/Stock instead of WH/Stock/Laptop Shelf. ## Root cause: When the user presses the unreserve button the finished move is passed to `_do_unreserve` https://github.com/odoo/odoo/blob/157874aad3aebef5bc9268de6e17530641107e31/addons/mrp/models/mrp_production.py#L2407 which unlinks all the move lines on finished product moves if they are not picked: https://github.com/odoo/odoo/blob/157874aad3aebef5bc9268de6e17530641107e31/addons/stock/models/stock_move.py#L1043 Now when the user presses the Produce All button, `button_mark_done` is called, which calls `_post_inventory` at: https://github.com/odoo/odoo/blob/a51ca77c825d2dba326dd540e2b4c04ef6c2385d/addons/mrp/models/mrp_production.py#L2236 `_post_inventory` assigns `lot_ids` to the finished product moves at: https://github.com/odoo/odoo/blob/157874aad3aebef5bc9268de6e17530641107e31/addons/mrp/models/mrp_production.py#L1928-L1930 This calls `_set_lot_ids` which creates a move line with quantity 1 at: https://github.com/odoo/odoo/blob/157874aad3aebef5bc9268de6e17530641107e31/addons/stock/models/stock_move.py#L679-L683 After that, `_post_inventory` sets the quantity for the finished product moves at: https://github.com/odoo/odoo/blob/157874aad3aebef5bc9268de6e17530641107e31/addons/mrp/models/mrp_production.py#L1935 Which calls `_set_quantity` and the delta quantity is now zero at: https://github.com/odoo/odoo/blob/157874aad3aebef5bc9268de6e17530641107e31/addons/stock/models/stock_move.py#L477-L483 Because `_set_lot_ids` has already created a move line that satisfies the move quantity, `_process_increase` is not called. Since `_process_increase` is not called, `_set_quantity_done` is never called at: https://github.com/odoo/odoo/blob/157874aad3aebef5bc9268de6e17530641107e31/addons/stock/models/stock_move.py#L463-L465 Since `_set_quantity_done` is not called, `_apply_putaway_strategy` is never called within that function at: https://github.com/odoo/odoo/blob/157874aad3aebef5bc9268de6e17530641107e31/addons/stock/models/stock_move.py#L2565 As a result, the laptop ends up in stock instead of on the shelf. This issue did not occur in lower versions because the feature to produce multiple lots was introduced in version 19.0 by the following commit: https://github.com/odoo/odoo/commit/4bb4e08066449177f89382718ceadd840ce90d0e Before this commit, only `_set_quantity` was called. Since no move line was created because lot_ids were not set in `_post_inventory`, `_process_increase` was called, which then called `_apply_putaway_strategy`, so the putaway rules were applied correctly. ## Solution: Apply putaway rules in the post-inventory function after the user manufactures a product, ensuring the items are placed in the correct locations and preventing products from being misplaced even when putaway rules are defined. opw-6517324 Forward-Port-Of: odoo/odoo#287390
Employee-paid expenses that have been posted now remain included in the Waiting Reimbursement dashboard tile and filter until reimbursement is actually registered. This prevents approved expenses from disappearing from view before payment, giving managers and employees a more accurate reimbursement status.
Original PR description
#### Description of the issue/feature this PR addresses: The "Waiting Reimbursement" tile stops counting an employee-paid expense once its journal entry is posted, instead of once the employee is reimbursed. #### Current behavior before PR: _compute_state sets the state to 'posted' as soon as a move is posted and unpaid, so an own_account expense never stays 'approved', yet get_expense_dashboard still totals the tile on 'approved' only. Regression from the removal of hr.expense.sheet in 704a5a1, which carried the 'posted' state until then. The "Waiting Reimbursement" search filter has the same condition. #### Desired behavior after PR is merged: The tile and the filter also match 'posted', so the expense stays counted until the payment is registered. opw-6410953 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281882