Saturday, June 21, 2025
15 changes · saas-18.2
Miscellaneous changes
**Current behavior before PR:** - When a list contains content separated by **Shift+Enter** toggling the list would break these lines and create a separate base container for each segment separated by `<br>`. **Desired behavior after PR is merged:** - Only a single base container is created when toggling a list that contains **Shift+Enter** contents. task:4854372 Forward-Port-Of: odoo/odoo#213546
Original PR description
**Current behavior before PR:** - When a list contains content separated by **Shift+Enter** toggling the list would break these lines and create a separate base container for each segment separated by `<br>`. **Desired behavior after PR is merged:** - Only a single base container is created when toggling a list that contains **Shift+Enter** contents. task:4854372 Forward-Port-Of: odoo/odoo#213546
**Description** - Correction of the entry to calculate Time as per the set duration. **Steps to Reproduce** 1. go to Payroll app -> work entries -> work entries 2. Create new work entry. 3. set the end date at least 24 hours away from the start date. 4. notice that there is a 24 hours extra added/ per everyday you add. --- **Before** the calculation of the work entries duration was incorrect if it exceeds one day. --- **After** the work entry duration is calculated correc
Original PR description
**Description** - Correction of the entry to calculate Time as per the set duration. **Steps to Reproduce** 1. go to Payroll app -> work entries -> work entries 2. Create new work entry. 3. set the end date at least 24 hours away from the start date. 4. notice that there is a 24 hours extra added/ per everyday you add. --- **Before** the calculation of the work entries duration was incorrect if it exceeds one day. --- **After** the work entry duration is calculated correctly and still well rounded. --- **Why the fix** - When the following commit was merged, it introduced duration rounding , but rouding the entire timedelta converted to seconds instead of the number of seconds within a day, while still adding the total days - - commit : https://github.com/odoo/odoo/commit/80ae5f47650077b75dfbe4e813a122c81538cab3 --- opw-4827487 Forward-Port-Of: odoo/odoo#213211
### Steps to reproduce: - On a contact, add the "Factur-X" E-Invoicing method under the "Accounting" tab - Create an invoice with this contact as the customer - Send the invoice, download the PDF - Verify the PDF. For example with https://demo.verapdf.org/ - `The aforementioned EOL marker shall be immediately followed by a % (25h) character followed by at least four bytes, each of whose encoded byte values shall have a decimal value greater than 127` - `The MIME type of an embedded file, o
Original PR description
### Steps to reproduce: - On a contact, add the "Factur-X" E-Invoicing method under the "Accounting" tab - Create an invoice with this contact as the customer - Send the invoice, download the PDF -…
### Steps to reproduce: - On a contact, add the "Factur-X" E-Invoicing method under the "Accounting" tab - Create an invoice with this contact as the customer - Send the invoice, download the PDF - Verify the PDF. For example with https://demo.verapdf.org/ - `The aforementioned EOL marker shall be immediately followed by a % (25h) character followed by at least four bytes, each of whose encoded byte values shall have a decimal value greater than 127` - `The MIME type of an embedded file, or a subset of a file, shall be specified using the Subtype key of the file specification dictionary. If the MIME type is not known, the "application/octet-stream" shall be used` ### Cause: - 1 Pypdf 2.2 is [adding the necessary binary](https://github.com/py-pdf/pypdf/commit/036789a4664e3f572292bc7dceec10f08b7dbf62) like Odoo [does](https://github.com/odoo/odoo/blob/c1679123c9c6f7184293befb399de1e79a6205a9/odoo/tools/pdf/__init__.py#L471) for Pypdf2.1 because it is mandatory for PDF/A. The issue comes from two line break following each others: Pypdf2.2 adds one at the beginning of the [file](https://github.com/py-pdf/pypdf/blob/036789a4664e3f572292bc7dceec10f08b7dbf62/PyPDF2/pdf.py#L487): `\n % E2 E3 CF D3` Then Odoo [adds the header `%PDF-1.7\n` before](https://github.com/odoo/odoo/blob/c1679123c9c6f7184293befb399de1e79a6205a9/odoo/tools/pdf/__init__.py#L469) resulting in : `b"%PDF-1.7" \n \n % E2 E3 CF D3` PDF/A expects to have `% E2 E3 CF D3` on the second line right after the header but there is nothing on this line. - 2 The Subtype is badly formatted: from `text/xml` to `/text#232Fxml` instead of `/text#2Fxml` This occurs as Odoo [replace `/` by `#2F`](https://github.com/odoo/odoo/blob/2e43bee546d5c14729d654386209b539d8aa71d7/odoo/tools/pdf/__init__.py#L369-L377). But then when [adding the subtype](https://github.com/odoo/odoo/blob/2e43bee546d5c14729d654386209b539d8aa71d7/odoo/tools/pdf/__init__.py#L595C17-L595C74) to the attachment, we call `NameObject` from PyPdf. This object will [format](https://github.com/py-pdf/pypdf/blob/1c4173a12cd21b91dff6d6596ed0bbf1999f2d10/PyPDF2/generic/_base.py#L548) the text again replacing the `#` by `#23`. ### Solution: - Don't add a `\n` after `%PDF-1.7` when using `_pypdf2_2`. - As PyPdf2.2 is doing the formatting itself, we don't format on our side if `submod == ._pypdf2_2`. We still need to add the `/`. opw-4748600 Forward-Port-Of: odoo/odoo#211006
Currently a missing dependency error is generated when the user clicks the `Cancel Install` button on an already installed module. This issue may occur due to the below reason: - When the user installs multiple modules at once, the user may click `Cancel Install` on laready installed module - In the duplicate tab scenario, the user module is installed from one tab, and the user clicks `Cancel Install` on another tab. Error : `Some modules are not loaded, some dependencies or mani
Original PR description
Currently a missing dependency error is generated when the user clicks the `Cancel Install` button on an already installed module. This issue may occur due to the below reason: - When the user installs multiple modules at once, the user may click `Cancel Install` on laready installed module - In the duplicate tab scenario, the user module is installed from one tab, and the user clicks `Cancel Install` on another tab. Error : `Some modules are not loaded, some dependencies or manifest may be missing...` This commit will fix the above issue by writing state as 'uninstalled` when the module state is `to install`. Also, the same for `Cancel Uninstall` write the module's state as `installed` when its state is 'to remove' sentry-3928883995 Forward-Port-Of: odoo/odoo#213798
task-id: 4746445 IAP PR: https://github.com/odoo/iap-apps/pull/1088 Forward-Port-Of: odoo/odoo#213819
Original PR description
task-id: 4746445 IAP PR: https://github.com/odoo/iap-apps/pull/1088 Forward-Port-Of: odoo/odoo#213819
When activating a loyalty program with a buy X get Y promotion. For example for buy 10 get 3, if you have 10 products in your cart and add 1 more product, it will add a reward for 1 free product. But if you add another product, the reward will stay the same, it will not give 2 free product. Steps to reproduce: ------------------- * Create a buy X get Y loyalty program (10 get 3 free) where X and Y are the same product. * Add 10 products to the cart. * Add 1 more product to the ca
Original PR description
When activating a loyalty program with a buy X get Y promotion. For example for buy 10 get 3, if you have 10 products in your cart and add 1 more product, it will add a reward for 1 free product. But if you add another product, the reward will stay the same, it will not give 2 free product. Steps to reproduce: ------------------- * Create a buy X get Y loyalty program (10 get 3 free) where X and Y are the same product. * Add 10 products to the cart. * Add 1 more product to the cart, it will add a reward for 1 free product. * Add another product to the cart > Observation: The reward will not change, it will still be 1 free product. Why the fix: ------------ If possible we will try to maximize the reward quantity. That's why we don't do it in cases where multiple rewards are possible. opw-4762083 Forward-Port-Of: odoo/odoo#214643 Forward-Port-Of: odoo/odoo#211087
A random change of permissions from 755 to 775 of `/home/pi` was blocking ssh connection with key, as well as compromising the safety of the directory. We updated aliases to run commands directly with the right user, to ensure no ownership or permission change occurs. We also updated the `devtools` alias to run `sed` commands as sudo, for it to be able to write its temporary files in the current directory. Forward-Port-Of: odoo/odoo#215159
Original PR description
A random change of permissions from 755 to 775 of `/home/pi` was blocking ssh connection with key, as well as compromising the safety of the directory. We updated aliases to run commands directly with the right user, to ensure no ownership or permission change occurs. We also updated the `devtools` alias to run `sed` commands as sudo, for it to be able to write its temporary files in the current directory. Forward-Port-Of: odoo/odoo#215159
In this commit, we fix the tour snippet_popup_and_animations. For trigger: "...olumns .row > :last-child:not(:has(.o_animating))", :not(:has) is always true because no child has class o_animating. When the goal is check that the element has not a class, just use :not Also, when the scroll is well done, the element become invisible. So we need to add :hidden. Forward-Port-Of: odoo/odoo#215183
Original PR description
In this commit, we fix the tour snippet_popup_and_animations. For trigger: "...olumns .row > :last-child:not(:has(.o_animating))", :not(:has) is always true because no child has class o_animating. When the goal is check that the element has not a class, just use :not Also, when the scroll is well done, the element become invisible. So we need to add :hidden. Forward-Port-Of: odoo/odoo#215183
Backport of https://github.com/odoo/enterprise/pull/86477 which improves what was done in commits - https://github.com/odoo/odoo/commit/ebd6b5f374303dcdfcc69fa64522c1b83bd7fe58 - https://github.com/odoo/enterprise/commit/37cc5e067ff8d1e45edbd9a167a2d801c658739c since it avoids reloading the demo data twice by hooking on `_install_demo`. Instead, we just call our own function to create the demo data once in the accountant module. This commit therefore only reverts ebd6b5f374303dcd
Original PR description
Backport of https://github.com/odoo/enterprise/pull/86477 which improves what was done in commits - https://github.com/odoo/odoo/commit/ebd6b5f374303dcdfcc69fa64522c1b83bd7fe58 - https://github.com/odoo/enterprise/commit/37cc5e067ff8d1e45edbd9a167a2d801c658739c since it avoids reloading the demo data twice by hooking on `_install_demo`. Instead, we just call our own function to create the demo data once in the accountant module. This commit therefore only reverts ebd6b5f374303dcdfcc69fa64522c1b83bd7fe58 Enterprise PR: https://github.com/odoo/enterprise/pull/87204 Forward-Port-Of: odoo/odoo#214883 Forward-Port-Of: odoo/odoo#213379
Runbot tests will soon be run in dockers with no access to the outside world, so all their interfaces will be disconnected. The problem is that the browser considers itself offline when no interface is connected. However, in this case, if the Odoo server is still accessible. This method also makes it possible to run local tests when no connection is available and an Odoo server is running locally. A ping is required to verify that the connection to the server is not possible. Forward
Original PR description
Runbot tests will soon be run in dockers with no access to the outside world, so all their interfaces will be disconnected. The problem is that the browser considers itself offline when no interface is connected. However, in this case, if the Odoo server is still accessible. This method also makes it possible to run local tests when no connection is available and an Odoo server is running locally. A ping is required to verify that the connection to the server is not possible. Forward-Port-Of: odoo/odoo#215130
**Version:** 16.0 **Steps to reproduce:** - Install industry_fsm_sale - Create two tasks without linking them to a Sale Order - Go to list view and select those tasks - Click "Create Invoice" **Issue:** When the user selects tasks from the list view that are not linked to any Sale Order and tries to create an invoice, a traceback occurs. **Cause:** At least one linked Sale Order record is required when generating an invoice. If the selected tasks are not associated w
Original PR description
**Version:**
16.0
**Steps to reproduce:**
- Install industry_fsm_sale
- Create two tasks without linking them to a Sale Order
- Go to list view and select those tasks
- Click "Create Invoice"
**Issue:**
When the user selects tasks from the list view that are not linked to any Sale Order and tries to create an invoice, a traceback occurs.
**Cause:**
At least one linked Sale Order record is required when generating an invoice. If the selected tasks are not associated with any Sale Order, the process fails.
**Fix:**
This commit raise a red toast notification if none of the selected tasks are linked to a Sale Order. This helps the user understand the issue and prevent traceback..
task-4594178`
Forward-Port-Of: odoo/enterprise#87822
Forward-Port-Of: odoo/enterprise#83661Backport of https://github.com/odoo/enterprise/pull/86477 which improves what was done in commits - https://github.com/odoo/odoo/commit/ebd6b5f374303dcdfcc69fa64522c1b83bd7fe58 - https://github.com/odoo/enterprise/commit/37cc5e067ff8d1e45edbd9a167a2d801c658739c since it avoids reloading the demo data twice by hooking on `_install_demo`. Instead, we just call our own function to create the demo data once in the accountant module Community PR: https://github.com/odoo/odoo/pull/2133
Original PR description
Backport of https://github.com/odoo/enterprise/pull/86477 which improves what was done in commits - https://github.com/odoo/odoo/commit/ebd6b5f374303dcdfcc69fa64522c1b83bd7fe58 - https://github.com/odoo/enterprise/commit/37cc5e067ff8d1e45edbd9a167a2d801c658739c since it avoids reloading the demo data twice by hooking on `_install_demo`. Instead, we just call our own function to create the demo data once in the accountant module Community PR: https://github.com/odoo/odoo/pull/213379 Forward-Port-Of: odoo/enterprise#87993 Forward-Port-Of: odoo/enterprise#87204
**Steps to reproduce:** - Install account_budget - Activate "Budget Management" in Accounting settings - Go to "Accounting / Accounting / Analytic Budget" - Create a new budget: * Budget Type: Expense * Period: [this month] * Budget Lines: [a line with an analytic account (AA) in 2 plans] - Open the budget **Issue 1:** Create a PO at the current date with a line having only one of the AA as analytic distribution and an amount higher than the budgeted amount. The PO line and
Original PR description
**Steps to reproduce:** - Install account_budget - Activate "Budget Management" in Accounting settings - Go to "Accounting / Accounting / Analytic Budget" - Create a new budget: * Budget Type:…
**Steps to reproduce:** - Install account_budget - Activate "Budget Management" in Accounting settings - Go to "Accounting / Accounting / Analytic Budget" - Create a new budget: * Budget Type: Expense * Period: [this month] * Budget Lines: [a line with an analytic account (AA) in 2 plans] - Open the budget **Issue 1:** Create a PO at the current date with a line having only one of the AA as analytic distribution and an amount higher than the budgeted amount. The PO line and the Budget button appear in red, but it shouldn't because the analytic distribution of the line doesn't match all the accounts defined on the budget line. The line will not impact the budget, but it appears in red, which is confusing. **Cause 1:** When computing the budget lines linked to the PO line, the domain that is used is only taking into account the plans that are set on the PO line, ignoring the plans that are not set. For the Budget button, all the PO lines are used instead of just those having the correct analytic distribution. **Issue 2:** - Create a PO at the current date with 2 lines: 1) a line with the same AA than the budget line and an amount higher than the budget amount 2) a line with the same AA than the budget line and an amount lower than the budget amount - Save the PO The first line should be red, but it is not. **Cause 2:** When computing the budget lines linked to the PO lines, only the last PO line has its value set. opw-4757067 Forward-Port-Of: odoo/enterprise#87884
When creating a SEPA Direct Debit (SDD) mandate for a contact, mandates linked to a child contact are not recognized as valid at payment registration. It should be but it suggests a configuration issue so it needs a warning but not an error. task-4507135 Forward-Port-Of: odoo/enterprise#85882
Original PR description
When creating a SEPA Direct Debit (SDD) mandate for a contact, mandates linked to a child contact are not recognized as valid at payment registration. It should be but it suggests a configuration issue so it needs a warning but not an error. task-4507135 Forward-Port-Of: odoo/enterprise#85882
…rrect data from MO operation **Problem:** lines of mrp.workcenter.productivity added from the workorder widget do not update the linked analytic account with the right amount **Steps to reproduce:** - enable "analytic accounting" setting - Unarchive MTO route - Create a new product - In the inventory page check MTO and Manufacture routes - click on the Bill of materials smart button and create a new BOM - add a component and an operation - Create another product, set "produc
Original PR description
…rrect data from MO operation **Problem:** lines of mrp.workcenter.productivity added from the workorder widget do not update the linked analytic account with the right amount **Steps to reproduce:**…
…rrect data from MO operation **Problem:** lines of mrp.workcenter.productivity added from the workorder widget do not update the linked analytic account with the right amount **Steps to reproduce:** - enable "analytic accounting" setting - Unarchive MTO route - Create a new product - In the inventory page check MTO and Manufacture routes - click on the Bill of materials smart button and create a new BOM - add a component and an operation - Create another product, set "product type" as service - in the "create on order" field select "project & task" - create a new quotation with these two products and confirm - click on the "manufacturing" smart button - in the work orders page click on the "open work order" button at the right of the line - click on add a line - set a duration of 30:10 and clik elsewhere on the screen - save - click on the "analytic account" smart button - select the only line and click on the "gross margin" smart button **Current behavior:** There is a single line with an amount of 0.01 **Expected behavior:** The price should reflect the hourly rate of the employee for the task (that's 50.28 with a 100$/hours rate for instance) **Cause of the issue:** There is two issue here. First Issue : When clicking on save on the widget, this will modify the time_ids field of the mrp.workorder this will create a new mrp.workcenter.productivity with the values we wrote. Consequently, on the vals_list when the create method is triggered duration is set to the duration we wrote (so here 30.17) Because of this, when the _compute_duration is the triggered previous_durations will be [30.17] and _create_analytic_entry will be called with a parameter of 30.17 https://github.com/odoo/enterprise/blob/8a21b4f8ee8d24ebbc9ac2eb08696a0de056357f/project_mrp_workorder_account/models/mrp_workcenter_productivity.py#L10-L14 Therefore, inside _create_analytic_entry duration will be 0 and amount will also be 0 This issue does not happen if the duration is set by changing the "real duration" in the "work orders" page of the manufacturing order. This is because when doing it this way, we modify the duration of the mrp.workorder which triggers the set_duration_method which also creates a new mrp.workcenter.productivity but here the _prepare_timeline_vals returns a dictonary without a duration field https://github.com/odoo/odoo/blob/4fe90167266a92c3a5941eac9a6a2084a80056ac/addons/mrp/models/mrp_workorder.py#L352-L353 Second Issue: The line we see with a 0.01 amount is actually created before we save. It's created from the onchange method when we change the duration on the form. The onchange of duration triggers an onchange of start date which gets the value of duration and triggers of recomputation of duration https://github.com/odoo/odoo/blob/4fe90167266a92c3a5941eac9a6a2084a80056ac/addons/mrp/models/mrp_workcenter.py#L522-L531 As a consequence, _compute_duration is called. self.duration is initially not rounded so in our exemple previous duration will be equal to 30.1666666666668 https://github.com/odoo/enterprise/blob/8a21b4f8ee8d24ebbc9ac2eb08696a0de056357f/project_mrp_workorder_account/models/mrp_workcenter_productivity.py#L10-L11 However after the call to super()._compute_duration(), self.duration will be rounded thanks to the use of convert to duration inside the super method https://github.com/odoo/odoo/blob/4fe90167266a92c3a5941eac9a6a2084a80056ac/addons/mrp/models/mrp_workcenter.py#L472 So when doing the difference here inside _create_analytic_entry https://github.com/odoo/enterprise/blob/8a21b4f8ee8d24ebbc9ac2eb08696a0de056357f/project_mrp_workorder_account/models/mrp_workcenter_productivity.py#L38 duration will be 5.555555555556424e-05 and amount will be -0.005555555555556424 which results in the creation of this line with an amount of 0.01 **fix:** Calling the creation of account.analytic.line from the compute method leads to other problems : For instance, if a line is added in the "open work order" widget and we change the end date but change our mind and don't save the line, the duration will have been computed and a new account analytic line will have been created Whereas calling the method _create_analytic_entries from create() and write() ensures it's only called when the model is saved opw-4715690 Forward-Port-Of: odoo/enterprise#85517