Daily updates from Odoo
Tuesday, July 21, 2026
13 changes · saas-19.1
Resolved issues and error corrections
This fixes Peruvian electronic invoices so detraction amounts are converted to PEN correctly even when the company currency is not PEN. It also ensures invoice PDFs show the correct Peruvian currency symbol, reducing reporting errors and SUNAT submission issues.
Original PR description
**Steps to reproduce:** * Install the **l10n_pe_edi** module. * Change the company currency to **USD**. * Configure **Peruvian detraction** settings: * Set a **withholding percentage** on a product.…
**Steps to reproduce:**
* Install the **l10n_pe_edi** module.
* Change the company currency to **USD**.
* Configure **Peruvian detraction** settings:
* Set a **withholding percentage** on a product.
* Set a **withholding code** on the same product.
* Create a customer invoice in **USD**.
* Set the **Operation Type** to **[1001] Operation Subject to Detraction**.
* Add the configured product to the invoice.
* Confirm the invoice, **send it to SUNAT** by *process now**, and generate the ZIP which has XML.
**Observed behavior:**
* The generated XML contains: `<cbc:Amount currencyID="PEN">116.82</cbc:Amount>` The `currencyID` is `PEN` but the amount is the raw USD value instead of being converted to PEN using the exchange rate.
* The PDF report also shows the withholding amount with the wrong currency symbol.
**Cause:**
* `_l10n_pe_edi_get_spot()` computed `spot['amount']` as `amount_total_signed * percent`, where `amount_total_signed` is stored in the **company currency**. When the company currency is PEN this works correctly, but when it is changed to USD the value is in USD while the XML node hardcodes `currencyID="PEN"`.
* `spot['currency']` was also set to `company_id.currency_id`, so the PDF rendered the amount with the wrong currency symbol.
* In `_add_invoice_payment_terms_nodes`, `spot_amount` was selected via `spot['amount'] if invoice.currency_id == invoice.company_id.currency_id` which relied on company currency being PEN as a proxy for the invoice being in PEN, breaking when company currency is USD.
**Fix:**
* In `_l10n_pe_edi_get_spot()`, compute `spot['amount']` by explicitly converting `amount_total` from the invoice currency to PEN using `currency_id._convert(..., env.ref('base.PEN'), ...)`, ensuring the detraction amount is always in PEN regardless of the company currency.
* Set `spot['currency']` to `env.ref('base.PEN')` so the PDF report always displays the withholding amount with the correct PEN symbol.
* In `_add_invoice_payment_terms_nodes`, always use `spot['spot_amount']` (invoice currency amount) for the `FormaPago`/`Cuota` arithmetic, since `spot['amount']` is now exclusively the PEN amount for the detraction XML node.
opw-6327571
Forward-Port-Of: odoo/enterprise#123782The chatter panel now remains visible at the right side of the screen when viewing large or wide financial reports. This lets users keep communicating and reviewing notes without needing to scroll horizontally across the report.
Original PR description
Issue: - When reports are large/wide, the chatter component is pushed beyond the visible viewport, appearing only at the absolute right edge of the overflowing report rather than the right edge of the screen. Fix: - Updated the layout container to prevent the chatter from shrinking or overflowing with the report block, ensuring the main report scrolls independently while the chatter stays pinned to the screen viewport. Impact: - Keeps the chatter panel fully visible on the right side of the screen, allowing users to communicate without scrolling horizontally on wide reports. task-[6376792](https://www.odoo.com/odoo/project/967/tasks/6376792) Forward-Port-Of: odoo/enterprise#123734
Amazon shipping through Envia now includes each product's weight when creating labels. This prevents valid high-quantity shipments from being blocked by Amazon's weight validation error.
Original PR description
**Issue:** Envia API documentation is very bad. When trying to generate an Amazon Ground shipping with Envia, the API will sometimes reject the payload with the following error: `Total items weight…
**Issue:** Envia API documentation is very bad. When trying to generate an Amazon Ground shipping with Envia, the API will sometimes reject the payload with the following error: `Total items weight exceeds package weight. Please refer to API documentation for allowable limits. (D-703)` Even though the [Envia documentation](https://docs.envia.com/reference/create-shipping-label) doesn't include it, it seems that Amazon requires the weight for each product. If the payload doesn't include the per-item weight, Amazon will set a default weight, which will cause the error to show up if the delivery contains a high quantity. This can be a blocking issue for some customers. **Steps to reproduce on a fresh DB:** - Install Inventory, Sales, and Envia Shipping - Switch company to be based in India (need to provide an address to deliver from, I just used the Odoo India address - InfoCity Gate, Gandhinagar, Gujarat 382007) - Configure an Amazon delivery carrier with Envia (India seems to be the only country that supports Amazon with Envia) - Inventory > Configuration > Delivery Methods > Envia.com method - Must be in a Production environment (because Envia's sandbox server does not work for some reason?) - Add an Envia Production Access Token (will have to use one with some funds) - Change 'Ship From' to India - Configure the `Envia.com Service Name`, set Carrier and Service to AMAZON and AMAZON - Amazon Shipping Standard - Create a demo product, give it an arbitrary weight like 0.1 kg - Create a sales order to an Indian customer, include the demo product with a high quantity (like 20), confirm (might have to create a warehouse and configure the customer's information) - On the generated picking, set the Carrier to Envia.com on the Additional Info tab - When trying to Validate, it should throw the error **Fix:** When generating the payload in _get_shipping_lines() in envia_request, include the item weight in the dictionary. Related ticket: opw-6261682 Forward-Port-Of: odoo/enterprise#123935
Lazada and Shopee order imports now calculate discounts, shipping, and small rounding differences in a way that matches the marketplace totals. This reduces mismatches during order reconciliation and gives clearer sales lines for discounts and shipping.
Original PR description
Marketplace orders with discount lines could not match the platform total: Odoo accumulated a small rounding residue vs Shopee's total_amount / Lazada's order price. sale_shopee ----------- Changes:…
Marketplace orders with discount lines could not match the platform total: Odoo accumulated a small rounding residue vs Shopee's total_amount / Lazada's order price. sale_shopee ----------- Changes: - Fetch buyer-side escrow amounts via `_fetch_order_income` and pass them through `self.env.context` (`order_income`). - Build item lines from the buyer-paid item price with `discount=0` and a recomputed tax-exclusive `price_unit`. - Distribute order-level discounts (seller/platform vouchers and coins) as dedicated negative lines per product tax group via `_prepare_discount_lines_values`. - Append a shipping line from `buyer_paid_shipping_fee` with fiscal-position mapped taxes. - Reconcile any leftover residue with `_adjust_order_total` using a single tax-free amount-adjustment line. - Register `default_discount_product` and configure it on upgrade (v1.1). sale_lazada ----------- - Port the same reconciliation model as shopee: reconciled line specs, discount=0 with discounted unit from paid_price, shipping line from shipping_fee, order-level "Discount line" distributed at order-level. task-6112062 Forward-Port-Of: odoo/enterprise#117561
This fix makes the point-of-sale barcode lookup check product creation permissions immediately and consistently. It helps avoid inconsistent behavior when staff try to create products from barcode lookup screens.
Original PR description
Replace the asynchronous `allowProductCreation` method with the `hasProductCreationAccess` getter to evaluate product creation permissions synchronously and ensure consistent behavior. Task-6361787 Related PR: https://github.com/odoo/odoo/pull/274420 Forward-Port-Of: odoo/enterprise#124825 Forward-Port-Of: odoo/enterprise#123073
Steps to reproduce: - Install the PayU payment provider. - Click the Connect button and complete the onboarding flow. - After being redirected back to the PayU provider form, click Disconnect. Issue: - After confirming the disconnection, a validation error is raised stating that the PayU fields must be filled in. Cause: - During disconnection, the PayU-specific fields are cleared. At that point, `_check_required_if_provider` is triggered, and since those fields have the `required_if_p
Original PR description
Steps to reproduce: - Install the PayU payment provider. - Click the Connect button and complete the onboarding flow. - After being redirected back to the PayU provider form, click Disconnect. Issue: - After confirming the disconnection, a validation error is raised stating that the PayU fields must be filled in. Cause: - During disconnection, the PayU-specific fields are cleared. At that point, `_check_required_if_provider` is triggered, and since those fields have the `required_if_provider` attribute, it raises a `ValidationError` because their values are now `None`. Fix: - Remove the `required_if_provider` attribute from the PayU-specific fields. opw-6391133 Forward-Port-Of: odoo/odoo#276567
Steps to reproduce: 1. Edit/Create an activity type (e.g., "To Do") and enable "Keep Done". 2. Schedule an activity of this type on a journal (or a journal entry/move) with a deadline in the past. 3. Mark the activity as done. 4. Go to the Accounting Dashboard. Notice that the activity is still shown as "overdue" in red on the journal card. When an activity type has "Keep Done" enabled, completed activities are not deleted from the database. Instead, they are archived by setting `active =
Original PR description
Steps to reproduce: 1. Edit/Create an activity type (e.g., "To Do") and enable "Keep Done". 2. Schedule an activity of this type on a journal (or a journal entry/move) with a deadline in the past. 3. Mark the activity as done. 4. Go to the Accounting Dashboard. Notice that the activity is still shown as "overdue" in red on the journal card. When an activity type has "Keep Done" enabled, completed activities are not deleted from the database. Instead, they are archived by setting `active = False` and `date_done` is populated. Since the activity dashboard query retrieves records via direct SQL, it bypasses Odoo's automatic active filtering on `mail.activity`. As a result, archived (done) activities were incorrectly fetched and displayed on the journal dashboard cards, appearing as overdue. This commit resolves the issue by explicitly adding `AND activity.active = TRUE` to the SQL queries. Task-6142042 Forward-Port-Of: odoo/odoo#276998 Forward-Port-Of: odoo/odoo#274313
The reversal wizard always injected a shared 'R4' onto every credit note it created, so a credit note of a simplified invoice never got the required 'R5', and reversing several invoices of mixed simplified status at once forced the same reason onto all of them. The wizard now derives the reason per original move ('R5' if it is simplified, 'R4' otherwise) instead of using one shared value, while still respecting an explicit manual choice. `l10n_es_is_simplified` already freezes correctly
Original PR description
The reversal wizard always injected a shared 'R4' onto every credit
note it created, so a credit note of a simplified invoice never got
the required 'R5', and reversing several invoices of mixed simplified
status at once forced the same reason onto all of them.
The wizard now derives the reason per original move ('R5' if it is
simplified, 'R4' otherwise) instead of using one shared value, while
still respecting an explicit manual choice. `l10n_es_is_simplified`
already freezes correctly on the credit note via its existing compute,
so no new compute is needed on `l10n_es_edi_verifactu_refund_reason`.
task-6358684
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#276187PR #247474 fixed an error where the lock date restriction was applied overzealously, restricting `stock.picking` models with a `scheduled_date` field before the lock date. This field does not affect accounting entries. The previous fix was to only check the `scheduled_date` field if the picking was in the `done` state. A more complete fix is to simply not check the `scheduled_date` field. opw-6311703 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-
Original PR description
PR #247474 fixed an error where the lock date restriction was applied overzealously, restricting `stock.picking` models with a `scheduled_date` field before the lock date. This field does not affect accounting entries. The previous fix was to only check the `scheduled_date` field if the picking was in the `done` state. A more complete fix is to simply not check the `scheduled_date` field. opw-6311703 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270875
Issue: In a multi-company environment, when an attachment is uploaded in the chatter, the resulting `ir.attachment` record incorrectly sets the company_id to the current user's default company. This occurs regardless of the active company or the company associated with the record the attachment is linked to. Steps to reproduce: In a multi-company setup, activate only Company B. Open any chatter and attach a file. Navigate to Settings > Technical > Data Structure > Attachments. Current b
Original PR description
Issue: In a multi-company environment, when an attachment is uploaded in the chatter, the resulting `ir.attachment` record incorrectly sets the company_id to the current user's default company. This…
Issue: In a multi-company environment, when an attachment is uploaded in the chatter, the resulting `ir.attachment` record incorrectly sets the company_id to the current user's default company. This occurs regardless of the active company or the company associated with the record the attachment is linked to. Steps to reproduce: In a multi-company setup, activate only Company B. Open any chatter and attach a file. Navigate to Settings > Technical > Data Structure > Attachments. Current behaviour: The created attachment has its company_id set to the user's default company, rather than the currently active company, or the company of the record, even when the record has a company_id field. This behavior introduces inconsistencies in data visibility, particularly when attachments appear to belong to a company different from the one associated with the related business record. Behaviour After Fix: If the related record (i.e., the model the attachment is linked to) contains a company_id field, its value will be used as the attachment's company_id otherwise, the attachment's company_id will be set to the currently active company's id. This logic ensures proper alignment between attachments and their related business records and also maintaining consistency in multi-company scenarios. task-4563173 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277582 Forward-Port-Of: odoo/odoo#235665
Steps: - Enable `pos_hr` and configure employees - Open the POS - Log in as an employee - Open the burger menu in the navbar Issue: - The "Create Product" menu is not visible immediately after the employee logs in. - It only appears after refreshing the POS. Cause: - The visibility of the menu is determined when `Navbar` component is mounted. - Since the `Navbar` is mounted only once when the POS UI loads, the value is not updated after employee login. Fix: - Replace the asynch
Original PR description
Steps: - Enable `pos_hr` and configure employees - Open the POS - Log in as an employee - Open the burger menu in the navbar Issue: - The "Create Product" menu is not visible immediately after the employee logs in. - It only appears after refreshing the POS. Cause: - The visibility of the menu is determined when `Navbar` component is mounted. - Since the `Navbar` is mounted only once when the POS UI loads, the value is not updated after employee login. Fix: - Replace the asynchronous permission check with a getter that evaluates product creation rights. - Cache the group access information in `posService` and let the hr override use the getter. Task-6361787 Related PR: https://github.com/odoo/enterprise/pull/123073 Forward-Port-Of: odoo/odoo#277216 Forward-Port-Of: odoo/odoo#274420
Issue: When a shopper pays for an online order entirely using a reward (e.g. a discount code covering 100% of the total), the order total is zero. With automatic invoicing enabled, an invoice with an amount of 0 is created. But, the 0 invoice is never emailed to the customer. Whereas, for orders where the total is more than 0, an invoice is created, then emailed to the customer. The customer should be emailed the invoice, even if its amount is 0. Steps to reproduce: 1. Enable automatic invo
Original PR description
Issue: When a shopper pays for an online order entirely using a reward (e.g. a discount code covering 100% of the total), the order total is zero. With automatic invoicing enabled, an invoice with an…
Issue: When a shopper pays for an online order entirely using a reward (e.g. a discount code covering 100% of the total), the order total is zero. With automatic invoicing enabled, an invoice with an amount of 0 is created. But, the 0 invoice is never emailed to the customer. Whereas, for orders where the total is more than 0, an invoice is created, then emailed to the customer. The customer should be emailed the invoice, even if its amount is 0. Steps to reproduce: 1. Enable automatic invoicing. 2. Create a code for a 100% discount. 3. As a shopper, add a product to cart on the website. 4. While checking out, apply the 100% discount code to the order. 5. Complete the checkout. 6. Confirm that an invoice was created and posted, but was not emailed to the customer. Explanation: Normally, order confirmation and invoicing are handled by the `_post_process` method on the `payment.transaction` model. With automatic invoicing enabled, `_post_process` confirms the sale order, creates the invoice, and sends the invoice via `_send_invoice` (another method on the `payment.transaction` model). If `sale.async_emails` is enabled, `_post_process` will trigger a cron that invokes `_send_invoice` instead of invoking it directly. When an order is fully covered by a reward, there's nothing to pay. In this case, no payment.transaction record is ever created, and `_post_process` never runs. Instead, the order is confirmed through the `_validate_order` method on the `sale.order` model. The `sale_loyalty` module extends `_validate_order` so that, with automatic invoicing enabled, it will create and post an invoice for zero-amount orders. But, nothing in this path ever calls `_send_invoice` or an equivalent. So, the invoice is created and posted but never sent. Solution: This adds logic for sending invoices to the extension of `_validate_order` in the `sale_loyalty` module. We mirror the logic used in `_send_invoice` in the `payment.transaction` model. Notes: There is duplicated code from `_send_invoice` in this fix. That is because `_send_invoice`, a method on the `payment.transaction` model, can't be used in this flow. A fix that avoids code duplication would require serious refactoring. This will never trigger a cron to send the invoice, even if `sale.async_emails` is enabled. That is because the cron invokes `_send_invoice`. Since fully reward-covered orders are probably not common, any performance benefits of using a cron are probably not significant. But, making a new cron to be used in this case is also an option. opw-6363334 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275190
Miscellaneous changes
_**Description of the issue/feature this PR addresses:**_ SaleOrder._onchange_order_line retrieves the linked lines of each order line by calling SaleOrderLine._get_linked_lines(). That method filters the whole order_line recordset on every call. Since the onchange is triggered by any change to order_line, this noticeably slows down every modification of the lines on large orders even when the order contains no combo product at all. _**Current behavior before PR:**_ For every order line,
Original PR description
_**Description of the issue/feature this PR addresses:**_ SaleOrder._onchange_order_line retrieves the linked lines of each order line by calling SaleOrderLine._get_linked_lines(). That method…
_**Description of the issue/feature this PR addresses:**_
SaleOrder._onchange_order_line retrieves the linked lines of each order line by calling SaleOrderLine._get_linked_lines().
That method filters the whole order_line recordset on every call.
Since the onchange is triggered by any change to order_line, this noticeably slows down every modification of the lines on large orders even when the order contains no combo product at all.
_**Current behavior before PR:**_
For every order line, _onchange_order_line calls line._get_linked_lines(), and each call re-scans the entire order_line recordset with filtered(). The cost therefore grows with the total number of lines (regular lines included), so editing any line on a large order is sluggish.
_**Desired behavior after PR is merged:**_
The {line: linked_lines} mapping is computed in a single pass via the new method SaleOrderLine._get_linked_lines_by_line(), called once per onchange instead of once per line.
The method _get_linked_lines() is kept as a thin single-record wrapper delegating to the batched method, preserving backward compatibility for external callers. Behavior is unchanged and only the performance is improved: the onchange now scales linearly with the number of order lines.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#277185