# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import fields, models, api, _ from odoo.exceptions import UserError class ResCompany(models.Model): _inherit = 'res.company' google_drive_crm_folder_id = fields.Char( string='Google Drive CRM Folder ID', help='ID del folder en Google Drive para documentos del CRM' ) google_drive_crm_folder_name = fields.Char( string='Google Drive CRM Folder Name', help='Nombre del folder en Google Drive para documentos del CRM', readonly=True ) google_drive_crm_enabled = fields.Boolean( string='Enable Google Drive CRM Integration', default=False, help='Habilitar integración con Google Drive para CRM' ) google_drive_crm_stage_id = fields.Many2one( 'crm.stage', string='CRM Stage for Google Drive Folder Creation', help='Etapa del CRM en la que se creará automáticamente la carpeta en Google Drive' ) google_drive_crm_field_id = fields.Many2one( 'ir.model.fields', string='Google Drive Field', domain=[('model', '=', 'crm.lead')], help='Campo opcional de crm.lead que contiene información de Google Drive' ) @api.onchange('google_drive_crm_folder_id') def _onchange_google_drive_crm_folder_id(self): """Update folder name when folder ID changes""" if self.google_drive_crm_folder_id: # TODO: Implement Google Drive API call to get folder name # For now, just clear the name self.google_drive_crm_folder_name = False def action_test_google_drive_connection(self): """Test Google Drive connection for this company""" self.ensure_one() if not self.google_drive_crm_enabled: raise UserError(_('Google Drive CRM Integration is not enabled for this company')) if not self.google_drive_crm_folder_id: raise UserError(_('Please set a Google Drive CRM Folder ID first')) try: import requests import json # Get Google API credentials from system parameters google_api_enabled = self.env['ir.config_parameter'].sudo().get_param('google_api.enabled', 'False') google_api_client_id = self.env['ir.config_parameter'].sudo().get_param('google_api.client_id', '') google_api_client_secret = self.env['ir.config_parameter'].sudo().get_param('google_api.client_secret', '') if not google_api_enabled or google_api_enabled == 'False': raise UserError(_('Google API Integration is not enabled in system settings')) if not google_api_client_id or not google_api_client_secret: raise UserError(_('Google API credentials are not configured in system settings')) # Get manual OAuth token access_token = self.env['ir.config_parameter'].sudo().get_param('google_api.access_token') if not access_token: raise UserError(_('No OAuth token found. Please connect your Google account in Google API settings first.')) # Validate folder ID format (Google Drive folder IDs are typically 33 characters) if len(self.google_drive_crm_folder_id) < 10 or len(self.google_drive_crm_folder_id) > 50: raise UserError(_('Google Drive Folder ID format appears to be invalid (should be 10-50 characters)')) # Test Google Drive API access with OAuth token headers = { 'Authorization': f'Bearer {access_token}', } # Test access to the specific folder - try both regular Drive and Shared Drive endpoints folder_found = False folder_name = 'Unknown' # First, try the regular Drive API endpoint drive_api_url = f"https://www.googleapis.com/drive/v3/files/{self.google_drive_crm_folder_id}" drive_response = requests.get(drive_api_url, headers=headers, timeout=10) if drive_response.status_code == 200: folder_data = drive_response.json() folder_name = folder_data.get('name', 'Unknown') folder_found = True elif drive_response.status_code == 404: # If not found in regular Drive, try Shared Drive endpoint shared_drive_api_url = f"https://www.googleapis.com/drive/v3/drives/{self.google_drive_crm_folder_id}" shared_drive_response = requests.get(shared_drive_api_url, headers=headers, timeout=10) if shared_drive_response.status_code == 200: shared_drive_data = shared_drive_response.json() folder_name = shared_drive_data.get('name', 'Unknown') folder_found = True # For shared drives, we also need to check if we can access files within it files_in_drive_url = f"https://www.googleapis.com/drive/v3/files?supportsAllDrives=true&includeItemsFromAllDrives=true&corpora=drive&driveId={self.google_drive_crm_folder_id}&pageSize=1" files_response = requests.get(files_in_drive_url, headers=headers, timeout=10) if files_response.status_code != 200: raise UserError(_('Access denied to Shared Drive. Please check your permissions in the Shared Drive.')) elif shared_drive_response.status_code == 403: raise UserError(_('Access denied to Shared Drive. Please check your permissions in the Shared Drive.')) elif shared_drive_response.status_code == 404: raise UserError(_('Google Drive folder not found. Please verify the Folder ID is correct. This could be a regular folder or Shared Drive.')) else: raise UserError(_('Shared Drive API test failed. Status: %s') % shared_drive_response.status_code) elif drive_response.status_code == 403: raise UserError(_('Access denied to Google Drive folder. Please check folder permissions.')) elif drive_response.status_code == 401: raise UserError(_('OAuth token expired or invalid. Please reconnect your Google account in Google API settings.')) else: raise UserError(_('Google Drive API test failed. Status: %s') % drive_response.status_code) if folder_found: return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': { 'title': _('Success'), 'message': _('Google Drive connection test successful! Folder "%s" is accessible.') % folder_name, 'type': 'success', 'sticky': False, } } except requests.exceptions.Timeout: raise UserError(_('Connection timeout. Please check your internet connection.')) except requests.exceptions.ConnectionError: raise UserError(_('Connection error. Please check your internet connection.')) except Exception as e: raise UserError(_('Google Drive connection test failed: %s') % str(e)) def action_open_google_drive_folder(self): """Open Google Drive folder in browser""" self.ensure_one() if not self.google_drive_crm_folder_id: raise UserError(_('No Google Drive CRM folder configured')) # For shared drives, the URL format is different # Try to determine if it's a shared drive by checking the API try: import requests access_token = self.env['ir.config_parameter'].sudo().get_param('google_api.access_token') if access_token: headers = {'Authorization': f'Bearer {access_token}'} # First try regular folder drive_api_url = f"https://www.googleapis.com/drive/v3/files/{self.google_drive_crm_folder_id}" drive_response = requests.get(drive_api_url, headers=headers, timeout=5) if drive_response.status_code == 404: # Try shared drive shared_drive_api_url = f"https://www.googleapis.com/drive/v3/drives/{self.google_drive_crm_folder_id}" shared_drive_response = requests.get(shared_drive_api_url, headers=headers, timeout=5) if shared_drive_response.status_code == 200: # It's a shared drive folder_url = f"https://drive.google.com/drive/u/0/folders/{self.google_drive_crm_folder_id}" else: # Regular folder folder_url = f"https://drive.google.com/drive/folders/{self.google_drive_crm_folder_id}" else: # Regular folder folder_url = f"https://drive.google.com/drive/folders/{self.google_drive_crm_folder_id}" else: # Fallback to regular folder URL folder_url = f"https://drive.google.com/drive/folders/{self.google_drive_crm_folder_id}" except Exception: # Fallback to regular folder URL folder_url = f"https://drive.google.com/drive/folders/{self.google_drive_crm_folder_id}" return { 'type': 'ir.actions.act_url', 'url': folder_url, 'target': 'new', } def action_create_google_drive_folder(self): """Create a folder in Google Drive using manual OAuth flow""" self.ensure_one() if not self.google_drive_crm_enabled: raise UserError(_('Google Drive CRM Integration is not enabled for this company')) # Get manual OAuth token access_token = self.env['ir.config_parameter'].sudo().get_param('google_api.access_token') if not access_token: raise UserError(_('No OAuth token found. Please connect your Google account in Google API settings first.')) try: import requests from datetime import datetime # Test Google Drive API access with OAuth token headers = { 'Authorization': f'Bearer {access_token}', 'Content-Type': 'application/json' } # Create folder metadata folder_name = f"CRM Folder - {self.name} - {datetime.now().strftime('%Y-%m-%d %H:%M')}" folder_metadata = { 'name': folder_name, 'mimeType': 'application/vnd.google-apps.folder' } # Add parent folder if specified if self.google_drive_crm_folder_id: folder_metadata['parents'] = [self.google_drive_crm_folder_id] # Create folder - check if parent is a shared drive and adjust accordingly is_shared_drive = False # Check if the parent folder is a shared drive if self.google_drive_crm_folder_id: # Try to get parent folder info to determine if it's a shared drive parent_check_url = f"https://www.googleapis.com/drive/v3/files/{self.google_drive_crm_folder_id}" parent_response = requests.get(parent_check_url, headers=headers, timeout=10) if parent_response.status_code == 404: # Parent might be a shared drive, try shared drive endpoint shared_drive_check_url = f"https://www.googleapis.com/drive/v3/drives/{self.google_drive_crm_folder_id}" shared_drive_response = requests.get(shared_drive_check_url, headers=headers, timeout=10) if shared_drive_response.status_code == 200: is_shared_drive = True # For shared drives, we need to add specific parameters folder_metadata['supportsAllDrives'] = True folder_metadata['includeItemsFromAllDrives'] = True # Create folder response = requests.post( 'https://www.googleapis.com/drive/v3/files', headers=headers, json=folder_metadata, timeout=30 ) if response.status_code == 200: folder_data = response.json() return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': { 'title': _('Success'), 'message': _('Google Drive folder created successfully: %s') % folder_data.get('name'), 'type': 'success', 'sticky': False, } } elif response.status_code == 401: raise UserError(_('OAuth token expired or invalid. Please reconnect your Google account in Google API settings.')) else: raise UserError(_('Failed to create Google Drive folder. Status: %s') % response.status_code) except Exception as e: raise UserError(_('Failed to create Google Drive folder: %s') % str(e)) def action_list_google_drive_folders(self): """List folders in Google Drive using manual OAuth flow""" self.ensure_one() if not self.google_drive_crm_enabled: raise UserError(_('Google Drive CRM Integration is not enabled for this company')) # Get manual OAuth token access_token = self.env['ir.config_parameter'].sudo().get_param('google_api.access_token') if not access_token: raise UserError(_('No OAuth token found. Please connect your Google account in Google API settings first.')) try: import requests headers = { 'Authorization': f'Bearer {access_token}', } # List folders - include both regular folders and shared drives params = { 'q': "mimeType='application/vnd.google-apps.folder' and trashed=false", 'fields': 'files(id,name,webViewLink)', 'pageSize': 10, 'supportsAllDrives': 'true', 'includeItemsFromAllDrives': 'true' } response = requests.get( 'https://www.googleapis.com/drive/v3/files', headers=headers, params=params, timeout=30 ) if response.status_code == 200: data = response.json() folders = data.get('files', []) return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': { 'title': _('Success'), 'message': _('Found %d folders in Google Drive.') % len(folders), 'type': 'success', 'sticky': False, } } elif response.status_code == 401: raise UserError(_('OAuth token expired or invalid. Please reconnect your Google account in Google API settings.')) else: raise UserError(_('Failed to list Google Drive folders. Status: %s') % response.status_code) except Exception as e: raise UserError(_('Failed to list Google Drive folders: %s') % str(e))