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

# -*- 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