Daily updates from Odoo
Monday, July 20, 2026
18 changes · 19.0
Enhancements to existing features
This update adds a cleanup script for the Belgian POS blackbox module. It helps prevent copied or test databases from retaining device network details and Belgian POS identifiers that should be reset before reuse.
Original PR description
Add a `neutralize.sql` file to the `l10n_be_pos_blackbox` module to reset the blackbox `local_ip` and the config's `l10n_be_pos_id` and `establishment_number`.
Resolved issues and error corrections
Fixed an issue where Project tasks could be accidentally duplicated after switching browser tabs during a drag action. Tasks now correctly reschedule when dropped unless the user is actively choosing to copy them, reducing accidental planning errors.
Original PR description
## Current behavior: When rescheduling a task in Project's Gantt chart view, if user switches to a different browser tab using the Ctrl shortcuts (either Ctrl + Tab, Ctrl + Shift + Tab or Ctrl + PgUp…
## Current behavior: When rescheduling a task in Project's Gantt chart view, if user switches to a different browser tab using the Ctrl shortcuts (either Ctrl + Tab, Ctrl + Shift + Tab or Ctrl + PgUp / PgDn), and navigate back to Gantt chart view, the task will get duplicated unexpectedly when getting dragged around even when the Ctrl button is released ## Expected behavior: Dropping a task without Ctrl held should reschedule even after a tab switch using the Ctrl shortcuts ## Steps to reproduce: 1. Install `project` module 2. Create a project and switch to Gantt chart view 3. Hold Ctrl and start dragging a task while switching browser tab with Ctrl+Tab, Ctrl+Shift+Tab, or Ctrl+PgUp/PgDn 4. Return to the Gantt tab and drop the task without holding Ctrl 5. The task is duplicated instead of rescheduled ## Cause of the issue: Copy and reschedule actions are tracked internally via interaction.dragAction, updated only on window keydown/keyup for Control. Currently, we're not keeping track of the `visibilitychange` event when switching tabs, causing the state of `ctrlPressed` to stale after a tab change, causing the dragAction to stay on copy mode ## Fix: Reset `dragAction` and `ctrlPressed` on document's `visibilitychange` when the tab has been changed opw-6298440
Lazada and Shopee order imports now handle discounts, vouchers, shipping fees, and small rounding differences in a way that matches the marketplace totals. This reduces mismatches during reconciliation and gives teams clearer order 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
Reconciliation models now use the correct currency when transactions involve multiple currencies. This prevents amounts from staying tied to the original transaction currency and helps businesses reconcile entries more accurately.
Original PR description
In the reconciliation model, the currency is not automatically converted if multiple currencies are being used. Instead, it remains stuck on the original currency of the transaction. This issue is resolved by this commit. runbot-https://runbot.odoo.com/runbot/bundle/190-reconciliation-model-currency-fix-andha-461793 task-5974154
Fixes an issue where selecting a customer in Point of Sale could show an AvaTax tax-loading error when an AvaTax fiscal position was used. This restores the checkout flow for businesses using AvaTax in PoS and avoids interruptions during sales.
Original PR description
Steps to reproduce: ------------------- 1. Install pos_avatax. 2. Enable Avatax in accounting, and use the testing credentials of Odoo. 3. Enable "Use AvaTax API" and "Detect Automatically" on the…
Steps to reproduce: ------------------- 1. Install pos_avatax. 2. Enable Avatax in accounting, and use the testing credentials of Odoo. 3. Enable "Use AvaTax API" and "Detect Automatically" on the default fiscal position (or another fiscal position available in PoS). 4. In a PoS shop, enable "AvaTax PoS Integration" 5. Find a product sell in that PoS, and assign it an "Avatax Category" 6. Open that PoS, add the prodct of step 5, and choose a customer (make sure the fiscal position of step 3 is being used). Observation: Error modal "Error while loading Avatax taxes", and error in the terminal `KeyError: 'base_line'`. Why it's happening: ------------------- Commit 0404086db567 changed the return of `_get_line_data_for_external_taxes`. Before, pos was returning something with `id`, `qty`, `price_subtotal` etc. After the commit the return should have a `base_line` key (the accounting base line we get from `_prepare_base_line_for_taxes_computation`). But that commit forgot to update the override in pos. So when avatax tries to read `line_data['base_line']` we get the KeyError. The fix: -------- Update the override in pos to return the new format, same way `sale_external_tax` is already doing it for sale orders. opw-6244141
Argentine electronic invoices now show a clear warning when a final consumer contact uses an unsupported identification type. This prevents a system error during invoice confirmation and helps users correct customer details before submitting invoices.
Original PR description
After applying the community fix, a new issue appears in enterprise. **Steps to reproduce:** - Install the `l10n_ar_edi` module. - Go to Customers and create a new customer with: - Country: Argentina…
After applying the community fix, a new issue appears in enterprise. **Steps to reproduce:** - Install the `l10n_ar_edi` module. - Go to Customers and create a new customer with: - Country: Argentina - Identification Type: `Passport` - Identification Number: `1234567890a` - AFIP Responsibility Type: `Consumidor Final` - Create a new invoice for this customer with: - Journal: `Electronic Invoice (FE)` - Document Type: `(6) INVOICES B` - Try to confirm the invoice. **Error:** ValueError: invalid literal for int() with base 10: '1234567890a' **Expected behaviour:** For Argentinean contacts with AFIP Responsibility Type `Consumidor Final`, the identification type must be `DNI` or `CUIL/CUIT`. If another identification type is used, the user should receive a proper warning instead of a traceback. (see [1]) **Root Cause:** After the community fix, `_get_id_number_sanitize()` can return an alphanumeric value, which is later converted with `int()` at [2] and [3], causing an error. **Fix:** This commit adds an explicit validation for Argentinean contacts with AFIP Responsibility Type Consumidor Final before converting the identification number to an integer, ensuring the user receives the proper warning message. [1]: https://www.odoo.com/mail/message/1118392033 [2]: https://github.com/odoo/enterprise/blob/064812dd9f1074f287fee677ba35ea4aeef3ab3f/l10n_ar_edi/models/account_move.py#L780-L798 [3]: https://github.com/odoo/enterprise/blob/064812dd9f1074f287fee677ba35ea4aeef3ab3f/l10n_ar_edi/models/account_move.py#L927-L931 Related community PR: https://github.com/odoo/odoo/pull/272651 opw-6333998 Forward-Port-Of: odoo/enterprise#123729
The Commission Adjustments screen no longer offers a quick-create option that could crash the system when users entered an unmatched name. This prevents interruptions for sales teams managing commission adjustments and keeps the workflow stable.
Original PR description
Steps to reproduce: - Go to Sales > Commission > Adjustments - In Add to/Reduce From, type a name with no match - Click Create '<name>' -> server crashes (RPC_ERROR) Cause: `sale.commission.plan.user._rec_name` is a Many2one (`user_id`). Default `name_create` wrote the typed text into that integer column, which Postgres rejected. Fix: - Disable quick-create on `add_user_id`/`reduce_user_id` in the Adjustments list view Version: saas-18.3 to master opw-6384909 Forward-Port-Of: odoo/enterprise#124431
Philippine check printing now rounds the cents portion of written payment amounts to two decimals, even when the currency is configured with more precision. This prevents confusing or incorrect wording on checks and helps printed payments match standard check formatting.
Original PR description
Current behavior: --- When paying with checks, if the currency has more than 2 decimals, the decimal amount is printed with more than 2 decimals. Steps to reproduce: --- 1. Switch to PH company 2. Set setting Check Layout as "Print Check - PH" 3. In the PHP currency, change rounding factor to 0.0001 4. In Decimal accuracy > product price, set 4 digits 5. Create a new Vendor Payment, payment method Check, amount 100.1268 PHP 6. Results: One Hundred and 1268/100, should be 13/100 Expected behavior: --- The xx/100 part of amount in words text in the check should always be rounded to 2 decimals. opw-6302337 Forward-Port-Of: odoo/enterprise#122581 Forward-Port-Of: odoo/enterprise#121913
Appraisals now choose the template assigned to an employee's department instead of keeping a generic default. This helps HR teams use the right appraisal forms automatically while preserving deliberate template choices when they match the department.
Original PR description
**Problem:** When a template is restricted to a department, appraisals for employees of that department do not use it — a generic (global) template is used instead. **Steps to reproduce:** 1. Create…
**Problem:** When a template is restricted to a department, appraisals for employees of that department do not use it — a generic (global) template is used instead. **Steps to reproduce:** 1. Create an appraisal template and restrict it to a department. 2. Make sure at least one global (no department) template also exists. 3. Open a new appraisal and select an employee of that department. 4. Observe the appraisal template stays on the global one. **Current behavior:** The global template that was auto-selected before an employee was chosen is kept, ignoring the department-restricted template. **Expected behavior:** The template restricted to the employee's department is selected. **Cause of the issue:** On a new appraisal the template is computed before an employee (and therefore a department) is set, so a global template is pre-selected. When the employee is then chosen, `_compute_appraisal_template` reruns but the `appraisal.appraisal_template_id or ...` clause short-circuits on the already set global template and never falls through to the department's template. **Fix:** Evaluating the department's template before the existing value ensures a department-restricted template takes precedence over a template that was only auto-selected as a default. The existing value is still preserved when the department has no template of its own, so deliberate choices are untouched. opw-6293936
Planning kanban cards now move overflowing content onto the next line instead of squeezing or cutting it off. This makes schedule information easier to read when entries contain longer text.
Original PR description
Wrap the kanban card content onto the next line when it does not fit on a single line. task-5085363
Spanish VAT books now report tax amounts correctly for vendor bills using EU taxes with negative components. This prevents valid tax amounts from being shown as zero, improving the accuracy of VAT reporting.
Original PR description
Problem: In the Spanish VAT books, taxes with negative component (like 21% EU G) always show their amounts as zero. Steps to reproduce: 1. Install the l10n_es_reports module and select the Spanish company 2. Create a vendor bill with a vendor from another EU country and add a product 3. Make sure the tax applied to the product has a negative component (like 21% EU G) 4. Confirm the bill 5. Go to Accounting > Reporting > Tax Return 6. Generate the VAT books from the action menu and check the tax amounts 7. Notice how the tax amount is zero, even though the tax was applied to the bill Cause: When calculating the tax amounts, the negative component cancels out the positive component, leading to the amount always showing as zero in the VAT books. opw-6169766 Forward-Port-Of: odoo/enterprise#123738
Swiss QR-IBAN payment references are now sanitized before payment files are generated. This helps prevent ISO 20022 payment files from being rejected by Swiss banks due to unsupported characters in references.
Original PR description
**Steps to reproduce:** * Configure a Swiss company with the Swiss accounting localization. * Install `account_sepa`. * Configure a bank journal with a valid Swiss **QR-IBAN**. * Create a vendor with…
**Steps to reproduce:** * Configure a Swiss company with the Swiss accounting localization. * Install `account_sepa`. * Configure a bank journal with a valid Swiss **QR-IBAN**. * Create a vendor with a valid Swiss bank account. * Under **Accounting -> Configuration -> Settings** enable QR Payments. * Go to the vendor and enter the correct QR-IBAN number under the Accounting Section. * Navigate to **Accounting -> Configuration -> Journals** and in the **bank** journal, add the account number of QR-IBAN. * Create and post a vendor payment using the bank journal. * Set the payment reference (`ref`) to contain the `°` character. * Add the payment to a batch payment and generate the ISO 20022 payment file. * Inspect the generated XML. **Observed Behaviour:** The `°` character is preserved in the payment reference for QR-IBAN payments, producing an ISO 20022 file that may be rejected by Swiss banks because it does not comply with the EPC minimum character set. **Cause:** The QR-IBAN branch validates the structured reference before sanitizing it, allowing unsupported characters to remain in the generated XML. **Fix:** Sanitize the payment reference before validating it as a QR structured reference, ensuring invalid characters are removed while preserving valid QR references. opw - 6350931 Forward-Port-Of: odoo/enterprise#124299 Forward-Port-Of: odoo/enterprise#123267
This fixes a failing automated test in the AI module by ensuring the test data matches the expected Gemini embedding response format. The change helps keep quality checks reliable and prevents unrelated demo data from causing false failures during validation.
Original PR description
_cron_generate_embedding retrieves all the sources that don't have an embedding and generate embeddings for those using the model from the provider of the agent configured on the source. The agent configured on the demo sources has OpenAI as the provider and these sources don't have embeddings. When _cron_generate_embedding runs in the test case, it retrieves these demo sources + the source defined in the test case (Which relies on embeddings from Google) and generates the embeddings but then fails. This happens because the _request method is mocked to return the response in Google's format as the test case is specific to Gemini models. runbot.build.error-944173
The point of sale barcode lookup flow now uses the standard permission check when deciding whether a user can create products. This avoids inconsistent behavior and helps ensure only authorized users see or use product creation options.
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#124527 Forward-Port-Of: odoo/enterprise#123073
Resetting a submitted tax return no longer changes the company-wide tax lock date, preventing closed periods from being reopened for everyone by mistake. The fix also ensures companies can set the tax lock date before submitting a return, supporting safer workflows in larger accounting teams.
Original PR description
To reproduce the issue: 1) Initialize a company in Belgium, create the tax returns 2) Submit the VAT return from January 3) Open the lock date wizard. The tax lock date is January 31st. 4) Add a lock…
To reproduce the issue:
1) Initialize a company in Belgium, create the tax returns 2) Submit the VAT return from January
3) Open the lock date wizard. The tax lock date is January 31st. 4) Add a lock date exception removing the tax lock date just for you, for 5 min. 5) Reset January's return
6) Reopen the lock date wizard.
====> Your exception is still there, but the tax lock date for everyone has been reset to December 31st.
This is plain wrong. Resetting a return should not automatically reopen the period for everyone. Lock dates exceptions/modifications are anyway required to reset the return ; they should pilot the whole flow. Nothing being magically hidden from the user means there can't be someone else mistakenly encoding something into the reopened period.
Another fix was required to make this one work: setting the tax lock date before submitting the return should work. In bigger environments, users might want to do that as a first step to reduce the number of people encoding data before actually doing the submission of the return. Therefore, the case where the tax lock date is already set at the date_to of the return when submitting it was supposed to be already supported, and allow the creation of the closing entry for that return, despite it being on the tax lock date. The test ensuring this was however badly written, and the feature didn't work: the closing was created at a later date than the lock date automatically, due to the Bills' Algorithm.
Forward-Port-Of: odoo/enterprise#124811The report screen layout was adjusted so the chatter panel remains visible on the right side of the screen even when reports are very wide. Users can now discuss and follow up on reports without needing to scroll horizontally to find the conversation panel.
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)
Peruvian electronic invoices now convert detraction withholding amounts to PEN correctly even when the company currency is set to USD. This prevents incorrect XML submissions to SUNAT and ensures PDF reports show the proper Peruvian sol amount and symbol.
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-6327571Peruvian electronic invoices that were registered by SUNAT but temporarily lacked their confirmation receipt will no longer get stuck after a duplicate-document response. Odoo now treats this as a retryable warning, allowing automatic retries to continue until SUNAT provides the confirmation, reducing manual follow-up.
Original PR description
Steps to reproduce: - Post a Peruvian invoice so it is sent to SUNAT (directly or through Estela/Digiflow). - SUNAT's sendBill call hangs and Odoo's request times out (ReadTimeout / ConnectionError),…
Steps to reproduce: - Post a Peruvian invoice so it is sent to SUNAT (directly or through Estela/Digiflow). - SUNAT's sendBill call hangs and Odoo's request times out (ReadTimeout / ConnectionError), even though SUNAT actually finishes registering the document on its side a moment later. - Odoo retries sending the same invoice (either automatically through the EDI cron, or manually). SUNAT now replies with a "document already exists" SOAP fault (code 1033/4000), since it processed the previous attempt. - Odoo tries to recover from this by fetching the CDR through getStatusCdr, but SUNAT has not finished generating it yet, so the lookup also fails. Cause of the issue: _l10n_pe_edi_post_invoice_web_service() already has recovery logic for error codes 1033/4000: it calls _l10n_pe_edi_retrieve_cdr() to fetch the CDR and treat the invoice as sent. But when that lookup itself fails (CDR not generated yet), the resulting error keeps the 'blocking_level' set to 'error' from the original SOAP fault. Documents with blocking_level 'error' are excluded from the automatic EDI cron retries (see account.edi.document._cron_process_documents_web_services), so the invoice gets stuck needing a manual retry, which can lose the same race against SUNAT again and again. Solution: When the CDR can't be retrieved yet after a 1033/4000 duplicate error, mark the result as 'blocking_level': 'warning' instead of leaving it at 'error'. This keeps the invoice eligible for the automatic EDI cron retries, so Odoo keeps polling SUNAT until the CDR becomes available, instead of requiring manual intervention every time this race is lost. opw-6393231