Friday, July 3, 2026
5 changes · saas-18.3
Resolved issues and error corrections
This update fixes an issue where users weren't receiving notifications when a sign request was completed after they selected 'Handle in Odoo' (inbox) for notifications. The change ensures that the sender receives a notification, improving transparency and workflow efficiency for sign requests. This was a bug impacting the sign process.
Original PR description
## Issue When a user sets their notification to "Handle in Odoo" (`inbox`) and a sign requested is completed, they do not receive the expected notification. ## Steps to reproduce 1. Install *Sign*…
## Issue When a user sets their notification to "Handle in Odoo" (`inbox`) and a sign requested is completed, they do not receive the expected notification. ## Steps to reproduce 1. Install *Sign* (`sign`) 2. Sets the current user's notification preference to "Handle in Odoo" (`inbox`) 3. Create a sign request and send it to Marc Demo 4. As Marc Demo, sign the request 5. **The user who sent the sign request did not receive a notification to notify them that the request was signed.** ## Fix This is a partial backport of both https://github.com/odoo/enterprise/commit/463d6a2aae536356e6dee6b902f2e881dbc4fbda (saas-18.2) and a related fix https://github.com/odoo/enterprise/commit/41395dba4fd31222f5fd9fc94a84c977cf9334f9 (19.0). Before the first commit, users would not receive inbox notification when sign requests would be completed. ## Note to reviewer The issue only occurs in 18.0, as it is fixed by https://github.com/odoo/enterprise/commit/463d6a2aae536356e6dee6b902f2e881dbc4fbda in 18.2, but we can backport the fix from https://github.com/odoo/enterprise/commit/41395dba4fd31222f5fd9fc94a84c977cf9334f9 from 18.2 to 18.4 if desired. opw-6251702 Forward-Port-Of: odoo/enterprise#122519 Forward-Port-Of: odoo/enterprise#120740
This update resolves an issue where server reloads triggered by file changes could cause the application to crash. The fix prevents a series of signals from interrupting the server's restart process, ensuring stability and preventing service interruptions during updates. This improves the reliability of the Odoo server.
Original PR description
### Summary When `dev_mode` includes `reload`, `ThreadedServer`'s FSWatcher reacts to a file change by sending the process a `SIGHUP` to trigger a phoenix restart. `signal_handler` turns `SIGHUP`…
### Summary When `dev_mode` includes `reload`, `ThreadedServer`'s FSWatcher reacts to a file change by sending the process a `SIGHUP` to trigger a phoenix restart. `signal_handler` turns `SIGHUP` into `KeyboardInterrupt`, which `ThreadedServer.run()`'s wait-loop catches. The catch is too narrow — a reload `SIGHUP` can kill the process through **three** windows that all sit outside the wait-loop's `try/except`, so the exception escapes `run()`/`main()`. Under Docker's default `restart: no`, PID 1 dies and the container stays down. ### The three windows 1. **Teardown duplicate (exit 130).** One file change can emit several FS events; the FSWatcher's `if not odoo.phoenix:` dedup races across threads and fires more than one `SIGHUP`. The first begins the phoenix teardown; the second lands during `stop()` / `watcher.stop()` / `_reexec()` and `KeyboardInterrupt` escapes. 2. **Exec-gap (exit 129).** `os.execve()` resets caught signal handlers to their default disposition (`SIGHUP` terminates) but preserves `SIG_IGN`; a `SIGHUP` arriving after the exec but before the re-exec'd process re-installs its handler kills the process outright. 3. **Startup (exit 130).** In the re-exec'd process, a `SIGHUP` anywhere in the startup section that precedes the wait-loop — `start()`, `preload_registries()` **and** `cron_spawn()` — escapes `run()`. ### Reproducer (deterministic) Boot a `ThreadedServer` (`--workers 0`) on any initialised db, then signal PID 1 a few times in quick succession: ```bash docker exec <container> sh -c 'i=0; while [ $i -lt 8 ]; do kill -HUP 1; sleep 0.1; i=$((i+1)); done' ``` Unpatched the process exits 130 or 129. Patched it stays up after one clean phoenix reload. Verified live on 17.0 and 18.0: stock `server.py` dies; the patched `server.py` survives sustained bursts (20/20 across repeated reload cycles on each version); `SIGINT`/`SIGTERM` still exit 0. ### Fix Minimal, in `signal_handler` + `run()` + `_reexec()`; `SIGINT`/`SIGTERM` untouched; one new instance attribute, no new module globals: - **Teardown duplicate:** ignore a `SIGHUP` once `quit_signals_received` is set (a restart/shutdown is already pending; the re-exec reloads fresh code). - **Startup:** a per-instance `in_preload` flag marks the entire startup section (`start()` + `preload_registries()` + `cron_spawn()`); a `SIGHUP` there sets the phoenix flag + counter and returns instead of raising, so the wait-loop exits right after startup and runs the normal restart. - **Exec-gap:** `signal.signal(signal.SIGHUP, signal.SIG_IGN)` just before `os.execve` so a `SIGHUP` in the gap is dropped rather than terminating the process. ### Related - #21209 (merged) — introduced the phoenix flag; did not guard these windows. - #206898 (merged), #207930 (open) — PreforkServer reload. ### CLA Covered by Codeforward B.V.'s corporate CLA; #269240 adds me to its contributor list (pending merge). Forward-Port-Of: odoo/odoo#269247
This update resolves an issue preventing users from modifying a product's Bill of Materials (BOM) type when sales orders are already linked across multiple companies. Previously, the system prevented changes to ensure data integrity. Now, users can safely adjust BOM types, maintaining accurate sales order fulfillment and inventory management within a multi-company environment.
Original PR description
### Steps to reproduce: - Have two companies: company1 and company2 - Create a producct P available in both company1 and company2 - with company1, create a kit bom for a product P - with company2,…
### Steps to reproduce: - Have two companies: company1 and company2 - Create a producct P available in both company1 and company2 - with company1, create a kit bom for a product P - with company2, create and confirm a sale order for 1 unit of P - with company1, change the bom type of P from kit to manufature #### > UserError: As long as there are some sale order lines that must be delivered/invoiced and are related to these bills of materials, you can not remove them. ### Cause of the issue: Changing the bom type from a kit (phantom type) to a non kit will launch a call of the `_ensure_bom_is_free` in order to ensure data integrity if the kit bom was used by a relevant sale order line: https://github.com/odoo/odoo/blob/f4c76be062bec47b68ee42505d7d42fed31ac0f2/addons/sale_mrp/models/mrp_bom.py#L15-L18 https://github.com/odoo/odoo/blob/f4c76be062bec47b68ee42505d7d42fed31ac0f2/addons/sale_mrp/models/mrp_bom.py#L24-L42 However, this check does not take the company of the bom into account and in the present flow, the company of the bom is different from the company of the supposedly problematic sol. opw-6290304 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273486 Forward-Port-Of: odoo/odoo#271119
This update fixes an error in how timesheet revenue is calculated for prepaid services, ensuring accurate reporting. The previous calculation incorrectly accounted for day UoM rounding, leading to inflated revenue figures. This change now uses the correct per-unit rate, reflecting discounts and ensuring accurate revenue reporting for prepaid orders.
Original PR description
Steps to reproduce 1. Create a service product: Invoicing Policy = Prepaid/Fixed Price, Track Service = Timesheets, Unit of Measure = Days 2. Confirm a Sales Order with 2 days of that product at…
Steps to reproduce 1. Create a service product: Invoicing Policy = Prepaid/Fixed Price, Track Service = Timesheets, Unit of Measure = Days 2. Confirm a Sales Order with 2 days of that product at 800/day 3. Register 1 hour on the generated task 4. Open Timesheets > Reporting, add the "Timesheet Revenues" measure Issue `timesheet_revenues` in `timesheets.analysis.report` was computed per analytic line as `(SOL.price_subtotal / SOL.qty_delivered) * (unit_amount * sol_uom.factor / ts_uom.factor)` (https://github.com/odoo/odoo/blob/16f170619d9cc5fd86529a3f17e349da37607f73/addons/sale_timesheet/report/timesheets_analysis_report.py#L42-L44). `SOL.qty_delivered` is a stored float rounded to the day UoM precision (0.01d). For 1 hour timesheeted, qty_delivered = 1/8 = 0.125d rounds to 0.13d, so the formula yields (1600 / 0.13) × (1/8) = 1538.46 instead of the correct 100. Because `qty_delivered` is recomputed each time a timesheet is added, all existing rows shift their revenue figure with every new entry. Additionally, using `price_subtotal / qty_delivered` as the per-unit rate ignores any line discount: the rate derived from a discounted subtotal divided by a delivered quantity that differs from the ordered quantity is not the effective price per day. For prepaid lines, the effective per-unit rate is `price_subtotal / product_uom_qty` — the ordered quantity is stable and the subtotal already reflects any discount — multiplied by the timesheet hours converted to the SO line UoM. opw-6150555 Forward-Port-Of: odoo/odoo#272910 Forward-Port-Of: odoo/odoo#262524
This update fixes an issue where the price of Point of Sale (POS) order lines wasn't correctly recalculated after a refund and quantity change. Specifically, when a refund was processed and the line quantity was adjusted, the price wasn't updated to reflect the fiscal position. This ensures accurate pricing and tax calculations during POS transactions.
Original PR description
When changing the quantity of a pos order line the fiscal position set on the order was not used when recomputing the line price and taxes. Steps to reproduce: ------------------- * Create a tax with 15% rate and another with 10% rate * Create a fiscal position that maps the 15% tax to the 10% tax * Setup a PoS to be able to use that fiscal position * Open the PoS, add a product with the 15% tax, set the fiscal position and validate the order * Refund the order in the backend and change the quantity of the line from -1 to 0 and back to -1. > Observation: The price is not the same as before Why the fix: ------------ The fiscal position was not applied when recomputing the line's price and taxes. opw-6253311 Forward-Port-Of: odoo/odoo#273366 Forward-Port-Of: odoo/odoo#270135