Friday, July 18, 2025
14 changes · 18.0
Enhancements to existing features
Purchase order lines linked to a project now retain their existing analytic allocations while also adding the project’s allocation when there is no conflict. This improves cost tracking accuracy by ensuring project-related purchases are reflected without overwriting manually entered or model-based distributions.
Original PR description
Currently, if a purchase order line has an analytic distribution and then a project with an analytic account is added to the PO, the project analytic distribution is not added. Only in lines without any analytic distribution, the projetc account is added as expected. This commit modifies `_compute_analytic_distribution()` to keep both the project account and the existing analytic distribution (that were added manually or from a distribution model) in all PO lines where the analytic plans do not conflict. task-4904044 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Italian e-invoicing registrations now include an additional identifier, such as the VAT number, so incoming vendor bills can be matched to the correct registered user more reliably. This helps prevent processing failures when documents contain only a VAT number instead of the main identifier.
Original PR description
This improvement addresses an issue in the Italian e-invoicing (l10n_it_edi) and IAP registration logic where incoming vendor bills with only a VAT number failed to match the correct registered EDI user. Changes introduced: - Added `edi_identification_secondary` (e.g. VAT number) to support fallback user matching. - Updated the `/create_user` endpoint to accept and store the secondary identifier. - Modified `create_user` logic to send both primary and secondary IDs from Odoo. - Prepared the base for matching incoming invoices against both identifiers. See also: odoo/iap-apps#1056 Task [link](https://www.odoo.com/odoo/project/967/tasks/4619718) task-4619718
Resolved issues and error corrections
Italian electronic invoice XML generation now excludes linked accounting documents dated after the document being sent. This prevents SDI rejections caused by references to future invoices or payments in credit note XML files.
Original PR description
In a FatturaElettronica xml document <DatiFattureCollegate> allow us to specify any references to other previously sent documents. However, it is currently possible that the system populate this element with moves dated after the current document, causing the SDI to reject the document. Steps to reproduce: - Create an invoice A and register a full payment via the button - Create a credit note for the invoice, unreconcile the credit note if necessary - Create a new invoice B and add the credit note as payment - Create the XML of the credit note Issue: The XML includes info about invoice B, created after the credit note. If invoice B is dated after the credit note, the SDI will reject the xml Solution: Avoid including reconciled elements with date later than the current document date opw-4795664 Forward-Port-Of: odoo/odoo#219106
Project to-do activity counts now use each user's timezone to decide whether items are late, due today, or planned for the future. This prevents mismatches where dashboard counts and the activity list showed different results during certain hours of the day.
Original PR description
User timezone was not being used for activity states and thus the future, today, and late activities would be inaccurate. They were being computed with CURRENT_DATE through SQL which is based on the timezone that the SQL server is in. This would lead to there being a period of some hours based on the user timezone where the actual activities page that you click into and the systray showing different counts of activity states. For example, on our Odoo production database, activities that SF office members create on projects that were for tomorrow would show today after 5pm and when clicking on the today activities there would be nothing until midnight. Using the user timezone in order to compute what today is for them, then using this in the SQL query fixes this issue. This is the same behavior as the compute_state for the state field in mail.activity. opw-4893182
When a project task or subtask is assigned a milestone, it now uses the sales order item linked to that milestone instead of falling back to a parent task or project value. This prevents incorrect invoicing links after users manually clear and reassign milestones on sales-driven project tasks.
Original PR description
**Step to reprocduce :** 1. Install sale_project module 2. Create a product - type: Service - Invoice policy: based on the milestones - Create on order: Project & Task. 3. Create a sale order with…
**Step to reprocduce :**
1. Install sale_project module
2. Create a product
- type: Service
- Invoice policy: based on the milestones
- Create on order: Project & Task.
3. Create a sale order with that product and add two SO lines with different descriptions.
4. Confirm the sale order.
5. Click on the Tasks smart button in the sale order to open the generated tasks.
6. From one of the tasks (e.g., m1)
7. Manually remove the existing milestone and sales order item from the task.
8. Then assign a different milestone (e.g., m2) to the task.
9. The sale order item set different (e.g., m1) instead of the newly set milestone.
**Issue:**
When a task has its `milestone_id` and `sale_line_id` manually cleared, and a new milestone
is later assigned, the task does not get the correct Sales Order Item.
**Cause:**
In the `_compute_sale_line` method, the logic priority the parent task and project when
computing the `sale_line_id`, and only uses the `milestone_id.sale_line_id` as a fallback.
https://github.com/odoo/odoo/blob/259f7eafb15882807640a00cf6939129f27c8fbb/addons/sale_project/models/project_task.py#L109-L113
**Solution :**
To fix this `_compute_sale_line` method to priority the milestone's `sale_line_id`
when a milestone is explicitly set. This ensures that if the task’s milestone
changes, its sale line reflects the one from the milestone, even for subtasks.
opw-4701106Deleting a customer or address will no longer automatically remove related draft or cancelled sales orders. This prevents users from unknowingly losing orders when removing a partner that was only used as a shipping or invoicing address, and lets them review and handle those orders themselves.
Original PR description
On partner deletion, draft & cancelled orders were automatically deleted as well (to ease the deletion of 'unused' partners). Nevertheless, since both the main customer and the shipping and invoicing addresses were considered, the deletion of a partner might lead to the unexpected deletion of an order where the deleted partner was only the invoicing or shipping address. The user might not even be aware of it if they didn't enable the shipping/invoicing addresses setting. We believe it's better to drop this magical deletion and let the user be aware that there are orders related to the customer, so that they can handle it the way they want to, without the program deciding for them. opw-4866778 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
When settling a sales order in Point of Sale, the order lines are now reloaded from the server instead of relying on older cached data. This ensures cashiers see the latest quantities and prices after changes made in Sales or previous partial payments, reducing billing mistakes.
Original PR description
Steps to reproduce ------------------ 1. Create a Sales Order, add a product with QTY = X 2. Open PoS 3. Load this same Sales order (by clicking "Settle the order"-> QTX is X as expected 4. Return to…
Steps to reproduce ------------------ 1. Create a Sales Order, add a product with QTY = X 2. Open PoS 3. Load this same Sales order (by clicking "Settle the order"-> QTX is X as expected 4. Return to Sales order (in the sales app) 5. Edit QTY from X to Y and save 6. Go back to PoS 7. Delete the laoded Sales Order and load it again -> Notice that QTY is still X and not the updated Y!! Other Flow in frontend ---------------------- 1. Create a Sales Order, add a product with QTY = X 2. Open PoS 3. Load this same Sales order (by clicking "Settle the order"-> QTY is X as expected 4. Change the quantity manually, to pay for X - 1 5. Validate and pay for the order 6. Load the same Sales order again with "Settle the order" -> The quantity is still X and the price is the unit price times X!! Why the issue ------------- When settling the order, we get its value using _getSaleOrder which basically reads it from the cache. So it will read the old order lines having the old qty, and not the updated one. The fix ------- Instead of reading the lines from the cache, we read them direcly from the backend, to accomodate for cases where the data might have been changed on another device or has not been updated in the cache. opw-4819708 opw-4913397 Co-authored-by: Arthur Nanson <artn@odoo.com>
Odoo now blocks users from archiving a pricelist that is still linked to an active loyalty or promotional program. This prevents coupon codes from being rejected unexpectedly and keeps discount program setup consistent for sales teams.
Original PR description
**Step to Reproduce:** 1. Install `sale_loyalty` and `sale` 2. Enable the `Pricelists` option in the settings. 3. Create a pricelist named demo. 4. Create a Discount & Loyalty named `test program`…
**Step to Reproduce:**
1. Install `sale_loyalty` and `sale`
2. Enable the `Pricelists` option in the settings.
3. Create a pricelist named demo.
4. Create a Discount & Loyalty named `test program` with type `Discount Code`,
5. Assign the demo pricelist to the loyalty program.
6. Copy the discount code from the program’s conditional rules.
7. Archive the demo pricelist.
8. create sale order for any product.
9. Try to apply the copied coupon code.
**Observation:**
- An error is shown: "This code is invalid".
- check loyalty program `test program` pricelist field is empty, that suggesting it's valid for all pricelists, but the coupon still fails.
**Issue:**
- When a linked pricelist is archived, it's hidden in the UI, but the relation still exists in the relational table.
```17_sale=# select id,name,active from product_pricelist;
id | name | active
----+------------------------------------+--------
1 | {"en_US": "Default USD pricelist"} | t
2 | {"en_US": "new"} | f
(2 rows)
17_sale=# select * from loyalty_program_product_pricelist_rel;
loyalty_program_id | product_pricelist_id
--------------------+----------------------
5 | 2
(1 row)
```
- While filtering the domain for coupon, the condition is not satisfied due to the program's pricelist.
https://github.com/odoo/odoo/blob/94d727bd9ba38116d3e14188c730c7566744e9f0/addons/sale_loyalty/models/sale_order.py#L636-L647
**Solution:**
- Display a validation error to the user when trying to archive a pricelist
that is linked to any active promotional programs.
opw-4841678
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#214968Reinstalling the Amazon sales integration on databases with past Amazon sales could previously run out of memory. This change reduces the data loaded during setup, making reinstallations much more reliable and lowering peak memory use significantly.
Original PR description
Description ----------- On databases that had `sale_amazon` installed in the past, were used for sales for a certain period, then had the module uninstalled, and later attempted to re-install it, a…
Description ----------- On databases that had `sale_amazon` installed in the past, were used for sales for a certain period, then had the module uninstalled, and later attempted to re-install it, a memory error will occur. The peak memory usage stems from `sale.order.line._compute_is_service`. The reason the compute is triggered is because of the "re-creation" of the master data products `default_product` & `shipping_product`, which writes `type`, which the compute depends on. So the compute will be triggered for all `sale.order.line` records that had those products. This commit avoids the excessive memory usage by explicitly fetching the fields that are needed for the compute, which avoids fetching large fields like the different products' HTML descriptions. Benchmark --------- On a database with 400k+ `sale.order.line` with an amazon related product, installing `sale_amazon` peak memory usage was: | | Peak Mem. | |--------|-----------| | Before | 3.8 GiB | | After | 580 MiB | Reference --------- opw-4915892 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
French electronic invoices sent through Peppol now use the expected XML identifier field. This prevents Peppol validation errors when companies send BIS Billing 3.0 invoices with French SIRET details.
Original PR description
### Issue: BIS3 XML is not valid for Peppol ### Steps to reproduce: - Install l10n_fr_facturx_chorus_pro and switch to french company - Activate peppol - Create a French customer - Under Sales and…
### Issue: BIS3 XML is not valid for Peppol ### Steps to reproduce: - Install l10n_fr_facturx_chorus_pro and switch to french company - Activate peppol - Create a French customer - Under Sales and Purchase tab, set SIRET to "11000201100044" - Under Accounting tab, set the following: - Invoice sending = Peppol - Einvoice format = BIS Billing 3.0 - peppol_eas = France SIRET - peppol endpoint = 11000201100044 - Use Invoice/Invoiced smart button, then select New to create an invoice for this french customer - Add any non-zero invoice line, then confirm - Send and print, send to peppol - Download the XML. The /PartyIdentification/ID element will have the schemeName attribute set. ### Cause: Previous [commit](https://github.com/odoo/odoo/commit/0f3a9dee5cf15fa978a1857c184413003147c4a6#diff-10c62c279423109c43458eab15a3177ff5592d6570451f890fead74389bc3740) added `schemeName`. But Peppol doesn't want any `schemeName`, see the [doc](https://docs.peppol.eu/poacc/billing/3.0/rules/ubl-tc434/UBL-DT-08/). ### Solution: The correct attribute here seems to be `schemeID`. See an [example from the docs of Peppol](https://docs.peppol.eu/poacc/billing/3.0/bis/#_parties_2). Change `schemeName` to `schemeID`. opw-4934436
This update prevents referral refusal notifications from being sent just because HR opens the refusal wizard. Notifications are now sent only after the refusal is confirmed and are attached to the correct referrer user records, avoiding unnecessary emails and improving email processing performance.
Original PR description
## [PERF] hr_referral: Send refusal notification to referrer's users Description ----------- Following https://github.com/odoo/enterprise/commit/764f9b6f513c90eb79935d9e8469989ea704b61b,…
## [PERF] hr_referral: Send refusal notification to referrer's users Description ----------- Following https://github.com/odoo/enterprise/commit/764f9b6f513c90eb79935d9e8469989ea704b61b, `_send_notification` will not attach the message on the `hr.applicant` itself, so a `model` was provided. But due to a missing `res_id`, `message_notify` will set both `model` & `res_id` to `False` since both are not specified. This leads to the creation of a `mail.message` with no `res_id` and no `model` (as `self` is an empty `mail.thread` recordset). This leads to a performance regression when mail references need to be computed to attach to the notification in `_notify_by_email_get_base_mail_values`, due to the missing `model` and `res_id` of the message. This commit attaches the notification to the referrer's users instead, providing its `model` and `res_id`. Reference --------- opw-4943488 --- ## [FIX] hr_referral: Do not send notif when opening the refuse wizard Description ----------- Currently, when opening the refusal wizard for an applicant, a call to `archive_applicant` is made. However, there is an override of it in `hr_referral` to send a notification for the applicant's refusal, and closing the `referral_state`, even though the applicant may have not been provided a reason for refusal, and the HR can simply close the wizard instead of confirming it. This commit removes the override of `archive_applicant` and moves its logic into `action_refuse_reason_apply` which is called when the wizard is confirmed. Reference --------- opw-4943488 Forward-Port-Of: odoo/enterprise#90309
Fixes an error that could prevent users from reconfirming a loan after cancellation when Accounting Audit Trail is enabled. This ensures loan workflows remain usable even when past posted accounting entries must be preserved for compliance.
Original PR description
Steps: - Activate Audit Trail in Accounting configuration - Create and confirm a loan, having some moves posted in the past - Cancel it, reset it to draft the re-confirm it again -> ValueError: Expected singleton This is because posted moves can not be unlinked when canceling/closing the loan if audit trail is activated. Therefore we try to access the `state` field from a recordset instead of a singleton. With this commit, we filter the generated move to get the newly created one. opw-4834361
This fix prevents the Barcode app from storing invalid empty values while scanning lots during receipt operations. It avoids a crash when users scan multiple lots, helping warehouse teams complete incoming shipments reliably.
Original PR description
## How to reproduce: https://github.com/user-attachments/assets/bf44f9fd-0402-4d70-8b55-5baf192d42e8 - Enable Consignment - On Receipt operation type, enable 'Use existing lots' - Create product P,…
## How to reproduce:
https://github.com/user-attachments/assets/bf44f9fd-0402-4d70-8b55-5baf192d42e8
- Enable Consignment
- On Receipt operation type, enable 'Use existing lots'
- Create product P, tracked by lot
- Create lot SN-001 & SN-002
- Add 1 unit on hand with lot SN-001
- Create Receipt for 10 units of P -> Confirm
- Open receipt on Barcode App
- Scan "SN-002" => 'undefined' value added to 'dbQuantCache'
- Scan "SN-001" => Uncaught Promise > quantsByLocation is not iterable (cannot read property undefined)
---
## Test result without fix:
```
2025-07-18 09:30:33,801 20801 ERROR oes_test_18 odoo.addons.stock_barcode.tests.test_barcode_client_action_picking: FAIL: TestPickingBarcodeClientAction.test_barcode_lazy_cache_scan_two_lots
Traceback (most recent call last):
File "/home/odoo/projects/odoo-src/multiverse/src/18.0/enterprise/stock_barcode/tests/test_barcode_client_action_picking.py", line 3508, in test_barcode_lazy_cache_scan_two_lots
self.start_tour(url, 'test_barcode_lazy_cache_scan_two_lots', login='admin')
File "/home/odoo/projects/odoo-src/multiverse/src/18.0/odoo/odoo/tests/common.py", line 2264, in start_tour
return self.browser_js(url_path=url_path, code=code, ready=ready, timeout=timeout, success_signal="tour succeeded", **kwargs)
File "/home/odoo/projects/odoo-src/multiverse/src/18.0/odoo/odoo/tests/common.py", line 2235, in browser_js
self.fail('%s\n\n%s' % (message, error))
AssertionError: The test code "odoo.startTour('test_barcode_lazy_cache_scan_two_lots', {"stepDelay": 0, "keepWatchBrowser": false, "debug": false, "startUrl": "/odoo/147/action-stock_barcode.stock_barcode_picking_client_action", "delayToCheckUndeterminisms": 0})" failed
TypeError: quantsByLocation is not iterable (cannot read property undefined)
at LazyBarcodeCache.getQuants (http://127.0.0.1:8565/web/assets/3d6bda7/web.assets_web.min.js:21482:279)
at BarcodePickingModel._processBarcode (http://127.0.0.1:8565/web/assets/3d6bda7/web.assets_web.min.js:21748:631)
at async http://127.0.0.1:8565/web/assets/3d6bda7/web.assets_web.min.js:21661:75
```
OPW-4942192Project profitability now includes relevant budget lines even when a project’s analytic account is linked through a different analytic plan. This prevents missing budget information after upgrades or account-plan mismatches, giving users a more complete view of project finances.
Original PR description
In version 17.3, the analytic mixin was introduced in budget.line model to allow to link a budget line to multiple analytic accounts belonging to different analytic plans. The issue is that we have…
In version 17.3, the analytic mixin was introduced in budget.line model to allow to link a budget line to multiple analytic accounts belonging to different analytic plans. The issue is that we have not adapted the code in project profitability, to take those changes into account. A problematic situation could be the following: 1. We have a project where the account "X" is set to the main project plan (the first one) "Projects" BUT the account "X" actually belongs to the analytic plan "Departments" (yes, it's possible that there is a mismatch between the project plan and the analytic plan, especially after the 18.0 upgrade where "analytic_account_id" just became "account_id", no matter in which plan it was). 2. We have a budget line linked to the account "X" for the plan "Departments". 3. We want to display the budget lines in project profitability, but this line does not appear. That's because we currently only look for the budget lines belonging to the analytic plan "Projects" aka the main/first plan, that match the account "X" of the project. But as account "X" actually belongs to the analytic plan "Departments", no budget lines are found. task-4901400 version-18.0