[wsgi] [minor] fixed flags

This commit is contained in:
Rushabh Mehta 2013-10-08 18:25:03 +05:30
commit 26c5a585c7
6 changed files with 262 additions and 0 deletions

View File

View File

@ -0,0 +1,3 @@
.funnel-wrapper {
margin: 15px;
}

View 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);
}
});

View 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" }
]

View 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"
}
]

View File

@ -155,6 +155,10 @@ wn.module_page["Selling"] = [
"label":wn._("Sales Analytics"),
page: "sales-analytics"
},
{
"label":wn._("Sales Funnel"),
page: "sales-funnel"
},
]
},
{