diff --git a/hubspot_odoo_connector/README.rst b/hubspot_odoo_connector/README.rst new file mode 100644 index 000000000..9e3d7dfa9 --- /dev/null +++ b/hubspot_odoo_connector/README.rst @@ -0,0 +1,49 @@ +.. image:: https://img.shields.io/badge/license-LGPL--3-green.svg + :target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 + +HubSpot Odoo Connector +====================== +HubSpot Odoo Connector Module for Odoo 15. + +Installation +============ +- www.odoo.com/documentation/15.0/setup/install.html +- pip install hubspot-api-client + +License +------- +General Public License, Version 3 (LGPL v3). +(https://www.gnu.org/licenses/lgpl-3.0-standalone.html) + +Company +------- +* `Cybrosys Techno Solutions `__ + +Credits +------- +* Developers: (V16) Vishnuraj P + (V15) Neethu U M , Jumana Jabin MP +* Contact: odoo@cybrosys.com + +Contacts +-------- +* Mail Contact : odoo@cybrosys.com +* Website : https://cybrosys.com + +Bug Tracker +----------- +Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. + +Maintainer +========== +.. image:: https://cybrosys.com/images/logo.png + :target: https://cybrosys.com + +This module is maintained by Cybrosys Technologies. + +For support and more information, please visit https://www.cybrosys.com + +Further information +=================== +HTML Description: ``__ diff --git a/hubspot_odoo_connector/__init__.py b/hubspot_odoo_connector/__init__.py new file mode 100644 index 000000000..97f4c673b --- /dev/null +++ b/hubspot_odoo_connector/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Jumana Jabin MP (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 . +# +############################################################################# +from . import models diff --git a/hubspot_odoo_connector/__manifest__.py b/hubspot_odoo_connector/__manifest__.py new file mode 100644 index 000000000..468a8926f --- /dev/null +++ b/hubspot_odoo_connector/__manifest__.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Jumana Jabin MP (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 . +# +############################################################################# +{ + 'name': 'HubSpot Odoo Connector', + 'version': '15.0.1.0.0', + 'summary': 'This module integrate Hubspot with odoo', + 'description': """ This module integrates HubSpot with Odoo to sync + contacts, companies, and deals. It allows seamless integration between + HubSpot and Odoo, enabling the synchronization of important data such as + contacts, companies, and deals between the two systems. With this connector, + you can ensure that your customer data remains consistent and up-to-date in + both HubSpot and Odoo, streamlining your sales and marketing processes.""", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'depends': ['base', 'crm', 'project'], + 'data': [ + 'security/hubspot_odoo_connector_groups.xml', + 'security/ir.model.access.csv', + 'views/hubspot_connector_views.xml', + 'views/hubspot_sync_history_views.xml', + 'views/res_partner_views.xml', + 'views/res_company_views.xml', + 'views/crm_lead_views.xml', + ], + "external_dependencies": { + 'python': ['hubspot-api-client'] + }, + 'images': [ + 'static/description/banner.png', + ], + 'license': 'LGPL-3', + 'installable': True, + 'auto_install': False, + 'application': True, +} diff --git a/hubspot_odoo_connector/doc/RELEASE_NOTES.md b/hubspot_odoo_connector/doc/RELEASE_NOTES.md new file mode 100644 index 000000000..53605794f --- /dev/null +++ b/hubspot_odoo_connector/doc/RELEASE_NOTES.md @@ -0,0 +1,6 @@ +## Module + +#### 09.02.2024 +#### Version 15.0.1.0.0 +#### ADD +- Initial commit for HubSpot Odoo Connector diff --git a/hubspot_odoo_connector/models/__init__.py b/hubspot_odoo_connector/models/__init__.py new file mode 100644 index 000000000..53fe82dd1 --- /dev/null +++ b/hubspot_odoo_connector/models/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Vishnuraj P (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 . +# +############################################################################# +from . import crm_lead +from . import hubspot_connector +from . import hubspot_sync_history +from . import res_company +from . import res_partner diff --git a/hubspot_odoo_connector/models/crm_lead.py b/hubspot_odoo_connector/models/crm_lead.py new file mode 100644 index 000000000..7c4168b00 --- /dev/null +++ b/hubspot_odoo_connector/models/crm_lead.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Vishnuraj P (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 . +# +############################################################################# +from odoo import fields, models + + +class CrmLead(models.Model): + """ Model to add sync info to CrmLead model """ + _inherit = 'crm.lead' + + hs_object_id = fields.Char(string="Hubspot ID", + help="Hubspot ID associated with this record.") + sync_mode = fields.Selection( + selection=[('import', 'HS Imported'), ('export', 'HS Exported')], + string='Sync Mode', help="Sync mode for the record.") diff --git a/hubspot_odoo_connector/models/hubspot_connector.py b/hubspot_odoo_connector/models/hubspot_connector.py new file mode 100644 index 000000000..a9f3a9be2 --- /dev/null +++ b/hubspot_odoo_connector/models/hubspot_connector.py @@ -0,0 +1,1000 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Vishnuraj P (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 . +# +############################################################################# +import base64 +from datetime import datetime, timezone +from hubspot import HubSpot +from hubspot.crm.deals import BatchInputSimplePublicObjectBatchInput +from hubspot.crm.deals import SimplePublicObjectInput +import requests +from odoo import fields, models, _ +from odoo.exceptions import AccessError + + +class HubspotConnector(models.Model): + """ + Model for hubspot connector to set up the credentials and contains + methods for various sync operations. + Methods: + action_connect(self): + CONNECT smart button action to check the hubspot account with + provided credentials, if account exist it connects, and shows the + sync options. + action_contact_sync(self): + Button action for sync contacts based on user preference. + action_company_sync(self): + Button action for sync company based on user preference. + action_deal_sync(self): + Button action for sync deals based on user preference. + #--- Contacts Various Sync Methods ---# + action_export_partner(self): + Method for exporting contacts when the contact is not available in + hubspot. + action_import_partner(self): + Method for importing contacts when the contact is not available in + odoo. + action_update_hub_partner(self): + Method for update contacts in hubspot, based on odoo contacts, + action_update_odoo_partner(self): + Method for update contacts in odoo, based on hubspot contacts, + #--- Various Sync Methods for Company ---# + action_export_company(self): + Method for exporting company when the company is not available in + hubspot. + action_import_company(self): + Method for importing company when the company is not available in + odoo. + action_update_hub_company(self): + Method for update company in hubspot, based on odoo company. + action_update_odoo_company(self): + Method for update company in odoo, based on hubspot company. + #--- Various Sync Methods for Deals ---# + action_export_deals(self): + Method for exporting deals when the deals are not available in + hubspot. + action_import_deals(self): + Method for importing deals when the deals are not available in + odoo. + action_update_hub_deals(self): + Method for update deals in hubspot, based on odoo deals. + action_update_odoo_deals(self): + Method for update deals in odoo, based on hubspot deals. + """ + _name = 'hubspot.connector' + _description = 'HubSpot Connector' + + state = fields.Selection(string="State", + selection=[("disconnected", "Disconnected"), + ("connected", "Connected")], + default="disconnected", + help="Shows the connection is true or false") + name = fields.Char(string="Connector Name", help="name of the instance") + access_key = fields.Char(string="Access Token", + help="Private app key of hubspot account") + owner_id = fields.Char(string="Owner ID", required=True, + help="Owner ID of Hubspot account") + connection = fields.Boolean(string="Connection", + help="Shows connected to hubspot or nor") + # Toggles for Contacts sync + import_contacts = fields.Boolean(string="Import Contacts", + help="This will enable import of contact " + "from hubspot to odoo") + export_contacts = fields.Boolean(string="Export Contacts", + help="This will enable export of contact " + "from odoo to hubspot") + update_odoo_contacts = fields.Boolean(string="Update Odoo Contacts", + help="This will update contact in " + "odoo from hubspot data") + update_hub_contacts = fields.Boolean(string="Update Hubspot Contacts", + help="This will update contact in " + "hubspot from odoo data") + # Toggles for Company sync + import_company = fields.Boolean(string="Import Company", + help="This will enable import of companies" + "from hubspot to odoo") + export_company = fields.Boolean(string="Export Company", + help="This will enable export of companies " + "from Odoo to HubSpot") + update_odoo_company = fields.Boolean(string="Update Odoo Company", + help="This will update company in odoo" + "from hubspot data") + update_hub_company = fields.Boolean(string="Update Hubspot Company", + help="This will update company in " + "hubspot from odoo data") + # Toggles for Deals sync + export_deals = fields.Boolean( + string="Export Deals", + help="This will enable export of deals from odoo to hubspot") + import_deals = fields.Boolean( + string="Import Deals", + help="This will enable import of deals from hubspot to odoo") + update_odoo_deals = fields.Boolean( + string="Update Odoo Deals", + help="This will update deals in odoo from hubspot data") + update_hub_deals = fields.Boolean( + string="Update Hubspot Deals", + help="This will update deals in hubspot from odoo data") + # Contacts last sync Times + contacts_last_imported = fields.Datetime( + string="Contact Last Imported", readonly=True, + help="This is the last imported time") + contacts_last_exported = fields.Datetime( + string="Contact Last Exported", readonly=True, + help="This is the last exported time") + hub_contact_last_updated = fields.Datetime( + string="Hubspot Contacts Updated", readonly=True, + help="Last Hubspot Contacts Updated Time") + odoo_contact_last_updated = fields.Datetime( + string="Odoo Contacts Updated", readonly=True, + help="Last Odoo Contacts Updated Time") + # Company last sync Times + company_last_imported = fields.Datetime( + string="Company Last Imported", readonly=True, + help="This is the last imported time") + company_last_exported = fields.Datetime( + string="Company Last Exported", readonly=True, + help="This is the last exported time") + hub_company_last_updated = fields.Datetime( + string="Hubspot Company Updated", readonly=True, + help="Last Hubspot Company Updated Time") + odoo_company_last_updated = fields.Datetime( + string="Odoo Company Updated", readonly=True, + help="Last Odoo Company Updated Time") + # Deals last sync Times + deals_last_imported = fields.Datetime( + string="Deals Last Imported", readonly=True, + help="This is the last imported time") + deals_last_exported = fields.Datetime( + string="Deals Last Exported", readonly=True, + help="This is the last exported time") + hub_deal_last_updated = fields.Datetime( + string="Hubspot Deal Updated", readonly=True, + help="Last Hubspot Deal Updated Time") + odoo_deal_last_updated = fields.Datetime( + string="Odoo Deal Updated", readonly=True, + help="Last Odoo Deal Updated Time") + + def action_connect(self): + """ + Method for testing connection; if credentials are correct connects + and shows sync options, if connected disconnects. + """ + if not self.connection: + owners_endpoint = 'https://api.hubapi.com/owners/v2/owners' + headers = {'Authorization': f'Bearer {self.access_key}'} + try: + response = requests.get(owners_endpoint, headers=headers) + if response.status_code == 200: + data = response.json() + if str(data[0]['ownerId']) == self.owner_id: + self.connection = True + self.state = "connected" + else: + raise AccessError(_("Error when Fetching account info")) + except requests.exceptions.RequestException: + return None + else: + self.connection = False + self.state = "disconnected" + + def action_contact_sync(self): + """ + Method used to sync contacts it calls methods for import, export and + update contacts methods when user need specific condition on sync + """ + rainbow_msg = "Congrats, " + if self.export_contacts: + exported_count = self.action_export_partner() + if exported_count > 0: + rainbow_msg += f"# {exported_count} Contacts Exported" + if self.import_contacts: + imported_count = self.action_import_partner() + if imported_count > 0: + rainbow_msg += f", # {imported_count} Contacts Imported" + if self.update_hub_contacts: + hub_update_count = self.action_update_hub_partner() + if hub_update_count > 0: + rainbow_msg += f", #{hub_update_count} Hubspot Contacts Updated" + if self.update_odoo_contacts: + odoo_update_count = self.action_update_odoo_partner() + if odoo_update_count > 0: + rainbow_msg += f", # {odoo_update_count} Odoo Contacts Updated" + # If there is no sync option modifies data + if rainbow_msg == "Congrats, ": + rainbow_msg += "Contacts are already synced" + # Rainbow man displays status of sync + return { + 'effect': { + 'fadeout': 'slow', + 'message': rainbow_msg, + 'type': 'rainbow_man' + } + } + + def action_company_sync(self): + """ + Method used to sync company it calls methods for import, export and + update company methods when user need specific condition on sync + """ + rainbow_msg = "Congrats, " + if self.export_company: + exported_count = self.action_export_company() + if exported_count > 0: + rainbow_msg += f"# {exported_count} Companies Exported" + if self.import_company: + imported_count = self.action_import_company() + if imported_count > 0: + rainbow_msg += f", # {imported_count} Companies Imported" + if self.update_hub_company: + hub_update_count = self.action_update_hub_company() + if hub_update_count > 0: + rainbow_msg += (f", # {hub_update_count}" + f" Hubspot Companies Updated") + if self.update_odoo_company: + odoo_update_count = self.action_update_odoo_company() + if odoo_update_count > 0: + rainbow_msg += f", # {odoo_update_count} Odoo Companies Updated" + if rainbow_msg == "Congrats, ": + rainbow_msg += "Companies are already synced" + return { + 'effect': { + 'fadeout': 'slow', + 'message': rainbow_msg, + 'type': 'rainbow_man' + } + } + + def action_deal_sync(self): + """ + Method used to sync deals, it calls methods for import, export and + update deals methods when user need specific condition on sync + """ + rainbow_msg = "Congrats, " + if self.export_deals: + exported_count = self.action_export_deals() + if exported_count > 0: + rainbow_msg += f"# {exported_count} Deals Exported" + if self.import_deals: + imported_count = self.action_import_deals() + if imported_count > 0: + rainbow_msg += f", # {imported_count} Deals Imported" + if self.update_hub_deals: + hub_update_count = self.action_update_hub_deals() + if hub_update_count > 0: + rainbow_msg += f", # {hub_update_count} Hubspot Deals Updated" + if self.update_odoo_deals: + odoo_update_count = self.action_update_odoo_deals() + if odoo_update_count > 0: + rainbow_msg += f", # {odoo_update_count} Odoo Deals Updated" + if rainbow_msg == "Congrats, ": + rainbow_msg += "Deals are already synced" + return { + 'effect': { + 'fadeout': 'slow', + 'message': rainbow_msg, + 'type': 'rainbow_man' + } + } + + def action_export_partner(self): + """ + Method used to Export Contacts from Odoo to Hubspot, also creates + non-existing odoo_mail and odoo_image_string fields which are not + present in hubspot and export according data to it. + """ + # Set up HubSpot API connection. + api_key = self.access_key + base_url = 'https://api.hubapi.com' + # Lists fields and their properties need to create in hubspot. + partner_fields = [ + { + 'name': 'odoo_mail', + 'label': 'Mail', + 'type': 'string' + }, + { + 'name': 'odoo_image_string', + 'label': 'Image String', + 'type': 'string' + }, + ] + for field in partner_fields: + # Check each field in partner_fields exists in HubSpot or not + endpoint = f"/properties/v1/contacts/properties/named/" \ + f"{field['name']}" + headers = { + 'Content-Type': 'application/json', + 'Authorization': f'Bearer {api_key}' + } + response = requests.get(base_url + endpoint, headers=headers) + # Response returns a status code "200" when field exist in hubspot. + if response.status_code != 200: + # Create custom field in HubSpot + endpoint = '/properties/v1/contacts/properties' + headers = { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer {}'.format(api_key) + } + # Properties of Field ie, going to create + payload = { + 'name': field['name'], + 'label': field['label'], + 'description': 'Custom field created form odoo', + 'groupName': 'contactinformation', + 'type': field['type'] + } + # API call for Field creation + response = requests.post(base_url + endpoint, json=payload, + headers=headers) + # Returns status code "200" when successfully created the field + if response.status_code == 200: + pass # Notification : Successfully connected. + else: + raise AccessError(f"Failed to create {field['name']} field," + f"Status code: {response.status_code}") + # Setting api client connection via api + api_client = HubSpot(access_token=self.access_key) + odoo_partners = self.env['res.partner'].search([]) + success_count = 0 + # Fetch HubSpot contact's ID as list + hubspot_partners = [rec.properties['hs_object_id'] + for rec in api_client.crm.contacts.get_all()] + for rec in odoo_partners: + # If the Odoo contact not present in Hubspot ID list export it + if rec.hs_object_id not in hubspot_partners: + properties = { + "firstname": rec.name, + "lastname": "", + "odoo_mail": rec.email, + "phone": rec.phone if rec.phone else None, + "company": rec.commercial_company_name or rec.company_name + if rec.commercial_company_name or rec.company_name + else None, + "jobtitle": rec.function if rec.function else None, + "website": rec.website if rec.website else None, + "address": rec.street + "," + rec.street2 if ( + rec.street and rec.street2) else ( + rec.street or rec.street2 or ""), + "city": rec.city if rec.city else None, + "state": rec.state_id.name if rec.state_id else None, + "zip": rec.zip if rec.zip else None, + "country": rec.country_id.name if rec.country_id else None, + "odoo_image_string": base64.b64encode(rec.image_1920). + decode('utf-8') if (rec.image_1920 and len(base64.b64encode( + rec.image_1920).decode('utf-8')) < 65500) else None, + } + api_response = api_client.crm.contacts.basic_api.create( + simple_public_object_input_for_create= + SimplePublicObjectInput(properties)) + # If Exported then update Hubspot ID in Odoo + if api_response: + rec.write({ + 'hs_object_id': api_response.properties['hs_object_id'], + 'sync_mode': 'export'}) + else: + # change it to Failure msg. + pass + success_count += 1 + # If Any record exported Create Sync History + if success_count > 0: + self.env['hubspot.sync.history'].sudo().create({ + 'date': datetime.now(), + 'res_model_id': self.env.ref('base.model_res_partner').id, + 'sync_mode': 'export', + 'state': 'success', + 'count': success_count, + }) + self.contacts_last_exported = datetime.now() + # Returns Exported Count + return success_count + + def action_import_partner(self): + """ + Method used fetch data from Hubspot and creates contacts based on it. + """ + # Fields needs to fetch from hubspot. + needed_fields = [ + "firstname", "lastname", "email", "phone", "company", "jobtitle", + "website", "address", "city", "state", "zip", "country", + "odoo_mail", "odoo_image_string", "hs_object_id" + ] + api_client = HubSpot(access_token=self.access_key) + odoo_partners = self.env['res.partner'].search([]).mapped( + 'hs_object_id') + # Getting needed fields from hubspot + hubspot_partners = api_client.crm.contacts.get_all( + properties=needed_fields) + partners_to_create = [] + success_count = 0 + # Creates Dictionaries from country and state model to fetch + # state_id and country_id + state_dict = {state['name']: state['id'] for state in self.env[ + 'res.country.state'].search_read([], ['name'])} + country_dict = {country['name']: country['id'] for country in self.env[ + 'res.country'].search_read([], ['name'])} + for rec in hubspot_partners: + # If hubspot record not present in odoo records creates it. + if rec.properties['hs_object_id'] not in odoo_partners: + partners_to_create.append({ + 'name': rec.properties['firstname'] + '' + rec.properties[ + 'lastname'] if rec.properties[ + 'lastname'] else rec.properties['firstname'], + 'email': rec.properties['email'] if rec.properties[ + 'email'] else rec.properties[ + 'odoo_mail'] if rec.properties['odoo_mail'] else None, + 'phone': rec.properties['phone'], + 'function': rec.properties['jobtitle'], + 'website': rec.properties['website'], + 'street': rec.properties['address'], + 'city': rec.properties['city'], + 'zip': rec.properties['zip'], + 'state_id': state_dict.get(str(rec.properties['state']), + None), + 'country_id': country_dict.get( + str(rec.properties['country']), None), + 'image_1920': base64.b64decode( + rec.properties['odoo_image_string']) if rec.properties[ + 'odoo_image_string'] else None, + 'hs_object_id': rec.properties['hs_object_id'], + 'sync_mode': 'import' + }) + # counting total records created + success_count += 1 + if partners_to_create: + self.env['res.partner'].sudo().create(partners_to_create) + # If new record created, then creates sync history. + if success_count > 0: + self.env['hubspot.sync.history'].sudo().create({ + 'date': datetime.now(), + 'res_model_id': self.env.ref('base.model_res_partner').id, + 'sync_mode': 'import', + 'state': 'success', + 'count': success_count, + }) + self.contacts_last_imported = datetime.now() + return success_count + + def action_update_hub_partner(self): + """ Method used to update hubspot contacts based on odoo contacts. """ + api_client = HubSpot(access_token=self.access_key) + odoo_partners = self.env['res.partner'].search([]) + odoo_partners_list = odoo_partners.mapped('hs_object_id') + hubspot_partners = api_client.crm.contacts.get_all() + update_success = 0 + data_to_update = [] + for rec in hubspot_partners: + # Checking the hubspot contact present in odoo + # then take the corresponding odoo record + if rec.properties['hs_object_id'] in odoo_partners_list: + odoo_record = self.env['res.partner'].search( + [('hs_object_id', '=', rec.properties['hs_object_id'])]) + # If the corresponding odoo record is last updated then + # update hubspot record based on that + if odoo_record.write_date > ( + self.hub_contact_last_updated or rec.updated_at. + astimezone(timezone.utc).replace(tzinfo=None)): + data_to_update.append({ + 'id': rec.properties['hs_object_id'], + 'properties': { + "firstname": odoo_record.name, + "lastname": "", + "odoo_mail": odoo_record.email, + "phone": odoo_record.phone, + "company": odoo_record.commercial_company_name + or odoo_record.company_name, + "jobtitle": odoo_record.function, + "website": odoo_record.website, + "address": odoo_record.street + "," + + odoo_record.street2 if ( + odoo_record.street and odoo_record.street2) + else (odoo_record.street + or odoo_record.street2 or ""), + "city": odoo_record.city if odoo_record.city + else None, + "state": odoo_record.state_id.name + if odoo_record.state_id else None, + "zip": odoo_record.zip if odoo_record.zip else None, + "country": odoo_record.country_id.name + if odoo_record.country_id else None, + "odoo_image_string": base64.b64encode( + odoo_record.image_1920).decode('utf-8') if ( + odoo_record.image_1920 and len( + base64.b64encode( + odoo_record.image_1920).decode( + 'utf-8')) < 65500) else "", + } + }) + update_success += 1 + # Batch Update of record to hubspot. + api_client.crm.contacts.batch_api.update( + batch_input_simple_public_object_batch_input= + BatchInputSimplePublicObjectBatchInput(data_to_update)) + self.hub_contact_last_updated = datetime.now() + if update_success > 0: + self.env['hubspot.sync.history'].sudo().create({ + 'date': self.hub_contact_last_updated, + 'res_model_id': self.env.ref('base.model_res_partner').id, + 'sync_mode': 'hub_updated', + 'state': 'success', + 'count': update_success, + }) + # Returns successfully updated count. + return update_success + + def action_update_odoo_partner(self): + """Method used to update odoo partner based on the hubspot contacts.""" + api_client = HubSpot(access_token=self.access_key) + odoo_partners = self.env['res.partner'].search([]) + # Fields need to fetch from hubspot. + needed_fields = [ + "firstname", "lastname", "email", "phone", "company", "jobtitle", + "website", "address", "city", "state", "zip", "country", + "odoo_mail", "odoo_image_string", "hs_object_id" + ] + hubspot_partners = api_client.crm.contacts.get_all( + properties=needed_fields) + hubspot_partners_list = [rec.properties['hs_object_id'] + for rec in hubspot_partners] + update_success = 0 + # Creates Dictionaries from country and state model to fetch + # state_id and country_id + state_dict = {state['name']: state['id'] for state in self.env[ + 'res.country.state'].search_read([], ['name'])} + country_dict = {country['name']: country['id'] for country in self.env[ + 'res.country'].search_read([], ['name'])} + for rec in odoo_partners: + # If odoo record present in hubspot record then teke + # corresponding hubspot record + if rec.hs_object_id in hubspot_partners_list: + hubspot_partner = {h.id: h for h in hubspot_partners} + hub_record = hubspot_partner.get(rec.hs_object_id, None) + # If hubspot record is recently updated, then update + # odoo record based on that + if hub_record.updated_at.astimezone(timezone.utc).replace( + tzinfo=None) > ( + self.odoo_contact_last_updated or rec.write_date): + data_to_update = { + 'name': hub_record.properties[ + 'firstname'] + '' + hub_record.properties[ + 'lastname'] if hub_record.properties[ + 'lastname'] else hub_record.properties['firstname'], + 'email': hub_record.properties[ + 'email'] if hub_record.properties[ + 'email'] else hub_record.properties[ + 'odoo_mail'] if hub_record.properties[ + 'odoo_mail'] else None, + + 'phone': hub_record.properties['phone'], + 'function': hub_record.properties['jobtitle'], + 'website': hub_record.properties['website'], + 'street': hub_record.properties['address'], + 'city': hub_record.properties['city'], + 'zip': hub_record.properties['zip'], + 'state_id': state_dict.get(str(hub_record.properties[ + 'state']), None), + 'country_id': country_dict.get( + str(hub_record.properties['country']), None), + + 'image_1920': base64.b64decode( + hub_record.properties[ + 'odoo_image_string']) if hub_record.properties[ + 'odoo_image_string'] else None, + } + update_success += 1 + rec.write(data_to_update) + self.odoo_contact_last_updated = datetime.now() + # If there is any contact updated then creates sync history. + if update_success > 0: + self.env['hubspot.sync.history'].sudo().create({ + 'date': self.odoo_contact_last_updated, + 'res_model_id': self.env.ref('base.model_res_partner').id, + 'sync_mode': 'odoo_updated', + 'state': 'success', + 'count': update_success, + }) + # Returns updated record's count. + return update_success + + def action_export_company(self): + """ Method to export companies to hubspot. """ + api_client = HubSpot(access_token=self.access_key) + odoo_companies = self.env['res.company'].search([]) + hubspot_companies = [] + success_count = 0 + for rec in api_client.crm.companies.get_all(): + hubspot_companies.append(rec.properties['hs_object_id']) + for rec in odoo_companies: + # If odoo record not present in hubspot record create it + # via api call + if rec.hs_object_id not in hubspot_companies: + properties = { + "name": rec.name, + "domain": rec.website, + "description": rec.company_details if rec.company_details + else None, + "phone": rec.phone, + "address": rec.street + "," + rec.street2 if ( + rec.street and rec.street2) else ( + rec.street or rec.street2 or ""), + "city": rec.city, + "state": rec.state_id.name if rec.state_id else None, + "zip": rec.zip if rec.zip else None, + "country": rec.country_id.name if rec.country_id else None, + "industry": "", + } + # API call for create company record on hubspot. + api_response = api_client.crm.companies.basic_api.create( + simple_public_object_input_for_create= + SimplePublicObjectInput(properties)) + # After exporting save the unique hubspot id on that record + if api_response: + rec.write({ + 'hs_object_id': api_response.properties['hs_object_id'], + 'sync_mode': 'export' + }) + success_count += 1 + self.company_last_exported = datetime.now() + # If there is any record exported then creates history record. + if success_count > 0: + self.env['hubspot.sync.history'].sudo().create({ + 'date': self.company_last_exported, + 'res_model_id': self.env.ref('base.model_res_company').id, + 'sync_mode': 'export', + 'state': 'success', + 'count': success_count, + }) + # Returns the exported count. + return success_count + + def action_import_company(self): + """ Method to Import record from hubspot """ + api_client = HubSpot(access_token=self.access_key) + odoo_companies = self.env['res.company'].search([]).mapped( + 'hs_object_id') + # The fields need to fetch from hubspot. + needed_fields = [ + "hs_object_id", "name", "domain", "website", "description", "phone", + "city", "state", "country", "zip" + ] + hubspot_companies = api_client.crm.companies.get_all( + properties=needed_fields) + companies_to_create = [] + success_count = 0 + # Creates Dictionaries from country and state model to fetch + # state_id and country_id + state_dict = {state['name']: state['id'] for state in self.env[ + 'res.country.state'].search_read([], ['name'])} + country_dict = {country['name']: country['id'] for country in self.env[ + 'res.country'].search_read([], ['name'])} + for rec in hubspot_companies: + # If hubspot record not present in odoo record, create new record. + if rec.properties['hs_object_id'] not in odoo_companies: + companies_to_create.append({ + 'name': rec.properties['name'], + 'website': rec.properties['domain'], + 'company_details': rec.properties['description'], + 'phone': rec.properties['phone'], + 'city': rec.properties['city'], + 'state_id': state_dict.get(str(rec.properties['state']), + None), + 'country_id': country_dict.get( + str(rec.properties['country']), None), + 'zip': rec.properties['zip'], + 'hs_object_id': rec.properties['hs_object_id'], + 'sync_mode': 'import', + }) + success_count += 1 + if companies_to_create: + self.env['res.company'].sudo().create(companies_to_create) + self.company_last_imported = datetime.now() + # If any new record created then create history record. + if success_count > 0: + self.env['hubspot.sync.history'].sudo().create({ + 'date': self.company_last_imported, + 'res_model_id': self.env.ref('base.model_res_company').id, + 'sync_mode': 'import', + 'state': 'success', + 'count': success_count, + }) + # Returns the created record count. + return success_count + + def action_update_hub_company(self): + """ Method to update hubspot record based on odoo records """ + api_client = HubSpot(access_token=self.access_key) + odoo_company = self.env['res.company'].search([]) + odoo_company_list = odoo_company.mapped('hs_object_id') + hubspot_company = api_client.crm.companies.get_all() + update_success = 0 + data_to_update = [] + for rec in hubspot_company: + # If hubspot record present in odoo record then take + # corresponding odoo record + if rec.properties['hs_object_id'] in odoo_company_list: + odoo_record = self.env['res.company'].search( + [('hs_object_id', '=', rec.properties['hs_object_id'])]) + # If odoo record is recently updated then update hubspot record. + if odoo_record.write_date > ( + self.hub_company_last_updated or rec.updated_at. + astimezone(timezone.utc).replace(tzinfo=None)): + data_to_update.append({ + 'id': rec.properties['hs_object_id'], + 'properties': { + "name": odoo_record.name, + "domain": odoo_record.website, + "description": odoo_record.company_details + if odoo_record.company_details else None, + "phone": odoo_record.phone, + "address": odoo_record.street + "," + + odoo_record.street2 + if (odoo_record.street and odoo_record.street2) + else (odoo_record.street + or odoo_record.street2 or ""), + "city": odoo_record.city, + "state": odoo_record.state_id.name + if odoo_record.state_id else None, + "zip": odoo_record.zip if odoo_record.zip else None, + "country": odoo_record.country_id.name + if odoo_record.country_id else None, + "industry": "", + } + }) + update_success += 1 + api_client.crm.companies.batch_api.update( + batch_input_simple_public_object_batch_input= + BatchInputSimplePublicObjectBatchInput(data_to_update)) + self.hub_company_last_updated = datetime.now() + if update_success > 0: + self.env['hubspot.sync.history'].sudo().create({ + 'date': self.hub_company_last_updated, + 'res_model_id': self.env.ref('base.model_res_company').id, + 'sync_mode': 'hub_updated', + 'state': 'success', + 'count': update_success, + }) + # Returns the updated count. + return update_success + + def action_update_odoo_company(self): + """ Method to update odoo company records based on hubspot record. """ + api_client = HubSpot(access_token=self.access_key) + odoo_company = self.env['res.company'].search([]) + # Needed fields to fetch from hubspot. + needed_fields = [ + "hs_object_id", "name", "domain", "website", "description", "phone", + "city", "state", "country", "zip" + ] + hubspot_company = api_client.crm.companies.get_all( + properties=needed_fields) + hubspot_company_list = [rec.properties['hs_object_id'] + for rec in hubspot_company] + update_success = 0 + # Creates Dictionaries from country and state model to fetch + # state_id and country_id. + state_dict = {state['name']: state['id'] for state in self.env[ + 'res.country.state'].search_read([], ['name'])} + country_dict = {country['name']: country['id'] for country in self.env[ + 'res.country'].search_read([], ['name'])} + for rec in odoo_company: + # If the odoo company record is present in hubspot company, + # take the corresponding hubspot record. + if rec.hs_object_id in hubspot_company_list: + hubspot_company_dict = {h.id: h for h in hubspot_company} + hub_record = hubspot_company_dict.get(rec.hs_object_id, None) + # If the hubspot record is recently modified then update + # odoo record based on that. + if hub_record.updated_at.astimezone(timezone.utc).replace( + tzinfo=None) > rec.write_date: + data_to_update = { + 'name': hub_record.properties['name'], + 'website': hub_record.properties['domain'], + 'company_details': hub_record.properties['description'], + 'phone': hub_record.properties['phone'], + 'city': hub_record.properties['city'], + 'state_id': state_dict.get(str(hub_record.properties[ + 'state']), None), + 'country_id': country_dict.get( + str(hub_record.properties['country']), None), + 'zip': hub_record.properties['zip'], + } + update_success += 1 + rec.write(data_to_update) + self.odoo_company_last_updated = datetime.now() + if update_success > 0: + self.env['hubspot.sync.history'].sudo().create({ + 'date': self.odoo_company_last_updated, + 'res_model_id': self.env.ref('base.model_res_company').id, + 'sync_mode': 'odoo_updated', + 'state': 'success', + 'count': update_success, + }) + # Returns updated count. + return update_success + + def action_export_deals(self): + """ Method for export deals from odoo to hubspot """ + api_client = HubSpot(access_token=self.access_key) + odoo_deals = self.env['crm.lead'].search([]) + hubspot_deals = [] + success_count = 0 + for rec in api_client.crm.deals.get_all(): + hubspot_deals.append(rec.properties['hs_object_id']) + for rec in odoo_deals: + # If the deal present in odoo not available in hubspot + # creates it via api call. + if rec.hs_object_id not in hubspot_deals: + properties = { + "dealname": rec.name, + "amount": rec.expected_revenue if rec.expected_revenue + else None, + "closedate": rec.date_deadline if rec.date_deadline else '', + "createdate": rec.create_date.strftime( + '%Y-%m-%dT%H:%M:%SZ') if rec.create_date else None, + } + # API call to create deals in hubspot. + api_response = api_client.crm.deals.basic_api.create( + simple_public_object_input_for_create= + SimplePublicObjectInput(properties)) + # If the record is created in hubspot then store the unique + # hubspot id in deal record in odoo too. + if api_response: + rec.write({ + 'hs_object_id': api_response.properties['hs_object_id'], + 'sync_mode': 'export' + }) + success_count += 1 + self.deals_last_exported = datetime.now() + # If there is any record exported then creates history record + if success_count > 0: + self.env['hubspot.sync.history'].sudo().create({ + 'date': self.deals_last_exported, + 'res_model_id': self.env.ref('crm.model_crm_lead').id, + 'sync_mode': 'export', + 'state': 'success', + 'count': success_count, + }) + # Returns the exported count. + return success_count + + def action_import_deals(self): + """ Method to import deals record from hubspot to odoo. """ + # Needed fields to fetch from hubspot. + needed_fields = [ + "dealname", "amount", "closedate" + ] + api_client = HubSpot(access_token=self.access_key) + odoo_deals = self.env['crm.lead'].search([]).mapped('hs_object_id') + hubspot_deals = api_client.crm.deals.get_all(properties=needed_fields) + deals_to_create = [] + success_count = 0 + for rec in hubspot_deals: + # If hubspot record not present in odoo creates the record. + if rec.properties['hs_object_id'] not in odoo_deals: + deals_to_create.append({ + 'name': rec.properties['dealname'] or 'Lead', + 'expected_revenue': rec.properties['amount'], + 'date_deadline': rec.properties['closedate'], + 'hs_object_id': rec.properties['hs_object_id'], + 'sync_mode': 'import', + }) + success_count += 1 + if deals_to_create: + self.env['crm.lead'].sudo().create(deals_to_create) + self.deals_last_imported = datetime.now() + # If create any records then creates the history for it. + if success_count > 0: + self.env['hubspot.sync.history'].sudo().create({ + 'date': self.deals_last_imported, + 'res_model_id': self.env.ref('crm.model_crm_lead').id, + 'sync_mode': 'import', + 'state': 'success', + 'count': success_count, + }) + # Return the created records count. + return success_count + + def action_update_hub_deals(self): + """ Method for update hubspot record based on odoo record. """ + api_client = HubSpot(access_token=self.access_key) + odoo_deal = self.env['crm.lead'].search([]) + odoo_deal_list = odoo_deal.mapped('hs_object_id') + hubspot_deal = api_client.crm.deals.get_all() + update_success = 0 + data_to_update = [] + for rec in hubspot_deal: + # If hubspot record present in odoo records then take the + # corresponding odoo record. + if rec.properties['hs_object_id'] in odoo_deal_list: + odoo_record = self.env['crm.lead'].search( + [('hs_object_id', '=', rec.properties['hs_object_id'])]) + # If the odoo record is recently modified then update hubspot + # record based on that. + if odoo_record.write_date > rec.updated_at.astimezone( + timezone.utc).replace(tzinfo=None): + data_to_update.append({ + 'id': rec.properties['hs_object_id'], + 'properties': { + "dealname": odoo_record.name, + "amount": odoo_record.expected_revenue + if odoo_record.expected_revenue else None, + "closedate": odoo_record.date_deadline + if odoo_record.date_deadline else '', + "createdate": odoo_record.create_date.strftime( + '%Y-%m-%dT%H:%M:%SZ') if odoo_record.create_date + else None, + } + }) + update_success += 1 + api_client.crm.deals.batch_api.update( + batch_input_simple_public_object_batch_input= + BatchInputSimplePublicObjectBatchInput(data_to_update)) + self.hub_deal_last_updated = datetime.now() + # Creates history record when any deal updated. + if update_success > 0: + self.env['hubspot.sync.history'].sudo().create({ + 'date': self.hub_deal_last_updated, + 'res_model_id': self.env.ref('crm.model_crm_lead').id, + 'sync_mode': 'hub_updated', + 'state': 'success', + 'count': update_success, + }) + # Returns the updated count. + return update_success + + def action_update_odoo_deals(self): + """ Method to update odoo leads based on hubspot records. """ + api_client = HubSpot(access_token=self.access_key) + odoo_deal = self.env['crm.lead'].search([]) + # Needed field to fetch from hubspot. + needed_fields = ["dealname", "hs_object_id", "amount", "closedate"] + hubspot_deal = api_client.crm.deals.get_all( + properties=needed_fields) + hubspot_deal_list = [rec.properties['hs_object_id'] + for rec in hubspot_deal] + update_success = 0 + for rec in odoo_deal: + # If odoo record present in hubspot record, take the hubspot record. + if rec.hs_object_id in hubspot_deal_list: + hubspot_deal_dict = {h.id: h for h in hubspot_deal} + hub_record = hubspot_deal_dict.get(rec.hs_object_id, None) + # If the hubspot record is recently modified then + # update odoo record based on that. + if hub_record.updated_at.astimezone(timezone.utc).replace( + tzinfo=None) > rec.write_date: + data_to_update = { + 'name': hub_record.properties['dealname'] or 'Lead', + 'expected_revenue': hub_record.properties['amount'], + 'date_deadline': hub_record.properties['closedate'], + } + update_success += 1 + rec.write(data_to_update) + self.odoo_deal_last_updated = datetime.now() + # Creates history record based on updated records count. + if update_success > 0: + self.env['hubspot.sync.history'].sudo().create({ + 'date': self.odoo_deal_last_updated, + 'res_model_id': self.env.ref('crm.model_crm_lead').id, + 'sync_mode': 'odoo_updated', + 'state': 'success', + 'count': update_success, + }) + # returns the updated count. + return update_success diff --git a/hubspot_odoo_connector/models/hubspot_sync_history.py b/hubspot_odoo_connector/models/hubspot_sync_history.py new file mode 100644 index 000000000..0dc887af6 --- /dev/null +++ b/hubspot_odoo_connector/models/hubspot_sync_history.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Vishnuraj P (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 . +# +############################################################################# +from odoo import api, fields, models + + +class HubspotSyncHistory(models.Model): + """ + model to set up the import/export history related to hubspot connector """ + _name = 'hubspot.sync.history' + _description = 'Sync History' + _rec_name = 'record_name' + + record_name = fields.Char(string="Record Name", compute='_compute_rec_name', + help="To show unique record name") + date = fields.Date( + string="Sync Date", + help="The date of the synchronization for this record.") + res_model_id = fields.Many2one(comodel_name='ir.model', string="Model", + help="The model associated with this record") + sync_mode = fields.Selection( + selection=[ + ('import', 'Imported'), + ('export', 'Exported'), + ('hub_updated', 'Hubspot Updated'), + ('odoo_updated', 'Odoo Updated')], + string='Sync Mode', + help="The synchronization mode for the record.") + state = fields.Selection( + selection=[('success', 'Success'), ('error', 'Failed')], + string='Status', readonly=True, required=True, + copy=False, help="The status of the synchronization process.") + count = fields.Integer(string="Count", + help="The count associated with this record.") + error = fields.Text(string="Reason", + help="The reason for any errors or failures that " + "occurred during synchronization.") + + @api.depends('date', 'res_model_id', 'count') + def _compute_rec_name(self): + for rec in self: + rec.record_name = (f"{self.date}" + f" : {self.res_model_id.name}-{self.count}") diff --git a/hubspot_odoo_connector/models/res_company.py b/hubspot_odoo_connector/models/res_company.py new file mode 100644 index 000000000..c82f6dea7 --- /dev/null +++ b/hubspot_odoo_connector/models/res_company.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Vishnuraj P (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 . +# +############################################################################# +from odoo import fields, models + + +class ResCompany(models.Model): + """ Adding new fields related to hubspot import/export in Company """ + _inherit = 'res.company' + + hs_object_id = fields.Char(string="Hubspot ID", + help="Hubspot ID associated with this record.") + sync_mode = fields.Selection( + selection=[('import', 'HS Imported'), ('export', 'HS Exported')], + string='Sync Mode', + help="Sync mode for the record. 'HS Imported' indicates the record was" + " imported from Hubspot, while 'HS Exported' indicates the record" + " was exported to Hubspot.") diff --git a/hubspot_odoo_connector/models/res_partner.py b/hubspot_odoo_connector/models/res_partner.py new file mode 100644 index 000000000..8dca068f5 --- /dev/null +++ b/hubspot_odoo_connector/models/res_partner.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Vishnuraj P (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 . +# +############################################################################# +from odoo import fields, models + + +class ResPartner(models.Model): + """ New fields related to hubspot connector """ + _inherit = 'res.partner' + + hs_object_id = fields.Char(string="Hubspot ID", + help="Hubspot ID associated with this record") + sync_mode = fields.Selection( + selection=[('import', 'HS Imported'), ('export', 'HS Exported')], + string='Sync Mode', + help="The synchronization mode for the record.") diff --git a/hubspot_odoo_connector/security/hubspot_odoo_connector_groups.xml b/hubspot_odoo_connector/security/hubspot_odoo_connector_groups.xml new file mode 100644 index 000000000..d27a9cbfa --- /dev/null +++ b/hubspot_odoo_connector/security/hubspot_odoo_connector_groups.xml @@ -0,0 +1,16 @@ + + + + + Hubspot Manager + 17 + Helps you manage the Hubspot. + + + + Hubspot Manager + + + + diff --git a/hubspot_odoo_connector/security/ir.model.access.csv b/hubspot_odoo_connector/security/ir.model.access.csv new file mode 100644 index 000000000..90799a48f --- /dev/null +++ b/hubspot_odoo_connector/security/ir.model.access.csv @@ -0,0 +1,5 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_hubspot_connector,access.hubspot.connector,model_hubspot_connector,base.group_user,1,0,0,0 +access_hubspot_connector_hubspot_manager,access.hubspot.connector.manager,model_hubspot_connector,hubspot_odoo_connector.group_hubspot_manager,1,1,1,1 +access_hubspot_sync_history,access.hubspot.sync.history,model_hubspot_sync_history,base.group_user,1,0,0,0 +access_hubspot_sync_history_hs_manager,access.hubspot.sync.history.manager,model_hubspot_sync_history,hubspot_odoo_connector.group_hubspot_manager,1,1,1,1 diff --git a/hubspot_odoo_connector/static/description/assets/icons/check.png b/hubspot_odoo_connector/static/description/assets/icons/check.png new file mode 100644 index 000000000..c8e85f51d Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/check.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/chevron.png b/hubspot_odoo_connector/static/description/assets/icons/chevron.png new file mode 100644 index 000000000..2089293d6 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/chevron.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/cogs.png b/hubspot_odoo_connector/static/description/assets/icons/cogs.png new file mode 100644 index 000000000..95d0bad62 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/cogs.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/consultation.png b/hubspot_odoo_connector/static/description/assets/icons/consultation.png new file mode 100644 index 000000000..8319d4baa Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/consultation.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/ecom-black.png b/hubspot_odoo_connector/static/description/assets/icons/ecom-black.png new file mode 100644 index 000000000..a9385ff13 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/ecom-black.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/education-black.png b/hubspot_odoo_connector/static/description/assets/icons/education-black.png new file mode 100644 index 000000000..3eb09b27b Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/education-black.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/hotel-black.png b/hubspot_odoo_connector/static/description/assets/icons/hotel-black.png new file mode 100644 index 000000000..130f613be Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/hotel-black.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/license.png b/hubspot_odoo_connector/static/description/assets/icons/license.png new file mode 100644 index 000000000..a5869797e Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/license.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/lifebuoy.png b/hubspot_odoo_connector/static/description/assets/icons/lifebuoy.png new file mode 100644 index 000000000..658d56ccc Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/lifebuoy.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/logo.png b/hubspot_odoo_connector/static/description/assets/icons/logo.png new file mode 100644 index 000000000..478462d3e Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/logo.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/manufacturing-black.png b/hubspot_odoo_connector/static/description/assets/icons/manufacturing-black.png new file mode 100644 index 000000000..697eb0e9f Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/manufacturing-black.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/pos-black.png b/hubspot_odoo_connector/static/description/assets/icons/pos-black.png new file mode 100644 index 000000000..97c0f90c1 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/pos-black.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/puzzle.png b/hubspot_odoo_connector/static/description/assets/icons/puzzle.png new file mode 100644 index 000000000..65cf854e7 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/puzzle.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/restaurant-black.png b/hubspot_odoo_connector/static/description/assets/icons/restaurant-black.png new file mode 100644 index 000000000..4a35eb939 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/restaurant-black.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/service-black.png b/hubspot_odoo_connector/static/description/assets/icons/service-black.png new file mode 100644 index 000000000..301ab51cb Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/service-black.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/trading-black.png b/hubspot_odoo_connector/static/description/assets/icons/trading-black.png new file mode 100644 index 000000000..9398ba2f1 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/trading-black.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/training.png b/hubspot_odoo_connector/static/description/assets/icons/training.png new file mode 100644 index 000000000..884ca024d Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/training.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/update.png b/hubspot_odoo_connector/static/description/assets/icons/update.png new file mode 100644 index 000000000..ecbc5a01a Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/update.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/user.png b/hubspot_odoo_connector/static/description/assets/icons/user.png new file mode 100644 index 000000000..6ffb23d9f Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/user.png differ diff --git a/hubspot_odoo_connector/static/description/assets/icons/wrench.png b/hubspot_odoo_connector/static/description/assets/icons/wrench.png new file mode 100644 index 000000000..6c04dea0f Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/icons/wrench.png differ diff --git a/hubspot_odoo_connector/static/description/assets/misc/categories.png b/hubspot_odoo_connector/static/description/assets/misc/categories.png new file mode 100644 index 000000000..bedf1e0b1 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/misc/categories.png differ diff --git a/hubspot_odoo_connector/static/description/assets/misc/check-box.png b/hubspot_odoo_connector/static/description/assets/misc/check-box.png new file mode 100644 index 000000000..42caf24b9 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/misc/check-box.png differ diff --git a/hubspot_odoo_connector/static/description/assets/misc/compass.png b/hubspot_odoo_connector/static/description/assets/misc/compass.png new file mode 100644 index 000000000..d5fed8faa Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/misc/compass.png differ diff --git a/hubspot_odoo_connector/static/description/assets/misc/corporate.png b/hubspot_odoo_connector/static/description/assets/misc/corporate.png new file mode 100644 index 000000000..2eb13edbf Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/misc/corporate.png differ diff --git a/hubspot_odoo_connector/static/description/assets/misc/customer-support.png b/hubspot_odoo_connector/static/description/assets/misc/customer-support.png new file mode 100644 index 000000000..79efc72ed Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/misc/customer-support.png differ diff --git a/hubspot_odoo_connector/static/description/assets/misc/cybrosys-logo.png b/hubspot_odoo_connector/static/description/assets/misc/cybrosys-logo.png new file mode 100644 index 000000000..cc3cc0ccf Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/misc/cybrosys-logo.png differ diff --git a/hubspot_odoo_connector/static/description/assets/misc/features.png b/hubspot_odoo_connector/static/description/assets/misc/features.png new file mode 100644 index 000000000..b41769f77 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/misc/features.png differ diff --git a/hubspot_odoo_connector/static/description/assets/misc/logo.png b/hubspot_odoo_connector/static/description/assets/misc/logo.png new file mode 100644 index 000000000..478462d3e Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/misc/logo.png differ diff --git a/hubspot_odoo_connector/static/description/assets/misc/pictures.png b/hubspot_odoo_connector/static/description/assets/misc/pictures.png new file mode 100644 index 000000000..56d255fe9 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/misc/pictures.png differ diff --git a/hubspot_odoo_connector/static/description/assets/misc/pie-chart.png b/hubspot_odoo_connector/static/description/assets/misc/pie-chart.png new file mode 100644 index 000000000..426e05244 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/misc/pie-chart.png differ diff --git a/hubspot_odoo_connector/static/description/assets/misc/right-arrow.png b/hubspot_odoo_connector/static/description/assets/misc/right-arrow.png new file mode 100644 index 000000000..730984a06 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/misc/right-arrow.png differ diff --git a/hubspot_odoo_connector/static/description/assets/misc/star.png b/hubspot_odoo_connector/static/description/assets/misc/star.png new file mode 100644 index 000000000..2eb9ab29f Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/misc/star.png differ diff --git a/hubspot_odoo_connector/static/description/assets/misc/support.png b/hubspot_odoo_connector/static/description/assets/misc/support.png new file mode 100644 index 000000000..4f18b8b82 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/misc/support.png differ diff --git a/hubspot_odoo_connector/static/description/assets/misc/whatsapp.png b/hubspot_odoo_connector/static/description/assets/misc/whatsapp.png new file mode 100644 index 000000000..d513a5356 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/misc/whatsapp.png differ diff --git a/hubspot_odoo_connector/static/description/assets/modules/live_chat.png b/hubspot_odoo_connector/static/description/assets/modules/live_chat.png new file mode 100644 index 000000000..3664700f5 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/modules/live_chat.png differ diff --git a/hubspot_odoo_connector/static/description/assets/modules/slack.png b/hubspot_odoo_connector/static/description/assets/modules/slack.png new file mode 100644 index 000000000..92ae36dc5 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/modules/slack.png differ diff --git a/hubspot_odoo_connector/static/description/assets/modules/twitter.png b/hubspot_odoo_connector/static/description/assets/modules/twitter.png new file mode 100644 index 000000000..ee4fa9abd Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/modules/twitter.png differ diff --git a/hubspot_odoo_connector/static/description/assets/modules/whatsapp.gif b/hubspot_odoo_connector/static/description/assets/modules/whatsapp.gif new file mode 100644 index 000000000..c51b9eb07 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/modules/whatsapp.gif differ diff --git a/hubspot_odoo_connector/static/description/assets/modules/zoom_meet.jpg b/hubspot_odoo_connector/static/description/assets/modules/zoom_meet.jpg new file mode 100644 index 000000000..ae7760bd2 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/modules/zoom_meet.jpg differ diff --git a/hubspot_odoo_connector/static/description/assets/screenshots/1.png b/hubspot_odoo_connector/static/description/assets/screenshots/1.png new file mode 100644 index 000000000..62af61805 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/screenshots/1.png differ diff --git a/hubspot_odoo_connector/static/description/assets/screenshots/10.png b/hubspot_odoo_connector/static/description/assets/screenshots/10.png new file mode 100644 index 000000000..fd8a89760 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/screenshots/10.png differ diff --git a/hubspot_odoo_connector/static/description/assets/screenshots/2.1.png b/hubspot_odoo_connector/static/description/assets/screenshots/2.1.png new file mode 100644 index 000000000..d0f7b2ddc Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/screenshots/2.1.png differ diff --git a/hubspot_odoo_connector/static/description/assets/screenshots/2.2.png b/hubspot_odoo_connector/static/description/assets/screenshots/2.2.png new file mode 100644 index 000000000..70e770cb3 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/screenshots/2.2.png differ diff --git a/hubspot_odoo_connector/static/description/assets/screenshots/2.3.png b/hubspot_odoo_connector/static/description/assets/screenshots/2.3.png new file mode 100644 index 000000000..4db2002f4 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/screenshots/2.3.png differ diff --git a/hubspot_odoo_connector/static/description/assets/screenshots/2.png b/hubspot_odoo_connector/static/description/assets/screenshots/2.png new file mode 100644 index 000000000..3c5ea8656 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/screenshots/2.png differ diff --git a/hubspot_odoo_connector/static/description/assets/screenshots/3.png b/hubspot_odoo_connector/static/description/assets/screenshots/3.png new file mode 100644 index 000000000..c98c78cf2 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/screenshots/3.png differ diff --git a/hubspot_odoo_connector/static/description/assets/screenshots/4.png b/hubspot_odoo_connector/static/description/assets/screenshots/4.png new file mode 100644 index 000000000..a9ce5226c Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/screenshots/4.png differ diff --git a/hubspot_odoo_connector/static/description/assets/screenshots/5.1.png b/hubspot_odoo_connector/static/description/assets/screenshots/5.1.png new file mode 100644 index 000000000..6ce9c2140 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/screenshots/5.1.png differ diff --git a/hubspot_odoo_connector/static/description/assets/screenshots/5.png b/hubspot_odoo_connector/static/description/assets/screenshots/5.png new file mode 100644 index 000000000..af7e1971f Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/screenshots/5.png differ diff --git a/hubspot_odoo_connector/static/description/assets/screenshots/6.png b/hubspot_odoo_connector/static/description/assets/screenshots/6.png new file mode 100644 index 000000000..aa1366734 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/screenshots/6.png differ diff --git a/hubspot_odoo_connector/static/description/assets/screenshots/7.png b/hubspot_odoo_connector/static/description/assets/screenshots/7.png new file mode 100644 index 000000000..3bfc3b821 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/screenshots/7.png differ diff --git a/hubspot_odoo_connector/static/description/assets/screenshots/8.png b/hubspot_odoo_connector/static/description/assets/screenshots/8.png new file mode 100644 index 000000000..6e3a590ac Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/screenshots/8.png differ diff --git a/hubspot_odoo_connector/static/description/assets/screenshots/hero.gif b/hubspot_odoo_connector/static/description/assets/screenshots/hero.gif new file mode 100644 index 000000000..463ce56f4 Binary files /dev/null and b/hubspot_odoo_connector/static/description/assets/screenshots/hero.gif differ diff --git a/hubspot_odoo_connector/static/description/banner.png b/hubspot_odoo_connector/static/description/banner.png new file mode 100644 index 000000000..18953cdfe Binary files /dev/null and b/hubspot_odoo_connector/static/description/banner.png differ diff --git a/hubspot_odoo_connector/static/description/icon.png b/hubspot_odoo_connector/static/description/icon.png new file mode 100644 index 000000000..a23f7cbf5 Binary files /dev/null and b/hubspot_odoo_connector/static/description/icon.png differ diff --git a/hubspot_odoo_connector/static/description/index.html b/hubspot_odoo_connector/static/description/index.html new file mode 100644 index 000000000..63d53da19 --- /dev/null +++ b/hubspot_odoo_connector/static/description/index.html @@ -0,0 +1,694 @@ +
+ +
+ +
+
+ Community +
+
+ Enterprise +
+
+ Odoo.sh +
+
+
+ +
+
+
+ +

+ Hubspot Odoo Connector

+

+ This Module Integrates Hubspot with Odoo to Sync + Contacts, Companies, and Deals.

+ + +
+
+
+
+ + +
+
+ +
+

+ Explore This Module

+
+ + + + + +
+
+ +
+

+ Overview

+
+ +
+
+ In this module we integrate the HubSpot with odoo. HubSpot acts + as a solution hack for CRM, sale and + marketing. + By integrating this both of them we can thereby benefit from the + best of both worlds. + With the help of this connector, you can link the two systems + and elevate customer relationship + management to a new level of client satisfaction and increased + productivity. +
+
+ + + +
+
+ +
+

+ Features

+
+ +
+
+
+ + Allowed to Create Multiple HubSpot Instance. +
+
+ + Import, Export and Update Contacts. +
+
+ + Import, Export and Update Companies. +
+
+ + Import, Export and Update Deals. +
+
+ + Sync History for all export, Import and Update. +
+
+
+ + + +
+
+ +
+

+ Screenshots

+
+ +
+
+
+

+ Configure Access Right. +

+

+ Go to Settings -> Users -> Select User -> Select Access Rights + for 'HubSpot Manager' +

+ +
+
+

+ Generate Token in HubSpot. +

+

+ Create a private app in HubSpot and get the Access Token +

+ +
+
+

+ Get owner ID from Hubspot. +

+

+ Go to Properties of hubspot settings +

+ +

+ Search for owner, select 'Contact Owner' and Copy the internal + Value +

+ +
+
+

+ Create HubSpot Instance In Odoo then CONNECT. +

+

+ Provide the Instance Name and Access Token and Owner ID of the Instance + in odoo +

+ +
+
+

+ Once it is connected, the state will be changed to CONNECTED + and the sync options will be visible. +

+ +
+
+

+ Then you can enable different Sync options by Toggle Buttons + then Sync Button. +

+ +
+
+

+ After sync the last sync time and the success message will be + shown. +

+ +
+
+

+ The Sync History record in Configuration -> Hubspot Sync History. +

+ +
+
+

+ The Sync Contacts Can be seen in Hubspot. +

+ +
+
+

+ Same Options are available for SyncCompany. +

+ +
+
+

+ The Sync Company Can be seen in Hubspot. +

+ +
+
+

+ Same Options are available for SyncDeals. +

+ +
+
+
+ + +
+
+

Suggested Products

+
+ + +
+
+ + + +
+
+
+

Our Services

+
+
+ +
+
+ +
+
+ Odoo + Customization
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Support
+
+ + +
+
+ +
+
+ Hire + Odoo + Developer
+
+ +
+
+ +
+
+ Odoo + Integration
+
+ +
+
+ +
+
+ Odoo + Migration
+
+ + +
+
+ +
+
+ Odoo + Consultancy
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Licensing Consultancy
+
+
+
+ + + +
+
+
+

Our Industries

+
+
+ +
+
+ +
+ Trading +
+

+ Easily procure + and + sell your products

+
+
+ +
+
+ +
+ POS +
+

+ Easy + configuration + and convivial experience

+
+
+ +
+
+ +
+ Education +
+

+ A platform for + educational management

+
+
+ +
+
+ +
+ Manufacturing +
+

+ Plan, track and + schedule your operations

+
+
+ +
+
+ +
+ E-commerce & Website +
+

+ Mobile + friendly, + awe-inspiring product pages

+
+
+ +
+
+ +
+ Service Management +
+

+ Keep track of + services and invoice

+
+
+ +
+
+ +
+ Restaurant +
+

+ Run your bar or + restaurant methodically

+
+
+ +
+
+ +
+ Hotel Management +
+

+ An + all-inclusive + hotel management application

+
+
+ +
+
+ + + + + +
+
+
+

Need Help?

+
+
+
+ + +
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+
+
+ diff --git a/hubspot_odoo_connector/views/crm_lead_views.xml b/hubspot_odoo_connector/views/crm_lead_views.xml new file mode 100644 index 000000000..79a25c3b2 --- /dev/null +++ b/hubspot_odoo_connector/views/crm_lead_views.xml @@ -0,0 +1,52 @@ + + + + + crm.lead.view.form.inherit.hubspot.odoo.connector + crm.lead + + + + + + + + + + + Opportunities + crm.lead + kanban,tree,graph,pivot,form,calendar,activity + [('sync_mode', '=', 'export')] + +

+ Odoo helps you track all exported leads from Hubspot. +

+
+
+ + + Opportunities + crm.lead + kanban,tree,graph,pivot,form,calendar,activity + [('sync_mode', '=', 'import')] + +

+ Odoo helps you track all exported leads to Hubspot. +

+
+
+ + + + +
diff --git a/hubspot_odoo_connector/views/hubspot_connector_views.xml b/hubspot_odoo_connector/views/hubspot_connector_views.xml new file mode 100644 index 000000000..8521e3a9e --- /dev/null +++ b/hubspot_odoo_connector/views/hubspot_connector_views.xml @@ -0,0 +1,169 @@ + + + + + hubspot.connector.view.form + hubspot.connector + +
+
+ +
+ + +
+ + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + Hubspot Connector + ir.actions.act_window + hubspot.connector + tree,form + + + + + + +
diff --git a/hubspot_odoo_connector/views/hubspot_sync_history_views.xml b/hubspot_odoo_connector/views/hubspot_sync_history_views.xml new file mode 100644 index 000000000..1b738c2d4 --- /dev/null +++ b/hubspot_odoo_connector/views/hubspot_sync_history_views.xml @@ -0,0 +1,54 @@ + + + + + hubspot.sync.history.view.tree + hubspot.sync.history + + + + + + + + + + + + hubspot.sync.history.view.form + hubspot.sync.history + +
+
+ +
+ + + + + + + + + + + + + +
+
+
+ + + Hubspot Sync History + ir.actions.act_window + hubspot.sync.history + tree,form + + + +
diff --git a/hubspot_odoo_connector/views/res_company_views.xml b/hubspot_odoo_connector/views/res_company_views.xml new file mode 100644 index 000000000..4afceadb4 --- /dev/null +++ b/hubspot_odoo_connector/views/res_company_views.xml @@ -0,0 +1,53 @@ + + + + + res.company.view.form.inherit.hubspot.odoo.connector + res.company + + + + + + + + + + + Company Import + ir.actions.act_window + res.company + tree,form + [('sync_mode', '=', 'import')] + +

+ Odoo helps you track all imported companies from Hubspot. +

+
+
+ + + Company Export + ir.actions.act_window + res.company + tree,form + [('sync_mode', '=', 'export')] + +

+ Odoo helps you track all exported companies to Hubspot. +

+
+
+ + + + +
diff --git a/hubspot_odoo_connector/views/res_partner_views.xml b/hubspot_odoo_connector/views/res_partner_views.xml new file mode 100644 index 000000000..53400efd8 --- /dev/null +++ b/hubspot_odoo_connector/views/res_partner_views.xml @@ -0,0 +1,56 @@ + + + + + res.partner.view.form.inherit.hubspot.odoo.connector + res.partner + + + + + + + + + + + Contacts + ir.actions.act_window + res.partner + kanban,tree,form,activity + [('sync_mode', '=', 'import')] + +

+ Odoo helps you track all imported contacts from Hubspot. +

+
+
+ + + Contacts + ir.actions.act_window + res.partner + kanban,tree,form,activity + [('sync_mode', '=', 'export')] + +

+ Odoo helps you track all exported contacts to Hubspot. +

+
+
+ + + + +