2009-10-13 05:58:37 +00:00
# -*- coding: utf-8 -*-
2006-12-07 13:41:40 +00:00
##############################################################################
2009-12-01 07:19:53 +00:00
#
2009-02-04 09:46:57 +00:00
# OpenERP, Open Source Management Solution
2012-05-22 08:14:13 +00:00
# Copyright (C) 2004-today OpenERP SA (<http://www.openerp.com>)
2008-06-16 11:00:21 +00:00
#
2008-11-03 19:18:56 +00:00
# This program is free software: you can redistribute it and/or modify
2009-10-14 11:15:34 +00:00
# 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.
2006-12-07 13:41:40 +00:00
#
2008-11-03 19:18:56 +00:00
# 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
2009-10-14 11:15:34 +00:00
# GNU Affero General Public License for more details.
2006-12-07 13:41:40 +00:00
#
2009-10-14 11:15:34 +00:00
# You should have received a copy of the GNU Affero General Public License
2009-12-01 07:19:53 +00:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2006-12-07 13:41:40 +00:00
#
##############################################################################
2013-10-03 08:27:36 +00:00
import calendar
2013-05-31 15:31:00 +00:00
from datetime import date , datetime
from dateutil import relativedelta
2013-04-19 10:36:00 +00:00
from openerp import tools
2012-12-06 14:56:32 +00:00
from openerp . osv import fields
from openerp . osv import osv
2009-09-24 10:46:21 +00:00
2006-12-07 13:41:40 +00:00
AVAILABLE_PRIORITIES = [
2010-04-28 07:20:02 +00:00
( ' 1 ' , ' Highest ' ) ,
2010-06-10 13:04:07 +00:00
( ' 2 ' , ' High ' ) ,
( ' 3 ' , ' Normal ' ) ,
( ' 4 ' , ' Low ' ) ,
( ' 5 ' , ' Lowest ' ) ,
2006-12-07 13:41:40 +00:00
]
2011-08-27 23:31:30 +00:00
class crm_case_channel ( osv . osv ) :
_name = " crm.case.channel "
_description = " Channels "
_order = ' name '
_columns = {
' name ' : fields . char ( ' Channel Name ' , size = 64 , required = True ) ,
' active ' : fields . boolean ( ' Active ' ) ,
}
_defaults = {
' active ' : lambda * a : 1 ,
}
2011-08-25 04:10:37 +00:00
class crm_case_stage ( osv . osv ) :
2012-05-22 08:14:13 +00:00
""" Model for case stages. This models the main stages of a document
2012-10-02 10:29:15 +00:00
management flow . Main CRM objects ( leads , opportunities , project
2012-05-22 08:14:13 +00:00
issues , . . . ) will now use only stages , instead of state and stages .
Stages are for example used to display the kanban view of records .
"""
2011-08-25 04:10:37 +00:00
_name = " crm.case.stage "
_description = " Stage of case "
_rec_name = ' name '
_order = " sequence "
_columns = {
' name ' : fields . char ( ' Stage Name ' , size = 64 , required = True , translate = True ) ,
2012-05-22 08:14:13 +00:00
' sequence ' : fields . integer ( ' Sequence ' , help = " Used to order stages. Lower is better. " ) ,
2011-08-25 04:10:37 +00:00
' probability ' : fields . float ( ' Probability ( % ) ' , required = True , help = " This percentage depicts the default/average probability of the Case for this stage to be a success " ) ,
' on_change ' : fields . boolean ( ' Change Probability Automatically ' , help = " Setting this stage will change the probability automatically on the opportunity. " ) ,
' requirements ' : fields . text ( ' Requirements ' ) ,
2013-07-16 15:10:03 +00:00
' section_ids ' : fields . many2many ( ' crm.case.section ' , ' section_stage_rel ' , ' stage_id ' , ' section_id ' , string = ' Sections ' ,
2012-05-22 08:14:13 +00:00
help = " Link between stages and sales teams. When set, this limitate the current stage to the selected sales teams. " ) ,
2012-12-16 15:58:43 +00:00
' case_default ' : fields . boolean ( ' Default to New Sales Team ' ,
2012-05-25 15:19:59 +00:00
help = " If you check this field, this stage will be proposed by default on each sales team. It will not assign this stage to existing teams. " ) ,
2013-10-18 13:21:20 +00:00
' fold ' : fields . boolean ( ' Folded in Kanban View ' ,
help = ' This stage is folded in the kanban view when '
' there are no records in that stage to display. ' ) ,
2013-07-16 15:10:03 +00:00
' type ' : fields . selection ( [ ( ' lead ' , ' Lead ' ) ,
2012-05-24 09:10:24 +00:00
( ' opportunity ' , ' Opportunity ' ) ,
( ' both ' , ' Both ' ) ] ,
string = ' Type ' , size = 16 , required = True ,
help = " This field is used to distinguish stages related to Leads from stages related to Opportunities, or to specify stages available for both types. " ) ,
2011-08-25 04:10:37 +00:00
}
_defaults = {
2013-10-23 16:30:29 +00:00
' sequence ' : 1 ,
' probability ' : 0.0 ,
2013-07-16 15:10:03 +00:00
' on_change ' : True ,
2012-05-22 14:11:27 +00:00
' fold ' : False ,
2012-05-24 09:10:24 +00:00
' type ' : ' both ' ,
2012-08-28 11:32:41 +00:00
' case_default ' : True ,
2011-08-25 04:10:37 +00:00
}
2013-04-03 08:10:09 +00:00
2011-08-25 04:10:37 +00:00
class crm_case_section ( osv . osv ) :
2012-05-22 08:14:13 +00:00
""" Model for sales teams. """
2011-08-25 04:10:37 +00:00
_name = " crm.case.section "
2012-06-26 11:21:09 +00:00
_inherits = { ' mail.alias ' : ' alias_id ' }
2012-09-24 12:51:39 +00:00
_inherit = " mail.thread "
2011-08-25 04:10:37 +00:00
_description = " Sales Teams "
_order = " complete_name "
2013-05-31 15:31:00 +00:00
# number of periods for lead/opportunities/... tracking in salesteam kanban dashboard/kanban view
_period_number = 5
2011-08-25 04:10:37 +00:00
def get_full_name ( self , cr , uid , ids , field_name , arg , context = None ) :
2013-04-03 08:10:09 +00:00
return dict ( self . name_get ( cr , uid , ids , context = context ) )
2011-08-25 04:10:37 +00:00
2013-05-31 15:31:00 +00:00
def __get_bar_values ( self , cr , uid , obj , domain , read_fields , value_field , groupby_field , context = None ) :
""" Generic method to generate data for bar chart values using SparklineBarWidget.
This method performs obj . read_group ( cr , uid , domain , read_fields , groupby_field ) .
: param obj : the target model ( i . e . crm_lead )
: param domain : the domain applied to the read_group
: param list read_fields : the list of fields to read in the read_group
: param str value_field : the field used to compute the value of the bar slice
: param str groupby_field : the fields used to group
: return list section_result : a list of dicts : [
{ ' value ' : ( int ) bar_column_value ,
' tootip ' : ( str ) bar_column_tooltip ,
}
]
"""
month_begin = date . today ( ) . replace ( day = 1 )
section_result = [ {
2013-10-03 08:27:36 +00:00
' value ' : 0 ,
' tooltip ' : ( month_begin + relativedelta . relativedelta ( months = - i ) ) . strftime ( ' % B ' ) ,
} for i in range ( self . _period_number - 1 , - 1 , - 1 ) ]
2013-05-31 15:31:00 +00:00
group_obj = obj . read_group ( cr , uid , domain , read_fields , groupby_field , context = context )
for group in group_obj :
group_begin_date = datetime . strptime ( group [ ' __domain ' ] [ 0 ] [ 2 ] , tools . DEFAULT_SERVER_DATE_FORMAT )
month_delta = relativedelta . relativedelta ( month_begin , group_begin_date )
section_result [ self . _period_number - ( month_delta . months + 1 ) ] = { ' value ' : group . get ( value_field , 0 ) , ' tooltip ' : group_begin_date . strftime ( ' % B ' ) }
return section_result
def _get_opportunities_data ( self , cr , uid , ids , field_name , arg , context = None ) :
""" Get opportunities-related data for salesteam kanban view
monthly_open_leads : number of open lead during the last months
monthly_planned_revenue : planned revenu of opportunities during the last months
"""
2013-05-24 13:52:55 +00:00
obj = self . pool . get ( ' crm.lead ' )
2013-05-31 15:31:00 +00:00
res = dict . fromkeys ( ids , False )
month_begin = date . today ( ) . replace ( day = 1 )
2013-10-03 08:27:36 +00:00
date_begin = month_begin - relativedelta . relativedelta ( months = self . _period_number - 1 )
date_end = month_begin . replace ( day = calendar . monthrange ( month_begin . year , month_begin . month ) [ 1 ] )
date_domain = [ ( ' create_date ' , ' >= ' , date_begin . strftime ( tools . DEFAULT_SERVER_DATE_FORMAT ) ) , ( ' create_date ' , ' <= ' , date_end . strftime ( tools . DEFAULT_SERVER_DATE_FORMAT ) ) ]
2013-05-31 15:31:00 +00:00
for id in ids :
res [ id ] = dict ( )
2013-10-03 08:27:36 +00:00
lead_domain = date_domain + [ ( ' type ' , ' = ' , ' lead ' ) , ( ' section_id ' , ' = ' , id ) ]
2013-05-31 15:31:00 +00:00
res [ id ] [ ' monthly_open_leads ' ] = self . __get_bar_values ( cr , uid , obj , lead_domain , [ ' create_date ' ] , ' create_date_count ' , ' create_date ' , context = context )
2013-10-03 08:27:36 +00:00
opp_domain = date_domain + [ ( ' type ' , ' = ' , ' opportunity ' ) , ( ' section_id ' , ' = ' , id ) ]
2013-05-31 15:31:00 +00:00
res [ id ] [ ' monthly_planned_revenue ' ] = self . __get_bar_values ( cr , uid , obj , opp_domain , [ ' planned_revenue ' , ' create_date ' ] , ' planned_revenue ' , ' create_date ' , context = context )
2013-04-17 10:43:02 +00:00
return res
2011-08-25 04:10:37 +00:00
_columns = {
' name ' : fields . char ( ' Sales Team ' , size = 64 , required = True , translate = True ) ,
' complete_name ' : fields . function ( get_full_name , type = ' char ' , size = 256 , readonly = True , store = True ) ,
' code ' : fields . char ( ' Code ' , size = 8 ) ,
' active ' : fields . boolean ( ' Active ' , help = " If the active field is set to " \
" true, it will allow you to hide the sales team without removing it. " ) ,
2012-07-13 10:17:51 +00:00
' change_responsible ' : fields . boolean ( ' Reassign Escalated ' , help = " When escalating to this team override the salesman with the team leader. " ) ,
2011-08-25 04:10:37 +00:00
' user_id ' : fields . many2one ( ' res.users ' , ' Team Leader ' ) ,
2013-03-28 13:09:56 +00:00
' member_ids ' : fields . many2many ( ' res.users ' , ' sale_member_rel ' , ' section_id ' , ' member_id ' , ' Team Members ' ) ,
2011-08-25 04:10:37 +00:00
' reply_to ' : fields . char ( ' Reply-To ' , size = 64 , help = " The email address put in the ' Reply-To ' of all emails sent by OpenERP about cases in this sales team " ) ,
' parent_id ' : fields . many2one ( ' crm.case.section ' , ' Parent Team ' ) ,
' child_ids ' : fields . one2many ( ' crm.case.section ' , ' parent_id ' , ' Child Teams ' ) ,
' resource_calendar_id ' : fields . many2one ( ' resource.calendar ' , " Working Time " , help = " Used to compute open days " ) ,
' note ' : fields . text ( ' Description ' ) ,
2013-03-28 13:09:56 +00:00
' working_hours ' : fields . float ( ' Working Hours ' , digits = ( 16 , 2 ) ) ,
2011-08-25 04:10:37 +00:00
' stage_ids ' : fields . many2many ( ' crm.case.stage ' , ' section_stage_rel ' , ' section_id ' , ' stage_id ' , ' Stages ' ) ,
2013-08-27 15:07:08 +00:00
' alias_id ' : fields . many2one ( ' mail.alias ' , ' Alias ' , ondelete = " restrict " , required = True ,
2012-08-01 09:14:39 +00:00
help = " The email address associated with this team. New emails received will automatically "
" create new leads assigned to the team. " ) ,
2013-02-06 11:57:36 +00:00
' color ' : fields . integer ( ' Color Index ' ) ,
2013-03-28 13:09:56 +00:00
' use_leads ' : fields . boolean ( ' Leads ' ,
2013-05-06 13:52:43 +00:00
help = " The first contact you get with a potential customer is a lead you qualify before converting it into a real business opportunity. Check this box to manage leads in this sales team. " ) ,
2013-04-17 13:17:59 +00:00
2013-05-31 15:31:00 +00:00
' monthly_open_leads ' : fields . function ( _get_opportunities_data ,
type = " string " , readonly = True , multi = ' _get_opportunities_data ' ,
string = ' Open Leads per Month ' ) ,
' monthly_planned_revenue ' : fields . function ( _get_opportunities_data ,
type = " string " , readonly = True , multi = ' _get_opportunities_data ' ,
string = ' Planned Revenue per Month ' )
2011-08-25 04:10:37 +00:00
}
2012-10-02 10:29:15 +00:00
2011-10-01 21:15:29 +00:00
def _get_stage_common ( self , cr , uid , context ) :
2013-04-03 08:10:09 +00:00
ids = self . pool . get ( ' crm.case.stage ' ) . search ( cr , uid , [ ( ' case_default ' , ' = ' , 1 ) ] , context = context )
2011-10-01 21:15:29 +00:00
return ids
2011-08-25 04:10:37 +00:00
_defaults = {
2012-08-14 10:51:14 +00:00
' active ' : 1 ,
' stage_ids ' : _get_stage_common ,
2013-03-25 10:25:55 +00:00
' use_leads ' : True ,
2011-08-25 04:10:37 +00:00
}
_sql_constraints = [
( ' code_uniq ' , ' unique (code) ' , ' The code of the sales team must be unique ! ' )
]
_constraints = [
2011-08-27 21:19:48 +00:00
( osv . osv . _check_recursion , ' Error ! You cannot create recursive Sales team. ' , [ ' parent_id ' ] )
2011-08-25 04:10:37 +00:00
]
def name_get ( self , cr , uid , ids , context = None ) :
2011-08-27 21:19:48 +00:00
""" Overrides orm name_get method """
2013-04-05 11:07:37 +00:00
if not isinstance ( ids , list ) :
2011-08-25 04:10:37 +00:00
ids = [ ids ]
res = [ ]
if not ids :
return res
reads = self . read ( cr , uid , ids , [ ' name ' , ' parent_id ' ] , context )
for record in reads :
name = record [ ' name ' ]
if record [ ' parent_id ' ] :
name = record [ ' parent_id ' ] [ 1 ] + ' / ' + name
res . append ( ( record [ ' id ' ] , name ) )
return res
2012-06-26 11:21:09 +00:00
def create ( self , cr , uid , vals , context = None ) :
2013-04-09 11:11:58 +00:00
if context is None :
context = { }
2013-05-16 16:42:07 +00:00
create_context = dict ( context , alias_model_name = ' crm.lead ' , alias_parent_model_name = self . _name )
2013-04-09 11:11:58 +00:00
section_id = super ( crm_case_section , self ) . create ( cr , uid , vals , context = create_context )
section = self . browse ( cr , uid , section_id , context = context )
2013-05-16 16:42:07 +00:00
self . pool . get ( ' mail.alias ' ) . write ( cr , uid , [ section . alias_id . id ] , { ' alias_parent_thread_id ' : section_id , ' alias_defaults ' : { ' section_id ' : section_id , ' type ' : ' lead ' } } , context = context )
2013-04-09 11:11:58 +00:00
return section_id
2012-10-02 10:29:15 +00:00
2012-07-05 12:54:17 +00:00
def unlink ( self , cr , uid , ids , context = None ) :
2012-07-05 14:17:06 +00:00
# Cascade-delete mail aliases as well, as they should not exist without the sales team.
mail_alias = self . pool . get ( ' mail.alias ' )
2013-04-05 11:07:37 +00:00
alias_ids = [ team . alias_id . id for team in self . browse ( cr , uid , ids , context = context ) if team . alias_id ]
2012-07-05 12:54:17 +00:00
res = super ( crm_case_section , self ) . unlink ( cr , uid , ids , context = context )
2012-07-05 14:17:06 +00:00
mail_alias . unlink ( cr , uid , alias_ids , context = context )
2012-07-05 12:54:17 +00:00
return res
2011-08-25 04:10:37 +00:00
class crm_case_categ ( osv . osv ) :
""" Category of Case """
_name = " crm.case.categ "
_description = " Category of Case "
_columns = {
' name ' : fields . char ( ' Name ' , size = 64 , required = True , translate = True ) ,
' section_id ' : fields . many2one ( ' crm.case.section ' , ' Sales Team ' ) ,
' object_id ' : fields . many2one ( ' ir.model ' , ' Object Name ' ) ,
}
def _find_object_id ( self , cr , uid , context = None ) :
2011-08-27 21:19:48 +00:00
""" Finds id for case object """
2012-12-08 13:14:49 +00:00
context = context or { }
object_id = context . get ( ' object_id ' , False )
2012-12-08 13:36:04 +00:00
ids = self . pool . get ( ' ir.model ' ) . search ( cr , uid , [ ' | ' , ( ' id ' , ' = ' , object_id ) , ( ' model ' , ' = ' , context . get ( ' object_name ' , False ) ) ] )
2011-11-14 21:33:19 +00:00
return ids and ids [ 0 ] or False
2011-08-25 04:10:37 +00:00
_defaults = {
' object_id ' : _find_object_id
}
class crm_case_resource_type ( osv . osv ) :
""" Resource Type of case """
_name = " crm.case.resource.type "
_description = " Campaign "
_rec_name = " name "
_columns = {
' name ' : fields . char ( ' Campaign Name ' , size = 64 , required = True , translate = True ) ,
' section_id ' : fields . many2one ( ' crm.case.section ' , ' Sales Team ' ) ,
}
2012-08-01 06:44:42 +00:00
class crm_payment_mode ( osv . osv ) :
""" Payment Mode for Fund """
_name = " crm.payment.mode "
_description = " CRM Payment Mode "
2010-01-08 11:05:05 +00:00
_columns = {
2012-08-01 08:50:40 +00:00
' name ' : fields . char ( ' Name ' , size = 64 , required = True ) ,
2012-08-01 06:44:42 +00:00
' section_id ' : fields . many2one ( ' crm.case.section ' , ' Sales Team ' ) ,
2010-02-01 08:21:18 +00:00
}
2011-02-18 09:54:19 +00:00
2013-03-25 16:32:04 +00:00
2011-11-22 08:51:38 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: