[IMP] import_google : refectroing for maintaining the partner and contact
[odoo/odoo.git] / addons / import_google / wizard / import_google.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
6 #
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.
11 #
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.
16 #
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/>.
19 #
20 ##############################################################################
21
22 import re
23 import urllib
24 import dateutil
25 import pytz
26 from dateutil import *
27 from pytz import timezone
28 from datetime import datetime
29 import time
30 try:
31     import gdata
32     import gdata.contacts.service
33     import gdata.calendar.service
34     import gdata.contacts
35     import gdata.calendar
36 except ImportError:
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 *
40
41 class google_import(import_framework):
42
43     gd_client = False
44     calendars = False
45     contact = False
46     DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
47     TABLE_CONTACT = 'Contact'
48     TABLE_ADDRESS ='Address'
49     TABLE_EVENT = 'Events'
50
51     def initialize(self):
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'))
57
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')
62
63     def get_mapping(self):
64         return {
65             self.TABLE_EVENT: self.get_event_mapping(),
66             self.TABLE_CONTACT: self.get_contact_mapping(),
67             self.TABLE_ADDRESS: self.get_address_mapping(),
68         }
69
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,
75         }
76
77         return data_fetching_function.get(table)()
78
79
80     def _get_tinydates(self, stime, etime,context):
81         stime = dateutil.parser.parse(stime)
82         etime = dateutil.parser.parse(etime)
83         try:
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')
89         except:
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)
93
94     def _get_rules(self, datas):
95         new_val = {}
96         if  datas['FREQ'] == 'WEEKLY' and datas.get('BYDAY'):
97             for day in datas['BYDAY'].split(','):
98                 new_val[day.lower()] = True
99             datas.pop('BYDAY')
100
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'
105             datas.pop('UNTIL')
106
107         if datas.get('COUNT'):
108             new_val['count'] = datas.get('COUNT')
109             new_val['end_type'] = 'count'
110             datas.pop('COUNT')
111
112         if datas.get('INTERVAL'):
113             new_val['interval'] = datas.get('INTERVAL')
114         else:
115             new_val['interval'] = 1
116
117         if datas.get('BYMONTHDAY'):
118             new_val['day'] = datas.get('BYMONTHDAY')
119             datas.pop('BYMONTHDAY')
120             new_val['select1'] = 'date'
121
122         if datas.get('BYDAY'):
123             d = datas.get('BYDAY')
124             if '-' in d:
125                 new_val['byday'] = d[:2]
126                 new_val['week_list'] = d[2:4].upper()
127             else:
128                 new_val['byday'] = d[:1]
129                 new_val['week_list'] = d[1:3].upper()
130             new_val['select1'] = 'day'
131
132         if datas.get('BYMONTH'):
133             new_val['month_list'] = datas.get('BYMONTH')
134             datas.pop('bymonth')
135         return new_val
136
137
138     def _get_repeat_status(self, str_google):
139         rrule = str_google[str_google.find('FREQ'):str_google.find('\nBEGIN')]
140         status = {}
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'})
146             status.pop('FREQ')
147         elif status.get('FREQ') == 'DAILY':
148             status.update({'rrule_type': 'daily'})
149             status.pop('FREQ')
150         elif status.get('FREQ') == 'MONTHLY':
151             status.update({'rrule_type': 'monthly'})
152             status.pop('FREQ')
153         elif status.get('FREQ') == 'YEARLY':
154             status.update({'rrule_type': 'yearly'})
155             status.pop('FREQ')
156         status.update(rules)
157         return status
158
159
160     def _get_repeat_dates(self, x):
161         if len(x) > 4:
162             if x[3].startswith('BY'):
163                 zone_time = x[4].split('+')[-1:][0].split(':')[0][:4]
164             else:
165                 zone_time = x[3].split('+')[-1:][0].split(':')[0][:4]
166         else:
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])
173         if len(o) == 2:
174             repeat_start += ' ' + str(o[1][:2]) + ':' + str(o[1][2:4]) + ':' + str(o[1][4:6])
175         else:
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])
179         if len(p) == 2:
180             repeat_end += ' ' + str(p[1][:2]) + ':' + str(p[1][2:4]) + ':' + str(p[1][4:6])
181         else:
182             repeat_end += ' ' + '00' + ':' + '00' + ':' + '00'
183         return (repeat_start, repeat_end, tz_format)
184
185     def get_events(self):
186         if 'tz' in self.context and self.context['tz']:
187             time_zone = self.context['tz']
188         else:
189             time_zone = tools.get_server_timezone()
190         au_tz = timezone(time_zone)
191         context = self.context
192         context.update({'au_tz':au_tz})
193         event_vals = []
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:
200                 event = {
201                     'recurrency': "0",
202                     'end_date' : False,
203                     'end_type' : False,
204                     'byday': 0,
205                     'count' : 0,
206                     'interval': 1,
207                     'day': False,
208                     'select1': False,
209                     'week_list': "",
210                     'month_list': False,
211                     'rrule_type': False,
212                 }
213
214                 timestring = timestring_end = datetime.datetime.now().strftime(self.DATETIME_FORMAT)
215                 if feed.when:
216                     timestring, timestring_end = self._get_tinydates(feed.when[0].start_time, feed.when[0].end_time,context)
217                 else:
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"))
223                     if repeat_status:
224                         repeat_status.update({'recurrency': True})
225                         event.update(repeat_status)
226
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,
233                               })
234                 event_vals.append(event)
235         return event_vals
236
237
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)])
243
244     def get_event(self, val):
245         if val.get("recurrency"):
246             val.update({"recurrency": "1"})
247         return val
248
249     def get_event_mapping(self):
250         return {
251             'model': 'crm.meeting',
252             'hook': self.get_event,
253             'map': {
254                     'id': 'id',
255                     'name': 'Name',
256                     'description': 'Description',
257                     'email_from': 'Email',
258                     'date': 'DateStart',
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',
264                     'byday':'byday',
265                     'count' : 'count',
266                     'interval': 'interval',
267                     'day': 'day',
268                     'select1': 'date',
269                     'week_list': 'week_list',
270                     'month_list':'month_list',
271                     'rrule_type': 'rrule_type',
272                 }
273         }
274
275
276     def get_contact(self):
277         table = self.context.get('table')[0]
278         datas = []
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())
283         else:
284             self.contact = self.gd_client.GetContactsFeed()
285         while self.contact:
286             for entry in self.contact.entry:
287                 data = {}
288                 data['id'] = entry.id.text
289                 name = tools.ustr(entry.title.text)
290                 if name == "None":
291                     name = entry.email[0].address
292                 data['name'] = name
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
311                 datas.append(data)
312             next = self.contact.GetNextLink()
313             self.contact = next and self.gd_client.GetContactsFeed(next.href) or None
314         return datas
315
316
317
318     def get_address_id(self, val):
319         contact = self.xml_id_exist(self.TABLE_ADDRESS, val.get('id'))
320         if contact:
321             return str(contact)
322         return False
323
324     def get_contact_mapping(self):
325         return {
326             'model': 'res.partner',
327             'dependencies': [self.TABLE_ADDRESS],
328             'map': {
329                 'id':'id',
330                 'name': 'name',
331                 'customer': 'customer',
332                 'supplier': 'supplier',
333                 'address/id': self.get_address_id,
334                 }
335             }
336
337     def get_partner_id(self, val):
338         partner_id = False
339         address_pool = self.obj.pool.get('res.partner.address')
340         company_pool = self.obj.pool.get('res.company')
341         if 'company' in val:
342             cids = company_pool.search(self.cr, self.uid, [('name', '=', val.get('company'))])
343             if cids:
344                 records = company_pool.browse(self.cr, self.uid, cids)
345                 for rec in records:
346                     if rec.partner_id:
347                         partner_id = rec.partner_id
348             return partner_id
349         contact = self.xml_id_exist(self.TABLE_CONTACT, val.get('id'))
350         if contact:
351             partner_id = self.get_mapped_id(self.TABLE_CONTACT, val.get('id'))
352         return partner_id
353
354     def get_address_mapping(self):
355         return {
356             'model': 'res.partner.address',
357             'dependencies': [],
358             'map': {
359                 'id':'id',
360                 'partner_id/.id': self.get_partner_id,
361                 'name': 'name',
362                 'city': 'city',
363                 'phone': 'phone',
364                 'mobile': 'mobile',
365                 'email': 'email',
366                 'fax': 'fax',
367                 'function': 'function'
368                 }
369
370         }