Monday, August 11, 2025
12 changes · 18.0
Resolved issues and error corrections
Quotation PDF templates now correctly display numeric fields when their value is zero. This prevents customers from seeing blank fields where a valid zero amount or quantity should be shown.
Original PR description
Versions -------- - 18.0+ Steps ----- 1. Using Studio, add an integer or float field to the sale order form; 2. upload a PDF using forms as a quotation header[^1]; 3. add a mapping of the form field to the studio field; 4. create a quoation using the header; 5. have the studio field be 0; 6. print quotation. [^1]: e.g. `tests/files/test_forms.pdf` Issue ----- The form field where the zero should be displayed is empty. Cause ----- When formatting values, it returns an empty string for any falsy value whose field isn't of type boolean or monetary. Solution -------- If the value is falsy, only return the empty string if the field type is not integer or float, this way, the zero value will get formatted in the final `else` as a string value (same as non-zero numeric values). opw-4937052
Contacts without a name or email now show their available display name in chatter recipient and follower lists instead of appearing blank or as “false”. This prevents confusion when adding invoice-address contacts or followers to messages and makes recipient selection clearer.
Original PR description
Steps to reproduce =============== 1. Create a contact of type invoice address without name and email. 2. Go to any app with chatter. 3. Add this user to the recipient ----> Only the blue tick will be visible (recipient name will be empty) After this commit, we will use the display_name as a fallback to show in the chatter.
This fixes a calendar test setup so it uses valid default event information when checking a fallback case. The change helps keep automated validation reliable and reduces the risk of false failures during updates.
Original PR description
Use valid res_model/res_id in context defaults runbot-235289 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#222426
Incoming return slips now show the correct destination address instead of placeholder demo text. This prevents confusion for warehouse teams and partners when printing return documentation for receipts.
Original PR description
Issue ----- Incoming return slips have a "Demo Address and Name" text instead of the correct destination address. <img width="928" height="658" alt="image"…
Issue ----- Incoming return slips have a "Demo Address and Name" text instead of the correct destination address. <img width="928" height="658" alt="image" src="https://github.com/user-attachments/assets/6ff0a5e7-f1ee-4faa-a22b-76ec8f2f7a28" /> Steps to reproduce ----- - Create a receipt for a product - Print its return slip Cause ----- By default, the address is taken from the pickings location_id -> warehouse_id -> partner_id. For incoming pickings, the warehouse is the vendor one, with no associated partner. In such cases, the partner can be found directly on the picking itself with the partner_id field. Note ----- To render t-fields, qweb first applies a `rsplit` before evaluating the expression, see https://github.com/odoo/odoo/blob/cb1c761777e84d96f82c4f754586795509ce1b3d/odoo/addons/base/models/ir_qweb.py#L2015-L2016 With this in mind, using parentheses and moving `.partner_id` outside of them seems like the most readable way to go about it. ----- Ticket: opw-4660716 Forward-Port-Of: odoo/odoo#219011
This fixes an error when exporting Spanish VAT record books for invoices using the 0.26% or 1% equivalence surcharge purchase taxes. Businesses in Spain can now generate the VAT book XLSX report for these cases without the process failing.
Original PR description
Added to SURCHARGE_TAX_EQUIVALENT taxes 0.26% SE and 1% SE When using the Odoo VAT book (location Spain) and we have an invoice with the taxes 0.26% SE (0,26% Recargo Equivalencia Compras) 1% SE (1%…
Added to SURCHARGE_TAX_EQUIVALENT taxes 0.26% SE and 1% SE When using the Odoo VAT book (location Spain) and we have an invoice with the taxes 0.26% SE (0,26% Recargo Equivalencia Compras) 1% SE (1% Recargo Equivalencia Compras). a KeyError error occurs <img width="1147" height="517" alt="Captura desde 2025-07-30 09-37-13" src="https://github.com/user-attachments/assets/771fcf6e-efed-4e79-a1d4-a133c7072c2a" /> Steps to Reproduce this error: 1. Create a new database using Odoo version 18. 2. Activate the module: “Spain - Accounting (PGCE 2008)” (l10n_es). 3. Create a new company and set Spain as the country. 4. In the company’s “Sales & Purchase” tab, set the Fiscal Position to "Equivalence surcharge". 5. Create a new quotation and select the company created in step 3. 6. Add a product with the following taxes: 0.26% and 2% VAT (G). 7. Add another product with the following taxes: 1% (SE) and 7.5% VAT (G). 8. Confirm the invoice generated from the quotation. 9. Go to Accounting → Reporting → Tax Report and select "Generic Tax Report". 10. Click the gear icon and select "VAT Record Books (XLSX)". OPW https://www.odoo.com/es_ES/my/tasks/4981807 @jco-odoo please review. Thank you! MT-10457 @moduon
The Web Studio test suite was updated to match a recent change in how suggested message recipients are returned. This helps keep automated checks reliable and reduces the risk of false test failures during future updates.
Original PR description
From the related community commit, the _message_add_suggested_recipient method is modified to also return display name under certain condition. This commit adapts the test inside web_studio to align with the method's change. Task-4812554
Field service users can once again access the map view for outgoing deliveries. This restores a useful planning view that was temporarily unavailable due to a dependency between community and enterprise features.
Original PR description
This commit is the continuity of the fix made in community. The issue fixed in community was the map view cannot be defined in the view mode of an action since the map view only exists in enterprise. This commit overrides the method defined in community to add the map view as before. Related PR: odoo/odoo#222003
The electronic signature reminder process now handles requests that do not have a validity date. This prevents scheduled reminder jobs from crashing and helps ensure signature follow-ups continue reliably.
Original PR description
The cron can fetch record with no validity date,
so the check request.validity < today
raise
```
Traceback (most recent call last):
File "/home/odoo/src/odoo/saas-18.3/odoo/tools/safe_eval.py", line 397, in safe_eval
return unsafe_eval(c, globals_dict, locals_dict)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "ir.actions.server(5136,)", line 3, in <module>
File "/home/odoo/src/enterprise/saas-18.3/sign/models/sign_request.py", line 437, in _cron_reminder
if request.validity < today:
^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: '<' not supported between instances of 'bool' and 'datetime.date'
```
Forward-Port-Of: odoo/enterprise#90279The Swedish SIE4 import now skips accounting entries that contain no transaction lines. This prevents empty or invalid journal entries from being created, improving data quality during imports.
Original PR description
The aim of this commit is making sure that we don't import move without transaction in it. In SIE4, we can have moves with BTRANS and RTRANS tags that we are ignoring. It means that we could have move without any move lines. It's not an expected behavior in Odoo. This commit checks that the move data are created only if we have lines for that move. no task id Forward-Port-Of: odoo/enterprise#91783
Documentation and clarification updates
This pull request records that contributor nikhilnakrani99 has signed Odoo's Contributor License Agreement. This supports legal compliance for accepting their contributions and has no direct impact on product features or users.
Original PR description
Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Miscellaneous changes
Issue ----- In a SO, changing the quantity for a product with packagings through the catalog correctly updates the SOL's packaging but not the move's. Instead, it creates a new move for the difference in quantity (with the correct new packaging) while leaving the existing one unchanged. The user ends up with 2 moves with different packagings. Steps to reproduce ----- - Install both Sale and Stock - Enable "Product Packagings" under Settings > Sales - Create a new product with a custom
Original PR description
Issue ----- In a SO, changing the quantity for a product with packagings through the catalog correctly updates the SOL's packaging but not the move's. Instead, it creates a new move for the…
Issue
-----
In a SO, changing the quantity for a product with packagings through the catalog correctly updates the SOL's packaging but not the move's. Instead, it creates a new move for the difference in quantity (with the correct new packaging) while
leaving the existing one unchanged. The user ends up with 2 moves with different packagings.
Steps to reproduce
-----
- Install both Sale and Stock
- Enable "Product Packagings" under Settings > Sales
- Create a new product with a custom packaging for 2 units (inventory tab)
- Create a SO
- Add the product to the SO
- Confirm SO
- Open product catalog
- Update the product quantity to 4
- Go back to the SO
- Go to the linked delivery
-> The delivery has 2 lines instead of 1
Cause
-----
The logic flow is different between when in form or catalog view.
When changing the quantity of a sale line through the form, the quantity update is done on a temporary record. This triggers a change of the packaging through
https://github.com/odoo/odoo/blob/0a0dc2f1bd54f44356a5959b8bcd52aaddcf1261/addons/sale/models/sale_order_line.py#L649-L650
When saving the changes, both the quantity and packaging are present in the write `values` as both fields have to be updated on the real record. This allows to enter the following block, which updates the packaging on the existing move.
https://github.com/odoo/odoo/blob/0a0dc2f1bd54f44356a5959b8bcd52aaddcf1261/addons/sale_stock/models/sale_order_line.py#L198-L201
Later on in the write, we trigger a replenishment.
https://github.com/odoo/odoo/blob/0a0dc2f1bd54f44356a5959b8bcd52aaddcf1261/addons/sale_stock/models/sale_order_line.py#L205-L206
This replenishment creates a new move for the rdifference in quantities, using the SOL's new packaging. Since both the new and existing line have the same packaging, they are merged together. Everything works as expected.
When making changes through the catalog, we are directly writing the new quantity on the existing SOL. We directly enter the SOL's `write` method with only the new quantity in `values`.
This means we don't update the packaging on the existing move since `product_packaging_id` is not in `values` so we can't enter the block
https://github.com/odoo/odoo/blob/0a0dc2f1bd54f44356a5959b8bcd52aaddcf1261/addons/sale_stock/models/sale_order_line.py#L198-L201
The write then goes on to trigger a replenishment. When preparing to create the procurement, we access the SOL's `product_packaging_id`
https://github.com/odoo/odoo/blob/0a0dc2f1bd54f44356a5959b8bcd52aaddcf1261/addons/sale_stock/models/sale_order_line.py#L248
Since it's dependency (the quantity) changed, the compute is triggered. The SOL packaging is updated and the newly computed packaging is used to create the procurement (and subsequent move).
We end up with two moves with different packagings,
- the existing move with the old packaging
- the new move with the new (correct) packaging
They can not be merged together because their packagings differ -> bug.
Version constraint
-----
The bug is only present in 17.X versions, as packagings have been deprecated in 18.0.
Making the field computed
-----
We could make the move's packaging a *computed* field. This seems like the most logical and practical solution. However, this approach has some problems:
- the field is used for both sales and purchases so we'd have to adapt the behaviour there as well.
- we have to consider multi step routes. In such cases, the moves are linked between themselves but not to the SOL. This means we can't make the dependence be on the SOL packaging, we have to make it on the other move's. So we would have to make the field recursive, so that an update on the first move's packaging can propagate along the chain.
- adding onto the previous point, sale and purchase multi step routes use different rules, so we would depend on the origin's product_packaging_id in one and on the destintation's in the other.
This leads to us propagating changes both ways across move chains, so we don't know whether the origin or the destination has the correct packaging.
Solution
-----
Update the packaging of existing moves through the SOL's write method before it launches the replenishment.
Why this works
-----
We first store the existing packaging (or lack thereof) of the SOL
> old_packaging = {sol: sol.product_packaging_id for sol in self}
We then write the content of `values` on the record.
> res = super(SaleOrderLine, self).write(values)
This only updates the quantity of the SOL.
We then force the recomputation of the SOL's packaging
> if sol.product_packaging_id != old_packaging[sol]:
If the new packaging differs from the previous, we update the existing move(s) so that they use the new packaging of the line
> sol.move_ids.filtered(
> lambda m: m.state not in ['cancel', 'done']
> ).product_packaging_id = sol.product_packaging_id
Only then does the write launch the replenishment
> lines._action_launch_stock_rule(previous_product_uom_qty)
Since the existing moves' packaging has been updated, they will correctly be merged with the new ones.
-----
Ticket:
opw-4603600
Forward-Port-Of: odoo/odoo#206973Modifications are made around read, filtered, list comprehension. The read function usually does not prefetech fields other than stated. But in this case, since the fields are related fields from another model, The fields of the other model are prefeteched. This includes the body which can be very big in size and cause an out of memory error. Filtered does not need other fields and keeps them unnecessarily in cache. List comprehension where it has a reference to specific field inside th
Original PR description
Modifications are made around read, filtered, list comprehension. The read function usually does not prefetech fields other than stated. But in this case, since the fields are related fields from…
Modifications are made around read, filtered, list comprehension. The read function usually does not prefetech fields other than stated. But in this case, since the fields are related fields from another model, The fields of the other model are prefeteched. This includes the body which can be very big in size and cause an out of memory error. Filtered does not need other fields and keeps them unnecessarily in cache. List comprehension where it has a reference to specific field inside the model also triggers the prefetecher. Benchmark: | |Number of queries| SQL time| Python time|| |-------|----------------------------|----------------|---------------|-| |with prefetch| 82| 1.887 | 7.898| Out of memory| |Without prefetch| 120| 0.385 | 5.973| | The benchmark with the prefetch was done locally with increasing the memory limit. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#206125 Forward-Port-Of: odoo/odoo#183893