2010-06-11 22:02:09 +00:00
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
##############################################################################
|
|
|
|
|
#
|
|
|
|
|
# OpenERP, Open Source Management Solution
|
|
|
|
|
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
|
|
|
|
#
|
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
|
# it under the terms of the GNU Affero General Public License as
|
|
|
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
|
|
|
# License, or (at your option) any later version.
|
|
|
|
|
#
|
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
# GNU Affero General Public License for more details.
|
|
|
|
|
#
|
|
|
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
#
|
|
|
|
|
##############################################################################
|
|
|
|
|
|
|
|
|
|
from osv import osv
|
|
|
|
|
from osv import fields
|
|
|
|
|
import urllib,re
|
|
|
|
|
import random, time
|
2010-06-28 17:56:45 +00:00
|
|
|
|
from tools.translate import _
|
2010-06-11 22:02:09 +00:00
|
|
|
|
|
|
|
|
|
def geo_find(addr):
|
2010-06-29 11:32:08 +00:00
|
|
|
|
try:
|
|
|
|
|
regex = '<coordinates>([+-]?[0-9\.]+),([+-]?[0-9\.]+),([+-]?[0-9\.]+)</coordinates>'
|
|
|
|
|
url = 'http://maps.google.com/maps/geo?q=' + urllib.quote(addr) + '&output=xml&oe=utf8&sensor=false'
|
|
|
|
|
xml = urllib.urlopen(url).read()
|
|
|
|
|
if '<error>' in xml:
|
|
|
|
|
return None
|
|
|
|
|
result = re.search(regex, xml, re.M|re.I)
|
|
|
|
|
if not result:
|
|
|
|
|
return None
|
|
|
|
|
return float(result.group(1)),float(result.group(2))
|
|
|
|
|
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)
|
2010-07-14 15:17:13 +00:00
|
|
|
|
|
2010-06-11 22:02:09 +00:00
|
|
|
|
|
2010-09-21 10:15:44 +00:00
|
|
|
|
class res_partner_grade(osv.osv):
|
|
|
|
|
_order = 'sequence'
|
|
|
|
|
_name = 'res.partner.grade'
|
|
|
|
|
_columns = {
|
|
|
|
|
'sequence': fields.integer('Sequence'),
|
|
|
|
|
'active': fields.boolean('Active'),
|
|
|
|
|
'name': fields.char('Grade Name', size=32)
|
|
|
|
|
}
|
|
|
|
|
_defaults = {
|
|
|
|
|
'active': lambda *args: 1
|
|
|
|
|
}
|
|
|
|
|
res_partner_grade()
|
|
|
|
|
|
|
|
|
|
|
2010-06-11 22:02:09 +00:00
|
|
|
|
class res_partner(osv.osv):
|
|
|
|
|
_inherit = "res.partner"
|
|
|
|
|
_columns = {
|
2010-06-25 18:36:37 +00:00
|
|
|
|
'partner_latitude': fields.float('Geo Latitude'),
|
|
|
|
|
'partner_longitude': fields.float('Geo Longitude'),
|
2010-07-14 15:17:13 +00:00
|
|
|
|
'date_localization': fields.date('Geo Localization Date'),
|
2010-06-11 22:02:09 +00:00
|
|
|
|
'partner_weight': fields.integer('Weight',
|
|
|
|
|
help="Gives the probability to assign a lead to this partner. (0 means no assignation.)"),
|
2010-09-21 08:36:59 +00:00
|
|
|
|
'opportunity_assigned_ids': fields.one2many('crm.lead', 'partner_assigned_id',\
|
|
|
|
|
'Assigned Opportunities'),
|
2010-09-21 10:15:44 +00:00
|
|
|
|
'grade_id': fields.many2one('res.partner.grade', 'Partner Grade')
|
2010-06-11 22:02:09 +00:00
|
|
|
|
}
|
|
|
|
|
_defaults = {
|
|
|
|
|
'partner_weight': lambda *args: 0
|
|
|
|
|
}
|
|
|
|
|
def geo_localize(self, cr, uid, ids, context=None):
|
|
|
|
|
for partner in self.browse(cr, uid, ids, context=context):
|
2010-06-25 18:36:37 +00:00
|
|
|
|
if not partner.address:
|
|
|
|
|
continue
|
2010-06-11 22:02:09 +00:00
|
|
|
|
part = partner.address[0]
|
2010-07-26 15:48:37 +00:00
|
|
|
|
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]))
|
2010-06-25 18:36:37 +00:00
|
|
|
|
result = geo_find(addr.encode('utf8'))
|
2010-06-11 22:02:09 +00:00
|
|
|
|
if result:
|
|
|
|
|
self.write(cr, uid, [partner.id], {
|
|
|
|
|
'partner_latitude': result[0],
|
2010-06-25 18:36:37 +00:00
|
|
|
|
'partner_longitude': result[1],
|
2010-07-14 15:17:13 +00:00
|
|
|
|
'date_localization': time.strftime('%Y-%m-%d')
|
2010-06-11 22:02:09 +00:00
|
|
|
|
}, context=context)
|
|
|
|
|
return True
|
|
|
|
|
res_partner()
|
|
|
|
|
|
|
|
|
|
class crm_lead(osv.osv):
|
|
|
|
|
_inherit = "crm.lead"
|
|
|
|
|
_columns = {
|
2010-06-25 18:36:37 +00:00
|
|
|
|
'partner_latitude': fields.float('Geo Latitude'),
|
|
|
|
|
'partner_longitude': fields.float('Geo Longitude'),
|
2010-09-21 08:36:59 +00:00
|
|
|
|
'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"),
|
2010-06-11 22:02:09 +00:00
|
|
|
|
}
|
2010-09-21 08:36:59 +00:00
|
|
|
|
def onchange_assign_id(self, cr, uid, ids, partner_assigned_id, context={}):
|
|
|
|
|
"""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:
|
|
|
|
|
return {'value':{'date_assign': time.strftime('%Y-%m-%d')}}
|
2010-06-25 18:36:37 +00:00
|
|
|
|
|
2010-06-11 22:02:09 +00:00
|
|
|
|
def assign_partner(self, cr, uid, ids, context=None):
|
2010-06-25 18:36:37 +00:00
|
|
|
|
ok = False
|
2010-06-11 22:02:09 +00:00
|
|
|
|
for part in self.browse(cr, uid, ids, context=context):
|
|
|
|
|
if not part.country_id:
|
|
|
|
|
continue
|
2010-07-26 15:48:37 +00:00
|
|
|
|
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]))
|
2010-06-25 18:36:37 +00:00
|
|
|
|
result = geo_find(addr.encode('utf8'))
|
2010-06-11 22:02:09 +00:00
|
|
|
|
if result:
|
|
|
|
|
self.write(cr, uid, [part.id], {
|
|
|
|
|
'partner_latitude': result[0],
|
|
|
|
|
'partner_longitude': result[1]
|
|
|
|
|
}, context=context)
|
2010-07-26 15:48:37 +00:00
|
|
|
|
|
|
|
|
|
# 1. first way: in the same country, small area
|
2010-06-11 22:02:09 +00:00
|
|
|
|
part_ids = self.pool.get('res.partner').search(cr, uid, [
|
|
|
|
|
('partner_weight','>',0),
|
|
|
|
|
('partner_latitude','>',result[0]-2), ('partner_latitude','<',result[0]+2),
|
2010-07-26 15:48:37 +00:00
|
|
|
|
('partner_longitude','>',result[1]-1.5), ('partner_longitude','<',result[1]+1.5),
|
|
|
|
|
('country', '=', part.country_id.id),
|
2010-06-11 22:02:09 +00:00
|
|
|
|
], context=context)
|
2010-07-26 15:48:37 +00:00
|
|
|
|
|
|
|
|
|
# 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),
|
|
|
|
|
], context=context)
|
|
|
|
|
|
|
|
|
|
# 3. third way: other countries, small area
|
|
|
|
|
if not part_ids:
|
|
|
|
|
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)
|
|
|
|
|
], context=context)
|
|
|
|
|
|
|
|
|
|
# 4. fourth way: other countries, big area
|
2010-06-11 22:02:09 +00:00
|
|
|
|
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)
|
|
|
|
|
], context=context)
|
2010-07-26 15:48:37 +00:00
|
|
|
|
|
|
|
|
|
# 5. fifth way: anywhere in same country
|
|
|
|
|
if not part_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),
|
|
|
|
|
], context=context)
|
|
|
|
|
|
|
|
|
|
# 6. sixth way: closest partner whatsoever, just to have at least one result
|
|
|
|
|
if not part_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]))
|
|
|
|
|
res = cr.dictfetchone()
|
2010-10-08 10:56:41 +00:00
|
|
|
|
if res:
|
|
|
|
|
part_ids.append(res['id'])
|
2010-07-26 15:48:37 +00:00
|
|
|
|
|
2010-06-11 22:02:09 +00:00
|
|
|
|
total = 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) )
|
2010-07-26 15:48:37 +00:00
|
|
|
|
random.shuffle(toassign) # avoid always giving the leads to the first ones in db natural order!
|
2010-06-11 22:02:09 +00:00
|
|
|
|
mypartner = random.randint(0,total)
|
|
|
|
|
for t in toassign:
|
|
|
|
|
if mypartner<=t[1]:
|
|
|
|
|
self.write(cr, uid, [part.id], {'partner_assigned_id': t[0], 'date_assign': time.strftime('%Y-%m-%d')}, context=context)
|
|
|
|
|
break
|
2010-06-25 18:36:37 +00:00
|
|
|
|
ok = True
|
|
|
|
|
return ok
|
2010-06-11 22:02:09 +00:00
|
|
|
|
crm_lead()
|
|
|
|
|
|