diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 788903ce083..22687965701 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -335,7 +335,7 @@ class crm_lead(crm_case, osv.osv): return self.set_priority(cr, uid, ids, '3') - def _merge_data(self, cr, uid, ids, oldest, context=None): + def _merge_data(self, cr, uid, ids, oldest, fields, context=None): # prepare opportunity data into dictionary for merging opportunities = self.browse(cr, uid, ids, context=context) def _get_first_not_null(attr): @@ -353,40 +353,20 @@ class crm_lead(crm_case, osv.osv): def _concat_all(attr): return ', '.join([getattr(opportunity, attr) or '' for opportunity in opportunities if hasattr(opportunity, attr)]) - data = { - 'partner_id': _get_first_not_null_id('partner_id'), # !! - 'title': _get_first_not_null_id('title'), - 'name' : _get_first_not_null('name'), #not lost - 'categ_id' : _get_first_not_null_id('categ_id'), # !! - 'channel_id' : _get_first_not_null_id('channel_id'), # !! - 'city' : _get_first_not_null('city'), # !! - 'company_id' : _get_first_not_null_id('company_id'), #!! - 'contact_name' : _get_first_not_null('contact_name'), #not lost - 'country_id' : _get_first_not_null_id('country_id'), #!! - 'partner_address_id' : _get_first_not_null_id('partner_address_id'), #!! - 'type_id' : _get_first_not_null_id('type_id'), #!! - 'user_id' : _get_first_not_null_id('user_id'), #!! - 'section_id' : _get_first_not_null_id('section_id'), #!! - 'state_id' : _get_first_not_null_id('state_id'), - 'description' : _concat_all('description'), #not lost - 'email' : _get_first_not_null('email'), # !! - 'fax' : _get_first_not_null('fax'), - 'mobile' : _get_first_not_null('mobile'), - 'partner_name' : _get_first_not_null('partner_name'), - 'phone' : _get_first_not_null('phone'), - 'probability' : _get_first_not_null('probability'), - 'planned_revenue' : _get_first_not_null('planned_revenue'), - 'street' : _get_first_not_null('street'), - 'street2' : _get_first_not_null('street2'), - 'zip' : _get_first_not_null('zip'), - 'state' : 'open', - 'create_date' : _get_first_not_null('create_date'), - 'date_action_last': _get_first_not_null('date_action_last'), - 'date_action_next': _get_first_not_null('date_action_next'), - 'email_from' : _get_first_not_null('email_from'), - 'email_cc' : _get_first_not_null('email_cc'), - 'partner_name' : _get_first_not_null('partner_name'), - } + data = {} + for field_name in fields: + field_info = self._all_columns.get(field_name) + if field_info is None: + continue + field = field_info.column + if field._type in ('many2many', 'one2many'): + continue + elif field._type == 'many2one': + data[field_name] = _get_first_not_null_id(field_name) # !! + elif field._type == 'text': + data[field_name] = _concat_all(field_name) #not lost + else: + data[field_name] = _get_first_not_null(field_name) #not lost return data def _merge_find_oldest(self, cr, uid, ids, context=None): @@ -401,35 +381,45 @@ class crm_lead(crm_case, osv.osv): oldest_id = opportunity_ids[0] return self.browse(cr, uid, oldest_id, context=context) + def _mail_body_text(self, cr, uid, lead, fields, title=False, context=None): + body = [] + if title: + body.append("%s\n" % (title)) + for field_name in fields: + field_info = self._all_columns.get(field_name) + if field_info is None: + continue + field = field_info.column + value = None + + if field._type == 'selection': + if hasattr(field.selection, '__call__'): + key = field.selection(self, cr, uid, context=context) + else: + key = field.selection + value = dict(key).get(lead[field_name], lead[field_name]) + elif field._type == 'many2one': + if lead[field_name]: + value = lead[field_name].name_get()[0][1] + else: + value = lead[field_name] + + body.append("%s: %s\n" % (field.string, value or '')) + return "\n".join(body + ['---']) + def _merge_notification(self, cr, uid, opportunity_id, opportunities, context=None): #TOFIX: mail template should be used instead of fix body, subject text details = [] merge_message = _('Merged opportunities') subject = [merge_message] + fields = ['name', 'partner_id', 'stage_id', 'section_id', 'user_id', 'categ_id', 'channel_id', 'company_id', 'contact_name', + 'email_from', 'phone', 'fax', 'mobile', 'state_id', 'description', 'probability', 'planned_revenue', + 'country_id', 'city', 'street', 'street2', 'zip'] for opportunity in opportunities: subject.append(opportunity.name) - details.append(_('%s : %s\n Partner: %s\n Stage: %s\n Section: %s\n Salesman: %s\n Category: %s\n Channel: %s\n Company: %s\n Contact name: %s\n Email: %s\n Phone number: %s\n Fax: %s\n Mobile: %s\n State: %s\n Description: %s\n Probability: %s\n Planned revennue: %s\n Country: %s\n City: %s\n Street: %s\n Street 2: %s\n Zip 2: %s') % (merge_message, opportunity.name, opportunity.partner_id.name or '', - opportunity.stage_id.name or '', - opportunity.section_id.name or '', - opportunity.user_id.name or '', - opportunity.categ_id.name or '', - opportunity.channel_id.name or '', - opportunity.company_id.name or '', - opportunity.contact_name or '', - opportunity.email_from or '', - opportunity.phone or '', - opportunity.fax or '', - opportunity.mobile or '', - opportunity.state_id.name or '', - opportunity.description or '', - opportunity.probability or '', - opportunity.planned_revenue or '', - opportunity.country_id.name or '', - opportunity.city or '', - opportunity.street or '', - opportunity.street2 or '', - opportunity.zip or '', - )) + title = "%s : %s" % (merge_message, opportunity.name) + details.append(self._mail_body_text(cr, uid, opportunity, fields, title=title, context=context)) + subject = subject[0] + ", ".join(subject[1:]) details = "\n\n".join(details) return self.message_append(cr, uid, [opportunity_id], subject, body_text=details, context=context) @@ -493,7 +483,12 @@ class crm_lead(crm_case, osv.osv): first_opportunity = opportunities_list[0] tail_opportunities = opportunities_list[1:] - data = self._merge_data(cr, uid, ids, oldest, context=context) + fields = ['partner_id', 'title', 'name', 'categ_id', 'channel_id', 'city', 'company_id', 'contact_name', 'country_id', + 'partner_address_id', 'type_id', 'user_id', 'section_id', 'state_id', 'description', 'email', 'fax', 'mobile', + 'partner_name', 'phone', 'probability', 'planned_revenue', 'street', 'street2', 'zip', 'create_date', 'date_action_last', + 'date_action_next', 'email_from', 'email_cc', 'partner_name'] + + data = self._merge_data(cr, uid, ids, oldest, fields, context=context) # merge data into first opportunity self.write(cr, uid, [first_opportunity.id], data, context=context) @@ -507,6 +502,8 @@ class crm_lead(crm_case, osv.osv): #delete tail opportunities self.unlink(cr, uid, [x.id for x in tail_opportunities], context=context) + #open first opportunity + self.case_open(cr, uid, [first_opportunity.id]) return first_opportunity.id def _convert_opportunity_data(self, cr, uid, lead, customer, section_id=False, context=None): @@ -571,9 +568,17 @@ class crm_lead(crm_case, osv.osv): }) return partner_id - def _lead_assign_partner(self, cr, uid, ids, partner_id, context=None): - contact_id = self.pool.get('res.partner').address_get(cr, uid, [partner_id])['default'] - return self.write(cr, uid, ids, {'partner_id' : partner_id, 'partner_address_id': contact_id}, context=context) + def assign_partner(self, cr, uid, ids, partner_id=None, context=None): + res = False + res_partner = self.pool.get('res.partner') + if partner_id: + contact_id = res_partner.address_get(cr, uid, [partner_id])['default'] + res = self.write(cr, uid, ids, {'partner_id' : partner_id, 'partner_address_id': contact_id}, context=context) + partner = res_partner.browse(cr, uid, partner_id, context=context) + if partner.user_id: + for lead_id in ids: + self.allocate_salesman(cr, uid, [lead_id], [partner.user_id.id], context=context) + return res def _lead_create_partner_address(self, cr, uid, lead, partner_id, context=None): address = self.pool.get('res.partner.address') @@ -609,7 +614,7 @@ class crm_lead(crm_case, osv.osv): if not partner_id: partner_id = self._lead_create_partner(cr, uid, lead, context=context) self._lead_create_partner_address(cr, uid, lead, partner_id, context=context) - self._lead_assign_partner(cr, uid, [lead.id], partner_id, context=context) + self.assign_partner(cr, uid, [lead.id], partner_id, context=context) partner_ids[lead.id] = partner_id return partner_ids diff --git a/addons/crm_partner_assign/__openerp__.py b/addons/crm_partner_assign/__openerp__.py index 0b9e14c29bf..1752c52f839 100644 --- a/addons/crm_partner_assign/__openerp__.py +++ b/addons/crm_partner_assign/__openerp__.py @@ -38,6 +38,9 @@ You can also use the geolocalization without using the GPS coordinates. """, 'author': 'OpenERP SA', 'depends': ['crm'], + 'demo_xml': [ + 'res_partner_demo.xml', + ], 'update_xml': [ 'security/ir.model.access.csv', 'res_partner_view.xml', @@ -46,8 +49,9 @@ You can also use the geolocalization without using the GPS coordinates. 'report/crm_lead_report_view.xml', 'report/crm_partner_report_view.xml', ], - 'test': ['test/process/partner_assign.yml', - 'test/ui/partner_assign_form.yml'], + 'test': [ + 'test/process/partner_assign.yml', + ], 'installable': True, 'active': False, 'certificate': '00503409558942442061', diff --git a/addons/crm_partner_assign/partner_geo_assign.py b/addons/crm_partner_assign/partner_geo_assign.py index 2b67f80c066..1e7168f1427 100644 --- a/addons/crm_partner_assign/partner_geo_assign.py +++ b/addons/crm_partner_assign/partner_geo_assign.py @@ -24,22 +24,25 @@ from osv import fields import urllib,re import random, time from tools.translate import _ +import tools def geo_find(addr): + addr = addr.encode('utf8') + regex = '([+-]?[0-9\.]+),([+-]?[0-9\.]+),([+-]?[0-9\.]+)' + url = 'http://maps.google.com/maps/geo?q=' + urllib.quote(addr) + '&output=xml&oe=utf8&sensor=false' try: - regex = '([+-]?[0-9\.]+),([+-]?[0-9\.]+),([+-]?[0-9\.]+)' - url = 'http://maps.google.com/maps/geo?q=' + urllib.quote(addr) + '&output=xml&oe=utf8&sensor=false' xml = urllib.urlopen(url).read() - if '' in xml: - return None - result = re.search(regex, xml, re.M|re.I) - if not result: - return None - return float(result.group(2)),float(result.group(1)) except Exception, e: raise osv.except_osv(_('Network error'), _('Could not contact geolocation servers, please make sure you have a working internet connection (%s)') % e) + if '' in xml: + return None + result = re.search(regex, xml, re.M|re.I) + if not result: + return None + return float(result.group(2)),float(result.group(1)) + class res_partner_grade(osv.osv): _order = 'sequence' @@ -74,9 +77,13 @@ class res_partner(osv.osv): for partner in self.browse(cr, uid, ids, context=context): if not partner.address: continue - part = partner.address[0] - addr = ', '.join(filter(None, [part.street, (part.zip or '')+' '+(part.city or ''), part.state_id and part.state_id.name, part.country_id and part.country_id.name])) - result = geo_find(addr.encode('utf8')) + contact = partner.address[0] #TOFIX: should be get latitude and longitude for default contact? + addr = ', '.join(filter(None, [ + contact.street, + "%s %s" % (contact.zip , contact.city), + contact.state_id and contact.state_id.name, + contact.country_id and contact.country_id.name])) + result = geo_find(tools.ustr(addr)) if result: self.write(cr, uid, [partner.id], { 'partner_latitude': result[0], @@ -94,14 +101,13 @@ class crm_lead(osv.osv): 'partner_assigned_id': fields.many2one('res.partner', 'Assigned Partner', help="Partner this case has been forwarded/assigned to.", select=True), 'date_assign': fields.date('Assignation Date', help="Last date this case was forwarded/assigned to a partner"), } + def _merge_data(self, cr, uid, ids, oldest, fields, context=None): + fields += ['partner_latitude', 'partner_longitude', 'partner_assigned_id', 'date_assign'] + return super(crm_lead, self)._merge_data(cr, uid, ids, oldest, fields, context=context) + def onchange_assign_id(self, cr, uid, ids, partner_assigned_id, context=None): """This function updates the "assignation date" automatically, when manually assign a partner in the geo assign tab - @param self: The object pointer - @param cr: the current row, from the database cursor, - @param uid: the current user’s ID for security checks, - @param ids: List of stage’s IDs - @stage_id: change state id on run time """ - + """ if not partner_assigned_id: return {'value':{'date_assign': False}} else: @@ -112,72 +118,102 @@ class crm_lead(osv.osv): 'user_id' : user_id} } - def assign_partner(self, cr, uid, ids, context=None): - ok = False - for part in self.browse(cr, uid, ids, context=context): - if not part.country_id: - continue - addr = ', '.join(filter(None, [part.street, (part.zip or '')+' '+(part.city or ''), part.state_id and part.state_id.name, part.country_id and part.country_id.name])) - result = geo_find(addr.encode('utf8')) - if result: - self.write(cr, uid, [part.id], { - 'partner_latitude': result[0], - 'partner_longitude': result[1] - }, context=context) + def assign_partner(self, cr, uid, ids, partner_id=None, context=None): + partner_ids = {} + res = False + if partner_id is None: + partner_ids = self.search_geo_partner(cr, uid, ids, context=context) + for lead in self.browse(cr, uid, ids, context=context): + if not partner_id: + partner_id = partner_ids.get(lead.id, False) + res = super(crm_lead, self).assign_partner(cr, uid, [lead.id], partner_id, context=context) + self.write(cr, uid, [lead.id], {'date_assign': time.strftime('%Y-%m-%d'), 'partner_assigned_id': partner_id}, context=context) + return res + + def assign_geo_localize(self, cr, uid, ids, latitude=False, longitude=False, context=None): + for lead in self.browse(cr, uid, ids, context=context): + if not lead.country_id: + continue + addr = ', '.join(filter(None, [ + lead.street, + "%s %s" % (lead.zip, lead.city), + lead.state_id and lead.state_id.name or '', + lead.country_id and lead.country_id.name or '' + ])) + result = geo_find(tools.ustr(addr)) + if not latitude and result: + latitude = result[0] + if not longitude and result: + longitude = result[1] + self.write(cr, uid, [lead.id], { + 'partner_latitude': latitude, + 'partner_longitude': longitude + }, context=context) + return True + + def search_geo_partner(self, cr, uid, ids, context=None): + res_partner = self.pool.get('res.partner') + res_partner_ids = {} + self.assign_geo_localize(cr, uid, ids, context=context) + for lead in self.browse(cr, uid, ids, context=context): + partner_ids = [] + if not lead.country_id: + continue + latitude = lead.partner_latitude + longitude = lead.partner_longitude + if latitude and longitude: # 1. first way: in the same country, small area - part_ids = self.pool.get('res.partner').search(cr, uid, [ - ('partner_weight','>',0), - ('partner_latitude','>',result[0]-2), ('partner_latitude','<',result[0]+2), - ('partner_longitude','>',result[1]-1.5), ('partner_longitude','<',result[1]+1.5), - ('country', '=', part.country_id.id), + partner_ids = res_partner.search(cr, uid, [ + ('partner_weight', '>', 0), + ('partner_latitude', '>', latitude - 2), ('partner_latitude', '<', latitude + 2), + ('partner_longitude', '>', longitude - 1.5), ('partner_longitude', '<', longitude + 1.5), + ('country', '=', lead.country_id.id), ], context=context) # 2. second way: in the same country, big area - if not part_ids: - part_ids = self.pool.get('res.partner').search(cr, uid, [ - ('partner_weight','>',0), - ('partner_latitude','>',result[0]-4), ('partner_latitude','<',result[0]+4), - ('partner_longitude','>',result[1]-3), ('partner_longitude','<',result[1]+3), - ('country', '=', part.country_id.id), + if not partner_ids: + partner_ids = res_partner.search(cr, uid, [ + ('partner_weight', '>', 0), + ('partner_latitude', '>', latitude - 4), ('partner_latitude', '<', latitude + 4), + ('partner_longitude', '>', longitude - 3), ('partner_longitude', '<' , longitude + 3), + ('country', '=', lead.country_id.id), ], context=context) # 5. fifth way: anywhere in same country - if not part_ids: + if not partner_ids: # still haven't found any, let's take all partners in the country! - part_ids = self.pool.get('res.partner').search(cr, uid, [ - ('partner_weight','>',0), - ('country', '=', part.country_id.id), + partner_ids = partner.search(cr, uid, [ + ('partner_weight', '>', 0), + ('country', '=', lead.country_id.id), ], context=context) # 6. sixth way: closest partner whatsoever, just to have at least one result - if not part_ids: + if not partner_ids: # warning: point() type takes (longitude, latitude) as parameters in this order! cr.execute("""SELECT id, distance FROM (select id, (point(partner_longitude, partner_latitude) <-> point(%s,%s)) AS distance FROM res_partner WHERE partner_longitude is not null AND partner_latitude is not null AND partner_weight > 0) AS d - ORDER BY distance LIMIT 1""", (result[1],result[0])) + ORDER BY distance LIMIT 1""", (longitude, latitude)) res = cr.dictfetchone() if res: - part_ids.append(res['id']) + partner_ids.append(res['id']) - total = 0 + total_weight = 0 toassign = [] - for part2 in self.pool.get('res.partner').browse(cr, uid, part_ids, context=context): - total += part2.partner_weight - toassign.append( (part2.id, total) ) + for partner in res_partner.browse(cr, uid, partner_ids, context=context): + total_weight += partner.partner_weight + toassign.append( (partner.id, total_weight) ) + random.shuffle(toassign) # avoid always giving the leads to the first ones in db natural order! - mypartner = random.randint(0,total) - for t in toassign: - if mypartner<=t[1]: - vals = self.onchange_assign_id(cr,uid, ids, t[0], context=context)['value'] - vals.update({'partner_assigned_id': t[0], 'date_assign': time.strftime('%Y-%m-%d')}) - self.write(cr, uid, [part.id], vals, context=context) + nearest_weight = random.randint(0, total_weight) + for partner_id, weight in toassign: + if nearest_weight <= weight: + res_partner_ids[lead.id] = partner_id break - ok = True - return ok + return res_partner_ids crm_lead() diff --git a/addons/crm_partner_assign/res_partner_demo.xml b/addons/crm_partner_assign/res_partner_demo.xml new file mode 100644 index 00000000000..66ee1fbd5e7 --- /dev/null +++ b/addons/crm_partner_assign/res_partner_demo.xml @@ -0,0 +1,13 @@ + + + + + First + 1 + + + + 10 + + + diff --git a/addons/crm_partner_assign/test/process/partner_assign.yml b/addons/crm_partner_assign/test/process/partner_assign.yml index 43c413fb588..01d771f9ad5 100644 --- a/addons/crm_partner_assign/test/process/partner_assign.yml +++ b/addons/crm_partner_assign/test/process/partner_assign.yml @@ -1,58 +1,38 @@ - In order to test find nearest Partner functionality and assign to opportunity , - so First i create a grade 'First' for partner. - - !record {model: res.partner.grade, id: res_partner_grade_first}: - name: First - sequence: 1 -- - I assign grade 'First' to the partner 'Eric' and give more probability to assign a lead to this partner. -- - !record {model: res.partner, id: base.res_partner_ericdubois0}: - grade_id: res_partner_grade_first - partner_weight: 10 -- - Set Lattitude and Longitude according to partner address. + I Set Geo Lattitude and Longitude according to partner address. - !python {model: res.partner}: | self.geo_localize(cr, uid, [ref('base.res_partner_ericdubois0')], context) +- + I check Geo Lattitude and Longitude of partner after set +- + !python {model: res.partner}: | partner = self.browse(cr, uid, ref('base.res_partner_ericdubois0')) assert partner.partner_latitude == 50.4530495 , "Lattitude is wrong" assert partner.partner_longitude == 3.9693885 , "Longitude is wrong" - - I would like to change the assign partner on opportunity, so find nearest partner assign to this opportunity. + I assign nearest partner to opportunity. - !python {model: crm.lead}: | - res = self.onchange_assign_id(cr, uid, [ref('crm.crm_case_abcfuelcounits0')], ref('base.res_partner_ericdubois0'), context) - assert res['value']['user_id'] == ref('base.user_demo'), "User not correct" - self.assign_partner(cr, uid, [ref('crm.crm_case_abcfuelcounits0')], context) + self.assign_partner(cr, uid, [ref('crm.crm_case_abcfuelcounits0')], context=context) - - In order to assigned partner to opportunity, so i test latitude and longitude of partner of opportunity - and opportuniy assign to assigned partner. + I check assigned partner of opportunity who is nearest Geo Lattitude and Longitude of opportunity. - !python {model: crm.lead}: | - lead = self.browse(cr, uid, [ref('crm.crm_case_abcfuelcounits0')])[0] + lead = self.browse(cr, uid, ref('crm.crm_case_abcfuelcounits0')) + assert lead.partner_assigned_id.id == ref('base.res_partner_ericdubois0') , "Opportuniy is not assigned nearest partner" assert lead.partner_latitude == 50.8495239 , "Lattitude is wrong" assert lead.partner_longitude == 4.3667002 , "Longitude is wrong" - assert lead.partner_assigned_id.id == ref('base.res_partner_ericdubois0') , "Opportuniy not assign partner" + - - Oppportuniry forword to its nearest partner, so first i create record of forword mail -- - !record {model: crm.lead.forward.to.partner, id: crm_lead_forward_to_partner_rec}: - send_to: email - email_from: 'admin@openerp.com' - email_to: 'admin@tinyerp.com' - subject: 'Openerp lead forward' - history: latest -- - I forword this opportunity to its nearest partner. + I forward this opportunity to its nearest partner. - !python {model: crm.lead.forward.to.partner}: | - from tools import config - host = config.get('smtp_user', '127.0.0.1') - assert config.get(host, True), 'SMTP not configured !' + context.update({'active_model': 'crm.lead', 'active_id': ref('crm.crm_case_abcfuelcounits0'), 'active_ids': [ref('crm.crm_case_abcfuelcounits0')]}) + forward_id = self.create(cr, uid, {'send_to': 'partner'}, context=context) try: - self.action_forward(cr, uid, ref("crm_lead_forward_to_partner_rec"), context={'active_id': ref('crm.crm_case_abcfuelcounits0'), - 'active_ids': [ref('crm.crm_case_abcfuelcounits0')], 'active_model': 'crm.lead'}) + self.action_forward(cr, uid, ref("crm_lead_forward_to_partner_rec"), context=context) except: pass diff --git a/addons/crm_partner_assign/test/ui/partner_assign_form.yml b/addons/crm_partner_assign/test/ui/partner_assign_form.yml deleted file mode 100644 index 747297a833c..00000000000 --- a/addons/crm_partner_assign/test/ui/partner_assign_form.yml +++ /dev/null @@ -1,18 +0,0 @@ -- - For onchange on partner , i assign an email address to Administrator user. -- - !record {model: res.users, id: base.user_root}: - user_email: admin@openerp.com - -- - I check onchange on email, partner, history and test the data accordingly change. -- - !python {model: crm.lead.forward.to.partner}: | - context.update({'history': 'latest', 'active_id': ref('crm.crm_case_abcfuelcounits0')}) - email = self.on_change_email(cr, uid, [ref('crm.crm_case_abcfuelcounits0')], ref('base.user_root')) - assert email['value']['email_to'] == "Administrator ", "Email is not correct" - partner = self.on_change_partner(cr, uid, [ref('crm.crm_case_abcfuelcounits0')], ref('base.res_partner_desertic_hispafuentes')) - assert partner['value']['address_id'] == ref('base.res_partner_desertic_hispafuentes'), "Address invalid" - assert partner['value']['email_to'] == 'info@axelor.com', "Email id incorrect" - history = self.on_change_history(cr, uid, [ref('crm.crm_case_abcfuelcounits0')], context.get('history'), context) - assert history, "History is blank" \ No newline at end of file diff --git a/addons/crm_partner_assign/wizard/__init__.py b/addons/crm_partner_assign/wizard/__init__.py index be6c1533722..9224173145b 100644 --- a/addons/crm_partner_assign/wizard/__init__.py +++ b/addons/crm_partner_assign/wizard/__init__.py @@ -20,4 +20,3 @@ ############################################################################## import crm_forward_to_partner -import crm_merge_opportunity diff --git a/addons/crm_partner_assign/wizard/crm_forward_to_partner.py b/addons/crm_partner_assign/wizard/crm_forward_to_partner.py index cdaf8f19b12..29a60ba71ba 100644 --- a/addons/crm_partner_assign/wizard/crm_forward_to_partner.py +++ b/addons/crm_partner_assign/wizard/crm_forward_to_partner.py @@ -24,6 +24,7 @@ import time import re from osv import osv, fields from tools.translate import _ +from mail.mail_message import to_email class crm_lead_forward_to_partner(osv.osv_memory): """Forwards lead history""" @@ -46,48 +47,8 @@ class crm_lead_forward_to_partner(osv.osv_memory): } - def get_whole_history(self, cr, uid, ids, context=None): - """This function gets whole communication history and returns as top posting style - @param self: The object pointer - @param cr: the current row, from the database cursor, - @param uid: the current user’s ID for security checks, - @param ids: List of history IDs - @param context: A standard dictionary for contextual values - """ - whole = [] - for hist_id in ids: - whole.append(self.get_latest_history(cr, uid, hist_id, context=context)) - whole = '\n\n'.join(whole) - return whole or '' - - def get_latest_history(self, cr, uid, hist_id, context=None): - """This function gets latest communication and returns as top posting style - @param self: The object pointer - @param cr: the current row, from the database cursor, - @param uid: the current user’s ID for security checks, - @param hist_id: Id of latest history - @param context: A standard dictionary for contextual values - """ - log_pool = self.pool.get('mail.message') - hist = log_pool.browse(cr, uid, hist_id, context=context) - header = '-------- Original Message --------' - sender = 'From: %s' %(hist.email_from or '') - to = 'To: %s' % (hist.email_to or '') - sentdate = 'Date: %s' % (hist.date or '') - desc = '\n%s'%(hist.body_text) - original = [header, sender, to, sentdate, desc] - original = '\n'.join(original) - return original - + def on_change_email(self, cr, uid, ids, user): - """This function fills email information based on user selected - @param self: The object pointer - @param cr: the current row, from the database cursor, - @param uid: the current user’s ID for security checks, - @param ids: List of Mail’s IDs - @param user: Changed User id - @param partner: Changed Partner id - """ if not user: return {'value': {'email_to': False}} email = self.pool.get('res.users')._get_email_from(cr, uid, [user])[user] @@ -98,54 +59,19 @@ class crm_lead_forward_to_partner(osv.osv_memory): * info: Forward the case information * whole: Send the whole history * latest: Send the latest histoy - @param self: The object pointer - @param cr: the current row, from the database cursor, - @param uid: the current user’s ID for security checks, - @param ids: List of history IDs - @param context: A standard dictionary for contextual values """ #TODO: ids and context are not comming - res = False + res = {} res_id = context.get('active_id') - msg_val = self._get_case_history(cr, uid, history_type, res_id, context=context) + model = context.get('active_model') + body_text = self._get_body_text(cr, uid, model, res_id, history_type, context=context) + context['mail.compose.message.body'] = history_type if msg_val: - res = {'value': {'body_text' : '\n\n' + msg_val}} + res = {'value': {'body_text' : body_text}} return res - - def _get_case_history(self, cr, uid, history_type, res_id, context=None): - if not res_id: - return - - msg_val = '' - case_info = self.get_lead_details(cr, uid, res_id, context=context) - model_pool = self.pool.get('crm.lead') - - if history_type == 'info': - msg_val = case_info - - elif history_type == 'whole': - log_ids = model_pool.browse(cr, uid, res_id, context=context).message_ids - log_ids = map(lambda x: x.id, filter(lambda x: x.email_from, log_ids)) - msg_val = case_info + '\n\n' + self.get_whole_history(cr, uid, log_ids, context=context) - - elif history_type == 'latest': - log_ids = model_pool.browse(cr, uid, res_id, context=context).message_ids - log_ids = filter(lambda x: x.email_from and x.id, log_ids) - if not log_ids: - msg_val = case_info - else: - msg_val = case_info + '\n\n' + self.get_latest_history(cr, uid, log_ids[0].id, context=context) - - return msg_val - + def on_change_partner(self, cr, uid, ids, partner_id): """This function fills address information based on partner/user selected - @param self: The object pointer - @param cr: the current row, from the database cursor, - @param uid: the current user’s ID for security checks, - @param ids: List of Mail’s IDs - @param user: Changed User id - @param partner: Changed Partner id """ if not partner_id: return {'value' : {'email_to' : False, 'address_id': False}} @@ -158,11 +84,11 @@ class crm_lead_forward_to_partner(osv.osv_memory): partner = partner_obj.browse(cr, uid, [partner_id]) user_id = partner and partner[0].user_id or False email = user_id and user_id.user_email or '' - data.update({'email_cc' : email}) + data.update({'email_cc' : email, 'user_id': user_id and user_id.id or False}) return { 'value' : data, 'domain' : {'address_id' : partner_id and "[('partner_id', '=', partner_id)]" or "[]"} - } + } def on_change_address(self, cr, uid, ids, address_id): email = '' @@ -170,155 +96,126 @@ class crm_lead_forward_to_partner(osv.osv_memory): email = self.pool.get('res.partner.address').browse(cr, uid, address_id).email return {'value': {'email_to' : email}} - def send_mail(self, cr, uid, ids, context=None): - if context is None: - context = {} - super(crm_lead_forward_to_partner, self).send_mail(cr, uid, ids, context=context) - self.action_forward(cr, uid, ids, context) - return {'type': 'ir.actions.act_window_close'} - def action_forward(self, cr, uid, ids, context=None): """ Forward the lead to a partner """ if context is None: context = {} + res = {'type': 'ir.actions.act_window_close'} + model = context.get('active_model') + if model not in ('crm.lead'): + return res + this = self.browse(cr, uid, ids[0], context=context) - case_pool = self.pool.get(context.get('active_model')) - res_id = context and context.get('active_id', False) or False - case = case_pool.browse(cr, uid, res_id, context=context) - context.update({'mail': 'forward'}) - - to_write = {'date_assign': time.strftime('%Y-%m-%d')} - if (this.send_to == 'partner' and this.partner_id): - to_write['partner_assigned_id'] = this.partner_id.id - - if this.send_to == 'user': - to_write.update({'user_id' : this.user_id.id}) - email_re = r'([^ ,<@]+@[^> ,]+)' - email_cc = re.findall(email_re, case.email_cc or '') - new_cc = [] - if case.email_cc: - new_cc.append(case.email_cc) - for to in this.email_to.split(','): - email_to = re.findall(email_re, to) - email_to = email_to and email_to[0] or '' - if email_to not in email_cc: - new_cc.append(to) - to_write.update({'email_cc' : ', '.join(new_cc) }) - case_pool.write(cr, uid, case.id, to_write, context=context) - return {'type': 'ir.actions.act_window_close'} - - def get_lead_details(self, cr, uid, lead_id, context=None): - body = [] - lead_proxy = self.pool.get('crm.lead') - lead = lead_proxy.browse(cr, uid, lead_id, context=context) - if not lead.type or lead.type == 'lead' or not lead.partner_address_id: - field_names = [ - 'partner_name', 'title', 'function', 'street', 'street2', - 'zip', 'city', 'country_id', 'state_id', 'email_from', - 'phone', 'fax', 'mobile', 'categ_id', 'description', - ] - - for field_name in field_names: - field_definition = lead_proxy._columns[field_name] - value = None - - if field_definition._type == 'selection': - if hasattr(field_definition.selection, '__call__'): - key = field_definition.selection(lead_proxy, cr, uid, context=context) - else: - key = field_definition.selection - value = dict(key).get(lead[field_name], lead[field_name]) - elif field_definition._type == 'many2one': - if lead[field_name]: - value = lead[field_name].name_get()[0][1] - else: - value = lead[field_name] - - body.append("%s: %s" % (field_definition.string, value or '')) - elif lead.type == 'opportunity': - pa = lead.partner_address_id - body += [ - "Partner: %s" % (lead.partner_id and lead.partner_id.name_get()[0][1]), - "Contact: %s" % (pa.name or ''), - "Title: %s" % (pa.title or ''), - "Function: %s" % (pa.function or ''), - "Street: %s" % (pa.street or ''), - "Street2: %s" % (pa.street2 or ''), - "Zip: %s" % (pa.zip or ''), - "City: %s" % (pa.city or ''), - "Country: %s" % (pa.country_id and pa.country_id.name_get()[0][1] or ''), - "State: %s" % (pa.state_id and pa.state_id.name_get()[0][1] or ''), - "Email: %s" % (pa.email or ''), - "Phone: %s" % (pa.phone or ''), - "Fax: %s" % (pa.fax or ''), - "Mobile: %s" % (pa.mobile or ''), - "Lead Category: %s" % (lead.categ_id and lead.categ_id.name or ''), - "Details: %s" % (lead.description or ''), - ] - return "\n".join(body + ['---']) - - def default_get(self, cr, uid, fields, context=None): - """ - This function gets default values - """ - - if context is None: - context = {} - - defaults = super(crm_lead_forward_to_partner, self).default_get(cr, uid, fields, context=context) - active_id = context.get('active_id') - if not active_id: - return defaults - - lead_proxy = self.pool.get('crm.lead') - partner_obj = self.pool.get('res.partner') - lead = lead_proxy.browse(cr, uid, active_id, context=context) - - email_cc = '' - email = '' - if lead.partner_assigned_id: - partner = partner_obj.browse(cr, uid, [lead.partner_assigned_id.id]) - user_id = partner and partner[0].user_id or False - email_cc = user_id and user_id.user_email or '' - - addr = partner_obj.address_get(cr, uid, [partner[0].id], ['contact']) - email = self.pool.get('res.partner.address').browse(cr, uid, addr['contact']).email - - body = self._get_case_history(cr, uid, defaults.get('history', 'latest'), lead.id, context=context) - defaults.update({ - 'subject' : '%s: %s - %s' % (_('Fwd'), 'Openerp lead forward', lead.name), - 'body_text' : body, - 'email_cc' : email_cc, - 'email_to' : email or 'dummy@dummy.ly' - }) - return defaults - -class crm_lead_mass_forward_to_partner(osv.osv_memory): - _name = 'crm.lead.mass.forward.to.partner' - _inherit = 'crm.lead.forward.to.partner' - - def action_mass_forward(self, cr, uid, ids, context=None): - if not context: - context = {} - - active_ids = context.get('active_ids') - case_obj = self.pool.get('crm.lead') - for case in case_obj.browse(cr, uid, active_ids, context=context): - if not case.partner_assigned_id: - case_obj.assign_partner(cr,uid, [case.id], context=context) - case = case_obj.browse(cr, uid, case.id, context=context) - - if not case.partner_assigned_id: - continue - - context.update({'active_id' : case.id}) + lead = self.pool.get(model) + lead_id = context and context.get('active_id', False) or False + lead_ids = lead_id and [lead_id] or [] + mode = context.get('mail.compose.message.mode') + if mode == 'mass_mail': + lead_ids = context and context.get('active_ids', []) or [] value = self.default_get(cr, uid, ['body_text', 'email_to', 'email_cc', 'subject', 'history'], context=context) self.write(cr, uid, ids, value, context=context) - self.action_forward(cr,uid, ids, context=context) + context['mail.compose.message.mode'] = mode - return {'type': 'ir.actions.act_window_close'} + self.send_mail(cr, uid, ids, context=context) + for case in lead.browse(cr, uid, lead_ids, context=context): + if (this.send_to == 'partner' and this.partner_id): + lead.assign_partner(cr, uid, [case.id], this.partner_id.id, context=context) + if this.send_to == 'user': + lead.assign_salesman(cr, uid, [case.id], [this.user_id.id], context=context) + email_cc = to_email(case.email_cc) + email_cc = email_to and email_cc[0] or '' + new_cc = [] + if email_cc: + new_cc.append(email_cc) + for to in this.email_to.split(','): + email_to = to_email(to) + email_to = email_to and email_to[0] or '' + if email_to not in new_cc: + new_cc.append(to) + update_vals = {'email_cc' : ', '.join(new_cc) } + lead.write(cr, uid, case.id, update_vals, context=context) + return res + + def _get_info_body_text(self, cr, uid, lead, context=None): + field_names = [] + proxy = self.pool.get(lead._name) + if lead.type == 'opportunity': + field_names += ['partner_id'] + field_names += [ + 'partner_name' , 'title', 'function', 'street', 'street2', + 'zip', 'city', 'country_id', 'state_id', 'email_from', + 'phone', 'fax', 'mobile', 'categ_id', 'description', + ] + return proxy._mail_body_text(cr, uid, lead, field_names, context=context) + + def _get_message_body_text(self, cr, uid, lead, mode='whole', context=None): + """This function gets whole communication history and returns as top posting style + """ + mail_message = self.pool.get('mail.message') + message_ids = [] + body = self._get_info_body_text(cr, uid, lead, context=context) + if mode in ('whole', 'latest'): + message_ids = lead.message_ids + message_ids = map(lambda x: x.id, filter(lambda x: x.email_from, message_ids)) + if mode == 'latest' and len(message_ids): + message_ids = [message_ids[0]] + for message in mail_message.browse(cr, uid, message_ids, context=context): + header = '-------- Original Message --------' + sender = 'From: %s' %(message.email_from or '') + to = 'To: %s' % (message.email_to or '') + sentdate = 'Date: %s' % (message.date or '') + desc = '\n%s'%(message.body_text) + original = [header, sender, to, sentdate, desc] + original = '\n'.join(original) + body += original + return body or '' + + def get_value(self, cr, uid, model, res_id, context=None): + if context is None: + context = {} + res = super(crm_lead_forward_to_partner, self).get_value(cr, uid, model, res_id, context=context) + if model not in ("crm.lead"): + return res + proxy = self.pool.get(model) + partner = self.pool.get('res.partner') + lead = proxy.browse(cr, uid, res_id, context=context) + mode = context.get('mail.compose.message.mode') + if mode == "forward": + body_type = context.get('mail.compose.message.body') + email_cc = res.get('email_cc', "") + email = res.get('email_to', "") + subject = '%s: %s - %s' % (_('Fwd'), 'Lead forward', lead.name) + body = self._get_message_body_text(cr, uid, lead, body_type, context=context) + partner_assigned_id = lead.partner_assigned_id and lead.partner_assigned_id.id or False + user_id = False + if not partner_assigned_id: + partner_assigned_id = lead.search_geo_partner(cr, uid, [lead.id], context=None).get(lead.id, False) + if partner_assigned_id: + assigned_partner = partner.browse(cr, uid, partner_assigned_id, context=context) + user_id = assigned_partner.user_id and assigned_partner.user_id.id or False + email_cc = assigned_partner.user_id and assigned_partner.user_id.user_email or '' + email = assigned_partner.email + + + res.update({ + 'subject' : subject, + 'body_text' : body, + 'email_cc' : email_cc, + 'email_to' : email, + 'partner_assigned_id': partner_assigned_id, + 'user_id': user_id, + }) + return res + + + def default_get(self, cr, uid, fields, context=None): + if context is None: + context = {} + context['mail.compose.message.mode'] = 'forward' + context['mail.compose.message.body'] = 'info' + return super(crm_lead_forward_to_partner, self).default_get(cr, uid, fields, context=context) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/crm_partner_assign/wizard/crm_forward_to_partner_view.xml b/addons/crm_partner_assign/wizard/crm_forward_to_partner_view.xml index aa2c45ea1c9..645c729b164 100644 --- a/addons/crm_partner_assign/wizard/crm_forward_to_partner_view.xml +++ b/addons/crm_partner_assign/wizard/crm_forward_to_partner_view.xml @@ -45,7 +45,7 @@