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.
		
		
		
		
		
			
		
			
				
					
					
						
							229 lines
						
					
					
						
							9.5 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							229 lines
						
					
					
						
							9.5 KiB
						
					
					
				| # -*- coding: utf-8 -*- | |
| ############################################################################### | |
| # | |
| #    Cybrosys Technologies Pvt. Ltd. | |
| # | |
| #    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | |
| #    Author: Arjun S (odoo@cybrosys.com) | |
| # | |
| #    You can modify it under the terms of the GNU AFFERO | |
| #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | |
| # | |
| #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | |
| #    (AGPL v3) along with this program. | |
| #    If not, see <http://www.gnu.org/licenses/>. | |
| # | |
| ############################################################################### | |
| import json | |
| import requests | |
| 
 | |
| from odoo import fields, models, _ | |
| from odoo.exceptions import ValidationError | |
| 
 | |
| 
 | |
| class ResConfigSettings(models.TransientModel): | |
|     """ | |
|     Inherits the model Res Config Settings to extend the model and add extra | |
|     fields and functionalities | |
|     """ | |
|     _inherit = 'res.config.settings' | |
| 
 | |
|     api_key = fields.Char(string='API Key', help='API key to connect', | |
|                           config_parameter='odoo_klaviyo_connector.api_key') | |
|     import_data = fields.Boolean(string="Import List", | |
|                                  help="Whether to import data from Klaviyo", | |
|                                  config_parameter='odoo_klaviyo_connector.import_data') | |
|     export_data = fields.Boolean(string="Export List", | |
|                                  help="Whether to export data to Klaviyo", | |
|                                  config_parameter='odoo_klaviyo_connector.export_data') | |
| 
 | |
|     def action_execute_operation(self): | |
|         """ | |
|         This is the method action_execute_operation which is here used to | |
|         execute the operations as to import and export datas from Klaviyo to | |
|         Odoo and vice versa. | |
|         """ | |
|         imported_records = 0 | |
|         exported_records = 0 | |
|         if self.import_data: | |
|             import_list_data = self.action_test_connection(get_data=True) | |
|             for klaviyo_list in import_list_data.json().get('data'): | |
|                 existing_record = self.env['mailing.list'].search( | |
|                     [('klaviyo_id', '=', klaviyo_list.get('id'))]) | |
|                 if not existing_record: | |
|                     members_response = self.get_klaviyo_members( | |
|                         user_id=klaviyo_list.get('id')) | |
|                     self.create_mailing_list_and_contacts( | |
|                         members_response=members_response, | |
|                         klaviyo_list=klaviyo_list) | |
|                     imported_records += 1 | |
|         if self.export_data: | |
|             headers = { | |
|                 "accept": 'application/json', | |
|                 "revision": '2023-09-15', | |
|                 "content-type": 'application/json', | |
|                 'Authorization': f'Klaviyo-API-Key {self.api_key}', | |
|             } | |
|             lists_to_export = self.env['mailing.list'].search( | |
|                 [('klaviyo_id', '=', False)]) | |
|             for mailing_list in lists_to_export: | |
|                 self.export_mailing_list(mailing_list=mailing_list, | |
|                                          headers=headers) | |
|                 exported_records += 1 | |
|         notification = { | |
|             'type': 'ir.actions.client', | |
|             'tag': 'display_notification', | |
|             'params': { | |
|                 'title': _( | |
|                     'Executed the operation successfully!'), | |
|                 'message': f'Successfully imported {imported_records} Records ' | |
|                            f'and exported {exported_records} Records', | |
|                 'sticky': True, | |
|                 'type': 'success' | |
|             } | |
|         } | |
|         return notification | |
| 
 | |
|     def export_mailing_list(self, mailing_list, headers): | |
|         """ | |
|         This is the method export_mailing_list which is responsible for | |
|         exporting the mailing list to the Klaviyo and also creates the contacts | |
|         in the corresponding mailing list. | |
|         """ | |
|         url = "https://a.klaviyo.com/api/lists/" | |
|         list_response = self.get_list_response( | |
|             mailing_list=mailing_list, url=url, headers=headers) | |
|         if list_response.status_code == 201: | |
|             created_list_id = list_response.json().get('data').get('id') | |
|             mailing_list.klaviyo_id = created_list_id | |
|             for profile in mailing_list.contact_ids: | |
|                 create_profile_url = 'https://a.klaviyo.com/api/profiles/' | |
|                 profile_data = { | |
|                     "data": { | |
|                         "type": "profile", | |
|                         "attributes": { | |
|                             "email": profile.email, | |
|                             "first_name": profile.name | |
|                         } | |
|                     } | |
|                 } | |
|                 response = requests.post(create_profile_url, | |
|                                          json=profile_data, | |
|                                          headers=headers, timeout=10) | |
|                 profile_id = False | |
|                 if response.status_code == 201: | |
|                     profile_id = response.json().get("data").get("id") | |
|                 elif response.status_code == 409: | |
|                     profile_id = response.json().get("errors")[0].get( | |
|                         "meta").get("duplicate_profile_id") | |
|                 add_profile_list_url = f"https://a.klaviyo.com/api/lists/{created_list_id}/relationships/profiles/" | |
|                 profile_data = json.dumps({ | |
|                     "data": [ | |
|                         { | |
|                             "type": "profile", | |
|                             "id": profile_id | |
|                         } | |
|                     ] | |
|                 }) | |
|                 requests.request("POST", add_profile_list_url, | |
|                                  headers=headers, | |
|                                  data=profile_data, timeout=10) | |
| 
 | |
|     def create_mailing_list_and_contacts(self, members_response, klaviyo_list): | |
|         """ | |
|         This is the method create_mailing_list_and_contacts which will create | |
|         the mailing list and contacts in odoo with the data get from the | |
|         Klaviyo API | |
|         """ | |
|         create_mailing_list = self.env['mailing.list'].create({ | |
|             'name': klaviyo_list.get('attributes').get('name'), | |
|             'klaviyo_id': klaviyo_list.get('id'), | |
|         }) | |
|         contacts = [ | |
|             self.env['mailing.contact'].create( | |
|                 {'email': record.get('email'), | |
|                  'klaviyo_id': record.get('id')}).id | |
|             for record in members_response.json().get('records') | |
|         ] | |
|         create_mailing_list.write( | |
|             {'contact_ids': [(6, 0, contacts)]}) | |
| 
 | |
|     def get_klaviyo_members(self, user_id): | |
|         """ | |
|         This is the method get_klaviyo_members which returns the list of members | |
|         in the list of the corresponding Klaviyo List | |
|         """ | |
|         url = f"https://a.klaviyo.com/api/v2/group/{user_id}/members/all?api_key={self.api_key}" | |
|         payload = {} | |
|         headers = { | |
|             'Accept': 'application/json' | |
|         } | |
|         members_response = requests.request("GET", url, | |
|                                             headers=headers, | |
|                                             data=payload, | |
|                                             timeout=10) | |
|         return members_response | |
| 
 | |
|     def get_list_response(self, mailing_list, url, headers): | |
|         """ | |
|         This is the method get_list_response which is here used to return the | |
|         all list in  the Klaviyo using the API | |
|         """ | |
|         payload = { | |
|             'data': { | |
|                 "type": 'list', | |
|                 "attributes": { | |
|                     "name": mailing_list.name | |
|                 }, | |
|             } | |
|         } | |
|         list_response = requests.post(url, json=payload, | |
|                                       headers=headers, | |
|                                       timeout=10) | |
|         return list_response | |
| 
 | |
|     def action_test_connection(self, get_data=False): | |
|         """ | |
|         This is the method action_test_connection which is here used to test | |
|         the connection to Klaviyo from odoo. | |
|         """ | |
|         if self.api_key: | |
|             url = "https://a.klaviyo.com/api/lists" | |
|             payload = {} | |
|             headers = { | |
|                 'revision': '2023-09-15', | |
|                 'Authorization': f'Klaviyo-API-Key {self.api_key}', | |
|                 'Accept': 'application/json' | |
|             } | |
|             response = requests.request("GET", url, headers=headers, | |
|                                         data=payload, timeout=10) | |
|             if get_data: | |
|                 return response | |
|             return self.action_notify( | |
|                 True) if response.status_code == 200 else self.action_notify( | |
|                 False) | |
|         raise ValidationError(_('Please enter the credentials')) | |
| 
 | |
|     def action_notify(self, success): | |
|         """ | |
|         This is the method action_notify which will be called when connection is | |
|         tested to klaviyo from odoo which this function return whether the | |
|         connection is true or false | |
|         """ | |
|         notification = { | |
|             'type': 'ir.actions.client', | |
|             'tag': 'display_notification', | |
|             'params': { | |
|                 'title': _('Connection successful!') if success is True else _( | |
|                     'Connection not successful!'), | |
|                 'message': 'Connection to Klaviyo is successful.' if success is True else 'Connection to Klaviyo is not successful.', | |
|                 'sticky': False, | |
|                 'type': 'success' if success is True else 'danger' | |
|             } | |
|         } | |
|         return notification
 | |
| 
 |