res_company.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. # -*- coding: utf-8 -*-
  2. # Part of Odoo. See LICENSE file for full copyright and licensing details.
  3. from odoo import fields, models, api, _
  4. from odoo.exceptions import UserError
  5. class ResCompany(models.Model):
  6. _inherit = 'res.company'
  7. google_drive_crm_folder_id = fields.Char(
  8. string='Google Drive CRM Folder ID',
  9. help='ID del folder en Google Drive para documentos del CRM'
  10. )
  11. google_drive_crm_folder_name = fields.Char(
  12. string='Google Drive CRM Folder Name',
  13. help='Nombre del folder en Google Drive para documentos del CRM',
  14. readonly=True
  15. )
  16. google_drive_crm_enabled = fields.Boolean(
  17. string='Enable Google Drive CRM Integration',
  18. default=False,
  19. help='Habilitar integración con Google Drive para CRM'
  20. )
  21. google_drive_crm_stage_id = fields.Many2one(
  22. 'crm.stage',
  23. string='CRM Stage for Google Drive Folder Creation',
  24. help='Etapa del CRM en la que se creará automáticamente la carpeta en Google Drive'
  25. )
  26. google_drive_crm_field_id = fields.Many2one(
  27. 'ir.model.fields',
  28. string='Google Drive Field',
  29. domain=[('model', '=', 'crm.lead')],
  30. help='Campo opcional de crm.lead que contiene información de Google Drive'
  31. )
  32. @api.onchange('google_drive_crm_folder_id')
  33. def _onchange_google_drive_crm_folder_id(self):
  34. """Update folder name when folder ID changes"""
  35. if self.google_drive_crm_folder_id:
  36. # TODO: Implement Google Drive API call to get folder name
  37. # For now, just clear the name
  38. self.google_drive_crm_folder_name = False
  39. def action_test_google_drive_connection(self):
  40. """Test Google Drive connection for this company"""
  41. self.ensure_one()
  42. if not self.google_drive_crm_enabled:
  43. raise UserError(_('Google Drive CRM Integration is not enabled for this company'))
  44. if not self.google_drive_crm_folder_id:
  45. raise UserError(_('Please set a Google Drive CRM Folder ID first'))
  46. try:
  47. import requests
  48. import json
  49. # Get Google API credentials from system parameters
  50. google_api_enabled = self.env['ir.config_parameter'].sudo().get_param('google_api.enabled', 'False')
  51. google_api_client_id = self.env['ir.config_parameter'].sudo().get_param('google_api.client_id', '')
  52. google_api_client_secret = self.env['ir.config_parameter'].sudo().get_param('google_api.client_secret', '')
  53. if not google_api_enabled or google_api_enabled == 'False':
  54. raise UserError(_('Google API Integration is not enabled in system settings'))
  55. if not google_api_client_id or not google_api_client_secret:
  56. raise UserError(_('Google API credentials are not configured in system settings'))
  57. # Get manual OAuth token
  58. access_token = self.env['ir.config_parameter'].sudo().get_param('google_api.access_token')
  59. if not access_token:
  60. raise UserError(_('No OAuth token found. Please connect your Google account in Google API settings first.'))
  61. # Validate folder ID format (Google Drive folder IDs are typically 33 characters)
  62. if len(self.google_drive_crm_folder_id) < 10 or len(self.google_drive_crm_folder_id) > 50:
  63. raise UserError(_('Google Drive Folder ID format appears to be invalid (should be 10-50 characters)'))
  64. # Test Google Drive API access with OAuth token
  65. headers = {
  66. 'Authorization': f'Bearer {access_token}',
  67. }
  68. # Test access to the specific folder - try both regular Drive and Shared Drive endpoints
  69. folder_found = False
  70. folder_name = 'Unknown'
  71. # First, try the regular Drive API endpoint
  72. drive_api_url = f"https://www.googleapis.com/drive/v3/files/{self.google_drive_crm_folder_id}"
  73. drive_response = requests.get(drive_api_url, headers=headers, timeout=10)
  74. if drive_response.status_code == 200:
  75. folder_data = drive_response.json()
  76. folder_name = folder_data.get('name', 'Unknown')
  77. folder_found = True
  78. elif drive_response.status_code == 404:
  79. # If not found in regular Drive, try Shared Drive endpoint
  80. shared_drive_api_url = f"https://www.googleapis.com/drive/v3/drives/{self.google_drive_crm_folder_id}"
  81. shared_drive_response = requests.get(shared_drive_api_url, headers=headers, timeout=10)
  82. if shared_drive_response.status_code == 200:
  83. shared_drive_data = shared_drive_response.json()
  84. folder_name = shared_drive_data.get('name', 'Unknown')
  85. folder_found = True
  86. # For shared drives, we also need to check if we can access files within it
  87. 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"
  88. files_response = requests.get(files_in_drive_url, headers=headers, timeout=10)
  89. if files_response.status_code != 200:
  90. raise UserError(_('Access denied to Shared Drive. Please check your permissions in the Shared Drive.'))
  91. elif shared_drive_response.status_code == 403:
  92. raise UserError(_('Access denied to Shared Drive. Please check your permissions in the Shared Drive.'))
  93. elif shared_drive_response.status_code == 404:
  94. raise UserError(_('Google Drive folder not found. Please verify the Folder ID is correct. This could be a regular folder or Shared Drive.'))
  95. else:
  96. raise UserError(_('Shared Drive API test failed. Status: %s') % shared_drive_response.status_code)
  97. elif drive_response.status_code == 403:
  98. raise UserError(_('Access denied to Google Drive folder. Please check folder permissions.'))
  99. elif drive_response.status_code == 401:
  100. raise UserError(_('OAuth token expired or invalid. Please reconnect your Google account in Google API settings.'))
  101. else:
  102. raise UserError(_('Google Drive API test failed. Status: %s') % drive_response.status_code)
  103. if folder_found:
  104. return {
  105. 'type': 'ir.actions.client',
  106. 'tag': 'display_notification',
  107. 'params': {
  108. 'title': _('Success'),
  109. 'message': _('Google Drive connection test successful! Folder "%s" is accessible.') % folder_name,
  110. 'type': 'success',
  111. 'sticky': False,
  112. }
  113. }
  114. except requests.exceptions.Timeout:
  115. raise UserError(_('Connection timeout. Please check your internet connection.'))
  116. except requests.exceptions.ConnectionError:
  117. raise UserError(_('Connection error. Please check your internet connection.'))
  118. except Exception as e:
  119. raise UserError(_('Google Drive connection test failed: %s') % str(e))
  120. def action_open_google_drive_folder(self):
  121. """Open Google Drive folder in browser"""
  122. self.ensure_one()
  123. if not self.google_drive_crm_folder_id:
  124. raise UserError(_('No Google Drive CRM folder configured'))
  125. # For shared drives, the URL format is different
  126. # Try to determine if it's a shared drive by checking the API
  127. try:
  128. import requests
  129. access_token = self.env['ir.config_parameter'].sudo().get_param('google_api.access_token')
  130. if access_token:
  131. headers = {'Authorization': f'Bearer {access_token}'}
  132. # First try regular folder
  133. drive_api_url = f"https://www.googleapis.com/drive/v3/files/{self.google_drive_crm_folder_id}"
  134. drive_response = requests.get(drive_api_url, headers=headers, timeout=5)
  135. if drive_response.status_code == 404:
  136. # Try shared drive
  137. shared_drive_api_url = f"https://www.googleapis.com/drive/v3/drives/{self.google_drive_crm_folder_id}"
  138. shared_drive_response = requests.get(shared_drive_api_url, headers=headers, timeout=5)
  139. if shared_drive_response.status_code == 200:
  140. # It's a shared drive
  141. folder_url = f"https://drive.google.com/drive/u/0/folders/{self.google_drive_crm_folder_id}"
  142. else:
  143. # Regular folder
  144. folder_url = f"https://drive.google.com/drive/folders/{self.google_drive_crm_folder_id}"
  145. else:
  146. # Regular folder
  147. folder_url = f"https://drive.google.com/drive/folders/{self.google_drive_crm_folder_id}"
  148. else:
  149. # Fallback to regular folder URL
  150. folder_url = f"https://drive.google.com/drive/folders/{self.google_drive_crm_folder_id}"
  151. except Exception:
  152. # Fallback to regular folder URL
  153. folder_url = f"https://drive.google.com/drive/folders/{self.google_drive_crm_folder_id}"
  154. return {
  155. 'type': 'ir.actions.act_url',
  156. 'url': folder_url,
  157. 'target': 'new',
  158. }
  159. def action_create_google_drive_folder(self):
  160. """Create a folder in Google Drive using manual OAuth flow"""
  161. self.ensure_one()
  162. if not self.google_drive_crm_enabled:
  163. raise UserError(_('Google Drive CRM Integration is not enabled for this company'))
  164. # Get manual OAuth token
  165. access_token = self.env['ir.config_parameter'].sudo().get_param('google_api.access_token')
  166. if not access_token:
  167. raise UserError(_('No OAuth token found. Please connect your Google account in Google API settings first.'))
  168. try:
  169. import requests
  170. from datetime import datetime
  171. # Test Google Drive API access with OAuth token
  172. headers = {
  173. 'Authorization': f'Bearer {access_token}',
  174. 'Content-Type': 'application/json'
  175. }
  176. # Create folder metadata
  177. folder_name = f"CRM Folder - {self.name} - {datetime.now().strftime('%Y-%m-%d %H:%M')}"
  178. folder_metadata = {
  179. 'name': folder_name,
  180. 'mimeType': 'application/vnd.google-apps.folder'
  181. }
  182. # Add parent folder if specified
  183. if self.google_drive_crm_folder_id:
  184. folder_metadata['parents'] = [self.google_drive_crm_folder_id]
  185. # Create folder - check if parent is a shared drive and adjust accordingly
  186. is_shared_drive = False
  187. # Check if the parent folder is a shared drive
  188. if self.google_drive_crm_folder_id:
  189. # Try to get parent folder info to determine if it's a shared drive
  190. parent_check_url = f"https://www.googleapis.com/drive/v3/files/{self.google_drive_crm_folder_id}"
  191. parent_response = requests.get(parent_check_url, headers=headers, timeout=10)
  192. if parent_response.status_code == 404:
  193. # Parent might be a shared drive, try shared drive endpoint
  194. shared_drive_check_url = f"https://www.googleapis.com/drive/v3/drives/{self.google_drive_crm_folder_id}"
  195. shared_drive_response = requests.get(shared_drive_check_url, headers=headers, timeout=10)
  196. if shared_drive_response.status_code == 200:
  197. is_shared_drive = True
  198. # For shared drives, we need to add specific parameters
  199. folder_metadata['supportsAllDrives'] = True
  200. folder_metadata['includeItemsFromAllDrives'] = True
  201. # Create folder
  202. response = requests.post(
  203. 'https://www.googleapis.com/drive/v3/files',
  204. headers=headers,
  205. json=folder_metadata,
  206. timeout=30
  207. )
  208. if response.status_code == 200:
  209. folder_data = response.json()
  210. return {
  211. 'type': 'ir.actions.client',
  212. 'tag': 'display_notification',
  213. 'params': {
  214. 'title': _('Success'),
  215. 'message': _('Google Drive folder created successfully: %s') % folder_data.get('name'),
  216. 'type': 'success',
  217. 'sticky': False,
  218. }
  219. }
  220. elif response.status_code == 401:
  221. raise UserError(_('OAuth token expired or invalid. Please reconnect your Google account in Google API settings.'))
  222. else:
  223. raise UserError(_('Failed to create Google Drive folder. Status: %s') % response.status_code)
  224. except Exception as e:
  225. raise UserError(_('Failed to create Google Drive folder: %s') % str(e))
  226. def action_list_google_drive_folders(self):
  227. """List folders in Google Drive using manual OAuth flow"""
  228. self.ensure_one()
  229. if not self.google_drive_crm_enabled:
  230. raise UserError(_('Google Drive CRM Integration is not enabled for this company'))
  231. # Get manual OAuth token
  232. access_token = self.env['ir.config_parameter'].sudo().get_param('google_api.access_token')
  233. if not access_token:
  234. raise UserError(_('No OAuth token found. Please connect your Google account in Google API settings first.'))
  235. try:
  236. import requests
  237. headers = {
  238. 'Authorization': f'Bearer {access_token}',
  239. }
  240. # List folders - include both regular folders and shared drives
  241. params = {
  242. 'q': "mimeType='application/vnd.google-apps.folder' and trashed=false",
  243. 'fields': 'files(id,name,webViewLink)',
  244. 'pageSize': 10,
  245. 'supportsAllDrives': 'true',
  246. 'includeItemsFromAllDrives': 'true'
  247. }
  248. response = requests.get(
  249. 'https://www.googleapis.com/drive/v3/files',
  250. headers=headers,
  251. params=params,
  252. timeout=30
  253. )
  254. if response.status_code == 200:
  255. data = response.json()
  256. folders = data.get('files', [])
  257. return {
  258. 'type': 'ir.actions.client',
  259. 'tag': 'display_notification',
  260. 'params': {
  261. 'title': _('Success'),
  262. 'message': _('Found %d folders in Google Drive.') % len(folders),
  263. 'type': 'success',
  264. 'sticky': False,
  265. }
  266. }
  267. elif response.status_code == 401:
  268. raise UserError(_('OAuth token expired or invalid. Please reconnect your Google account in Google API settings.'))
  269. else:
  270. raise UserError(_('Failed to list Google Drive folders. Status: %s') % response.status_code)
  271. except Exception as e:
  272. raise UserError(_('Failed to list Google Drive folders: %s') % str(e))