12 changed files with 462 additions and 0 deletions
@ -0,0 +1,22 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# Copyright (C) 2017-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Linto CT (<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# This program is free software: you can modify |
||||
|
# it under the terms of the GNU Affero General Public License (AGPL) as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################### |
||||
|
import models |
@ -0,0 +1,41 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# Copyright (C) 2017-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Linto CT (<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# This program is free software: you can modify |
||||
|
# it under the terms of the GNU Affero General Public License (AGPL) as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################### |
||||
|
{ |
||||
|
'name': 'Donut Diagram For Sales', |
||||
|
'version': '10.0.1.0.0', |
||||
|
'category': 'Sales', |
||||
|
'summary': 'Donut Analysis on Salesperson Target.', |
||||
|
'description': 'We can analyse the total target and analysis of each salesperson.', |
||||
|
'author': 'Cybrosys Techno Solutions', |
||||
|
'maintainer': 'Cybrosys Techno Solutions', |
||||
|
'company': 'Cybrosys Techno Solutions', |
||||
|
'depends': ['crm', 'sale', 'sales_team'], |
||||
|
'website': 'https://www.cybrosys.com', |
||||
|
'data': [ |
||||
|
'views/templates.xml', |
||||
|
], |
||||
|
'images': ['static/description/banner.jpg'], |
||||
|
'license': 'AGPL-3', |
||||
|
'application': False, |
||||
|
'installable': True, |
||||
|
'auto_install': False, |
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# Copyright (C) 2017-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Linto CT (<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# This program is free software: you can modify |
||||
|
# it under the terms of the GNU Affero General Public License (AGPL) as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################### |
||||
|
import find_user_target |
@ -0,0 +1,122 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# Copyright (C) 2017-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Linto CT (<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# This program is free software: you can modify |
||||
|
# it under the terms of the GNU Affero General Public License (AGPL) as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################### |
||||
|
import datetime |
||||
|
from odoo import models, fields |
||||
|
|
||||
|
|
||||
|
class CrmTargetAchievement(models.Model): |
||||
|
_inherit = 'crm.team' |
||||
|
|
||||
|
def find_target(self, uid): |
||||
|
"""This function will return the target and achievement in a list, |
||||
|
based on the user. |
||||
|
input: id of the user |
||||
|
output: list of dictionary with name and percentage """ |
||||
|
cr = self._cr |
||||
|
today = datetime.date.today() |
||||
|
begning = today.replace(day=1) |
||||
|
target = 0 |
||||
|
tmp = {} |
||||
|
achieved_total = 0 |
||||
|
if uid == 1: |
||||
|
# admin will see the details of all users |
||||
|
# taking all invoices |
||||
|
for user in self.env['res.users'].search([]): |
||||
|
target += user.target_sales_invoiced |
||||
|
cr.execute("select ai.user_id, sum(ai.amount_untaxed) as total from account_invoice ai" |
||||
|
" where ai.state in ('open', 'paid') and ai.type='out_invoice' " |
||||
|
" and ai.date_invoice >= %s group by ai.user_id", (begning,)) |
||||
|
achieved = cr.dictfetchall() |
||||
|
for i in achieved: |
||||
|
rec = self.env['res.users'].browse(i['user_id']) |
||||
|
tmp[rec.name] = i['total'] |
||||
|
achieved_total += i['total'] |
||||
|
|
||||
|
else: |
||||
|
# checking wheather this user is team lead or not |
||||
|
team = self.env['crm.team'].search([('user_id', '=', self._uid)], limit=1) |
||||
|
if team: |
||||
|
# this user is team lead |
||||
|
members = team.member_ids |
||||
|
# taking team member's targets' |
||||
|
for member in members: |
||||
|
target += member.target_sales_invoiced |
||||
|
# taking his target |
||||
|
target += self.env.user.target_sales_invoiced |
||||
|
ids = members.ids |
||||
|
ids.append(self._uid) |
||||
|
cr.execute("select ai.user_id, sum(ai.amount_untaxed) as total from account_invoice ai" |
||||
|
" where ai.state in ('open', 'paid') and ai.type='out_invoice' " |
||||
|
" and ai.user_id in %s and ai.date_invoice >= %s group by ai.user_id", |
||||
|
(tuple(ids), begning)) |
||||
|
achieved = cr.dictfetchall() |
||||
|
|
||||
|
for i in achieved: |
||||
|
rec = self.env['res.users'].browse(i['user_id']) |
||||
|
tmp[rec.name] = i['total'] |
||||
|
achieved_total += i['total'] |
||||
|
|
||||
|
else: |
||||
|
# this is just a user, not a team lead |
||||
|
target += self.env.user.target_sales_invoiced |
||||
|
cr.execute("select sum(amount_untaxed) as total from account_invoice " |
||||
|
" where state in ('open', 'paid') and ai.type='out_invoice' " |
||||
|
" and date_invoice >= %s and user_id=%s", (begning, self._uid)) |
||||
|
invoices = cr.dictfetchall() |
||||
|
|
||||
|
for i in invoices: |
||||
|
tmp[self.env.user.name] = i['total'] |
||||
|
achieved_total += i['total'] |
||||
|
# checking the achieved amount is greater than target or not |
||||
|
target_bal = target - achieved_total |
||||
|
result = [] |
||||
|
|
||||
|
if target_bal < 0: |
||||
|
# achieved amount is greater than target |
||||
|
for i in tmp: |
||||
|
temp = { |
||||
|
'name': i + ":" + str(tmp[i]), |
||||
|
'percent': round((tmp[i] / target) * 100, 1), |
||||
|
} |
||||
|
result.append(temp) |
||||
|
# taking the difference in target and achieved |
||||
|
temp = { |
||||
|
'name': 'Target Exceeded ' + ":" + str(-1*target_bal), |
||||
|
'percent': round(-1 * (target_bal / target) * 100, 1), |
||||
|
} |
||||
|
result.append(temp) |
||||
|
else: |
||||
|
# achieved amount is lesser than or equal to target |
||||
|
for i in tmp: |
||||
|
temp = { |
||||
|
'name': i + ":" + str(tmp[i]), |
||||
|
'percent': round((tmp[i] / target) * 100, 1), |
||||
|
} |
||||
|
result.append(temp) |
||||
|
# taking the difference in target and achieved |
||||
|
temp = { |
||||
|
'name': 'Target Pending ' + ":" + str(target_bal), |
||||
|
'percent': round((target_bal / target) * 100, 1), |
||||
|
} |
||||
|
result.append(temp) |
||||
|
|
||||
|
return result |
After Width: | Height: | Size: 87 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 34 KiB |
@ -0,0 +1,102 @@ |
|||||
|
<section class="oe_container"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<h2 class="oe_slogan">Donut Diagram For Sales</h2> |
||||
|
<h3 class="oe_slogan">Target vs Achievement Analysis With The Help of a Donut Diagram</h3> |
||||
|
<h4 class="oe_slogan"><a href="https://www.cybrosys.com">Cybrosys Technologies</a> </h4> |
||||
|
</div> |
||||
|
<div class="oe_row oe_spaced" style="padding-left:65px;"> |
||||
|
<h4>Features:</h4> |
||||
|
<div> |
||||
|
<span style="color:green;"> ☑ </span> Admin can see total target and achievements of each employee.<br/> |
||||
|
<span style="color:green;"> ☑ </span> Team leader can see the performance chart of his team.<br/> |
||||
|
<span style="color:green;"> ☑ </span> Each team member can see his own performance chart.<br/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
|
||||
|
<section class="oe_container oe_dark"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<div class="oe_picture"> |
||||
|
<h3 class="oe_slogan">Overview</h3> |
||||
|
<p class="oe_mt32"> |
||||
|
The module gives a detailed analysis report of the Invoice target and Achievement of the |
||||
|
Individual employee, Team as well as the Organization. The administrator and Team Lead |
||||
|
can view their own individual achievements well as Employee/Member wise achievements. |
||||
|
The employee can see their individual performance also. Everything is presented as donut |
||||
|
chart. |
||||
|
</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
|
||||
|
<section class="oe_container"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<div> |
||||
|
<div class="oe_span12"> |
||||
|
<div class="oe_demo oe_picture oe_screenshot"> |
||||
|
<img src="donut-sample-dashboard.png"> |
||||
|
</div> |
||||
|
</div> |
||||
|
<br><br><br> |
||||
|
<p>For the perfect working of this module, first, we have to configure targets for the users. If you |
||||
|
are using sales teams, you have to configure sales teams and team members first. |
||||
|
</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
<section class="oe_container oe_dark"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<div class=""> |
||||
|
<p> |
||||
|
The administrator can see the total target and achievements of each salesperson in a donut |
||||
|
chart. In the chart, you can see the percentage of amount achieved by each user. The amount |
||||
|
invoiced by each user will be specified near the chart. |
||||
|
</p> |
||||
|
<p> |
||||
|
The calculation is as follows, first, the system will take the targets of all the users, and then it |
||||
|
will consider each employees achievements. You can also see the difference between the total |
||||
|
target and total achieved amount. |
||||
|
</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
|
||||
|
<section class="oe_container"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<div class=""> |
||||
|
<p> |
||||
|
For the team lead, he will see the total target of his team including the team lead if there are any |
||||
|
and the amount achieved by each members including team lead. |
||||
|
<p> |
||||
|
<p> |
||||
|
For the salesperson, he will see his target and the amount invoiced by him. |
||||
|
</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
|
||||
|
<section class="oe_container oe_dark"> |
||||
|
<h2 class="oe_slogan" style="margin-top:20px;" >Need Any Help?</h2> |
||||
|
<div class="oe_slogan" style="margin-top:10px !important;"> |
||||
|
<div> |
||||
|
<a class="btn btn-primary btn-lg mt8" |
||||
|
style="color: #FFFFFF !important;border-radius: 0;" href="https://www.cybrosys.com"><i |
||||
|
class="fa fa-envelope"></i> Email </a> <a |
||||
|
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" |
||||
|
href="https://www.cybrosys.com/contact/"><i |
||||
|
class="fa fa-phone"></i> Contact Us </a> <a |
||||
|
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" |
||||
|
href="https://www.cybrosys.com/odoo-customization-and-installation/"><i |
||||
|
class="fa fa-check-square"></i> Request Customization </a> |
||||
|
</div> |
||||
|
<br> |
||||
|
<img src="cybro_logo.png" style="width: 190px; margin-bottom: 20px;" class="center-block"> |
||||
|
<div> |
||||
|
<a href="https://twitter.com/cybrosys" target="_blank"><i class="fa fa-2x fa-twitter" style="color:white;background: #00a0d1;width:35px;"></i></a></td> |
||||
|
<a href="https://www.linkedin.com/company/cybrosys-technologies-pvt-ltd" target="_blank"><i class="fa fa-2x fa-linkedin" style="color:white;background: #31a3d6;width:35px;padding-left: 3px;"></i></a></td> |
||||
|
<a href="https://www.facebook.com/cybrosystechnologies" target="_blank"><i class="fa fa-2x fa-facebook" style="color:white;background: #3b5998;width:35px;padding-left: 8px;"></i></a></td> |
||||
|
<a href="https://plus.google.com/106641282743045431892/about" target="_blank"><i class="fa fa-2x fa-google-plus" style="color:white;background: #c53c2c;width:35px;padding-left: 3px;"></i></a></td> |
||||
|
<a href="https://in.pinterest.com/cybrosys" target="_blank"><i class="fa fa-2x fa-pinterest" style="color:white;background: #ac0f18;width:35px;padding-left: 3px;"></i></a></td> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
@ -0,0 +1,3 @@ |
|||||
|
.dashboard_donut_chart{ |
||||
|
margin-left: 25%; |
||||
|
} |
@ -0,0 +1,139 @@ |
|||||
|
odoo.define('target_achievement_invoice.dashboard', function (require) { |
||||
|
"use strict"; |
||||
|
var core = require('web.core'); |
||||
|
var CrmDashboard = require('sales_team.dashboard'); |
||||
|
var Model = require('web.Model'); |
||||
|
var QWeb = core.qweb; |
||||
|
CrmDashboard.include({ |
||||
|
render: function() { |
||||
|
this._super(); |
||||
|
var self = this; |
||||
|
self.fetch_data().then(function(result) { |
||||
|
var sales_dashboard = QWeb.render('sales_team.SalesDashboard', { |
||||
|
widget: self, |
||||
|
show_demo: self.show_demo, |
||||
|
values: result, |
||||
|
}); |
||||
|
|
||||
|
var pie_div = "<div class='dashboard_donut_chart'></div>"; |
||||
|
var $pie_div = $(pie_div); |
||||
|
|
||||
|
var width = 550; |
||||
|
var height = 350; |
||||
|
var radius = height/2; |
||||
|
var color = d3.scale.category10(); |
||||
|
// getting data to show
|
||||
|
var uid = self.dataset.context.uid; |
||||
|
new Model('crm.team').call('find_target', ['', uid]).done(function (res_data) { |
||||
|
console.log("res_data: ", res_data) |
||||
|
var dataset = res_data; |
||||
|
|
||||
|
var pie=d3.layout.pie() |
||||
|
.value(function(d){return d.percent}) |
||||
|
.sort(null) |
||||
|
.padAngle(.03); |
||||
|
|
||||
|
var w=300,h=300; |
||||
|
|
||||
|
var outerRadius=w/2; |
||||
|
var innerRadius=85; |
||||
|
|
||||
|
var color = d3.scale.category10(); |
||||
|
|
||||
|
var arc=d3.svg.arc() |
||||
|
.outerRadius(outerRadius) |
||||
|
.innerRadius(innerRadius); |
||||
|
|
||||
|
var svg=d3.select($pie_div[0]) |
||||
|
.append("svg") |
||||
|
.attr({ |
||||
|
width:w+300, |
||||
|
height:h, |
||||
|
class:'shadow' |
||||
|
}).append('g') |
||||
|
.attr({ |
||||
|
transform:'translate('+w/2+','+h/2+')' |
||||
|
}); |
||||
|
var path=svg.selectAll('path') |
||||
|
.data(pie(dataset)) |
||||
|
.enter() |
||||
|
.append('path') |
||||
|
.attr({ |
||||
|
d:arc, |
||||
|
fill:function(d,i){ |
||||
|
return color(d.data.name); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
var text=svg.selectAll('text') |
||||
|
.data(pie(dataset)) |
||||
|
.enter() |
||||
|
.append("text") |
||||
|
.attr("transform", function (d) { |
||||
|
return "translate(" + arc.centroid(d) + ")"; |
||||
|
}) |
||||
|
.attr("dy", ".4em") |
||||
|
.attr("text-anchor", "middle") |
||||
|
.text(function(d){ |
||||
|
return d.data.percent+"%"; |
||||
|
}) |
||||
|
.style({ |
||||
|
fill:'black', |
||||
|
'font-size':'10px', |
||||
|
'color':'black' |
||||
|
}); |
||||
|
var legendRectSize=20; |
||||
|
var legendSpacing=7; |
||||
|
var legendHeight=legendRectSize+legendSpacing; |
||||
|
|
||||
|
|
||||
|
var legend=svg.selectAll('.legend') |
||||
|
.data(color.domain()) |
||||
|
.enter() |
||||
|
.append('g') |
||||
|
.attr({ |
||||
|
class:'legend', |
||||
|
transform:function(d,i){ |
||||
|
//Just a calculation for x and y position
|
||||
|
return 'translate(185,' + ((i*legendHeight)-65) + ')'; |
||||
|
} |
||||
|
}); |
||||
|
legend.append('rect') |
||||
|
.attr({ |
||||
|
width:legendRectSize, |
||||
|
height:legendRectSize, |
||||
|
rx:70, |
||||
|
ry:20 |
||||
|
}) |
||||
|
.style({ |
||||
|
fill:color, |
||||
|
stroke:color |
||||
|
}); |
||||
|
|
||||
|
legend.append('text') |
||||
|
.attr({ |
||||
|
x:75, |
||||
|
y:15 |
||||
|
}) |
||||
|
.text(function(d){ |
||||
|
return d; |
||||
|
}).style({ |
||||
|
fill:'#929DAF', |
||||
|
'font-size':'14px' |
||||
|
}); |
||||
|
|
||||
|
var target = svg.select('target') |
||||
|
.data("Target") |
||||
|
.enter() |
||||
|
.append('g'); |
||||
|
|
||||
|
var html_string = $pie_div[0].outerHTML; |
||||
|
$(html_string).prependTo(self.$el); |
||||
|
}); |
||||
|
}); |
||||
|
return; |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
}); |
||||
|
|
@ -0,0 +1,11 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
<template id="assets_backend" name="donut_dashboard" inherit_id="web.assets_backend"> |
||||
|
<xpath expr="." position="inside"> |
||||
|
<script type="text/javascript" src="/target_achievement_invoice/static/src/js/pie_dashboard.js"></script> |
||||
|
<link href="/target_achievement_invoice/static/src/css/style.css" rel="stylesheet"/> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
</data> |
||||
|
</openerp> |
Loading…
Reference in new issue