[REM] crm: remove dead code about sales team dashboard
CRM still holds code dead since more than 2 years about sales / crm dashboard.
Custom ugly un-onboarding not-wow headers have been removed at ea66192276.
LINKS
Related to Task ID 2092799 (not really spec, spotted while working on it)
PR odoo/odoo#42015
This commit is contained in:
@@ -1057,135 +1057,6 @@ class Lead(models.Model):
|
||||
message = _("Meeting scheduled at '%s'<br> Subject: %s <br> Duration: %s hours") % (html_time, meeting_subject, duration)
|
||||
return self.message_post(body=message)
|
||||
|
||||
# ----------------------------------------
|
||||
# Sales Team Dashboard
|
||||
# ----------------------------------------
|
||||
|
||||
@api.model
|
||||
def retrieve_sales_dashboard(self):
|
||||
""" Fetch data to setup Sales Dashboard """
|
||||
result = {
|
||||
'meeting': {
|
||||
'today': 0,
|
||||
'next_7_days': 0,
|
||||
},
|
||||
'activity': {
|
||||
'today': 0,
|
||||
'overdue': 0,
|
||||
'next_7_days': 0,
|
||||
},
|
||||
'closing': {
|
||||
'today': 0,
|
||||
'overdue': 0,
|
||||
'next_7_days': 0,
|
||||
},
|
||||
'done': {
|
||||
'this_month': 0,
|
||||
'last_month': 0,
|
||||
},
|
||||
'won': {
|
||||
'this_month': 0,
|
||||
'last_month': 0,
|
||||
},
|
||||
'nb_opportunities': 0,
|
||||
}
|
||||
|
||||
today = fields.Date.from_string(fields.Date.context_today(self))
|
||||
|
||||
opportunities = self.search([('type', '=', 'opportunity'), ('user_id', '=', self._uid)])
|
||||
|
||||
for opp in opportunities:
|
||||
# Expected closing
|
||||
if opp.activity_date_deadline:
|
||||
if opp.date_deadline:
|
||||
date_deadline = fields.Date.from_string(opp.date_deadline)
|
||||
if date_deadline == today:
|
||||
result['closing']['today'] += 1
|
||||
if today <= date_deadline <= today + timedelta(days=7):
|
||||
result['closing']['next_7_days'] += 1
|
||||
if date_deadline < today and not opp.date_closed:
|
||||
result['closing']['overdue'] += 1
|
||||
# Next activities
|
||||
for activity in opp.activity_ids:
|
||||
date_deadline = fields.Date.from_string(activity.date_deadline)
|
||||
if date_deadline == today:
|
||||
result['activity']['today'] += 1
|
||||
if today <= date_deadline <= today + timedelta(days=7):
|
||||
result['activity']['next_7_days'] += 1
|
||||
if date_deadline < today:
|
||||
result['activity']['overdue'] += 1
|
||||
# Won in Opportunities
|
||||
if opp.date_closed and opp.stage_id.is_won:
|
||||
date_closed = fields.Date.from_string(opp.date_closed)
|
||||
if today.replace(day=1) <= date_closed <= today:
|
||||
if opp.planned_revenue:
|
||||
result['won']['this_month'] += opp.planned_revenue
|
||||
elif today + relativedelta(months=-1, day=1) <= date_closed < today.replace(day=1):
|
||||
if opp.planned_revenue:
|
||||
result['won']['last_month'] += opp.planned_revenue
|
||||
|
||||
result['nb_opportunities'] = len(opportunities)
|
||||
|
||||
# crm.activity is a very messy model so we need to do that in order to retrieve the actions done.
|
||||
self._cr.execute("""
|
||||
SELECT
|
||||
mail_message.id,
|
||||
mail_message.subtype_id,
|
||||
mail_message.mail_activity_type_id,
|
||||
mail_message.date,
|
||||
crm_lead.user_id,
|
||||
crm_lead.type
|
||||
FROM mail_message
|
||||
LEFT JOIN crm_lead ON (mail_message.res_id = crm_lead.id)
|
||||
INNER JOIN mail_activity_type activity_type ON (mail_message.mail_activity_type_id = activity_type.id)
|
||||
WHERE
|
||||
(mail_message.model = 'crm.lead') AND (crm_lead.user_id = %s) AND (crm_lead.type = 'opportunity')
|
||||
""", (self._uid,))
|
||||
activites_done = self._cr.dictfetchall()
|
||||
for activity in activites_done:
|
||||
if activity['date']:
|
||||
date_act = fields.Date.from_string(activity['date'])
|
||||
if today.replace(day=1) <= date_act <= today:
|
||||
result['done']['this_month'] += 1
|
||||
elif today + relativedelta(months=-1, day=1) <= date_act < today.replace(day=1):
|
||||
result['done']['last_month'] += 1
|
||||
|
||||
# Meetings
|
||||
min_date = fields.Datetime.now()
|
||||
max_date = fields.Datetime.to_string(datetime.now() + timedelta(days=8))
|
||||
meetings_domain = [
|
||||
('start', '>=', min_date),
|
||||
('start', '<=', max_date),
|
||||
('partner_ids', 'in', [self.env.user.partner_id.id])
|
||||
]
|
||||
meetings = self.env['calendar.event'].search(meetings_domain)
|
||||
for meeting in meetings:
|
||||
if meeting['start']:
|
||||
start = meeting['start']
|
||||
if start == today:
|
||||
result['meeting']['today'] += 1
|
||||
if today <= start <= today + timedelta(days=7):
|
||||
result['meeting']['next_7_days'] += 1
|
||||
|
||||
result['done']['target'] = self.env.user.target_sales_done
|
||||
result['won']['target'] = self.env.user.target_sales_won
|
||||
result['currency_id'] = self.env.company.currency_id.id
|
||||
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def modify_target_sales_dashboard(self, target_name, target_value):
|
||||
""" Update the user objectives (`target_sales_done`, target_sales_won`
|
||||
and `target_sales_invoiced` fields).
|
||||
:param target_name : part of the fields name to update
|
||||
:param target_value : value of the field to update
|
||||
"""
|
||||
if target_name in ['won', 'done', 'invoiced']:
|
||||
# bypass rights, since self.env.user is browsed as SUPERUSER_ID
|
||||
self.env.user.write({'target_sales_' + target_name: target_value})
|
||||
else:
|
||||
raise UserError(_('This target does not exist.'))
|
||||
|
||||
# ----------------------------------------
|
||||
# Mail Gateway
|
||||
# ----------------------------------------
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
odoo.define('crm.dashboard_tests', function (require) {
|
||||
"use strict";
|
||||
|
||||
// this file is no longer loaded in the test suite, so i guess we can remove it
|
||||
|
||||
var testUtils = require('web.test_utils');
|
||||
var view_registry = require('web.view_registry');
|
||||
|
||||
var createView = testUtils.createView;
|
||||
|
||||
QUnit.module('CRM Sales Team Dashboard', {
|
||||
beforeEach: function () {
|
||||
this.data = {
|
||||
partner: {
|
||||
fields: {
|
||||
foo: {string: "Foo", type: "char"},
|
||||
},
|
||||
records: [
|
||||
{id: 1, foo: "yop"},
|
||||
{id: 2, foo: "blip"},
|
||||
{id: 3, foo: "gnap"},
|
||||
{id: 4, foo: "blip"},
|
||||
]
|
||||
},
|
||||
};
|
||||
this.dashboard_data = {
|
||||
nb_opportunities: 6,
|
||||
currency_id: 3,
|
||||
won: {this_month: 0, last_month: 0, target: 0},
|
||||
done: {this_month: 0, last_month: 0, target: 0},
|
||||
activity: {next_7_days: 3, today: 1, overdue: 1},
|
||||
closing: {next_7_days: 1, today: 0, overdue: 0},
|
||||
meeting: {next_7_days: 1, today: 0},
|
||||
invoiced: {this_month: 0, last_month: 0, target: 0}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test('dashboard basic rendering', function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var dashboard_data = this.dashboard_data;
|
||||
var kanban = createView({
|
||||
View: view_registry.get('sales_team_dashboard'),
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<kanban class="o_kanban_test">' +
|
||||
'<templates><t t-name="kanban-box">' +
|
||||
'<div><field name="foo"/></div>' +
|
||||
'</t></templates>' +
|
||||
'</kanban>',
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'retrieve_sales_dashboard') {
|
||||
assert.ok(true, "should call /retrieve_sales_dashboard");
|
||||
return Promise.resolve(dashboard_data);
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
});
|
||||
|
||||
assert.ok(kanban.$('div.o_sales_dashboard').length,
|
||||
"should render the dashboard");
|
||||
});
|
||||
|
||||
QUnit.test('dashboard set a new target', function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
var dashboard_data = this.dashboard_data;
|
||||
var kanban = createView({
|
||||
View: view_registry.get('sales_team_dashboard'),
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<kanban class="o_kanban_test">' +
|
||||
'<templates><t t-name="kanban-box">' +
|
||||
'<div><field name="foo"/></div>' +
|
||||
'</t></templates>' +
|
||||
'</kanban>',
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'retrieve_sales_dashboard') {
|
||||
// should be called twice: for the first rendering, and after the target update
|
||||
assert.ok(true, "should call /retrieve_sales_dashboard");
|
||||
return Promise.resolve(dashboard_data);
|
||||
}
|
||||
if (args.method === 'modify_target_sales_dashboard') {
|
||||
assert.ok(true, "should call /modify_target_sales_dashboard");
|
||||
dashboard_data[args.args[0]].target = args.args[1];
|
||||
return Promise.resolve();
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
});
|
||||
|
||||
testUtils.dom.click(kanban.$('.o_target_to_set').first());
|
||||
kanban.$('.o_sales_dashboard input')
|
||||
.val('20000')
|
||||
.trigger($.Event('keyup', {which: $.ui.keyCode.ENTER})); // set the target
|
||||
|
||||
assert.ok(kanban.$('.o_target_to_set:first():contains(20000)').length,
|
||||
"dashboard should have been correctly re-rendered after target update");
|
||||
});
|
||||
|
||||
QUnit.test('dashboard: click on a button to execute an action', function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var dashboard_data = this.dashboard_data;
|
||||
var kanban = createView({
|
||||
View: view_registry.get('sales_team_dashboard'),
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<kanban class="o_kanban_test">' +
|
||||
'<templates><t t-name="kanban-box">' +
|
||||
'<div>' +
|
||||
'<button name="func_name" String="A" type="object" class="my_button"/>' +
|
||||
'<field name="foo"/>' +
|
||||
'</div>' +
|
||||
'</t></templates>' +
|
||||
'</kanban>',
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'retrieve_sales_dashboard') {
|
||||
return Promise.resolve(dashboard_data);
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
testUtils.mock.intercept(kanban, 'execute_action', function (event) {
|
||||
assert.strictEqual(event.data.action_data.name, 'func_name',
|
||||
'execute_action should have been triggered with the correct data');
|
||||
assert.strictEqual(event.data.action_data.type, 'object',
|
||||
'execute_action should have been triggered with the correct data');
|
||||
});
|
||||
|
||||
testUtils.dom.click(kanban.$('.my_button:first()'));
|
||||
kanban.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('dashboard should be displayed even if there is no content', function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var dashboardData = this.dashboard_data;
|
||||
var kanban = createView({
|
||||
View: view_registry.get('sales_team_dashboard'),
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<kanban class="o_kanban_test">' +
|
||||
'<templates><t t-name="kanban-box">' +
|
||||
'<div><field name="foo"/></div>' +
|
||||
'</t></templates>' +
|
||||
'</kanban>',
|
||||
domain: [['id', '=', 239]], // no record will match this domain
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'retrieve_sales_dashboard') {
|
||||
return Promise.resolve(dashboardData);
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
viewOptions: {
|
||||
action: {
|
||||
help: '<p>A help message</p>',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.containsOnce(kanban, 'div.o_sales_dashboard',
|
||||
"should render the dashboard");
|
||||
assert.strictEqual(kanban.$('.o_view_nocontent:contains(A help message)').length, 1,
|
||||
"should correctly render the nocontent helper");
|
||||
|
||||
kanban.destroy();
|
||||
});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user