1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##############################################################################
26 from dateutil import *
27 from pytz import timezone
28 from datetime import datetime
32 import gdata.contacts.service
33 import gdata.calendar.service
37 raise osv.except_osv(_('Google Contacts Import Error!'), _('Please install gdata-python-client from http://code.google.com/p/gdata-python-client/downloads/list'))
38 from import_base.import_framework import *
39 from import_base.mapper import *
41 class google_import(import_framework):
46 DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
47 TABLE_CONTACT = 'Contact'
48 TABLE_ADDRESS ='Address'
49 TABLE_EVENT = 'Events'
52 google = self.obj.pool.get('google.login')
53 self.external_id_field = 'Id'
54 self.gd_client = google.google_login(self.context.get('user'),
55 self.context.get('password'),
56 self.context.get('instance'))
58 if self.context.get('instance') and self.context.get('instance') == 'contact':
59 self.contact = self.context.get('contact')
60 if self.context.get('instance') and self.context.get('instance') == 'calendar':
61 self.calendars = self.context.get('calendars')
63 def get_mapping(self):
65 self.TABLE_EVENT: self.get_event_mapping(),
66 self.TABLE_CONTACT: self.get_contact_mapping(),
67 self.TABLE_ADDRESS: self.get_address_mapping(),
70 def get_data(self, table):
71 data_fetching_function = {
72 self.TABLE_CONTACT: self.get_contact,
73 self.TABLE_ADDRESS: self.get_contact,
74 self.TABLE_EVENT: self.get_events,
77 return data_fetching_function.get(table)()
80 def _get_tinydates(self, stime, etime,context):
81 stime = dateutil.parser.parse(stime)
82 etime = dateutil.parser.parse(etime)
84 au_tz = context.get('au_tz')
85 au_dt = au_tz.normalize(stime.replace(tzinfo=pytz.utc).astimezone(au_tz))
86 timestring = datetime.datetime(*au_dt.timetuple()[:6]).strftime('%Y-%m-%d %H:%M:%S')
87 au_dt = au_tz.normalize(etime.replace(tzinfo=pytz.utc).astimezone(au_tz))
88 timestring_end = datetime.datetime(*au_dt.timetuple()[:6]).strftime('%Y-%m-%d %H:%M:%S')
90 timestring = datetime.datetime(*stime.timetuple()[:6]).strftime('%Y-%m-%d %H:%M:%S')
91 timestring_end = datetime.datetime(*etime.timetuple()[:6]).strftime('%Y-%m-%d %H:%M:%S')
92 return (timestring, timestring_end)
94 def _get_rules(self, datas):
96 if datas['FREQ'] == 'WEEKLY' and datas.get('BYDAY'):
97 for day in datas['BYDAY'].split(','):
98 new_val[day.lower()] = True
101 if datas.get('UNTIL'):
102 until = parser.parse(''.join((re.compile('\d')).findall(datas.get('UNTIL'))))
103 new_val['end_date'] = until.strftime('%Y-%m-%d')
104 new_val['end_type'] = 'end_date'
107 if datas.get('COUNT'):
108 new_val['count'] = datas.get('COUNT')
109 new_val['end_type'] = 'count'
112 if datas.get('INTERVAL'):
113 new_val['interval'] = datas.get('INTERVAL')
115 new_val['interval'] = 1
117 if datas.get('BYMONTHDAY'):
118 new_val['day'] = datas.get('BYMONTHDAY')
119 datas.pop('BYMONTHDAY')
120 new_val['select1'] = 'date'
122 if datas.get('BYDAY'):
123 d = datas.get('BYDAY')
125 new_val['byday'] = d[:2]
126 new_val['week_list'] = d[2:4].upper()
128 new_val['byday'] = d[:1]
129 new_val['week_list'] = d[1:3].upper()
130 new_val['select1'] = 'day'
132 if datas.get('BYMONTH'):
133 new_val['month_list'] = datas.get('BYMONTH')
138 def _get_repeat_status(self, str_google):
139 rrule = str_google[str_google.find('FREQ'):str_google.find('\nBEGIN')]
141 for rule in rrule.split(';'):
142 status[rule.split('=')[0]] = rule.split('=')[-1:] and rule.split('=')[-1:][0] or ''
143 rules = self._get_rules(status)
144 if status.get('FREQ') == 'WEEKLY':
145 status.update({'rrule_type': 'weekly'})
147 elif status.get('FREQ') == 'DAILY':
148 status.update({'rrule_type': 'daily'})
150 elif status.get('FREQ') == 'MONTHLY':
151 status.update({'rrule_type': 'monthly'})
153 elif status.get('FREQ') == 'YEARLY':
154 status.update({'rrule_type': 'yearly'})
160 def _get_repeat_dates(self, x):
162 if x[3].startswith('BY'):
163 zone_time = x[4].split('+')[-1:][0].split(':')[0][:4]
165 zone_time = x[3].split('+')[-1:][0].split(':')[0][:4]
167 zone_time = x[2].split('+')[-1:][0].split(':')[0][:4]
168 tz_format = zone_time[:2]+':'+zone_time[2:]
169 repeat_start = x[1].split('\n')[0].split(':')[1]
170 repeat_end = x[2].split('\n')[0].split(':')[1]
171 o = repeat_start.split('T')
172 repeat_start = str(o[0][:4]) + '-' + str(o[0][4:6]) + '-' + str(o[0][6:8])
174 repeat_start += ' ' + str(o[1][:2]) + ':' + str(o[1][2:4]) + ':' + str(o[1][4:6])
176 repeat_start += ' ' + '00' + ':' + '00' + ':' + '00'
177 p = repeat_end.split('T')
178 repeat_end = str(p[0][:4]) + '-' + str(p[0][4:6]) + '-' + str(p[0][6:8])
180 repeat_end += ' ' + str(p[1][:2]) + ':' + str(p[1][2:4]) + ':' + str(p[1][4:6])
182 repeat_end += ' ' + '00' + ':' + '00' + ':' + '00'
183 return (repeat_start, repeat_end, tz_format)
185 def get_events(self):
186 if 'tz' in self.context and self.context['tz']:
187 time_zone = self.context['tz']
189 time_zone = tools.get_server_timezone()
190 au_tz = timezone(time_zone)
191 context = self.context
192 context.update({'au_tz':au_tz})
194 for cal in self.calendars:
195 events_query = gdata.calendar.service.CalendarEventQuery(user=urllib.unquote(cal.split('/')[~0]))
196 events_query.start_index = 1
197 events_query.max_results = 1000
198 event_feed = self.gd_client.GetCalendarEventFeed(events_query.ToUri())
199 for feed in event_feed.entry:
214 timestring = timestring_end = datetime.datetime.now().strftime(self.DATETIME_FORMAT)
216 timestring, timestring_end = self._get_tinydates(feed.when[0].start_time, feed.when[0].end_time,context)
218 x = feed.recurrence.text.split(';')
219 repeat_status = self._get_repeat_status(feed.recurrence.text)
220 repeat_start, repeat_end, zone_time = self._get_repeat_dates(x)
221 timestring = time.strftime('%Y-%m-%d %H:%M:%S', time.strptime(repeat_start, "%Y-%m-%d %H:%M:%S"))
222 timestring_end = time.strftime('%Y-%m-%d %H:%M:%S', time.strptime(repeat_end, "%Y-%m-%d %H:%M:%S"))
224 repeat_status.update({'recurrency': True})
225 event.update(repeat_status)
227 event.update({'id' : feed.id.text,
228 'DateStart': timestring,
229 'DateEnd': timestring_end,
230 'Category':event_feed.title.text,
231 'Name': feed.title.text or 'No title',
232 'Description': feed.content.text,
234 event_vals.append(event)
238 def get_event_category(self, val, name):
239 fields = ['name', 'object_id']
240 nameid = 'event_category_'+name
241 data = [name, 'crm.meeting']
242 return self.import_object(fields, data, 'crm.case.categ', "crm_case_categ", nameid, [('name', 'ilike', name)])
244 def get_event(self, val):
245 if val.get("recurrency"):
246 val.update({"recurrency": "1"})
249 def get_event_mapping(self):
251 'model': 'crm.meeting',
252 'hook': self.get_event,
256 'description': 'Description',
257 'email_from': 'Email',
259 'date_deadline': 'DateEnd',
260 'categ_id/id': call(self.get_event_category, value('Category')),
261 'recurrency': 'recurrency',
262 'end_date' : 'end_date',
263 'end_type' : 'end_type',
266 'interval': 'interval',
269 'week_list': 'week_list',
270 'month_list':'month_list',
271 'rrule_type': 'rrule_type',
276 def get_contact(self):
277 table = self.context.get('table')[0]
279 if self.context.get('group_name'):
280 query = gdata.contacts.service.ContactsQuery()
281 query.group = self.context.get('group_name')
282 self.contact = self.gd_client.GetContactsFeed(query.ToUri())
284 self.contact = self.gd_client.GetContactsFeed()
286 for entry in self.contact.entry:
288 data['id'] = entry.id.text
289 name = tools.ustr(entry.title.text)
291 name = entry.email[0].address
293 emails = ','.join(email.address for email in entry.email)
294 data['email'] = emails
295 if table == 'Contact':
296 data.update({'customer': str(self.context.get('customer')),
297 'supplier': str(self.context.get('supplier'))})
298 if entry.organization:
299 if entry.organization.org_name:
300 data.update({'company': entry.organization.org_name.text})
301 if entry.organization.org_title:
302 data.update ({'function': entry.organization.org_title.text})
303 if entry.phone_number:
304 for phone in entry.phone_number:
305 if phone.rel == gdata.contacts.REL_WORK:
306 data['phone'] = phone.text
307 if phone.rel == gdata.contacts.PHONE_MOBILE:
308 data['mobile'] = phone.text
309 if phone.rel == gdata.contacts.PHONE_WORK_FAX:
310 data['fax'] = phone.text
312 next = self.contact.GetNextLink()
313 self.contact = next and self.gd_client.GetContactsFeed(next.href) or None
318 def get_address_id(self, val):
319 contact = self.xml_id_exist(self.TABLE_ADDRESS, val.get('id'))
324 def get_contact_mapping(self):
326 'model': 'res.partner',
327 'dependencies': [self.TABLE_ADDRESS],
331 'customer': 'customer',
332 'supplier': 'supplier',
333 'address/id': self.get_address_id,
337 def get_partner_id(self, val):
339 address_pool = self.obj.pool.get('res.partner.address')
340 company_pool = self.obj.pool.get('res.company')
342 cids = company_pool.search(self.cr, self.uid, [('name', '=', val.get('company'))])
344 records = company_pool.browse(self.cr, self.uid, cids)
347 partner_id = rec.partner_id
349 contact = self.xml_id_exist(self.TABLE_CONTACT, val.get('id'))
351 partner_id = self.get_mapped_id(self.TABLE_CONTACT, val.get('id'))
354 def get_address_mapping(self):
356 'model': 'res.partner.address',
360 'partner_id/.id': self.get_partner_id,
367 'function': 'function'