From 7e9db70ace0c65aef0e951eb78a591d917db6bca Mon Sep 17 00:00:00 2001 From: "DBR (OpenERP)" Date: Mon, 6 Jun 2011 12:40:10 +0530 Subject: [PATCH 1/9] MERGE:lp:~openerp-dev/openobject-addons/trunk-import_google-Backlog_2_ref-dbr bzr revid: dbr@tinyerp.com-20110606071010-mf063vww9oivtwtl --- .../wizard/google_login.py | 2 +- addons/import_base/import_framework.py | 10 +- .../wizard/google_contact_import.py | 427 +++++++++++------- 3 files changed, 265 insertions(+), 174 deletions(-) diff --git a/addons/google_base_account/wizard/google_login.py b/addons/google_base_account/wizard/google_login.py index 22a71dc21b1..76888fae107 100644 --- a/addons/google_base_account/wizard/google_login.py +++ b/addons/google_base_account/wizard/google_login.py @@ -81,4 +81,4 @@ class google_login(osv.osv_memory): google_login() -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/import_base/import_framework.py b/addons/import_base/import_framework.py index d041951ca11..8994e1568e6 100644 --- a/addons/import_base/import_framework.py +++ b/addons/import_base/import_framework.py @@ -214,7 +214,6 @@ class import_framework(Thread): fields.append(key) value = val(dict(dict_sugar)) data_lst.append(value) - return fields, data_lst def _generate_xml_id(self, name, table): @@ -297,7 +296,6 @@ class import_framework(Thread): domain_search = not domain_search and [('name', 'ilike', name)] or domain_search obj = self.obj.pool.get(model) xml_id = self._generate_xml_id(name, table) - xml_ref = self.mapped_id_if_exist(model, domain_search, table, name) fields.append('id') data.append(xml_id) @@ -342,13 +340,17 @@ class import_framework(Thread): """ - self.data_started = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.cr = pooler.get_db(self.cr.dbname).cursor() try: result = [] imported = set() #to invoid importing 2 times the sames modules for table in self.table_list: +# try: +# to_import = self.get_mapping()[table].get('import', True) +# except: +# import traceback,sys +# info = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback)) to_import = self.get_mapping()[table].get('import', True) if not table in imported: res = self._resolve_dependencies(self.get_mapping()[table].get('dependencies', []), imported) @@ -431,4 +433,4 @@ class import_framework(Thread): """ return "The import of data \n instance name : %s \n" % self.instance_name -#For example of use see import_sugarcrm \ No newline at end of file +#For example of use see import_sugarcrm diff --git a/addons/import_google_contact/wizard/google_contact_import.py b/addons/import_google_contact/wizard/google_contact_import.py index ac2314a5b9c..b7886173ab5 100644 --- a/addons/import_google_contact/wizard/google_contact_import.py +++ b/addons/import_google_contact/wizard/google_contact_import.py @@ -34,12 +34,96 @@ from osv import fields,osv from tools.translate import _ import tools +from import_base.import_framework import * +from import_base.mapper import * + +class impor_contact(import_framework): + + gd_client = False + TABLE_CONTACT = 'Contact' + TABLE_MEETING = 'Event' + + def initialize(self): + self.gd_client = gdata.contacts.service.ContactsService() + self.gd_client.ClientLogin(self.context.get('user', False),self.context.get('password', False)) + + def get_mapping(self): + return { + self.TABLE_CONTACT: self.get_contact_mapping(), + } + def _retreive_data(self,entry): + if entry: + data = {} + data['id'] = entry.id.text + name = tools.ustr(entry.title.text) + if name == "None": + name = entry.email[0].address + data['name'] = name + emails = ','.join(email.address for email in entry.email) + data['email'] = emails + if entry.organization: + if entry.organization.org_name: + data.update({'company': entry.organization.org_name.text}) + if entry.organization.org_title: + data.update ({'function': entry.organization.org_title.text}) + + if entry.phone_number: + for phone in entry.phone_number: + if phone.rel == gdata.contacts.REL_WORK: + data['phone'] = phone.text + else: + data['phone'] = False + if phone.rel == gdata.contacts.PHONE_MOBILE: + data['mobile'] = phone.text + else : + data['mobile'] = False + if phone.rel == gdata.contacts.PHONE_WORK_FAX: + data['fax'] = phone.text + else : + data['fax'] = False + + data.update({ + 'mobile': data.has_key('mobile') and data['mobile'] or False, + 'phone':data.has_key('phone') and data['phone'] or False, + 'fax':data.has_key('fax') and data['fax'] or False, + 'type':'contact', + 'id_new':data['id'] + '_data_'+ name, + }) + + + address = { + 'name': 'name', + 'type': 'type', + 'phone': 'phone', + 'mobile': 'mobile', + 'email': 'email', + 'fax': 'fax', + } + return self.import_object_mapping(address,data, 'res.partner.address', 'res.partner.address',data['id_new'], self.DO_NOT_FIND_DOMAIN) + + def get_contact_mapping(self): + contact = self.gd_client.GetContactsFeed() + while contact: + val = [] + for entry in contact.entry: + val = self._retreive_data(entry) + #val.append(self._retreive_data(entry)) + return { + 'model': 'res.partner.address', + 'import' : False, + 'dependencies': [], + #'hook': self._retreive_data, + 'map': val + } + class google_login_contact(osv.osv_memory): _inherit = 'google.login' _name = 'google.login.contact' - def _get_next_action(self, cr, uid, context=None): + + def _get_next_action(self, cr, uid, context): data_obj = self.pool.get('ir.model.data') data_id = data_obj._get_id(cr, uid, 'import_google_contact', 'view_synchronize_google_contact_import_form') + view_id = False if data_id: view_id = data_obj.browse(cr, uid, data_id, context=context).res_id @@ -89,185 +173,190 @@ class synchronize_google_contact(osv.osv_memory): 'create_partner': 'create_all', 'group_name': 'all', } - - def create_partner(self, cr, uid, data={}, context=None): - if context == None: - context = {} - if not data: - return False - name = data.get("company") or data.get('name','') - partner_pool = self.pool.get('res.partner') - partner_id = partner_pool.create(cr, uid, { - 'name': name, - 'user_id': uid, - 'address' : [(6, 0, [data['address_id']])], - 'customer': data.get('customer', False), - 'supplier': data.get('supplier', False) - }, context=context) - return partner_id - - def set_partner(self, cr, uid, name, address_id, context=None): - partner_pool = self.pool.get('res.partner') - partner_ids = partner_pool.search(cr, uid, [('name', '=', name)], context=context) - if partner_ids: - address_pool = self.pool.get('res.partner.address')#TODO create partner of find the one with the same name - data = {'partner_id' : partner_ids[0]} - address_pool.write(cr, uid, [address_id], data, context=context) - return partner_ids[0] - return False +# +# def create_partner(self, cr, uid, data={}, context=None): +# if context == None: +# context = {} +# if not data: +# return False +# name = data.get("company") or data.get('name','') +# partner_pool = self.pool.get('res.partner') +# partner_id = partner_pool.create(cr, uid, { +# 'name': name, +# 'user_id': uid, +# 'address' : [(6, 0, [data['address_id']])], +# 'customer': data.get('customer', False), +# 'supplier': data.get('supplier', False) +# }, context=context) +# return partner_id +# +# def set_partner(self, cr, uid, name, address_id, context=None): +# partner_pool = self.pool.get('res.partner') +# partner_ids = partner_pool.search(cr, uid, [('name', '=', name)], context=context) +# if partner_ids: +# address_pool = self.pool.get('res.partner.address')#TODO create partner of find the one with the same name +# data = {'partner_id' : partner_ids[0]} +# address_pool.write(cr, uid, [address_id], data, context=context) +# return partner_ids[0] +# return False def import_contact(self, cr, uid, ids, context=None): + tables = ['contact'] obj = self.browse(cr, uid, ids, context=context)[0] - user_obj = self.pool.get('res.users').browse(cr, uid, uid) - + google = self.pool.get('google.login') + gmail_user = user_obj.gmail_user gmail_pwd = user_obj.gmail_password - - google = self.pool.get('google.login') + context = {} gd_client = google.google_login(gmail_user, gmail_pwd, type='contact') - - if not gd_client: - raise osv.except_osv(_('Error'), _("Please specify correct user and password !")) - - if obj.group_name not in ['all']: - query = gdata.contacts.service.ContactsQuery() - query.group = obj.group_name - contact = gd_client.GetContactsFeed(query.ToUri()) - else: - contact = gd_client.GetContactsFeed() - - ids = self.create_contact(cr, uid, ids, gd_client, contact, option=obj.create_partner,context=context) - if not ids: - return {'type': 'ir.actions.act_window_close'} - - return { - 'name': _(obj.create_partner =='create_all' and 'Partners') or _('Contacts'), - 'domain': "[('id','in', ["+','.join(map(str,ids))+"])]", - 'view_type': 'form', - 'view_mode': 'tree,form', - 'res_model': obj.create_partner =='create_all' and 'res.partner' or 'res.partner.address', - 'context': context, - 'views': [(False, 'tree'),(False, 'form')], - 'type': 'ir.actions.act_window', - } + context.update({'user': gmail_user,'password': gmail_pwd,'gd_client':gd_client}) + + imp = impor_contact(self, cr, uid,'google', "synchronize_google_contact", context=context) + imp.set_table_list(tables) + imp.start() +# +# if not gd_client: +# raise osv.except_osv(_('Error'), _("Please specify correct user and password !")) +# +# if obj.group_name not in ['all']: +# query = gdata.contacts.service.ContactsQuery() +# query.group = obj.group_name +# contact = gd_client.GetContactsFeed(query.ToUri()) +# else: +# contact = gd_client.GetContactsFeed() +# +# ids = self.create_contact(cr, uid, ids, gd_client, contact, option=obj.create_partner,context=context) +# if not ids: +# return {'type': 'ir.actions.act_window_close'} +# +# return { +# 'name': _(obj.create_partner =='create_all' and 'Partners') or _('Contacts'), +# 'domain': "[('id','in', ["+','.join(map(str,ids))+"])]", +# 'view_type': 'form', +# 'view_mode': 'tree,form', +# 'res_model': obj.create_partner =='create_all' and 'res.partner' or 'res.partner.address', +# 'context': context, +# 'views': [(False, 'tree'),(False, 'form')], +# 'type': 'ir.actions.act_window', +# } - def create_contact(self, cr, uid, ids, gd_client, contact, option,context=None): - model_obj = self.pool.get('ir.model.data') - addresss_obj = self.pool.get('res.partner.address') - company_pool = self.pool.get('res.company') - addresses = [] - partner_ids = [] - contact_ids = [] - if 'tz' in context and context['tz']: - time_zone = context['tz'] - else: - time_zone = tools.get_server_timezone() - au_tz = timezone(time_zone) - while contact: - for entry in contact.entry: - data = self._retreive_data(entry) - google_id = data.pop('id') - model_data = { - 'name': google_id, - 'model': 'res.partner.address', - 'module': 'sync_google_contact', - 'noupdate': True - } +# def create_contact(self, cr, uid, ids, gd_client, contact, option,context=None): +# model_obj = self.pool.get('ir.model.data') +# addresss_obj = self.pool.get('res.partner.address') +# company_pool = self.pool.get('res.company') +# addresses = [] +# partner_ids = [] +# contact_ids = [] +# if 'tz' in context and context['tz']: +# time_zone = context['tz'] +# else: +# time_zone = tools.get_server_timezone() +# au_tz = timezone(time_zone) +# while contact: +# for entry in contact.entry: +# data = self._retreive_data(entry) +# google_id = data.pop('id') +# model_data = { +# 'name': google_id, +# 'model': 'res.partner.address', +# 'module': 'sync_google_contact', +# 'noupdate': True +# } +# +# data_ids = model_obj.search(cr, uid, [('model','=','res.partner.address'), ('name','=', google_id)]) +# if data_ids: +# contact_ids = [model_obj.browse(cr, uid, data_ids[0], context=context).res_id] +# elif data['email']: +# contact_ids = addresss_obj.search(cr, uid, [('email', 'ilike', data['email'])]) +# +# if contact_ids: +# addresses.append(contact_ids[0]) +# address = addresss_obj.browse(cr, uid, contact_ids[0], context=context) +# google_updated = entry.updated.text +# utime = dateutil.parser.parse(google_updated) +# au_dt = au_tz.normalize(utime.astimezone(au_tz)) +# updated_dt = datetime.datetime(*au_dt.timetuple()[:6]).strftime('%Y-%m-%d %H:%M:%S') +# if address.write_date < updated_dt: +# self.update_contact(cr, uid, contact_ids, data, context=context) +# res_id = contact_ids[0] +# if not contact_ids: +# #create or link to an existing partner only if it's a new contact +# data.update({'type': 'default'}) +# res_id = addresss_obj.create(cr, uid, data, context=context) +# data['address_id'] = res_id +# if option == 'create_all': +# obj = self.browse(cr, uid, ids, context=context)[0] +# data['customer'] = obj.customer +# data['supplier'] = obj.supplier +# res = False +# if 'company' in data: +# res = self.set_partner(cr, uid, data.get('company'), res_id, context=context) +# if res: +# partner_ids.append(res) +# if not res: +# partner_id = self.create_partner(cr, uid, data, context=context) +# partner_ids.append(partner_id) +# addresses.append(res_id) +# +# if not data_ids: #link to google_id if it was not the case before +# model_data.update({'res_id': res_id}) +# model_obj.create(cr, uid, model_data, context=context) +# +# next = contact.GetNextLink() +# contact = next and gd_client.GetContactsFeed(next.href) or None +# +# if option == 'create_all': +# return partner_ids +# else: +# return addresses - data_ids = model_obj.search(cr, uid, [('model','=','res.partner.address'), ('name','=', google_id)]) - if data_ids: - contact_ids = [model_obj.browse(cr, uid, data_ids[0], context=context).res_id] - elif data['email']: - contact_ids = addresss_obj.search(cr, uid, [('email', 'ilike', data['email'])]) +# def _retreive_data(self, entry): +# data = {} +# data['id'] = entry.id.text +# name = tools.ustr(entry.title.text) +# if name == "None": +# name = entry.email[0].address +# data['name'] = name +# emails = ','.join(email.address for email in entry.email) +# data['email'] = emails +# if entry.organization: +# if entry.organization.org_name: +# data.update({'company': entry.organization.org_name.text}) +# if entry.organization.org_title: +# data.update ({'function': entry.organization.org_title.text}) +# +# +# if entry.phone_number: +# for phone in entry.phone_number: +# if phone.rel == gdata.contacts.REL_WORK: +# data['phone'] = phone.text +# if phone.rel == gdata.contacts.PHONE_MOBILE: +# data['mobile'] = phone.text +# if phone.rel == gdata.contacts.PHONE_WORK_FAX: +# data['fax'] = phone.text +# return data - if contact_ids: - addresses.append(contact_ids[0]) - address = addresss_obj.browse(cr, uid, contact_ids[0], context=context) - google_updated = entry.updated.text - utime = dateutil.parser.parse(google_updated) - au_dt = au_tz.normalize(utime.astimezone(au_tz)) - updated_dt = datetime.datetime(*au_dt.timetuple()[:6]).strftime('%Y-%m-%d %H:%M:%S') - if address.write_date < updated_dt: - self.update_contact(cr, uid, contact_ids, data, context=context) - res_id = contact_ids[0] - if not contact_ids: - #create or link to an existing partner only if it's a new contact - data.update({'type': 'default'}) - res_id = addresss_obj.create(cr, uid, data, context=context) - data['address_id'] = res_id - if option == 'create_all': - obj = self.browse(cr, uid, ids, context=context)[0] - data['customer'] = obj.customer - data['supplier'] = obj.supplier - res = False - if 'company' in data: - res = self.set_partner(cr, uid, data.get('company'), res_id, context=context) - if res: - partner_ids.append(res) - if not res: - partner_id = self.create_partner(cr, uid, data, context=context) - partner_ids.append(partner_id) - addresses.append(res_id) - - if not data_ids: #link to google_id if it was not the case before - model_data.update({'res_id': res_id}) - model_obj.create(cr, uid, model_data, context=context) - - next = contact.GetNextLink() - contact = next and gd_client.GetContactsFeed(next.href) or None - - if option == 'create_all': - return partner_ids - else: - return addresses - - def _retreive_data(self, entry): - data = {} - data['id'] = entry.id.text - name = tools.ustr(entry.title.text) - if name == "None": - name = entry.email[0].address - data['name'] = name - emails = ','.join(email.address for email in entry.email) - data['email'] = emails - if entry.organization: - if entry.organization.org_name: - data.update({'company': entry.organization.org_name.text}) - if entry.organization.org_title: - data.update ({'function': entry.organization.org_title.text}) - - - if entry.phone_number: - for phone in entry.phone_number: - if phone.rel == gdata.contacts.REL_WORK: - data['phone'] = phone.text - if phone.rel == gdata.contacts.PHONE_MOBILE: - data['mobile'] = phone.text - if phone.rel == gdata.contacts.PHONE_WORK_FAX: - data['fax'] = phone.text - return data - - def update_contact(self, cr, uid, contact_ids, data, context=None): - addresss_obj = self.pool.get('res.partner.address') - vals = {} - addr = addresss_obj.browse(cr,uid,contact_ids)[0] - name = str((addr.name or addr.partner_id and addr.partner_id.name or '').encode('utf-8')) - - if name != data.get('name'): - vals['name'] = data.get('name','') - if addr.email != data.get('email'): - vals['email'] = data.get('email','') - if addr.mobile != data.get('mobile'): - vals['mobile'] = data.get('mobile','') - if addr.phone != data.get('phone'): - vals['phone'] = data.get('phone','') - if addr.fax != data.get('fax'): - vals['fax'] = data.get('fax','') - - addresss_obj.write(cr, uid, contact_ids, vals, context=context) - return {'type': 'ir.actions.act_window_close'} +# def update_contact(self, cr, uid, contact_ids, data, context=None): +# addresss_obj = self.pool.get('res.partner.address') +# vals = {} +# addr = addresss_obj.browse(cr,uid,contact_ids)[0] +# name = str((addr.name or addr.partner_id and addr.partner_id.name or '').encode('utf-8')) +# +# if name != data.get('name'): +# vals['name'] = data.get('name','') +# if addr.email != data.get('email'): +# vals['email'] = data.get('email','') +# if addr.mobile != data.get('mobile'): +# vals['mobile'] = data.get('mobile','') +# if addr.phone != data.get('phone'): +# vals['phone'] = data.get('phone','') +# if addr.fax != data.get('fax'): +# vals['fax'] = data.get('fax','') +# +# addresss_obj.write(cr, uid, contact_ids, vals, context=context) +# return {'type': 'ir.actions.act_window_close'} synchronize_google_contact() From b9831aa42d0ad755131ea5900861298d026e4ee2 Mon Sep 17 00:00:00 2001 From: "DBR (OpenERP)" Date: Tue, 7 Jun 2011 11:01:45 +0530 Subject: [PATCH 2/9] [ADD] Add new file import_google bzr revid: dbr@tinyerp.com-20110607053145-dtyiyktq6bxrxsbc --- .../import_google_contact/wizard/__init__.py | 2 +- .../wizard/google_contact_import.py | 85 +----------------- .../wizard/import_google.py | 88 +++++++++++++++++++ 3 files changed, 91 insertions(+), 84 deletions(-) create mode 100644 addons/import_google_contact/wizard/import_google.py diff --git a/addons/import_google_contact/wizard/__init__.py b/addons/import_google_contact/wizard/__init__.py index a7356cede9e..d92ae8c1588 100644 --- a/addons/import_google_contact/wizard/__init__.py +++ b/addons/import_google_contact/wizard/__init__.py @@ -18,7 +18,7 @@ # along with this program. If not, see . # ############################################################################## - +import import_google import google_contact_import # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/import_google_contact/wizard/google_contact_import.py b/addons/import_google_contact/wizard/google_contact_import.py index b7886173ab5..b87c7502fed 100644 --- a/addons/import_google_contact/wizard/google_contact_import.py +++ b/addons/import_google_contact/wizard/google_contact_import.py @@ -30,92 +30,11 @@ try: except ImportError: raise osv.except_osv(_('Google Contacts Import Error!'), _('Please install gdata-python-client from http://code.google.com/p/gdata-python-client/downloads/list')) +from import_google import import_contact from osv import fields,osv from tools.translate import _ import tools -from import_base.import_framework import * -from import_base.mapper import * - -class impor_contact(import_framework): - - gd_client = False - TABLE_CONTACT = 'Contact' - TABLE_MEETING = 'Event' - - def initialize(self): - self.gd_client = gdata.contacts.service.ContactsService() - self.gd_client.ClientLogin(self.context.get('user', False),self.context.get('password', False)) - - def get_mapping(self): - return { - self.TABLE_CONTACT: self.get_contact_mapping(), - } - def _retreive_data(self,entry): - if entry: - data = {} - data['id'] = entry.id.text - name = tools.ustr(entry.title.text) - if name == "None": - name = entry.email[0].address - data['name'] = name - emails = ','.join(email.address for email in entry.email) - data['email'] = emails - if entry.organization: - if entry.organization.org_name: - data.update({'company': entry.organization.org_name.text}) - if entry.organization.org_title: - data.update ({'function': entry.organization.org_title.text}) - - if entry.phone_number: - for phone in entry.phone_number: - if phone.rel == gdata.contacts.REL_WORK: - data['phone'] = phone.text - else: - data['phone'] = False - if phone.rel == gdata.contacts.PHONE_MOBILE: - data['mobile'] = phone.text - else : - data['mobile'] = False - if phone.rel == gdata.contacts.PHONE_WORK_FAX: - data['fax'] = phone.text - else : - data['fax'] = False - - data.update({ - 'mobile': data.has_key('mobile') and data['mobile'] or False, - 'phone':data.has_key('phone') and data['phone'] or False, - 'fax':data.has_key('fax') and data['fax'] or False, - 'type':'contact', - 'id_new':data['id'] + '_data_'+ name, - }) - - - address = { - 'name': 'name', - 'type': 'type', - 'phone': 'phone', - 'mobile': 'mobile', - 'email': 'email', - 'fax': 'fax', - } - return self.import_object_mapping(address,data, 'res.partner.address', 'res.partner.address',data['id_new'], self.DO_NOT_FIND_DOMAIN) - - def get_contact_mapping(self): - contact = self.gd_client.GetContactsFeed() - while contact: - val = [] - for entry in contact.entry: - val = self._retreive_data(entry) - #val.append(self._retreive_data(entry)) - return { - 'model': 'res.partner.address', - 'import' : False, - 'dependencies': [], - #'hook': self._retreive_data, - 'map': val - } - class google_login_contact(osv.osv_memory): _inherit = 'google.login' _name = 'google.login.contact' @@ -212,7 +131,7 @@ class synchronize_google_contact(osv.osv_memory): gd_client = google.google_login(gmail_user, gmail_pwd, type='contact') context.update({'user': gmail_user,'password': gmail_pwd,'gd_client':gd_client}) - imp = impor_contact(self, cr, uid,'google', "synchronize_google_contact", context=context) + imp = import_contact(self, cr, uid,'google', "synchronize_google_contact", context=context) imp.set_table_list(tables) imp.start() # diff --git a/addons/import_google_contact/wizard/import_google.py b/addons/import_google_contact/wizard/import_google.py new file mode 100644 index 00000000000..21edf9c65ab --- /dev/null +++ b/addons/import_google_contact/wizard/import_google.py @@ -0,0 +1,88 @@ +try: + import gdata + import gdata.contacts.service + import gdata.contacts +except ImportError: + raise osv.except_osv(_('Google Contacts Import Error!'), _('Please install gdata-python-client from http://code.google.com/p/gdata-python-client/downloads/list')) +from import_base.import_framework import * +from import_base.mapper import * + +class import_contact(import_framework): + + gd_client = False + TABLE_CONTACT = 'contact' + TABLE_MEETING = 'Event' + + def initialize(self): + self.gd_client = gdata.contacts.service.ContactsService() + self.gd_client.ClientLogin(self.context.get('user', False),self.context.get('password', False)) + + def get_mapping(self): + return { + self.TABLE_CONTACT: self.get_contact_mapping(), + } + def _retreive_data(self,entry): + if entry: + data = {} + data['id'] = entry.id.text + name = tools.ustr(entry.title.text) + if name == "None": + name = entry.email[0].address + data['name'] = name + emails = ','.join(email.address for email in entry.email) + data['email'] = emails + if entry.organization: + if entry.organization.org_name: + data.update({'company': entry.organization.org_name.text}) + if entry.organization.org_title: + data.update ({'function': entry.organization.org_title.text}) + + if entry.phone_number: + for phone in entry.phone_number: + if phone.rel == gdata.contacts.REL_WORK: + data['phone'] = phone.text + else: + data['phone'] = False + if phone.rel == gdata.contacts.PHONE_MOBILE: + data['mobile'] = phone.text + else : + data['mobile'] = False + if phone.rel == gdata.contacts.PHONE_WORK_FAX: + data['fax'] = phone.text + else : + data['fax'] = False + + data.update({ + 'mobile': data.has_key('mobile') and data['mobile'] or False, + 'phone':data.has_key('phone') and data['phone'] or False, + 'fax':data.has_key('fax') and data['fax'] or False, + 'type':'contact', + 'id_new':data['id'] + '_data_'+ name, + }) + + + address = { + 'name': 'name', + 'type': 'type', + 'phone': 'phone', + 'mobile': 'mobile', + 'email': 'email', + 'fax': 'fax', + } + return self.import_object_mapping(address,data, 'res.partner.address', 'res.partner.address',data['id_new'], self.DO_NOT_FIND_DOMAIN) + + def get_contact_mapping(self): + contact = self.gd_client.GetContactsFeed() + while contact: + val = [] + for entry in contact.entry: + val = self._retreive_data(entry) + #val.append(self._retreive_data(entry)) + return { + 'model': 'res.partner.address', + 'import' : False, + 'dependencies': [], + #'hook': self._retreive_data, + 'map': val + } + From 28dd15a6942569d0e8539a29483743ae29e894bd Mon Sep 17 00:00:00 2001 From: Jigar Amin Date: Tue, 7 Jun 2011 12:53:20 +0530 Subject: [PATCH 3/9] [IMP] Rnemed the module and merge contact and calendar modules bzr revid: jam@tinyerp.com-20110607072320-wkkw9q94vsd7mrlh --- .../wizard/google_login.py | 2 +- .../__init__.py | 6 +- .../__openerp__.py | 14 +- .../import_google_contact.py | 0 .../security/ir.model.access.csv | 0 addons/import_google/sync_google_calendar.py | 50 ++++ .../sync_google_calendar_view.xml | 32 +++ .../test/test_sync_google_calendar.yml | 36 +++ ...est_sync_google_contact_import_address.yml | 0 ...est_sync_google_contact_import_partner.yml | 0 .../wizard/__init__.py | 2 +- .../wizard/google_contact_import.py | 269 +++++++++++++++++- .../wizard/google_contact_import_view.xml | 43 ++- .../wizard/import_google.py | 10 +- 14 files changed, 443 insertions(+), 21 deletions(-) rename addons/{import_google_contact => import_google}/__init__.py (96%) rename addons/{import_google_contact => import_google}/__openerp__.py (77%) rename addons/{import_google_contact => import_google}/import_google_contact.py (100%) rename addons/{import_google_contact => import_google}/security/ir.model.access.csv (100%) create mode 100644 addons/import_google/sync_google_calendar.py create mode 100644 addons/import_google/sync_google_calendar_view.xml create mode 100644 addons/import_google/test/test_sync_google_calendar.yml rename addons/{import_google_contact => import_google}/test/test_sync_google_contact_import_address.yml (100%) rename addons/{import_google_contact => import_google}/test/test_sync_google_contact_import_partner.yml (100%) rename addons/{import_google_contact => import_google}/wizard/__init__.py (96%) rename addons/{import_google_contact => import_google}/wizard/google_contact_import.py (53%) rename addons/{import_google_contact => import_google}/wizard/google_contact_import_view.xml (55%) rename addons/{import_google_contact => import_google}/wizard/import_google.py (91%) diff --git a/addons/google_base_account/wizard/google_login.py b/addons/google_base_account/wizard/google_login.py index 76888fae107..78f27e51da4 100644 --- a/addons/google_base_account/wizard/google_login.py +++ b/addons/google_base_account/wizard/google_login.py @@ -24,7 +24,7 @@ from tools.translate import _ try: import gdata.contacts.service import gdata.contacts.client - + import gdata.calendar.service except ImportError: raise osv.except_osv(_('Google Contacts Import Error!'), _('Please install gdata-python-client from http://code.google.com/p/gdata-python-client/downloads/list')) diff --git a/addons/import_google_contact/__init__.py b/addons/import_google/__init__.py similarity index 96% rename from addons/import_google_contact/__init__.py rename to addons/import_google/__init__.py index 72009a6ca80..1889d262ff8 100644 --- a/addons/import_google_contact/__init__.py +++ b/addons/import_google/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################## -# +# # OpenERP, Open Source Management Solution # Copyright (C) 2004-2010 Tiny SPRL (). # @@ -15,11 +15,11 @@ # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . +# along with this program. If not, see . # ############################################################################## import import_google_contact +import sync_google_calendar import wizard # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/addons/import_google_contact/__openerp__.py b/addons/import_google/__openerp__.py similarity index 77% rename from addons/import_google_contact/__openerp__.py rename to addons/import_google/__openerp__.py index 6d19f2c6865..c5094c5cd02 100644 --- a/addons/import_google_contact/__openerp__.py +++ b/addons/import_google/__openerp__.py @@ -19,7 +19,6 @@ # ############################################################################## - { 'name': 'Google Contact Import', 'version': '1.0', @@ -27,15 +26,18 @@ 'description': """The module adds google contact in partner address""", 'author': 'OpenERP SA', 'website': 'http://www.openerp.com', - 'depends': ['base','google_base_account'], + 'depends': ['base', 'google_base_account','crm'], 'init_xml': [], 'update_xml': [ - 'wizard/google_contact_import_view.xml' - ], + 'sync_google_calendar_view.xml', + 'wizard/google_contact_import_view.xml', +# 'wizard/wizard_import_calendar_events_view.xml', + ], 'demo_xml': [], 'test': [ - 'test/test_sync_google_contact_import_partner.yml', - 'test/test_sync_google_contact_import_address.yml', +# 'test/test_sync_google_contact_import_partner.yml', +# 'test/test_sync_google_contact_import_address.yml', +# 'test/test_sync_google_calendar.yml', ], 'installable': True, 'active': False, diff --git a/addons/import_google_contact/import_google_contact.py b/addons/import_google/import_google_contact.py similarity index 100% rename from addons/import_google_contact/import_google_contact.py rename to addons/import_google/import_google_contact.py diff --git a/addons/import_google_contact/security/ir.model.access.csv b/addons/import_google/security/ir.model.access.csv similarity index 100% rename from addons/import_google_contact/security/ir.model.access.csv rename to addons/import_google/security/ir.model.access.csv diff --git a/addons/import_google/sync_google_calendar.py b/addons/import_google/sync_google_calendar.py new file mode 100644 index 00000000000..f61ac409fe6 --- /dev/null +++ b/addons/import_google/sync_google_calendar.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from osv import osv, fields + +class crm_meeting(osv.osv): + _inherit = "crm.meeting" + + def unlink(self, cr, uid, ids, context=None): + ids = self.web_client_unfucking_timebomb(ids) + res = super(crm_meeting, self).unlink(cr, uid, ids, context=context) + ids_real = self.remove_virtual_id(ids) + + model_obj = self.pool.get('ir.model.data') + remain_ids = self.search(cr, uid, [('id','in',ids_real)]) + ids_to_remove = list(set(ids_real) - set(remain_ids)) + + model_ids = model_obj.search(cr, uid, [('res_id','in',ids_to_remove),('model','=','crm.meeting'),('module','=','sync_google_calendar')], context=context) + model_obj.unlink(cr, uid, model_ids, context=context) + return res + +crm_meeting() + +class crm_case_categ(osv.osv): + """ Category of Case """ + _inherit = "crm.case.categ" + _columns = { + 'user_id': fields.many2one('res.users', 'User') + } +crm_case_categ() + +# vim:expandtab:smartindent:toabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/import_google/sync_google_calendar_view.xml b/addons/import_google/sync_google_calendar_view.xml new file mode 100644 index 00000000000..58e1e55efd0 --- /dev/null +++ b/addons/import_google/sync_google_calendar_view.xml @@ -0,0 +1,32 @@ + + + + + CRM - Meetings Form (Inherited) + crm.meeting + form + + + + + + + + + + CRM - Meetings Tree (Inherited) + crm.meeting + tree + + + + + + + + + \ No newline at end of file diff --git a/addons/import_google/test/test_sync_google_calendar.yml b/addons/import_google/test/test_sync_google_calendar.yml new file mode 100644 index 00000000000..38287cb111e --- /dev/null +++ b/addons/import_google/test/test_sync_google_calendar.yml @@ -0,0 +1,36 @@ +- + In order to test google calendar feature with OpenERP, I import events from + a google account and store them in Meetings. +- | + I create a record for the gmail account for which I want to import the contacts. +- + !record {model: google.login, id: google_login_contact_id0}: + user: testmail.openerp + password: openerptiny +- | + I login into that account. +- + !python {model: google.login}: | + self.login(cr, uid, [ref('google_login_contact_id0')], context) +- | + Now I want to import all the events from all the calendars in the user account. +- | + I select all calendars. +- + !record {model: synchronize.google.calendar, id: synchronize_google_calendar_id0}: + calendar_name: all +- | + I import the events from the google calendar. +- + !python {model: synchronize.google.calendar}: | + self.import_calendar_events(cr, uid, [ref('synchronize_google_calendar_id0')], context) +- | + Now I check my meetings are created or not. +- + !python {model: crm.meeting}: | + model_obj = self.pool.get('ir.model.data') + meeting_ids = self.search(cr, uid, []) + model_ids = model_obj.search(cr, uid, [('res_id','in',meeting_ids),('model','=','crm.meeting'),('module','=','sync_google_calendar')]) + assert model_ids, 'Meetings not created !' + + \ No newline at end of file diff --git a/addons/import_google_contact/test/test_sync_google_contact_import_address.yml b/addons/import_google/test/test_sync_google_contact_import_address.yml similarity index 100% rename from addons/import_google_contact/test/test_sync_google_contact_import_address.yml rename to addons/import_google/test/test_sync_google_contact_import_address.yml diff --git a/addons/import_google_contact/test/test_sync_google_contact_import_partner.yml b/addons/import_google/test/test_sync_google_contact_import_partner.yml similarity index 100% rename from addons/import_google_contact/test/test_sync_google_contact_import_partner.yml rename to addons/import_google/test/test_sync_google_contact_import_partner.yml diff --git a/addons/import_google_contact/wizard/__init__.py b/addons/import_google/wizard/__init__.py similarity index 96% rename from addons/import_google_contact/wizard/__init__.py rename to addons/import_google/wizard/__init__.py index d92ae8c1588..5e475d6fc7b 100644 --- a/addons/import_google_contact/wizard/__init__.py +++ b/addons/import_google/wizard/__init__.py @@ -20,5 +20,5 @@ ############################################################################## import import_google import google_contact_import - +#import wizard_import_calendar_events # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/import_google_contact/wizard/google_contact_import.py b/addons/import_google/wizard/google_contact_import.py similarity index 53% rename from addons/import_google_contact/wizard/google_contact_import.py rename to addons/import_google/wizard/google_contact_import.py index b87c7502fed..b38d3b1ce3e 100644 --- a/addons/import_google_contact/wizard/google_contact_import.py +++ b/addons/import_google/wizard/google_contact_import.py @@ -22,6 +22,9 @@ import datetime import dateutil from dateutil.parser import * from pytz import timezone +import time +import re +import urllib try: import gdata @@ -29,11 +32,11 @@ try: import gdata.contacts except ImportError: raise osv.except_osv(_('Google Contacts Import Error!'), _('Please install gdata-python-client from http://code.google.com/p/gdata-python-client/downloads/list')) - -from import_google import import_contact -from osv import fields,osv +from osv import fields +from osv import osv from tools.translate import _ import tools +from import_google import import_contact class google_login_contact(osv.osv_memory): _inherit = 'google.login' @@ -41,7 +44,7 @@ class google_login_contact(osv.osv_memory): def _get_next_action(self, cr, uid, context): data_obj = self.pool.get('ir.model.data') - data_id = data_obj._get_id(cr, uid, 'import_google_contact', 'view_synchronize_google_contact_import_form') + data_id = data_obj._get_id(cr, uid, 'import_google', 'view_synchronize_google_contact_import_form') view_id = False if data_id: @@ -134,6 +137,7 @@ class synchronize_google_contact(osv.osv_memory): imp = import_contact(self, cr, uid,'google', "synchronize_google_contact", context=context) imp.set_table_list(tables) imp.start() + return {'type': 'ir.actions.act_window_close'} # # if not gd_client: # raise osv.except_osv(_('Error'), _("Please specify correct user and password !")) @@ -278,5 +282,262 @@ class synchronize_google_contact(osv.osv_memory): # return {'type': 'ir.actions.act_window_close'} synchronize_google_contact() +def _get_tinydates(self, stime, etime): + stime = dateutil.parser.parse(stime) + etime = dateutil.parser.parse(etime) + try: + au_dt = au_tz.normalize(stime.astimezone(au_tz)) + timestring = datetime.datetime(*au_dt.timetuple()[:6]).strftime('%Y-%m-%d %H:%M:%S') + au_dt = au_tz.normalize(etime.astimezone(au_tz)) + timestring_end = datetime.datetime(*au_dt.timetuple()[:6]).strftime('%Y-%m-%d %H:%M:%S') + except: + timestring = datetime.datetime(*stime.timetuple()[:6]).strftime('%Y-%m-%d %H:%M:%S') + timestring_end = datetime.datetime(*etime.timetuple()[:6]).strftime('%Y-%m-%d %H:%M:%S') + return (timestring, timestring_end) + +def _get_rules(self, datas): + new_val = {} + if datas['FREQ'] == 'WEEKLY' and datas.get('BYDAY'): + for day in datas['BYDAY'].split(','): + new_val[day.lower()] = True + datas.pop('BYDAY') + + if datas.get('UNTIL'): + until = parser.parse(''.join((re.compile('\d')).findall(datas.get('UNTIL')))) + new_val['end_date'] = until.strftime('%Y-%m-%d') + new_val['end_type'] = 'end_date' + datas.pop('UNTIL') + + if datas.get('COUNT'): + new_val['count'] = datas.get('COUNT') + new_val['end_type'] = 'count' + datas.pop('COUNT') + + if datas.get('INTERVAL'): + new_val['interval'] = datas.get('INTERVAL') + else: + new_val['interval'] = 1 + + if datas.get('BYMONTHDAY'): + new_val['day'] = datas.get('BYMONTHDAY') + datas.pop('BYMONTHDAY') + new_val['select1'] = 'date' + + if datas.get('BYDAY'): + d = datas.get('BYDAY') + if '-' in d: + new_val['byday'] = d[:2] + new_val['week_list'] = d[2:4].upper() + else: + new_val['byday'] = d[:1] + new_val['week_list'] = d[1:3].upper() + new_val['select1'] = 'day' + + if datas.get('BYMONTH'): + new_val['month_list'] = datas.get('BYMONTH') + datas.pop('bymonth') + return new_val + + +def _get_repeat_status(self, str_google): + rrule = str_google[str_google.find('FREQ'):str_google.find('\nBEGIN')] + status = {} + for rule in rrule.split(';'): + status[rule.split('=')[0]] = rule.split('=')[-1:] and rule.split('=')[-1:][0] or '' + rules = _get_rules(self, status) + if status.get('FREQ') == 'WEEKLY': + status.update({'rrule_type': 'weekly'}) + status.pop('FREQ') + elif status.get('FREQ') == 'DAILY': + status.update({'rrule_type': 'daily'}) + status.pop('FREQ') + elif status.get('FREQ') == 'MONTHLY': + status.update({'rrule_type': 'monthly'}) + status.pop('FREQ') + elif status.get('FREQ') == 'YEARLY': + status.update({'rrule_type': 'yearly'}) + status.pop('FREQ') + status.update(rules) + return status + + +def _get_repeat_dates(self, x): + if len(x) > 4: + if x[3].startswith('BY'): + zone_time = x[4].split('+')[-1:][0].split(':')[0][:4] + else: + zone_time = x[3].split('+')[-1:][0].split(':')[0][:4] + else: + zone_time = x[2].split('+')[-1:][0].split(':')[0][:4] + tz_format = zone_time[:2]+':'+zone_time[2:] + repeat_start = x[1].split('\n')[0].split(':')[1] + repeat_end = x[2].split('\n')[0].split(':')[1] + o = repeat_start.split('T') + repeat_start = str(o[0][:4]) + '-' + str(o[0][4:6]) + '-' + str(o[0][6:8]) + if len(o) == 2: + repeat_start += ' ' + str(o[1][:2]) + ':' + str(o[1][2:4]) + ':' + str(o[1][4:6]) + else: + repeat_start += ' ' + '00' + ':' + '00' + ':' + '00' + p = repeat_end.split('T') + repeat_end = str(p[0][:4]) + '-' + str(p[0][4:6]) + '-' + str(p[0][6:8]) + if len(p) == 2: + repeat_end += ' ' + str(p[1][:2]) + ':' + str(p[1][2:4]) + ':' + str(p[1][4:6]) + else: + repeat_end += ' ' + '00' + ':' + '00' + ':' + '00' + return (repeat_start, repeat_end, tz_format) + +class google_login_calendar(osv.osv_memory): + _inherit = 'google.login' + _name = 'google.login.calendar' + + def _get_next_action(self, cr, uid, context): + data_obj = self.pool.get('ir.model.data') + data_id = data_obj._get_id(cr, uid, 'import_google', 'view_synchronize_google_calendar_import_form') + + view_id = False + if data_id: + view_id = data_obj.browse(cr, uid, data_id, context=context).res_id + value = { + 'name': _('Import Events'), + 'view_type': 'form', + 'view_mode': 'form,tree', + 'res_model': 'synchronize.google.calendar', + 'view_id': False, + 'context': context, + 'views': [(view_id, 'form')], + 'type': 'ir.actions.act_window', + 'target': 'new', + } + return value +google_login_calendar() + +class synchronize_google_calendar_events(osv.osv_memory): + _name = 'synchronize.google.calendar' + + def _get_calendars(self, cr, uid, context=None): + user_obj = self.pool.get('res.users').browse(cr, uid, uid) + google = self.pool.get('google.login') + res = [] + try: + gd_client = google.google_login(user_obj.gmail_user, user_obj.gmail_password, type='calendar') + + calendars = gd_client.GetAllCalendarsFeed() + + for cal in calendars.entry: + res.append((cal.id.text, cal.title.text)) + except Exception, e: + raise osv.except_osv('Error !', e.args[0].get('body')) + res.append(('all', 'All Calendars')) + return res + + _columns = { + 'calendar_name': fields.selection(_get_calendars, "Calendar Name", size=32), + } + + _defaults = { + 'calendar_name': 'all', + } + + def get_events(self, cr, uid, event_feed, context=None): + meeting_obj = self.pool.get('crm.meeting') + categ_obj = self.pool.get('crm.case.categ') + model_obj = self.pool.get('ir.model.data') + object_id = self.pool.get('ir.model').search(cr, uid, [('model', '=', 'crm.meeting')]) + meeting_ids = [] + categ_id = categ_obj.search(cr, uid, [('name', '=', event_feed.title.text), ('object_id', '=', object_id and object_id[0]), ('user_id', '=', uid)]) + if not categ_id: + categ_id.append(categ_obj.create(cr, uid, {'name': event_feed.title.text, + 'object_id': object_id and object_id[0], + 'user_id': uid})) + if 'tz' in context and context['tz']: + time_zone = context['tz'] + else: + time_zone = tools.get_server_timezone() + au_tz = timezone(time_zone) + + for feed in event_feed.entry: + google_id = feed.id.text + model_data = { + 'name': google_id, + 'model': 'crm.meeting', + 'module': 'sync_google_calendar', + 'noupdate': True, + } + vals = { + 'name': feed.title.text or '(No title)', + 'description': feed.content.text, + 'categ_id': categ_id and categ_id[0], + } + if feed.when: + timestring, timestring_end = _get_tinydates(self, feed.when[0].start_time, feed.when[0].end_time) + else: + x = feed.recurrence.text.split(';') + repeat_status = _get_repeat_status(self, feed.recurrence.text) + repeat_start, repeat_end, zone_time = _get_repeat_dates(self, x) + timestring = time.strftime('%Y-%m-%d %H:%M:%S', time.strptime(repeat_start, "%Y-%m-%d %H:%M:%S")) + timestring_end = time.strftime('%Y-%m-%d %H:%M:%S', time.strptime(repeat_end, "%Y-%m-%d %H:%M:%S")) + if repeat_status: + repeat_status.update({'recurrency': True}) + vals.update(repeat_status) + + vals.update({'date': timestring, 'date_deadline': timestring_end}) + data_ids = model_obj.search(cr, uid, [('model', '=', 'crm.meeting'), ('name', '=', google_id)]) + if data_ids: + res_id = model_obj.browse(cr, uid, data_ids[0], context=context).res_id + meeting = meeting_obj.browse(cr, uid, res_id, context=context) + google_updated = feed.updated.text + utime = dateutil.parser.parse(google_updated) + au_dt = au_tz.normalize(utime.astimezone(au_tz)) + updated_dt = datetime.datetime(*au_dt.timetuple()[:6]).strftime('%Y-%m-%d %H:%M:%S') + if meeting.write_date < updated_dt: + meeting_ids.append(res_id) + meeting_obj.write(cr, uid, [res_id], vals, context=context) + else: + res_id = meeting_obj.create(cr, uid, vals, context=context) + meeting_ids.append(res_id) + model_data.update({'res_id': res_id}) + model_obj.create(cr, uid, model_data, context=context) + return meeting_ids + + def import_calendar_events(self, cr, uid, ids, context=None): + obj = self.browse(cr, uid, ids, context=context)[0] + if not ids: + return {'type': 'ir.actions.act_window_close'} + + user_obj = self.pool.get('res.users').browse(cr, uid, uid) + gmail_user = user_obj.gmail_user + gamil_pwd = user_obj.gmail_password + + google = self.pool.get('google.login.calendar') + gd_client = google.google_login(gmail_user, gamil_pwd, type='calendar') + + if not gmail_user or not gamil_pwd: + raise osv.except_osv(_('Error'), _("Please specify the user and password !")) + + meetings = [] + if obj.calendar_name != 'all': + events_query = gdata.calendar.service.CalendarEventQuery(user=urllib.unquote(obj.calendar_name.split('/')[~0])) + events_query.start_index = 1 + events_query.max_results = 1000 + event_feed = gd_client.GetCalendarEventFeed(events_query.ToUri()) + meetings.append(self.get_events(cr, uid, event_feed, context=context)) + else: + calendars = map(lambda x: x[0], [cal for cal in self._get_calendars(cr, uid, context) if cal[0] != 'all']) + for cal in calendars: + events_query = gdata.calendar.service.CalendarEventQuery(user=urllib.unquote(cal.split('/')[~0])) + events_query.start_index = 1 + events_query.max_results = 1000 + event_feed = gd_client.GetCalendarEventFeed(events_query.ToUri()) + meetings.append(self.get_events(cr, uid, event_feed, context=context)) + + meeting_ids = [] + for meeting in meetings: + meeting_ids += meeting + + return { + 'type': 'ir.actions.act_window_close', + } + +synchronize_google_calendar_events() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/import_google_contact/wizard/google_contact_import_view.xml b/addons/import_google/wizard/google_contact_import_view.xml similarity index 55% rename from addons/import_google_contact/wizard/google_contact_import_view.xml rename to addons/import_google/wizard/google_contact_import_view.xml index fce2a8f2a53..2cefca6f6f9 100644 --- a/addons/import_google_contact/wizard/google_contact_import_view.xml +++ b/addons/import_google/wizard/google_contact_import_view.xml @@ -30,8 +30,43 @@ + + + + synchronize.google.calendar.form + synchronize.google.calendar + form + +
+ + + + + + + +