Daily updates from Odoo
Monday, June 22, 2026
5 changes · 17.0
Resolved issues and error corrections
This update resolves an issue where E-Way Bill amounts were incorrectly calculated when sales prices included tax. The fix ensures that tax-included prices are properly processed, preventing double tax calculations and ensuring accurate E-Way Bill generation. This impacts sales orders with 'Tax Included' settings.
Original PR description
`*` = `ewaybill_Stock, sale_stock, purchase_stock` **Steps to reproduce:** * Install `l10n_in_ewabill_stock` and `l10n_in_sale_Stock`. * Set the Default Tax Price Setting to "Tax Included". * Create…
`*` = `ewaybill_Stock, sale_stock, purchase_stock` **Steps to reproduce:** * Install `l10n_in_ewabill_stock` and `l10n_in_sale_Stock`. * Set the Default Tax Price Setting to "Tax Included". * Create a Sales Order (e.g. unit price 300, qty 600, 18% GST) and confirm the Delivery Challan/Delivery Order. * Generate an E-Way Bill from the Delivery Challan. **Observed behavior:** * The Taxable Amount and Total Invoice Amount are displayed incorrectly in the generated E-Way Bill, including both the printed document and the JSON. * The `ewaybill_price_unit` shows the tax-excluded price (e.g. 254.24) instead of the original tax-included price (300), leading to a double tax exclusion when `compute_all` processes it. **Cause:** * `_l10n_in_get_product_price_unit` in both `l10n_in_sale_stock` and `l10n_in_purchase_stock` unconditionally used `price_subtotal / qty` to compute the E-Way Bill price unit. `price_subtotal` is always tax-excluded, so for tax-included prices, the tax was already stripped. * `_l10n_in_tax_details_by_stock_move` then passed this already tax-excluded price to `compute_all` with taxes that have `price_include=True`, causing `compute_all` to strip the tax a second time (e.g. 254.24 / 1.18 = 215.46 instead of the correct 254.24). **Fix:** * Check whether any of the line's taxes have `price_include` set. If so, use `price_total / qty` (which preserves the tax-included price) so that `compute_all` can correctly extract the tax. Otherwise, continue using `price_subtotal / qty` as before. opw-6273101
This update fixes an issue where the Luxembourg eCDF XML export incorrectly reported financial year data. The change removes a problematic account mapping, ensuring the exported data aligns with the Odoo Profit and Loss view. This improves data accuracy for Luxembourg tax reporting.
Original PR description
Issue: Users reported that the financial year result in the XML export for the Luxembourg eCDF platform is incorrect, despite being correct in the Odoo Profit and Loss visualization. The exported XML populated incorrect amounts in cell 0161 under certain circumstances (namely, in the case of an explicit entry from account 999999 to account 142000). Solution: * Removed account 142 entirely from both the `ACCOUNTS_2019` and `ACCOUNTS_2020` dictionaries so it no longer auto-populates cells 0161/0162 (up to 2019 included) and 2955/2956 (from 2020 onward). * Removed the 2019 threshold condition in the loop bypass for account 142. * Removed the hard-coded manual pop for cell 2955 since it has been removed from the mapping. * Deleted the redundant reassignment of `net142` in the loss calculation block. Ticket [link](https://www.odoo.com/odoo/project.task/6059571) opw-6059571
This update enables branch companies to register on the PEPPOL network as 'sender only' participants, mirroring their parent company's registration. This simplifies the registration process for branch offices and ensures compliance with PEPPOL requirements, streamlining international trade operations.
Original PR description
This task backports the ability to register branch companies as sender only using the same identifier as their parent company task-id-6069374
This update resolves an issue where a duplicate stock move was being created in backorders after a quality check failure. The fix prevents the creation of an unnecessary move when a quality issue redirects a transfer, ensuring backorders are accurately reflected and avoids redundant inventory management.
Original PR description
Steps to reproduce: ------------------- - Install `purchase`, and `quality_control` - Enable Multi-Step Routes in Inventory settings - Create a storable product tracked by lot - Create a Quality…
Steps to reproduce:
-------------------
- Install `purchase`, and `quality_control`
- Enable Multi-Step Routes in Inventory settings
- Create a storable product tracked by lot
- Create a Quality Point:
- Operation Type: Internal Transfer
- Control Per: Quantity
- Configure a failure location
- Enable the 3-Step Incoming route for the warehouse
- Duplicate the Internal Transfer operation type and name it `Internal Transfer 2` Configure the operation types:
- Internal Transfer: <-- this is original one
- Source Location: WH/Input
- Destination Location: WH/Quality Control
- Internal Transfer 2:
- Source Location: WH/Quality Control
- Destination Location: WH/Stock
- Open the warehouse's 3-Step Incoming route
- Locate the push/pull rule whose source location is `WH/Quality Control`
- open that and Change its operation type from internal transfer -> `Internal Transfer 2`
- Create and confirm a Purchase Order for 20 units of the product
- Open the generated receipt
- Validate 12 units using Lot-1 and create a backorder
- Open the Internal Transfer (where source is that PO and there operation type
is internal transfer that original one)
- Demand: 20
- Reserved Quantity: 12
- Click into detail button on stock move and split the move line into:
- 9 units from Lot-1
- 3 units from Lot-1
- save
- Open the Quality Check
- Pass 9 units
- Fail 3 units
- Validate the transfer and create a backorder
- Open the internal transfer whose operation type `Internal Transfer 2`
Issue:
------
`Internal Transfer 2` contains two stock moves:
- Move 1:
- Demand: 20
- Quantity: 9
- This is correct.
- Move 2:
- Demand: 8
- Quantity: 0
- This move should not exist.
Expected behavior:
------------------
`Internal Transfer 2` should contain only the move corresponding to the successfully passed quantity:
- Demand: 20
- Quantity: 9
No additional move with demand 8 and quantity 0 should be generated.
Cause:
--------------------------
A 3-step route pre-creates the whole chain at confirm time: Receipt -> Internal Transfer -> Internal Transfer 2, each linked through move_dest_ids/move_orig_ids. Both fields are the two sides of a single many2many relation (stock_move_move_rel), so removing the relation from either side drops it entirely.
When the user confirms the failure on the quality check, the wizard calls quality.check._move_line_to_failure_location() (quality.py). Because the failure location differs from the next operation's source location, it runs
https://github.com/odoo/enterprise/blob/3a5e30f0bb7c1660827fd209cd74ef3bcd538213/quality_control/models/quality.py#L386
and `_break_mto_link()` then does unlink of `orig_location_id`
```py
self.move_orig_ids = [Command.unlink(parent_move.id)]
self.procure_method = 'make_to_stock'
```
**This is intentional** : it switches Internal Transfer 2 to `make_to_stock` so its `_action_assign()` reserves only what is physically present at Quality Control, instead of chain-reserving the 3 failed units that were rerouted to the failure location.
The side effect is that, because the relation is shared, unlinking parent_move from Internal Transfer 2's move_orig_ids also empties the Internal Transfer move's move_dest_ids.
- when the picking is validated and the backorder is created
When the picking is later validated, `_action_done()` splits off the remaining, never- reserved demand into a backorder move via `_split()` -> `_prepare_move_split_vals()`,
which copies `move_dest_ids` from the original move. but that's already empty,
because of the break at the time of failed quality check.
So the backorder is created with no `move_dest_ids` even though its 8 units have nothing to do with the quality failure they simply haven't
been reserved/processed yet.
https://github.com/odoo/odoo/blob/6feedc18b7873bfde62047ece1a5de882319bc21/addons/stock/models/stock_move.py#L1955
Then action_done trigger ` _action_confirm()` it calls `_push_apply()`.
https://github.com/odoo/odoo/blob/6feedc18b7873bfde62047ece1a5de882319bc21/addons/stock/models/stock_move.py#L966-L967
` _push_apply()` only skips a move if it already has `move_dest_ids` since the backorder has none, it doesn't skip — it searches for an applicable push rule from WH/Quality Control, finds the very same rule that already produced Internal Transfer 2
the first time, and creates a brand new Internal Transfer 2 move for its own demand (8)
via `rule._run_push()`. That new move has quantity 0,
Fix:
--------------------------
Before pushing a move that has no destination, `_push_apply()` now first checks whether a failed, diverted quality check (same product, same upstream chain via move_orig_ids) already exists for it. If so, this move is just a leftover backorder of a transfer that already had its link broken for quality reasons, and the existing destination move already covers it — so the push is skipped instead of creating a duplicate.
Nothing about the quality check wizard or the existing link-breaking
logic was changed; this only stops that breakage from leaking into a later, unrelated backorder.
----
opw-6298637This update resolves an issue where Odoo Server would unexpectedly crash (exit code 130) during automatic reloads. The fix prevents a race condition triggered by `SIGHUP` signals, ensuring Odoo Server remains stable and reliable even with frequent updates or file changes. This improves the overall stability and uptime of the Odoo instance.
Original PR description
### Summary When `dev_mode` includes `reload`, the `ThreadedServer` FSWatcher triggers a phoenix restart by sending the process a `SIGHUP`, and `signal_handler` turns `SIGHUP` into…
### Summary When `dev_mode` includes `reload`, the `ThreadedServer` FSWatcher triggers a phoenix restart by sending the process a `SIGHUP`, and `signal_handler` turns `SIGHUP` into `KeyboardInterrupt`. `ThreadedServer.run()` only catches that in its wait-loop — but there are two windows where the `KeyboardInterrupt` is raised **outside** the `try/except`, escapes `run()`/`main()`, and exits the interpreter with code **130**. Under Docker's default `restart: no`, PID 1 dies and the container does not come back. 1. **Startup** — a `SIGHUP` during `self.start() + preload_registries()` (e.g. a save while a previous reload is still loading modules). 2. **Teardown / duplicate** — a single save often emits two FS events; the FSWatcher's `if not odoo.phoenix:` dedup races across threads and fires two `SIGHUP`s. The first begins the phoenix teardown; the second lands during `self.stop()` / `_reexec()`, outside the guarded region, and escapes the same way. ### Reproducer (deterministic) Boot a threaded server and signal it a few times in quick succession: ```bash odoo-bin -d <db> --workers 0 # ThreadedServer # once it is up, with <pid> = the odoo process: for i in $(seq 8); do kill -HUP <pid>; sleep 0.12; done ``` Unpatched the process exits **130**; patched it survives after a single clean phoenix reload. The same happens from a single editor save (duplicate FS events) or a bulk file change. ### Fix Two guards in `signal_handler`, plus bracketing the startup window in `run()`: - **Startup**: a module flag marks the `self.start() + preload_registries()` window; a `SIGHUP` arriving then is *deferred* (recorded, not raised). After the window `run()` replays its effect inline so the wait-loop performs the normal phoenix restart. - **Duplicate**: if `odoo.phoenix` is already set a restart is already in flight, so a further `SIGHUP` is redundant and is ignored rather than raised. `SIGINT`/`SIGTERM` are untouched — `Ctrl-C` and `docker stop` keep working unchanged. The fast path (no `SIGHUP`) is one flag set + one clear per startup. ### Notes - Targeted at **17.0** (oldest affected branch) for forward-porting. The 17.0 → 18.0 hop will conflict: on 18.0/master the flag is the module-level `server_phoenix` global and `run()` wraps the critical section in `with Registry._lock:`. I'll resolve the forward-port. - Prior art: #21209 (introduced the phoenix flag), #206898 (graceful reload), #207930. - CLA: signed via #269075 (Codeforward corporate CLA).