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/>.
#
##############################################################################
2013-03-11 12:11:31 +00:00
import random
2013-10-07 14:41:35 +00:00
from openerp . addons . base_geolocalize . models . res_partner import geo_find , geo_query_address
2012-12-06 14:56:32 +00:00
from openerp . osv import osv
from openerp . osv import fields
2012-03-09 01:58:04 +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 ' ) ,
2013-06-10 12:50:57 +00:00
' name ' : fields . char ( ' Grade Name ' , size = 32 ) ,
' partner_weight ' : fields . integer ( ' Grade Weight ' ,
help = " Gives the probability to assign a lead to this partner. (0 means no assignation.) " ) ,
2010-09-21 10:15:44 +00:00
}
_defaults = {
2013-06-10 12:50:57 +00:00
' active ' : lambda * args : 1 ,
' partner_weight ' : 1
2010-09-21 10:15:44 +00:00
}
2012-02-09 16:15:44 +00:00
class res_partner_activation ( osv . osv ) :
_name = ' res.partner.activation '
_order = ' sequence '
_columns = {
' sequence ' : fields . integer ( ' Sequence ' ) ,
' name ' : fields . char ( ' Name ' , size = 32 , required = True ) ,
}
2010-09-21 10:15:44 +00:00
2010-06-11 22:02:09 +00:00
class res_partner ( osv . osv ) :
_inherit = " res.partner "
_columns = {
2013-06-10 12:50:57 +00:00
' partner_weight ' : fields . integer ( ' Grade Weight ' ,
2010-06-11 22:02:09 +00:00
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 ' , \
2011-02-24 11:21:25 +00:00
' Assigned Opportunities ' ) ,
2013-06-10 12:50:57 +00:00
' grade_id ' : fields . many2one ( ' res.partner.grade ' , ' Grade ' ) ,
2012-02-09 16:15:44 +00:00
' activation ' : fields . many2one ( ' res.partner.activation ' , ' Activation ' , select = 1 ) ,
' date_partnership ' : fields . date ( ' Partnership Date ' ) ,
' date_review ' : fields . date ( ' Latest Partner Review ' ) ,
' date_review_next ' : fields . date ( ' Next Partner Review ' ) ,
2010-06-11 22:02:09 +00:00
}
_defaults = {
' partner_weight ' : lambda * args : 0
}
2013-06-10 12:50:57 +00:00
def onchange_grade_id ( self , cr , uid , ids , grade_id , context = None ) :
res = { ' value ' : { ' partner_weight ' : 0 } }
if grade_id :
partner_grade = self . pool . get ( ' res.partner.grade ' ) . browse ( cr , uid , grade_id )
res [ ' value ' ] [ ' partner_weight ' ] = partner_grade . partner_weight
return res
2013-10-07 14:41:35 +00:00
2010-06-11 22:02:09 +00:00
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 ' ) ,
2013-06-10 12:50:57 +00:00
' partner_assigned_id ' : fields . many2one ( ' res.partner ' , ' Assigned Partner ' , track_visibility = ' onchange ' , help = " Partner this case has been forwarded/assigned to. " , select = True ) ,
2010-09-21 08:36:59 +00:00
' 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
}
2011-10-26 09:21:33 +00:00
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 )
2010-11-19 13:48:01 +00:00
def onchange_assign_id ( self , cr , uid , ids , partner_assigned_id , context = None ) :
2010-09-21 08:36:59 +00:00
""" This function updates the " assignation date " automatically, when manually assign a partner in the geo assign tab
2011-10-26 09:21:33 +00:00
"""
2013-06-10 12:50:57 +00:00
2010-09-21 08:36:59 +00:00
if not partner_assigned_id :
return { ' value ' : { ' date_assign ' : False } }
else :
2011-02-04 10:34:35 +00:00
partners = self . pool . get ( ' res.partner ' ) . browse ( cr , uid , [ partner_assigned_id ] , context = context )
user_id = partners [ 0 ] and partners [ 0 ] . user_id . id or False
2011-02-24 11:21:25 +00:00
return { ' value ' :
2012-02-14 12:25:20 +00:00
{ ' date_assign ' : fields . date . context_today ( self , cr , uid , context = context ) ,
2011-02-04 10:34:35 +00:00
' user_id ' : user_id }
}
2010-06-25 18:36:37 +00:00
2011-11-23 05:43:47 +00:00
def action_assign_partner ( self , cr , uid , ids , context = None ) :
return self . assign_partner ( cr , uid , ids , partner_id = False , context = context )
2011-10-26 16:27:27 +00:00
def assign_partner ( self , cr , uid , ids , partner_id = False , context = None ) :
2011-10-26 09:21:33 +00:00
partner_ids = { }
res = False
2011-10-26 16:27:27 +00:00
res_partner = self . pool . get ( ' res.partner ' )
if not partner_id :
2011-10-26 09:21:33 +00:00
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 )
2011-11-23 05:43:47 +00:00
if not partner_id :
continue
self . assign_geo_localize ( cr , uid , [ lead . id ] , lead . partner_latitude , lead . partner_longitude , context = context )
2011-10-26 16:27:27 +00:00
partner = res_partner . browse ( cr , uid , partner_id , context = context )
if partner . user_id :
2013-03-01 09:34:49 +00:00
salesteam_id = partner . section_id and partner . section_id . id or False
2011-10-26 16:27:27 +00:00
for lead_id in ids :
2013-03-01 09:34:49 +00:00
self . allocate_salesman ( cr , uid , [ lead_id ] , [ partner . user_id . id ] , team_id = salesteam_id , context = context )
2012-02-14 12:25:20 +00:00
self . write ( cr , uid , [ lead . id ] , { ' date_assign ' : fields . date . context_today ( self , cr , uid , context = context ) , ' partner_assigned_id ' : partner_id } , context = context )
2011-10-26 09:21:33 +00:00
return res
2012-02-13 18:07:41 +00:00
2011-10-26 09:21:33 +00:00
def assign_geo_localize ( self , cr , uid , ids , latitude = False , longitude = False , context = None ) :
2012-03-09 01:58:04 +00:00
# Don't pass context to browse()! We need country name in english below
for lead in self . browse ( cr , uid , ids ) :
2011-10-26 09:21:33 +00:00
if not lead . country_id :
2010-06-11 22:02:09 +00:00
continue
2012-03-09 01:58:04 +00:00
result = geo_find ( geo_query_address ( street = lead . street ,
zip = lead . zip ,
city = lead . city ,
state = lead . state_id . name ,
country = lead . country_id . name ) )
2011-10-26 09:21:33 +00:00
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
2012-03-09 01:58:04 +00:00
2011-10-26 09:21:33 +00:00
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 :
2010-07-26 15:48:37 +00:00
# 1. first way: in the same country, small area
2011-10-26 09:21:33 +00:00
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 ) ,
2012-03-06 13:48:46 +00:00
( ' country_id ' , ' = ' , lead . 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
2011-10-26 09:21:33 +00:00
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 ) ,
2012-03-06 13:48:46 +00:00
( ' country_id ' , ' = ' , lead . country_id . id ) ,
2010-07-26 15:48:37 +00:00
] , context = context )
2012-03-09 02:04:15 +00:00
# 3. third way: in the same country, extra large area
if not partner_ids :
partner_ids = res_partner . search ( cr , uid , [
( ' partner_weight ' , ' > ' , 0 ) ,
( ' partner_latitude ' , ' > ' , latitude - 8 ) , ( ' partner_latitude ' , ' < ' , latitude + 8 ) ,
( ' partner_longitude ' , ' > ' , longitude - 8 ) , ( ' partner_longitude ' , ' < ' , longitude + 8 ) ,
( ' country ' , ' = ' , lead . country_id . id ) ,
] , context = context )
2010-07-26 15:48:37 +00:00
# 5. fifth way: anywhere in same country
2011-10-26 09:21:33 +00:00
if not partner_ids :
2010-07-26 15:48:37 +00:00
# still haven't found any, let's take all partners in the country!
2011-11-23 05:43:47 +00:00
partner_ids = res_partner . search ( cr , uid , [
2011-10-26 09:21:33 +00:00
( ' partner_weight ' , ' > ' , 0 ) ,
2012-03-06 13:48:46 +00:00
( ' country_id ' , ' = ' , lead . country_id . id ) ,
2010-07-26 15:48:37 +00:00
] , context = context )
2011-02-24 11:21:25 +00:00
# 6. sixth way: closest partner whatsoever, just to have at least one result
2011-10-26 09:21:33 +00:00
if not partner_ids :
2010-07-26 15:48:37 +00:00
# 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
2011-10-26 09:21:33 +00:00
ORDER BY distance LIMIT 1 """ , (longitude, latitude))
2010-07-26 15:48:37 +00:00
res = cr . dictfetchone ( )
2010-10-08 10:56:41 +00:00
if res :
2011-10-26 09:21:33 +00:00
partner_ids . append ( res [ ' id ' ] )
2010-07-26 15:48:37 +00:00
2011-10-26 09:21:33 +00:00
total_weight = 0
2010-06-11 22:02:09 +00:00
toassign = [ ]
2011-10-26 09:21:33 +00:00
for partner in res_partner . browse ( cr , uid , partner_ids , context = context ) :
total_weight + = partner . partner_weight
toassign . append ( ( partner . id , total_weight ) )
2010-07-26 15:48:37 +00:00
random . shuffle ( toassign ) # avoid always giving the leads to the first ones in db natural order!
2011-10-26 09:21:33 +00:00
nearest_weight = random . randint ( 0 , total_weight )
for partner_id , weight in toassign :
if nearest_weight < = weight :
res_partner_ids [ lead . id ] = partner_id
2010-06-11 22:02:09 +00:00
break
2011-10-26 09:21:33 +00:00
return res_partner_ids
2010-06-11 22:02:09 +00:00
2011-11-22 08:51:38 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: