Saturday, July 26, 2025
13 changes · saas-18.4
Enhancements to existing features
Companies can now use a dedicated Peppol identifier that keeps activity in a local demo mode instead of contacting the real Peppol network. This makes it safer and easier to run training and trials while also improving scheduled processing for the correct company context.
Original PR description
When the company is registered with this particular EAS, Odoo will act as if it was in demo mode. No call to the real Peppol Network is performed, everything is mocked locally. This allows to do the trainings on /trial databases, and get the lastests improvements. Also fixing some crons that needed to be run with the right company. task-no (FP/WTA request) Forward-Port-Of: odoo/odoo#220641 Forward-Port-Of: odoo/odoo#219252
Online orders from UrbanPiper now show and calculate taxes more accurately based on the customer location and fiscal setup. This helps merchants avoid incorrect pricing or tax treatment, with special GST handling for India and clearer configuration expectations for other tax rates.
Original PR description
**: pos_urban_piper_zomato, pos_urban_piper_swiggy After this commit: --- - For orders outside India, price are received from UrbanPiper as tax-inclusive. Odoo now properly computes the unit price and applies taxes based on the fiscal position. - For India, special handling is implemented: - 5% GST is collected and paid by the aggregator, so only this tax is added via fiscal position mapping. - For other tax rates like 12% or 18%, the merchant is responsible, so these must be configured explicitly in the fiscal position. Note: --- - If a user does **not** want to receive a particular tax in the order, they must manually add a line for it in the fiscal position. Task: 4862417 Forward-Port-Of: odoo/enterprise#91036 Forward-Port-Of: odoo/enterprise#88118
Resolved issues and error corrections
Tax reports now calculate net amounts correctly when invoices use the same tax with different analytic distributions. This prevents undercounted or duplicated base values in grouped tax reports, improving accuracy for accounting and tax review.
Original PR description
### Issue: When having two lines on an invoice with the same tax and different analytic distribution, the base value is doubled on the tax report. ### Steps to reproduce: - Create a new tax on sales…
### Issue: When having two lines on an invoice with the same tax and different analytic distribution, the base value is doubled on the tax report. ### Steps to reproduce: - Create a new tax on sales (eg 10%) - Make sure the option "Analytic Accounting" is ticked in the settings - Create an invoice with a line, add the tax on it and change the analytic distribution - Do the same for another invoice with another analytic distribution - Confirm the invoices - Go to the tax report - Select the report "Group By: Account > Tax" - On the report the "Net" amount is only the one of the first invoice, the tax amount is correct ### Cause: The bug appeared after this [commit](https://github.com/odoo-dev/enterprise/commit/9a7142ef57503efad9538e571d2e35c4aaa59531) which fixed another issue with analytics. Now several lines with the same tax can be returned by the query if they have different analytics. This was used to avoid having the base amount doubled on the invoice when several lines from the same move had with different analytics: there is a line for each analytic but they all have the same base, in the end the base amounts was doubled for each different analytic. Now the query returns multiple lines but as they all have the same key the base amounts are not added together. This fixes the previous issue when several lines from the same move but with different analytics were added but it creates another issue when different invoices have the same tax and different analytic because these lines also have the same key. This result in only the base amount of the first invoice to be taken into account. ### Solution: The previous fix was incorrect. The correct fix is to not join the lines when there are two tax lines. To do this the [condition](https://github.com/odoo/odoo/blob/cf8d38205c09a2724f41907fa07c5f23ff2d46a3/addons/account/models/account_move_line_tax_details.py#L153) in the query needs to be the same as the [condition](https://github.com/odoo/odoo/blob/cf8d38205c09a2724f41907fa07c5f23ff2d46a3/addons/account/models/account_move_line.py#L984) that will duplicate the lines in python. The check on `use_in_tax_closing` was missing so we add it. opw-4766421 Forward-Port-Of: odoo/odoo#220662 Forward-Port-Of: odoo/odoo#220394
Sales quotations and orders now calculate fixed taxes correctly when an early payment discount is applied. This prevents fixed tax amounts from being doubled on discounted payment terms, improving invoice and quote accuracy.
Original PR description
### Issue: The fixed tax value is doubled in `sale` when an early payment discount is applied. Steps to reproduce: - Create a fixed tax of $20 for example - Create a payment term with an early…
### Issue: The fixed tax value is doubled in `sale` when an early payment discount is applied. Steps to reproduce: - Create a fixed tax of $20 for example - Create a payment term with an early discount of 10% if paid before 10 days - Select "Always (upon invoice)" - In Sale create a new quotation with a line of $100 and the fixed tax - Select the created payment term - The tax value is doubled ($40) ### Cause: To compute the payment terms `_add_base_lines_for_early_payment_discount` (added in this [commit](https://github.com/odoo/odoo/commit/781678fb07ab3dd4d132193a938bbb71e8395424)) is adding two lines: - one with the negative amount of the payment term and the taxes - one with the positive amount of the payment term The goal is to compute the taxes on the discounted untaxed amount of the line. The original line compute the taxes for the undiscounted amount. The first added line computes the taxes for the amount of the discount and is negative. When adding the two the result is the tax value computed from the discounted untaxed amount. The issue is that a fixed will always have the same value, this means that the tax amount of the first added line will be positive and the same as the original line. When adding the two the amount is doubled. ### Solution: We don't add taxes with fixed amount on the first add line. opw-4868011 Forward-Port-Of: odoo/odoo#220545 Forward-Port-Of: odoo/odoo#218816
Odoo now blocks users from archiving a pricelist that is still tied to an active loyalty or promotional program. This prevents discount codes from appearing invalid because their linked pricelist was hidden but still active in the background.
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#220301
Forward-Port-Of: odoo/odoo#214968This change prevents upgrade failures for companies using Documents with their own email alias domains. It ensures new email aliases are created using the correct company context, avoiding validation errors caused by mismatched company domains.
Original PR description
**Step to reproduce:** 1. Install documents in version 17.0. 2. create new company for that create document folder and set alias_domain 3. upgrade to 18.0 below menitoned traceback will raise…
**Step to reproduce:**
1. Install documents in version 17.0.
2. create new company for that create document folder and set alias_domain
3. upgrade to 18.0 below menitoned traceback will raise
**Issue** :-
previously fix was deployed https://github.com/odoo/upgrade/commit/edae53792f81859dd4c843d8da4307e4eae8e0ff in the upgrade forcefully creating the incoming mails.
**Cause** :-
``mail.alias.mixin`` is introduced in existing [model]( https://github.com/odoo/enterprise/commit/a32825ee00f2b330d99113f4d8c1488903fe744e#diff-b394e0e6aa5c87ff7d84c0317fa2ed372a90b7d3e730c462fcb81d4b747f46ebL34) As ``alias_id`` is kept as false according to this new alias records are creating but as it sudo it bringing all company records due to this and during upgrade env company is admin related company which is letting alias_domain_id [here](https://github.com/odoo/odoo/blob/9719feb1fac64e06c988b336b077a0aa47a2b96a/addons/mail/models/mail_alias.py#L262) of that company which is leading to validation error
**Fix:**
for fixing this is record have company_id so create mail alias
according to that
```
Traceback (most recent call last):
File "/home/odoo/src/odoo/18.0/odoo/service/server.py", line 1361, in preload_registries
registry = Registry.new(dbname, update_module=update_module)
File "<decorator-gen-13>", line 2, in new
File "/home/odoo/src/odoo/18.0/odoo/tools/func.py", line 97, in locked
return func(inst, *args, **kwargs)
File "/home/odoo/src/odoo/18.0/odoo/modules/registry.py", line 129, in new
odoo.modules.load_modules(registry, force_demo, status, update_module)
File "/home/odoo/src/odoo/18.0/odoo/modules/loading.py", line 480, in load_modules
processed_modules += load_marked_modules(env, graph,
File "/home/odoo/src/odoo/18.0/odoo/modules/loading.py", line 365, in load_marked_modules
loaded, processed = load_module_graph(
File "/home/odoo/src/odoo/18.0/odoo/modules/loading.py", line 206, in load_module_graph
registry.init_models(env.cr, model_names, {'module': package.name}, new_install)
File "/home/odoo/src/odoo/18.0/odoo/modules/registry.py", line 617, in init_models
func()
File "/home/odoo/src/odoo/18.0/addons/mail/models/mail_alias_mixin.py", line 49, in _init_column_alias_id
alias = self.env['mail.alias'].sudo().create(record._alias_get_creation_values())
File "<decorator-gen-136>", line 2, in create
File "/home/odoo/src/odoo/18.0/odoo/api.py", line 495, in _model_create_multi
return create(self, [arg])
File "/home/odoo/src/odoo/18.0/addons/mail/models/mail_alias.py", line 266, in create
return super().create(vals_list)
File "<decorator-gen-120>", line 2, in create
File "/home/odoo/src/odoo/18.0/odoo/api.py", line 496, in _model_create_multi
return create(self, arg)
File "/tmp/tmppqp1_15u/migrations/util/orm.py", line 249, in wrapper
return f(*args, **kwargs)
File "/tmp/tmppqp1_15u/migrations/base/0.0.0/pre-models-match_uniq.py", line 25, in create
return super().create(vals_list)
File "<decorator-gen-31>", line 2, in create
File "/home/odoo/src/odoo/18.0/odoo/api.py", line 496, in _model_create_multi
return create(self, arg)
File "/home/odoo/src/odoo/18.0/odoo/models.py", line 5017, in create
records = self._create(data_list)
File "/home/odoo/src/odoo/18.0/odoo/models.py", line 5275, in _create
records._validate_fields(name for data in data_list for name in data['stored'])
File "/home/odoo/src/odoo/18.0/odoo/models.py", line 1631, in _validate_fields
check(self)
File "/home/odoo/src/odoo/18.0/addons/mail/models/mail_alias.py", line 159, in _check_alias_domain_id_mc
raise ValidationError(_(
odoo.exceptions.ValidationError: We could not create alias Inactive Alias because domain bsiri.co.th belongs to company BSIRI Company Limited (HeadOffice) while the owner document belongs to company MindGift LL>
```
upg-3017582
opw-4941387
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#219223This update prevents invalid empty discount details from being added when preparing electronic invoices. It reduces the risk of invoice generation or sending failures for Nilvera e-invoicing users.
Original PR description
Description of the issue/feature this PR addresses: Fixes an issue in the _add_document_line_allowance_charge_nodes function in the account_edi_ubl_cii module. Previously, the function assigns a list…
Description of the issue/feature this PR addresses: Fixes an issue in the _add_document_line_allowance_charge_nodes function in the account_edi_ubl_cii module. Previously, the function assigns a list containing None to the 'cac:AllowanceCharge' key when the discount node was not applicable. This led to errors when attempting to assign values to 'cbc:AllowanceChargeReasonCode', as accessing properties on a None object will cause an error in l10n_tr_nilvera_einvoice under the _add_document_line_allowance_charge_nodes function. TypeError: 'NoneType' object does not support item assignment Current behavior before PR: The _add_document_line_allowance_charge_nodes function throws an error when generating or sending an E-Invoice to Nilvera, due to [None] being present in 'cac:AllowanceCharge'. Desired behavior after PR is merged: Ensure 'cac:AllowanceCharge' is only added to line_node when the returned node is valid or just an empty list. This avoids [None] values in the list and prevents assignment errors. Task: 4886128 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Fixes an issue where reducing the quantity of a sales order for a kit with dropshipped components could create incorrect negative purchase quantities. Purchase orders now keep the correct component quantities, helping avoid supplier order errors and fulfillment delays.
Original PR description
…d comp **Problem:** when updating the quantity of a sale order line for a kit whose components are dropshipped, the update of the quantity of the linked Purchase order lines is wrongly computed…
…d comp **Problem:** when updating the quantity of a sale order line for a kit whose components are dropshipped, the update of the quantity of the linked Purchase order lines is wrongly computed **Steps to reproduce:** - enable the dropshipping setting - create a new storable product - in the purchase tab set a vendor - in the inventory tab check only the dropship route - repeat these operations for another product - create a third storable product - create a BOM for this product and set it as "kit" - add the two first products you created in the components - create a new quotation for the kit product, set a quantity of 25 and confirm - modify the quantity to 10 and save - click on the purchase smart button **Current behavior:** the quantities of the two purchase order lines have been updated to -15 **Expected behavior:** it should be 10 **Cause of the issue:** When we change the quantity on the sale order line: The method action_stock_rule from SaleOrderLine is triggered. It will create a procurement: https://github.com/odoo/odoo/blob/2e7fd1c45a0f68d123e85c95f3eb3a7fd5395527/addons/sale_stock/models/sale_order_line.py#L338 To compute the quantity used for this procurement,the computation is : product_qty = line.product_uom_qty - qty where qty is line._get_qty_procurement https://github.com/odoo/odoo/blob/2e7fd1c45a0f68d123e85c95f3eb3a7fd5395527/addons/sale_stock/models/sale_order_line.py#L313 The error comes from the _get_qty_procurement - The "normal" behaviour of _get_qty_procurement is to compute the difference between outgoing moves and incoming moves https://github.com/odoo/odoo/blob/2e7fd1c45a0f68d123e85c95f3eb3a7fd5395527/addons/sale_stock/models/sale_order_line.py#L253-L263 - Basic _get_qty_procurement wouldn't work for a kit as a move is created for each components. So there is an override of the method to handle this case https://github.com/odoo/odoo/blob/2e7fd1c45a0f68d123e85c95f3eb3a7fd5395527/addons/sale_mrp/models/sale_order_line.py#L128-L141 this override calls _compute_kit_quantities on the stock moves linked to the sale order line via its move_ids attribute. _compute_kit_quantities does a computation of the ratios for each component and returns the minimum - Basic _get_qty_procurement wouldn't work either for a dropshipped product as no move is created when confirming the sale order. So there is another override of the method to compute this case https://github.com/odoo/odoo/blob/2e7fd1c45a0f68d123e85c95f3eb3a7fd5395527/addons/stock_dropshipping/models/sale.py#L42-L51 This override uses the purchase order line linked to the sale order line via its purchase_line_ids to compute the quantity. Neither of those two overrides would work for a kit with dropshipped components. The first one would fail because no stock moves are created. The second one would fail because adding the value of each purchase order line created returns a value too high **fix** for this specific case we just take the previous quantity opw-4743482 Forward-Port-Of: odoo/odoo#217070 Forward-Port-Of: odoo/odoo#211726
Order transfers in Point of Sale and Restaurant now work reliably, including floating orders and table-based orders. This prevents errors during service and helps staff move orders between tables or tickets without interruption.
Original PR description
While transferring a floating order to another or a table, a traceback was raised. Is now possible to transfer orders to anything independent of the table or order type. taskId: 4948719 Forward-Port-Of: odoo/odoo#219236
This fix prevents a failed website builder action from disrupting the whole editor. It also rolls back unsuccessful changes so pages are not left in an inconsistent state, improving reliability for content editors.
Original PR description
The goal of this commit is to better manage the apply fail of a BuilderAction. 1. Previewing an action that fails should not block the entire editor. 2. Apply an action that fails must be reverted to avoid leaving invalid mutations in the dom. 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
HR officers can now use the Employees app's Load Sample Data button without running into an access error. This prevents setup interruptions when authorized HR users are preparing or testing employee records.
Original PR description
Currently, an error occurs when a user with Officer access rights attempts to load sample data in the Employees app. **Steps to reproduce:** - Install the HR app without demo data. - Delete the…
Currently, an error occurs when a user with Officer access rights attempts to load sample data in the Employees app.
**Steps to reproduce:**
- Install the HR app without demo data.
- Delete the Administrator employee record.
- Create a new user and assign the access right "Office: Manage All Employees".
- Log in with the newly created user.
- Open the Employees app and click on the Load Sample Data button.
**Traceback:**
```
AccessError
Ops! Parece que você se deparou com alguns registros ultrassecretos.
Desculpe, Wendel Xavier de Miranda (id=2) não tem 'criar' acesso a:
- Contato (res.partner)
Se você realmente precisar de acesso, talvez valha a pena tentar conquistar o administrador com uns pães de queijo.
Esse parece ser um problema de várias empresas. Talvez seja possível acessar o registro mudando para a empresa: WM SERVICOS TECNICOS E COMISSIONAMENTO LTDA.
ParseError
while parsing /home/odoo/src/odoo/saas-18.4/addons/hr/data/scenarios/hr_scenario.xml:79, somewhere inside <record id="work_contact_eg" model="res.partner" forcecreate="1"> ...
ValueError - ParseError('while parsing /home/odoo/src/odoo/saas-18.4/addons/hr/data/scenarios/hr_scenario.xml:79 ....
```
**Cause:**
The issue occurs because the user doesn’t have the required rights to create res partner records when loading sample data.
**Fix:**
This commit resolves the issue by granting the user superuser rights.
sentry-6751634609Fixes tax reports grouped by account and tax so invoices using the same tax with different analytic distributions show the correct net amount. This prevents understated or duplicated tax base values, improving accuracy for accounting and tax reporting.
Original PR description
### Issue: When having two lines on an invoice with the same tax and different analytic distribution, the base value is doubled on the tax report. ### Steps to reproduce: - Create a new tax on sales…
### Issue: When having two lines on an invoice with the same tax and different analytic distribution, the base value is doubled on the tax report. ### Steps to reproduce: - Create a new tax on sales (eg 10%) - Make sure the option "Analytic Accounting" is ticked in the settings - Create an invoice with a line, add the tax on it and change the analytic distribution - Do the same for another invoice with another analytic distribution - Confirm the invoices - Go to the tax report - Select the report "Group By: Account > Tax" - On the report the "Net" amount is only the one of the first invoice, the tax amount is correct ### Cause: The bug appeared after this [commit](https://github.com/odoo-dev/enterprise/commit/9a7142ef57503efad9538e571d2e35c4aaa59531) which fixed another issue with analytics. Now several lines with the same tax can be returned by the query if they have different analytics. This was used to avoid having the base amount doubled on the invoice when several lines from the same move had with different analytics: there is a line for each analytic but they all have the same base, in the end the base amounts was doubled for each different analytic. Now the query returns multiple lines but as they all have the same key the base amounts are not added together. This fixes the previous issue when several lines from the same move but with different analytics were added but it creates another issue when different invoices have the same tax and different analytics. Because these lines also have the same key. This result in only the base amount of the first invoice to be taken into account. ### Solution: The previous fix was incorrect. The correct fix is to not join the lines when there are two tax lines. To do this the [condition](https://github.com/odoo/odoo/blob/cf8d38205c09a2724f41907fa07c5f23ff2d46a3/addons/account/models/account_move_line_tax_details.py#L153) in the query needs to be the same as the [condition](https://github.com/odoo/odoo/blob/cf8d38205c09a2724f41907fa07c5f23ff2d46a3/addons/account/models/account_move_line.py#L984) that will duplicate the lines in python. The check on `use_in_tax_closing` was missing so we add it. opw-4766421 Forward-Port-Of: odoo/enterprise#91065 Forward-Port-Of: odoo/enterprise#90936
Users with Planning access but no Employee permissions can now open role configuration without hitting an access error. This keeps planning setup usable for authorized planning users while still respecting employee access restrictions.
Original PR description
Trying to display the roles in the planning app is not possible if the user doesn't have hr_rights even with full planning rights. ** Step to reproduce ** - Connect to Odoo with an user that only have acces right for "Planning" (no employees). - Open Planning app - Configuration>Roles - It will trigger an Access Error (If it didn't trigger add a user to Ressources) ** Cause of the issue ** The acces for the default_role_id is limited to hr.group_hr_user: https://github.com/odoo/enterprise/blob/a7122011a0b0cdd111eccf59c917c6b8e2c25137/planning/models/resource_resource.py#L27 But is used in _compute_display_name: https://github.com/odoo/enterprise/blob/a7122011a0b0cdd111eccf59c917c6b8e2c25137/planning/models/resource_resource.py#L73 ** Fix ** Retrieve the information about the role with sudo opw-4908979 Forward-Port-Of: odoo/enterprise#90243