Thursday, August 27, 2026
9 changes · 18.0
Resolved issues and error corrections
The checkout flow now detects carts that become zero-priced because of country-based pricing while zero-priced product sales are blocked. Customers are sent back to the cart with a clear warning instead of getting stuck during payment, reducing failed checkout experiences and support issues.
Original PR description
When 'Prevent Sale of Zero Priced Product' is enabled and a country-group pricelist prices a product at 0 once the customer's country becomes known during checkout, the cart total becomes 0. The 'free order' branch then validated the order at the payment step, which could hang and time out for a cart that is not actually sellable. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix prevents duplicate Odoo calendar entries when a single event that was already synced with Outlook is changed into a recurring meeting in Outlook. The old one-time event is removed during sync because the new recurring series now represents it, keeping calendars cleaner and reducing confusion.
Original PR description
When a single event already synced with Outlook is turned into a recurring event directly in Outlook, Microsoft reuses the event in place: the seriesMaster keeps the iCalUId of the former single event, while each occurrence gets a fresh id/iCalUId. On resync, a seriesMaster is only matched against calendar.recurrence, never against calendar.event. As no recurrence exists yet, it is handled as a brand new recurrence whose occurrences are created from scratch. The original single event, which shares the master's iCalUId and the first occurrence's timeslot, is then left untouched. Drop that pre-existing single event when building a new recurrence from an inbound seriesMaster, since it is now represented by the recurrence itself. opw-5129848 Forward-Port-Of: odoo/odoo#271787
This fixes an error that could stop users from generating PDF quotes when Quote Builder documents include dynamic fields. The change preserves required PDF form settings and adds the missing structure expected by the PDF library, making quote printing more reliable.
Original PR description
Issue: --- Due to this issue, generating PDF Quote using Quote Builder with dynamic fields leads to a traceback. This was partially fixed by: e16edc7b0d9f56cb7769068ecf7d64ff8b0f6359 Steps: --- 1-…
Issue: --- Due to this issue, generating PDF Quote using Quote Builder with dynamic fields leads to a traceback. This was partially fixed by: e16edc7b0d9f56cb7769068ecf7d64ff8b0f6359 Steps: --- 1- Using a python 3.13 env, install requirements.txt. (You could instead uninstall pypdf2 and install pypdf==5.4.0) 2- Enable Quote Builder. 3- Create a SO and in quote builder tab, select a document. This document should have dynamic fields. e.g. you could use`Office Furnitures Header` document. 4- Print -> PDF Quote. Cause: --- In previous fix, we fixed the traceback when no dynamic field is set. However, if you have a dynamic field, then inside `PdfWriter._update_field_annotation()`, the font is get from `DR` dict inside acroform: https://github.com/py-pdf/pypdf/blob/f20954f2241640feb484800e191373f8fbdfa44b/pypdf/_writer.py#L917-L929 Even if we are not setting a font, we need to have an empty `DR` dict inside acroform, in order to avoid calling `get` on a none object, which is leading to the traceback. Also in previous fix we were losing `NeedAppearances` inside `AcroForm` by creating new dict which wasn't right. opw-6392001
Content typed with a phone or other virtual keyboard in HTML note fields is now properly saved when users submit a form immediately. This prevents notes such as scheduled activity details from being lost when the field still has focus.
Original PR description
On a virtual keyboard the editor handles typing as a composition and only commits its history step on a later interaction. The html field marks itself dirty from that step, so right after typing the…
On a virtual keyboard the editor handles typing as a composition and only commits its history step on a later interaction. The html field marks itself dirty from that step, so right after typing the field is not dirty. On save the form calls commitChanges, but it only writes the value when the field is dirty, or on an urgent or inline-style save. None of those hold for a plain sanitized html field, so the typed content is not written to the record. Finalize the pending composition in commitChanges by calling the editor _compositionStep() before that check. commitChanges is the single point every save path goes through, so committing the pending step there marks the field dirty and the content is saved. It does nothing on a physical keyboard, where the composition flag is cleared after each keystroke. Steps to reproduce: 1. Open the Sales app and a quotation. 2. In the chatter, click Activities then Schedule Activity. 3. On a phone, or a browser with a virtual keyboard, fill Summary, tap the note field and type a note. 4. Tap Schedule while the note field still has focus. 5. Open the created activity. => the note is empty Ticket [link](https://www.odoo.com/odoo/project.task/6331719) opw-6331719 Forward-Port-Of: odoo/odoo#274465
When time off accrual allocations are created for a company, department, or employee category with a start date in the past, employees now receive the days they should have already accrued. This prevents missing leave balances and makes bulk allocations behave consistently with individual employee allocations.
Original PR description
**Problem:** Creating an accrual allocation for a whole company, a department or an employee category, with a plan that started in the past, does not grant the employees the days they should already…
**Problem:** Creating an accrual allocation for a whole company, a department or an employee category, with a plan that started in the past, does not grant the employees the days they should already have accrued. Doing the same allocation employee by employee works. **Steps to reproduce:** 1. Create a monthly accrual plan (e.g. 2 days, gained at the end of the period) 2. Create an accrual allocation for a whole company/department with a start date a few months in the past, and validate it 3. Observe each employee only gets the current period **Current behavior:** The child allocations only get the current period; the backlog between the start date and today is lost. **Expected behavior:** Each employee is back-filled for every elapsed period, exactly like a single-employee allocation. **Cause of the issue:** The single-employee flow runs `_onchange_date_from`, which resets `lastcall` to the allocation start date so `_process_accrual_plans` back-fills every elapsed period. That onchange returns early when there is no `employee_id`, which is always the case for company/department/category allocations, so the parent's `number_of_days` preview stays 0. The per-employee children are then created through `create`, where `_add_lastcalls` sets `lastcall` to the current period; the subsequent accrual run therefore only grants the current period and drops the whole backlog. **Fix:** Restart the child accrual from the allocation's start date before processing it, the same way the single-employee onchange does, so the plan is evaluated period by period for every employee. This is scoped to company/department/ category modes because employee-mode multi allocations already carry the value computed on the parent and must keep it. opw-6308064 Forward-Port-Of: odoo/odoo#272152
Checkout now detects carts that become zero-priced because of country-based pricing rules while zero-priced product sales are blocked. Instead of trying to complete the order and timing out, customers are sent back to the cart with a clear warning so they can resolve the issue.
Original PR description
When 'Prevent Sale of Zero Priced Product' is enabled and a country-group pricelist prices a product at 0 once the customer's country becomes known during checkout, the cart total becomes 0. The 'free order' branch then validated the order at the payment step, which could hang and time out for a cart that is not actually sellable. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Uruguay electronic invoicing now uses the exchange rate saved on the original invoice instead of recalculating it later. This prevents mismatches on credit notes or references when exchange rates are updated after an invoice is posted.
Original PR description
18.0 introduced an `invoice_currency_rate` field, storing the currency rate used for each invoice. Currently `_l10n_uy_edi_get_used_rate` uses the `currency.convert()` method using the date and company of the invoice. This is vulnerable to inaccuracy if the currency rates are changed after the invoice posting. For example, if an invoiceis posted and the currency rates are updated, the invoice will use the old rate, while `_l10n_uy_edi_get_used_rate` will return the new one. In the case of the customer in the related ticket, this caused their credit note reference currency rate to mismatch with the one on the invoice. This PR changes the `currency.convert()` call to fetching and inverting the `invoice_currency_rate` field. This ensures the returned value will match the one used for the invoice. opw-6456867
The Guatemala localization now applies the updated tax treatment for regular gasoline containing 10% alcohol. This ensures new customers receive the correct tax setup where only 90% of gallons are taxable under the new government rule.
Original PR description
Starting August 22nd Regular Gasoline is changing to a version that contains 10% alcohol. Because of this, the government is only taxing 90% of the gallons since the 10% alcohol portion is exempt. This will update COA for new customers, any current dbs who need to use the new formula can manually update theirs to include the * 0.9 portion. task-6483303
Fixes an issue where automated activity creation could cause new time off requests to show 0 days or 0 hours, even when valid dates were entered. The system now recalculates the duration after the request is created, helping managers and employees see accurate leave balances and approvals.
Original PR description
Current behavior: -- With an active automation rule (base_automation) whose action creates an activity (e.g. a "Time Off Approval" activity) on hr.leave creation, every newly created time off request…
Current behavior: -- With an active automation rule (base_automation) whose action creates an activity (e.g. a "Time Off Approval" activity) on hr.leave creation, every newly created time off request has a duration of 0 days / 0 hours, regardless of the requested dates. Expected behavior: -- The leave duration is computed from the requested dates, unaffected by the presence of an activity-creating automation rule. Steps to reproduce: -- - Create an automation rule on hr.leave, trigger "On Creation & Update". - Add an action that creates an activity (type "Time Off Approval"). - Create any time off request for an employee with a working schedule. - The request shows a duration of "0 days" (or "0 hours"). Cause of the issue: -- When an automation with a "Create Activity" action runs on leave creation, base_automation schedules the activity after the record is created. Creating the activity reads the leave record, forcing an early flush of its pending computes. At that point date_from/date_to are not yet settled, so the duration compute (number_of_days/number_of_hours) reads empty dates and stores (0, 0). As these are stored fields, they are marked done and never recompute. Fix: -- In create(), after the record is created and its dates are settled, recompute the duration explicitly so any zero stored by an early flush is overwritten with the correct value. opw-6235902 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr