diff --git a/addons/crm/data/crm_stage_data.xml b/addons/crm/data/crm_stage_data.xml index 81c69cf5697..4f24ec2e511 100644 --- a/addons/crm/data/crm_stage_data.xml +++ b/addons/crm/data/crm_stage_data.xml @@ -2,27 +2,20 @@ New - 10 - 1 1 Qualified - 30 - 1 2 Proposition - 70 - 1 3 Won - 100 - 1 + True 70 \ No newline at end of file diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py index efba9117dc8..4b869d65ca7 100644 --- a/addons/crm/models/crm_lead.py +++ b/addons/crm/models/crm_lead.py @@ -53,15 +53,6 @@ class Lead(models.Model): _inherit = ['mail.thread.cc', 'mail.thread.blacklist', 'mail.activity.mixin', 'utm.mixin', 'format.address.mixin'] _primary_email = 'email_from' - def _default_probability(self): - if 'default_stage_id' in self._context: - stage_id = self._context.get('default_stage_id') - else: - stage_id = self._default_stage_id() - if stage_id: - return self.env['crm.stage'].browse(stage_id).probability - return 10 - def _default_stage_id(self): team = self.env['crm.team'].sudo()._get_default_team_id(user_id=self.env.uid) return self._stage_find(team_id=team.id, domain=[('fold', '=', False)]).id @@ -100,7 +91,7 @@ class Lead(models.Model): date_conversion = fields.Datetime('Conversion Date', readonly=True) # Only used for type opportunity - probability = fields.Float('Probability', group_operator="avg", default=lambda self: self._default_probability()) + probability = fields.Float('Probability', group_operator="avg", default=10.0) planned_revenue = fields.Monetary('Expected Revenue', currency_field='company_currency', tracking=True) expected_revenue = fields.Monetary('Prorated Revenue', currency_field='company_currency', store=True, compute="_compute_expected_revenue") date_deadline = fields.Date('Expected Closing', help="Estimate of the date on which the opportunity will be won.") @@ -196,21 +187,6 @@ class Lead(models.Model): for lead in self: lead.meeting_count = mapped_data.get(lead.id, 0) - @api.model - def _onchange_stage_id_values(self, stage_id): - """ returns the new values when stage_id has changed """ - if not stage_id: - return {} - stage = self.env['crm.stage'].browse(stage_id) - if stage.on_change: - return {'probability': stage.probability} - return {} - - @api.onchange('stage_id') - def _onchange_stage_id(self): - values = self._onchange_stage_id_values(self.stage_id.id) - self.update(values) - def _onchange_partner_id_values(self, partner_id): """ returns the new values when partner_id has changed """ if partner_id: @@ -299,14 +275,6 @@ class Lead(models.Model): # ORM override (CRUD, fields_view_get, ...) # ---------------------------------------- - @api.model - def name_create(self, name): - res = super(Lead, self).name_create(name) - - # update the probability of the lead if the stage is set to update it automatically - self.browse(res[0])._onchange_stage_id() - return res - @api.model def create(self, vals): # set up context used to find the lead's Sales Team which is needed @@ -329,19 +297,22 @@ class Lead(models.Model): @api.multi def write(self, vals): - # stage change: update date_last_stage_update + # stage change: if 'stage_id' in vals: vals['date_last_stage_update'] = fields.Datetime.now() + stage_id = self.env['crm.stage'].browse(vals['stage_id']) + if stage_id.is_won: + vals.update({'probability': 100}) # Only write the 'date_open' if no salesperson was assigned. if vals.get('user_id') and 'date_open' not in vals and not self.mapped('user_id'): vals['date_open'] = fields.Datetime.now() # stage change with new stage: update probability and date_closed - if vals.get('stage_id') and 'probability' not in vals: - vals.update(self._onchange_stage_id_values(vals.get('stage_id'))) if vals.get('probability', 0) >= 100 or not vals.get('active', True): vals['date_closed'] = fields.Datetime.now() elif 'probability' in vals: vals['date_closed'] = False + if vals.get('user_id') and 'date_open' not in vals: + vals['date_open'] = fields.Datetime.now() return super(Lead, self).write(vals) @api.multi @@ -385,7 +356,7 @@ class Lead(models.Model): def action_set_won(self): """ Won semantic: probability = 100 (active untouched) """ for lead in self: - stage_id = lead._stage_find(domain=[('probability', '=', 100.0), ('on_change', '=', True)]) + stage_id = lead._stage_find(domain=[('is_won', '=', True)]) lead.write({'stage_id': stage_id.id, 'probability': 100}) return True @@ -478,14 +449,6 @@ class Lead(models.Model): 'context': {'default_type': 'opportunity'} } - def toggle_active(self): - """ When re-activating leads and opportunities set their probability - to the default stage one. """ - res = super(Lead, self).toggle_active() - for lead in self.filtered(lambda lead: lead.active and lead.stage_id.probability): - lead.probability = lead.stage_id.probability - return res - # ---------------------------------------- # Business Methods # ---------------------------------------- @@ -686,13 +649,10 @@ class Lead(models.Model): raise UserError(_('Please select more than one element (lead or opportunity) from the list view.')) # Sorting the leads/opps according to the confidence level of its stage, which relates to the probability of winning it - # The confidence level increases with the stage sequence, except when the stage probability is 0.0 (Lost cases) - # An Opportunity always has higher confidence level than a lead, unless its stage probability is 0.0 + # The confidence level increases with the stage sequence + # An Opportunity always has higher confidence level than a lead def opps_key(opportunity): - sequence = -1 - if opportunity.stage_id.on_change: - sequence = opportunity.stage_id.sequence - return (sequence != -1 and opportunity.type == 'opportunity'), sequence, -opportunity.id + return opportunity.type == 'opportunity', opportunity.stage_id.sequence, -opportunity.id opportunities = self.sorted(key=opps_key, reverse=True) # get SORTED recordset of head and tail, and complete list @@ -778,8 +738,6 @@ class Lead(models.Model): if not self.stage_id: stage = self._stage_find(team_id=team_id) value['stage_id'] = stage.id - if stage: - value['probability'] = stage.probability return value @api.multi @@ -1042,7 +1000,7 @@ class Lead(models.Model): if date_deadline < today: result['activity']['overdue'] += 1 # Won in Opportunities - if opp.date_closed and opp.stage_id.probability == 100: + if opp.date_closed and opp.stage_id.is_won: date_closed = fields.Date.from_string(opp.date_closed) if today.replace(day=1) <= date_closed <= today: if opp.planned_revenue: @@ -1122,7 +1080,7 @@ class Lead(models.Model): @api.multi def _track_subtype(self, init_values): self.ensure_one() - if 'stage_id' in init_values and self.probability == 100 and self.stage_id and self.stage_id.on_change: + if 'stage_id' in init_values and self.probability == 100 and self.stage_id: return self.env.ref('crm.mt_lead_won') elif 'active' in init_values and self.probability == 0 and not self.active: return self.env.ref('crm.mt_lead_lost') diff --git a/addons/crm/models/crm_stage.py b/addons/crm/models/crm_stage.py index d324a3fc00a..6902a9b4ccd 100644 --- a/addons/crm/models/crm_stage.py +++ b/addons/crm/models/crm_stage.py @@ -34,8 +34,7 @@ class Stage(models.Model): name = fields.Char('Stage Name', required=True, translate=True) sequence = fields.Integer('Sequence', default=1, help="Used to order stages. Lower is better.") - probability = fields.Float('Probability (%)', required=True, default=10.0, 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.") + is_won = fields.Boolean('Is Won Stage?') requirements = fields.Text('Requirements', help="Enter here the internal requirements for this stage (ex: Offer sent to customer). It will appear as a tooltip over the stage's name.") team_id = fields.Many2one('crm.team', string='Sales Team', ondelete='set null', help='Specific team that uses this stage. Other teams will not be able to see or use this stage.') @@ -44,7 +43,7 @@ class Stage(models.Model): fold = fields.Boolean('Folded in Pipeline', help='This stage is folded in the kanban view when there are no records in that stage to display.') - #This field for interface only + # This field for interface only team_count = fields.Integer('team_count', compute='_compute_team_count') @api.multi diff --git a/addons/crm/report/crm_activity_report_views.xml b/addons/crm/report/crm_activity_report_views.xml index b143b0ad713..8e751d916ea 100644 --- a/addons/crm/report/crm_activity_report_views.xml +++ b/addons/crm/report/crm_activity_report_views.xml @@ -52,7 +52,7 @@ + domain="['&', ('stage_id.is_won', '=', True)]"/> diff --git a/addons/crm/tests/test_crm_lead.py b/addons/crm/tests/test_crm_lead.py index 8e701932050..69100f463bf 100644 --- a/addons/crm/tests/test_crm_lead.py +++ b/addons/crm/tests/test_crm_lead.py @@ -40,7 +40,7 @@ class TestCRMLead(TestCrmCases): # Now I change the stage of opportunity to won. lead.action_set_won() # I check stage of opp should won, after change stage. - stage_id = lead._stage_find(domain=[('probability', '=', 100.0)]) + stage_id = lead._stage_find(domain=[('is_won', '=', True)]) self.assertEqual(stage_id, lead.stage_id, "Stage of opportunity is incorrect!") def test_crm_lead_message(self): diff --git a/addons/crm/views/crm_lead_views.xml b/addons/crm/views/crm_lead_views.xml index 5d6064fbccc..65372748bcf 100644 --- a/addons/crm/views/crm_lead_views.xml +++ b/addons/crm/views/crm_lead_views.xml @@ -753,7 +753,7 @@ - + - + @@ -21,7 +21,7 @@ - + @@ -44,14 +44,11 @@ - - - - - + + diff --git a/addons/website_crm_partner_assign/controllers/main.py b/addons/website_crm_partner_assign/controllers/main.py index 429e8f9d822..3acffdacd50 100644 --- a/addons/website_crm_partner_assign/controllers/main.py +++ b/addons/website_crm_partner_assign/controllers/main.py @@ -102,7 +102,7 @@ class WebsiteAccount(CustomerPortal): 'week': {'label': _('This Week Activities'), 'domain': [('activity_date_deadline', '>=', today), ('activity_date_deadline', '<=', this_week_end_date)]}, 'overdue': {'label': _('Overdue Activities'), 'domain': [('activity_date_deadline', '<', today)]}, - 'won': {'label': _('Won'), 'domain': [('stage_id.probability', '=', 100), ('stage_id.on_change', '=', True)]}, + 'won': {'label': _('Won'), 'domain': [('stage_id.is_won', '=', True)]}, 'lost': {'label': _('Lost'), 'domain': [('active', '=', False), ('probability', '=', 0)]}, } searchbar_sortings = { @@ -170,7 +170,7 @@ class WebsiteAccount(CustomerPortal): "website_crm_partner_assign.portal_my_opportunity", { 'opportunity': opp, 'user_activity': opp.sudo().activity_ids.filtered(lambda activity: activity.user_id == request.env.user)[:1], - 'stages': request.env['crm.stage'].search([('probability', '!=', '100')], order='sequence desc, name desc, id desc'), + 'stages': request.env['crm.stage'].search([('is_won', '!=', True)], order='sequence desc, name desc, id desc'), 'activity_types': request.env['mail.activity.type'].sudo().search([]), 'states': request.env['res.country.state'].sudo().search([]), 'countries': request.env['res.country'].sudo().search([]), diff --git a/addons/website_crm_partner_assign/models/crm_lead.py b/addons/website_crm_partner_assign/models/crm_lead.py index 153aa703939..4bca5f4878d 100644 --- a/addons/website_crm_partner_assign/models/crm_lead.py +++ b/addons/website_crm_partner_assign/models/crm_lead.py @@ -40,7 +40,7 @@ class CrmLead(models.Model): def assign_salesman_of_assigned_partner(self): salesmans_leads = {} for lead in self: - if (lead.stage_id.probability > 0 and lead.stage_id.probability < 100) or lead.stage_id.sequence == 1: + if (lead.probability > 0 and lead.probability < 100) or lead.stage_id.sequence == 1: if lead.partner_assigned_id and lead.partner_assigned_id.user_id != lead.user_id: salesmans_leads.setdefault(lead.partner_assigned_id.user_id.id, []).append(lead.id)