Tuesday, February 20, 2024
23 changes · master
Enhancements to existing features
Helpdesk sample data now shows clearer SLA success rates and more realistic daily targets, making demonstrations and evaluations more representative. The update also simplifies ticket activity views and restores the expected menus when returning to edit mode, reducing confusion for users.
Original PR description
**Prior this commit:** - Value of sla success rate is not displayed in sample data - Daily target is not realistic in sample data - State button exists in activity view - Handle Ticket activity type exists - Back to edit mode is without menus **Post this commit:** - Displaying value of sla success rate in sample data - Setting realistic daily target for sample data - State button removed because it doesn't mean much without stage information - Removing Handle Ticket because it's redundant with to-do. - Back to edit mode has corresponding menus **Task**-3696002
The Appraisal Analysis report now includes a deadline filter, making it easier to narrow results to appraisals due within specific timeframes. This helps HR teams review upcoming or overdue appraisals more efficiently and focus on the right records.
Original PR description
This commit adds a deadline filter to the appraisal analysis view. It will help to filter out appraisals by the deadline task-3629899
Users now see a helpful message when there are no tasks available to display on the map. This makes the empty map view clearer and reduces confusion about whether content is missing or still loading.
Original PR description
Before this commit: - There was no helper message displayed when there were no tasks to view on the map. After this commit: - Added a helper message to inform users when there are no tasks available for display on the map. taskid:3734820
Approval request status labels in the kanban view now appear as ribbons instead of pills, making them more visually prominent and easier to scan. The canceled status wording was also standardized from “Cancel” to “Canceled” for clearer communication.
Original PR description
Change alters pills with ribbons for approval requests status in kanban view. task-3633858
Features or functions removed from Odoo
An empty subcontracting customization module has been fully removed because it no longer contained functional code. This reduces clutter in the system and avoids maintaining a module that no longer provides business value.
Original PR description
Commit 9aefb84c0ca removes all the specific code of `mrp_subcontracting_studio` module leaving only the description keys in the __manifest__. This commit removes completely the module
Code cleanup and technical improvements
The spreadsheet version history panel was reworked to open through the application's shared state system. This is an internal cleanup that should make the feature easier to maintain without changing the user workflow.
Original PR description
Task: 3724792
Miscellaneous changes
### Steps to reproduce: - Create a sale order with a service - Create a task in field service. - Link the sale order with the task - Duplicate the sale order. - Assign the new sale order to the task. - The smart buttons in this case aren't being updated and they remain linked to the previous sale. You can see this in the following video. ### Investigation: - The smart button is related to the `sale_order_id` - the method `_compute_sale_order_id` tends to set the sale_order_id to the o
Original PR description
### Steps to reproduce: - Create a sale order with a service - Create a task in field service. - Link the sale order with the task - Duplicate the sale order. - Assign the new sale order to the task. - The smart buttons in this case aren't being updated and they remain linked to the previous sale. You can see this in the following video. ### Investigation: - The smart button is related to the `sale_order_id` - the method `_compute_sale_order_id` tends to set the sale_order_id to the old value saved in `fsm_task_to_sale_order` before calling the parent `_compute_sale_order_id` even if the new value is not False -which is the purpose of the override- https://github.com/odoo/enterprise/blob/d9e66635dd3c2e9b994280b5e81fd53decbbf9d2/industry_fsm_sale/models/project_task.py#L168-L169 opw-3700469 Forward-Port-Of: odoo/enterprise#56115
The spreadsheet pivot features were adjusted to stay compatible with recent changes in the pivot interface. This keeps pivot-related spreadsheet actions, dialogs, templates, and collaboration behavior working consistently after the underlying interface update.
- Create an asset - Add a related purchase in tab Bills. - Click on the related purchase. => You have the horrible form view of an aml, which is something we want to avoid at all costs. We instead prevent the opening and add a clickable name of the move, as it is what people would want to see. task-3749634 Forward-Port-Of: odoo/enterprise#56899
Original PR description
- Create an asset - Add a related purchase in tab Bills. - Click on the related purchase. => You have the horrible form view of an aml, which is something we want to avoid at all costs. We instead prevent the opening and add a clickable name of the move, as it is what people would want to see. task-3749634 Forward-Port-Of: odoo/enterprise#56899
**Performance Improvement on Referral Link Generation** --------------------------------------------------------------------------------------- Current State ------------------- Currently in the `hr.referral` module when you want to generate a new referral link for a user it takes more or less a second. State After this commit --------------------------------- The generation of the link is in average way under the 10ms mark Tests ordered by performance uplift ascending -------
Original PR description
**Performance Improvement on Referral Link Generation** --------------------------------------------------------------------------------------- Current State ------------------- Currently in the…
**Performance Improvement on Referral Link Generation**
---------------------------------------------------------------------------------------
Current State
-------------------
Currently in the `hr.referral` module when you want to generate a new referral link for a user it takes more or less a second.
State After this commit
---------------------------------
The generation of the link is in average way under the 10ms mark
Tests ordered by performance uplift ascending
-------------------------------------------------------------------
Note: All the tests have been made 3times and I took the less advantageous one for this commit every time.
Note2: As explained after the result are probably underestimated since with the current behavior we litterally make a request and get the full web page of the job position when generating a referral link which is extremely dependent on the load of the server and the db. (We can even have timeout) The time it takes currently is also directly dependant of the size of the job page so it could be theoretically speaking arbitrary long to get the job page.
Note3: All the tests are realized on 15.0
**Full response (+- 18x)**
**On runbot including the time of response before**

**On runbot including the time of response after**

We are in the golden bracket of 50-150ms latency
**Create (+- 100x)**
**On runbot before**
Note: Don't hesitate to click on the photos to zoom in it
cropped

full

**On runbot after**
cropped

full

**Note for master**
In master the `create` method is taking most of the time 3.8ms to execute with no real changes for the `search_or_create` so you'll get an uplift of arround 250x with this commit
Explaination
------------------
Currently when you generate a referral link in the referral app you'll call the the `search_or_create` method of the `link.tracker` model.
``` python
@api.model
def search_or_create(self, vals):
if 'url' not in vals:
raise ValueError(_('Creating a Link Tracker without URL is not possible'))
if vals['url'].startswith(('?', '#')):
raise UserError(_("%r is not a valid link, links cannot redirect to the current page.", vals['url']))
vals['url'] = tools.validate_url(vals['url'])
search_domain = [
(fname, '=', value)
for fname, value in vals.items()
if fname in ['url', 'campaign_id', 'medium_id', 'source_id']
]
result = self.search(search_domain, limit=1)
if result:
return result
return self.create(vals)
```
And if we don't have a hit during the search we will create the `link.tracker` record that is created this way:
```python
@api.model_create_multi
def create(self, vals_list):
vals_list = [vals.copy() for vals in vals_list]
for vals in vals_list:
if 'url' not in vals:
raise ValueError(_('Creating a Link Tracker without URL is not possible'))
if vals['url'].startswith(('?', '#')):
raise UserError(_("%r is not a valid link, links cannot redirect to the current page.", vals['url']))
vals['url'] = tools.validate_url(vals['url'])
if not vals.get('title'):
vals['title'] = self._get_title_from_url(vals['url'])
# Prevent the UTMs to be set by the values of UTM cookies
for (__, fname, __) in self.env['utm.mixin'].tracking_fields():
if fname not in vals:
vals[fname] = False
```
As we can see here if no **title** is given to the `search_or_create` method we will call the `_get_title_from_url` method of `link.tracker`
```python
@api.model
@api.depends('url')
def _get_title_from_url(self, url):
preview = link_preview.get_link_preview_from_url(url)
if preview and preview.get('og_title'):
return preview['og_title']
return url
```
If you time this method it takes around .9 seconds to do it's job. (In local it represent more than 99 percent of the time that take the `create` method)
On the runbot

If we go to `odoo.addons.mail.tools.link_preview` we can clearly see why it takes time
```python
def get_link_preview_from_url(url, request_session=None):
# Some websites are blocking non browser user agent.
user_agent = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0'}
try:
if request_session:
response = request_session.get(url, timeout=3, headers=user_agent, allow_redirects=True, stream=True)
else:
response = requests.get(url, timeout=3, headers=user_agent, allow_redirects=True, stream=True)
except requests.exceptions.RequestException:
return False
if not response.ok or not response.headers.get('Content-Type'):
return False
# Content-Type header can return a charset, but we just need the
# mimetype (eg: image/jpeg;charset=ISO-8859-1)
content_type = response.headers['Content-Type'].split(';')
if response.headers['Content-Type'].startswith('image/'):
return {
'image_mimetype': content_type[0],
'og_image': url, # If the url mimetype is already an image type, set url as preview image
'source_url': url,
}
elif response.headers['Content-Type'].startswith('text/html'):
return get_link_preview_from_html(url, response)
return False
def get_link_preview_from_html(url, response):
content = b""
for chunk in response.iter_content(chunk_size=8192):
content += chunk
pos = content.find(b'</head>', -8196 * 2)
# Stop reading once all the <head> data is found
if pos != -1:
content = content[:pos + 7]
break
if not content:
return False
tree = html.fromstring(content)
og_title = tree.xpath('//meta[@property="og:title"]/@content')
if og_title:
og_title = og_title[0]
elif tree.find('.//title') is not None:
# Fallback on the <title> tag if it exists
og_title = tree.find('.//title').text
else:
return False
og_description = tree.xpath('//meta[@property="og:description"]/@content')
og_type = tree.xpath('//meta[@property="og:type"]/@content')
og_site_name = tree.xpath('//meta[@property="og:site_name"]/@content')
og_image = tree.xpath('//meta[@property="og:image"]/@content')
og_mimetype = tree.xpath('//meta[@property="og:image:type"]/@content')
return {
'og_description': og_description[0] if og_description else None,
'og_image': og_image[0] if og_image else None,
'og_mimetype': og_mimetype[0] if og_mimetype else None,
'og_title': og_title,
'og_type': og_type[0] if og_type else None,
'og_site_name': og_site_name[0] if og_site_name else None,
'source_url': url,
}
```
As we can see it clearly makes a request to the server (in this case itself) that will take in most cases something like a second. (It can be longer and **timeout after 3 seconds and thus not even giving us a title at all and then give you the url as a title**)
[BTW In this case, doing that is probably sub optimal because we could probably just used some internal methods to accelerate the process instead of using `get`]
So we make a request to the server that will need to actually render the view with all the fields and then analyzing it to retrieve infos.
**In conclusion**
By giving a title to the link that we want to generate it will be way faster and since the title is not taken into account during the search part of the `search_or_create`, we basically have no change in behavior and even getting more consistency in the titles that will be displayed on base_url/r.
Other benefits
----------------------
1. Before the links title where generated using the meta of the web page. This can lead to basically random titles because if no one has visited the page before, the title will be the link (same if the request timeout) and if it has been visited it will be the title that you can see in your tabs.
2. You can basically reduce the number of requests to the server which in this case is even better because the more user you have the more likely you will overload it and increase the probability of a request timeout.
3. Before the multi db on read mode all the activity on website are tracked and since you literally visit the web page of the job title you'll get some bias on the website activity. This commit solve this issue as well because we'll not visit the job url anymore.
4. Consistency in the time needed to generated a link.
Performance impact for big companies like odoo
----------------------------------------------------------------------
**Today**
we have 35 different jobs opened for referral
We are 4k employees
if you want to generate all referral links even when taking advantage of batch it will take you more or less 35hours of computations
(in the near future we will include the possibility to generate all the links and send them to all employees and with this it's possible to do it in less than a minute by taking advantage of the batch create)
For the near future
----------------------------
2 tasks are including to generate a bunch of referral links at the same time (with a company of the size of odoo)
- 3418434 (more than a minute just to open the jobs page)
- 3607159 (with current state more than 2hours to send the mails)
task-3707478
Forward-Port-Of: odoo/enterprise#56907
Forward-Port-Of: odoo/enterprise#55349Before this commit, the ticket is set to a random helpdesk team with the id equals to 2 which is surely the id of a demo data (VIP Support). This commit makes sure the ticket created inside the test will be linked to a helpdesk team created in the test and not a helpdesk team linked to the demo data. runbot-57412 Forward-Port-Of: odoo/enterprise#56944
Original PR description
Before this commit, the ticket is set to a random helpdesk team with the id equals to 2 which is surely the id of a demo data (VIP Support). This commit makes sure the ticket created inside the test will be linked to a helpdesk team created in the test and not a helpdesk team linked to the demo data. runbot-57412 Forward-Port-Of: odoo/enterprise#56944
Before this commit, when the demo data adds a public leave for the current day, the test `test_adjust_grid_holidays` could fail because we could fetch the timesheet generating the public leave instead of the one created. This commit adds a freeze_time on the test to be sure the current date is not the current one but `2018-06-02`. runbot-57194 Forward-Port-Of: odoo/enterprise#56884 Forward-Port-Of: odoo/enterprise#56524
Original PR description
Before this commit, when the demo data adds a public leave for the current day, the test `test_adjust_grid_holidays` could fail because we could fetch the timesheet generating the public leave instead of the one created. This commit adds a freeze_time on the test to be sure the current date is not the current one but `2018-06-02`. runbot-57194 Forward-Port-Of: odoo/enterprise#56884 Forward-Port-Of: odoo/enterprise#56524
https://github.com/odoo/enterprise/pull/40112 allowed resending documents in mass, however it does not check for shared sign requests. Since shared sign requests are targetted at public users, it is not possible to resend them. This PR fixes this by ignoring the shared sign requests. It was chosen to ignore them because we still want to allow selecting all documents and resending only the ones that can be resent. task-3721338 Forward-Port-Of: odoo/enterprise#55824
Original PR description
https://github.com/odoo/enterprise/pull/40112 allowed resending documents in mass, however it does not check for shared sign requests. Since shared sign requests are targetted at public users, it is not possible to resend them. This PR fixes this by ignoring the shared sign requests. It was chosen to ignore them because we still want to allow selecting all documents and resending only the ones that can be resent. task-3721338 Forward-Port-Of: odoo/enterprise#55824
Steps: - Create a PO, confirm and receive the product - Create the bill from the PO - On the bill form add a section/note - Go to Other Infos tab -> "Should be paid" is set to "Exceptions", it should be "Yes" This is because we don't exclude section and note from the line when computing the field `release_to_pay` opw-3724937 Forward-Port-Of: odoo/enterprise#56622
Original PR description
Steps: - Create a PO, confirm and receive the product - Create the bill from the PO - On the bill form add a section/note - Go to Other Infos tab -> "Should be paid" is set to "Exceptions", it should be "Yes" This is because we don't exclude section and note from the line when computing the field `release_to_pay` opw-3724937 Forward-Port-Of: odoo/enterprise#56622
Task: 3584650 Forward-Port-Of: odoo/enterprise#56457 Forward-Port-Of: odoo/enterprise#52871
Original PR description
Task: 3584650 Forward-Port-Of: odoo/enterprise#56457 Forward-Port-Of: odoo/enterprise#52871
### Version: - 17.0 ### Steps to reproduce: - Add a document to the subscription product and make it visible during the confirmed order. - Create a new subscription quotation for that product. - Confirm the subscription quotation. - In confirmed orders, the product document will not be visible. ### Issue: The product documents are not visible on the portal template. ### Improvement: According to its visibility value, the product document will be shown on the portal template
Original PR description
### Version: - 17.0 ### Steps to reproduce: - Add a document to the subscription product and make it visible during the confirmed order. - Create a new subscription quotation for that product. - Confirm the subscription quotation. - In confirmed orders, the product document will not be visible. ### Issue: The product documents are not visible on the portal template. ### Improvement: According to its visibility value, the product document will be shown on the portal template. task-3667716 --- I confirm I have signed the CLA and read the PR guidelines at [www.odoo.com/submit-pr](http://www.odoo.com/submit-pr) Forward-Port-Of: odoo/enterprise#56369 Forward-Port-Of: odoo/enterprise#54126
Task: 3581647 Forward-Port-Of: odoo/enterprise#56190 Forward-Port-Of: odoo/enterprise#54628
Original PR description
Task: 3581647 Forward-Port-Of: odoo/enterprise#56190 Forward-Port-Of: odoo/enterprise#54628
IAP: https://github.com/odoo/iap-apps/pull/751 Documentation: https://github.com/odoo/documentation/pull/7683 task-id 3704792 Forward-Port-Of: odoo/enterprise#56838 Forward-Port-Of: odoo/enterprise#55858
Original PR description
IAP: https://github.com/odoo/iap-apps/pull/751 Documentation: https://github.com/odoo/documentation/pull/7683 task-id 3704792 Forward-Port-Of: odoo/enterprise#56838 Forward-Port-Of: odoo/enterprise#55858
This pr contains Three commits: - The first commit will add a little banner on the cart of bank journal when they don't have an account number linked (only for l10n_dk). - The other commit will add a user error if the user tries to export the saf-t report without having an account number set on the company. Also adding the infos in the warning of the general ledger saying the missing field for the saf-t. - Also adding the translation for the two commits above task: 3709843 Forwar
Original PR description
This pr contains Three commits: - The first commit will add a little banner on the cart of bank journal when they don't have an account number linked (only for l10n_dk). - The other commit will add a user error if the user tries to export the saf-t report without having an account number set on the company. Also adding the infos in the warning of the general ledger saying the missing field for the saf-t. - Also adding the translation for the two commits above task: 3709843 Forward-Port-Of: odoo/enterprise#55636
The `parent_line_id` parameter and value was missing from the generic line id. Forward-Port-Of: odoo/enterprise#56807 Forward-Port-Of: odoo/enterprise#56725
Original PR description
The `parent_line_id` parameter and value was missing from the generic line id. Forward-Port-Of: odoo/enterprise#56807 Forward-Port-Of: odoo/enterprise#56725
## Description When a user opens the Shop Floor app, each MrpDisplayRecord will compute the barcode target record based on the admin ID. This can lead to slow computations and make the browser crash when there are many records. ## Analysis The barcode target record ID will always be the same as long as the admin ID doesn't change. ### Before this commit All MrpDisplayRecord are recomputing the barcode target record. ### After this commit We cache the admin ID and the barcode target
Original PR description
## Description When a user opens the Shop Floor app, each MrpDisplayRecord will compute the barcode target record based on the admin ID. This can lead to slow computations and make the browser crash when there are many records. ## Analysis The barcode target record ID will always be the same as long as the admin ID doesn't change. ### Before this commit All MrpDisplayRecord are recomputing the barcode target record. ### After this commit We cache the admin ID and the barcode target record ID to avoid recomputing it if unecessary. ## Benchmarks Computing the barcode target records when opening the Shop Floor app: | Relevant MO | Before | After | |-------------|---------|--------| | 80 | 0.9 s | 0.6 s | | 400 | 23.2 s | 1.8 s | | 879 | 140 s / Browser crash | 2.8 s | ## References opw-3721896 opw-3741051 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/enterprise#56167
Currently, when an employee contract belongs to a company different than the employee's company, a warning is shown in the payroll dashboard [1]. However, if the current user has no access to the contract's company, an access error is raised, which makes not possible to neither see the warning nor load the dashboard. This commit fixes the above issue by ensuring the employee contract is read as sudo, to avoid requiring the current user to have both companies selected to see the warning. R
Original PR description
Currently, when an employee contract belongs to a company different than the employee's company, a warning is shown in the payroll dashboard [1]. However, if the current user has no access to the contract's company, an access error is raised, which makes not possible to neither see the warning nor load the dashboard. This commit fixes the above issue by ensuring the employee contract is read as sudo, to avoid requiring the current user to have both companies selected to see the warning. References: - [1] https://github.com/odoo/enterprise/blob/e41d2ce5/hr_payroll/models/hr_payslip.py#L1072 **Access Error:**  Forward-Port-Of: odoo/enterprise#56655 Forward-Port-Of: odoo/enterprise#56335
This commit fixes a bug where the Comments would only load one of the different Components present inside of the view, meaning that only one thread would show their messages. This leads to possible losses of comments and the main chatter being unable to show messages. The issue was that both the comments and the form view shared a singular chatter object in the environment. This object enables the Thread component to know if it needs to either load more data or messages via two booleans: `fet
Original PR description
This commit fixes a bug where the Comments would only load one of the different Components present inside of the view, meaning that only one thread would show their messages. This leads to possible…
This commit fixes a bug where the Comments would only load one of the different Components present inside of the view, meaning that only one thread would show their messages. This leads to possible losses of comments and the main chatter being unable to show messages. The issue was that both the comments and the form view shared a singular chatter object in the environment. This object enables the Thread component to know if it needs to either load more data or messages via two booleans: `fetchData` and `fetchMessages` that would be set to false when the Thread finished fetching either messages or data. To fix this, the chatter in the environment below the Comment level was set to false, as the condition to fetch data and messages is `!this.env.chatter || this.env.chatter?.fetchData`. This way when OWL mounts each Comment Component it will fetch the necessary data without impacting each other and the Form view's main chatter. task-3714345 Forward-Port-Of: odoo/enterprise#55517