Browse Source

Apr 5 : [UPDT] Updated 'project_dashboard_odoo'

pull/254/head
AjmalCybro 2 years ago
parent
commit
1e4db8dbfb
  1. 3
      project_dashboard_odoo/README.rst
  2. 1
      project_dashboard_odoo/__init__.py
  3. 4
      project_dashboard_odoo/__manifest__.py
  4. 22
      project_dashboard_odoo/controllers/__init__.py
  5. 157
      project_dashboard_odoo/controllers/main.py
  6. 8
      project_dashboard_odoo/doc/RELEASE_NOTES.md
  7. 241
      project_dashboard_odoo/models/pj_dashboard.py
  8. BIN
      project_dashboard_odoo/static/description/assets/screenshots/Screenshot1.png
  9. BIN
      project_dashboard_odoo/static/description/assets/screenshots/Screenshot2.png
  10. BIN
      project_dashboard_odoo/static/description/assets/screenshots/Screenshot3.png
  11. BIN
      project_dashboard_odoo/static/description/assets/screenshots/Screenshot4.png
  12. BIN
      project_dashboard_odoo/static/description/assets/screenshots/Screenshot5.png
  13. BIN
      project_dashboard_odoo/static/description/assets/screenshots/Screenshot6.png
  14. BIN
      project_dashboard_odoo/static/description/assets/screenshots/checked.png
  15. BIN
      project_dashboard_odoo/static/description/assets/screenshots/hero.gif
  16. BIN
      project_dashboard_odoo/static/description/assets/screenshots/hero.png
  17. BIN
      project_dashboard_odoo/static/description/assets/screenshots/logo.png
  18. BIN
      project_dashboard_odoo/static/description/assets/screenshots/pd1.png
  19. BIN
      project_dashboard_odoo/static/description/assets/screenshots/pd2.png
  20. BIN
      project_dashboard_odoo/static/description/assets/screenshots/pd3.png
  21. BIN
      project_dashboard_odoo/static/description/assets/screenshots/pd4.png
  22. BIN
      project_dashboard_odoo/static/description/assets/screenshots/pd5.png
  23. BIN
      project_dashboard_odoo/static/description/assets/screenshots/prg_db.png
  24. BIN
      project_dashboard_odoo/static/description/assets/screenshots/prg_db2.png
  25. BIN
      project_dashboard_odoo/static/description/assets/screenshots/prg_db3.png
  26. BIN
      project_dashboard_odoo/static/description/assets/screenshots/prg_db4.png
  27. BIN
      project_dashboard_odoo/static/description/assets/screenshots/screenshot.png
  28. 45
      project_dashboard_odoo/static/description/index.html
  29. 831
      project_dashboard_odoo/static/src/css/dashboard.css
  30. 439
      project_dashboard_odoo/static/src/js/dashboard.js
  31. 279
      project_dashboard_odoo/static/src/xml/dashboard.xml

3
project_dashboard_odoo/README.rst

@ -24,7 +24,8 @@ Company
Credits Credits
------- -------
* Developers: odoo@cybrosys.com * Developers: odoo@cybrosys.com
V15 - Archana V, archana@cybrosys.info V15 - Archana V, archana @ cybrosys
V16 - YadhuKrishnan K Yadhu @ cybrosys
Contacts Contacts
-------- --------

1
project_dashboard_odoo/__init__.py

@ -21,3 +21,4 @@
############################################################################# #############################################################################
from .import models from .import models
from . import controllers

4
project_dashboard_odoo/__manifest__.py

@ -3,7 +3,7 @@
# #
# Cybrosys Technologies Pvt. Ltd. # Cybrosys Technologies Pvt. Ltd.
# #
# Copyright (C) 2022-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) # Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) # Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
# #
# You can modify it under the terms of the GNU LESSER # You can modify it under the terms of the GNU LESSER
@ -25,7 +25,7 @@
'category': 'Productivity', 'category': 'Productivity',
'summary': 'Detailed Dashboard View for Project', 'summary': 'Detailed Dashboard View for Project',
'description': 'Detailed Dashboard View for Project', 'description': 'Detailed Dashboard View for Project',
'version': '15.0.1.0.0', 'version': '15.0.2.0.1',
'author': 'Cybrosys Techno Solutions', 'author': 'Cybrosys Techno Solutions',
'company': 'Cybrosys Techno Solutions', 'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions', 'maintainer': 'Cybrosys Techno Solutions',

22
project_dashboard_odoo/controllers/__init__.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import main

157
project_dashboard_odoo/controllers/main.py

@ -0,0 +1,157 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
import datetime
from odoo import http
from odoo.http import request
class ProjectFilter(http.Controller):
"""
The ProjectFilter class provides the filter option to the js.
When applying the filter return the corresponding data.
Methods:
project_filter(self):
when the page is loaded adding filter options to the selection
field.
return a list variable.
project_filter_apply(self,**kw):
after applying the filter receiving the values and return the
filtered data.
"""
@http.route('/project/filter', auth='public', type='json')
def project_filter(self):
"""
Summery:
transferring data to the selection field that works as a filter
Returns:
type:list of lists , it contains the data for the corresponding
filter.
"""
project_list = []
employee_list = []
project_ids = request.env['project.project'].search([])
employee_ids = request.env['hr.employee'].search([])
# getting partner data
for employee_id in employee_ids:
dic = {'name': employee_id.name,
'id': employee_id.id}
employee_list.append(dic)
for project_id in project_ids:
dic = {'name': project_id.name,
'id': project_id.id}
project_list.append(dic)
return [project_list, employee_list]
@http.route('/project/filter-apply', auth='public', type='json')
def project_filter_apply(self, **kw):
"""
Summery:
transferring data after filter 9is applied
Args:
kw(dict):This parameter contain value of selection field
Returns:
type:dict, it contains the data for the corresponding
filter.
and transferring data to ui after filtration.
"""
data = kw['data']
pro_selected = []
emp_selected = []
# checking tje employee selected or not
if data['employee'] == 'null':
emp_selected = [employee.id for employee in
request.env['hr.employee'].search([])]
else:
emp_selected = [int(data['employee'])]
start_date = data['start_date']
end_date = data['end_date']
pro_selected = False
# checking the dates are selected or not
if start_date != 'null' and end_date != 'null':
start_date = datetime.datetime.strptime(start_date,
"%Y-%m-%d").date()
end_date = datetime.datetime.strptime(end_date, "%Y-%m-%d").date()
if data['project'] == 'null':
pro_selected = [project.id for project in
request.env['project.project'].search(
[('date_start', '>', start_date),
('date_start', '<', end_date)])]
else:
pro_selected = [int(data['project'])]
elif start_date == 'null' and end_date != 'null':
end_date = datetime.datetime.strptime(end_date, "%Y-%m-%d").date()
if data['project'] == 'null':
pro_selected = [project.id for project in
request.env['project.project'].search(
[('date_start', '<', end_date)])]
else:
pro_selected = [int(data['project'])]
elif start_date != 'null' and end_date == 'null':
start_date = datetime.datetime.strptime(start_date,
"%Y-%m-%d").date()
if data['project'] == 'null':
pro_selected = [project.id for project in
request.env['project.project'].search(
[('date_start', '>', start_date)])]
else:
pro_selected = [int(data['project'])]
else:
if data['project'] == 'null':
pro_selected = [project.id for project in
request.env['project.project'].search([])]
else:
pro_selected = [int(data['project'])]
report_project = request.env['project.profitability.report'].search(
[('project_id', 'in', pro_selected)])
to_invoice = sum(report_project.mapped('amount_untaxed_to_invoice'))
invoice = sum(report_project.mapped('amount_untaxed_invoiced'))
timesheet_cost = sum(report_project.mapped('timesheet_cost'))
other_cost = sum(report_project.mapped('expense_cost'))
profitability = to_invoice + invoice + timesheet_cost + other_cost
analytic_project = request.env['account.analytic.line'].search(
[('project_id', 'in', pro_selected),
('employee_id', 'in', emp_selected)])
sale_orders = []
for rec in analytic_project:
if rec.order_id.id and rec.order_id.id not in sale_orders:
sale_orders.append(rec.order_id.id)
total_time = sum(analytic_project.mapped('unit_amount'))
return {
'total_project': pro_selected,
'total_emp': emp_selected,
'total_task': [rec.id for rec in request.env['project.task'].search(
[('project_id', 'in', pro_selected)])],
'hours_recorded': total_time,
'list_hours_recorded': [rec.id for rec in analytic_project],
'total_margin': profitability,
'total_so': sale_orders
}

8
project_dashboard_odoo/doc/RELEASE_NOTES.md

@ -4,5 +4,11 @@
#### 26.05.2022 #### 26.05.2022
#### Version 15.0.1.0.0 #### Version 15.0.1.0.0
## Module <project_dashboard_odoo> ## Module <project_dashboard_odoo>
##### Initial Commit for project_dashboard_odoo ##### Initial Commit for project_dashboard_odoo
#### 30.03.2023
#### Version 15.0.2.0.1
## Module <project_dashboard_odoo>
#### UPDT
#### Update the module with additional graph and filter, changed the UI.

241
project_dashboard_odoo/models/pj_dashboard.py

@ -20,18 +20,56 @@
# #
############################################################################# #############################################################################
from odoo import models, api import calendar
import random
from datetime import datetime from datetime import datetime
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
import pandas as pd
import calendar from odoo import models, api
class PosDashboard(models.Model): class PosDashboard(models.Model):
"""
The ProjectDashboard class provides the data to the js when the dashboard is loaded.
Methods:
get_tiles_data(self):
when the page is loaded get the data from different models and transfer to the js file.
return a dictionary variable.
get_top_timesheet_employees(model_ids):
getting data for the timesheet graph.
get_hours_data(self):
getting data for the hours table.
get_task_data(self):
getting data to project task table
get_project_task_count(self):
getting data to project task table
get_color_code(self):
getting dynamic color code for the graph
get_income_this_month(self):
getting data to profitable graph after month filter apply
get_income_last_year(self):
getting data to profitable graph after last year filter apply
get_income_this_year(self):
getting data to profitable graph after current year filter apply
get_details(self):
getting data for the profatable table
"""
_inherit = 'project.project' _inherit = 'project.project'
@api.model @api.model
def get_tiles_data(self): def get_tiles_data(self):
"""
Summery:
when the page is loaded get the data from different models and transfer to the js file.
return a dictionary variable.
return:
type:It is a dictionary variable. This dictionary contain data that affecting the dashboard view.
"""
all_project = self.env['project.project'].search([]) all_project = self.env['project.project'].search([])
all_task = self.env['project.task'].search([]) all_task = self.env['project.task'].search([])
analytic_project = self.env['account.analytic.line'].search([]) analytic_project = self.env['account.analytic.line'].search([])
@ -48,18 +86,39 @@ class PosDashboard(models.Model):
('sale_order_id', '!=', False) ('sale_order_id', '!=', False)
], ['sale_order_id']) ], ['sale_order_id'])
task_so_ids = [o['sale_order_id'][0] for o in task] task_so_ids = [o['sale_order_id'][0] for o in task]
sale_orders = self.mapped('sale_line_id.order_id') | self.env['sale.order'].browse(task_so_ids) sale_orders = self.mapped('sale_line_id.order_id') | self.env[
'sale.order'].browse(task_so_ids)
sale_list = [rec.id for rec in sale_orders]
project_stage_ids = self.env['project.project.stage'].search([])
project_stage_list = []
for project_stage_id in project_stage_ids:
total_projects = self.env['project.project'].search_count(
[('stage_id', '=', project_stage_id.id)])
project_stage_list.append({
'name': project_stage_id.name,
'projects': total_projects,
})
return { return {
'total_projects': len(all_project), 'total_projects': len(all_project),
'total_tasks': len(all_task), 'total_tasks': len(all_task),
'total_hours': total_time, 'total_hours': total_time,
'total_profitability': profitability, 'total_profitability': profitability,
'total_employees': len(employees), 'total_employees': len(employees),
'total_sale_orders': len(sale_orders) 'total_sale_orders': len(sale_orders),
'project_stage_list': project_stage_list,
'sale_list': sale_list
} }
@api.model @api.model
def get_top_timesheet_employees(self): def get_top_timesheet_employees(self):
"""
Summery:
when the page is loaded get the data for the timesheet graph.
return:
type:It is a list. This list contain data that affecting the graph of employees.
"""
query = '''select hr_employee.name as employee,sum(unit_amount) as unit query = '''select hr_employee.name as employee,sum(unit_amount) as unit
from account_analytic_line from account_analytic_line
@ -80,80 +139,19 @@ class PosDashboard(models.Model):
return final return final
@api.model @api.model
def get_project_task(self): def get_details(self):
cr = self._cr """
cr.execute("""select project_id, project_project.name,count(*)
from project_task join project_project on project_project.id=project_task.project_id
group by project_task.project_id,project_project.name""")
dat = cr.fetchall()
data = []
for i in range(0, len(dat)):
data.append({'label': dat[i][1], 'value': dat[i][2]})
return data
@api.model
def project_profitability_trend(self):
leave_lines = []
month_list = []
graph_result = []
for i in range(6, -2, -1):
last_month = datetime.now() - relativedelta(months=i)
text = format(last_month, '%B %Y')
month_list.append(text)
for month in month_list:
vals = {
'l_month': month,
'leave': 0
}
graph_result.append(vals)
sql = """SELECT h.id,h.margin,
to_char(y, 'YYYY') as month_year
FROM (select * from project_profitability_report) h
,date_trunc('year', line_date)y"""
self.env.cr.execute(sql)
results = self.env.cr.dictfetchall()
for line in results:
days = line['margin']
vals = {
'l_month': line['month_year'],
'days': days
}
leave_lines.append(vals)
if leave_lines:
df = pd.DataFrame(leave_lines)
rf = df.groupby(['l_month']).sum()
result_lines = rf.to_dict('index')
for line in result_lines:
match = list(graph_result)
if match:
match[0]['leave'] = result_lines[line]['days']
for result in graph_result:
result['l_month'] = result['l_month'].split(' ')[:1][0].strip()[:3] + " " + \
result['l_month'].split(' ')[1:2][0]
return graph_result
@api.model Summery:
def get_profitability_details(self): when the page is loaded get the data for the profitable table.
query = '''select sum(margin) as payment_details from project_profitability_report''' return:
self._cr.execute(query) type:It is a dictionary variable. This dictionary contain data
data = self._cr.dictfetchall() that profitable table.
payment_details = []
for record in data:
payment_details.append(record.get('payment_details'))
return { """
'payment_details': payment_details,
}
@api.model
def get_details(self):
query = '''select sum(amount_untaxed_invoiced) as invoiced, query = '''select sum(amount_untaxed_invoiced) as invoiced,
sum(amount_untaxed_to_invoice) as to_invoice,sum(timesheet_cost) as time_cost, sum(amount_untaxed_to_invoice) as to_invoice,sum(timesheet_cost) as
time_cost,
sum(expense_cost) as expen_cost, sum(expense_cost) as expen_cost,
sum(margin) as payment_details from project_profitability_report''' sum(margin) as payment_details from project_profitability_report'''
self._cr.execute(query) self._cr.execute(query)
@ -165,7 +163,7 @@ class PosDashboard(models.Model):
to_invoice = [] to_invoice = []
for record in data: for record in data:
to_invoice.append(record.get('to_invoice')) to_invoice.append(record.get('to_invoice'))
record.get('to_invoice')
time_cost = [] time_cost = []
for record in data: for record in data:
time_cost.append(record.get('time_cost')) time_cost.append(record.get('time_cost'))
@ -177,7 +175,6 @@ class PosDashboard(models.Model):
payment_details = [] payment_details = []
for record in data: for record in data:
payment_details.append(record.get('payment_details')) payment_details.append(record.get('payment_details'))
return { return {
'invoiced': invoiced, 'invoiced': invoiced,
'to_invoice': to_invoice, 'to_invoice': to_invoice,
@ -188,6 +185,14 @@ class PosDashboard(models.Model):
@api.model @api.model
def get_hours_data(self): def get_hours_data(self):
"""
Summery:
when the page is loaded get the data for the hours table.
return:
type:It is a dictionary variable. This dictionary contain data that hours table.
"""
query = '''SELECT sum(unit_amount) as hour_recorded FROM account_analytic_line query = '''SELECT sum(unit_amount) as hour_recorded FROM account_analytic_line
WHERE timesheet_invoice_type='non_billable_project' ''' WHERE timesheet_invoice_type='non_billable_project' '''
self._cr.execute(query) self._cr.execute(query)
@ -239,6 +244,14 @@ class PosDashboard(models.Model):
@api.model @api.model
def get_income_this_year(self): def get_income_this_year(self):
"""
Summery:
when the filter is applied get the data for the profitable graph.
return:
type:It is a dictionary variable. This dictionary contain data for profitable graph.
"""
month_list = [] month_list = []
for i in range(11, -1, -1): for i in range(11, -1, -1):
@ -256,7 +269,8 @@ class PosDashboard(models.Model):
records = [] records = []
for month in month_list: for month in month_list:
last_month_inc = list(filter(lambda m: m['month'].strip() == month, record)) last_month_inc = list(
filter(lambda m: m['month'].strip() == month, record))
if not last_month_inc: if not last_month_inc:
records.append({ records.append({
@ -283,6 +297,14 @@ class PosDashboard(models.Model):
@api.model @api.model
def get_income_last_year(self): def get_income_last_year(self):
"""
Summery:
when the filter is applied get the data for the profitable graph.
return:
type:It is a dictionary variable. This dictionary contain data for profitable graph.
"""
month_list = [] month_list = []
for i in range(11, -1, -1): for i in range(11, -1, -1):
l_month = datetime.now() - relativedelta(months=i) l_month = datetime.now() - relativedelta(months=i)
@ -290,7 +312,6 @@ class PosDashboard(models.Model):
month_list.append(text) month_list.append(text)
states_arg = "" states_arg = ""
self._cr.execute(('''select sum(margin) as income ,to_char(project_profitability_report.line_date, 'Month') self._cr.execute(('''select sum(margin) as income ,to_char(project_profitability_report.line_date, 'Month')
as month from project_profitability_report where as month from project_profitability_report where
Extract(year FROM project_profitability_report.line_date) = Extract(year FROM DATE(NOW())) -1 Extract(year FROM project_profitability_report.line_date) = Extract(year FROM DATE(NOW())) -1
@ -299,7 +320,8 @@ class PosDashboard(models.Model):
records = [] records = []
for month in month_list: for month in month_list:
last_month_inc = list(filter(lambda m: m['month'].strip() == month, record)) last_month_inc = list(
filter(lambda m: m['month'].strip() == month, record))
if not last_month_inc: if not last_month_inc:
records.append({ records.append({
'month': month, 'month': month,
@ -327,6 +349,14 @@ class PosDashboard(models.Model):
@api.model @api.model
def get_income_this_month(self): def get_income_this_month(self):
"""
Summery:
when the filter is applied get the data for the profitable graph.
return:
type:It is a dictionary variable. This dictionary contain data for profitable graph.
"""
states_arg = "" states_arg = ""
day_list = [] day_list = []
now = datetime.now() now = datetime.now()
@ -370,6 +400,15 @@ class PosDashboard(models.Model):
@api.model @api.model
def get_task_data(self): def get_task_data(self):
"""
Summery:
when the page is loaded get the data from different models and transfer to the js file.
return a dictionary variable.
return:
type:It is a dictionary variable. This dictionary contain data that affecting project task table.
"""
self._cr.execute('''select project_task.name as task_name,pro.name as project_name from project_task self._cr.execute('''select project_task.name as task_name,pro.name as project_name from project_task
Inner join project_project as pro on project_task.project_id = pro.id ORDER BY project_name ASC''') Inner join project_project as pro on project_task.project_id = pro.id ORDER BY project_name ASC''')
data = self._cr.fetchall() data = self._cr.fetchall()
@ -380,3 +419,43 @@ class PosDashboard(models.Model):
return { return {
'project': project_name 'project': project_name
} }
@api.model
def get_project_task_count(self):
"""
Summery:
when the page is loaded get the data from different models and transfer to the js file.
return a dictionary variable.
return:
type:It is a dictionary variable. This dictionary contain data for the project task graph.
"""
project_name = []
total_task = []
colors = []
project_ids = self.env['project.project'].search([])
for project_id in project_ids:
project_name.append(project_id.name)
task = self.env['project.task'].search_count(
[('project_id', '=', project_id.id)])
total_task.append(task)
color_code = self.get_color_code()
colors.append(color_code)
return {
'project': project_name,
'task': total_task,
'color': colors
}
def get_color_code(self):
"""
Summery:
the function is for creating the dynamic color code.
return:
type:variable containing color code.
"""
color = "#{:06x}".format(random.randint(0, 0xFFFFFF))
return color

BIN
project_dashboard_odoo/static/description/assets/screenshots/Screenshot1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 KiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/Screenshot2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/Screenshot3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/Screenshot4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/Screenshot5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/Screenshot6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/checked.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/hero.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 5.8 MiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/hero.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/pd1.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/pd2.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/pd3.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/pd4.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/pd5.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/prg_db.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/prg_db2.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/prg_db3.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/prg_db4.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

BIN
project_dashboard_odoo/static/description/assets/screenshots/screenshot.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

45
project_dashboard_odoo/static/description/index.html

@ -186,31 +186,39 @@
<div class="col-lg-12 my-2"> <div class="col-lg-12 my-2">
<h4 class="mt-2" <h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Project Details</h4> Use DIffrent Type of filters<h4>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"></p>
<img src="assets/screenshots/screenshot.png" class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Dynamic And Clickable Dashboard Tiles</h4>
<p <p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
Display the Project related information likes Total Project, Total Employees, Total Tasks, User can click the Tiles and States in tile,That shows the detailed view of corresponding tiles.</p>
Hours Recorded, Total Profitability, Total Sale Orders.</p> <img src="assets/screenshots/Screenshot1.png" class="img-responsive img-thumbnail border" width="100%"
<img src="assets/screenshots/pd1.png" class="img-responsive img-thumbnail border" width="100%"
height="auto"/> height="auto"/>
</div> </div>
<div class="col-lg-12 my-3"> <div class="col-lg-12 my-3">
<h4 class="mt-3" <h4 class="mt-3"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Task Analysis</h4> Different Types of Graphs</h4>
<p <p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
Task analysis from various projects. </p> Project dashboard have different types of graphs that will give you complete analyse of the project module. </p>
<img src="assets/screenshots/pd2.png" class="img-responsive img-thumbnail border" width="100%" <img src="assets/screenshots/Screenshot2.png" class="img-responsive img-thumbnail border" width="100%"
height="auto"/> height="auto"/>
</div> </div>
<div class="col-lg-12 my-3"> <div class="col-lg-12 my-3">
<h4 class="mt-3" <h4 class="mt-3"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Employees Timesheet</h4> Employees Timesheet Graphh</h4>
<img src="assets/screenshots/pd3.png" class="img-responsive img-thumbnail border" width="100%" <img src="assets/screenshots/Screenshot3.png" class="img-responsive img-thumbnail border" width="100%"
height="auto"/> height="auto"/>
</div> </div>
@ -218,11 +226,24 @@
<div class="col-lg-12 my-3"> <div class="col-lg-12 my-3">
<h4 class="mt-3" <h4 class="mt-3"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Project Profitability</h4> Project Profitability Graph</h4>
<img src="assets/screenshots/pd4.png" class="img-responsive img-thumbnail border" width="100%" <img src="assets/screenshots/Screenshot4.png" class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-3">
<h4 class="mt-3"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Diffrent Type Of Tables</h4>
<img src="assets/screenshots/Screenshot5.png" class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-3">
<h4 class="mt-3"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
</h4>
<img src="assets/screenshots/Screenshot6.png" class="img-responsive img-thumbnail border" width="100%"
height="auto"/> height="auto"/>
</div> </div>
</div> </div>
<!-- SUGGESTED PRODUCTS --> <!-- SUGGESTED PRODUCTS -->

831
project_dashboard_odoo/static/src/css/dashboard.css

@ -13,28 +13,6 @@ overflow: auto !important;
.breadcrumbs { .breadcrumbs {
margin-top: 0; margin-top: 0;
} }
.buttons button {
margin: 2px 0; }
/* Button Reset */
.btn, .button {
display: inline-block;
font-weight: 400;
text-align: center;
white-space: nowrap;
vertical-align: middle;
transition: all .15s ease-in-out;
border-radius: 0;
cursor: pointer; }
/* Widget One
---------------------------*/
.stat-content {
display: inline-block;
width: 66%;
}
.stat-icon{ .stat-icon{
display: inline-block; display: inline-block;
} }
@ -67,120 +45,6 @@ overflow: auto !important;
.stat_count { .stat_count {
font-size: 28px !important; font-size: 28px !important;
} }
.stat-count {
font-size: 28px;
text-align: center;
color: #00438b;}
.stat-title {
font-size: 17px;
text-align: center;
color: #00438b; }
.mb-0{
font-size: 20px;
position: relative;
text-align: center;
}
.mb-0 .dash-title {
font-size: 20px;
text-align: center;
color: rgba(255, 255, 255, 0.81);
}
.hr_birthday {
font-size: 28px;
text-align: center;
padding: 20px 0;
color: #00438b;
font-weight: 600;
}
body .text-color {
color: #00438b;
}
.slice {
stroke: #fff;
stroke-width: 0px;
}
/* Leave graph */
path { stroke: #fff; }
path:hover { opacity:0.9; }
rect:hover { fill:#934da5; }
.axis { font: 10px sans-serif; }
.legend tr{ border-bottom:1px solid grey; }
.legend tr:first-child{ border-top:1px solid grey; }
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path { display: none; }
.legend{
border-collapse: collapse;
border-spacing: 0px;
display: inline-block;
}
.monthly_leave_graph_view .legend{
height: 250px;
overflow: scroll;
margin-left: 112px;
margin-top: 77px;
margin-bottom: -97px
}
.legend td, .legend .legend_col{
padding:4px 5px;
vertical-align:bottom;
}
.legendFreq, .legendPerc{
align:right;
width:50px;
}
/* Leave broadfactor graph */
.broad_factor_graph .axis path,
.broad_factor_graph .axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.broad_factor_graph .axis text {
font-family: sans-serif;
font-size: 11px;
}
.broad_factor_graph rect {
-moz-transition: all 0.3s;
-webkit-transition: all 0.3s;
-o-transition: all 0.3s;
transition: all 0.3s;
}
.broad_factor_graph rect:hover{
fill: #ff618a;
}
#broad_factor_pdf {
background-color: #ffffff;
border: 0;
color : #000000;
float: right;
}
#broad_factor_pdf i {
color: red;
}
.leave_broad_factor{
overflow-x: auto !important;
overflow-y: hidden !important;
height: auto;
}
/*=====================New Dashboard===========================*/
.oh_dashboards { .oh_dashboards {
background-color: #f8faff !important; background-color: #f8faff !important;
@ -190,25 +54,6 @@ rect:hover { fill:#934da5; }
.container-fluid.o_hr_dashboard { .container-fluid.o_hr_dashboard {
padding: 0px !important; padding: 0px !important;
} }
.employee-prof {
padding: 0px;
height: 100%;
background-color: #3e6282;
/*background-image: linear-gradient(180deg, #3e6282, #41666f);*/
position: fixed;
/*z-index: 999;*/
}
.employee-prof .oh-card:hover {
transform:none !important;
box-shadow: none !important;
}
/*.dummy{
height:130vh;
}*/
.oh-card { .oh-card {
padding-top: 0px; padding-top: 0px;
@ -227,116 +72,6 @@ rect:hover { fill:#934da5; }
box-shadow: 0 10px 10px 0 rgba(62, 57, 107, 0.12), 0 0 0 transparent !important; box-shadow: 0 10px 10px 0 rgba(62, 57, 107, 0.12), 0 0 0 transparent !important;
} }
.employee-prof .employee-icon {
float: left;
padding-right: 0px;
width: 100%;
height: 185px;
overflow: hidden;
background: #999999;
}
.employee-prof .employee-icon img{
width: 100%;
background: #fff;
}
.employee-prof .employee-name h2 {
text-align: center;
font-weight: 300;
text-transform: uppercase;
font-size: 17px;
margin-top: 12px;
margin-bottom: 2px;
color: #fff;
}
.media-body.employee-name {
background: #466b8d;
float: left;
margin: 0;
width: 100%
}
.employee-prof .employee-name p {
margin: 0 0 9px;
text-align: center;
font-size: 12px;
color: #f3f3f3;
}
.employee-prof p {
margin: 0 0 9px;
color: #fff;
}
.employee-gender {
width: 40%;
margin-left: 10%;
padding: 8% 10% 4%;
text-align: center;
border-right: 1px solid #4d769b;
margin-top: 14%;
float: left;
border-bottom: 1px solid #4d769b;
}
.employee-gender p {
margin: 0px 0 4px !important;
color: #fff;
}
.employee-age {
width: 40%;
margin-right: 10%;
padding: 4% 10% 7%;
text-align: center;
margin-top: 18%;
float: left;
border-bottom: 1px solid #4d769b;
}
.employee-age p {
margin: 0 0 1px;
color: #fff;
}
.employee-experience {
width: 100%;
text-align: center;
padding-top: 8%;
float: left;
padding-bottom: 3%;
}
.employee-country {
width: 40%;
margin-left: 10%;
padding: 9% 0% 4%;
text-align: center;
border-right: 1px solid #4d769b;
margin-top: 2%;
float: left;
border-top: 1px solid #4d769b;
}
.employee-country p {
margin: 0px 0 1px !important;
color: #fff;
}
.employee-mobile {
width: 40%;
margin-right: 10%;
padding: 9% 0% 7%;
text-align: center;
margin-top: 2%;
float: left;
border-top: 1px solid #4d769b;
}
.employee-mobile p {
margin: 0 0 1px;
color: #fff;
}
.oh-payslip { .oh-payslip {
margin-top: 1.5%; margin-top: 1.5%;
@ -348,7 +83,6 @@ rect:hover { fill:#934da5; }
height: 85px; height: 85px;
text-align: center; text-align: center;
padding-top: 2%; padding-top: 2%;
background: #ff8762;
color: #fff; color: #fff;
} }
@ -362,7 +96,6 @@ rect:hover { fill:#934da5; }
.stat-widget-one .stat-text { .stat-widget-one .stat-text {
font-size: 14px; font-size: 14px;
color: #ff8762;
margin-top: 2.3rem; margin-top: 2.3rem;
margin-left: 1rem; margin-left: 1rem;
@ -380,7 +113,7 @@ rect:hover { fill:#934da5; }
font-size: 42px; font-size: 42px;
font-weight: 900; font-weight: 900;
display: inline-block; display: inline-block;
color: #fff; color: #000;
top: 16px; top: 16px;
position: relative; position: relative;
} }
@ -401,147 +134,7 @@ rect:hover { fill:#934da5; }
padding-top: 2%; padding-top: 2%;
} }
.oh-timesheets .stat-icon{
background: #5ebade !important;
}
.oh-contracts .stat-icon{
background: #b298e1 !important;
}
.oh-broad-factor .stat-icon{
background: #70cac1 !important;
}
.oh-timesheets .stat-widget-one .stat-text {
color: #5ebade;
}
.oh-contracts .stat-widget-one .stat-text {
color: #b298e1;
}
.oh-broad-factor .stat-widget-one .stat-text {
color: #70cac1;
}
.leave-manager {
background-color: #fff;
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
padding: 0px;
margin: 15px;
}
.hr_leave_request_approve {
padding: 0;
padding-bottom: 0em;
padding-top: 0em;
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
}
.leaves_request_month {
padding: 0;
padding-top: 0px;
padding-bottom: 0px;
padding-bottom: 0em;
padding-top: 0em;
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
border-bottom: 1px solid #f1f1f133;
}
.leaves_request_today{
padding: 0;
padding-bottom: 0em;
padding-top: 0em;
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
}
.hr_leave_request_approve:hover, .leaves_request_month:hover, .leaves_request_today:hover{
transform: translateY(-2px) translateZ(0) !important;
box-shadow: 0 10px 10px 0 rgba(62, 57, 107, 0.12), 0 0 0 transparent !important;
}
.hr_leave_request_approve p {
font-size: 14px;
color: #ff8762;
margin-left: 1rem;
margin-bottom: 0px;
text-align: left;
width: 64%;
font-weight: bold;
float: left;
text-align: center !important;
}
.leaves_request_today p {
font-size: 14px;
color: #5ebade;
margin-left: 1rem;
margin-bottom: 0px;
text-align: left;
width:64%;
float:left;
font-weight: bold;
text-align: center;
text-align: center !important;
}
.leaves_request_month p{
font-size: 14px;
color: #b298e1;
margin-left: 1rem;
margin-bottom:0px;
text-align: left;
width:64%;
float:left;
font-weight: bold;
text-align: center !important;
}
h4 .stat-count {
font-size: 17px;
text-align: center;
color: #000 !important;
margin-top: 0px;
width: 100%;
float: left;
margin: 0;
}
.leave-manager h4 {
float: left;
width: 23%;
}
.hr_leave_request_approve h4 {
padding: 5.2rem 0;
margin: 0;
background: #ff8762;
color: #fff;
}
.leaves_request_today h4 {
padding: 2.2rem 0;
margin: 0 !important;
background: #5ebade;
color: #fff;
}
.leaves_request_month h4 {
padding: 2.1rem 0;
margin: 0 !important;
background: #b298e1;
color: #fff;
}
.leaves_request_today h4 .stat-count ,.leaves_request_month h4 .stat-count , .hr_leave_request_approve h4 .stat-count
{
color:#fff !important;
}
.graph_view .legend {
margin-bottom: -79px !important;
display: inline-block;
border-collapse: collapse;
border-spacing: 0px;
margin-left: 90px !important;
margin-top: 77px !important;
}
.hr-chart-1{ .hr-chart-1{
margin: 15px 0px; margin: 15px 0px;
background: #fff; background: #fff;
@ -568,223 +161,12 @@ h4 .stat-count {
padding-bottom: 65px; padding-bottom: 65px;
text-align: center !important; text-align: center !important;
} }
.hr_leave_allocations_approve p {
font-size: 14px;
color: #ff8762;
margin-left: 1rem;
margin-bottom: 0px;
text-align: left;
width: 70%;
float: left;
font-weight: bold;
text-align: center !important;
}
.hr_leave_allocations_approve h4 {
padding: 2.5rem 0;
margin: 0;
background: #ff8762;
color: #fff;
width: 26%;
float: left;
}
.hr_leave_allocations_approve .stat-count {
font-size: 17px;
text-align: center;
color: #fff !important;
margin-top: 0px;
width: 100%;
float: left;
margin: 0;
}
.hr_leave_allocations_approve {
padding: 0;
padding-top: 0px;
padding-bottom: 0px;
padding-bottom: 0em;
padding-top: 0em;
box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
background: #fff;
height: 80px;
}
.hr_leave_allocations_approve:hover{
transform: translateY(-2px) translateZ(0) !important;
box-shadow: 0 10px 10px 0 rgba(62, 57, 107, 0.12), 0 0 0 transparent !important;
}
.leave-manager {
background-color: #fff;
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
padding: 0px;
margin: 15px;
margin-right: 15px;
margin-right: 0px;
width: 95% !important;
padding: 0;
}
.hr_job_application_approve {
padding: 0;
padding-top: 0px;
padding-bottom: 0px;
padding-top: 0px;
padding-bottom: 0px;
padding-top: 0px;
padding-bottom: 0px;
padding-bottom: 0em;
padding-top: 0em;
box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
background: #fff;
margin-top: 15px;
height: 80px;
}
.hr_job_application_approve p {
font-size: 14px;
color: #70cac1;
margin-left: 1rem;
margin-bottom: 0px;
text-align: left;
width: 70%;
float: left;
font-weight: bold;
text-align: center !important;
}
.hr_job_application_approve h4 {
padding: 2.5rem 0;
margin: 0;
background: #70cac1;
color: #fff;
width: 26%;
float: left;
}
.hr_job_application_approve .stat-count {
font-size: 17px !important;
color: #fff !important;
margin-top: 0px !important;
width: 100%;
float: left;
margin: 0;
margin: 0px !important;
text-align: center !important;
width: 100% !important;
}
.hr_job_application_approve:hover{
transform: translateY(-2px) translateZ(0) !important;
box-shadow: 0 10px 10px 0 rgba(62, 57, 107, 0.12), 0 0 0 transparent !important;
}
.hr_attendance_login .oh-card {
margin: 0;
margin-bottom: 0px;
margin-bottom: 0px;
background: #134c8a;
padding-bottom: 7px;
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
}
.hr_attendance_login .stat-widget-one {
background: none;
}
.hr_attendance_login .stat-widget-one .stat-icon {
text-align: center;
padding-top: 9px;
}
.hr_attendance_login .stat-content {
width: 100%;
color: #fff !important;
}
.hr_attendance_login .stat-widget-one .stat-text {
margin: 0;
text-align: center;
width: 100% !important;
padding: 0;
color: #fff;
}
.hr_attendance_login .stat-widget-one .stat-icon .fa {
font-size: 50px;
}
.hr_attendance_login .stat-widget-one .stat-icon .fa {
font-size: 50px;
margin: 0px;
box-shadow: none;
}
.hr_attendance_login {
margin-top: 1.5%;
}
.monthly_leave_graph_view .oh-card {
background: #fff;
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
padding: 15px;
}
.broad_factor_graph .oh-card {
padding: 15px !important;
background: #fff;
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
padding: 15px;
}
.leave_broad_factor {
overflow-x: auto !important;
overflow-y: hidden !important;
height: 336px;
padding: 0px;
padding-left: 0px;
}
#broad_factor_pdf {
background-color: #ffffff;
float: right;
border-radius: 30px;
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
border: 1px solid #4ec3b7;
color: #757575;
padding-top: 9px;
color: #4ec3b7;
}
#broad_factor_pdf:hover{
transform: translateY(-2px) translateZ(0) !important;
box-shadow: 0 10px 10px 0 rgba(62, 57, 107, 0.12), 0 0 0 transparent !important;
}
.hr_birthday {
font-size: 17px;
text-align: center;
padding: 20px 0;
color: #00438b;
font-weight: 300;
}
.hr_notification img {
width: 40px;
height: 40px;
border-radius: 100%;
}
.hr_notification { .hr_notification {
background: #fff; background: #fff;
transition: transform 0.2s ease, box-shadow 0.2s ease; transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow; will-change: transform, box-shadow;
box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06); box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
height: 316px; height: 757pxpx;
overflow-y: auto;
margin-bottom: 15px; margin-bottom: 15px;
} }
.hr_notification .media { .hr_notification .media {
@ -810,32 +192,6 @@ h4 .stat-count {
background: #5ebade; background: #5ebade;
margin-bottom: 9px; margin-bottom: 9px;
} }
.monthly_leave_trend .oh-card{
background: #fff;
transition: none !important;
will-change: none !important;
box-shadow: none !important;
margin-bottom: 5px;
}
.monthly_leave_trend path {
stroke: #70cac1;
stroke-width: 2;
fill: none;
}
.monthly_leave_trend .axis path,
.monthly_leave_trend .axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
.monthly_leave_trend circle{
fill: #ffffff;
stroke: #44b7ac;
stroke-width: 1.5;
}
.hr-chart-1 { .hr-chart-1 {
margin: 15px 0px; margin: 15px 0px;
background: #fff; background: #fff;
@ -846,168 +202,57 @@ h4 .stat-count {
box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06); box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
padding-top: 3px !important; padding-top: 3px !important;
} }
.monthly_leave_trend { .row.main-section {
background: #fff; margin-right: 0px; !important;
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
}
.monthly_leave_trend:hover{
transform: translateY(-2px) translateZ(0) !important;
box-shadow: 0 10px 10px 0 rgba(62, 57, 107, 0.12), 0 0 0 transparent !important;
}
/*----------------------*/
.monthly_join_resign_trend{
padding-right: 0px !important;
}
.monthly_join_resign_trend .oh-card {
background: #fff;
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
padding: 15px;
}
.monthly_join_resign_trend .axis path,
.monthly_join_resign_trend .axis line {
fill: none;
shape-rendering: crispEdges;
}
.monthly_join_resign_trend .line {
fill: none;
stroke-width: 3px;
}
.monthly_join_resign_trend .area {
fill: steelblue;
opacity: 0.5;
}
.monthly_join_resign_trend .dot {
fill: steelblue;
stroke: steelblue;
stroke-width: 1.5px;
}
/*----------------------------------------*/
.monthly_attrition_rate path {
stroke: #70cac1;
stroke-width: 2;
fill: none;
}
.monthly_attrition_rate .axis path,
.monthly_attrition_rate .axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
.monthly_attrition_rate circle{
fill: #ffffff;
stroke: #44b7ac;
stroke-width: 1.5;
}
.monthly_attrition_rate .oh-card {
background: #fff;
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
padding: 15px;
} }
.monthly_attrition_rate .oh-card:hover{ .text-align {
transform: translateY(-2px) translateZ(0) !important; margin-left: 17px;
box-shadow: 0 10px 10px 0 rgba(62, 57, 107, 0.12), 0 0 0 transparent !important;
} }
.chart {
.row.main-section { width: 100% !important;
margin-right: 0px; !important; height: 400px !important;
} }
/* width */ .inner_select {
.hr_notification::-webkit-scrollbar { min-width: 150px
width: 4px;
} }
/* Track */ #table_status {
.hr_notification::-webkit-scrollbar-track { width: 90%;
background: #f1f1f1; margin-left: 5%;
font-family: Arial, Helvetica, sans-serif;
} }
/* Handle */ #table_status tr:nth-child(even) {
.hr_notification::-webkit-scrollbar-thumb { background-color: #f2f2f2;
background: #495057;;
} }
/* Handle on hover */ #table_status tr:hover {
.hr_notification::-webkit-scrollbar-thumb:hover { background-color: #ddd;
background: #598da1;
} }
.oh-card-body { .project-pill {
display: flex;
justify-content: space-between;
align-items: center; align-items: center;
} font-family: "Open Sans", Arial, Verdana, sans-serif;
.oh-ribbon {
position: absolute;
left: -5px; top: -5px;
z-index: 1;
overflow: hidden;
width: 150px; height: 150px;
text-align: right;
}
.oh-ribbon span {
font-size: 10px;
font-weight: bold; font-weight: bold;
color: #FFF; font-size: 11px;
text-transform: uppercase; display: inline-block;
text-align: center; height: 100%;
line-height: 20px; white-space: nowrap;
transform: rotate(-45deg); width: auto;
-webkit-transform: rotate(-45deg); position: relative;
width: 200px; border-radius: 100px;
display: block; line-height: 1;
background: #79A70A; overflow: hidden;
background: linear-gradient(#2989d8 0%, #1e5799 100%); padding: 0px 8px 0px 7px;
box-shadow: 0 3px 10px -5px rgba(0, 0, 0, 1); text-overflow: ellipsis;
position: absolute; line-height: 1.25rem;
top: 56px; color: #fff;
left: -35px; word-break: break-word;
} background: #0253e8;
.oh-ribbon span::before {
content: "";
position: absolute; left: 0px; top: 100%;
z-index: -1;
border-left: 3px solid #1e5799;
border-right: 3px solid transparent;
border-bottom: 3px solid transparent;
border-top: 3px solid #1e5799;
}
.oh-ribbon span::after {
content: "";
position: absolute; right: 0px; top: 100%;
z-index: -1;
border-left: 3px solid transparent;
border-right: 3px solid #1e5799;
border-bottom: 3px solid transparent;
border-top: 3px solid #1e5799;
}
.text-align {
margin-left: 17px;
} }
.chart { .inner_select p {
width: 100% !important; margin-left: 20px
height: 400px !important;
} }

439
project_dashboard_odoo/static/src/js/dashboard.js

@ -1,21 +1,24 @@
odoo.define('pj_dashboard.Dashboard', function (require) { odoo.define('pj_dashboard.Dashboard', function(require) {
"use strict"; "use strict";
var AbstractAction = require('web.AbstractAction'); var AbstractAction = require('web.AbstractAction');
var core = require('web.core'); var core = require('web.core');
var QWeb = core.qweb; var QWeb = core.qweb;
var ajax = require('web.ajax'); var ajax = require('web.ajax');
var rpc = require('web.rpc'); var rpc = require('web.rpc');
var _t = core._t; var _t = core._t;
var session = require('web.session'); var session = require('web.session');
var web_client = require('web.web_client'); var web_client = require('web.web_client');
var abstractView = require('web.AbstractView'); var abstractView = require('web.AbstractView');
var flag = 0;
var tot_so = []
var tot_project = []
var tot_task = []
var PjDashboard = AbstractAction.extend({ var tot_employee = []
template:'PjDashboard', var tot_hrs = []
var tot_margin = []
var PjDashboard = AbstractAction.extend({
template: 'PjDashboard',
cssLibs: [ cssLibs: [
'/project_dashboard_odoo/static/src/css/lib/nv.d3.css' '/project_dashboard_odoo/static/src/css/lib/nv.d3.css'
], ],
@ -24,21 +27,22 @@ var PjDashboard = AbstractAction.extend({
], ],
events: { events: {
'click .tot_projects':'tot_projects', 'click .tot_projects': 'tot_projects',
'click .tot_tasks':'tot_tasks', 'click .tot_tasks': 'tot_tasks',
'click .tot_profitability':'tot_profitability', 'click .tot_profitability': 'tot_profitability',
'click .hr_recorded':'hr_recorded', 'click .hr_recorded': 'hr_recorded',
'click .tot_sale':'tot_sale', 'click .tot_sale': 'tot_sale',
'click .tot_emp':'tot_emp', 'click .tot_emp': 'tot_emp',
'click #income_this_year': 'onclick_income_this_year', 'change #income_expense_values': 'onchange_profitability',
'click #income_last_year': 'onclick_income_last_year', 'change #start_date': '_onchangeFilter',
'click #income_this_month': 'onclick_income_this_month', 'change #end_date': '_onchangeFilter',
'change #employee_selection': '_onchangeFilter',
'change #project_selection': '_onchangeFilter',
}, },
init: function(parent, context) { init: function(parent, context) {
this._super(parent, context); this._super(parent, context);
this.dashboards_templates = ['DashboardProject','DashboardChart']; this.dashboards_templates = ['DashboardProject', 'DashboardChart'];
this.today_sale = []; this.today_sale = [];
}, },
@ -56,23 +60,70 @@ var PjDashboard = AbstractAction.extend({
return this._super().then(function() { return this._super().then(function() {
self.render_dashboards(); self.render_dashboards();
self.render_graphs(); self.render_graphs();
self.render_filter()
}); });
}, },
render_dashboards: function(){ render_dashboards: function() {
var self = this; var self = this;
_.each(this.dashboards_templates, function(template) { _.each(this.dashboards_templates, function(template) {
self.$('.o_pj_dashboard').append(QWeb.render(template, {widget: self})); self.$('.o_pj_dashboard').append(QWeb.render(template, {
widget: self
}));
}); });
}, },
render_filter: function() {
ajax.rpc('/project/filter').then(function(data) {
var projects = data[0]
var employees = data[1]
$(projects).each(function(project) {
$('#project_selection').append("<option value=" + projects[project].id + ">" + projects[project].name + "</option>");
});
$(employees).each(function(employee) {
$('#employee_selection').append("<option value=" + employees[employee].id + ">" + employees[employee].name + "</option>");
});
})
},
render_graphs: function() {
render_graphs: function(){
var self = this; var self = this;
self.render_project_task(); self.render_project_task();
self.render_top_employees_graph(); self.render_top_employees_graph();
self.income_this_year();
},
render_project_task: function() {
var self = this
rpc.query({
model: "project.project",
method: "get_project_task_count",
}).then(function(data) {
var ctx = self.$("#project_doughnut");
new Chart(ctx, {
type: "doughnut",
data: {
labels: data.project,
datasets: [{
backgroundColor: data.color,
data: data.task
}]
},
options: {
legend: {
position: 'left'
},
title: {
display: true,
position: "top",
text: " ProjectTask Analysis",
fontSize: 20,
fontColor: "#111"
},
cutoutPercentage: 40,
responsive: true,
}
});
})
}, },
on_reverse_breadcrumb: function() { on_reverse_breadcrumb: function() {
@ -84,65 +135,54 @@ var PjDashboard = AbstractAction.extend({
self.render_graphs(); self.render_graphs();
}); });
}, },
_onchangeFilter: function() {
// flag = 1
onclick_toggle_two: function(ev) { var start_date = $('#start_date').val();
this.onclick_income_this_year(ev); var end_date = $('#end_date').val();
this.onclick_income_last_year(ev); if (!start_date) {
this.onclick_income_this_month(ev); start_date = "null"
}, }
if (!end_date) {
end_date = "null"
}
var employee_selection = $('#employee_selection').val();
render_project_task:function(){ var project_selection = $('#project_selection').val();
var self = this; ajax.rpc('/project/filter-apply', {
var w = 400; 'data': {
var h = 400; 'start_date': start_date,
var r = h/2; 'end_date': end_date,
var elem = this.$('.emp_graph'); 'project': project_selection,
var colors = ['#70cac1', '#659d4e', '#208cc2', '#4d6cb1', '#584999', '#8e559e', '#cf3650', '#f65337', '#fe7139', 'employee': employee_selection
'#ffa433', '#ffc25b', '#f8e54b']; }
var color = d3.scale.ordinal().range(colors); }).then(function(data) {
rpc.query({ tot_hrs = data['list_hours_recorded']
model: "project.project", tot_employee = data['total_emp']
method: "get_project_task", tot_project = data['total_project']
}).then(function (data) { tot_task = data['total_task']
var segColor = {}; tot_so = data['total_so']
var vis = d3.select(elem[0]).append("svg:svg").data([data]).attr("width", w).attr("height", h).append("svg:g").attr("transform", "translate(" + r + "," + r + ")"); document.getElementById("tot_project").innerHTML = data['total_project'].length
var pie = d3.layout.pie().value(function(d){return d.value;}); document.getElementById("tot_employee").innerHTML = data['total_emp'].length
var arc = d3.svg.arc().outerRadius(r); document.getElementById("tot_task").innerHTML = data['total_task'].length
var arcs = vis.selectAll("g.slice").data(pie).enter().append("svg:g").attr("class", "slice"); document.getElementById("tot_hrs").innerHTML = data['hours_recorded']
arcs.append("svg:path") document.getElementById("tot_margin").innerHTML = data['total_margin']
.attr("fill", function(d, i){ document.getElementById("tot_so").innerHTML = data['total_so'].length
return color(i);
}) })
.attr("d", function (d) {
return arc(d);
});
var legend = d3.select(elem[0]).append("table").attr('class','legend');
var tr = legend.append("tbody").selectAll("tr").data(data).enter().append("tr");
tr.append("td").append("svg").attr("width", '16').attr("height", '16').append("rect")
.attr("width", '16').attr("height", '16')
.attr("fill",function(d, i){ return color(i) });
tr.append("td").text(function(d){ return d.label;});
tr.append("td").attr("class",'legendFreq')
.text(function(d){ return d.value;});
});
}, },
onchange_profitability: function(ev) {
var selected_filter = $('#income_expense_values').val()
//project var self = this
if (selected_filter == 'income_last_year') {
self.income_last_year(ev)
} else if (selected_filter == 'income_this_year') {
self.income_this_year(ev)
} else {
self.income_this_month(ev)
}
},
/**
for opening project view
*/
tot_projects: function(e) { tot_projects: function(e) {
var self = this; var self = this;
e.stopPropagation(); e.stopPropagation();
@ -150,17 +190,41 @@ var PjDashboard = AbstractAction.extend({
var options = { var options = {
on_reverse_breadcrumb: this.on_reverse_breadcrumb, on_reverse_breadcrumb: this.on_reverse_breadcrumb,
}; };
if (flag == 0) {
this.do_action({ this.do_action({
name: _t("Projects"), name: _t("Projects"),
type: 'ir.actions.act_window', type: 'ir.actions.act_window',
res_model: 'project.project', res_model: 'project.project',
view_mode: 'kanban,form', view_mode: 'kanban,form',
views: [[false, 'list'],[false, 'form']], views: [
[false, 'kanban'],
[false, 'form']
],
target: 'current' target: 'current'
}, options) }, options)
} else {
if (tot_project) {
this.do_action({
name: _t("Projects"),
type: 'ir.actions.act_window',
res_model: 'project.project',
domain: [
["id", "in", tot_project]
],
view_mode: 'kanban,form',
views: [
[false, 'kanban'],
[false, 'form']
],
target: 'current'
}, options)
}
}
}, },
//task /**
for opening project task view
*/
tot_tasks: function(e) { tot_tasks: function(e) {
var self = this; var self = this;
e.stopPropagation(); e.stopPropagation();
@ -168,17 +232,41 @@ var PjDashboard = AbstractAction.extend({
var options = { var options = {
on_reverse_breadcrumb: this.on_reverse_breadcrumb, on_reverse_breadcrumb: this.on_reverse_breadcrumb,
}; };
if (flag == 0) {
this.do_action({ this.do_action({
name: _t("Tasks"), name: _t("Tasks"),
type: 'ir.actions.act_window', type: 'ir.actions.act_window',
res_model: 'project.task', res_model: 'project.task',
view_mode: 'tree,kanban,form', view_mode: 'tree,kanban,form',
views: [[false, 'list'],[false, 'form']], views: [
[false, 'list'],
[false, 'form']
],
target: 'current' target: 'current'
}, options) }, options)
} else {
if (tot_task) {
this.do_action({
name: _t("Tasks"),
type: 'ir.actions.act_window',
res_model: 'project.task',
domain: [
["id", "in", tot_task]
],
view_mode: 'tree,kanban,form',
views: [
[false, 'list'],
[false, 'form']
],
target: 'current'
}, options)
}
}
}, },
//task /**
for opening margin view
*/
tot_profitability: function(e) { tot_profitability: function(e) {
var self = this; var self = this;
e.stopPropagation(); e.stopPropagation();
@ -189,15 +277,19 @@ var PjDashboard = AbstractAction.extend({
this.do_action({ this.do_action({
name: _t("Profitability"), name: _t("Profitability"),
type: 'ir.actions.act_window', type: 'ir.actions.act_window',
res_model: 'project.profitability.report', res_model: 'project.project',
view_mode: 'pivot', view_mode: 'pivot',
views: [[false, 'pivot'],[false, 'graph']], views: [
[false, 'pivot'],
[false, 'graph']
],
target: 'current' target: 'current'
}, options) }, options)
}, },
//hr timesheets /**
for opening account analytic line view
*/
hr_recorded: function(e) { hr_recorded: function(e) {
var self = this; var self = this;
e.stopPropagation(); e.stopPropagation();
@ -205,17 +297,39 @@ var PjDashboard = AbstractAction.extend({
var options = { var options = {
on_reverse_breadcrumb: this.on_reverse_breadcrumb, on_reverse_breadcrumb: this.on_reverse_breadcrumb,
}; };
if (flag == 0) {
this.do_action({ this.do_action({
name: _t("Timesheets"), name: _t("Timesheets"),
type: 'ir.actions.act_window', type: 'ir.actions.act_window',
res_model: 'account.analytic.line', res_model: 'account.analytic.line',
view_mode: 'tree,form', view_mode: 'tree,form',
views: [[false, 'list']], views: [
[false, 'list']
],
target: 'current'
}, options)
} else {
if (tot_hrs) {
this.do_action({
name: _t("Timesheets"),
type: 'ir.actions.act_window',
res_model: 'account.analytic.line',
domain: [
["id", "in", tot_hrs]
],
view_mode: 'tree,form',
views: [
[false, 'list']
],
target: 'current' target: 'current'
}, options) }, options)
}
}
}, },
//total saleorder /**
for opening sale order view
*/
tot_sale: function(e) { tot_sale: function(e) {
var self = this; var self = this;
@ -224,19 +338,42 @@ var PjDashboard = AbstractAction.extend({
var options = { var options = {
on_reverse_breadcrumb: this.on_reverse_breadcrumb, on_reverse_breadcrumb: this.on_reverse_breadcrumb,
}; };
if (flag == 0) {
this.do_action({ this.do_action({
name: _t("Sale Order"), name: _t("Sale Order"),
type: 'ir.actions.act_window', type: 'ir.actions.act_window',
res_model: 'sale.order', res_model: 'sale.order',
view_mode: 'tree', view_mode: 'tree',
views: [[false, 'list']], views: [
domain: [['analytic_account_id', '!=',self.analytic_account_id ]], [false, 'list']
],
domain: [
["id", "in", tot_so]
],
target: 'current' target: 'current'
}, options) }, options)
} else {
if (tot_so) {
this.do_action({
name: _t("Sale Order"),
type: 'ir.actions.act_window',
res_model: 'sale.order',
domain: [
["id", "in", tot_so]
],
view_mode: 'tree',
views: [
[false, 'list']
],
target: 'current'
}, options)
}
}
}, },
//total emp /**
for opening hr employee view
*/
tot_emp: function(e) { tot_emp: function(e) {
var self = this; var self = this;
e.stopPropagation(); e.stopPropagation();
@ -244,36 +381,52 @@ var PjDashboard = AbstractAction.extend({
var options = { var options = {
on_reverse_breadcrumb: this.on_reverse_breadcrumb, on_reverse_breadcrumb: this.on_reverse_breadcrumb,
}; };
if (flag == 0) {
this.do_action({ this.do_action({
name: _t("Employees"), name: _t("Employees"),
type: 'ir.actions.act_window', type: 'ir.actions.act_window',
res_model: 'hr.employee', res_model: 'hr.employee',
view_mode: 'tree,form', view_mode: 'tree,form',
views: [[false, 'list'],[false, 'form']], views: [
[false, 'list'],
[false, 'form']
],
target: 'current'
}, options)
} else {
this.do_action({
name: _t("Employees"),
type: 'ir.actions.act_window',
res_model: 'hr.employee',
domain: [
["id", "in", tot_employee]
],
view_mode: 'tree,form',
views: [
[false, 'list'],
[false, 'form']
],
target: 'current' target: 'current'
}, options) }, options)
},
}
},
render_top_employees_graph:function(){ render_top_employees_graph: function() {
console.log('hhhh')
var self = this var self = this
console.log('bbb')
var ctx = self.$(".top_selling_employees"); var ctx = self.$(".top_selling_employees");
console.log('vvv',ctx)
rpc.query({ rpc.query({
model: "project.project", model: "project.project",
method: 'get_top_timesheet_employees', method: 'get_top_timesheet_employees',
}).then(function (arrays) { }).then(function(arrays) {
var data = { var data = {
labels: arrays[1], labels: arrays[1],
datasets: [ datasets: [{
{
label: "Hours Spent", label: "Hours Spent",
data: arrays[0], data: arrays[0],
backgroundColor: [ backgroundColor: [
@ -305,7 +458,6 @@ var PjDashboard = AbstractAction.extend({
] ]
}; };
console.log(data)
//options //options
var options = { var options = {
@ -317,14 +469,6 @@ var PjDashboard = AbstractAction.extend({
fontSize: 18, fontSize: 18,
fontColor: "#111" fontColor: "#111"
}, },
legend: {
display: true,
position: "bottom",
labels: {
fontColor: "#333",
fontSize: 16
}
},
scales: { scales: {
yAxes: [{ yAxes: [{
ticks: { ticks: {
@ -333,7 +477,6 @@ var PjDashboard = AbstractAction.extend({
}] }]
} }
}; };
console.log('lllll',data)
//create Chart class object //create Chart class object
var chart = new Chart(ctx, { var chart = new Chart(ctx, {
type: 'bar', type: 'bar',
@ -344,7 +487,7 @@ var PjDashboard = AbstractAction.extend({
}); });
}, },
onclick_income_last_year: function(ev) { income_last_year: function(ev) {
ev.preventDefault(); ev.preventDefault();
var selected = $('.btn.btn-tool.income'); var selected = $('.btn.btn-tool.income');
var data = $(selected[0]).data(); var data = $(selected[0]).data();
@ -356,7 +499,6 @@ var PjDashboard = AbstractAction.extend({
args: [], args: [],
}) })
.then(function(result) { .then(function(result) {
$('#net_profit_current_months').hide(); $('#net_profit_current_months').hide();
$('#net_profit_last_year').show(); $('#net_profit_last_year').show();
$('#net_profit_this_year').hide(); $('#net_profit_this_year').hide();
@ -378,8 +520,7 @@ var PjDashboard = AbstractAction.extend({
type: 'bar', type: 'bar',
data: { data: {
labels: labels, labels: labels,
datasets: [ datasets: [{
{
label: 'Profitability', // Name the series label: 'Profitability', // Name the series
data: profit, // Specify the data values array data: profit, // Specify the data values array
backgroundColor: '#0bd465', backgroundColor: '#0bd465',
@ -388,8 +529,7 @@ var PjDashboard = AbstractAction.extend({
borderWidth: 1, // Specify bar border width borderWidth: 1, // Specify bar border width
type: 'line', // Set this data to a line chart type: 'line', // Set this data to a line chart
fill: false fill: false
} }]
]
}, },
options: { options: {
responsive: true, // Instruct chart js to respond nicely. responsive: true, // Instruct chart js to respond nicely.
@ -400,8 +540,7 @@ var PjDashboard = AbstractAction.extend({
}) })
}, },
onclick_income_this_year: function(ev) { income_this_year: function() {
ev.preventDefault();
var selected = $('.btn.btn-tool.income'); var selected = $('.btn.btn-tool.income');
var data = $(selected[0]).data(); var data = $(selected[0]).data();
var posted = false; var posted = false;
@ -414,15 +553,11 @@ var PjDashboard = AbstractAction.extend({
}) })
.then(function(result) { .then(function(result) {
$('#net_profit_current_months').hide();
$('#net_profit_last_year').hide();
$('#net_profit_this_year').show();
var ctx = document.getElementById("canvas").getContext('2d'); var ctx = document.getElementById("canvas").getContext('2d');
// Define the data // Define the data
var income = result.income; // Add data values to array var income = result.income; // Add data values to array
// var expense = result.expense; // var expense = result.expense;
var profit = result.profit; var profit = result.profit;
var labels = result.month; // Add labels to array var labels = result.month; // Add labels to array
@ -435,8 +570,7 @@ var PjDashboard = AbstractAction.extend({
type: 'bar', type: 'bar',
data: { data: {
labels: labels, labels: labels,
datasets: [ datasets: [{
{
label: 'Profitability', // Name the series label: 'Profitability', // Name the series
data: profit, // Specify the data values array data: profit, // Specify the data values array
backgroundColor: '#0bd465', backgroundColor: '#0bd465',
@ -445,8 +579,7 @@ var PjDashboard = AbstractAction.extend({
borderWidth: 1, // Specify bar border width borderWidth: 1, // Specify bar border width
type: 'line', // Set this data to a line chart type: 'line', // Set this data to a line chart
fill: false fill: false
} }]
]
}, },
options: { options: {
responsive: true, // Instruct chart js to respond nicely. responsive: true, // Instruct chart js to respond nicely.
@ -457,7 +590,8 @@ var PjDashboard = AbstractAction.extend({
}) })
}, },
onclick_income_this_month: function(ev) { income_this_month: function(ev) {
ev.preventDefault(); ev.preventDefault();
var selected = $('.btn.btn-tool.income'); var selected = $('.btn.btn-tool.income');
var data = $(selected[0]).data(); var data = $(selected[0]).data();
@ -517,21 +651,21 @@ var PjDashboard = AbstractAction.extend({
var def1 = this._rpc({ var def1 = this._rpc({
model: 'project.project', model: 'project.project',
method: 'get_tiles_data' method: 'get_tiles_data'
}).then(function(result) }).then(function(result) {
{
self.total_projects = result['total_projects'], self.total_projects = result['total_projects'],
self.total_tasks = result['total_tasks'], self.total_tasks = result['total_tasks'],
self.total_hours = result['total_hours'], self.total_hours = result['total_hours'],
self.total_profitability = result['total_profitability'], self.total_profitability = result['total_profitability'],
self.total_employees = result['total_employees'], self.total_employees = result['total_employees'],
self.total_sale_orders = result['total_sale_orders'] self.total_sale_orders = result['total_sale_orders'],
self.project_stage_list = result['project_stage_list']
tot_so = result['sale_list']
}); });
var def2 = self._rpc({ var def2 = self._rpc({
model: "project.project", model: "project.project",
method: "get_details", method: "get_details",
}) })
.then(function (res) { .then(function(res) {
self.invoiced = res['invoiced']; self.invoiced = res['invoiced'];
self.to_invoice = res['to_invoice']; self.to_invoice = res['to_invoice'];
self.time_cost = res['time_cost']; self.time_cost = res['time_cost'];
@ -542,7 +676,7 @@ var PjDashboard = AbstractAction.extend({
model: "project.project", model: "project.project",
method: "get_hours_data", method: "get_hours_data",
}) })
.then(function (res) { .then(function(res) {
self.hour_recorded = res['hour_recorded']; self.hour_recorded = res['hour_recorded'];
self.hour_recorde = res['hour_recorde']; self.hour_recorde = res['hour_recorde'];
self.billable_fix = res['billable_fix']; self.billable_fix = res['billable_fix'];
@ -554,19 +688,18 @@ var PjDashboard = AbstractAction.extend({
model: "project.project", model: "project.project",
method: "get_task_data", method: "get_task_data",
}) })
.then(function (res) { .then(function(res) {
self.task_data = res['project']; self.task_data = res['project'];
}); });
return $.when(def1,def2,def3,def4); return $.when(def1, def2, def3, def4);
}, },
}); });
core.action_registry.add('project_dashboard', PjDashboard); core.action_registry.add('project_dashboard', PjDashboard);
return PjDashboard; return PjDashboard;
}); });

279
project_dashboard_odoo/static/src/xml/dashboard.xml

@ -9,81 +9,105 @@
<t t-name="DashboardProject"> <t t-name="DashboardProject">
<div class="row main-section" style="margin-left: 170px;"> <div class="row main-section" style="margin-left: 170px;">
<div class="col-md-4 col-sm-6 tot_projects oh-payslip" > <div class="inner_select" style="display: flex;width:100%;">
<p style="margin-left: 20px;">Start Date :</p>
<p>
<input type="date" class="inner_select" id="start_date" name="start_date" />
</p>
<p>End Date :</p>
<p>
<input type="date" class="inner_select" id="end_date" name="end_date" />
</p>
<p>Project :</p>
<p>
<select class="inner_select" id="project_selection">
<option value="null">All Projects</option>
</select>
</p>
<p>Employees :</p>
<p>
<select class="inner_select" id="employee_selection">
<option value="null">All Employees</option>
</select>
</p>
</div>
</div>
<div class="row" style="margin-left: 4%;">
<div class="col-md-4 col-sm-6 tot_projects oh-payslip">
<div class="oh-card" style="width: 410px;"> <div class="oh-card" style="width: 410px;">
<div class="oh-card-body"> <div class="oh-card-body tot_projects" style="box-shadow:5px 11px 30px;">
<div class="stat-widget-one"> <div class="stat-widget-one" style="display:flex;">
<div class="stat-icon" style="background:#e08048;"><i class="fa fa-puzzle-piece"/></div> <div class="stat-icon"><i class="fa fa-puzzle-piece" /></div>
<div class="stat-content"> <div class="stat-head" style="padding: 5%;width: 60%;">Total Project</div>
<div class="stat-head">Total Project</div> <div class="stat_count" style="padding: 4%;width: 30%;" id="tot_project">
<div class="stat_count"><t t-esc="widget.total_projects"/></div> <t t-esc="widget.total_projects" />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-4 col-sm-6 tot_emp oh-payslip"> <div class="col-md-4 col-sm-6 oh-payslip">
<div class="oh-card" style="width: 410px;"> <div class="oh-card" style="width: 410px;">
<div class="oh-card-body"> <div class="oh-card-body tot_emp" style="box-shadow:5px 11px 30px;">
<div class="stat-widget-one"> <div class="stat-widget-one" style="display:flex;">
<div class="stat-icon" style="background:#645bd0"><i class="fa fa-user"/></div> <div class="stat-icon"><i class="fa fa-user" /></div>
<div class="stat-content"> <div class="stat-head" style="padding: 5%;width: 60%;">Total Employees</div>
<div class="stat-head">Total Employees</div> <div class="stat_count" style="padding: 4%;width: 30%;" id="tot_employee">
<div class="stat_count"><t t-esc="widget.total_employees"/></div> <t t-esc="widget.total_employees" />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-4 col-sm-6 tot_tasks oh-payslip"> <div class="col-md-4 col-sm-6 oh-payslip">
<div class="oh-card" style="width: 410px;"> <div class="oh-card" style="width: 410px;">
<div class="oh-card-body"> <div class="oh-card-body tot_tasks" style="box-shadow:5px 11px 30px;">
<div class="stat-widget-one"> <div class="stat-widget-one" style="display:flex;">
<div class="stat-icon" style="background:#85d05b"><i class="fa fa-tasks"/></div> <div class="stat-icon"><i class="fa fa-tasks" /></div>
<div class="stat-content"> <div class="stat-head" style="padding: 5%;width: 60%;">Total tasks</div>
<div class="stat-head">Total tasks</div> <div class="stat_count" style="padding: 4%;width: 30%;" id="tot_task">
<div class="stat_count"><t t-esc="widget.total_tasks"/></div> <t t-esc="widget.total_tasks" />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-4 col-sm-6 hr_recorded oh-payslip"> <div class="col-md-4 col-sm-6 oh-payslip">
<div class="oh-card" style="width: 410px;"> <div class="oh-card" style="width: 410px;">
<div class="oh-card-body"> <div class="oh-card-body hr_recorded" style="box-shadow:5px 11px 30px;">
<div class="stat-widget-one"> <div class="stat-widget-one" style="display:flex;">
<div class="stat-icon" style="background:#d05bb8"><i class="fa fa-clock-o"/></div> <div class="stat-icon"><i class="fa fa-clock-o" /></div>
<div class="stat-content"> <div class="stat-head" style="padding: 5%;width: 60%;">Hours Recorded</div>
<div class="stat-head">Hours Recorded</div> <div class="stat_count" style="padding: 4%;width: 30%;" id="tot_hrs">
<div class="stat_count"><t t-esc="widget.total_hours"/></div> <t t-esc="widget.total_hours" />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-4 col-sm-6 tot_profitability oh-payslip"> <div class="col-md-4 col-sm-6 oh-payslip">
<div class="oh-card" style="width: 410px;"> <div class="oh-card" style="width: 410px;">
<div class="oh-card-body"> <div class="oh-card-body tot_profitability" style="box-shadow:5px 11px 30px;">
<div class="stat-widget-one"> <div class="stat-widget-one" style="display:flex;">
<div class="stat-icon" style="background:#d0c35b"><i class="fa fa-dollar"/></div> <div class="stat-icon"><i class="fa fa-dollar" /></div>
<div class="stat-content"> <div class="stat-head" style="padding: 5%;width: 60%;">Total Profitability</div>
<div class="stat-head">Total Profitability</div> <div class="stat_count" style="padding: 4%;width: 30%;" id="tot_margin">
<div class="stat_count"><t t-esc="widget.total_profitability"/></div> <t t-esc="widget.total_profitability" />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-4 col-sm-6 tot_sale oh-payslip"> <div class="col-md-4 col-sm-6 oh-payslip">
<div class="oh-card" style="width: 410px;"> <div class="oh-card" style="width: 410px;">
<div class="oh-card-body"> <div class="oh-card-body tot_sale" style="box-shadow:5px 11px 30px;">
<div class="stat-widget-one"> <div class="stat-widget-one" style="display:flex;">
<div class="stat-icon" style="background:#5b8ed0"><i class="fa fa-ticket"/></div> <div class="stat-icon"><i class="fa fa-ticket" /></div>
<div class="stat-content"> <div class="stat-head" style="padding: 5%;width: 60%;">Total Sale Orders</div>
<div class="stat-head">Total Sale Orders</div> <div class="stat_count" style="padding: 4%;width: 30%;" id="tot_so">
<div class="stat_count"><t t-esc="widget.total_sale_orders"/></div> <t t-esc="widget.total_sale_orders" />
</div> </div>
</div> </div>
</div> </div>
@ -95,28 +119,57 @@
<t t-name="DashboardChart"> <t t-name="DashboardChart">
<div class="col-xs-12 col-sm-12 col-lg-12 col-md-12"> <div class="col-xs-12 col-sm-12 col-lg-12 col-md-12">
<div class="row main-section"> <div class="row main-section">
<div class="col-sm-7 col-lg-7"> <div class="col-sm-7 col-lg-7" style="margin-left: 2%;">
<div class="graph_view" style="padding:0"> <div class="graph_view" style="padding:0">
<div class="text-color hr-chart-1"> <div class="text-color hr-chart-1">
<div class="oh-card-body pb-0"> <canvas id="project_doughnut" style="background:#fff;" width="200" height="120" />
<h4 class="mb-0"/> </div>
<p class="stat-head" style="padding : 0px;">ProjectTask Analysis</p> </div>
<div class="selling_product_graph_view">
<div class="oh-card text-color" style="background-color:#fff;">
<canvas class="top_selling_employees" width="200" height="120" />
</div>
</div>
<div class="row" style="margin:0px">
<div class="col-md-12" id="col-graph">
<div class="card">
<div class="card-header">
<div class="card-title">
<b>
<h3 class="custom-h3">Profitability</h3>
</b>
</div>
<div class="card-tools">
<select id="income_expense_values">
<option id="income_this_year" value="income_this_year">This Year</option>
<option id="income_this_month" value="income_this_month">This Month</option>
<div role="separator" class="dropdown-divider" />
<option id="income_last_year" value="income_last_year">Last Year</option>
</select>
</div>
</div>
<div class="card-body mt-3" id="in_ex_body_hide">
<div class="row">
<p id="myelement1"> </p>
<div class="chart">
<canvas id="canvas" width="100% !important" height="auto !important"> </canvas>
</div>
</div>
</div>
</div> </div>
<div class="emp_graph"/>
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-4 col-lg-4" style="top: 82px;right: -100px;"> <div class="col-md-4 col-lg-4" style="top: 20px;right: -100px;">
<div class="hr_notification" style="background: #fff;transition: transform 0.2s ease, box-shadow 0.2s ease;will-change: transform, box-shadow;box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06); <div class="hr_notification" style="background: #fff;
height: 316px;overflow-y: auto;margin-bottom: 15px;"> height: 763px;margin-bottom: 15px;margin-top: 15px;box-shadow:5px 11px 30px;">
<div class="hr_notification_head" <div class="hr_notification_head" style="font-size: 17px;text-align: center;padding: 12px 0;color: #fff;font-weight: 300;background: #000080;margin-bottom: 9px;">
style="font-size: 17px;text-align: center;padding: 12px 0;color: #fff;font-weight: 300;background: #218a45a3;margin-bottom: 9px;"> Project Task Details
ProjectTask Details
</div> </div>
<div class="col-sm-12 col-lg-12" style="padding:0;"> <div class="col-sm-12 col-lg-12" style="padding:0;">
<div class="text-color"> <div class="text-color">
<div class="media"> <div class="media" style="overflow-y: auto;height: 704px;">
<div class="media-body"> <div class="media-body">
<table class="table table-sm"> <table class="table table-sm">
<thead> <thead>
@ -129,10 +182,10 @@
<t t-foreach="widget.task_data" t-as="proj"> <t t-foreach="widget.task_data" t-as="proj">
<tr> <tr>
<td> <td>
<t t-esc="proj[1]"/> <t t-esc="proj[1]" />
</td> </td>
<td> <td>
<t t-esc="proj[0]"/> <t t-esc="proj[0]" />
</td> </td>
</tr> </tr>
</t> </t>
@ -143,30 +196,9 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-12 col-lg-12 col-md-12">
<div class="row main-section">
<div class="col-sm-7 col-lg-7">
<div class="selling_product_graph_view">
<div class="oh-card text-color">
<div class="oh-card-body pb-0">
<h4 class="mb-0">
</h4>
<p class="stat-head" style="padding : 0px;">Timesheet Analysis</p>
</div>
<canvas class="top_selling_employees" width="200" height="120"/>
</div>
</div>
</div>
<div class="col-md-4 col-lg-4" style="top: 149px;right: -100px;">
<div class="hr_notification" style="background: #fff;transition: transform 0.2s ease, box-shadow 0.2s ease;will-change: transform, box-shadow;box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06); <div class="hr_notification" style="background: #fff;transition: transform 0.2s ease, box-shadow 0.2s ease;will-change: transform, box-shadow;box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
height: 316px;overflow-y: auto;margin-bottom: 15px;"> height: 284px;margin-bottom: 15px;">
<div class="hr_notification_head" <div class="hr_notification_head" style="font-size: 17px;text-align: center;padding: 12px 0;color: #fff;font-weight: 300;background: #000080;margin-bottom: 9px;">
style="font-size: 17px;text-align: center;padding: 12px 0;color: #fff;font-weight: 300;background: #218a45a3;margin-bottom: 9px;">
Hours Recorded Hours Recorded
</div> </div>
<div class="col-sm-12 col-lg-12" style="padding:0;"> <div class="col-sm-12 col-lg-12" style="padding:0;">
@ -186,7 +218,7 @@
<tr> <tr>
<td> <td>
<h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;"> <h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;">
<t t-esc="hour_recorde"/> <t t-esc="hour_recorde" />
</h2> </h2>
</td> </td>
</tr> </tr>
@ -204,7 +236,7 @@
<tr> <tr>
<td> <td>
<h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;"> <h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;">
<t t-esc="billable_fix"/> <t t-esc="billable_fix" />
</h2> </h2>
</td> </td>
</tr> </tr>
@ -225,7 +257,7 @@
<td> <td>
<h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;"> <h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;">
<t t-esc="hour_recorded"/> <t t-esc="hour_recorded" />
</h2> </h2>
</td> </td>
</tr> </tr>
@ -246,7 +278,7 @@
<td> <td>
<h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;"> <h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;">
<t t-esc="non_billable"/> <t t-esc="non_billable" />
</h2> </h2>
</td> </td>
</tr> </tr>
@ -267,7 +299,7 @@
<td> <td>
<h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;"> <h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;">
<t t-esc="total_hr"/> <t t-esc="total_hr" />
</h2> </h2>
</td> </td>
</tr> </tr>
@ -279,53 +311,11 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-12 col-lg-12 col-md-12">
<div class="row main-section">
<div class="col-sm-7 col-lg-7">
<div class="row" style="margin:0px">
<div class="col-md-12" id="col-graph">
<div class="card">
<div class="card-header">
<div class="card-title">
<b>
<h3 class="custom-h3">Profitability</h3>
</b>
</div>
<div class="card-tools">
<select id="income_expense_values">
<option id="income_this_year" value="income_this_year">This Year</option>
<option id="income_this_month" value="income_this_month">This Month</option>
<div role="separator" class="dropdown-divider" />
<option id="income_last_year" value="income_this_year">Last Year</option>
</select>
</div>
</div> </div>
<div class="card-body mt-3" id="in_ex_body_hide">
<div class="row">
<!-- <div class="col-md-12">-->
<p id="myelement1"> </p>
<div class="chart">
<!-- <canvas id="canvas"> </canvas>-->
<canvas id="canvas" width="100% !important" height="auto !important"> </canvas>
</div>
<!-- </div>-->
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-4 col-lg-4" style="top: 155px;right: -100px;">
<div class="hr_notification" style="background: #fff;transition: transform 0.2s ease, box-shadow 0.2s ease;will-change: transform, box-shadow;box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06); <div class="hr_notification" style="background: #fff;transition: transform 0.2s ease, box-shadow 0.2s ease;will-change: transform, box-shadow;box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
height: 316px;overflow-y: auto;margin-bottom: 15px;"> height: 284px;margin-bottom: 15px;">
<div class="hr_notification_head" <div class="hr_notification_head" style="font-size: 17px;text-align: center;padding: 12px 0;color: #fff;font-weight: 300;background:#000080;;margin-bottom: 9px;">
style="font-size: 17px;text-align: center;padding: 12px 0;color: #fff;font-weight: 300;background:#218a45a3;;margin-bottom: 9px;">
Profitability Profitability
</div> </div>
<div class="col-sm-12 col-lg-12" style="padding:0;"> <div class="col-sm-12 col-lg-12" style="padding:0;">
@ -344,7 +334,7 @@
<tr> <tr>
<td> <td>
<h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;"> <h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;">
<t t-esc="invoiced"/> <t t-esc="invoiced" />
</h2> </h2>
</td> </td>
</tr> </tr>
@ -363,7 +353,7 @@
<td> <td>
<h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;"> <h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;">
<t t-esc="to_invoice"/> <t t-esc="to_invoice" />
</h2> </h2>
</td> </td>
</tr> </tr>
@ -383,7 +373,7 @@
<td> <td>
<h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;"> <h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;">
<t t-esc="time_cost"/> <t t-esc="time_cost" />
</h2> </h2>
</td> </td>
</tr> </tr>
@ -403,7 +393,7 @@
<td> <td>
<h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;"> <h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;">
<t t-esc="expen_cost"/> <t t-esc="expen_cost" />
</h2> </h2>
</td> </td>
</tr> </tr>
@ -423,7 +413,7 @@
<td> <td>
<h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;"> <h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;">
<t t-esc="payment_method"/> <t t-esc="payment_method" />
</h2> </h2>
</td> </td>
</tr> </tr>
@ -436,11 +426,30 @@
</div> </div>
</div> </div>
</div> </div>
<div class="hr_notification" style="background: #fff;transition: transform 0.2s ease, box-shadow 0.2s ease;will-change: transform, box-shadow;box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
height: auto;padding-bottom: 15px;box-shadow:5px 11px 30px;">
<div class="hr_notification_head" style="font-size: 17px;text-align: center;padding: 12px 0;color: #fff;font-weight: 300;background: #000080;margin-bottom: 9px;">
Stage Wise Total Projects
</div>
<table id="table_status" style="width">
<tr>
<th />
<th />
</tr>
<t t-foreach="widget.project_stage_list" t-as="data">
<tr>
<td style="text-align:center;">
<h4 t-esc="data['name']" />
</td>
<td style="text-align:center;">
<h4 class="project-pill" t-esc="data['projects']" />
</td>
</tr>
</t>
</table>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</t> </t>
</templates> </templates>

Loading…
Cancel
Save