diff --git a/target_achievement_invoice/__init__.py b/target_achievement_invoice/__init__.py new file mode 100644 index 000000000..fc5bfc86b --- /dev/null +++ b/target_achievement_invoice/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Linto CT () +# +# 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 . +# +################################################################################### +import models diff --git a/target_achievement_invoice/__manifest__.py b/target_achievement_invoice/__manifest__.py new file mode 100644 index 000000000..7f2f91f5d --- /dev/null +++ b/target_achievement_invoice/__manifest__.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Linto CT () +# +# 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 . +# +################################################################################### +{ + '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, +} diff --git a/target_achievement_invoice/models/__init__.py b/target_achievement_invoice/models/__init__.py new file mode 100644 index 000000000..7c192091d --- /dev/null +++ b/target_achievement_invoice/models/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Linto CT () +# +# 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 . +# +################################################################################### +import find_user_target diff --git a/target_achievement_invoice/models/find_user_target.py b/target_achievement_invoice/models/find_user_target.py new file mode 100644 index 000000000..f2b7b797d --- /dev/null +++ b/target_achievement_invoice/models/find_user_target.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Linto CT () +# +# 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 . +# +################################################################################### +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 diff --git a/target_achievement_invoice/static/description/banner.jpg b/target_achievement_invoice/static/description/banner.jpg new file mode 100644 index 000000000..cf0ad2313 Binary files /dev/null and b/target_achievement_invoice/static/description/banner.jpg differ diff --git a/target_achievement_invoice/static/description/cybro_logo.png b/target_achievement_invoice/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/target_achievement_invoice/static/description/cybro_logo.png differ diff --git a/target_achievement_invoice/static/description/donut-sample-dashboard.png b/target_achievement_invoice/static/description/donut-sample-dashboard.png new file mode 100644 index 000000000..fff17601b Binary files /dev/null and b/target_achievement_invoice/static/description/donut-sample-dashboard.png differ diff --git a/target_achievement_invoice/static/description/icon.png b/target_achievement_invoice/static/description/icon.png new file mode 100644 index 000000000..22777fc51 Binary files /dev/null and b/target_achievement_invoice/static/description/icon.png differ diff --git a/target_achievement_invoice/static/description/index.html b/target_achievement_invoice/static/description/index.html new file mode 100644 index 000000000..087f31258 --- /dev/null +++ b/target_achievement_invoice/static/description/index.html @@ -0,0 +1,102 @@ +
+
+

Donut Diagram For Sales

+

Target vs Achievement Analysis With The Help of a Donut Diagram

+

Cybrosys Technologies

+
+
+

Features:

+
+ Admin can see total target and achievements of each employee.
+ Team leader can see the performance chart of his team.
+ Each team member can see his own performance chart.
+
+
+
+ +
+
+
+

Overview

+

+ 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. +

+
+
+
+ +
+
+
+
+
+ +
+
+


+

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. +

+
+
+
+
+
+
+

+ 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. +

+

+ 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. +

+
+
+
+ +
+
+
+

+ 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. +

+

+ For the salesperson, he will see his target and the amount invoiced by him. +

+
+
+
+ +
+

Need Any Help?

+ +
\ No newline at end of file diff --git a/target_achievement_invoice/static/src/css/style.css b/target_achievement_invoice/static/src/css/style.css new file mode 100644 index 000000000..7ca8a0738 --- /dev/null +++ b/target_achievement_invoice/static/src/css/style.css @@ -0,0 +1,3 @@ +.dashboard_donut_chart{ +margin-left: 25%; +} \ No newline at end of file diff --git a/target_achievement_invoice/static/src/js/pie_dashboard.js b/target_achievement_invoice/static/src/js/pie_dashboard.js new file mode 100644 index 000000000..88f0accc5 --- /dev/null +++ b/target_achievement_invoice/static/src/js/pie_dashboard.js @@ -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 = "
"; + 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; + }, +}); + +}); + diff --git a/target_achievement_invoice/views/templates.xml b/target_achievement_invoice/views/templates.xml new file mode 100644 index 000000000..4c7bd5940 --- /dev/null +++ b/target_achievement_invoice/views/templates.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file