[IMP] website_crm_score: multi improvements

Move section_user before the use of this one in a many2many, else demo data are not installable because field id is never created in db. (same 'issue' that https://github.com/odoo/odoo/issues/2386)
    Add a cron to compute score each hours
    Add merge pageview and merge (clean) score when we merge opportunities via merge_opportunities/merge_dependencies
    Score the lead after the assignation to salesteam. Because when we assign to salesteam, sometimes we call the method merge_opportunities which one delete old scores on this lead, all score rules needs to be recomputed since the fields have been updated. So we compute now the score not at starting, but between assignation to salesteam and salesman.
This commit is contained in:
Jeremy Kersten
2015-01-19 09:45:59 +01:00
parent 14efd71694
commit 576933ff08
5 changed files with 85 additions and 56 deletions
@@ -12,7 +12,7 @@
<!-- Creating salesmen -->
<record id="website_crm_score_partner_0" model="res.partner">
<field name="name">Toni Buchanan</field>
<field name="email">Toni.Buchanan@yourcompany?com</field>
<field name="email">Toni.Buchanan@yourcompany.com</field>
<field name="supplier" eval="False"/>
<field name="customer" eval="False"/>
<field name="notify_email">none</field>
+20 -1
View File
@@ -10,7 +10,7 @@ class Lead(models.Model):
def _count_pageviews(self):
self.pageviews_count = len(self.score_pageview_ids)
@api.depends('score_ids.value')
@api.depends('score_ids', 'score_ids.value')
def _compute_score(self):
self._cr.execute("""
SELECT
@@ -54,4 +54,23 @@ class Lead(models.Model):
def get_score_domain_cookies(self):
# TODO should be return request.httprequest.host in master
# return request.httprequest.host
return "." + ".".join(request.httprequest.host.rsplit(".", 2)[1:])
def _merge_pageviews(self, cr, uid, opportunity_id, opportunities, context=None):
lead_ids = [opp.id for opp in opportunities if opp.id != opportunity_id]
pv_ids = self.pool.get('website.crm.pageview').search(cr, uid, [('lead_id', 'in', lead_ids)], context=context)
self.pool.get('website.crm.pageview').write(cr, uid, pv_ids, {'lead_id': opportunity_id}, context=context)
return True
def _merge_scores(self, cr, uid, opportunity_id, opportunities, context=None):
# We needs to delete score from opportunity_id, to be sure that all rules will be re-evaluated.
self.write(cr, uid, [opportunity_id], {'score_ids': [(6, 0, [])]}, context=context)
return True
def merge_dependences(self, cr, uid, highest, opportunities, context=None):
self._merge_pageviews(cr, uid, highest, opportunities, context=context)
self._merge_scores(cr, uid, highest, opportunities, context=context)
# Call default merge function
super(Lead, self).merge_dependences(cr, uid, highest, opportunities, context=context)
+49 -52
View File
@@ -26,6 +26,51 @@ except ImportError:
return True
class section_user(models.Model):
_name = 'section.user'
@api.one
def _count_leads(self):
if self.id:
limit_date = datetime.datetime.now() - datetime.timedelta(days=30)
domain = [('user_id', '=', self.user_id.id),
('section_id', '=', self.section_id.id),
('assign_date', '>', limit_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT))
]
self.leads_count = self.env['crm.lead'].search_count(domain)
else:
self.leads_count = 0
@api.one
def _get_percentage(self):
try:
self.percentage_leads = round(100 * self.leads_count / float(self.maximum_user_leads), 2)
except ZeroDivisionError:
self.percentage_leads = 0.0
@api.one
@api.constrains('section_user_domain')
def _assert_valid_domain(self):
try:
domain = safe_eval(self.section_user_domain or '[]', evaluation_context)
self.env['crm.lead'].search(domain)
except Exception:
raise Warning('The domain is incorrectly formatted')
section_id = fields.Many2one('crm.case.section', string='SaleTeam', required=True)
user_id = fields.Many2one('res.users', string='Saleman', required=True)
name = fields.Char(related='user_id.partner_id.display_name')
running = fields.Boolean(string='Running', default=True)
section_user_domain = fields.Char('Domain')
maximum_user_leads = fields.Integer('Leads Per Month')
leads_count = fields.Integer('Assigned Leads', compute='_count_leads', help='Assigned Leads this last month')
percentage_leads = fields.Float(compute='_get_percentage', string='Percentage leads')
@api.one
def toggle_active(self):
self.running = not self.running
class crm_case_section(osv.osv):
_inherit = "crm.case.section"
@@ -72,11 +117,6 @@ class crm_case_section(osv.osv):
user_ids = fields.Many2many('res.users', 'section_user', 'section_id', 'user_id', readonly=True) # Use for display in Kanban
min_for_assign = fields.Integer("Minimum score", help="Minimum Score for a lead to be automatically assign (>=)", default=0, required=True)
@api.model
def score_and_assign_leads(self):
self.env['website.crm.score'].assign_scores_to_leads()
self._assign_leads()
@api.model
def direct_assign_leads(self, ids=[]):
self._assign_leads()
@@ -183,8 +223,6 @@ class crm_case_section(osv.osv):
if not user['nbr']:
del users[i]
# ids is needed when the button is used to start the function,
# the default [] is needed for the function to be usable by the cron
@api.model
def _assign_leads(self, dry=False):
# Emptying the table
@@ -203,49 +241,8 @@ class crm_case_section(osv.osv):
all_section_users = self.env['section.user'].search([('running', '=', True)])
self.assign_leads_to_salesteams(all_salesteams, dry=dry)
# Compute score after assign to salesteam, because if a merge has been done, the score for leads is removed.
self.env['website.crm.score'].assign_scores_to_leads()
self.assign_leads_to_salesmen(all_section_users, dry=dry)
class section_user(models.Model):
_name = 'section.user'
@api.one
def _count_leads(self):
if self.id:
limit_date = datetime.datetime.now() - datetime.timedelta(days=30)
domain = [('user_id', '=', self.user_id.id),
('section_id', '=', self.section_id.id),
('assign_date', '>', limit_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT))
]
self.leads_count = self.env['crm.lead'].search_count(domain)
else:
self.leads_count = 0
@api.one
def _get_percentage(self):
try:
self.percentage_leads = round(100 * self.leads_count / float(self.maximum_user_leads), 2)
except ZeroDivisionError:
self.percentage_leads = 0.0
@api.one
@api.constrains('section_user_domain')
def _assert_valid_domain(self):
try:
domain = safe_eval(self.section_user_domain or '[]', evaluation_context)
self.env['crm.lead'].search(domain)
except Exception:
raise Warning('The domain is incorrectly formatted')
section_id = fields.Many2one('crm.case.section', string='SaleTeam', required=True)
user_id = fields.Many2one('res.users', string='Saleman', required=True)
name = fields.Char(related='user_id.partner_id.display_name')
running = fields.Boolean(string='Running', default=True)
section_user_domain = fields.Char('Domain')
maximum_user_leads = fields.Integer('Leads Per Month')
leads_count = fields.Integer('Assigned Leads', compute='_count_leads', help='Assigned Leads this last month')
percentage_leads = fields.Float(compute='_get_percentage', string='Percentage leads')
@api.one
def toggle_active(self):
self.running = not self.running
@@ -11,6 +11,7 @@ evaluation_context = {
'context_today': datetime.datetime.now,
}
class website_crm_score(models.Model):
_name = 'website.crm.score'
+14 -2
View File
@@ -6,7 +6,7 @@
<!-- Scheduler for Lead Scoring and Assignation -->
<record forcecreate="True" id="ir_cron_lead_assign" model="ir.cron">
<field name="name">Lead Scoring and Assignation Cron</field>
<field name="name">Lead Assignation</field>
<field eval="False" name="active" />
<field name="user_id" ref="base.user_root" />
<field name="interval_number">1</field>
@@ -14,9 +14,21 @@
<field name="numbercall">-1</field>
<field eval="False" name="doall" />
<field eval="'crm.case.section'" name="model" />
<field eval="'score_and_assign_leads'" name="function" />
<field eval="'direct_assign_leads'" name="function" />
</record>
<!-- Scheduler for Lead Scoring -->
<record forcecreate="True" id="ir_cron_lead_scoring" model="ir.cron">
<field name="name">Lead Scoring </field>
<field eval="False" name="active" />
<field name="user_id" ref="base.user_root" />
<field name="interval_number">1</field>
<field name="interval_type">hours</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall" />
<field eval="'website.crm.score'" name="model" />
<field eval="'assign_scores_to_leads'" name="function" />
</record>
<record id="action_score_now" model="ir.actions.server">
<field name="name">Apply marked scores</field>