diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py index 025f793e3f2ee6c548b3d3f7e8102d9f9b4e2909..00a4c09ba601357e53a58e3d89b75725c1893b97 100644 --- a/addons/crm/models/crm_lead.py +++ b/addons/crm/models/crm_lead.py @@ -1741,7 +1741,8 @@ class Lead(models.Model): s_lead_lost *= value_result['lost'] / total_lost # 3. Compute Probability to win - lead_probabilities[lead_id] = round(100 * s_lead_won / (s_lead_won + s_lead_lost), 2) + probability = s_lead_won / (s_lead_won + s_lead_lost) + lead_probabilities[lead_id] = min(max(round(100 * probability, 2), 0.01), 99.99) return lead_probabilities # --------------------------------- diff --git a/addons/crm/tests/test_crm_pls.py b/addons/crm/tests/test_crm_pls.py index 66023f62e1ad08582ebc6be0e526fd154150413e..8963dc8ab4921b517833baee465ec82e000de839 100644 --- a/addons/crm/tests/test_crm_pls.py +++ b/addons/crm/tests/test_crm_pls.py @@ -379,6 +379,56 @@ class TestCRMPLS(TransactionCase): self.assertEqual(tools.float_compare(leads[3].automated_probability, 4.21, 2), 0) self.assertEqual(tools.float_compare(leads[8].automated_probability, 0.23, 2), 0) + def test_predictive_lead_scoring_always_won(self): + """ The computation may lead scores close to 100% (or 0%), we check that pending + leads are always in the ]0-100[ range.""" + Lead = self.env['crm.lead'] + LeadScoringFrequency = self.env['crm.lead.scoring.frequency'] + country_id = self.env['res.country'].search([], limit=1).id + stage_id = self.env['crm.stage'].search([], limit=1).id + team_id = self.env['crm.team'].create({'name': 'Team Test 1'}).id + # create two leads + leads = Lead.create([ + self._get_lead_values(team_id, 'edge pending', country_id, False, False, False, False, stage_id), + self._get_lead_values(team_id, 'edge lost', country_id, False, False, False, False, stage_id), + self._get_lead_values(team_id, 'edge won', country_id, False, False, False, False, stage_id), + ]) + # set a new tag + leads.tag_ids = self.env['crm.tag'].create({'name': 'lead scoring edge case'}) + + # Set the PLS config + self.env['ir.config_parameter'].sudo().set_param("crm.pls_start_date", "2000-01-01") + # tag_ids can be used in versions newer than v14 + self.env['ir.config_parameter'].sudo().set_param("crm.pls_fields", "country_id") + + # set leads as won and lost + leads[1].action_set_lost() + leads[2].action_set_won() + + # recompute + Lead._cron_update_automated_probabilities() + Lead.invalidate_cache() + + # adapt the probability frequency to have high values + # this way we are nearly sure it's going to be won + freq_stage = LeadScoringFrequency.search([('variable', '=', 'stage_id'), ('value', '=', str(stage_id))]) + freq_tag = LeadScoringFrequency.search([('variable', '=', 'tag_id'), ('value', '=', str(leads.tag_ids.id))]) + freqs = freq_stage + freq_tag + + # check probabilities: won edge case + freqs.write({'won_count': 10000000, 'lost_count': 1}) + leads._compute_probabilities() + self.assertEqual(tools.float_compare(leads[2].probability, 100, 2), 0) + self.assertEqual(tools.float_compare(leads[1].probability, 0, 2), 0) + self.assertEqual(tools.float_compare(leads[0].probability, 99.99, 2), 0) + + # check probabilities: lost edge case + freqs.write({'won_count': 1, 'lost_count': 10000000}) + leads._compute_probabilities() + self.assertEqual(tools.float_compare(leads[2].probability, 100, 2), 0) + self.assertEqual(tools.float_compare(leads[1].probability, 0, 2), 0) + self.assertEqual(tools.float_compare(leads[0].probability, 0.01, 2), 0) + def test_settings_pls_start_date(self): # We test here that settings never crash due to ill-configured config param 'crm.pls_start_date' set_param = self.env['ir.config_parameter'].sudo().set_param