[wsgi] [minor] fixed flags
This commit is contained in:
commit
26c5a585c7
0
selling/page/sales_funnel/__init__.py
Normal file
0
selling/page/sales_funnel/__init__.py
Normal file
3
selling/page/sales_funnel/sales_funnel.css
Normal file
3
selling/page/sales_funnel/sales_funnel.css
Normal file
@ -0,0 +1,3 @@
|
||||
.funnel-wrapper {
|
||||
margin: 15px;
|
||||
}
|
189
selling/page/sales_funnel/sales_funnel.js
Normal file
189
selling/page/sales_funnel/sales_funnel.js
Normal file
@ -0,0 +1,189 @@
|
||||
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
wn.pages['sales-funnel'].onload = function(wrapper) {
|
||||
wn.ui.make_app_page({
|
||||
parent: wrapper,
|
||||
title: 'Sales Funnel',
|
||||
single_column: true
|
||||
});
|
||||
|
||||
wrapper.crm_funnel = new erpnext.CRMFunnel(wrapper);
|
||||
|
||||
wrapper.appframe.add_module_icon("Selling", "sales-funnel", function() {
|
||||
wn.set_route("selling-home");
|
||||
});
|
||||
}
|
||||
|
||||
erpnext.CRMFunnel = Class.extend({
|
||||
init: function(wrapper) {
|
||||
var me = this;
|
||||
// 0 setTimeout hack - this gives time for canvas to get width and height
|
||||
setTimeout(function() {
|
||||
me.setup(wrapper);
|
||||
me.get_data();
|
||||
}, 0);
|
||||
},
|
||||
|
||||
setup: function(wrapper) {
|
||||
var me = this;
|
||||
|
||||
this.elements = {
|
||||
layout: $(wrapper).find(".layout-main"),
|
||||
from_date: wrapper.appframe.add_date("From Date"),
|
||||
to_date: wrapper.appframe.add_date("To Date"),
|
||||
refresh_btn: wrapper.appframe.add_button("Refresh",
|
||||
function() { me.get_data(); }, "icon-refresh"),
|
||||
};
|
||||
|
||||
this.elements.no_data = $('<div class="alert alert-warning">No Data</div>')
|
||||
.toggle(false)
|
||||
.appendTo(this.elements.layout);
|
||||
|
||||
this.elements.funnel_wrapper = $('<div class="funnel-wrapper text-center"></div>')
|
||||
.appendTo(this.elements.layout);
|
||||
|
||||
this.options = {
|
||||
from_date: wn.datetime.add_months(wn.datetime.get_today(), -1),
|
||||
to_date: wn.datetime.get_today()
|
||||
};
|
||||
|
||||
// set defaults and bind on change
|
||||
$.each(this.options, function(k, v) {
|
||||
me.elements[k].val(wn.datetime.str_to_user(v));
|
||||
me.elements[k].on("change", function() {
|
||||
me.options[k] = wn.datetime.user_to_str($(this).val());
|
||||
me.get_data();
|
||||
});
|
||||
});
|
||||
|
||||
// bind refresh
|
||||
this.elements.refresh_btn.on("click", function() {
|
||||
me.get_data(this);
|
||||
});
|
||||
|
||||
// bind resize
|
||||
$(window).resize(function() {
|
||||
me.render();
|
||||
});
|
||||
},
|
||||
|
||||
get_data: function(btn) {
|
||||
var me = this;
|
||||
wn.call({
|
||||
module: "selling",
|
||||
page: "crm_funnel",
|
||||
method: "get_funnel_data",
|
||||
args: {
|
||||
from_date: this.options.from_date,
|
||||
to_date: this.options.to_date
|
||||
},
|
||||
btn: btn,
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
me.options.data = r.message;
|
||||
me.render();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var me = this;
|
||||
this.prepare();
|
||||
|
||||
var context = this.elements.context,
|
||||
x_start = 0.0,
|
||||
x_end = this.options.width,
|
||||
x_mid = (x_end - x_start) / 2.0,
|
||||
y = 0,
|
||||
y_old = 0.0;
|
||||
|
||||
if(this.options.total_value === 0) {
|
||||
this.elements.no_data.toggle(true);
|
||||
return;
|
||||
}
|
||||
|
||||
this.options.data.forEach(function(d) {
|
||||
context.fillStyle = d.color;
|
||||
context.strokeStyle = d.color;
|
||||
me.draw_triangle(x_start, x_mid, x_end, y, me.options.height);
|
||||
|
||||
y_old = y;
|
||||
|
||||
// new y
|
||||
y = y + d.height;
|
||||
|
||||
// new x
|
||||
var half_side = (me.options.height - y) / Math.sqrt(3);
|
||||
x_start = x_mid - half_side;
|
||||
x_end = x_mid + half_side;
|
||||
|
||||
var y_mid = y_old + (y - y_old) / 2.0;
|
||||
|
||||
me.draw_legend(x_mid, y_mid, me.options.width, me.options.height, d.value + " - " + d.title);
|
||||
});
|
||||
},
|
||||
|
||||
prepare: function() {
|
||||
var me = this;
|
||||
|
||||
this.elements.no_data.toggle(false);
|
||||
|
||||
// calculate width and height options
|
||||
this.options.width = $(this.elements.funnel_wrapper).width() * 2.0 / 3.0;
|
||||
this.options.height = (Math.sqrt(3) * this.options.width) / 2.0;
|
||||
|
||||
// calculate total weightage
|
||||
// as height decreases, area decreases by the square of the reduction
|
||||
// hence, compensating by squaring the index value
|
||||
this.options.total_weightage = this.options.data.reduce(
|
||||
function(prev, curr, i) { return prev + Math.pow(i+1, 2) * curr.value; }, 0.0);
|
||||
|
||||
// calculate height for each data
|
||||
$.each(this.options.data, function(i, d) {
|
||||
d.height = me.options.height * d.value * Math.pow(i+1, 2) / me.options.total_weightage;
|
||||
});
|
||||
|
||||
this.elements.canvas = $('<canvas></canvas>')
|
||||
.appendTo(this.elements.funnel_wrapper.empty())
|
||||
.attr("width", $(this.elements.funnel_wrapper).width())
|
||||
.attr("height", this.options.height);
|
||||
|
||||
this.elements.context = this.elements.canvas.get(0).getContext("2d");
|
||||
},
|
||||
|
||||
draw_triangle: function(x_start, x_mid, x_end, y, height) {
|
||||
var context = this.elements.context;
|
||||
context.beginPath();
|
||||
context.moveTo(x_start, y);
|
||||
context.lineTo(x_end, y);
|
||||
context.lineTo(x_mid, height);
|
||||
context.lineTo(x_start, y);
|
||||
context.closePath();
|
||||
context.fill();
|
||||
},
|
||||
|
||||
draw_legend: function(x_mid, y_mid, width, height, title) {
|
||||
var context = this.elements.context;
|
||||
|
||||
// draw line
|
||||
context.beginPath();
|
||||
context.moveTo(x_mid, y_mid);
|
||||
context.lineTo(width, y_mid);
|
||||
context.closePath();
|
||||
context.stroke();
|
||||
|
||||
// draw circle
|
||||
context.beginPath();
|
||||
context.arc(width, y_mid, 5, 0, Math.PI * 2, false);
|
||||
context.closePath();
|
||||
context.fill();
|
||||
|
||||
// draw text
|
||||
context.fillStyle = "black";
|
||||
context.textBaseline = "middle";
|
||||
context.font = "1.1em sans-serif";
|
||||
context.fillText(title, width + 20, y_mid);
|
||||
}
|
||||
});
|
33
selling/page/sales_funnel/sales_funnel.py
Normal file
33
selling/page/sales_funnel/sales_funnel.py
Normal file
@ -0,0 +1,33 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_funnel_data(from_date, to_date):
|
||||
active_leads = webnotes.conn.sql("""select count(*) from `tabLead`
|
||||
where (`modified` between %s and %s)
|
||||
and status != "Do Not Contact" """, (from_date, to_date))[0][0]
|
||||
|
||||
active_leads += webnotes.conn.sql("""select count(distinct customer) from `tabContact`
|
||||
where (`modified` between %s and %s)
|
||||
and status != "Passive" """, (from_date, to_date))[0][0]
|
||||
|
||||
opportunities = webnotes.conn.sql("""select count(*) from `tabOpportunity`
|
||||
where docstatus = 1 and (`modified` between %s and %s)
|
||||
and status != "Lost" """, (from_date, to_date))[0][0]
|
||||
|
||||
quotations = webnotes.conn.sql("""select count(*) from `tabQuotation`
|
||||
where docstatus = 1 and (`modified` between %s and %s)
|
||||
and status != "Lost" """, (from_date, to_date))[0][0]
|
||||
|
||||
sales_orders = webnotes.conn.sql("""select count(*) from `tabQuotation`
|
||||
where docstatus = 1 and (`modified` between %s and %s)""", (from_date, to_date))[0][0]
|
||||
|
||||
return [
|
||||
{ "title": "Active Leads / Customers", "value": active_leads, "color": "#B03B46" },
|
||||
{ "title": "Opportunities", "value": opportunities, "color": "#F09C00" },
|
||||
{ "title": "Quotations", "value": quotations, "color": "#006685" },
|
||||
{ "title": "Sales Orders", "value": sales_orders, "color": "#00AD65" }
|
||||
]
|
33
selling/page/sales_funnel/sales_funnel.txt
Normal file
33
selling/page/sales_funnel/sales_funnel.txt
Normal file
@ -0,0 +1,33 @@
|
||||
[
|
||||
{
|
||||
"creation": "2013-10-04 13:17:18",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-10-04 13:17:18",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
{
|
||||
"doctype": "Page",
|
||||
"icon": "icon-filter",
|
||||
"module": "Selling",
|
||||
"name": "__common__",
|
||||
"page_name": "sales-funnel",
|
||||
"standard": "Yes",
|
||||
"title": "Sales Funnel"
|
||||
},
|
||||
{
|
||||
"doctype": "Page Role",
|
||||
"name": "__common__",
|
||||
"parent": "sales-funnel",
|
||||
"parentfield": "roles",
|
||||
"parenttype": "Page",
|
||||
"role": "Sales Manager"
|
||||
},
|
||||
{
|
||||
"doctype": "Page",
|
||||
"name": "sales-funnel"
|
||||
},
|
||||
{
|
||||
"doctype": "Page Role"
|
||||
}
|
||||
]
|
@ -155,6 +155,10 @@ wn.module_page["Selling"] = [
|
||||
"label":wn._("Sales Analytics"),
|
||||
page: "sales-analytics"
|
||||
},
|
||||
{
|
||||
"label":wn._("Sales Funnel"),
|
||||
page: "sales-funnel"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user