You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							585 lines
						
					
					
						
							28 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							585 lines
						
					
					
						
							28 KiB
						
					
					
				
								# -*- coding: utf-8 -*-
							 | 
						|
								###############################################################################
							 | 
						|
								#
							 | 
						|
								#    Cybrosys Technologies Pvt. Ltd.
							 | 
						|
								#
							 | 
						|
								#    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
							 | 
						|
								#    Author: Gokul P I (odoo@cybrosys.com)
							 | 
						|
								#
							 | 
						|
								#    You can modify it under the terms of the GNU LESSER
							 | 
						|
								#    GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
							 | 
						|
								#
							 | 
						|
								#    This program is distributed in the hope that it will be useful,
							 | 
						|
								#    but WITHOUT ANY WARRANTY without even the implied warranty of
							 | 
						|
								#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
							 | 
						|
								#    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
							 | 
						|
								#
							 | 
						|
								#    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
							 | 
						|
								#    (LGPL v3) along with this program.
							 | 
						|
								#    If not, see <http://www.gnu.org/licenses/>.
							 | 
						|
								#
							 | 
						|
								###############################################################################
							 | 
						|
								import base64
							 | 
						|
								import json
							 | 
						|
								import os
							 | 
						|
								import re
							 | 
						|
								import requests
							 | 
						|
								from requests.auth import HTTPBasicAuth
							 | 
						|
								from odoo import fields, models, _
							 | 
						|
								from odoo.exceptions import ValidationError
							 | 
						|
								from odoo.tools import html2plaintext
							 | 
						|
								# The Header parameters
							 | 
						|
								HEADERS = {
							 | 
						|
								    'Accept': 'application/json',
							 | 
						|
								    'Content-Type': 'application/json'
							 | 
						|
								}
							 | 
						|
								JIRA_HEADERS = {
							 | 
						|
								    'Accept': 'application/json'
							 | 
						|
								}
							 | 
						|
								ATTACHMENT_HEADERS = {
							 | 
						|
								    'X-Atlassian-Token': 'no-check'
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								class ResConfigSettings(models.TransientModel):
							 | 
						|
								    """ This class is inheriting the model res.config.settings It contains
							 | 
						|
								    fields and functions for the model.
							 | 
						|
								    Methods:
							 | 
						|
								        get_values():
							 | 
						|
								            extends get_values() to include new config parameters
							 | 
						|
								        set_values():
							 | 
						|
								            extends set_values() to include new config parameters
							 | 
						|
								        action_test_connection():
							 | 
						|
								            action to perform when clicking on the 'Test Connection'
							 | 
						|
								            button.
							 | 
						|
								        action_export_to_jira():
							 | 
						|
								            action to perform when clicking on the 'Export/Sync Project'
							 | 
						|
								            button.
							 | 
						|
								        action_import_from_jira():
							 | 
						|
								            action to perform when clicking on the 'Export Users' button.
							 | 
						|
								        action_export_users():
							 | 
						|
								            action to perform when clicking on the 'Reset to Draft' button.
							 | 
						|
								        action_import_users():
							 | 
						|
								            action to perform when clicking on the 'Import Users' button.
							 | 
						|
								        _export_attachments(attachments, attachment_url):
							 | 
						|
								            it is used to export the given attachments to Jira.
							 | 
						|
								        find_attachment_type(attachment):
							 | 
						|
								           it is used to find the attachment type for the given attachment.
							 | 
						|
								    """
							 | 
						|
								    _inherit = 'res.config.settings'
							 | 
						|
								
							 | 
						|
								    url = fields.Char(
							 | 
						|
								        string='URL', config_parameter='odoo_jira_connector.url',
							 | 
						|
								        help='Your Jira URL: E.g. https://yourname.atlassian.net/')
							 | 
						|
								    user_id_jira = fields.Char(
							 | 
						|
								        string='User Name', help='E.g. yourmail@gmail.com ',
							 | 
						|
								        config_parameter='odoo_jira_connector.user_id_jira')
							 | 
						|
								    api_token = fields.Char(string='API Token', help='API token in your Jira.',
							 | 
						|
								                            config_parameter='odoo_jira_connector.api_token')
							 | 
						|
								    connection = fields.Boolean(
							 | 
						|
								        string='Connection', default=False, help='To identify the connection.',
							 | 
						|
								        config_parameter='odoo_jira_connector.connection')
							 | 
						|
								    export_project_count = fields.Integer(
							 | 
						|
								        string='Export Project Count', default=0, readonly=True,
							 | 
						|
								        help='Number of export projects.',
							 | 
						|
								        config_parameter='odoo_jira_connector.export_project_count')
							 | 
						|
								    export_task_count = fields.Integer(
							 | 
						|
								        string='Export Task Count', default=0, readonly=True,
							 | 
						|
								        help='Number of export tasks.',
							 | 
						|
								        config_parameter='odoo_jira_connector.export_task_count')
							 | 
						|
								    import_project_count = fields.Integer(
							 | 
						|
								        string='Import Project Count', default=0, readonly=True,
							 | 
						|
								        help='Number of import project.',
							 | 
						|
								        config_parameter='odoo_jira_connector.import_project_count')
							 | 
						|
								    import_task_count = fields.Integer(
							 | 
						|
								        string='Import Task Count', default=0, readonly=True,
							 | 
						|
								        help='Number of import tasks.',
							 | 
						|
								        config_parameter='odoo_jira_connector.import_task_count')
							 | 
						|
								    automatic = fields.Boolean(string='Automatic',
							 | 
						|
								                               help='to make export/import data automated '
							 | 
						|
								                                    'while creating it on configured Jira '
							 | 
						|
								                                    'account.',
							 | 
						|
								                               config_parameter='odoo_jira_connector.automatic')
							 | 
						|
								
							 | 
						|
								    def action_test_connection(self):
							 | 
						|
								        """ Test the connection to Jira
							 | 
						|
								        Raises: ValidationError: If the credentials are invalid.
							 | 
						|
								        Returns:
							 | 
						|
								            dict: client action for displaying notification
							 | 
						|
								        """
							 | 
						|
								        try:
							 | 
						|
								            # Create an authentication object, using registered email-ID, and
							 | 
						|
								            # token received.
							 | 
						|
								            auth = HTTPBasicAuth(self.user_id_jira, self.api_token)
							 | 
						|
								            response = requests.request('GET',
							 | 
						|
								                                        self.url + 'rest/api/2/project',
							 | 
						|
								                                        headers=JIRA_HEADERS, auth=auth)
							 | 
						|
								            if response.status_code == 200 and 'expand' in response.text:
							 | 
						|
								                self.env['ir.config_parameter'].sudo().set_param(
							 | 
						|
								                    'odoo_jira_connector.connection', True)
							 | 
						|
								                return {
							 | 
						|
								                    'type': 'ir.actions.client',
							 | 
						|
								                    'tag': 'display_notification',
							 | 
						|
								                    'params': {
							 | 
						|
								                        'type': 'success',
							 | 
						|
								                        'message': _(
							 | 
						|
								                            'Test connection to Jira successful.'),
							 | 
						|
								                        'next': {
							 | 
						|
								                            'type': 'ir.actions.act_window_close'
							 | 
						|
								                        }
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								            return {
							 | 
						|
								                'type': 'ir.actions.client',
							 | 
						|
								                'tag': 'display_notification',
							 | 
						|
								                'params': {
							 | 
						|
								                    'type': 'danger',
							 | 
						|
								                    'message': _('Please Enter Valid Credentials.'),
							 | 
						|
								                    'next': {
							 | 
						|
								                        'type': 'ir.actions.act_window_close'
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								        except Exception:
							 | 
						|
								            raise ValidationError(_('Please Enter Valid Credentials.'))
							 | 
						|
								
							 | 
						|
								    def action_export_to_jira(self):
							 | 
						|
								        """ Exporting All The Projects And Corresponding Tasks to Jira,
							 | 
						|
								        and updating the project or task on Jira if it is updated in Odoo.
							 | 
						|
								        """
							 | 
						|
								        ir_config_parameter = self.env['ir.config_parameter'].sudo()
							 | 
						|
								        auth = HTTPBasicAuth(self.user_id_jira, self.api_token)
							 | 
						|
								        response = requests.request('GET', self.url + 'rest/api/2/project',
							 | 
						|
								                                    headers=JIRA_HEADERS, auth=auth)
							 | 
						|
								        projects = json.dumps(json.loads(response.text), sort_keys=True,
							 | 
						|
								                              indent=4, separators=(',', ': '))
							 | 
						|
								        project_json = json.loads(projects)
							 | 
						|
								        name_list = [project['name'] for project in project_json]
							 | 
						|
								        id_list = [project['id'] for project in project_json]
							 | 
						|
								        odoo_projects = self.env['project.project'].search(
							 | 
						|
								            [('project_id_jira', 'in', id_list)])
							 | 
						|
								        for project in odoo_projects:
							 | 
						|
								            if project.jira_project_key:
							 | 
						|
								                project_keys = project.jira_project_key
							 | 
						|
								            else:
							 | 
						|
								                key = project.name.upper()
							 | 
						|
								                project_key = key[:3] + '1' + key[-3:]
							 | 
						|
								                project_keys = project_key.replace(' ', '')
							 | 
						|
								            response = requests.get(
							 | 
						|
								                self.url + 'rest/api/3/search', headers=HEADERS,
							 | 
						|
								                params={'jql': 'project = %s' % project_keys},
							 | 
						|
								                auth=(self.user_id_jira, self.api_token))
							 | 
						|
								            data = response.json()
							 | 
						|
								            issue_keys = [issue.get('key') for issue in data.get('issues', {})]
							 | 
						|
								            tasks = self.env['project.task'].search(
							 | 
						|
								                [('project_id', '=', project.id)])
							 | 
						|
								            for task in tasks:
							 | 
						|
								                attachment_url = self.url + 'rest/api/3/issue/%s/' \
							 | 
						|
								                                            'attachments' % task.task_id_jira
							 | 
						|
								                comment_url = self.url + 'rest/api/3/issue/%s/comment' % (
							 | 
						|
								                    task.task_id_jira)
							 | 
						|
								                if str(task.task_id_jira) in issue_keys:
							 | 
						|
								                    messages = self.env['mail.message'].search(
							 | 
						|
								                        ['&', ('res_id', '=', task.id),
							 | 
						|
								                         ('model', '=', 'project.task')])
							 | 
						|
								                    attachments = self.env['ir.attachment'].search(
							 | 
						|
								                        [('res_id', '=', task.id)])
							 | 
						|
								                    self._export_attachments(attachments, attachment_url)
							 | 
						|
								                    response = requests.get(
							 | 
						|
								                        comment_url, headers=HEADERS, auth=(
							 | 
						|
								                            self.user_id_jira, self.api_token))
							 | 
						|
								                    data = response.json()
							 | 
						|
								                    jira_comment_list = []
							 | 
						|
								                    for comments in data['comments']:
							 | 
						|
								                        content = comments.get('body', {}).get('content', [])
							 | 
						|
								                        if content and isinstance(content, list) and content[
							 | 
						|
								                            0].get('type') == 'paragraph':
							 | 
						|
								                            text = content[0]['content'][0].get('text')
							 | 
						|
								                            if text:
							 | 
						|
								                                jira_comment_list.append(str(text))
							 | 
						|
								                    odoo_comment_list = [str(
							 | 
						|
								                        html2plaintext(chat.body)) for chat in messages if
							 | 
						|
								                        str(html2plaintext(
							 | 
						|
								                            chat.body)) not in jira_comment_list]
							 | 
						|
								                    comment_list = list(filter(None, odoo_comment_list))
							 | 
						|
								                    if len(comment_list) > 0:
							 | 
						|
								                        for comment in comment_list:
							 | 
						|
								                            data = json.dumps({
							 | 
						|
								                                'body': {
							 | 
						|
								                                    'type': 'doc',
							 | 
						|
								                                    'version': 1,
							 | 
						|
								                                    'content': [{
							 | 
						|
								                                        'type': 'paragraph',
							 | 
						|
								                                        'content': [{
							 | 
						|
								                                            'text': comment,
							 | 
						|
								                                            'type': 'text'
							 | 
						|
								                                        }]}
							 | 
						|
								                                    ]}
							 | 
						|
								                            })
							 | 
						|
								                            requests.post(
							 | 
						|
								                                comment_url, headers=HEADERS, data=data,
							 | 
						|
								                                auth=(self.user_id_jira, self.api_token))
							 | 
						|
								                else:
							 | 
						|
								                    payload = json.dumps({
							 | 
						|
								                        'fields': {
							 | 
						|
								                            'project':
							 | 
						|
								                                {
							 | 
						|
								                                    'key': project_keys
							 | 
						|
								                                },
							 | 
						|
								                            'summary': task.name,
							 | 
						|
								                            'description': task.description,
							 | 
						|
								                            'issuetype': {
							 | 
						|
								                                'name': 'Task'
							 | 
						|
								                            }
							 | 
						|
								                        }
							 | 
						|
								                    })
							 | 
						|
								                    response = requests.post(
							 | 
						|
								                        self.url + '/rest/api/2/issue', headers=HEADERS,
							 | 
						|
								                        data=payload, auth=(self.user_id_jira, self.api_token))
							 | 
						|
								                    data = response.json()
							 | 
						|
								                    task.task_id_jira = data['key']
							 | 
						|
								                    ir_config_parameter.set_param('export_task_count', int(
							 | 
						|
								                        ir_config_parameter.get_param(
							 | 
						|
								                            'export_task_count')) + 1)
							 | 
						|
								                    messages = self.env['mail.message'].search(
							 | 
						|
								                        ['&', ('res_id', '=', task.id),
							 | 
						|
								                         ('model', '=', 'project.task')])
							 | 
						|
								                    attachments = self.env['ir.attachment'].search(
							 | 
						|
								                        [('res_id', '=', task.id)])
							 | 
						|
								                    self._export_attachments(attachments, attachment_url)
							 | 
						|
								                    for chat in messages:
							 | 
						|
								                        data = json.dumps({
							 | 
						|
								                            'body': {
							 | 
						|
								                                'type': 'doc',
							 | 
						|
								                                'version': 1,
							 | 
						|
								                                'content': [{
							 | 
						|
								                                    'type': 'paragraph',
							 | 
						|
								                                    'content': [{
							 | 
						|
								                                        'text': str(html2plaintext(chat.body)),
							 | 
						|
								                                        'type': 'text'}]
							 | 
						|
								                                }]
							 | 
						|
								                            }
							 | 
						|
								                        })
							 | 
						|
								                        requests.post(
							 | 
						|
								                            comment_url, headers=HEADERS, data=data,
							 | 
						|
								                            auth=(self.user_id_jira, self.api_token))
							 | 
						|
								        odoo_projects = self.env['project.project'].search(
							 | 
						|
								            [('project_id_jira', 'not in', id_list),
							 | 
						|
								             ('name', 'not in', name_list)])
							 | 
						|
								        for project in odoo_projects:
							 | 
						|
								            key = project.name.upper()
							 | 
						|
								            project_key = key[:3] + '1' + key[-3:]
							 | 
						|
								            project_keys = project_key.replace(' ', "")
							 | 
						|
								            auth = HTTPBasicAuth(self.user_id_jira, self.api_token)
							 | 
						|
								            project_payload = {
							 | 
						|
								                'name': project.name,
							 | 
						|
								                'key': project_keys,
							 | 
						|
								                'templateKey': 'com.pyxis.greenhopper.jira:gh-simplified'
							 | 
						|
								                               '-kanban-classic'
							 | 
						|
								            }
							 | 
						|
								            response = requests.request(
							 | 
						|
								                'POST', self.url + 'rest/simplified/latest/project',
							 | 
						|
								                data=json.dumps(project_payload), headers=HEADERS, auth=auth)
							 | 
						|
								            data = response.json()
							 | 
						|
								            if 'projectId' in data:
							 | 
						|
								                project.write({
							 | 
						|
								                    'project_id_jira': data['projectId'],
							 | 
						|
								                    'jira_project_key': data['projectKey']
							 | 
						|
								                })
							 | 
						|
								                ir_config_parameter.set_param(
							 | 
						|
								                    'export_project_count', int(ir_config_parameter.get_param(
							 | 
						|
								                        'export_project_count')) + 1)
							 | 
						|
								                # for creating a new task inside the project
							 | 
						|
								                tasks = self.env['project.task'].search(
							 | 
						|
								                    [('project_id', '=', project.id)])
							 | 
						|
								                for task in tasks:
							 | 
						|
								                    payload = json.dumps({
							 | 
						|
								                        'fields': {
							 | 
						|
								                            'project': {
							 | 
						|
								                                'key': project_keys
							 | 
						|
								                            },
							 | 
						|
								                            'summary': task.name,
							 | 
						|
								                            'description': task.description,
							 | 
						|
								                            'issuetype': {
							 | 
						|
								                                'name': 'Task'
							 | 
						|
								                            }
							 | 
						|
								                        }
							 | 
						|
								                    })
							 | 
						|
								                    response2 = requests.post(
							 | 
						|
								                        self.url + '/rest/api/2/issue', headers=HEADERS,
							 | 
						|
								                        data=payload, auth=(self.user_id_jira, self.api_token))
							 | 
						|
								                    data = response2.json()
							 | 
						|
								                    task.task_id_jira = data['key']
							 | 
						|
								                    attachment_url = self.url + 'rest/api/3/issue/%s/' \
							 | 
						|
								                                                'attachments' % task.task_id_jira
							 | 
						|
								                    comment_url = self.url + 'rest/api/3/issue/%s/comment' % (
							 | 
						|
								                        task.task_id_jira)
							 | 
						|
								                    ir_config_parameter.set_param('export_task_count', int(
							 | 
						|
								                        ir_config_parameter.get_param('export_task_count')) + 1)
							 | 
						|
								                    messages = self.env['mail.message'].search(
							 | 
						|
								                        ['&', ('res_id', '=', task.id),
							 | 
						|
								                         ('model', '=', 'project.task')])
							 | 
						|
								                    attachments = self.env['ir.attachment'].search(
							 | 
						|
								                        [('res_id', '=', task.id)])
							 | 
						|
								                    self._export_attachments(attachments, attachment_url)
							 | 
						|
								                    for message in messages:
							 | 
						|
								                        data = json.dumps({
							 | 
						|
								                            'body': {
							 | 
						|
								                                'type': 'doc',
							 | 
						|
								                                'version': 1,
							 | 
						|
								                                'content': [{
							 | 
						|
								                                    'type': 'paragraph',
							 | 
						|
								                                    'content': [{
							 | 
						|
								                                        'text': str(
							 | 
						|
								                                            html2plaintext(message.body)),
							 | 
						|
								                                        'type': 'text'}]
							 | 
						|
								                                }]
							 | 
						|
								                            }
							 | 
						|
								                        })
							 | 
						|
								                        requests.post(comment_url, headers=HEADERS, data=data,
							 | 
						|
								                                      auth=(self.user_id_jira, self.api_token))
							 | 
						|
								            elif 'errors' in data and 'projectName' in data['errors']:
							 | 
						|
								                raise ValidationError(
							 | 
						|
								                    "A project with the names already exists in Jira. Please "
							 | 
						|
								                    "rename the project to export as a new project.")
							 | 
						|
								            elif 'errors' in data and 'projectKey' in data['errors']:
							 | 
						|
								                raise ValidationError(data['errors']['projectKey'])
							 | 
						|
								
							 | 
						|
								    def action_import_from_jira(self):
							 | 
						|
								        """ Import all the projects and corresponding tasks
							 | 
						|
								           from Odoo to Jira. If a project or task is modified in Odoo,
							 | 
						|
								           it will also be updated in Jira.
							 | 
						|
								        """
							 | 
						|
								        ir_config_parameter = self.env['ir.config_parameter'].sudo()
							 | 
						|
								        auth = HTTPBasicAuth(self.user_id_jira, self.api_token)
							 | 
						|
								        response = requests.request(
							 | 
						|
								            'GET', self.url + 'rest/api/2/project', headers=JIRA_HEADERS,
							 | 
						|
								            auth=auth)
							 | 
						|
								        projects = json.dumps(json.loads(response.text), sort_keys=True,
							 | 
						|
								                              indent=4, separators=(',', ': '))
							 | 
						|
								        project_json = json.loads(projects)
							 | 
						|
								        value_list = [a_dict['key'] for a_dict in project_json]
							 | 
						|
								        name_list = [a_dict['name'] for a_dict in project_json]
							 | 
						|
								        id_list = [a_dict['id'] for a_dict in project_json]
							 | 
						|
								        odoo_projects = self.env['project.project'].search([])
							 | 
						|
								        for (project, key, jira_id) in zip(name_list, value_list, id_list):
							 | 
						|
								            jira_project_ids = [
							 | 
						|
								                project.project_id_jira for project in odoo_projects]
							 | 
						|
								            if int(jira_id) in jira_project_ids:
							 | 
						|
								                response = requests.get(
							 | 
						|
								                    self.url + 'rest/api/3/search', headers=HEADERS,
							 | 
						|
								                    params={'jql': 'project = %s' % key},
							 | 
						|
								                    auth=(self.user_id_jira, self.api_token))
							 | 
						|
								                data = response.json()
							 | 
						|
								                project = self.env['project.project'].search(
							 | 
						|
								                    [('project_id_jira', '=', int(jira_id))])
							 | 
						|
								                tasks = self.env['project.task'].search(
							 | 
						|
								                    [('project_id', '=', project.id)])
							 | 
						|
								                task_jira_ids = [task.task_id_jira for task in tasks]
							 | 
						|
								                for issue in data['issues']:
							 | 
						|
								                    comment_url = self.url + 'rest/api/3/issue/%s/' \
							 | 
						|
								                                             'comment' % issue['key']
							 | 
						|
								                    if issue['key'] in task_jira_ids:
							 | 
						|
								                        task_id = self.env['project.task'].search(
							 | 
						|
								                            [('task_id_jira', '=', issue['key'])])
							 | 
						|
								                        response = requests.get(
							 | 
						|
								                            comment_url, headers=HEADERS,
							 | 
						|
								                            auth=(self.user_id_jira, self.api_token))
							 | 
						|
								                        data = response.json()
							 | 
						|
								                        messages = self.env['mail.message'].search(
							 | 
						|
								                            ['&', ('res_id', '=', task_id.id),
							 | 
						|
								                             ('model', '=', 'project.task')])
							 | 
						|
								                        odoo_comment_list = [str(html2plaintext(
							 | 
						|
								                            chat.body)) for chat in messages]
							 | 
						|
								                        jira_comment_list = [str(
							 | 
						|
								                            comments['body']['content'][0]['content'][0][
							 | 
						|
								                                'text']) for comments in
							 | 
						|
								                            data['comments'] if str(
							 | 
						|
								                                comments['body']['content'][0]['content'][0][
							 | 
						|
								                                    'text']) not in odoo_comment_list]
							 | 
						|
								                        comment_list = list(filter(None, jira_comment_list))
							 | 
						|
								
							 | 
						|
								                        if len(comment_list) > 0:
							 | 
						|
								                            for comment in comment_list:
							 | 
						|
								                                task_id.message_post(body=str(comment))
							 | 
						|
								                    else:
							 | 
						|
								                        task_id = self.env['project.task'].create({
							 | 
						|
								                            'project_id': project.id,
							 | 
						|
								                            'name': issue['fields']['summary'],
							 | 
						|
								                            'task_id_jira': issue['key']
							 | 
						|
								                        })
							 | 
						|
								                        ir_config_parameter.set_param(
							 | 
						|
								                            'import_task_count', int(
							 | 
						|
								                                ir_config_parameter.get_param(
							 | 
						|
								                                    'import_task_count')) + 1)
							 | 
						|
								                        messages = self.env['mail.message'].search(
							 | 
						|
								                            ['&', ('res_id', '=', task_id.id),
							 | 
						|
								                             ('model', '=', 'project.task')])
							 | 
						|
								                        response = requests.get(
							 | 
						|
								                            comment_url, headers=HEADERS,
							 | 
						|
								                            auth=(self.user_id_jira, self.api_token))
							 | 
						|
								                        data = response.json()
							 | 
						|
								                        odoo_comment_list = [str(
							 | 
						|
								                            html2plaintext(chat.body)) for chat in messages]
							 | 
						|
								                        jira_comment_list = [str(
							 | 
						|
								                            comments['body']['content'][0]['content'][0][
							 | 
						|
								                                'text']) for comments in
							 | 
						|
								                            data['comments'] if str(
							 | 
						|
								                                comments['body']['content'][0]['content'][0][
							 | 
						|
								                                    'text']) not in odoo_comment_list]
							 | 
						|
								                        comment_list = list(filter(None, jira_comment_list))
							 | 
						|
								                        if len(comment_list) > 0:
							 | 
						|
								                            for comment in comment_list:
							 | 
						|
								                                task_id.message_post(body=str(comment))
							 | 
						|
								            else:
							 | 
						|
								                project = self.env['project.project'].create({
							 | 
						|
								                    'name': project,
							 | 
						|
								                    'project_id_jira': jira_id,
							 | 
						|
								                    'jira_project_key': key
							 | 
						|
								                })
							 | 
						|
								                ir_config_parameter.set_param(
							 | 
						|
								                    'import_project_count', int(ir_config_parameter.get_param(
							 | 
						|
								                        'import_project_count')) + 1)
							 | 
						|
								                response = requests.get(
							 | 
						|
								                    self.url + 'rest/api/3/search', headers=HEADERS,
							 | 
						|
								                    params={'jql': 'project = %s' % key},
							 | 
						|
								                    auth=(self.user_id_jira, self.api_token))
							 | 
						|
								                data = response.json()
							 | 
						|
								                for issue in data['issues']:
							 | 
						|
								                    task_id = self.env['project.task'].create({
							 | 
						|
								                        'project_id': project.id,
							 | 
						|
								                        'name': issue['fields']['summary'],
							 | 
						|
								                        'task_id_jira': issue['key']
							 | 
						|
								                    })
							 | 
						|
								                    ir_config_parameter.set_param(
							 | 
						|
								                        'import_task_count', int(ir_config_parameter.get_param(
							 | 
						|
								                            'import_task_count')) + 1)
							 | 
						|
								                    messages = self.env['mail.message'].search(
							 | 
						|
								                        ['&', ('res_id', '=', task_id.id),
							 | 
						|
								                         ('model', '=', 'project.task')])
							 | 
						|
								                    comment_url = self.url + 'rest/api/3/issue/%s/' \
							 | 
						|
								                                             'comment' % issue['key']
							 | 
						|
								                    response = requests.get(
							 | 
						|
								                        comment_url, headers=HEADERS,
							 | 
						|
								                        auth=(self.user_id_jira, self.api_token))
							 | 
						|
								                    data = response.json()
							 | 
						|
								                    odoo_comment_list = [str(html2plaintext(
							 | 
						|
								                        chat.body)) for chat in messages]
							 | 
						|
								                    jira_comment_list = [str(
							 | 
						|
								                        comments['body']['content'][0]['content'][0][
							 | 
						|
								                            'text']) for comments in
							 | 
						|
								                        data['comments'] if str(
							 | 
						|
								                            comments['body']['content'][0]['content'][0][
							 | 
						|
								                                'text']) not in odoo_comment_list]
							 | 
						|
								                    comment_list = list(filter(None, jira_comment_list))
							 | 
						|
								                    if len(comment_list) > 0:
							 | 
						|
								                        for comment in comment_list:
							 | 
						|
								                            task_id.message_post(body=str(comment))
							 | 
						|
								
							 | 
						|
								    def action_export_users(self):
							 | 
						|
								        """ Exporting all the users from Odoo to Jira, and updating the user's
							 | 
						|
								        information on Jira if it has been updated in Odoo
							 | 
						|
								        Raises: ValidationError: If the credentials are not valid.
							 | 
						|
								        """
							 | 
						|
								        response = requests.get(
							 | 
						|
								            self.url + 'rest/api/2/users/search', headers=HEADERS,
							 | 
						|
								            auth=(self.user_id_jira, self.api_token))
							 | 
						|
								        data = response.json()
							 | 
						|
								        issue_keys = [issue['accountId'] for issue in data]
							 | 
						|
								        users = self.env['res.users'].search(
							 | 
						|
								            [('jira_user_key', 'in', issue_keys)])
							 | 
						|
								        non_jira_users = self.env['res.users'].search(
							 | 
						|
								            [('jira_user_key', 'not in', issue_keys)])
							 | 
						|
								        if users:
							 | 
						|
								            for user_data in data:
							 | 
						|
								                for user in users:
							 | 
						|
								                    if user_data['accountId'] == user.jira_user_key:
							 | 
						|
								                        user_data.update({
							 | 
						|
								                            'displayName': user.name
							 | 
						|
								                        })
							 | 
						|
								        if non_jira_users:
							 | 
						|
								            regex = '^\S+@\S+\.\S+$'
							 | 
						|
								            for user in non_jira_users:
							 | 
						|
								                objs = re.search(regex, user.login)
							 | 
						|
								                if objs:
							 | 
						|
								                    if objs.string == str(user.login):
							 | 
						|
								                        payload = json.dumps({
							 | 
						|
								                            'emailAddress': user.login,
							 | 
						|
								                            'displayName': user.name,
							 | 
						|
								                            'name': user.name
							 | 
						|
								                        })
							 | 
						|
								                        response = requests.post(
							 | 
						|
								                            self.url + 'rest/api/3/user', headers=HEADERS,
							 | 
						|
								                            data=payload,
							 | 
						|
								                            auth=(self.user_id_jira, self.api_token))
							 | 
						|
								                        data = response.json()
							 | 
						|
								                        user.write({
							 | 
						|
								                            'jira_user_key': data['accountId']
							 | 
						|
								                        })
							 | 
						|
								                    else:
							 | 
						|
								                        raise ValidationError('Invalid E-mail address.')
							 | 
						|
								
							 | 
						|
								    def action_import_users(self):
							 | 
						|
								        """ Importing all the users from Jira to Odoo, and updating the user's
							 | 
						|
								        information on Odoo if it has been updated in Jira.
							 | 
						|
								        """
							 | 
						|
								        response = requests.get(
							 | 
						|
								            self.url + 'rest/api/2/users/search', headers=HEADERS,
							 | 
						|
								            auth=(self.user_id_jira, self.api_token))
							 | 
						|
								        data = response.json()
							 | 
						|
								        for user_data in data:
							 | 
						|
								            users = self.env['res.users'].sudo().search(
							 | 
						|
								                [('login', '=', user_data['displayName'])])
							 | 
						|
								            if users:
							 | 
						|
								                users.write({
							 | 
						|
								                    'jira_user_key': user_data['accountId']
							 | 
						|
								                })
							 | 
						|
								            else:
							 | 
						|
								                self.env['res.users'].create({
							 | 
						|
								                    'login': user_data['displayName'],
							 | 
						|
								                    'name': user_data['displayName'],
							 | 
						|
								                    'jira_user_key': user_data['accountId'],
							 | 
						|
								                })
							 | 
						|
								
							 | 
						|
								    def _export_attachments(self, attachments, attachment_url):
							 | 
						|
								        """ To find the corresponding attachment type in the attachment model
							 | 
						|
								        Args:
							 | 
						|
								           attachments (model.Model): values for creating new records.
							 | 
						|
								           attachment_url (str): URL for the attachment.
							 | 
						|
								        """
							 | 
						|
								        for attachment in attachments:
							 | 
						|
								            attachment_type = self.find_attachment_type(attachment)
							 | 
						|
								            if attachment.datas and attachment_type in ('pdf', 'xlsx', 'jpg'):
							 | 
						|
								                temp_file_path = f'/tmp/temp.{attachment_type}'
							 | 
						|
								                binary_data = base64.b64decode(attachment.datas)
							 | 
						|
								                # Save the binary data to a file
							 | 
						|
								                with open(temp_file_path, 'wb') as file:
							 | 
						|
								                    file.write(binary_data)
							 | 
						|
								                if attachment_type == 'jpg' and os.path.splitext(
							 | 
						|
								                        temp_file_path)[1].lower() != '.jpg':
							 | 
						|
								                    # Rename the saved file to its corresponding JPG file format
							 | 
						|
								                    file_path = os.path.splitext(temp_file_path)[0] + '.jpg'
							 | 
						|
								                    os.rename(temp_file_path, file_path)
							 | 
						|
								                    temp_file_path = file_path
							 | 
						|
								                attachment_file = {
							 | 
						|
								                    'file': (attachment.name, open(temp_file_path, 'rb'))
							 | 
						|
								                }
							 | 
						|
								                requests.post(attachment_url, headers=ATTACHMENT_HEADERS,
							 | 
						|
								                              files=attachment_file,
							 | 
						|
								                              auth=(self.user_id_jira, self.api_token))
							 | 
						|
								
							 | 
						|
								    def find_attachment_type(self, attachment):
							 | 
						|
								        """ To find the corresponding attachment type in the attachment model
							 | 
						|
								        Args:
							 | 
						|
								           attachment (model.Model): attachment to fetch the type.
							 | 
						|
								        Returns:
							 | 
						|
								            str: the attachment type
							 | 
						|
								        """
							 | 
						|
								        if attachment.mimetype == 'application/pdf':
							 | 
						|
								            return 'pdf'
							 | 
						|
								        if attachment.mimetype == 'image/png':
							 | 
						|
								            return 'jpg'
							 | 
						|
								        if attachment.mimetype == 'application/vnd.openxmlformats-' \
							 | 
						|
								                                  'officedocument.spreadsheetml.sheet':
							 | 
						|
								            return 'xlsx'
							 | 
						|
								        return ''
							 | 
						|
								
							 |