From ba294e231845a798567e47f7572bdb909dd2d7d0 Mon Sep 17 00:00:00 2001 From: Jeremy Kersten Date: Mon, 19 Jan 2015 09:52:46 +0100 Subject: [PATCH] [REF] website_crm_score: migrate code to be compatible with master. Courtesy Review : xmo, mat --- addons/website_crm_score/__init__.py | 1 + addons/website_crm_score/__openerp__.py | 4 +- .../website_crm_score/controllers/__init__.py | 1 + addons/website_crm_score/controllers/main.py | 41 +-- .../demo/website_crm_score_demo.xml | 144 ++++----- addons/website_crm_score/models/__init__.py | 3 +- addons/website_crm_score/models/crm_lead.py | 50 +-- addons/website_crm_score/models/ir.py | 16 +- .../website_crm_score/models/leads_dry_run.py | 17 +- addons/website_crm_score/models/pageview.py | 33 +- addons/website_crm_score/models/sales_team.py | 108 ++++--- .../models/website_crm_score.py | 5 +- .../security/ir.model.access.csv | 4 +- .../static/src/js/display_filters.js | 304 ------------------ addons/website_crm_score/tests/__init__.py | 1 + addons/website_crm_score/tests/common.py | 56 ++-- addons/website_crm_score/tests/test_assign.py | 19 +- .../website_crm_score/tests/test_dry_run.py | 29 +- .../website_crm_score/tests/test_pageview.py | 17 +- addons/website_crm_score/views/marketing.xml | 68 ++-- addons/website_crm_score/views/reporting.xml | 4 +- addons/website_crm_score/views/sales.xml | 32 +- .../views/website_crm_score.xml | 5 - 23 files changed, 338 insertions(+), 624 deletions(-) delete mode 100644 addons/website_crm_score/static/src/js/display_filters.js diff --git a/addons/website_crm_score/__init__.py b/addons/website_crm_score/__init__.py index 396c76fe87a..14ce547a094 100644 --- a/addons/website_crm_score/__init__.py +++ b/addons/website_crm_score/__init__.py @@ -1,2 +1,3 @@ +# -*- coding: utf-8 -*- import models import controllers diff --git a/addons/website_crm_score/__openerp__.py b/addons/website_crm_score/__openerp__.py index a33e1693dbe..5e363a35f1b 100644 --- a/addons/website_crm_score/__openerp__.py +++ b/addons/website_crm_score/__openerp__.py @@ -1,9 +1,9 @@ { 'name': "Lead Scoring", - 'category': "Test", + 'category': "CRM", 'version': "1.0", 'depends': ['base', 'sales_team', 'marketing', 'website_crm'], - 'author': "OpenErp S.A.", + 'author': "Odoo S.A.", 'description': """\ Lead scoring""", 'data': [ diff --git a/addons/website_crm_score/controllers/__init__.py b/addons/website_crm_score/controllers/__init__.py index 8ee9bae18d9..a84d81a791b 100644 --- a/addons/website_crm_score/controllers/__init__.py +++ b/addons/website_crm_score/controllers/__init__.py @@ -1 +1,2 @@ +# -*- coding: utf-8 -*- import main diff --git a/addons/website_crm_score/controllers/main.py b/addons/website_crm_score/controllers/main.py index 8d5f362d159..cc95bec8685 100644 --- a/addons/website_crm_score/controllers/main.py +++ b/addons/website_crm_score/controllers/main.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from openerp import addons, http, SUPERUSER_ID, fields from openerp.http import request @@ -9,24 +10,23 @@ class PageController(addons.website.controllers.main.Website): response = super(PageController, self).page(page, **opt) # duplication of ir_http.py - if hasattr(response, 'status_code') and response.status_code == 200: + if getattr(response, 'status_code', 0) == 200: try: view = request.website.get_template(page) + except: + pass # view not found + else: if view.track: # avoid tracking redirected page cr, uid, context = request.cr, request.uid, request.context - lead_id = request.registry["crm.lead"].decode(request) + lead_id = request.env["crm.lead"].decode(request) url = request.httprequest.url - vals = {'lead_id': lead_id, 'partner_id': request.session.get('uid', None), 'url': url} + vals = {'lead_id': lead_id, 'user_id': request.session.get('uid'), 'url': url} - if lead_id and request.registry['website.crm.pageview'].create_pageview(cr, uid, vals, context=context): - # create_pageview was successful - pass - else: + if not lead_id or request.registry['website.crm.pageview'].create_pageview(cr, uid, vals, context=context): + # create_pageview failed response.delete_cookie('lead_id') request.session.setdefault('pages_viewed', {})[url] = fields.Datetime.now() request.session.modified = True - except: - pass # view not found return response @@ -45,8 +45,6 @@ class ContactController(addons.website_crm.controllers.main.contactus): # sign the lead_id sign = lead_model.encode(lead_id) response.set_cookie('lead_id', sign, domain=lead_model.get_score_domain_cookies()) - else: - pass # lead_id == None because no lead was created return response def create_real_lead(self, request, values, kwargs): @@ -54,7 +52,7 @@ class ContactController(addons.website_crm.controllers.main.contactus): return super(ContactController, self).create_lead(request, values, kwargs) def create_lead(self, request, values, kwargs): - cr, uid, context = request.cr, request.uid, request.context + cr, context = request.cr, request.context lead_model = request.registry["crm.lead"] lead_id = lead_model.decode(request) @@ -62,10 +60,15 @@ class ContactController(addons.website_crm.controllers.main.contactus): # domain: leads that are still open: # NOT [ on_change AND (proba = 0 OR proba = 100) ] # the condition on the lead_id is prepended - domain = [('id', '=', lead_id), - '!', '&', ('stage_id.on_change', '!=', True), - '|', ('stage_id.probability', '!=', 0.0), ('stage_id.probability', '!=', 100.0) - ] + domain = [ + ('id', '=', lead_id), + '|', + ('stage_id.on_change', '=', False), + '&', + ('stage_id.probability', '!=', 0), + ('stage_id.probability', '!=', 100) + ] + domain.extend(['|', ('stage_id.on_change', '=', False), '&', ('stage_id.probability', '!=', 0), ('stage_id.probability', '!=', 100)]) lead_instance = lead_model.search(cr, SUPERUSER_ID, domain, context=context) if lead_instance: @@ -75,7 +78,7 @@ class ContactController(addons.website_crm.controllers.main.contactus): # NOTE: the following should be changed when dynamic forms exist changed_values = {} for fieldname, fieldvalue in values.items(): - if fieldname in lead._all_columns and fieldvalue: # and not lead[fieldname]: # rem : why this last condition ? + if fieldname in lead._all_columns and fieldvalue: if lead[fieldname] and lead[fieldname] != fieldvalue: changed_values[fieldname] = fieldvalue else: @@ -89,7 +92,6 @@ class ContactController(addons.website_crm.controllers.main.contactus): else: # either no lead_id cookie OR the lead_id doesn't exist in db OR the current one is closed -> a lead is created - lang = context.get('lang', False) lang_id = request.registry["res.lang"].search(cr, SUPERUSER_ID, [('code', '=', lang)], context=context) lang_id = lang_id and lang_id[0] or False @@ -101,7 +103,7 @@ class ContactController(addons.website_crm.controllers.main.contactus): url_list = [] pages_viewed = request.session['pages_viewed'] for url, date in pages_viewed.iteritems(): - vals = {'partner_id': request.session.get('uid', None), 'url': url, 'view_date': date} + vals = {'user_id': request.session.get('uid'), 'url': url, 'view_date': date} score_pageview_ids.append((0, 0, vals)) url_list.append(url) del request.session['pages_viewed'] @@ -117,5 +119,4 @@ class ContactController(addons.website_crm.controllers.main.contactus): if body: request.registry['crm.lead'].message_post(cr, SUPERUSER_ID, [new_lead_id], body=body, subject="Pages visited", context=context) - # TODO : try to write the cookies here, after retreiving a response ? return new_lead_id diff --git a/addons/website_crm_score/demo/website_crm_score_demo.xml b/addons/website_crm_score/demo/website_crm_score_demo.xml index bd68d5cd478..8ca0fc5dfa9 100644 --- a/addons/website_crm_score/demo/website_crm_score_demo.xml +++ b/addons/website_crm_score/demo/website_crm_score_demo.xml @@ -2,11 +2,11 @@ - - [['country_id', '=', 'France']] + + [['country_id', '=', 'France']] - - [['country_id', '=', 'Belgium']] + + [['country_id', '=', 'Belgium']] @@ -85,152 +85,152 @@ - + - + 2 - ['|', ['country_id', '=', 'Belgium'], ['country_id', '=', 'France']] + ['|', ['country_id', '=', 'Belgium'], ['country_id', '=', 'France']] - + - + 1 - [['country_id', '!=', 'Belgium']] + [['country_id', '!=', 'Belgium']] - + - + 1 - + - + 2 - ['&', ['lang_id', '=', 'English'], ['country_id', '=', 'Belgium']] + ['&', ['lang_id', '=', 'English'], ['country_id', '=', 'Belgium']] - + - + 1 - + - + 3 - [['country_id', '=', 'France']] + [['country_id', '=', 'France']] - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/addons/website_crm_score/models/__init__.py b/addons/website_crm_score/models/__init__.py index 967816958c5..e72a5602e0f 100644 --- a/addons/website_crm_score/models/__init__.py +++ b/addons/website_crm_score/models/__init__.py @@ -1,6 +1,7 @@ +# -*- coding: utf-8 -*- import website_crm_score import crm_lead import ir import sales_team import pageview -import leads_dry_run \ No newline at end of file +import leads_dry_run diff --git a/addons/website_crm_score/models/crm_lead.py b/addons/website_crm_score/models/crm_lead.py index b2f7623ca52..9027caf9794 100644 --- a/addons/website_crm_score/models/crm_lead.py +++ b/addons/website_crm_score/models/crm_lead.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from openerp.http import request from openerp import api, fields, models, SUPERUSER_ID import md5 @@ -34,17 +35,17 @@ class Lead(models.Model): lang_id = fields.Many2one('res.lang', string='Language', help="Language from the website when lead has been created") def encode(self, lead_id): - encrypted_lead_id = md5.new("%s%s" % (lead_id, self.get_key())).hexdigest() - return "%s-%s" % (str(lead_id), encrypted_lead_id) + md5_lead_id = md5.new("%s%s" % (lead_id, self.get_key())).hexdigest() + return "%s-%s" % (str(lead_id), md5_lead_id) def decode(self, request): # opens the cookie, verifies the signature of the lead_id # returns lead_id if the verification passes and None otherwise cookie_content = request.httprequest.cookies.get('lead_id') if cookie_content: - lead_id, encrypted_lead_id = cookie_content.split('-', 1) + lead_id, md5_lead_id = cookie_content.split('-', 1) expected_encryped_lead_id = md5.new("%s%s" % (lead_id, self.get_key())).hexdigest() - if encrypted_lead_id == expected_encryped_lead_id: + if md5_lead_id == expected_encryped_lead_id: return int(lead_id) else: return None @@ -53,38 +54,37 @@ class Lead(models.Model): return self.pool['ir.config_parameter'].get_param(request.cr, SUPERUSER_ID, 'database.uuid') def get_score_domain_cookies(self): - # TODO should be return request.httprequest.host in master - # return request.httprequest.host - dom = "." + ".".join(request.httprequest.host.rsplit(".", 2)[1:]) - if ':' in dom: # Hack if in local mode with port - dom = request.httprequest.host - return dom + return request.httprequest.host - def _merge_pageviews(self, cr, uid, opportunity_id, opportunities, context=None): + @api.model + def _merge_pageviews(self, opportunity_id, opportunities): + crmpv = self.env['website.crm.pageview'] 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, SUPERUSER_ID, pv_ids, {'lead_id': opportunity_id}, context=context) - return True + pv_ids = crmpv.sudo().search([('lead_id', 'in', lead_ids)]) + pv_ids.write({'lead_id': opportunity_id}) - def _merge_scores(self, cr, uid, opportunity_id, opportunities, context=None): + @api.model + def _merge_scores(self, opportunity_id, opportunities): # We needs to delete score from opportunity_id, to be sure that all rules will be re-evaluated. - self.write(cr, SUPERUSER_ID, [opportunity_id], {'score_ids': [(6, 0, [])]}, context=context) - return True + self.sudo().browse(opportunity_id).write({'score_ids': [(6, 0, [])]}) - 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) + @api.model + def merge_dependences(self, highest, opportunities): + self._merge_pageviews(highest, opportunities) + self._merge_scores(highest, opportunities) # Call default merge function - super(Lead, self).merge_dependences(cr, uid, highest, opportunities, context=context) + super(Lead, self).merge_dependences(highest, opportunities) # Overwritte ORM to add or remove the assign date - def create(self, cr, uid, vals, context=None): + @api.model + def create(self, vals): if vals.get('user_id'): vals['assign_date'] = fields.datetime.now() - return super(Lead, self).create(cr, uid, vals, context=context) + return super(Lead, self).create(vals) - def write(self, cr, uid, ids, vals, context=None): + @api.multi + def write(self, vals): if 'user_id' in vals: vals['assign_date'] = vals.get('user_id') and fields.datetime.now() or False - return super(Lead, self).write(cr, uid, ids, vals, context=context) + return super(Lead, self).write(vals) diff --git a/addons/website_crm_score/models/ir.py b/addons/website_crm_score/models/ir.py index 3712e259f00..e1240551be1 100644 --- a/addons/website_crm_score/models/ir.py +++ b/addons/website_crm_score/models/ir.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from openerp import fields, models from openerp.http import request from openerp.osv import osv @@ -9,16 +10,13 @@ class ir_http(models.AbstractModel): def _dispatch(self): response = super(ir_http, self)._dispatch() - if hasattr(response, 'status_code') and response.status_code == 200: # may not be needed because find_handler not used anymore - if request.endpoint and request.endpoint.routing and request.endpoint.routing.get('track', False): - cr, uid, context = request.cr, request.uid, request.context - lead_id = request.registry["crm.lead"].decode(request) + if getattr(response, 'status_code', 0) == 200: + if request.endpoint and request.endpoint.routing and request.endpoint.routing.get('track'): + lead_id = request.env["crm.lead"].decode(request) url = request.httprequest.url - vals = {'lead_id': lead_id, 'partner_id': request.session.get('uid', None), 'url': url} - if lead_id and request.registry['website.crm.pageview'].create_pageview(cr, uid, vals, context=context): - # create_pageview was successful - pass - else: + vals = {'lead_id': lead_id, 'user_id': request.session.get('uid'), 'url': url} + if not lead_id or request.env['website.crm.pageview'].create_pageview(vals): + # create_pageview was fail response.delete_cookie('lead_id') request.session.setdefault('pages_viewed', {})[url] = fields.Datetime.now() request.session.modified = True diff --git a/addons/website_crm_score/models/leads_dry_run.py b/addons/website_crm_score/models/leads_dry_run.py index 1454e979852..3e4071e2f2f 100644 --- a/addons/website_crm_score/models/leads_dry_run.py +++ b/addons/website_crm_score/models/leads_dry_run.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from openerp import fields, models, api @@ -5,7 +6,7 @@ class leads_dry_run(models.TransientModel): _name = "leads.dry.run" lead_id = fields.Many2one('crm.lead', string='Lead', required=True) - section_id = fields.Many2one('crm.case.section', string='SaleTeam', required=True) + team_id = fields.Many2one('crm.team', string='SaleTeam', required=True, oldname='section_id') user_id = fields.Many2one('res.users', string='Saleman') @api.model @@ -13,17 +14,13 @@ class leads_dry_run(models.TransientModel): # Allow to assign the result from a previous dry run. # Once the user agrees with the result shown by a dry run # It differs from launching the assignement process again, - # because salemen would be selected at random again - dry_run_fields = ['lead_id', - 'section_id', - 'user_id', - ] - all_dry_run = self.search_read(domain=[('user_id','!=',False)], fields=dry_run_fields) + # because salemen would be selected at random again + all_dry_run = self.search([('user_id', '!=', False)]) for dry_run in all_dry_run: - lead_record = self.env['crm.lead'].browse(dry_run['lead_id'][0]) + lead_record = dry_run.lead_id values = { - 'section_id': dry_run['section_id'][0], - 'user_id': dry_run['user_id'][0], + 'team_id': dry_run.team_id.id, + 'user_id': dry_run.user_id.id, 'assign_date': fields.Datetime.now() } lead_record.write(values) diff --git a/addons/website_crm_score/models/pageview.py b/addons/website_crm_score/models/pageview.py index f658b2de44f..b6ff22ce2da 100644 --- a/addons/website_crm_score/models/pageview.py +++ b/addons/website_crm_score/models/pageview.py @@ -1,4 +1,5 @@ -from openerp import fields, models, SUPERUSER_ID +# -*- coding: utf-8 -*- +from openerp import fields, models, SUPERUSER_ID, tools, api from psycopg2 import IntegrityError @@ -7,21 +8,20 @@ class pageview(models.Model): view_date = fields.Datetime(string='Viewing Date') lead_id = fields.Many2one('crm.lead', string='Lead') - partner_id = fields.Many2one('res.partner', string='Partner') + user_id = fields.Many2one('res.users', string='User', oldname='partner_id') url = fields.Char(string='Url') - def create_pageview(self, cr, uid, vals, context=None, test=False): + @api.model + def create_pageview(self, vals, test=False): # returns True if the operation in the db was successful, False otherwise - lead_id = vals.get('lead_id', None) - partner_id = vals.get('partner_id', None) - url = vals.get('url', None) + lead_id = vals.get('lead_id') + user_id = vals.get('user_id') + url = vals.get('url') view_date = fields.Datetime.now() - # registry = modules.registry.RegistryManager.get(request.session.db) - # with registry.cursor() as pv_cr: with self.pool.cursor() as pv_cr: if test: - pv_cr = cr + pv_cr = self._cr pv_cr.execute(''' UPDATE website_crm_pageview SET view_date=%s WHERE lead_id=%s AND url=%s RETURNING id; ''', (view_date, lead_id, url)) @@ -31,17 +31,18 @@ class pageview(models.Model): else: # update failed try: - pv_cr.execute(''' - INSERT INTO website_crm_pageview (lead_id, partner_id, url, view_date) - SELECT %s,%s,%s,%s - RETURNING id; - ''', (lead_id, partner_id, url, view_date)) + with tools.mute_logger('openerp.sql_db'): + pv_cr.execute(''' + INSERT INTO website_crm_pageview (lead_id, user_id, url, view_date) + SELECT %s,%s,%s,%s + RETURNING id; + ''', (lead_id, user_id, url, view_date)) fetch = pv_cr.fetchone() if fetch: # a new pageview has been created, a message is posted body = '' + url + '' - ctx = dict(context or {}, mail_notify_noemail=True) - self.pool['crm.lead'].message_post(cr, SUPERUSER_ID, [lead_id], body=body, subject="Page visited", context=ctx) + ctx = dict(self._context, mail_notify_noemail=True) + self.pool['crm.lead'].message_post(self._cr, SUPERUSER_ID, [lead_id], body=body, subject="Page visited", context=ctx) return True except IntegrityError: return False diff --git a/addons/website_crm_score/models/sales_team.py b/addons/website_crm_score/models/sales_team.py index 4fc794be4ad..feab22d89db 100644 --- a/addons/website_crm_score/models/sales_team.py +++ b/addons/website_crm_score/models/sales_team.py @@ -1,9 +1,9 @@ -from openerp.osv import osv +# -*- coding: utf-8 -*- from openerp import fields, api, models -import datetime +from openerp.osv import osv from openerp.tools.safe_eval import safe_eval from random import randint, shuffle -from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT +import datetime import logging import math @@ -20,21 +20,23 @@ try: return bool(address.validate_address(mail)) except ImportError: - _logger.warning('Flanker library not found, Flanker features (check email on lead) disabled. If you plan to use it, please install the Flanker library from http://pypi.python.org/pypi/flanker') + _logger.warning('Flanker library not found, Flanker features (check email on lead) disabled. \ + If you plan to use it, please install the Flanker library from http://pypi.python.org/pypi/flanker') def checkmail(mail): return True -class section_user(models.Model): - _name = 'section.user' + +class team_user(models.Model): + _name = 'team.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)) + ('team_id', '=', self.team_id.id), + ('assign_date', '>', fields.Datetime.to_string(limit_date)) ] self.leads_count = self.env['crm.lead'].search_count(domain) else: @@ -48,19 +50,19 @@ class section_user(models.Model): self.percentage_leads = 0.0 @api.one - @api.constrains('section_user_domain') + @api.constrains('team_user_domain') def _assert_valid_domain(self): try: - domain = safe_eval(self.section_user_domain or '[]', evaluation_context) + domain = safe_eval(self.team_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) + team_id = fields.Many2one('crm.team', string='SaleTeam', required=True, oldname='section_id') 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') + team_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') @@ -70,51 +72,53 @@ class section_user(models.Model): self.running = not self.running -class crm_case_section(osv.osv): - _inherit = "crm.case.section" +class crm_team(osv.osv): + _inherit = "crm.team" @api.one def _count_leads(self): if self.id: - self.leads_count = self.env['crm.lead'].search_count([('section_id', '=', self.id)]) + self.leads_count = self.env['crm.lead'].search_count([('team_id', '=', self.id)]) else: self.leads_count = 0 @api.one def _assigned_leads(self): limit_date = datetime.datetime.now() - datetime.timedelta(days=30) - domain = [('assign_date', '>=', limit_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT)), - ('section_id', '=', self.id), + domain = [('assign_date', '>=', fields.Datetime.to_string(limit_date)), + ('team_id', '=', self.id), ('user_id', '!=', False) ] self.assigned_leads = self.env['crm.lead'].search_count(domain) @api.one def _unassigned_leads(self): - self.unassigned_leads = self.env['crm.lead'].search_count([('section_id', '=', self.id), ('user_id', '=', False), ('assign_date', '=', False)]) + self.unassigned_leads = self.env['crm.lead'].search_count( + [('team_id', '=', self.id), ('user_id', '=', False), ('assign_date', '=', False)] + ) @api.one def _capacity(self): - self.capacity = sum(s.maximum_user_leads for s in self.section_user_ids) + self.capacity = sum(s.maximum_user_leads for s in self.team_user_ids) @api.one - @api.constrains('score_section_domain') + @api.constrains('score_team_domain') def _assert_valid_domain(self): try: - domain = safe_eval(self.score_section_domain or '[]', evaluation_context) + domain = safe_eval(self.score_team_domain or '[]', evaluation_context) self.env['crm.lead'].search(domain) except Exception: raise Warning('The domain is incorrectly formatted') ratio = fields.Float(string='Ratio') - score_section_domain = fields.Char('Domain') + score_team_domain = fields.Char('Domain') leads_count = fields.Integer(compute='_count_leads') assigned_leads = fields.Integer(compute='_assigned_leads') unassigned_leads = fields.Integer(compute='_unassigned_leads') capacity = fields.Integer(compute='_capacity') - section_user_ids = fields.One2many('section.user', 'section_id', string='Salesman') - 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) + team_user_ids = fields.One2many('team.user', 'team_id', string='Salesman') + user_ids = fields.Many2many('res.users', 'team_user', 'team_id', 'user_id', readonly=True) # Use for display in Kanban + min_for_assign = fields.Integer("Minimum score", help="Minimum score to be automatically assign (>=)", default=0, required=True) @api.model def direct_assign_leads(self, ids=[]): @@ -134,8 +138,8 @@ class crm_case_section(osv.osv): while haslead: haslead = False for salesteam in all_salesteams: - domain = safe_eval(salesteam['score_section_domain'], evaluation_context) - domain.extend([('section_id', '=', False), ('user_id', '=', False)]) + domain = safe_eval(salesteam['score_team_domain'], evaluation_context) + domain.extend([('team_id', '=', False), ('user_id', '=', False)]) domain.extend(['|', ('stage_id.on_change', '=', False), '&', ('stage_id.probability', '!=', 0), ('stage_id.probability', '!=', 100)]) leads = self.env["crm.lead"].search(domain, limit=50) haslead = haslead or (len(leads) == 50 and not dry) @@ -145,59 +149,62 @@ class crm_case_section(osv.osv): if dry: for lead in leads: - values = {'lead_id': lead.id, 'section_id': salesteam['id']} + values = {'lead_id': lead.id, 'team_id': salesteam['id']} self.env['leads.dry.run'].create(values) else: - leads.write({'section_id': salesteam['id']}) + leads.write({'team_id': salesteam['id']}) # Erase fake/false email spams = map(lambda x: x.id, filter(lambda x: x.email_from and not checkmail(x.email_from), leads)) + if spams: self.env["crm.lead"].browse(spams).write({'email_from': False}) # Merge duplicated lead - leads_done = [] + leads_done = set() for lead in leads: if lead.id not in leads_done: leads_duplicated = lead.get_duplicated_leads(False) if len(leads_duplicated) > 1: self.env["crm.lead"].browse(leads_duplicated).merge_opportunity(False, False) - leads_done += leads_duplicated + leads_done.update(leads_duplicated) self._cr.commit() self._cr.commit() @api.model - def assign_leads_to_salesmen(self, all_section_users, dry=False): + def assign_leads_to_salesmen(self, all_team_users, dry=False): users = [] - for su in all_section_users: + for su in all_team_users: if (su.maximum_user_leads - su.leads_count) <= 0: continue - domain = safe_eval(su.section_user_domain or '[]', evaluation_context) - domain.append(('user_id', '=', False)) - domain.append(('assign_date', '=', False)) - domain.append(('score', '>=', su.section_id.min_for_assign)) + domain = safe_eval(su.team_user_domain or '[]', evaluation_context) + domain.extend([ + ('user_id', '=', False), + ('assign_date', '=', False), + ('score', '>=', su.team_id.min_for_assign) + ]) # assignation rythm: 2 days of leads if a lot of leads should be assigned limit = int(math.ceil(su.maximum_user_leads / 15.0)) if dry: - dry_leads = self.env["leads.dry.run"].search([('section_id', '=', su.section_id.id)]) - domain.append(['id', 'in', [dl.lead_id.id for dl in dry_leads]]) + dry_leads = self.env["leads.dry.run"].search([('team_id', '=', su.team_id.id)]) + domain.append(['id', 'in', dry_leads.mapped('lead_id.id')]) else: - domain.append(('section_id', '=', su.section_id.id)) + domain.append(('team_id', '=', su.team_id.id)) - leads = self.env["crm.lead"].search(domain, order='score desc', limit=limit * len(su.section_id.section_user_ids)) + leads = self.env["crm.lead"].search(domain, order='score desc', limit=limit * len(su.team_id.team_user_ids)) users.append({ "su": su, "nbr": min(su.maximum_user_leads - su.leads_count, limit), "leads": leads }) - assigned = {} + assigned = set() while users: i = 0 - # statistically select the user that should receive the next lead + # statistically select the user that should receive the next lead idx = randint(0, reduce(lambda nbr, x: nbr + x['nbr'], users, 0) - 1) while idx > users[i]['nbr']: @@ -214,16 +221,16 @@ class crm_case_section(osv.osv): #lead convert for this user lead = user['leads'][0] - assigned[lead] = True + assigned.add(lead) if dry: - values = {'lead_id': lead.id, 'section_id': user['su'].section_id.id, 'user_id': user['su'].user_id.id} + values = {'lead_id': lead.id, 'team_id': user['su'].team_id.id, 'user_id': user['su'].user_id.id} self.env['leads.dry.run'].create(values) else: # Assign date will be setted by write function data = {'user_id': user['su'].user_id.id} lead.write(data) - lead.convert_opportunity(None) + lead.convert_opportunity(lead.partner_id and lead.partner_id.id or None) self._cr.commit() user['nbr'] -= 1 @@ -237,14 +244,15 @@ class crm_case_section(osv.osv): TRUNCATE TABLE leads_dry_run; """) - all_salesteams = self.search_read(fields=['score_section_domain'], domain=[('score_section_domain', '!=', False)]) - # casting the list into a dict to ease the access afterwards + all_salesteams = self.search_read(fields=['score_team_domain'], domain=[('score_team_domain', '!=', False)]) - all_section_users = self.env['section.user'].search([('running', '=', True)]) + all_team_users = self.env['team.user'].search([('running', '=', True)]) + + self.env['website.crm.score'].assign_scores_to_leads() 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) + self.assign_leads_to_salesmen(all_team_users, dry=dry) diff --git a/addons/website_crm_score/models/website_crm_score.py b/addons/website_crm_score/models/website_crm_score.py index c407c974dfb..23767e1002e 100644 --- a/addons/website_crm_score/models/website_crm_score.py +++ b/addons/website_crm_score/models/website_crm_score.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from openerp import fields, models, api from openerp.tools.safe_eval import safe_eval from openerp.osv.expression import expression @@ -54,7 +55,7 @@ class website_crm_score(models.Model): domain = safe_eval(score['domain'], evaluation_context) # Don't replace the domain with a 'not in' like below... that doesn't make the same thing !!! - #domain.extend(['|', ('stage_id.on_change', '=', False), ('stage_id.probability', 'not in', [0,100])]) + # domain.extend(['|', ('stage_id.on_change', '=', False), ('stage_id.probability', 'not in', [0,100])]) domain.extend(['|', ('stage_id.on_change', '=', False), '&', ('stage_id.probability', '!=', 0), ('stage_id.probability', '!=', 100)]) e = expression(self._cr, self._uid, domain, self.pool['crm.lead'], self._context) @@ -68,7 +69,7 @@ class website_crm_score(models.Model): FROM crm_lead WHERE %s RETURNING lead_id""" % (score['id'], where_clause), where_params) - # Todo: force recompute of fields that depends on score_ids + # Force recompute of fields that depends on score_ids lead_ids = [resp[0] for resp in self._cr.fetchall()] leads = self.env["crm.lead"].browse(lead_ids) leads.modified(['score_ids']) diff --git a/addons/website_crm_score/security/ir.model.access.csv b/addons/website_crm_score/security/ir.model.access.csv index b46b55eb391..2fa1a339a33 100644 --- a/addons/website_crm_score/security/ir.model.access.csv +++ b/addons/website_crm_score/security/ir.model.access.csv @@ -1,7 +1,7 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_website_crm_score,access_website_crm_score,model_website_crm_score,,1,0,0,0 access_website_crm_score_manager,access_website_crm_score_manager,model_website_crm_score,base.group_website_designer,1,1,1,1 -access_section_user,access_section_user,model_section_user,,1,0,0,0 -access_section_user_manager,access_section_user_manager,model_section_user,marketing.group_marketing_manager,1,1,1,1 +access_team_user,access_team_user,model_team_user,,1,0,0,0 +access_team_user_manager,access_team_user_manager,model_team_user,marketing.group_marketing_manager,1,1,1,1 access_website_crm_pageview,access_website_crm_pageview,model_website_crm_pageview,,1,0,0,0 access_website_crm_pageview_manager,access_website_crm_pageview_manager,model_website_crm_pageview,marketing.group_marketing_manager,1,1,1,1 \ No newline at end of file diff --git a/addons/website_crm_score/static/src/js/display_filters.js b/addons/website_crm_score/static/src/js/display_filters.js deleted file mode 100644 index 00ec831b882..00000000000 --- a/addons/website_crm_score/static/src/js/display_filters.js +++ /dev/null @@ -1,304 +0,0 @@ -openerp.website_crm_score = function(instance) { - var _t = instance.web._t, - _lt = instance.web._lt; - var QWeb = instance.web.qweb; - - instance.website_crm_score = {}; - - instance.website_crm_score.filters = instance.web_kanban.AbstractField.extend({ - /** - bnf grammar of a filter: - ::= - ::= | '!' | - ::= '&' | '|' - ::= '(' ',' ',' ')' - ::= '=' | '!=' | '<=' | '<' | '>' | '>=' | '=?' | - '=like' | '=ilike' | 'like' | 'not like' | - 'ilike' | 'not ilike' | 'in' | 'not in' | 'child_of' - some operators are negative - */ - NEG_OP: ['!=', 'not like', 'not ilike', 'not in'], - MAX_LEN: 5, - start: function() { - var val = this.field.raw_value; - var self = this; - if (val) { - val = eval(val); - if (val.length <= this.MAX_LEN) { - var i = 0; - while (i < val.length) { - var res = this.interpret(val, i); - i = res[0]; - var $span = res[1]; - // var $span = '

' + res[1] + '

'; - self.$el.append($span); - } - } - else { - var $span = 'Domain too big'; - self.$el.append($span); - } - } - }, - - interpret: function(val, i) { - var a = val[i]; - if(typeof a !== 'string'){ - // a is a tuple (field, op, value) - var tag = a[0]; // field name - var tip = a[2]; // field value - if (this.NEG_OP.indexOf(a[1]) !== -1){ - // op in NEG_OP - tip = 'not ' + tip; - } - var span = ''+ tag +''; - // var span = ''+ tag +''; - return [i+1, span]; - } - else if (a === '!'){ - var res = this.interpret(val, i+1); - // var span = '' + res[1] + ''; - var span = '!' + res[1]; - // var span = '' + res[1] + ''; - return [res[0], span]; - } - else { - // binary operator - var res = this.binary_operator(val, i); - return res; - } - return [i+1, '']; - }, - - binary_operator: function(val, i) { - var resA = this.interpret(val, i+1); - var resB = this.interpret(val, resA[0]); - var label = ''; - var op = ''; - if (val[i] === '|') { - label = 'label-success'; - op = ' or '; - } - else if (val[i] === '&') { - label = 'label-primary'; - op = ' and '; - } - // var span = '' + resA[1] + ' ' + resB[1] + ''; - var span = resA[1] + resB[1]; - return [resB[0], span]; - } - }); - - instance.web_kanban.fields_registry.add('filters', 'instance.website_crm_score.filters'); - - instance.website_crm_score.smart_filters = instance.web_kanban.AbstractField.extend({ - /** - bnf grammar of a filter: - ::= - ::= | '!' | - ::= '&' | '|' - ::= '(' ',' ',' ')' - ::= '=' | '!=' | '<=' | '<' | '>' | '>=' | '=?' | - '=like' | '=ilike' | 'like' | 'not like' | - 'ilike' | 'not ilike' | 'in' | 'not in' | 'child_of' - some operators are negative - - the widget works in 3 steps (all 3 are recursive): - - parse the filter and generate a tree - - flatten the tree to a certain point - - format the tree so that it can be displayed - - - parsing: - done by interpret() - the general representation are lists with list[0] a marker and list[1:] being arguments - a tuple is represented as ['d', tip, tag] - tag being the field name - tip being the field value - note: a negative statement is cast into a negation as described below - eg: [(field, '!=', value)] = ['not', ['d', tag, tip]] - a negation is represented as ['not', elem] - elem being a list (eg : ['d', tip, tag], ['not', elem], ...) - a binary operation (or/and) is represented as ['or/and', elem1, elem2] - elem1 and elem2 are the operands of the or/and - example: - - ['&', ['|', ['d',..], ['d',..] ], ['d',..] ] = ['&', '|', d1, d2, d3] - - - flattening: - done by flatten() - if similar operations are successive, then the lists are flatten - exemple: - - ['&', ['&', d1, d2], d3 ] = ['&', d1, d2, d3] - - ['not', ['not', d1]] = d1 - - - formatting - done by format_domain() - the list somehow represents a tree due to its format ([marker, args..]) - browses a list/tree and returns an html representation - this is fairly simple as it only needs to match the marker and act accordinly - */ - - NEG_OP: ['!=', 'not like', 'not ilike', 'not in'], - MAX_LEN: 10, - start: function() { - var val = this.field.raw_value; - var self = this; - if (val) { - val = eval(val); - if (val.length <= this.MAX_LEN) { - var i = 0; - while (i < val.length) { - var res = this.interpret(val, i); - // the returned index i is the index of the first elem not parsed yet in val - i = res[0]; - var flat = this.flatten(res[1]); - var form = this.format_domain(flat); - var $span = form; - self.$el.append($span); - } - } - else { - var $span = 'Domain too big'; - self.$el.append($span); - } - } - }, - - interpret: function(val, i) { - // returns the index of the next element to parse and the representation of the parsed element - var a = val[i]; - if(typeof a !== 'string'){ - // a is a tuple (field, op, value) - var tag = a[0]; // field name - var tip = a[2]; // field value - var span = ['d', tip, tag]; - if (this.NEG_OP.indexOf(a[1]) !== -1){ - // op in NEG_OP - span = ['not', span]; - } - return [i+1, span]; - } - else if (a === '!'){ - var res = this.interpret(val, i+1); - var span = ['not', res[1]]; - return [res[0], span]; - } - else { - // binary operator ( | or & ) - var res = this.binary_operator(val, i); - return res; - } - return [i+1, '']; - }, - - binary_operator: function(val, i) { - var resA = this.interpret(val, i+1); - var resB = this.interpret(val, resA[0]); - var label = ''; - var op = ''; - if (val[i] === '|') { - label = 'label-success'; - op = 'or'; - } - else if (val[i] === '&') { - label = 'label-primary'; - op = 'and'; - } - var span = [op, resA[1], resB[1]]; - return [resB[0], span]; - }, - - flatten: function(t) { - /** - Python code (which is easier to read and understand): - /!\ in the following code, a domain is a string in dom instead of an array ['d', tag, tip] like in js - it explains the differences but the logic is the same - def flatten(t): - op = t[0] - for c in t[1:]: - if not c in dom: - fc = flatten(c) - t.remove(c) - if fc[0] == op: - if op == 'not': - t = fc[1] - else: - t.extend(fc[1:]) - else: - t.append(fc) - return t - */ - var self = this; - var op = t[0]; - if (op != 'd') { - var ts = t.slice(1); - _.each(ts, function(c) { - if (c[0] != 'd') { - var fc = self.flatten(c); - var idx = t.indexOf(c); - t.splice(idx, 1); - if (fc[0] == op) { - if (op == 'not') { - t = fc[1]; - } - else { - t.push.apply(t,fc.slice(1)); - } - } - else { - t.push(fc); - } - } - }); - } - return t; - }, - - format_domain: function(a) { - var self = this; - var style = 'padding:1px; border-style: solid; border-width:1px; border-color=black; text-align:center; border-radius: 4px;'; - if (a[0] == 'd'){ - /** format here what a domain should look like - a[1] : tip - a[2] : tag - */ - var span = ''+ a[2] +''; - return span; - } - else if (a[0] == 'not') { - var res = this.format_domain(a[1]); - /** format here what a negation should look like - res is the expression that is negated - */ - var color = '#d66'; - var span = '
' + res + '
'; - return span; - } - else if (a[0] == 'and' || a[0] == 'or') { - var label = ''; - var color = ''; - /** format here what an or/and shoud look like - as there can be more than 2 operands, it is needed to loop over a[1:] - */ - if (a[0] == 'or') { - color = '#5c5'; - // label = 'label-success'; - } - else if (a[0] == 'and') { - color = '#77e'; - // label = 'label-primary'; - } - var span = '
'; - var as = a.slice(1); - _.each(as, function(s) { - var res = self.format_domain(s); - span += res; - }); - span += '
'; - return span; - } - }, - - }); - - instance.web_kanban.fields_registry.add('smart_filters', 'instance.website_crm_score.smart_filters'); -} diff --git a/addons/website_crm_score/tests/__init__.py b/addons/website_crm_score/tests/__init__.py index 022e106dbfe..c30353b1320 100644 --- a/addons/website_crm_score/tests/__init__.py +++ b/addons/website_crm_score/tests/__init__.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from . import test_assign, test_dry_run, test_pageview checks = [ diff --git a/addons/website_crm_score/tests/common.py b/addons/website_crm_score/tests/common.py index affa64d31ac..fcd4a313289 100644 --- a/addons/website_crm_score/tests/common.py +++ b/addons/website_crm_score/tests/common.py @@ -1,26 +1,28 @@ +# -*- coding: utf-8 -*- from openerp.tests import common +from mock import Mock + class TestScoring(common.TransactionCase): - def _init_(self): - pass - # self._build_email_args_list = [] - # self._build_email_kwargs_list = [] - def setUp(self): + + super(TestScoring, self).setUp() cr, uid = self.cr, self.uid + cr.commit = Mock(return_value=None) + # empty tables before testing to only use test records cr.execute(""" - UPDATE res_partner SET section_id=NULL; + UPDATE res_partner SET team_id=NULL; """) cr.execute(""" - TRUNCATE TABLE section_user; + TRUNCATE TABLE team_user; """) cr.execute(""" - DELETE FROM crm_case_section; + DELETE FROM crm_team; """) cr.execute(""" DELETE FROM crm_lead; @@ -37,16 +39,16 @@ class TestScoring(common.TransactionCase): self.leads_dry_run = self.registry('leads.dry.run') self.pageview = self.registry('website.crm.pageview') self.website_crm_score = self.registry('website.crm.score') - self.section = self.registry('crm.case.section') + self.team = self.registry('crm.team') self.res_users = self.registry('res.users') - self.section_user = self.registry('section.user') + self.team_user = self.registry('team.user') self.country = self.registry('res.country') - self.crm_case_stage = self.registry('crm.case.stage') + self.crm_stage = self.registry('crm.stage') self.belgium = self.country.search(cr, uid, [('name', '=', 'Belgium')])[0] self.france = self.country.search(cr, uid, [('name', '=', 'France')])[0] - self.stage = self.crm_case_stage.create(cr, uid, { + self.stage = self.crm_stage.create(cr, uid, { 'name': 'testing', 'probability': '50', 'on_change': False, @@ -86,15 +88,15 @@ class TestScoring(common.TransactionCase): }) # Salesteam - self.section0 = self.section.create(cr, uid, { - 'name': 'section0', + self.team0 = self.team.create(cr, uid, { + 'name': 'team0', 'code': 'S0', - 'score_section_domain': [('country_id', '=', 'Belgium')], + 'score_team_domain': [('country_id', '=', 'Belgium')], }) - self.section1 = self.section.create(cr, uid, { - 'name': 'section1', + self.team1 = self.team.create(cr, uid, { + 'name': 'team1', 'code': 'S1', - 'score_section_domain': [('country_id', '=', 'France')], + 'score_team_domain': [('country_id', '=', 'France')], }) # Salesmen @@ -113,22 +115,22 @@ class TestScoring(common.TransactionCase): # 'groups_id': [(6, 0, [self.group_employee_id])] }, {'no_reset_password': True}) - # Section_user - self.section_user0 = self.section_user.create(cr, uid, { + # team_user + self.team_user0 = self.team_user.create(cr, uid, { 'user_id': self.salesmen0, - 'section_id': self.section0, + 'team_id': self.team0, 'maximum_user_leads': 1, - 'section_user_domain': [('country_id', '=', 'Belgium')], + 'team_user_domain': [('country_id', '=', 'Belgium')], }) - self.section_user1 = self.section_user.create(cr, uid, { + self.team_user1 = self.team_user.create(cr, uid, { 'user_id': self.salesmen1, - 'section_id': self.section0, + 'team_id': self.team0, 'maximum_user_leads': 0, - 'section_user_domain': [('country_id', '=', 'France')], + 'team_user_domain': [('country_id', '=', 'France')], }) - self.section_user2 = self.section_user.create(cr, uid, { + self.team_user2 = self.team_user.create(cr, uid, { 'user_id': self.salesmen1, - 'section_id': self.section1, + 'team_id': self.team1, 'maximum_user_leads': 1, }) diff --git a/addons/website_crm_score/tests/test_assign.py b/addons/website_crm_score/tests/test_assign.py index 10c7a04d185..393dfeaf735 100644 --- a/addons/website_crm_score/tests/test_assign.py +++ b/addons/website_crm_score/tests/test_assign.py @@ -1,9 +1,12 @@ +# -*- coding: utf-8 -*- from openerp.addons.website_crm_score.tests.common import TestScoring +from openerp.tools import mute_logger class test_assign(TestScoring): - def test_assign(self): + @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models') + def test_00_assign(self): cr, uid = self.cr, self.uid # scoring self.website_crm_score.assign_scores_to_leads(cr, uid) @@ -17,15 +20,15 @@ class test_assign(TestScoring): self.assertEqual(l2['score'], 0, 'scoring failed') # assignation - self.section.direct_assign_leads(cr, uid, None) + self.team.direct_assign_leads(cr, uid, None) - l0 = self.crm_lead.read(cr, uid, self.lead0, ['section_id', 'user_id'], None) - l1 = self.crm_lead.read(cr, uid, self.lead1, ['section_id', 'user_id'], None) - l2 = self.crm_lead.read(cr, uid, self.lead2, ['section_id', 'user_id'], None) + l0 = self.crm_lead.read(cr, uid, self.lead0, ['team_id', 'user_id'], None) + l1 = self.crm_lead.read(cr, uid, self.lead1, ['team_id', 'user_id'], None) + l2 = self.crm_lead.read(cr, uid, self.lead2, ['team_id', 'user_id'], None) - self.assertEqual(l0['section_id'][0], self.section0, 'assignation failed') - self.assertEqual(l1['section_id'][0], self.section1, 'assignation failed') - self.assertEqual(l2['section_id'], False, 'assignation failed') + self.assertEqual(l0['team_id'][0], self.team0, 'assignation failed') + self.assertEqual(l1['team_id'][0], self.team1, 'assignation failed') + self.assertEqual(l2['team_id'], False, 'assignation failed') self.assertEqual(l0['user_id'][0], self.salesmen0, 'assignation failed') self.assertEqual(l1['user_id'][0], self.salesmen1, 'assignation failed') diff --git a/addons/website_crm_score/tests/test_dry_run.py b/addons/website_crm_score/tests/test_dry_run.py index b1393bca88b..42587ac5cc0 100644 --- a/addons/website_crm_score/tests/test_dry_run.py +++ b/addons/website_crm_score/tests/test_dry_run.py @@ -1,9 +1,12 @@ +# -*- coding: utf-8 -*- from openerp.addons.website_crm_score.tests.common import TestScoring +from openerp.tools import mute_logger class test_dry_run(TestScoring): - def test_dry_run(self): + @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models') + def test_00_dry_run(self): cr, uid = self.cr, self.uid # scoring @@ -18,9 +21,9 @@ class test_dry_run(TestScoring): self.assertEqual(l2['score'], 0, 'scoring failed') # dry run - self.section.dry_assign_leads(cr, uid, None) + self.team.dry_assign_leads(cr, uid, None) - fields = ['section_id', 'user_id', 'lead_id'] + fields = ['team_id', 'user_id', 'lead_id'] dr0_sect = self.leads_dry_run.search_read(cr, uid, [('lead_id', '=', self.lead0), ('user_id', '=', False)], fields)[0] dr0_user = self.leads_dry_run.search_read(cr, uid, [('lead_id', '=', self.lead0), ('user_id', '!=', False)], fields)[0] @@ -30,12 +33,12 @@ class test_dry_run(TestScoring): dr2 = self.leads_dry_run.search_read(cr, uid, [('lead_id', '=', self.lead2)], fields) - self.assertEqual(dr0_sect['section_id'][0], self.section0, 'dry run failed') - self.assertEqual(dr0_user['section_id'][0], self.section0, 'dry run failed') + self.assertEqual(dr0_sect['team_id'][0], self.team0, 'dry run failed') + self.assertEqual(dr0_user['team_id'][0], self.team0, 'dry run failed') self.assertEqual(dr0_user['user_id'][0], self.salesmen0, 'dry run failed') - self.assertEqual(dr1_sect['section_id'][0], self.section1, 'dry run failed') - self.assertEqual(dr1_user['section_id'][0], self.section1, 'dry run failed') + self.assertEqual(dr1_sect['team_id'][0], self.team1, 'dry run failed') + self.assertEqual(dr1_user['team_id'][0], self.team1, 'dry run failed') self.assertEqual(dr1_user['user_id'][0], self.salesmen1, 'dry run failed') self.assertEqual(dr2, [], 'dry run failed') @@ -46,13 +49,13 @@ class test_dry_run(TestScoring): # assignement after dry run self.leads_dry_run.assign_leads(cr, uid, None) - l0 = self.crm_lead.read(cr, uid, self.lead0, ['section_id', 'user_id'], None) - l1 = self.crm_lead.read(cr, uid, self.lead1, ['section_id', 'user_id'], None) - l2 = self.crm_lead.read(cr, uid, self.lead2, ['section_id', 'user_id'], None) + l0 = self.crm_lead.read(cr, uid, self.lead0, ['team_id', 'user_id'], None) + l1 = self.crm_lead.read(cr, uid, self.lead1, ['team_id', 'user_id'], None) + l2 = self.crm_lead.read(cr, uid, self.lead2, ['team_id', 'user_id'], None) - self.assertEqual(l0['section_id'][0], self.section0, 'assignation failed') - self.assertEqual(l1['section_id'][0], self.section1, 'assignation failed') - self.assertEqual(l2['section_id'], False, 'assignation failed') + self.assertEqual(l0['team_id'][0], self.team0, 'assignation failed') + self.assertEqual(l1['team_id'][0], self.team1, 'assignation failed') + self.assertEqual(l2['team_id'], False, 'assignation failed') self.assertEqual(l0['user_id'][0], self.salesmen0, 'assignation failed') self.assertEqual(l1['user_id'][0], self.salesmen1, 'assignation failed') diff --git a/addons/website_crm_score/tests/test_pageview.py b/addons/website_crm_score/tests/test_pageview.py index f292efa943f..994eb3f5506 100644 --- a/addons/website_crm_score/tests/test_pageview.py +++ b/addons/website_crm_score/tests/test_pageview.py @@ -1,21 +1,26 @@ +# -*- coding: utf-8 -*- from openerp.addons.website_crm_score.tests.common import TestScoring from psycopg2 import IntegrityError +from openerp.tools import mute_logger class test_assign(TestScoring): - def test_pageview(self): + @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models') + def test_00_pageview(self): cr, uid = self.cr, self.uid - right_lead = self.pageview.create_pageview(cr, uid, {'lead_id': self.lead0, 'url':'url2'}, test=True) + right_lead = self.pageview.create_pageview(cr, uid, {'lead_id': self.lead0, 'url': 'url2'}, test=True) self.assertTrue(right_lead, 'create_pageview should have succeded') pg0 = self.pageview.search_read(cr, uid, [('lead_id', '=', self.lead0), ('url', '=', 'url2')], ['view_date']) self.assertNotEqual(pg0, [], 'pageview was not created') - update_lead = self.pageview.create_pageview(cr, uid, {'lead_id': self.lead0, 'url':'url2'}, test=True) + update_lead = self.pageview.create_pageview(cr, uid, {'lead_id': self.lead0, 'url': 'url2'}, test=True) self.assertTrue(update_lead, 'create_pageview should have updated the lead') - # with self.assertRaises(IntegrityError): - # self.pageview.create_pageview(cr, uid, {'lead_id': -1, 'url':'url2'}, test=True) - + + self.assertFalse( + self.pageview.create_pageview(cr, uid, {'lead_id': -1, 'url': 'url2'}, test=True), + 'create_pageview should not works with unexisting lead id' + ) diff --git a/addons/website_crm_score/views/marketing.xml b/addons/website_crm_score/views/marketing.xml index b51b697fb48..ffe49e8d4c3 100644 --- a/addons/website_crm_score/views/marketing.xml +++ b/addons/website_crm_score/views/marketing.xml @@ -13,7 +13,7 @@ days -1 - +
@@ -115,12 +115,12 @@ - - - Section User Form - section.user + + + Team User Form + team.user
@@ -128,26 +128,26 @@ - +
- - - Section User Tree - section.user + + + Team User Tree + team.user - + @@ -155,10 +155,10 @@ - - - section.user.kanban - section.user + + + team.user.kanban + team.user @@ -204,9 +204,9 @@
  • - +
  • -
  • +
  • @@ -227,10 +227,10 @@
    - - + + Sales Men - section.user + team.user form kanban,tree,form @@ -243,20 +243,20 @@ - - + + - - - + + + Sales Teams - crm.case.section + crm.team form tree,form - - + + @@ -271,7 +271,7 @@ - + @@ -197,7 +197,7 @@ - +