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
-------
* Developers: odoo@cybrosys.com
V15 - Archana V, archana@cybrosys.info
V15 - Archana V, archana @ cybrosys
V16 - YadhuKrishnan K Yadhu @ cybrosys
Contacts
--------

1
project_dashboard_odoo/__init__.py

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

4
project_dashboard_odoo/__manifest__.py

@ -3,7 +3,7 @@
#
# 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>)
#
# You can modify it under the terms of the GNU LESSER
@ -25,7 +25,7 @@
'category': 'Productivity',
'summary': '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',
'company': '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
#### Version 15.0.1.0.0
## Module <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 dateutil.relativedelta import relativedelta
import pandas as pd
import calendar
from odoo import models, api
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'
@api.model
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_task = self.env['project.task'].search([])
analytic_project = self.env['account.analytic.line'].search([])
@ -48,18 +86,39 @@ class PosDashboard(models.Model):
('sale_order_id', '!=', False)
], ['sale_order_id'])
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 {
'total_projects': len(all_project),
'total_tasks': len(all_task),
'total_hours': total_time,
'total_profitability': profitability,
'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
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
from account_analytic_line
@ -80,80 +139,19 @@ class PosDashboard(models.Model):
return final
@api.model
def get_project_task(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
def get_details(self):
"""
@api.model
def get_profitability_details(self):
query = '''select sum(margin) as payment_details from project_profitability_report'''
self._cr.execute(query)
data = self._cr.dictfetchall()
payment_details = []
for record in data:
payment_details.append(record.get('payment_details'))
Summery:
when the page is loaded get the data for the profitable table.
return:
type:It is a dictionary variable. This dictionary contain data
that profitable table.
return {
'payment_details': payment_details,
}
@api.model
def get_details(self):
"""
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(margin) as payment_details from project_profitability_report'''
self._cr.execute(query)
@ -165,7 +163,7 @@ class PosDashboard(models.Model):
to_invoice = []
for record in data:
to_invoice.append(record.get('to_invoice'))
record.get('to_invoice')
time_cost = []
for record in data:
time_cost.append(record.get('time_cost'))
@ -177,7 +175,6 @@ class PosDashboard(models.Model):
payment_details = []
for record in data:
payment_details.append(record.get('payment_details'))
return {
'invoiced': invoiced,
'to_invoice': to_invoice,
@ -188,6 +185,14 @@ class PosDashboard(models.Model):
@api.model
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
WHERE timesheet_invoice_type='non_billable_project' '''
self._cr.execute(query)
@ -239,6 +244,14 @@ class PosDashboard(models.Model):
@api.model
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 = []
for i in range(11, -1, -1):
@ -256,7 +269,8 @@ class PosDashboard(models.Model):
records = []
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:
records.append({
@ -283,6 +297,14 @@ class PosDashboard(models.Model):
@api.model
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 = []
for i in range(11, -1, -1):
l_month = datetime.now() - relativedelta(months=i)
@ -290,7 +312,6 @@ class PosDashboard(models.Model):
month_list.append(text)
states_arg = ""
self._cr.execute(('''select sum(margin) as income ,to_char(project_profitability_report.line_date, 'Month')
as month from project_profitability_report where
Extract(year FROM project_profitability_report.line_date) = Extract(year FROM DATE(NOW())) -1
@ -299,7 +320,8 @@ class PosDashboard(models.Model):
records = []
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:
records.append({
'month': month,
@ -327,6 +349,14 @@ class PosDashboard(models.Model):
@api.model
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 = ""
day_list = []
now = datetime.now()
@ -370,6 +400,15 @@ class PosDashboard(models.Model):
@api.model
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
Inner join project_project as pro on project_task.project_id = pro.id ORDER BY project_name ASC''')
data = self._cr.fetchall()
@ -380,3 +419,43 @@ class PosDashboard(models.Model):
return {
'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">
<h4 class="mt-2"
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
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,
Hours Recorded, Total Profitability, Total Sale Orders.</p>
<img src="assets/screenshots/pd1.png" class="img-responsive img-thumbnail border" width="100%"
User can click the Tiles and States in tile,That shows the detailed view of corresponding tiles.</p>
<img src="assets/screenshots/Screenshot1.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;">
Task Analysis</h4>
Different Types of Graphs</h4>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
Task analysis from various projects. </p>
<img src="assets/screenshots/pd2.png" class="img-responsive img-thumbnail border" width="100%"
Project dashboard have different types of graphs that will give you complete analyse of the project module. </p>
<img src="assets/screenshots/Screenshot2.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;">
Employees Timesheet</h4>
<img src="assets/screenshots/pd3.png" class="img-responsive img-thumbnail border" width="100%"
Employees Timesheet Graphh</h4>
<img src="assets/screenshots/Screenshot3.png" class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
@ -218,11 +226,24 @@
<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;">
Project Profitability</h4>
<img src="assets/screenshots/pd4.png" class="img-responsive img-thumbnail border" width="100%"
Project Profitability Graph</h4>
<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"/>
</div>
</div>
<!-- SUGGESTED PRODUCTS -->

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

@ -13,28 +13,6 @@ overflow: auto !important;
.breadcrumbs {
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{
display: inline-block;
}
@ -67,120 +45,6 @@ overflow: auto !important;
.stat_count {
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 {
background-color: #f8faff !important;
@ -190,25 +54,6 @@ rect:hover { fill:#934da5; }
.container-fluid.o_hr_dashboard {
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 {
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;
}
.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 {
margin-top: 1.5%;
@ -348,7 +83,6 @@ rect:hover { fill:#934da5; }
height: 85px;
text-align: center;
padding-top: 2%;
background: #ff8762;
color: #fff;
}
@ -362,7 +96,6 @@ rect:hover { fill:#934da5; }
.stat-widget-one .stat-text {
font-size: 14px;
color: #ff8762;
margin-top: 2.3rem;
margin-left: 1rem;
@ -380,7 +113,7 @@ rect:hover { fill:#934da5; }
font-size: 42px;
font-weight: 900;
display: inline-block;
color: #fff;
color: #000;
top: 16px;
position: relative;
}
@ -401,147 +134,7 @@ rect:hover { fill:#934da5; }
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{
margin: 15px 0px;
background: #fff;
@ -568,223 +161,12 @@ h4 .stat-count {
padding-bottom: 65px;
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 {
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;
height: 757pxpx;
margin-bottom: 15px;
}
.hr_notification .media {
@ -810,32 +192,6 @@ h4 .stat-count {
background: #5ebade;
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 {
margin: 15px 0px;
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);
padding-top: 3px !important;
}
.monthly_leave_trend {
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);
}
.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;
.row.main-section {
margin-right: 0px; !important;
}
.monthly_attrition_rate .oh-card:hover{
transform: translateY(-2px) translateZ(0) !important;
box-shadow: 0 10px 10px 0 rgba(62, 57, 107, 0.12), 0 0 0 transparent !important;
.text-align {
margin-left: 17px;
}
.row.main-section {
margin-right: 0px; !important;
.chart {
width: 100% !important;
height: 400px !important;
}
/* width */
.hr_notification::-webkit-scrollbar {
width: 4px;
.inner_select {
min-width: 150px
}
/* Track */
.hr_notification::-webkit-scrollbar-track {
background: #f1f1f1;
#table_status {
width: 90%;
margin-left: 5%;
font-family: Arial, Helvetica, sans-serif;
}
/* Handle */
.hr_notification::-webkit-scrollbar-thumb {
background: #495057;;
#table_status tr:nth-child(even) {
background-color: #f2f2f2;
}
/* Handle on hover */
.hr_notification::-webkit-scrollbar-thumb:hover {
background: #598da1;
#table_status tr:hover {
background-color: #ddd;
}
.oh-card-body {
display: flex;
justify-content: space-between;
.project-pill {
align-items: center;
}
.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-family: "Open Sans", Arial, Verdana, sans-serif;
font-weight: bold;
color: #FFF;
text-transform: uppercase;
text-align: center;
line-height: 20px;
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
width: 200px;
display: block;
background: #79A70A;
background: linear-gradient(#2989d8 0%, #1e5799 100%);
box-shadow: 0 3px 10px -5px rgba(0, 0, 0, 1);
position: absolute;
top: 56px;
left: -35px;
}
.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;
font-size: 11px;
display: inline-block;
height: 100%;
white-space: nowrap;
width: auto;
position: relative;
border-radius: 100px;
line-height: 1;
overflow: hidden;
padding: 0px 8px 0px 7px;
text-overflow: ellipsis;
line-height: 1.25rem;
color: #fff;
word-break: break-word;
background: #0253e8;
}
.chart {
width: 100% !important;
height: 400px !important;
.inner_select p {
margin-left: 20px
}

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

@ -1,21 +1,24 @@
odoo.define('pj_dashboard.Dashboard', function (require) {
"use strict";
var AbstractAction = require('web.AbstractAction');
var core = require('web.core');
var QWeb = core.qweb;
var ajax = require('web.ajax');
var rpc = require('web.rpc');
var _t = core._t;
var session = require('web.session');
var web_client = require('web.web_client');
var abstractView = require('web.AbstractView');
var PjDashboard = AbstractAction.extend({
template:'PjDashboard',
odoo.define('pj_dashboard.Dashboard', function(require) {
"use strict";
var AbstractAction = require('web.AbstractAction');
var core = require('web.core');
var QWeb = core.qweb;
var ajax = require('web.ajax');
var rpc = require('web.rpc');
var _t = core._t;
var session = require('web.session');
var web_client = require('web.web_client');
var abstractView = require('web.AbstractView');
var flag = 0;
var tot_so = []
var tot_project = []
var tot_task = []
var tot_employee = []
var tot_hrs = []
var tot_margin = []
var PjDashboard = AbstractAction.extend({
template: 'PjDashboard',
cssLibs: [
'/project_dashboard_odoo/static/src/css/lib/nv.d3.css'
],
@ -24,21 +27,22 @@ var PjDashboard = AbstractAction.extend({
],
events: {
'click .tot_projects':'tot_projects',
'click .tot_tasks':'tot_tasks',
'click .tot_profitability':'tot_profitability',
'click .hr_recorded':'hr_recorded',
'click .tot_sale':'tot_sale',
'click .tot_emp':'tot_emp',
'click #income_this_year': 'onclick_income_this_year',
'click #income_last_year': 'onclick_income_last_year',
'click #income_this_month': 'onclick_income_this_month',
'click .tot_projects': 'tot_projects',
'click .tot_tasks': 'tot_tasks',
'click .tot_profitability': 'tot_profitability',
'click .hr_recorded': 'hr_recorded',
'click .tot_sale': 'tot_sale',
'click .tot_emp': 'tot_emp',
'change #income_expense_values': 'onchange_profitability',
'change #start_date': '_onchangeFilter',
'change #end_date': '_onchangeFilter',
'change #employee_selection': '_onchangeFilter',
'change #project_selection': '_onchangeFilter',
},
init: function(parent, context) {
this._super(parent, context);
this.dashboards_templates = ['DashboardProject','DashboardChart'];
this.dashboards_templates = ['DashboardProject', 'DashboardChart'];
this.today_sale = [];
},
@ -56,23 +60,70 @@ var PjDashboard = AbstractAction.extend({
return this._super().then(function() {
self.render_dashboards();
self.render_graphs();
self.render_filter()
});
},
render_dashboards: function(){
render_dashboards: function() {
var self = this;
_.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;
self.render_project_task();
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() {
@ -84,65 +135,54 @@ var PjDashboard = AbstractAction.extend({
self.render_graphs();
});
},
//
onclick_toggle_two: function(ev) {
this.onclick_income_this_year(ev);
this.onclick_income_last_year(ev);
this.onclick_income_this_month(ev);
},
render_project_task:function(){
var self = this;
var w = 400;
var h = 400;
var r = h/2;
var elem = this.$('.emp_graph');
var colors = ['#70cac1', '#659d4e', '#208cc2', '#4d6cb1', '#584999', '#8e559e', '#cf3650', '#f65337', '#fe7139',
'#ffa433', '#ffc25b', '#f8e54b'];
var color = d3.scale.ordinal().range(colors);
rpc.query({
model: "project.project",
method: "get_project_task",
}).then(function (data) {
var segColor = {};
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 + ")");
var pie = d3.layout.pie().value(function(d){return d.value;});
var arc = d3.svg.arc().outerRadius(r);
var arcs = vis.selectAll("g.slice").data(pie).enter().append("svg:g").attr("class", "slice");
arcs.append("svg:path")
.attr("fill", function(d, i){
return color(i);
_onchangeFilter: function() {
flag = 1
var start_date = $('#start_date').val();
var end_date = $('#end_date').val();
if (!start_date) {
start_date = "null"
}
if (!end_date) {
end_date = "null"
}
var employee_selection = $('#employee_selection').val();
var project_selection = $('#project_selection').val();
ajax.rpc('/project/filter-apply', {
'data': {
'start_date': start_date,
'end_date': end_date,
'project': project_selection,
'employee': employee_selection
}
}).then(function(data) {
tot_hrs = data['list_hours_recorded']
tot_employee = data['total_emp']
tot_project = data['total_project']
tot_task = data['total_task']
tot_so = data['total_so']
document.getElementById("tot_project").innerHTML = data['total_project'].length
document.getElementById("tot_employee").innerHTML = data['total_emp'].length
document.getElementById("tot_task").innerHTML = data['total_task'].length
document.getElementById("tot_hrs").innerHTML = data['hours_recorded']
document.getElementById("tot_margin").innerHTML = data['total_margin']
document.getElementById("tot_so").innerHTML = data['total_so'].length
})
.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;});
});
},
//project
onchange_profitability: function(ev) {
var selected_filter = $('#income_expense_values').val()
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) {
var self = this;
e.stopPropagation();
@ -150,17 +190,41 @@ var PjDashboard = AbstractAction.extend({
var options = {
on_reverse_breadcrumb: this.on_reverse_breadcrumb,
};
if (flag == 0) {
this.do_action({
name: _t("Projects"),
type: 'ir.actions.act_window',
res_model: 'project.project',
view_mode: 'kanban,form',
views: [[false, 'list'],[false, 'form']],
views: [
[false, 'kanban'],
[false, 'form']
],
target: 'current'
}, 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) {
var self = this;
e.stopPropagation();
@ -168,17 +232,41 @@ var PjDashboard = AbstractAction.extend({
var options = {
on_reverse_breadcrumb: this.on_reverse_breadcrumb,
};
if (flag == 0) {
this.do_action({
name: _t("Tasks"),
type: 'ir.actions.act_window',
res_model: 'project.task',
view_mode: 'tree,kanban,form',
views: [[false, 'list'],[false, 'form']],
views: [
[false, 'list'],
[false, 'form']
],
target: 'current'
}, 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) {
var self = this;
e.stopPropagation();
@ -189,15 +277,19 @@ var PjDashboard = AbstractAction.extend({
this.do_action({
name: _t("Profitability"),
type: 'ir.actions.act_window',
res_model: 'project.profitability.report',
res_model: 'project.project',
view_mode: 'pivot',
views: [[false, 'pivot'],[false, 'graph']],
views: [
[false, 'pivot'],
[false, 'graph']
],
target: 'current'
}, options)
},
//hr timesheets
/**
for opening account analytic line view
*/
hr_recorded: function(e) {
var self = this;
e.stopPropagation();
@ -205,17 +297,39 @@ var PjDashboard = AbstractAction.extend({
var options = {
on_reverse_breadcrumb: this.on_reverse_breadcrumb,
};
if (flag == 0) {
this.do_action({
name: _t("Timesheets"),
type: 'ir.actions.act_window',
res_model: 'account.analytic.line',
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'
}, options)
}
}
},
//total saleorder
/**
for opening sale order view
*/
tot_sale: function(e) {
var self = this;
@ -224,19 +338,42 @@ var PjDashboard = AbstractAction.extend({
var options = {
on_reverse_breadcrumb: this.on_reverse_breadcrumb,
};
if (flag == 0) {
this.do_action({
name: _t("Sale Order"),
type: 'ir.actions.act_window',
res_model: 'sale.order',
view_mode: 'tree',
views: [[false, 'list']],
domain: [['analytic_account_id', '!=',self.analytic_account_id ]],
views: [
[false, 'list']
],
domain: [
["id", "in", tot_so]
],
target: 'current'
}, 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) {
var self = this;
e.stopPropagation();
@ -244,36 +381,52 @@ var PjDashboard = AbstractAction.extend({
var options = {
on_reverse_breadcrumb: this.on_reverse_breadcrumb,
};
if (flag == 0) {
this.do_action({
name: _t("Employees"),
type: 'ir.actions.act_window',
res_model: 'hr.employee',
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'
}, options)
},
}
},
render_top_employees_graph:function(){
console.log('hhhh')
render_top_employees_graph: function() {
var self = this
console.log('bbb')
var ctx = self.$(".top_selling_employees");
console.log('vvv',ctx)
rpc.query({
model: "project.project",
method: 'get_top_timesheet_employees',
}).then(function (arrays) {
}).then(function(arrays) {
var data = {
labels: arrays[1],
datasets: [
{
datasets: [{
label: "Hours Spent",
data: arrays[0],
backgroundColor: [
@ -305,7 +458,6 @@ var PjDashboard = AbstractAction.extend({
]
};
console.log(data)
//options
var options = {
@ -317,14 +469,6 @@ var PjDashboard = AbstractAction.extend({
fontSize: 18,
fontColor: "#111"
},
legend: {
display: true,
position: "bottom",
labels: {
fontColor: "#333",
fontSize: 16
}
},
scales: {
yAxes: [{
ticks: {
@ -333,7 +477,6 @@ var PjDashboard = AbstractAction.extend({
}]
}
};
console.log('lllll',data)
//create Chart class object
var chart = new Chart(ctx, {
type: 'bar',
@ -344,7 +487,7 @@ var PjDashboard = AbstractAction.extend({
});
},
onclick_income_last_year: function(ev) {
income_last_year: function(ev) {
ev.preventDefault();
var selected = $('.btn.btn-tool.income');
var data = $(selected[0]).data();
@ -356,7 +499,6 @@ var PjDashboard = AbstractAction.extend({
args: [],
})
.then(function(result) {
$('#net_profit_current_months').hide();
$('#net_profit_last_year').show();
$('#net_profit_this_year').hide();
@ -378,8 +520,7 @@ var PjDashboard = AbstractAction.extend({
type: 'bar',
data: {
labels: labels,
datasets: [
{
datasets: [{
label: 'Profitability', // Name the series
data: profit, // Specify the data values array
backgroundColor: '#0bd465',
@ -388,8 +529,7 @@ var PjDashboard = AbstractAction.extend({
borderWidth: 1, // Specify bar border width
type: 'line', // Set this data to a line chart
fill: false
}
]
}]
},
options: {
responsive: true, // Instruct chart js to respond nicely.
@ -400,8 +540,7 @@ var PjDashboard = AbstractAction.extend({
})
},
onclick_income_this_year: function(ev) {
ev.preventDefault();
income_this_year: function() {
var selected = $('.btn.btn-tool.income');
var data = $(selected[0]).data();
var posted = false;
@ -414,15 +553,11 @@ var PjDashboard = AbstractAction.extend({
})
.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');
// Define the data
var income = result.income; // Add data values to array
// var expense = result.expense;
// var expense = result.expense;
var profit = result.profit;
var labels = result.month; // Add labels to array
@ -435,8 +570,7 @@ var PjDashboard = AbstractAction.extend({
type: 'bar',
data: {
labels: labels,
datasets: [
{
datasets: [{
label: 'Profitability', // Name the series
data: profit, // Specify the data values array
backgroundColor: '#0bd465',
@ -445,8 +579,7 @@ var PjDashboard = AbstractAction.extend({
borderWidth: 1, // Specify bar border width
type: 'line', // Set this data to a line chart
fill: false
}
]
}]
},
options: {
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();
var selected = $('.btn.btn-tool.income');
var data = $(selected[0]).data();
@ -517,21 +651,21 @@ var PjDashboard = AbstractAction.extend({
var def1 = this._rpc({
model: 'project.project',
method: 'get_tiles_data'
}).then(function(result)
{
}).then(function(result) {
self.total_projects = result['total_projects'],
self.total_tasks = result['total_tasks'],
self.total_hours = result['total_hours'],
self.total_profitability = result['total_profitability'],
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({
model: "project.project",
method: "get_details",
})
.then(function (res) {
.then(function(res) {
self.invoiced = res['invoiced'];
self.to_invoice = res['to_invoice'];
self.time_cost = res['time_cost'];
@ -542,7 +676,7 @@ var PjDashboard = AbstractAction.extend({
model: "project.project",
method: "get_hours_data",
})
.then(function (res) {
.then(function(res) {
self.hour_recorded = res['hour_recorded'];
self.hour_recorde = res['hour_recorde'];
self.billable_fix = res['billable_fix'];
@ -554,19 +688,18 @@ var PjDashboard = AbstractAction.extend({
model: "project.project",
method: "get_task_data",
})
.then(function (res) {
.then(function(res) {
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">
<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-body">
<div class="stat-widget-one">
<div class="stat-icon" style="background:#e08048;"><i class="fa fa-puzzle-piece"/></div>
<div class="stat-content">
<div class="stat-head">Total Project</div>
<div class="stat_count"><t t-esc="widget.total_projects"/></div>
<div class="oh-card-body tot_projects" style="box-shadow:5px 11px 30px;">
<div class="stat-widget-one" style="display:flex;">
<div class="stat-icon"><i class="fa fa-puzzle-piece" /></div>
<div class="stat-head" style="padding: 5%;width: 60%;">Total Project</div>
<div class="stat_count" style="padding: 4%;width: 30%;" id="tot_project">
<t t-esc="widget.total_projects" />
</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-body">
<div class="stat-widget-one">
<div class="stat-icon" style="background:#645bd0"><i class="fa fa-user"/></div>
<div class="stat-content">
<div class="stat-head">Total Employees</div>
<div class="stat_count"><t t-esc="widget.total_employees"/></div>
<div class="oh-card-body tot_emp" style="box-shadow:5px 11px 30px;">
<div class="stat-widget-one" style="display:flex;">
<div class="stat-icon"><i class="fa fa-user" /></div>
<div class="stat-head" style="padding: 5%;width: 60%;">Total Employees</div>
<div class="stat_count" style="padding: 4%;width: 30%;" id="tot_employee">
<t t-esc="widget.total_employees" />
</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-body">
<div class="stat-widget-one">
<div class="stat-icon" style="background:#85d05b"><i class="fa fa-tasks"/></div>
<div class="stat-content">
<div class="stat-head">Total tasks</div>
<div class="stat_count"><t t-esc="widget.total_tasks"/></div>
<div class="oh-card-body tot_tasks" style="box-shadow:5px 11px 30px;">
<div class="stat-widget-one" style="display:flex;">
<div class="stat-icon"><i class="fa fa-tasks" /></div>
<div class="stat-head" style="padding: 5%;width: 60%;">Total tasks</div>
<div class="stat_count" style="padding: 4%;width: 30%;" id="tot_task">
<t t-esc="widget.total_tasks" />
</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-body">
<div class="stat-widget-one">
<div class="stat-icon" style="background:#d05bb8"><i class="fa fa-clock-o"/></div>
<div class="stat-content">
<div class="stat-head">Hours Recorded</div>
<div class="stat_count"><t t-esc="widget.total_hours"/></div>
<div class="oh-card-body hr_recorded" style="box-shadow:5px 11px 30px;">
<div class="stat-widget-one" style="display:flex;">
<div class="stat-icon"><i class="fa fa-clock-o" /></div>
<div class="stat-head" style="padding: 5%;width: 60%;">Hours Recorded</div>
<div class="stat_count" style="padding: 4%;width: 30%;" id="tot_hrs">
<t t-esc="widget.total_hours" />
</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-body">
<div class="stat-widget-one">
<div class="stat-icon" style="background:#d0c35b"><i class="fa fa-dollar"/></div>
<div class="stat-content">
<div class="stat-head">Total Profitability</div>
<div class="stat_count"><t t-esc="widget.total_profitability"/></div>
<div class="oh-card-body tot_profitability" style="box-shadow:5px 11px 30px;">
<div class="stat-widget-one" style="display:flex;">
<div class="stat-icon"><i class="fa fa-dollar" /></div>
<div class="stat-head" style="padding: 5%;width: 60%;">Total Profitability</div>
<div class="stat_count" style="padding: 4%;width: 30%;" id="tot_margin">
<t t-esc="widget.total_profitability" />
</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-body">
<div class="stat-widget-one">
<div class="stat-icon" style="background:#5b8ed0"><i class="fa fa-ticket"/></div>
<div class="stat-content">
<div class="stat-head">Total Sale Orders</div>
<div class="stat_count"><t t-esc="widget.total_sale_orders"/></div>
<div class="oh-card-body tot_sale" style="box-shadow:5px 11px 30px;">
<div class="stat-widget-one" style="display:flex;">
<div class="stat-icon"><i class="fa fa-ticket" /></div>
<div class="stat-head" style="padding: 5%;width: 60%;">Total Sale Orders</div>
<div class="stat_count" style="padding: 4%;width: 30%;" id="tot_so">
<t t-esc="widget.total_sale_orders" />
</div>
</div>
</div>
@ -95,28 +119,57 @@
<t t-name="DashboardChart">
<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="col-sm-7 col-lg-7" style="margin-left: 2%;">
<div class="graph_view" style="padding:0">
<div class="text-color hr-chart-1">
<div class="oh-card-body pb-0">
<h4 class="mb-0"/>
<p class="stat-head" style="padding : 0px;">ProjectTask Analysis</p>
<canvas id="project_doughnut" style="background:#fff;" width="200" height="120" />
</div>
</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 class="emp_graph"/>
</div>
</div>
</div>
<div class="col-md-4 col-lg-4" style="top: 82px;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);
height: 316px;overflow-y: auto;margin-bottom: 15px;">
<div class="hr_notification_head"
style="font-size: 17px;text-align: center;padding: 12px 0;color: #fff;font-weight: 300;background: #218a45a3;margin-bottom: 9px;">
ProjectTask Details
<div class="col-md-4 col-lg-4" style="top: 20px;right: -100px;">
<div class="hr_notification" style="background: #fff;
height: 763px;margin-bottom: 15px;margin-top: 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;">
Project Task Details
</div>
<div class="col-sm-12 col-lg-12" style="padding:0;">
<div class="text-color">
<div class="media">
<div class="media" style="overflow-y: auto;height: 704px;">
<div class="media-body">
<table class="table table-sm">
<thead>
@ -129,10 +182,10 @@
<t t-foreach="widget.task_data" t-as="proj">
<tr>
<td>
<t t-esc="proj[1]"/>
<t t-esc="proj[1]" />
</td>
<td>
<t t-esc="proj[0]"/>
<t t-esc="proj[0]" />
</td>
</tr>
</t>
@ -143,30 +196,9 @@
</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);
height: 316px;overflow-y: auto;margin-bottom: 15px;">
<div class="hr_notification_head"
style="font-size: 17px;text-align: center;padding: 12px 0;color: #fff;font-weight: 300;background: #218a45a3;margin-bottom: 9px;">
height: 284px;margin-bottom: 15px;">
<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;">
Hours Recorded
</div>
<div class="col-sm-12 col-lg-12" style="padding:0;">
@ -186,7 +218,7 @@
<tr>
<td>
<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>
</td>
</tr>
@ -204,7 +236,7 @@
<tr>
<td>
<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>
</td>
</tr>
@ -225,7 +257,7 @@
<td>
<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>
</td>
</tr>
@ -246,7 +278,7 @@
<td>
<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>
</td>
</tr>
@ -267,7 +299,7 @@
<td>
<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>
</td>
</tr>
@ -279,53 +311,11 @@
</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 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);
height: 316px;overflow-y: auto;margin-bottom: 15px;">
<div class="hr_notification_head"
style="font-size: 17px;text-align: center;padding: 12px 0;color: #fff;font-weight: 300;background:#218a45a3;;margin-bottom: 9px;">
height: 284px;margin-bottom: 15px;">
<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;">
Profitability
</div>
<div class="col-sm-12 col-lg-12" style="padding:0;">
@ -344,7 +334,7 @@
<tr>
<td>
<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>
</td>
</tr>
@ -363,7 +353,7 @@
<td>
<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>
</td>
</tr>
@ -383,7 +373,7 @@
<td>
<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>
</td>
</tr>
@ -403,7 +393,7 @@
<td>
<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>
</td>
</tr>
@ -423,7 +413,7 @@
<td>
<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>
</td>
</tr>
@ -436,11 +426,30 @@
</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>
</t>
</templates>

Loading…
Cancel
Save