2018-01-16 06:58:15 +01:00
# -*- coding: utf-8 -*-
2018-01-16 11:34:37 +01:00
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
2018-01-16 06:58:15 +01:00
from dateutil . relativedelta import relativedelta
2018-01-16 11:34:37 +01:00
from flectra import api , fields , models , _
from flectra . tools . safe_eval import safe_eval
from flectra . exceptions import ValidationError
2018-01-16 06:58:15 +01:00
class Team ( models . Model ) :
_name = ' crm.team '
_inherit = [ ' mail.alias.mixin ' , ' crm.team ' ]
use_leads = fields . Boolean ( ' Leads ' , help = " Check this box to filter and qualify incoming requests as leads before converting them into opportunities and assigning them to a salesperson. " )
use_opportunities = fields . Boolean ( ' Pipeline ' , help = " Check this box to manage a presales process with opportunities. " )
alias_id = fields . Many2one ( ' mail.alias ' , string = ' Alias ' , ondelete = " restrict " , required = True , help = " The email address associated with this channel. New emails received will automatically create new leads assigned to the channel. " )
unassigned_leads_count = fields . Integer (
compute = ' _compute_unassigned_leads_count ' ,
string = ' Unassigned Leads ' , readonly = True )
opportunities_count = fields . Integer (
compute = ' _compute_opportunities ' ,
string = ' Number of open opportunities ' , readonly = True )
opportunities_amount = fields . Integer (
compute = ' _compute_opportunities ' ,
string = ' Amount of quotations to invoice ' , readonly = True )
dashboard_graph_model = fields . Selection ( selection_add = [ ( ' crm.opportunity.report ' , ' Pipeline ' ) ] )
dashboard_graph_period_pipeline = fields . Selection ( [
( ' week ' , ' Within a Week ' ) ,
( ' month ' , ' Within a Month ' ) ,
( ' year ' , ' Within a Year ' ) ,
] , string = ' Expected to Close ' , help = " The time period this channel ' s dashboard graph will consider. " ,
compute = " _compute_dashboard_graph_period_pipeline " , inverse = " _inverse_dashboard_graph_period_pipeline " )
dashboard_graph_group_pipeline = fields . Selection ( [
( ' day ' , ' Expected Closing Day ' ) ,
( ' week ' , ' Expected Closing Week ' ) ,
( ' month ' , ' Expected Closing Month ' ) ,
( ' user ' , ' Salesperson ' ) ,
( ' stage ' , ' Stage ' ) ,
] , string = ' Group by ' , default = ' day ' , help = " How this channel ' s dashboard graph will group the results. " )
def _compute_unassigned_leads_count ( self ) :
leads_data = self . env [ ' crm.lead ' ] . read_group ( [
( ' team_id ' , ' in ' , self . ids ) ,
( ' type ' , ' = ' , ' lead ' ) ,
( ' user_id ' , ' = ' , False ) ,
] , [ ' team_id ' ] , [ ' team_id ' ] )
counts = { datum [ ' team_id ' ] [ 0 ] : datum [ ' team_id_count ' ] for datum in leads_data }
for team in self :
team . unassigned_leads_count = counts . get ( team . id , 0 )
def _compute_opportunities ( self ) :
opportunity_data = self . env [ ' crm.lead ' ] . read_group ( [
( ' team_id ' , ' in ' , self . ids ) ,
( ' probability ' , ' < ' , 100 ) ,
( ' type ' , ' = ' , ' opportunity ' ) ,
] , [ ' planned_revenue ' , ' probability ' , ' team_id ' ] , [ ' team_id ' ] )
counts = { datum [ ' team_id ' ] [ 0 ] : datum [ ' team_id_count ' ] for datum in opportunity_data }
amounts = { datum [ ' team_id ' ] [ 0 ] : ( datum [ ' planned_revenue ' ] * datum [ ' probability ' ] / 100 ) for datum in opportunity_data }
for team in self :
team . opportunities_count = counts . get ( team . id , 0 )
team . opportunities_amount = amounts . get ( team . id , 0 )
def _compute_dashboard_graph_period_pipeline ( self ) :
for channel in self :
channel . dashboard_graph_period_pipeline = channel . dashboard_graph_period
def _inverse_dashboard_graph_period_pipeline ( self ) :
for channel in self . filtered ( lambda ch : ch . dashboard_graph_model == ' crm.opportunity.report ' ) :
channel . dashboard_graph_period = channel . dashboard_graph_period_pipeline
def get_alias_model_name ( self , vals ) :
return ' crm.lead '
def get_alias_values ( self ) :
has_group_use_lead = self . env . user . has_group ( ' crm.group_use_lead ' )
values = super ( Team , self ) . get_alias_values ( )
values [ ' alias_defaults ' ] = defaults = safe_eval ( self . alias_defaults or " {} " )
defaults [ ' type ' ] = ' lead ' if has_group_use_lead and self . use_leads else ' opportunity '
defaults [ ' team_id ' ] = self . id
2018-01-18 10:57:39 +01:00
defaults [ ' branch_id ' ] = self . branch_id . id
2018-01-16 06:58:15 +01:00
return values
@api.onchange ( ' use_leads ' , ' use_opportunities ' )
def _onchange_use_leads_opportunities ( self ) :
if not self . use_leads and not self . use_opportunities :
self . alias_name = False
if not self . use_opportunities and self . use_leads :
self . use_leads = False
@api.onchange ( ' team_type ' )
def _onchange_team_type ( self ) :
if self . team_type == ' sales ' :
self . use_opportunities = True
self . use_leads = lambda self : self . user_has_groups ( ' crm.group_use_lead ' )
self . dashboard_graph_model = ' crm.opportunity.report '
else :
self . use_opportunities = False
self . use_leads = False
return super ( Team , self ) . _onchange_team_type ( )
@api.onchange ( ' dashboard_graph_model ' )
def _onchange_dashboard_graph_model ( self ) :
if self . dashboard_graph_model == ' crm.opportunity.report ' :
self . dashboard_graph_period_pipeline = self . dashboard_graph_period
self . dashboard_graph_group_pipeline = self . dashboard_graph_group
else :
self . dashboard_graph_period = self . dashboard_graph_period_pipeline
if not self . dashboard_graph_group :
self . dashboard_graph_group = self . _fields [ ' dashboard_graph_group ' ] . default ( self )
@api.onchange ( ' dashboard_graph_group_pipeline ' )
def _onchange_dashboard_graph_group_pipeline ( self ) :
if self . dashboard_graph_group_pipeline == ' stage ' :
self . dashboard_graph_group = False
else :
self . dashboard_graph_group = self . dashboard_graph_group_pipeline
@api.constrains ( ' dashboard_graph_model ' , ' use_opportunities ' )
def _check_graph_model ( self ) :
if not self . use_opportunities and self . dashboard_graph_model == ' crm.opportunity.report ' :
raise ValidationError ( _ ( " Dashboard graph content cannot be Pipeline if the sales channel doesn ' t use it. (Pipeline is unchecked.) " ) )
@api.multi
def write ( self , vals ) :
result = super ( Team , self ) . write ( vals )
if ' use_leads ' in vals or ' alias_defaults ' in vals :
for team in self :
team . alias_id . write ( team . get_alias_values ( ) )
return result
#TODO JEM : refactor this stuff with xml action, proper customization,
@api.model
def action_your_pipeline ( self ) :
action = self . env . ref ( ' crm.crm_lead_opportunities_tree_view ' ) . read ( ) [ 0 ]
user_team_id = self . env . user . sale_team_id . id
if not user_team_id :
user_team_id = self . search ( [ ] , limit = 1 ) . id
action [ ' help ' ] = """ <p class= ' oe_view_nocontent_create ' >Click here to add new opportunities</p><p>
Looks like you are not a member of a sales channel . You should add yourself
as a member of one of the sales channel .
< / p > """
if user_team_id :
2018-01-16 11:34:37 +01:00
action [ ' help ' ] + = " <p>As you don ' t belong to any sales channel, Flectra opens the first one by default.</p> "
2018-01-16 06:58:15 +01:00
action_context = safe_eval ( action [ ' context ' ] , { ' uid ' : self . env . uid } )
if user_team_id :
action_context [ ' default_team_id ' ] = user_team_id
tree_view_id = self . env . ref ( ' crm.crm_case_tree_view_oppor ' ) . id
form_view_id = self . env . ref ( ' crm.crm_case_form_view_oppor ' ) . id
kanb_view_id = self . env . ref ( ' crm.crm_case_kanban_view_leads ' ) . id
action [ ' views ' ] = [
[ kanb_view_id , ' kanban ' ] ,
[ tree_view_id , ' tree ' ] ,
[ form_view_id , ' form ' ] ,
[ False , ' graph ' ] ,
[ False , ' calendar ' ] ,
[ False , ' pivot ' ]
]
action [ ' context ' ] = action_context
return action
def _compute_dashboard_button_name ( self ) :
opportunity_teams = self . filtered ( ' use_opportunities ' )
opportunity_teams . update ( { ' dashboard_button_name ' : _ ( " Pipeline " ) } )
super ( Team , self - opportunity_teams ) . _compute_dashboard_button_name ( )
def action_primary_channel_button ( self ) :
if self . use_opportunities :
action = self . env . ref ( ' crm.crm_case_form_view_salesteams_opportunity ' ) . read ( ) [ 0 ]
return action
return super ( Team , self ) . action_primary_channel_button ( )
def _graph_get_dates ( self , today ) :
""" return a coherent start and end date for the dashboard graph according to the graph settings.
"""
if self . dashboard_graph_model == ' crm.opportunity.report ' :
if self . dashboard_graph_group == ' month ' :
start_date = today . replace ( day = 1 )
elif self . dashboard_graph_group == ' week ' :
start_date = today - relativedelta ( days = today . isocalendar ( ) [ 2 ] - 1 )
else :
start_date = today
if self . dashboard_graph_period == ' week ' :
end_date = today + relativedelta ( weeks = 1 )
elif self . dashboard_graph_period == ' year ' :
end_date = today + relativedelta ( years = 1 )
else :
end_date = today + relativedelta ( months = 1 )
# we take the end of the preceding month/week/day if we group by month/week/day
# (to avoid having twice the same month/week/day from different years/month/week)
if self . dashboard_graph_group == ' month ' :
end_date = end_date . replace ( day = 1 ) - relativedelta ( days = 1 )
elif self . dashboard_graph_group == ' week ' :
end_date - = relativedelta ( days = end_date . isocalendar ( ) [ 2 ] )
else :
end_date - = relativedelta ( days = 1 )
return [ start_date , end_date ]
return super ( Team , self ) . _graph_get_dates ( today )
def _get_graph ( self ) :
graph_datas = super ( Team , self ) . _get_graph ( )
if self . dashboard_graph_model == ' crm.opportunity.report ' and self . dashboard_graph_group_pipeline == ' stage ' :
stage_ids = [ d [ ' label ' ] for d in graph_datas [ 0 ] [ ' values ' ] if d [ ' label ' ] is not None ]
stage_data = self . env [ ' crm.stage ' ] . browse ( stage_ids ) . read ( [ ' sequence ' , ' name ' ] )
stage_data = { d [ ' id ' ] : { ' name ' : d [ ' name ' ] , ' sequence ' : d [ ' sequence ' ] } for d in stage_data }
# use "Undefined" stage for unset stage records
stage_data [ None ] = { ' name ' : _ ( ' Undefined ' ) , ' sequence ' : - 1 }
graph_datas [ 0 ] [ ' values ' ] = sorted ( graph_datas [ 0 ] [ ' values ' ] , key = lambda el : stage_data [ el [ ' label ' ] ] [ ' sequence ' ] )
for gdata in graph_datas [ 0 ] [ ' values ' ] :
gdata [ ' label ' ] = stage_data [ gdata [ ' label ' ] ] [ ' name ' ]
return graph_datas
def _graph_date_column ( self ) :
if self . dashboard_graph_model == ' crm.opportunity.report ' :
return ' date_deadline '
return super ( Team , self ) . _graph_date_column ( )
def _graph_x_query ( self ) :
if self . dashboard_graph_model == ' crm.opportunity.report ' and self . dashboard_graph_group_pipeline == ' stage ' :
return ' stage_id '
return super ( Team , self ) . _graph_x_query ( )
def _graph_y_query ( self ) :
if self . dashboard_graph_model == ' crm.opportunity.report ' :
return ' SUM(expected_revenue) '
return super ( Team , self ) . _graph_y_query ( )
def _graph_title_and_key ( self ) :
if self . dashboard_graph_model == ' crm.opportunity.report ' :
return [ ' ' , _ ( ' Pipeline: Expected Revenue ' ) ] # no more title
return super ( Team , self ) . _graph_title_and_key ( )