[IMP]: Add url parsing for backlog8 correction
[odoo/odoo.git] / addons / import_sugarcrm / import_sugarcrm.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 from osv import fields, osv
22 import sugar
23 from tools.translate import _
24 from import_base.import_framework import *
25 from import_base.mapper import *
26 from datetime import datetime
27 import base64
28 import pprint
29 pp = pprint.PrettyPrinter(indent=4)
30 #copy old import here
31
32 class related_ref(dbmapper):
33     def __init__(self, type):
34         self.type = type
35         
36     def __call__(self, external_val):
37         if external_val.get('parent_type') in self.type and external_val.get('parent_id'):
38             return self.parent.xml_id_exist(external_val['parent_type'], external_val['parent_id'])
39         return ''
40
41 class sugar_import(import_framework):
42     URL = False   
43     TABLE_CONTACT = 'Contacts'
44     TABLE_ACCOUNT = 'Accounts'
45     TABLE_USER = 'Users'
46     TABLE_EMPLOYEE = 'Employees'
47     TABLE_RESSOURCE = "resource"
48     TABLE_OPPORTUNITY = 'Opportunities'
49     TABLE_LEAD = 'Leads'
50     TABLE_STAGE = 'crm_stage'
51     TABLE_ATTENDEE = 'calendar_attendee'
52     TABLE_CALL = 'Calls'
53     TABLE_MEETING = 'Meetings'
54     TABLE_TASK = 'Tasks'
55     TABLE_PROJECT = 'Project'
56     TABLE_PROJECT_TASK = 'ProjectTask'
57     TABLE_BUG = 'Bugs'
58     TABLE_CASE = 'Cases'
59     TABLE_NOTE = 'Notes'
60     TABLE_EMAIL = 'Emails'
61     TABLE_COMPAIGN = 'Campaigns'
62     TABLE_HISTORY_ATTACHMNET = 'history_attachment'
63     
64     def initialize(self):
65         #login
66         global URL
67         url = self.context.get('url','')
68         url_sting = []
69         for url in str(url).split('/'):
70             if url.startswith('index.php'):
71                 url_soap = url.replace(url, 'soap.php')
72                 url_sting.append(url_soap)
73             else:
74                 url_sting.append(url)
75         URL = '/'.join(url_sting)
76         
77         PortType,sessionid = sugar.login(self.context.get('username',''), self.context.get('password',''), URL)
78         if sessionid == '-1':
79             raise osv.except_osv(_('Error !'), _('Authentication error !\nBad Username or Password !'))
80         self.context['port'] = PortType
81         self.context['session_id'] = sessionid
82         
83     def get_data(self, table):
84         return sugar.search(self.context.get('port'), self.context.get('session_id'), table)
85     """
86     Common import method
87     """
88
89     def get_category(self, val, model, name):
90         fields = ['name', 'object_id']
91         data = [name, model]
92         return self.import_object(fields, data, 'crm.case.categ', 'crm_categ', name, [('object_id.model','=',model), ('name', 'ilike', name)])
93
94     def get_job_title(self, dict, salutation):
95         fields = ['shortcut', 'name', 'domain']
96         if salutation:
97             data = [salutation, salutation, 'Contact']
98             return self.import_object(fields, data, 'res.partner.title', 'contact_title', salutation, [('shortcut', '=', salutation)])
99
100     def get_channel_id(self, dict, val):
101         fields = ['name']
102         data = [val]
103         return self.import_object(fields, data, 'res.partner.canal', 'crm_channel', val)
104     
105     def get_all_states(self, external_val, country_id):
106         """Get states or create new state unless country_id is False"""
107         state_code = external_val[0:3] #take the tree first char
108         fields = ['country_id/id', 'name', 'code']
109         data = [country_id, external_val, state_code]
110         if country_id:
111             return self.import_object(fields, data, 'res.country.state', 'country_state', external_val) 
112         return False
113
114     def get_all_countries(self, val):
115         """Get Country, if no country match do not create anything, to avoid duplicate country code"""
116         return self.mapped_id_if_exist('res.country', [('name', 'ilike', val)], 'country', val)
117     
118     def get_float_time(self, dict, hour, min):
119         min = int(min) * 100 / 60
120         return "%s.%i" % (hour, min)
121     
122     def get_attachment(self, val):
123         File, Filename = sugar.attachment_search(self.context.get('port'), self.context.get('session_id'), self.TABLE_NOTE, val.get('id')) 
124         attach_xml_id = False
125         if File:
126             fields = ['name', 'datas', 'datas_fname','res_id', 'res_model']
127             name = 'attachment_'+ (Filename or val.get('name'))
128             datas = [Filename or val.get('name'), File, Filename, val.get('res_id'),val.get('model',False)]
129             attach_xml_id = self.import_object(fields, datas, 'ir.attachment', self.TABLE_HISTORY_ATTACHMNET, name, [('res_id', '=', val.get('res_id'), ('model', '=', val.get('model')))])
130         return attach_xml_id
131         
132     """
133     import Emails
134     """
135     def import_email(self, val):
136         model_obj =  self.obj.pool.get('ir.model.data')
137         xml_id = self.xml_id_exist(val.get('parent_type'), val.get('parent_id'))
138         model_ids = model_obj.search(self.cr, self.uid, [('name', 'like', xml_id)])
139         if model_ids:
140             model = model_obj.browse(self.cr, self.uid, model_ids)[0]
141             if model.model == 'res.partner':
142                 val['partner_id/.id'] = model.res_id
143             else:    
144                 val['res_id'] = model.res_id
145                 val['model'] = model.model
146         return val   
147         
148     def get_email_mapping(self): 
149         return { 
150                 'model' : 'mailgate.message',
151                 'dependencies' : [self.TABLE_USER, self.TABLE_PROJECT, self.TABLE_PROJECT_TASK, self.TABLE_ACCOUNT, self.TABLE_CONTACT, self.TABLE_LEAD, self.TABLE_OPPORTUNITY, self.TABLE_MEETING, self.TABLE_CALL],
152                 'hook' : self.import_email,
153                 'map' : {'name':'name',
154                          'history' : const("1"),
155                         'date':'date_sent',
156                         'email_from': 'from_addr_name',
157                         'email_to': 'reply_to_addr',
158                         'email_cc': 'cc_addrs_names',
159                         'email_bcc': 'bcc_addrs_names',
160                         'message_id': 'message_id',
161                         'res_id': 'res_id',
162                         'model': 'model',
163                         'partner_id/.id': 'partner_id/.id',                         
164                         'attachment_ids/id': self.get_attachment,
165                         'user_id/id': ref(self.TABLE_USER, 'assigned_user_id'),
166                         'description': ppconcat('description', 'description_html'),
167                 }
168             } 
169     
170     """
171     import History(Notes)
172     """
173
174     def import_history(self, val):
175         model_obj =  self.obj.pool.get('ir.model.data')
176         xml_id = self.xml_id_exist(val.get('parent_type'), val.get('parent_id'))
177         model_ids = model_obj.search(self.cr, self.uid, [('name', 'like', xml_id)])
178         if model_ids:
179             model = model_obj.browse(self.cr, self.uid, model_ids)[0]
180             if model.model == 'res.partner':
181                 val['partner_id/.id'] = model.res_id
182                 val['history'] = "1"
183             else:    
184                 val['res_id'] = model.res_id
185                 val['model'] = model.model
186         return val    
187     
188     def get_history_mapping(self): 
189         return { 
190                 'model' : 'mailgate.message',
191                 'dependencies' : [self.TABLE_USER, self.TABLE_PROJECT, self.TABLE_PROJECT_TASK, self.TABLE_ACCOUNT, self.TABLE_CONTACT, self.TABLE_LEAD, self.TABLE_OPPORTUNITY, self.TABLE_MEETING, self.TABLE_CALL],
192                 'hook' : self.import_history,
193                 'map' : {
194                       'name':'name',
195                       'date': 'date_entered',
196                       'user_id/id': ref(self.TABLE_USER, 'assigned_user_id'),
197                       'description': ppconcat('description', 'description_html'),
198                       'res_id': 'res_id',
199                       'model': 'model',
200                       'attachment_ids/id': self.get_attachment,
201                       'partner_id/.id' : 'partner_id/.id',
202                       'history' : 'history',
203                 }
204             }     
205     
206     """
207     import Claims(Cases)
208     """
209     def get_claim_priority(self, val):
210         priority_dict = {            
211                 'P1': '2',
212                 'P2': '3',
213                 'P3': '4'
214         }
215         return priority_dict.get(val.get('priority'), '')
216         
217     def get_contact_info_from_account(self, val):
218         partner_id = self.get_mapped_id(self.TABLE_ACCOUNT, val.get('account_id'))
219         partner_address_id = False
220         partner_phone = False
221         partner_email = False
222         partner = self.obj.pool.get('res.partner').browse(self.cr, self.uid, [partner_id])[0]
223         if partner.address and partner.address[0]:
224             address = partner.address[0]
225             partner_address_id = address.id
226             partner_phone = address.phone
227             partner_email = address.email
228         return partner_address_id, partner_phone,partner_email
229     
230     def import_crm_claim(self, val):
231         partner_address_id, partner_phone,partner_email =  self.get_contact_info_from_account(val)
232         val['partner_address_id/.id'] = partner_address_id
233         val['partner_phone'] = partner_phone
234         val['email_from'] = partner_email
235         return val
236     
237     def get_crm_claim_mapping(self): 
238         return { 
239                 'model' : 'crm.claim',
240                 'dependencies' : [self.TABLE_USER, self.TABLE_ACCOUNT, self.TABLE_CONTACT, self.TABLE_LEAD],
241                 'hook' : self.import_crm_claim,
242                 'map' : {
243                     'name': concat('case_number','name', delimiter='-'),
244                     'date': 'date_entered',
245                     'user_id/id': ref(self.TABLE_USER, 'assigned_user_id'),
246                     'description': ppconcat('description', 'resolution', 'work_log'),
247                     'partner_id/id': ref(self.TABLE_ACCOUNT, 'account_id'),
248                     'partner_address_id/.id': 'partner_address_id/.id',
249                     'partner_phone': 'partner_phone',
250                     'email_from': 'email_from',                                        
251                     'priority': self.get_claim_priority,
252                     'state': map_val('status', self.project_issue_state)
253                 }
254             }    
255     """
256     Import Project Issue(Bugs)
257     """
258     project_issue_state = {
259             'New' : 'draft',
260             'Assigned':'open',
261             'Closed': 'done',
262             'Pending': 'pending',
263             'Rejected': 'cancel',
264     }
265      
266     def get_project_issue_priority(self, val):
267         pp.pprint(val)
268         priority_dict = {
269                 'Urgent': '1',
270                 'High': '2',
271                 'Medium': '3',
272                 'Low': '4'
273          }
274         return priority_dict.get(val.get('priority'), '')     
275       
276     def get_bug_project_id(self, dict, val):
277         fields = ['name']
278         data = [val]
279         return self.import_object(fields, data, 'project.project', 'project_issue', val)    
280     
281     def get_project_issue_mapping(self):
282         return { 
283                 'model' : 'project.issue',
284                 'dependencies' : [self.TABLE_USER],
285                 'map' : {
286                     'name': concat('bug_number', 'name', delimiter='-'),
287                     'project_id/id': call(self.get_bug_project_id, 'sugarcrm_bugs'),
288                     'categ_id/id': call(self.get_category, 'project.issue', value('type')),
289                     'description': ppconcat('description', 'source', 'resolution', 'work_log', 'found_in_release', 'release_name', 'fixed_in_release_name', 'fixed_in_release'),
290                     'priority': self.get_project_issue_priority,
291                     'state': map_val('status', self.project_issue_state),
292                     'assigned_to/id' : ref(self.TABLE_USER, 'assigned_user_id'),
293                 }
294             }
295     
296     """
297     import Project Tasks
298     """
299     project_task_state = {
300             'Not Started': 'draft',
301             'In Progress': 'open',
302             'Completed': 'done',
303             'Pending Input': 'pending',
304             'Deferred': 'cancelled',
305      }
306     
307     def get_project_task_priority(self, val):
308         priority_dict = {
309             'High': '0',
310             'Medium': '2',
311             'Low': '3'
312         }
313         return priority_dict.get(val.get('priority'), '')
314     
315     def get_project_task_mapping(self):
316         return { 
317                 'model' : 'project.task',
318                 'dependencies' : [self.TABLE_USER, self.TABLE_PROJECT],
319                 'map' : {
320                     'name': 'name',
321                     'date_start': 'date_start',
322                     'date_end': 'date_finish',
323                     'project_id/id': ref(self.TABLE_PROJECT, 'project_id'),
324                     'planned_hours': 'estimated_effort',
325                     'priority': self.get_project_task_priority,
326                     'description': ppconcat('description','milestone_flag', 'project_task_id', 'task_number', 'percent_complete'),
327                     'user_id/id': ref(self.TABLE_USER, 'assigned_user_id'),
328                     'partner_id/id': 'partner_id/id',
329                     'contact_id/id': 'contact_id/id',
330                     'state': map_val('status', self.project_task_state)
331                 }
332             }
333
334     """
335     import Projects
336     """
337     project_state = {
338             'Draft' : 'draft',
339             'In Review': 'open',
340             'Published': 'close'
341      }
342     
343     def import_project_account(self, val):
344         partner_id = False
345         partner_invoice_id = False        
346         sugar_project_account = sugar.relation_search(self.context.get('port'), self.context.get('session_id'), 'Project', module_id=val.get('id'), related_module=self.TABLE_ACCOUNT, query=None, deleted=None)
347         sugar_project_contact = sugar.relation_search(self.context.get('port'), self.context.get('session_id'), 'Project', module_id=val.get('id'), related_module=self.TABLE_CONTACT, query=None, deleted=None)
348         for contact_id in sugar_project_contact:
349             partner_invoice_id = self.get_mapped_id(self.TABLE_CONTACT, contact_id)
350         for account_id in sugar_project_account:
351             partner_id = self.get_mapped_id(self.TABLE_ACCOUNT, account_id)
352         return partner_id, partner_invoice_id      
353            
354     def import_project(self, val):
355         partner_id, partner_invoice_id  = self.import_project_account(val)    
356         val['partner_id/.id'] = partner_id
357         val['contact_id/.id'] = partner_invoice_id
358         return val
359     
360     def get_project_mapping(self):
361         return { 
362                 'model' : 'project.project',
363                 'dependencies' : [self.TABLE_CONTACT, self.TABLE_ACCOUNT, self.TABLE_USER],
364                 'hook' : self.import_project,
365                 'map' : {
366                     'name': 'name',
367                     'date_start': 'estimated_start_date',
368                     'date': 'estimated_end_date',
369                     'user_id/id': ref(self.TABLE_USER, 'assigned_user_id'),
370                     'partner_id/.id': 'partner_id/.id',
371                     'contact_id/.id': 'contact_id/.id',
372                     'state': map_val('status', self.project_state)
373                 }
374             }
375     
376     """
377     import Tasks
378     """
379     task_state = {
380             'Completed' : 'done',
381             'Not Started':'draft',
382             'In Progress': 'open',
383             'Pending Input': 'draft',
384             'deferred': 'cancel'
385         }
386
387     def import_task(self, val):
388         val['date'] = val.get('date_start') or datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
389         val['date_deadline'] = val.get('date_due') or datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
390         return val
391
392     def get_task_mapping(self):
393         return { 
394                 'model' : 'crm.meeting',
395                 'dependencies' : [self.TABLE_CONTACT, self.TABLE_ACCOUNT, self.TABLE_USER],
396                 'hook' : self.import_task,
397                 'map' : {
398                     'name': 'name',
399                     'date': 'date',
400                     'date_deadline': 'date_deadline',
401                     'user_id/id': ref(self.TABLE_USER, 'assigned_user_id'),
402                     'categ_id/id': call(self.get_category, 'crm.meeting', const('Tasks')),
403                     'partner_id/id': related_ref(self.TABLE_ACCOUNT),
404                     'partner_address_id/id': ref(self.TABLE_CONTACT,'contact_id'),
405                     'state': map_val('status', self.task_state)
406                 }
407             }
408        
409     """
410     import Calls
411     """  
412     #TODO adapt with project trunk-crm-imp   
413     call_state = {   
414             'Planned' : 'open',
415             'Held':'done',
416             'Not Held': 'pending',
417         }
418
419     def get_calls_mapping(self):
420         return { 
421                 'model' : 'crm.phonecall',
422                 'dependencies' : [self.TABLE_ACCOUNT, self.TABLE_CONTACT, self.TABLE_OPPORTUNITY, self.TABLE_LEAD],
423                 'map' : {
424                     'name': 'name',
425                     'date': 'date_start',
426                     'duration': call(self.get_float_time, value('duration_hours'), value('duration_minutes')),
427                     'user_id/id':  ref(self.TABLE_USER, 'assigned_user_id'),
428                     'partner_id/id': related_ref(self.TABLE_ACCOUNT),
429                     'partner_address_id/id': related_ref(self.TABLE_CONTACT),
430                     'categ_id/id': call(self.get_category, 'crm.phonecall', value('direction')),
431                     'opportunity_id/id': related_ref(self.TABLE_OPPORTUNITY),
432                     'description': ppconcat('description'),   
433                     'state': map_val('status', self.call_state)                      
434                 }
435             }       
436          
437     """
438         import meeting
439     """
440     meeting_state = {
441             'Planned' : 'draft',
442             'Held': 'open',
443             'Not Held': 'draft', 
444         }
445 #TODO    
446     def get_attendee_id(self, cr, uid, module_name, module_id):
447         contact_id = False
448         user_id = False
449         attendee_id= []
450         attendee_dict = sugar.user_get_attendee_list(self.context.get('port'), self.context.get('session_id'), module_name, module_id)
451         for attendee in attendee_dict:
452             user_id = self.xml_id_exist(self.TABLE_USER, attendee.get('id', False))
453             if user_id:
454                 contact_id = False
455             else:    
456                 contact_id = self.xml_id_exist(self.TABLE_CONTACT, attendee.get('id', False))
457             fields = ['user_id/id', 'email', 'partner_address_id/id']
458             data = [user_id or False, attendee.get('email1'), contact_id]
459             attendee_xml_id = self.import_object(fields, data, 'calendar.attendee', self.TABLE_ATTENDEE, user_id or contact_id or attendee.get('email1'), ['|',('user_id', '=', attendee.get('id')),('partner_address_id','=',attendee.get('id')),('email', '=', attendee.get('email1'))])
460             attendee_id.append(attendee_xml_id)
461         return ','.join(attendee_id) 
462     
463     def get_alarm_id(self, dict_val, val):
464         alarm_dict = {
465             '60': '1 minute before',
466             '300': '5 minutes before',
467             '600': '10 minutes before',
468             '900': '15 minutes before',
469             '1800':'30 minutes before',
470             '3600': '1 hour before',
471         }
472         return self.mapped_id_if_exist('res.alarm', [('name', 'like', alarm_dict.get(val))], 'alarm', val)
473     
474     #TODO attendees
475
476     def import_meeting(self, val):
477         attendee_id = self.get_attendee_id(self.cr, self.uid, 'Meetings', val.get('id')) #TODO
478         val['attendee_ids/id'] = attendee_id
479         return val
480
481     def get_meeting_mapping(self):
482         return { 
483                 'model' : 'crm.meeting',
484                 'dependencies' : [self.TABLE_CONTACT, self.TABLE_OPPORTUNITY, self.TABLE_LEAD, self.TABLE_TASK],
485                 'hook': self.import_meeting,
486                 'map' : {
487                     'name': 'name',
488                     'date': 'date_start',
489                     'duration': call(self.get_float_time, value('duration_hours'), value('duration_minutes')),
490                     'location': 'location',
491                     'attendee_ids/id':'attendee_ids/id',
492                     'alarm_id/id': call(self.get_alarm_id, value('reminder_time')),
493                     'user_id/id': ref(self.TABLE_USER, 'assigned_user_id'),
494                     'partner_id/id': related_ref(self.TABLE_ACCOUNT),
495                     'partner_address_id/id': related_ref(self.TABLE_CONTACT),
496                     'state': map_val('status', self.meeting_state)
497                 }
498             }
499     
500     """
501         import Opportunity
502     """
503     opp_state = {
504             'Need Analysis' : 'New',
505             'Closed Lost': 'Lost',
506             'Closed Won': 'Won', 
507             'Value Proposition': 'Proposition',
508             'Negotiation/Review': 'Negotiation'
509         }
510         
511     def get_opportunity_status(self, sugar_val):
512         fields = ['name', 'type']
513         name = 'Opportunity_' + sugar_val['sales_stage']
514         data = [sugar_val['sales_stage'], 'Opportunity']
515         return self.import_object(fields, data, 'crm.case.stage', self.TABLE_STAGE, name, [('type', '=', 'opportunity'), ('name', 'ilike', sugar_val['sales_stage'])])
516     
517     def import_opportunity_contact(self, val):
518         sugar_opportunities_contact = set(sugar.relation_search(self.context.get('port'), self.context.get('session_id'), 'Opportunities', module_id=val.get('id'), related_module='Contacts', query=None, deleted=None))
519             
520         partner_contact_id = False 
521         partner_contact_email = False       
522         partner_address_obj = self.obj.pool.get('res.partner.address')
523         partner_xml_id = self.name_exist(self.TABLE_ACCOUNT, val['account_name'], 'res.partner')
524         
525         for contact in sugar_opportunities_contact:
526             address_id = self.get_mapped_id(self.TABLE_CONTACT, contact)
527             if address_id:                    
528                 address = partner_address_obj.browse(self.cr, self.uid, address_id)
529                 partner_name = address.partner_id and address.partner_id.name or False
530                 if not partner_name: #link with partner id 
531                     fields = ['partner_id/id']
532                     data = [partner_xml_id]
533                     self.import_object(fields, data, 'res.partner.address', self.TABLE_CONTACT, contact, self.DO_NOT_FIND_DOMAIN)
534                 if not partner_name or partner_name == val.get('account_name'):
535                     partner_contact_id = self.xml_id_exist(self.TABLE_CONTACT, contact)
536                     partner_contact_email = address.email
537         return partner_contact_id, partner_contact_email
538
539     def import_opp(self, val):    
540         partner_contact_id, partner_contact_email = self.import_opportunity_contact(val)
541         val['partner_address_id/id'] = partner_contact_id
542         val['email_from'] = partner_contact_email
543         return val
544     
545     def get_opp_mapping(self):
546         return {
547             'model' : 'crm.lead',
548             'dependencies' : [self.TABLE_USER, self.TABLE_ACCOUNT, self.TABLE_CONTACT,self.TABLE_COMPAIGN],
549             'hook' : self.import_opp,
550             'map' :  {
551                 'name': 'name',
552                 'probability': 'probability',
553                 'partner_id/id': refbyname(self.TABLE_ACCOUNT, 'account_name', 'res.partner'),
554                 'title_action': 'next_step',
555                 'partner_address_id/id': 'partner_address_id/id',
556                 'planned_revenue': 'amount',
557                 'date_deadline': 'date_closed',
558                 'user_id/id' : ref(self.TABLE_USER, 'assigned_user_id'),
559                 'stage_id/id' : self.get_opportunity_status,
560                 'type' : const('opportunity'),
561                 'categ_id/id': call(self.get_category, 'crm.lead', value('opportunity_type')),
562                 'email_from': 'email_from',
563                 'state': map_val('status', self.opp_state)  , #TODO
564             }
565         }
566         
567     """
568     import campaign
569     """
570     
571     def get_compaign_mapping(self):
572         return {
573             'model' : 'crm.case.resource.type',
574             'map' : {
575                 'name': 'name',
576                 } 
577         }    
578         
579     """
580         import lead
581     """
582     def get_lead_status(self, sugar_val):
583         fields = ['name', 'type']
584         name = 'lead_' + sugar_val.get('status', '')
585         data = [sugar_val.get('status', ''), 'lead']
586         return self.import_object(fields, data, 'crm.case.stage', self.TABLE_STAGE, name, [('type', '=', 'lead'), ('name', 'ilike', sugar_val.get('status', ''))])
587
588     lead_state = {
589         'New' : 'draft',
590         'Assigned':'open',
591         'In Progress': 'open',
592         'Recycled': 'cancel',
593         'Dead': 'done',
594         'Converted': 'done',
595     }
596
597     
598     def import_lead(self, val):
599         if val.get('opportunity_id'): #if lead is converted into opp, don't import as lead
600             return False
601         if val.get('primary_address_country'):
602             country_id = self.get_all_countries(val.get('primary_address_country'))
603             val['country_id/id'] =  country_id
604             val['state_id/id'] =  self.get_all_states(val.get('primary_address_state'), country_id)
605         return val
606     
607     def get_lead_mapping(self):
608         return {
609             'model' : 'crm.lead',
610             'dependencies' : [self.TABLE_COMPAIGN, self.TABLE_USER],
611             'hook' : self.import_lead,
612             'map' : {
613                 'name': concat('first_name', 'last_name'),
614                 'contact_name': concat('first_name', 'last_name'),
615                 'description': ppconcat('description', 'refered_by', 'lead_source', 'lead_source_description', 'website', 'email2', 'status_description', 'lead_source_description', 'do_not_call'),
616                 'partner_name': 'account_name',
617                 'email_from': 'email1',
618                 'phone': 'phone_work',
619                 'mobile': 'phone_mobile',
620                 'title/id': call(self.get_job_title, value('salutation')),
621                 'function':'title',
622                 'street': 'primary_address_street',
623                 'street2': 'alt_address_street',
624                 'zip': 'primary_address_postalcode',
625                 'city':'primary_address_city',
626                 'user_id/id' : ref(self.TABLE_USER, 'assigned_user_id'),
627                 'stage_id/id' : self.get_lead_status,
628                 'type' : const('lead'),
629                 'state': map_val('status', self.lead_state) ,
630                 'fax': 'phone_fax',
631                 'referred': 'refered_by',
632                 'optout': 'do_not_call',
633                 'channel_id/id': call(self.get_channel_id, value('lead_source')),
634                 'type_id/id': ref(self.TABLE_COMPAIGN, 'campaign_id'),
635                 'country_id/id': 'country_id/id',
636                 'state_id/id': 'state_id/id'
637                 } 
638         }
639     
640     """
641         import contact
642     """
643     def import_contact(self, val):
644         if val.get('primary_address_country'):
645             country_id = self.get_all_countries(val.get('primary_address_country'))
646             state = self.get_all_states(val.get('primary_address_state'), country_id)
647             val['country_id/id'] =  country_id
648             val['state_id/id'] =  state
649         return val    
650         
651     def get_contact_mapping(self):
652         return { 
653             'model' : 'res.partner.address',
654             'dependencies' : [self.TABLE_ACCOUNT],
655             'hook' : self.import_contact,
656             'map' :  {
657                 'name': concat('first_name', 'last_name'),
658                 'partner_id/id': ref(self.TABLE_ACCOUNT,'account_id'),
659                 'phone': 'phone_work',
660                 'mobile': 'phone_mobile',
661                 'fax': 'phone_fax',
662                 'function': 'title',
663                 'street': 'primary_address_street',
664                 'zip': 'primary_address_postalcode',
665                 'city': 'primary_address_city',
666                 'country_id/id': 'country_id/id',
667                 'state_id/id': 'state_id/id',
668                 'email': concat('email1', 'email2', delimiter=','),
669                 'type': const('contact')
670             }
671         }
672     
673     """ 
674         import Account
675     """
676     def get_address_type(self, val, type):
677         if type == 'invoice':
678             type_address = 'billing'
679         else:
680             type_address = 'shipping'     
681     
682         map_partner_address = {
683             'name': 'name',
684             'phone': 'phone_office',
685             'mobile': 'phone_mobile',
686             'fax': 'phone_fax',
687             'type': 'type',
688             'street': type_address + '_address_street',
689             'zip': type_address +'_address_postalcode',
690             'city': type_address +'_address_city',
691              'country_id/id': 'country_id/id',
692              'type': 'type',
693             }
694         
695         if val.get(type_address +'_address_country'):
696             country_id = self.get_all_countries(val.get(type_address +'_address_country'))
697             state = self.get_all_states(val.get(type_address +'_address_state'), country_id)
698             val['country_id/id'] =  country_id
699             val['state_id/id'] =  state
700         val['type'] = type
701         val['id_new'] = val['id'] + '_address_' + type
702         return self.import_object_mapping(map_partner_address, val, 'res.partner.address', self.TABLE_CONTACT, val['id_new'], self.DO_NOT_FIND_DOMAIN) 
703     
704     def get_partner_address(self, val):
705         address_id=[]
706         type_dict = {'billing_address_street' : 'invoice', 'shipping_address_street' : 'delivery'}
707         for key, type_value in type_dict.items():
708             if val.get(key):
709                 id = self.get_address_type(val, type_value)
710                 address_id.append(id)
711           
712         return ','.join(address_id)
713     
714     def get_partner_mapping(self):
715         return {
716                 'model' : 'res.partner',
717                 'dependencies' : [self.TABLE_USER],
718                 'map' : {
719                     'name': 'name',
720                     'website': 'website',
721                     'user_id/id': ref(self.TABLE_USER,'assigned_user_id'),
722                     'ref': 'sic_code',
723                     'comment': ppconcat('description', 'employees', 'ownership', 'annual_revenue', 'rating', 'industry', 'ticker_symbol'),
724                     'customer': const('1'),
725                     'supplier': const('0'),
726                     'address/id':'address/id', 
727                     'parent_id/id_parent' : ref(self.TABLE_ACCOUNT,'parent_id'),
728                     'address/id' : self.get_partner_address,
729                 }
730         }
731
732     """
733         import Employee
734     """
735     def get_ressource(self, val):
736         map_resource = { 
737             'name': concat('first_name', 'last_name'),
738         }        
739         return self.import_object_mapping(map_resource, val, 'resource.resource', self.TABLE_RESSOURCE, val['id'], self.DO_NOT_FIND_DOMAIN)
740     
741     def get_job_id(self, val):
742         fields = ['name']
743         data = [val.get('title')]
744         return self.import_object(fields, data, 'hr.job', 'hr_job', val.get('title'))
745
746     def get_user_address(self, val):
747         map_user_address = {
748             'name': concat('first_name', 'last_name'),
749             'city': 'address_city',
750             'country_id/id': 'country_id/id',
751             'state_id/id': 'state_id/id',
752             'street': 'address_street',
753             'zip': 'address_postalcode',
754             'fax': 'phone_fax',
755             'phone': 'phone_work',
756             'mobile':'phone_mobile',
757             'email': 'email1'
758         }
759         
760         if val.get('address_country'):
761             country_id = self.get_all_countries(val.get('address_country'))
762             state_id = self.get_all_states(val.get('address_state'), country_id)
763             val['country_id/id'] =  country_id
764             val['state_id/id'] =  state_id
765             
766         return self.import_object_mapping(map_user_address, val, 'res.partner.address', self.TABLE_CONTACT, val['id'], self.DO_NOT_FIND_DOMAIN)
767
768     def get_employee_mapping(self):
769         return {
770             'model' : 'hr.employee',
771             'dependencies' : [self.TABLE_USER],
772             'map' : {
773                 'resource_id/id': self.get_ressource, 
774                 'name': concat('first_name', 'last_name'),
775                 'work_phone': 'phone_work',
776                 'mobile_phone':  'phone_mobile',
777                 'user_id/id': ref(self.TABLE_USER, 'id'), 
778                 'address_home_id/id': self.get_user_address,
779                 'notes': ppconcat('messenger_type', 'messenger_id', 'description'),
780                 'job_id/id': self.get_job_id,
781                 'work_email' : 'email1',
782                 'coach_id/id_parent' : 'reports_to_id',
783             }
784      }
785     
786     """
787         import user
788     """  
789     def import_user(self, val):
790         user_obj = self.obj.pool.get('res.users')
791         user_ids = user_obj.search(self.cr, self.uid, [('login', '=', val.get('user_name'))])
792         if user_ids: 
793             val['.id'] = str(user_ids[0])
794         else:
795             val['password'] = 'sugarcrm' #default password for all user #TODO needed in documentation
796             
797         val['context_lang'] = self.context.get('lang','en_US')
798         return val
799     
800     def get_users_department(self, val):
801         dep = val.get('department')
802         fields = ['name']
803         data = [dep]
804         if not dep:
805             return False
806         return self.import_object(fields, data, 'hr.department', 'hr_department_user', dep)
807
808     def get_user_mapping(self):
809         return {
810             'model' : 'res.users',
811             'hook' : self.import_user,
812             'map' : { 
813                 'name': concat('first_name', 'last_name'),
814                 'login': 'user_name',
815                 'context_lang' : 'context_lang',
816                 'password' : 'password',
817                 '.id' : '.id',
818                 'context_department_id/id': self.get_users_department,
819                 'user_email' : 'email1',
820             }
821         }
822
823
824     def get_mapping(self):
825         return {
826             self.TABLE_USER : self.get_user_mapping(),
827             self.TABLE_EMPLOYEE : self.get_employee_mapping(),
828             self.TABLE_ACCOUNT : self.get_partner_mapping(),
829             self.TABLE_CONTACT : self.get_contact_mapping(),
830             self.TABLE_LEAD : self.get_lead_mapping(),
831             self.TABLE_OPPORTUNITY : self.get_opp_mapping(),
832             self.TABLE_MEETING : self.get_meeting_mapping(),
833             self.TABLE_CALL : self.get_calls_mapping(),
834             self.TABLE_TASK : self.get_task_mapping(),
835             self.TABLE_PROJECT : self.get_project_mapping(),
836             self.TABLE_PROJECT_TASK: self.get_project_task_mapping(),
837             self.TABLE_BUG: self.get_project_issue_mapping(),
838             self.TABLE_CASE: self.get_crm_claim_mapping(),
839             self.TABLE_NOTE: self.get_history_mapping(),
840             self.TABLE_EMAIL: self.get_email_mapping(),
841             self.TABLE_COMPAIGN: self.get_compaign_mapping()
842         }
843         
844     """
845         Email notification
846     """   
847     def get_email_subject(self, result):
848         return "your sugarcrm data were successfully imported at %s" % self.date_ended 
849     
850     def get_body_header(self, result):
851         return "Sugarcrm import : report of last import" 
852
853
854 class import_sugarcrm(osv.osv):
855     """Import SugarCRM DATA"""
856     
857     _name = "import.sugarcrm"
858     _description = __doc__
859     _columns = {
860                
861         'username': fields.char('User Name', size=64, required=True),
862         'password': fields.char('Password', size=24,required=True),
863          'url' : fields.char('SugarSoap Api url:', size=264, required=True, help="Webservice's url where to get the data.\
864                       'exemple : http://example.com/sugarcrm/soap.php, or copy the address of your sugarcrm application http://trial.sugarcrm.com/qbquyj4802/index.php?module=Home&action=index"),
865                 
866         'opportunity': fields.boolean('Leads and Opportunities', help="If Opportunities are checked, SugarCRM opportunities data imported in OpenERP crm-Opportunity form"),
867         'contact': fields.boolean('Contacts', help="If Contacts are checked, SugarCRM Contacts data imported in OpenERP partner address form"),
868         'account': fields.boolean('Accounts', help="If Accounts are checked, SugarCRM  Accounts data imported in OpenERP partners form"),
869         'employee': fields.boolean('Employee', help="If Employees is checked, SugarCRM Employees data imported in OpenERP employees form"),
870         'meeting': fields.boolean('Meetings', help="If Meetings is checked, SugarCRM Meetings and Meeting Tasks data imported in OpenERP meetings form"),
871         'call': fields.boolean('Calls', help="If Calls is checked, SugarCRM Calls data imported in OpenERP phonecalls form"),
872         'claim': fields.boolean('Cases', help="If Cases is checked, SugarCRM Cases data imported in OpenERP Claims form"),
873         'email_history': fields.boolean('Email and History',help="If Email and History is checked, SugarCRM Notes and Emails data imported in OpenERP's Related module's History with attachment"),
874         'project': fields.boolean('Projects', help="If Projects is checked, SugarCRM Projects data imported in OpenERP Projects form"),
875         'project_task': fields.boolean('Project Tasks', help="If Project Tasks is checked, SugarCRM Project Tasks data imported in OpenERP Project Tasks form"),
876         'bug': fields.boolean('Bugs', help="If Bugs is checked, SugarCRM Bugs data imported in OpenERP Project Issues form"),
877         'email_from': fields.char('Notify End Of Import To:', size=128),
878         'instance_name': fields.char("Instance's Name", size=64, help="Prefix of SugarCRM id to differentiate xml_id of SugarCRM models datas come from different server."),
879         
880     }
881     _defaults = {#to be set to true, but easier for debugging
882        'opportunity': False,
883        'contact' : False,
884        'account' : False,
885         'employee' : False,
886         'meeting' : False,
887         'call' : False,
888         'claim' : False,    
889         'email_history' : False, 
890         'project' : False,   
891         'project_task': False,     
892         'bug': False,
893         'instance_name': 'sugarcrm',
894         'email_from': 'tfr@openerp.com',
895         'username' : 'tfr',
896         'password' : 'a',
897         'url':  "http://example.com/sugarcrm/soap.php"        
898     }
899     def get_key(self, cr, uid, ids, context=None):
900         """Select Key as For which Module data we want import data."""
901         if not context:
902             context = {}
903         key_list = []
904         for current in self.browse(cr, uid, ids, context):
905             context.update({'username': current.username, 'password': current.password, 'url': current.url, 'email_user': current.email_from or False, 'instance_name': current.instance_name or False})
906             if current.opportunity:
907                 key_list.append('Leads')
908                 key_list.append('Opportunities')
909             if current.contact:
910                 key_list.append('Contacts')
911             if current.account:
912                 key_list.append('Accounts') 
913             if current.employee:
914                 key_list.append('Employees')  
915             if current.meeting:
916                 key_list.append('Meetings')
917             if current.call:
918                 key_list.append('Calls')
919             if current.claim:
920                 key_list.append('Cases')                
921             if current.email_history:
922                 key_list.append('Emails') 
923                 key_list.append('Notes') 
924             if current.project:
925                 key_list.append('Project')
926             if current.project_task:
927                 key_list.append('ProjectTask')
928             if current.bug:
929                 key_list.append('Bugs')
930         return key_list
931
932
933     def do_import_all(self, cr, uid, *args):
934         """
935         scheduler Method
936         """
937         context = {'username': args[4], 'password': args[5], 'url': args[3], 'instance_name': args[3]}
938         imp = sugar_import(self, cr, uid, args[2], "import_sugarcrm", [args[1]], context)
939         imp.set_table_list(args[0])
940         imp.start()
941         return True 
942
943     def import_from_scheduler_all(self, cr, uid, ids, context=None):
944         keys = self.get_key(cr, uid, ids, context)
945         if not keys:
946             raise osv.except_osv(_('Warning !'), _('Select Module to Import.'))
947         cron_obj = self.pool.get('ir.cron')
948         args = (keys,context.get('email_user'), context.get('instance_name'), context.get('url'), context.get('username'), context.get('password') )
949         new_create_id = cron_obj.create(cr, uid, {'name': 'Import SugarCRM datas','interval_type': 'hours','interval_number': 1, 'numbercall': -1,'model': 'import.sugarcrm','function': 'do_import_all', 'args': args, 'active': False})
950         return {
951             'name': 'SugarCRM Scheduler',
952             'view_type': 'form',
953             'view_mode': 'form,tree',
954             'res_model': 'ir.cron',
955             'res_id': new_create_id,
956             'type': 'ir.actions.act_window',
957         }
958     
959     def import_all(self, cr, uid, ids, context=None):
960         
961 #        """Import all sugarcrm data into openerp module"""
962         keys = self.get_key(cr, uid, ids, context)
963         imp = sugar_import(self, cr, uid, context.get('instance_name'), "import_sugarcrm", [context.get('email_user')], context)
964         imp.set_table_list(keys)
965         imp.start()
966         
967         obj_model = self.pool.get('ir.model.data')
968         model_data_ids = obj_model.search(cr,uid,[('model','=','ir.ui.view'),('name','=','import.message.form')])
969         resource_id = obj_model.read(cr, uid, model_data_ids, fields=['res_id'])
970         return {
971                 'view_type': 'form',
972                 'view_mode': 'form',
973                 'res_model': 'import.message',
974                 'views': [(resource_id,'form')],
975                 'type': 'ir.actions.act_window',
976                 'target': 'new',
977             }
978         
979 import_sugarcrm()