Daily updates from Odoo
Wednesday, June 10, 2026
18 changes · saas-18.4
Resolved issues and error corrections
This update fixes an issue where adding a recurring product to a confirmed sales order without a linked subscription plan would cause an error. The change adds a validation step to prevent this, ensuring that recurring products are only added when a valid subscription is present, improving data integrity.
Original PR description
Steps to reproduce: - Go to Sales → Products. - Create a Service product and enable the Recurring option. - Open an already confirmed Sales Order that does not contain any recurring products. - Add the newly created recurring product to the confirmed order. - Click Save. - Observe that a traceback occurs. Cause: - When adding a recurring product without a subscription plan to a confirmed Sale Order, _timesheet_create_task() attempts to compute a start date using order.next_invoice_date, which is not set. - This leads to a TypeError when `order.next_invoice_date` receives `False`. Solution: - Add a validation to prevent adding recurring products without a subscription plan and raise a proper `UserError` instead of allowing the code to reach task generation logic. task-5932700 Forward-Port-Of: odoo/enterprise#119847 Forward-Port-Of: odoo/enterprise#107691
This update fixes an error in the Colombian DIAN reporting process. Previously, the system incorrectly flagged invoices due to a timezone mismatch between UTC and Bogota time. The fix ensures invoices are validated against the correct local date, allowing accurate DIAN document submissions and avoiding potential reporting issues.
Original PR description
**Steps to reproduce:** * Install `l10n_co_edi` module with DEMO DIAN mode enabled. * Go to Accounting > Vendor > Bills and create a new bill. * Select any Colombian partner different from…
**Steps to reproduce:** * Install `l10n_co_edi` module with DEMO DIAN mode enabled. * Go to Accounting > Vendor > Bills and create a new bill. * Select any Colombian partner different from `Consumidor Final`. * Set the invoice date to 6 days in the past. * Select the DIAN Support Documents journal and a product with UNSPSC category. * Confirm the bill and click `Send Support Document to DIAN` after 5 PM Colombia time. **Observed behavior:** * An error is raised stating the issue date cannot be older than 6 days or more than 6 days in the future, even though the invoice date is within the allowed window in Colombia local time. **Cause:** * The date window validation in `_check_move_configuration` used `fields.Datetime.now()` which returns UTC time. Since Colombia is UTC-5, after 5 PM local time the UTC clock has already rolled over to the next calendar day, making a 6-day-old invoice appear 7 days old and failing the validation incorrectly. **Fix:** * Convert the current UTC datetime to the `America/Bogota` timezone and extract its local date before computing the allowed date window. * Compare directly against `move.invoice_date` (a `date` field) instead of using `fields.Datetime.to_datetime()`, keeping the comparison consistent as `date` vs `date`. opw-6011502 Forward-Port-Of: odoo/enterprise#119794 Forward-Port-Of: odoo/enterprise#115256
This update corrects a missing field on Fedex shipping labels, specifically the 'REF' field. This field is required by the Fedex API and was previously left blank, causing delivery issues. The fix ensures accurate label generation and proper communication with the shipping carrier.
Original PR description
Backport of bb4f8bf Original PR #116870 Forward-Port-Of: odoo/enterprise#118967 Forward-Port-Of: odoo/enterprise#117873
This update resolves an issue where the barcode inventory count feature would fail when using archived units of measure. The fix ensures that archived UOMs are correctly included in the inventory count cache, allowing accurate counts to be performed. This prevents errors during physical inventory adjustments.
Original PR description
### Steps to reproduce: - In the settings enable: "Units of Measure & Packagings", "Storage Locations" - Create a product in units and register 1 unit in stock - Inventory > Operations > Adjustments…
### Steps to reproduce: - In the settings enable: "Units of Measure & Packagings", "Storage Locations" - Create a product in units and register 1 unit in stock - Inventory > Operations > Adjustments > Physical Inventory - Select your line and request a count > Set Current Value - Inventory > Configurations > units of measures > UOM categories - Select unit and archive it - Go to the barcode app > Click Count inventory ### > Owl error: Uncaught promise ### Cause of the issue: Since the uom used on the quant is archived, it is not found by the search used to fill the barcodeCache: https://github.com/odoo/enterprise/blob/26546bcd3beebc7f65ce08385441b6284b46598e/stock_barcode/static/src/components/main.js#L209-L213 https://github.com/odoo/enterprise/blob/26546bcd3beebc7f65ce08385441b6284b46598e/stock_barcode/models/stock_quant.py#L104-L106 https://github.com/odoo/enterprise/blob/26546bcd3beebc7f65ce08385441b6284b46598e/stock_barcode/static/src/components/main.js#L229 https://github.com/odoo/enterprise/blob/26546bcd3beebc7f65ce08385441b6284b46598e/stock_barcode/static/src/models/barcode_model.js#L37-L39 However, if the uom is not present in the barcode cache the `BarcodeQautnModel` will fail to createLinesState whihc raises a missing error: https://github.com/odoo/enterprise/blob/26546bcd3beebc7f65ce08385441b6284b46598e/stock_barcode/static/src/models/barcode_quant_model.js#L712 https://github.com/odoo/enterprise/blob/26546bcd3beebc7f65ce08385441b6284b46598e/stock_barcode/static/src/lazy_barcode_cache.js#L107-L110 opw-6250090 Forward-Port-Of: odoo/enterprise#118987 Forward-Port-Of: odoo/enterprise#118813
This update fixes an issue where undoing the auto-plan feature would reset the allocated hours for shifts, leading to inaccurate workload calculations. The change ensures that shift workloads remain consistent after undoing the auto-plan, improving the reliability of resource planning.
Original PR description
Steps to Reproduce --- 1. Open the Planning module 2. Create an open shift with allocated_hours 3. Click Auto Plan 4. Click Undo on the auto-plan notification Issue --- Undoing an auto-plan operation…
Steps to Reproduce --- 1. Open the Planning module 2. Create an open shift with allocated_hours 3. Click Auto Plan 4. Click Undo on the auto-plan notification Issue --- Undoing an auto-plan operation triggers recomputation of allocated_hours, causing the shift to lose its original workload value. Current Behaviour --- When resource_id is set to False during undo: - _compute_allocated_hours is triggered (depends on resource_id) - _compute_allocated_percentage is triggered (depends on allocated_hours) - Both fields are recalculated, potentially changing allocated_hours from its pre-assignment value Expected Behaviour --- Undoing auto-plan should preserve allocated_hours at its pre-assignment value while allowing allocated_percentage to adapt to the new context (open slot vs assigned resource). Fix --- Use protecting context manager in action_rollback_auto_plan_ids to prevent allocated_hours from being recomputed when resource_id is removed. This allows allocated_percentage to recalculate naturally based on slot duration while keeping allocated_hours stable. task - 4952149 Forward-Port-Of: odoo/enterprise#119772 Forward-Port-Of: odoo/enterprise#102864
This update fixes a bug where untaxed invoice lines in German accounting reports incorrectly copied the datev code from the previous line. The fix ensures that untaxed lines now properly display an empty datev code, aligning with German tax regulations. This prevents reporting discrepancies and ensures accurate financial data for our German clients.
Original PR description
**PROBLEM** Untaxed move lines would take the datev code of the previous line instead of having no datev code like they should. **STEP TO REPRODUCE** 1. On a german company, create an invoice with a line with tax 19% I, and a line that is untaxed (with a non-null price). 2. On the general ledger, generate the datev zip. 3. Unzip, and open the account entries csv, and notice the 2nd line of the invoice as the datev code set to something instead of it being empty (column BU-Schlüssel). opw-6141003 Forward-Port-Of: odoo/enterprise#118486
This update resolves an error that occurred when confirming DHL deliveries. The system now automatically sets a future delivery date (one hour ahead) to avoid the 'date must be in the future' error, which previously prevented successful order confirmations. This ensures DHL delivery confirmations function correctly.
Original PR description
When confirming the delivery of an order using DHL shipping method we get an error that the date must be in the future. This happens when the scheduled date was not set, or set for a time in the past. This commit automatically sets the time to 1 hour in the future and bypasses the user error. opw-6148927 Forward-Port-Of: odoo/enterprise#116211
This update fixes an issue where subscription product quantities weren't correctly applying pricelist rules, specifically when the quantity was set to 1. The change ensures that the unit price adjusts to the correct price based on the defined quantity tiers, improving the accuracy of subscription billing.
Original PR description
Steps to produce: --- - Install `sale_subscription` module. - Enable `pricelists` from Settings. - Create a new subscription product. - Create a new pricelist and Under Recurring Prices, add below…
Steps to produce:
---
- Install `sale_subscription` module.
- Enable `pricelists` from Settings.
- Create a new subscription product.
- Create a new pricelist and Under Recurring Prices, add below rules for
the monthly recurring plan on creatred subscription product:
- Min Qty = 0 then Price = 0.
- Min Qty = 10 then Price = 10.
- Min Qty = 20 then price = 20.
(This setup ensures the product is free when the quantity is less than 10, and
pricing increases based on the defined quantity tiers.)
- Create a sale order > Set a customer > Select the recurring plan as `Monthly` > Apply the created pricelist.
- Add the subscription product with quantity = 20 then Unit price is correctly set to 20.
- Change the quantity to 1.
Observation:
---
- The unit price does not update to 0 as expected.
Root cause:
---
- At [1], when quantity is updated to 1, `super()._get_pricelist_price()` correctly returns `0`.
- However, due to the `or self.price_unit` condition, the existing unit price is retained instead of applying the new value.
- This prevents valid pricelist rules (including zero-priced ones) from being applied.
Fix:
---
- As shown in [2], `line.pricelist_item_id` is set when a matching pricelist rule is found. Therefore, when a rule (including one for quantity = 0) applies, it will be reflected in `line.pricelist_item_id`.
- If `pricelist_item_id` is set, the computed price from the rule must be used; otherwise, fall back to the existing unit price.
[1]: https://github.com/odoo/enterprise/blob/7498010b8206df56fc5d8a9fd08b24169bf08cb2/sale_subscription/models/sale_order_line.py#L651-L654
[2]: https://github.com/odoo/odoo/blob/fab39bbea642c1a185e6cb91afea860fa0c0f27d/addons/sale/models/sale_order_line.py#L547-L557
opw-6122234
---This update significantly speeds up the process of adding and removing participants from marketing campaigns. The change optimizes a key function within the marketing automation module, reducing processing time from over 51 seconds to just 0.65 seconds when handling large campaigns (over 115,000 participants). This improves overall campaign management efficiency.
Original PR description
Replace search_read with search_fetch to avoid unnecessary _read_format call in backend context. Use OrderedSet instead of a custom _uniquify_list helper to get O(1) membership tests when computing records to add or remove from campaigns. Benchmark on a campaign with 115k participants: | Before PR | After PR | |:---------:|:--------:| | 51.71s | 0.652s | opw-6055334 Forward-Port-Of: odoo/enterprise#119589 Forward-Port-Of: odoo/enterprise#117656
This update resolves an issue where PE tax reports in Odoo 18.4 couldn't generate closing entries due to a change in the accounting workflow. The fix adds a dedicated Peruvian tax report variant and a Return Type, allowing users to correctly configure tax accounts and trigger the closing process safely, particularly in multi-VAT environments.
Original PR description
### Issue Since the introduction of the Tax Returns feature in 18.3, it was no longer possible to generate a Closing Entry as the button has been replaced by Returns The Return mechanism implies that…
### Issue Since the introduction of the Tax Returns feature in 18.3, it was no longer possible to generate a Closing Entry as the button has been replaced by Returns The Return mechanism implies that you need a Return Type in order to make a Closing Entry using the Validate button Additionally, using the Generic Tax Report by default creates a risk in Multi-VAT environments, as it mixes taxes from all countries instead of isolating Peruvian taxes ### Cause The new 18.3 accounting workflow requires at least one active Return Type associated with a country-specific report variant to display the Return options and process the closing entry Peru was relying on the Generic Tax Report, without a dedicated report variant No Return Type was configured, which blocked Odoo's automatic VAT closing workflow and prevented the system from prompting the user to configure the required closing accounts ### Steps to reproduce - Install `l10n_pe_reports` and `accountant` - Switch to a PE Company - Go to the Tax Report Before the fix, no Returns button is available for any of the existing reports, making it impossible to use Odoo's automatic process to configure the tax accounts and trigger the closing entry ### Notes This is fixed by creating a dedicated Peruvian tax report variant directly in Enterprise that inherits from the generic tax report A custom handler is added to force the domain filtering on Peruvian taxes only, and a corresponding Return Type is defined to restore the full closing entry process safely opw-5978673 Forward-Port-Of: odoo/enterprise#117891
This update fixes a misleading error message displayed when a shift template's start time was set after its end time. The message has been corrected to accurately state that the start time must be before the end time, improving clarity for users creating shift templates. This ensures accurate shift scheduling.
Original PR description
Before this commit, when the user set a start hour after end hour, the error message raised said: "The start hour cannot be before the end hour for a one-day shift template.". Which does not make sense since the start hour has to be before the end hour to be valid. This commit fixes the error message to say the start hour cannot be after the end hour. Forward-Port-Of: odoo/enterprise#119637
This update resolves a potential error in the Hong Kong payroll calculations. The fix ensures the system doesn't divide by zero when a company's resource calendar is missing or if an employee has zero hours per week. This prevents inaccurate payroll processing and ensures correct payments.
Original PR description
. Add a check for a null resource calendar and zero hours per week. task-6229271 Forward-Port-Of: odoo/enterprise#117685
This update prevents users from directly creating employee, cost, or mandatory benefits records through the Benefits form. This change ensures data integrity by requiring these records to be created through the standard HR contract workflow, improving data accuracy and reducing potential errors.
Original PR description
This commit prevents creating new employee, cost or mandatory benefits records directly from the Benefits form by setting these fields' `'no_create'` to `True`. task-5156844 Forward-Port-Of: odoo/enterprise#96770
This update corrects a display issue in the journal report when multiple countries are used for tax calculations. Previously, the report incorrectly rendered column widths and, critically, failed to show country selections with more than two options. This ensures accurate tax reporting across multiple jurisdictions.
Original PR description
When more than 2 country are used in the taxes, the colspan of the header is wrong. When more than 2 country are used in tax grids, the country isn't displayed anymore. Forward-Port-Of: odoo/enterprise#119348
This update resolves an issue where users with limited accounting rights incorrectly marked invoices as fully paid during bank reconciliation, leading to inaccurate financial reporting. The fix ensures proper reconciliation matching by safely bypassing a user permission check within the automated process, maintaining data auditability.
Original PR description
### Issue When you have an invoice partially paid via a method using an Outstanding Account, the payment can be kept open, leaving the invoice considered as partially paid If a user with only…
### Issue When you have an invoice partially paid via a method using an Outstanding Account, the payment can be kept open, leaving the invoice considered as partially paid If a user with only "Invoicing & Banks" rights tries to reconcile a Bank Statement with the same partner, amount, and the invoice name as the memo, the automatic reconciliation fails to properly match the payment Instead, the invoice is incorrectly considered as Fully Paid with an unwanted extra Account Receivable line added ### Cause When a new Bank Statement is created, `_try_auto_reconcile_statement_lines()` is called and matches the outstanding credit, which invokes `set_line_bank_statement_line()` This function creates a balancing line and triggers `move._compute_checked()` to update dependencies However, `move.checked` requires `_is_user_able_to_review()` to be True A user with "Invoicing & Banks" rights lacks the `account.group_account_user` group, meaning the move is not marked as checked, preventing dependencies from computing correctly Consequently, the statement line's `amount_residual` is not cleared and the line is not removed from `remaining_st_line_ids` Later in the process, `_try_auto_reconcile_statement_lines()` is called again with `with_user(SUPERUSER_ID)` Because the payment matching was never finalized in the previous step, the engine fallback matches against the full invoice, adding an incorrect Account Receivable line to close it ### Steps to reproduce - Install `accountant` - Go to Accounting / Configuration / Accounting / Journals - Open the Bank, under Incoming Payments tab, set the Manual Payment method's Outstanding Receipts account to 101403 Outstanding Receipts - Update the Demo user's accounting rights to Invoicing & Banks - Log in with the Demo user - Create and confirm an invoice for Acme Corporation (Amount: $1100) - Register a payment on the invoice (Amount: $500, Keep open) - Copy the invoice name - Open the Bank Reconciliation widget from the Accounting Dashboard - Create and add a new Bank Statement Line (Label: Invoice name, Partner: Acme Corporation, Amount: $500) Before the fix, an unexpected Account Receivable line is created and the invoice is marked as Fully Paid ### Notes Instead of processing the entire block under SUPERUSER_ID, which would hide the creator identity in logs and chatter, the context key `skip_account_review_check=True` is injected during the automated statement line reconciliation This safely bypasses the group check inside `_is_user_able_to_review` for this specific automated flow A fallback using `.with_user(SUPERUSER_ID)` is already implemented twice within the same `_try_auto_reconcile_statement_lines` method for this specific use case, but avoiding it here preserves data auditability opw-6077137
This update resolves an issue where a specific combination of input data (short street address and a 'false' setting for a second street) was causing errors in the generation of French VAT reports. The fix ensures accurate report formatting and prevents potential processing failures, improving the reliability of this important financial reporting process.
Original PR description
When the street field is shorter than 30 char and street 2 is false, we end up with " False" in the xml, which will return an error in aspone. no task id Forward-Port-Of: odoo/enterprise#119718
A recent issue preventing users from adding cover images to Knowledge articles has been resolved. The fix corrects a technical error within the Knowledge module related to how cover uploads were handled, ensuring a smoother user experience. This resolves a crash that occurred during the upload process.
Original PR description
Steps to reproduce: 1. Install Knowledge. 2. Create an article. 3. Open the more actions menu. 4. Click "Add Cover". 5. Upload a cover image. Issue: - The upload crashes with the following traceback: `Uncaught Promise > this.props.setAbortUploadsCallback is not a function` Cause: - `KnowledgeCoverSelector` extends the html_editor `ImageSelector`, whose upload flow registers an abort callback through setAbortUploadsCallback. The generic MediaDialog provides this callback, but KnowledgeCoverDialog renders KnowledgeCoverSelector directly and did not pass it. As a result, the inherited upload flow called a missing prop. Solution: - Pass setAbortUploadsCallback from KnowledgeCoverDialog to KnowledgeCoverSelector and abort pending uploads when the cover dialog is discarded. Alternative approach: - Make ImageSelector tolerate callers that do not provide setAbortUploadsCallback by calling it with optional chaining. opw-6176716
This update fixes an issue where placeholder images were unnecessarily included in menu synchronization, leading to slower loading times. Now, only actual product images are sent, resulting in a more efficient and responsive menu display for users. This change improves the overall user experience.
Original PR description
This commit prevents placeholder images from being included in the menu sync payload and only sends `img_url` when an actual image is configured on the product or category. Task-6251430 Forward-Port-Of: odoo/enterprise#119883 Forward-Port-Of: odoo/enterprise#119482