diff options
Diffstat (limited to 'addons/crm/models/crm_team.py')
| -rw-r--r-- | addons/crm/models/crm_team.py | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/addons/crm/models/crm_team.py b/addons/crm/models/crm_team.py new file mode 100644 index 00000000..791755e9 --- /dev/null +++ b/addons/crm/models/crm_team.py @@ -0,0 +1,183 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import ast +import datetime + +from odoo import api, fields, models, _ +from odoo.tools.safe_eval import safe_eval + + +class Team(models.Model): + _name = 'crm.team' + _inherit = ['mail.alias.mixin', 'crm.team'] + _description = 'Sales 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', default=True, 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.") + # statistics about leads / opportunities / both + lead_unassigned_count = fields.Integer( + string='# Unassigned Leads', compute='_compute_lead_unassigned_count') + lead_all_assigned_month_count = fields.Integer( + string='# Leads/Opps assigned this month', compute='_compute_lead_all_assigned_month_count', + help="Number of leads and opportunities assigned this last month.") + opportunities_count = fields.Integer( + string='# Opportunities', compute='_compute_opportunities_data') + opportunities_amount = fields.Monetary( + string='Opportunities Revenues', compute='_compute_opportunities_data') + opportunities_overdue_count = fields.Integer( + string='# Overdue Opportunities', compute='_compute_opportunities_overdue_data') + opportunities_overdue_amount = fields.Monetary( + string='Overdue Opportunities Revenues', compute='_compute_opportunities_overdue_data',) + # alias: improve fields coming from _inherits, use inherited to avoid replacing them + alias_user_id = fields.Many2one( + 'res.users', related='alias_id.alias_user_id', inherited=True, + domain=lambda self: [('groups_id', 'in', self.env.ref('sales_team.group_sale_salesman_all_leads').id)]) + + def _compute_lead_unassigned_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.lead_unassigned_count = counts.get(team.id, 0) + + def _compute_lead_all_assigned_month_count(self): + limit_date = datetime.datetime.now() - datetime.timedelta(days=30) + leads_data = self.env['crm.lead'].read_group([ + ('team_id', 'in', self.ids), + ('date_open', '>=', fields.Datetime.to_string(limit_date)), + ('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.lead_all_assigned_month_count = counts.get(team.id, 0) + + def _compute_opportunities_data(self): + opportunity_data = self.env['crm.lead'].read_group([ + ('team_id', 'in', self.ids), + ('probability', '<', 100), + ('type', '=', 'opportunity'), + ], ['expected_revenue:sum', 'team_id'], ['team_id']) + counts = {datum['team_id'][0]: datum['team_id_count'] for datum in opportunity_data} + amounts = {datum['team_id'][0]: datum['expected_revenue'] 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_opportunities_overdue_data(self): + opportunity_data = self.env['crm.lead'].read_group([ + ('team_id', 'in', self.ids), + ('probability', '<', 100), + ('type', '=', 'opportunity'), + ('date_deadline', '<', fields.Date.to_string(fields.Datetime.now())) + ], ['expected_revenue', 'team_id'], ['team_id']) + counts = {datum['team_id'][0]: datum['team_id_count'] for datum in opportunity_data} + amounts = {datum['team_id'][0]: (datum['expected_revenue']) for datum in opportunity_data} + for team in self: + team.opportunities_overdue_count = counts.get(team.id, 0) + team.opportunities_overdue_amount = amounts.get(team.id, 0) + + @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 + + # ------------------------------------------------------------ + # ORM + # ------------------------------------------------------------ + + def write(self, vals): + result = super(Team, self).write(vals) + if 'use_leads' in vals or 'use_opportunities' in vals: + for team in self: + alias_vals = team._alias_get_creation_values() + team.write({ + 'alias_name': alias_vals.get('alias_name', team.alias_name), + 'alias_defaults': alias_vals.get('alias_defaults'), + }) + return result + + # ------------------------------------------------------------ + # MESSAGING + # ------------------------------------------------------------ + + def _alias_get_creation_values(self): + values = super(Team, self)._alias_get_creation_values() + values['alias_model_id'] = self.env['ir.model']._get('crm.lead').id + if self.id: + if not self.use_leads and not self.use_opportunities: + values['alias_name'] = False + values['alias_defaults'] = defaults = ast.literal_eval(self.alias_defaults or "{}") + has_group_use_lead = self.env.user.has_group('crm.group_use_lead') + defaults['type'] = 'lead' if has_group_use_lead and self.use_leads else 'opportunity' + defaults['team_id'] = self.id + return values + + # ------------------------------------------------------------ + # ACTIONS + # ------------------------------------------------------------ + + #TODO JEM : refactor this stuff with xml action, proper customization, + @api.model + def action_your_pipeline(self): + action = self.env["ir.actions.actions"]._for_xml_id("crm.crm_lead_action_pipeline") + user_team_id = self.env.user.sale_team_id.id + if user_team_id: + # To ensure that the team is readable in multi company + user_team_id = self.search([('id', '=', user_team_id)], limit=1).id + else: + user_team_id = self.search([], limit=1).id + action['help'] = _("""<p class='o_view_nocontent_smiling_face'>Add new opportunities</p><p> + Looks like you are not a member of a Sales Team. You should add yourself + as a member of one of the Sales Team. +</p>""") + if user_team_id: + action['help'] += _("<p>As you don't belong to any Sales Team, Odoo opens the first one by default.</p>") + + action_context = safe_eval(action['context'], {'uid': self.env.uid}) + if user_team_id: + action_context['default_team_id'] = user_team_id + + action['context'] = action_context + return action + + def _compute_dashboard_button_name(self): + super(Team, self)._compute_dashboard_button_name() + team_with_pipelines = self.filtered(lambda el: el.use_opportunities) + team_with_pipelines.update({'dashboard_button_name': _("Pipeline")}) + + def action_primary_channel_button(self): + if self.use_opportunities: + return self.env["ir.actions.actions"]._for_xml_id("crm.crm_case_form_view_salesteams_opportunity") + return super(Team,self).action_primary_channel_button() + + def _graph_get_model(self): + if self.use_opportunities: + return 'crm.lead' + return super(Team,self)._graph_get_model() + + def _graph_date_column(self): + if self.use_opportunities: + return 'create_date' + return super(Team,self)._graph_date_column() + + def _graph_y_query(self): + if self.use_opportunities: + return 'count(*)' + return super(Team,self)._graph_y_query() + + def _extra_sql_conditions(self): + if self.use_opportunities: + return "AND type LIKE 'opportunity'" + return super(Team,self)._extra_sql_conditions() + + def _graph_title_and_key(self): + if self.use_opportunities: + return ['', _('New Opportunities')] # no more title + return super(Team,self)._graph_title_and_key() |
