[REF] website_crm_score: migrate code to be compatible with master.
Courtesy Review : xmo, mat
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import models
|
||||
import controllers
|
||||
|
||||
@@ -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': [
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import main
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record model="crm.case.section" id="sales_team.section_sales_department">
|
||||
<field name="score_section_domain">[['country_id', '=', 'France']]</field>
|
||||
<record model="crm.team" id="sales_team.team_sales_department">
|
||||
<field name="score_team_domain">[['country_id', '=', 'France']]</field>
|
||||
</record>
|
||||
<record model="crm.case.section" id="website.salesteam_website_sales">
|
||||
<field name="score_section_domain">[['country_id', '=', 'Belgium']]</field>
|
||||
<record model="crm.team" id="website.salesteam_website_sales">
|
||||
<field name="score_team_domain">[['country_id', '=', 'Belgium']]</field>
|
||||
</record>
|
||||
|
||||
<!-- Creating salesmen -->
|
||||
@@ -85,152 +85,152 @@
|
||||
|
||||
<!-- Assigning salesmen to salesteams -->
|
||||
<!-- Team 0 -->
|
||||
<record id="website_crm_score_section_user_0" model="section.user">
|
||||
<record id="website_crm_score_team_user_0" model="team.user">
|
||||
<field name="user_id" ref="website_crm_score_user_0"/>
|
||||
<field name="section_id" ref="sales_team.section_sales_department"/>
|
||||
<field name="team_id" ref="sales_team.team_sales_department"/>
|
||||
<field name="maximum_user_leads">2</field>
|
||||
<field name="section_user_domain">['|', ['country_id', '=', 'Belgium'], ['country_id', '=', 'France']]</field>
|
||||
<field name="team_user_domain">['|', ['country_id', '=', 'Belgium'], ['country_id', '=', 'France']]</field>
|
||||
</record>
|
||||
<record id="website_crm_score_section_user_1" model="section.user">
|
||||
<record id="website_crm_score_team_user_1" model="team.user">
|
||||
<field name="user_id" ref="website_crm_score_user_2"/>
|
||||
<field name="section_id" ref="sales_team.section_sales_department"/>
|
||||
<field name="team_id" ref="sales_team.team_sales_department"/>
|
||||
<field name="maximum_user_leads">1</field>
|
||||
<field name="section_user_domain">[['country_id', '!=', 'Belgium']]</field>
|
||||
<field name="team_user_domain">[['country_id', '!=', 'Belgium']]</field>
|
||||
</record>
|
||||
|
||||
<!-- Team 1 -->
|
||||
<record id="website_crm_score_section_user_3" model="section.user">
|
||||
<record id="website_crm_score_team_user_3" model="team.user">
|
||||
<field name="user_id" ref="website_crm_score_user_1"/>
|
||||
<field name="section_id" ref="website.salesteam_website_sales"/>
|
||||
<field name="team_id" ref="website.salesteam_website_sales"/>
|
||||
<field name="maximum_user_leads">1</field>
|
||||
</record>
|
||||
<record id="website_crm_score_section_user_4" model="section.user">
|
||||
<record id="website_crm_score_team_user_4" model="team.user">
|
||||
<field name="user_id" ref="website_crm_score_user_3"/>
|
||||
<field name="section_id" ref="website.salesteam_website_sales"/>
|
||||
<field name="team_id" ref="website.salesteam_website_sales"/>
|
||||
<field name="maximum_user_leads">2</field>
|
||||
<field name="section_user_domain">['&', ['lang_id', '=', 'English'], ['country_id', '=', 'Belgium']]</field>
|
||||
<field name="team_user_domain">['&', ['lang_id', '=', 'English'], ['country_id', '=', 'Belgium']]</field>
|
||||
</record>
|
||||
|
||||
<!-- Team 3 -->
|
||||
<record id="website_crm_score_section_user_6" model="section.user">
|
||||
<record id="website_crm_score_team_user_6" model="team.user">
|
||||
<field name="user_id" ref="website_crm_score_user_3"/>
|
||||
<field name="section_id" ref="sales_team.crm_case_section_1"/>
|
||||
<field name="team_id" ref="sales_team.crm_team_1"/>
|
||||
<field name="maximum_user_leads">1</field>
|
||||
</record>
|
||||
|
||||
<!-- Team 4 -->
|
||||
<record id="website_crm_score_section_user_7" model="section.user">
|
||||
<record id="website_crm_score_team_user_7" model="team.user">
|
||||
<field name="user_id" ref="website_crm_score_user_2"/>
|
||||
<field name="section_id" ref="sales_team.crm_case_section_2"/>
|
||||
<field name="team_id" ref="sales_team.crm_team_2"/>
|
||||
<field name="maximum_user_leads">3</field>
|
||||
<field name="section_user_domain">[['country_id', '=', 'France']]</field>
|
||||
<field name="team_user_domain">[['country_id', '=', 'France']]</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- Leads -->
|
||||
<record id="crm.crm_case_1" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_2" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_3" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_4" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_5" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_6" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_7" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_8" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_9" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_10" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_11" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_12" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_13" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_14" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_15" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_16" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_17" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_18" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_19" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_20" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_21" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_22" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_23" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_24" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_25" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
<record id="crm.crm_case_26" model="crm.lead">
|
||||
<field name="section_id" ref=""/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="team_id" />
|
||||
<field name="user_id" />
|
||||
</record>
|
||||
|
||||
<!-- Scores -->
|
||||
|
||||
@@ -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
|
||||
import leads_dry_run
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 = '<a href="' + url + '" target="_blank"><b>' + url + '</b></a>'
|
||||
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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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'])
|
||||
|
||||
@@ -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
|
||||
|
@@ -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:
|
||||
<filter> ::= <expr>
|
||||
<expr> ::= <tuple> | '!' <expr> | <bin_op> <expr> <expr>
|
||||
<bin_op> ::= '&' | '|'
|
||||
<tuple> ::= '(' <field_name> ',' <operator> ',' <field_value> ')'
|
||||
<operator> ::= '=' | '!=' | '<=' | '<' | '>' | '>=' | '=?' |
|
||||
'=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 = '<h2>' + res[1] + '</h2>';
|
||||
self.$el.append($span);
|
||||
}
|
||||
}
|
||||
else {
|
||||
var $span = '<span class="oe_tag" style="background-color:#fce9e9;">Domain too big<span>';
|
||||
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 = '<span class="oe_tag" title="' + tip + '">'+ tag +'</span>';
|
||||
// var span = '<span class="label label-info" title="' + tip + '">'+ tag +'</span>';
|
||||
return [i+1, span];
|
||||
}
|
||||
else if (a === '!'){
|
||||
var res = this.interpret(val, i+1);
|
||||
// var span = '<span class="label label-danger">' + res[1] + '</span>';
|
||||
var span = '<span class="oe_tag">!</span>' + res[1];
|
||||
// var span = '<span class="label label-danger" style="border-style: solid; border-width: 1px; border-color: #666;">' + res[1] + '</span>';
|
||||
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 = '<span class="label ' + label + '"">' + resA[1] + ' ' + resB[1] + '</span>';
|
||||
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:
|
||||
<filter> ::= <expr>
|
||||
<expr> ::= <tuple> | '!' <expr> | <bin_op> <expr> <expr>
|
||||
<bin_op> ::= '&' | '|'
|
||||
<tuple> ::= '(' <field_name> ',' <operator> ',' <field_value> ')'
|
||||
<operator> ::= '=' | '!=' | '<=' | '<' | '>' | '>=' | '=?' |
|
||||
'=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 = '<span class="oe_tag" style="background-color:#fce9e9;">Domain too big<span>';
|
||||
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 = '<span class="oe_tag" title="' + a[1] + '">'+ a[2] +'</span>';
|
||||
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 = '<div style="background-color:' + color + '; ' + style + '">' + res + '</div>';
|
||||
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 = '<div style="background-color:' + color + '; ' + style + '">';
|
||||
var as = a.slice(1);
|
||||
_.each(as, function(s) {
|
||||
var res = self.format_domain(s);
|
||||
span += res;
|
||||
});
|
||||
span += '</div>';
|
||||
return span;
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
instance.web_kanban.fields_registry.add('smart_filters', 'instance.website_crm_score.smart_filters');
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import test_assign, test_dry_run, test_pageview
|
||||
|
||||
checks = [
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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'
|
||||
)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall" />
|
||||
<field eval="'crm.case.section'" name="model" />
|
||||
<field eval="'crm.team'" name="model" />
|
||||
<field eval="'direct_assign_leads'" name="function" />
|
||||
</record>
|
||||
|
||||
@@ -115,12 +115,12 @@
|
||||
<menuitem id="scores_menu" name="Scoring Rules" parent="leads_menu" action="score_action" />
|
||||
|
||||
<!--
|
||||
SECTION USER
|
||||
TEAM USER
|
||||
-->
|
||||
<!-- Section User From View -->
|
||||
<record model="ir.ui.view" id="view_crm_section_user_form">
|
||||
<field name="name">Section User Form</field>
|
||||
<field name="model">section.user</field>
|
||||
<!-- Team User From View -->
|
||||
<record model="ir.ui.view" id="view_crm_team_user_form">
|
||||
<field name="name">Team User Form</field>
|
||||
<field name="model">team.user</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Sales Men">
|
||||
<sheet>
|
||||
@@ -128,26 +128,26 @@
|
||||
<field name="user_id"/>
|
||||
</h1>
|
||||
<group>
|
||||
<field name="section_id" readonly="context.get('ro_section', False)"/>
|
||||
<field name="team_id" readonly="context.get('ro_team', False)"/>
|
||||
<label for="maximum_user_leads" String="Maximum Leads / 30 days" />
|
||||
<div>
|
||||
<field name="maximum_user_leads" class="oe_inline"/>
|
||||
</div>
|
||||
<!--<field name="section_user_domain" widget="char_domain" options="{'model': 'crm.lead'}"/>-->
|
||||
<field name="section_user_domain" />
|
||||
<!--<field name="team_user_domain" widget="char_domain" options="{'model': 'crm.lead'}"/>-->
|
||||
<field name="team_user_domain" />
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Section User Tree View -->
|
||||
<record model="ir.ui.view" id="view_crm_section_user_tree">
|
||||
<field name="name">Section User Tree</field>
|
||||
<field name="model">section.user</field>
|
||||
<!-- team User Tree View -->
|
||||
<record model="ir.ui.view" id="view_crm_team_user_tree">
|
||||
<field name="name">Team User Tree</field>
|
||||
<field name="model">team.user</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Sales Men">
|
||||
<field name="section_id"/>
|
||||
<field name="team_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="maximum_user_leads"/>
|
||||
<field name="leads_count"/>
|
||||
@@ -155,10 +155,10 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Section User Kanban View -->
|
||||
<record model="ir.ui.view" id="section_user_kanban">
|
||||
<field name="name">section.user.kanban</field>
|
||||
<field name="model">section.user</field>
|
||||
<!-- Team User Kanban View -->
|
||||
<record model="ir.ui.view" id="team_user_kanban">
|
||||
<field name="name">team.user.kanban</field>
|
||||
<field name="model">team.user</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban quick_create="false" create="true">
|
||||
<field name="user_id"/>
|
||||
@@ -204,9 +204,9 @@
|
||||
<b><field name="name"/></b>
|
||||
</a></li>
|
||||
<li><a type="open">
|
||||
<field name="section_id"/>
|
||||
<field name="team_id"/>
|
||||
</a></li>
|
||||
<li><field name="section_user_domain" widget='filters'/></li>
|
||||
<li><field name="team_user_domain" widget='filters'/></li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
@@ -227,10 +227,10 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Section User Action - form - tree -->
|
||||
<record model="ir.actions.act_window" id="section_user_action">
|
||||
<!-- Team User Action - form - tree -->
|
||||
<record model="ir.actions.act_window" id="team_user_action">
|
||||
<field name="name">Sales Men</field>
|
||||
<field name="res_model">section.user</field>
|
||||
<field name="res_model">team.user</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">kanban,tree,form</field>
|
||||
<field name="help" type="html">
|
||||
@@ -243,20 +243,20 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Section User Menu Item -->
|
||||
<menuitem id="section_user" name="Leads Assignation" parent="leads_menu" action="section_user_action" />
|
||||
<!-- Team User Menu Item -->
|
||||
<menuitem id="team_user" name="Leads Assignation" parent="leads_menu" action="team_user_action" />
|
||||
|
||||
<!-- SECTION -->
|
||||
<!-- Section Action - form - tree -->
|
||||
<record model="ir.actions.act_window" id="section_action">
|
||||
<!-- TEAM -->
|
||||
<!-- Team Action - form - tree -->
|
||||
<record model="ir.actions.act_window" id="team_action">
|
||||
<field name="name">Sales Teams</field>
|
||||
<field name="res_model">crm.case.section</field>
|
||||
<field name="res_model">crm.team</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<!-- Section User Menu Item -->
|
||||
<menuitem id="section" name="Teams Assignation" parent="leads_menu" action="section_action" />
|
||||
<!-- Team User Menu Item -->
|
||||
<menuitem id="team" name="Teams Assignation" parent="leads_menu" action="team_action" />
|
||||
|
||||
|
||||
<!-- LEAD DRY RUN -->
|
||||
@@ -271,7 +271,7 @@
|
||||
<field name="lead_id"/>
|
||||
</h1>
|
||||
<group>
|
||||
<field name="section_id"/>
|
||||
<field name="team_id"/>
|
||||
<field name="user_id"/>
|
||||
<button name="assign_leads" type="object" string="Assign Now" class="oe_link"/>
|
||||
</group>
|
||||
@@ -287,7 +287,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Assignation Dry Run">
|
||||
<field name="lead_id"/>
|
||||
<field name="section_id"/>
|
||||
<field name="team_id"/>
|
||||
<field name="user_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
@@ -301,7 +301,7 @@
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<!-- Section User Menu Item -->
|
||||
<!-- Team User Menu Item -->
|
||||
<menuitem id="leads_dry_run" name="Assignation dry run" parent="leads_menu" action="lead_dry_run_action" groups="base.group_no_one"/>
|
||||
|
||||
</data>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
</h1>
|
||||
<group>
|
||||
<field name="lead_id"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="view_date"/>
|
||||
</group>
|
||||
</sheet>
|
||||
@@ -56,7 +56,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Page Views">
|
||||
<field name="lead_id"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="url"/>
|
||||
<field name="view_date"/>
|
||||
</tree>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<field name="phone" position="after">
|
||||
<field name="score" />
|
||||
</field>
|
||||
<field name="section_id" position="after">
|
||||
<field name="team_id" position="after">
|
||||
<field name="user_id" />
|
||||
</field>
|
||||
</field>
|
||||
@@ -71,7 +71,7 @@
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="inherit_id" ref="crm.crm_case_tree_view_oppor" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="section_id" position="after">
|
||||
<field name="team_id" position="after">
|
||||
<field name="score" />
|
||||
</field>
|
||||
</field>
|
||||
@@ -101,14 +101,14 @@
|
||||
|
||||
<!-- SALESTEAM -->
|
||||
<!-- SalesTeam Kanban View - Lead information added -->
|
||||
<record id="crm_case_section_salesteams_view_kanban_inherit" model="ir.ui.view">
|
||||
<field name="name">crm.case.section.kanban.inherit</field>
|
||||
<field name="model">crm.case.section</field>
|
||||
<field name="inherit_id" ref="sales_team.crm_case_section_salesteams_view_kanban"/>
|
||||
<record id="crm_team_salesteams_view_kanban_inherit" model="ir.ui.view">
|
||||
<field name="name">crm.team.kanban.inherit</field>
|
||||
<field name="model">crm.team</field>
|
||||
<field name="inherit_id" ref="sales_team.crm_team_salesteams_view_kanban"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<field name="member_ids" position="after">
|
||||
<field name="section_user_ids"/>
|
||||
<field name="team_user_ids"/>
|
||||
</field>
|
||||
<xpath expr="//div[@class='oe_clear']" position="after">
|
||||
<div class="oe_items_list">
|
||||
@@ -175,21 +175,21 @@
|
||||
|
||||
<!-- SalesTeam Form View - Lead information and page Assignation added -->
|
||||
<record model="ir.ui.view" id="sales_team_form_view_assign">
|
||||
<field name="name">crm.case.section.form.inherit</field>
|
||||
<field name="model">crm.case.section</field>
|
||||
<field name="inherit_id" ref="sales_team.crm_case_section_view_form"/>
|
||||
<field name="name">crm.team.form.inherit</field>
|
||||
<field name="model">crm.team</field>
|
||||
<field name="inherit_id" ref="sales_team.crm_team_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@class='oe_title']" position="before">
|
||||
<div class="oe_right oe_button_box" name="buttons">
|
||||
<button class="oe_inline oe_stat_button" type="action"
|
||||
name="%(crm_score_views_action_graph)d" icon="fa-tags"
|
||||
context="{'search_default_section_id': active_id, 'search_default_unassigned': 1 }"
|
||||
context="{'search_default_team_id': active_id, 'search_default_unassigned': 1 }"
|
||||
>
|
||||
<field string="Unassigned leads" name="unassigned_leads" widget="statinfo"/>
|
||||
</button>
|
||||
<button class="oe_inline oe_stat_button" type="action"
|
||||
name="%(crm_score_views_action_table)d" icon="fa-tags"
|
||||
context="{'search_default_section_id': active_id}"
|
||||
context="{'search_default_team_id': active_id}"
|
||||
>
|
||||
<field string="Opportunities" name="leads_count" widget="statinfo"/>
|
||||
</button>
|
||||
@@ -197,7 +197,7 @@
|
||||
</xpath>
|
||||
<xpath expr="//group[@name='left']" position="after">
|
||||
<group name="right">
|
||||
<field name="score_section_domain" options="{'model': 'crm.lead'}"/>
|
||||
<field name="score_team_domain" options="{'model': 'crm.lead'}"/>
|
||||
<label for="assigned_leads"/>
|
||||
<div>
|
||||
<field name="assigned_leads" class="oe_inline"/> /
|
||||
@@ -217,7 +217,7 @@
|
||||
</xpath>
|
||||
<xpath expr="//page[@string='Team Members']" position="replace">
|
||||
<page string="Assignation">
|
||||
<field name="section_user_ids" widget="many2many_kanban" context="{'default_section_id':active_id, 'ro_section':True}">
|
||||
<field name="team_user_ids" widget="many2many_kanban" context="{'default_team_id':active_id, 'ro_team':True}">
|
||||
<kanban quick_create="true" create="true" delete="true">
|
||||
<field name="user_id"/>
|
||||
<field name="running"/>
|
||||
@@ -261,8 +261,8 @@
|
||||
<li><a type="open">
|
||||
<b><field name="name"/></b>
|
||||
</a></li>
|
||||
<!-- <li><field name="section_user_domain" widget="smart_filters"/></li> -->
|
||||
<li><field name="section_user_domain" widget='filters'/></li>
|
||||
<!-- <li><field name="team_user_domain" widget="smart_filters"/></li> -->
|
||||
<li><field name="team_user_domain" widget='filters'/></li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
@@ -8,10 +8,5 @@
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="assets_backend" name="web_kanban_gauge assets" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<script type="text/javascript" src="/website_crm_score/static/src/js/display_filters.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
Reference in New Issue
Block a user