@ -0,0 +1,45 @@ |
|||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
|||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html |
|||
:alt: License: AGPL-3 |
|||
=========================== |
|||
Project Dashboard |
|||
=========================== |
|||
In this dashboard you can get Detailed Dashboard View for Project |
|||
|
|||
|
|||
Configuration |
|||
============= |
|||
* No additional configurations needed |
|||
|
|||
Company |
|||
------- |
|||
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ |
|||
|
|||
Credits |
|||
------- |
|||
* Developers: yadhukrishnan @ cybrosys, odoo@cybrosys.com |
|||
|
|||
|
|||
Contacts |
|||
-------- |
|||
* Mail Contact : odoo@cybrosys.com |
|||
* Website : https://cybrosys.com |
|||
|
|||
Bug Tracker |
|||
----------- |
|||
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. |
|||
|
|||
Maintainer |
|||
========== |
|||
.. image:: https://cybrosys.com/images/logo.png |
|||
:target: https://cybrosys.com |
|||
|
|||
This module is maintained by Cybrosys Technologies. |
|||
|
|||
For support and more information, please visit `Our Website <https://cybrosys.com/>`__ |
|||
|
|||
Further information |
|||
=================== |
|||
HTML Description: `<static/description/index.html>`__ |
|||
|
|||
|
@ -0,0 +1,22 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Yadhukrishnan K (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
################################################################################ |
|||
from . import controllers |
|||
from . import models |
@ -0,0 +1,57 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Yadhukrishnan K (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
################################################################################ |
|||
{ |
|||
'name': 'Project Dashboard', |
|||
'category': 'Productivity, Project', |
|||
'summary': """Project Dashboard For Odoo16 Community And Enterprise Edition""", |
|||
'description': """In this dashboard user the Detailed information about |
|||
project, task, employee, hours recorded, total margin and total |
|||
sale orders.""", |
|||
'version': '16.0.1.0.0', |
|||
'author': 'Cybrosys Techno Solutions', |
|||
'company': 'Cybrosys Techno Solutions', |
|||
'maintainer': 'Cybrosys Techno Solutions', |
|||
'website': 'https://www.cybrosys.com', |
|||
'license': 'AGPL-3', |
|||
'depends': [ |
|||
'base', |
|||
'sale_management', |
|||
'project', |
|||
'sale_timesheet', |
|||
], |
|||
'data': [ |
|||
'views/dashboard_views.xml', |
|||
], |
|||
'images': [ |
|||
'static/description/banner.png', |
|||
], |
|||
'assets': { |
|||
'web.assets_backend': [ |
|||
'project_dashboard_odoo/static/src/css/dashboard.css', |
|||
"project_dashboard_odoo/static/src/js/dashboard.js", |
|||
'project_dashboard_odoo/static/src/xml/dashboard.xml', |
|||
'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js' |
|||
], |
|||
}, |
|||
'installable': True, |
|||
'application': False, |
|||
'auto_install': False, |
|||
} |
@ -0,0 +1,21 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Yadhukrishnan K (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
################################################################################ |
|||
from . import project_dashboard_odoo |
@ -0,0 +1,150 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Yadhukrishnan K (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL 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'] |
|||
# checking the 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'] |
|||
# 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['timesheets.analysis.report'].search( |
|||
[('project_id', 'in', pro_selected), |
|||
('employee_id', 'in', emp_selected)]) |
|||
analytic_project = request.env['account.analytic.line'].search( |
|||
[('project_id', 'in', pro_selected), |
|||
('employee_id', 'in', emp_selected)]) |
|||
margin = sum(report_project.mapped('margin')) |
|||
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': margin, |
|||
'total_so': sale_orders |
|||
} |
@ -0,0 +1,6 @@ |
|||
## Module <project_dashboard_odoo> |
|||
|
|||
#### 29.03.2023 |
|||
#### Version 16.0.1.0.0 |
|||
##### ADD |
|||
##### Initial Commit for Project Dashboard |
@ -0,0 +1,21 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Yadhukrishnan K (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
################################################################################ |
|||
from . import project |
@ -0,0 +1,339 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Yadhukrishnan K (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
################################################################################ |
|||
import random |
|||
from odoo import api, models |
|||
|
|||
|
|||
class Project(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 |
|||
|
|||
""" |
|||
_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. |
|||
|
|||
""" |
|||
user_employee = self.env.user.partner_id |
|||
if user_employee.user_has_groups('project.group_project_manager'): |
|||
all_project = self.env['project.project'].search([]) |
|||
all_task = self.env['project.task'].search([]) |
|||
analytic_project = self.env['account.analytic.line'].search([]) |
|||
report_project = self.env['timesheets.analysis.report'].search([]) |
|||
margin = sum(report_project.mapped('margin')) |
|||
total_time = sum(analytic_project.mapped('unit_amount')) |
|||
employees = self.env['hr.employee'].search([]) |
|||
|
|||
task = self.env['project.task'].search_read([ |
|||
('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) |
|||
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_projects_ids': all_project.ids, |
|||
'total_tasks': len(all_task), |
|||
'total_tasks_ids': all_task.ids, |
|||
'total_hours': total_time, |
|||
'total_profitability': margin, |
|||
'total_employees': len(employees), |
|||
'total_sale_orders': len(sale_orders), |
|||
'sale_orders_ids': sale_orders.mapped('id'), |
|||
'project_stage_list': project_stage_list, |
|||
'flag': 1 |
|||
} |
|||
else: |
|||
all_project = self.env['project.project'].search( |
|||
[('user_id', '=', self.env.uid)]) |
|||
all_task = [] |
|||
for task in self.env['project.task'].search([]): |
|||
for assignee in task.user_ids: |
|||
if assignee.id == self.env.uid: |
|||
all_task.append(task.id) |
|||
analytic_project = self.env['account.analytic.line'].search( |
|||
[('project_id', 'in', all_project.ids)]) |
|||
total_time = sum(analytic_project.mapped('unit_amount')) |
|||
task = self.env['project.task'].search_read([ |
|||
('sale_order_id', '!=', False), |
|||
('project_id', 'in', all_project.ids) |
|||
], ['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) |
|||
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), |
|||
('id', 'in', all_project.ids)]) |
|||
project_stage_list.append({ |
|||
'name': project_stage_id.name, |
|||
'projects': total_projects |
|||
}) |
|||
return { |
|||
'total_projects': len(all_project), |
|||
'total_projects_ids': all_project.ids, |
|||
'total_tasks': len(all_task), |
|||
'total_tasks_ids': all_task, |
|||
'total_hours': total_time, |
|||
'total_sale_orders': len(sale_orders), |
|||
'sale_orders_ids': sale_orders.mapped('id'), |
|||
'project_stage_list': project_stage_list, |
|||
'flag': 2 |
|||
} |
|||
|
|||
@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 |
|||
inner join hr_employee on hr_employee.id = |
|||
account_analytic_line.employee_id |
|||
group by hr_employee.id ORDER |
|||
BY unit DESC Limit 10 ''' |
|||
self._cr.execute(query) |
|||
top_product = self._cr.dictfetchall() |
|||
|
|||
unit = [] |
|||
for record in top_product: |
|||
unit.append(record.get('unit')) |
|||
employee = [] |
|||
for record in top_product: |
|||
employee.append(record.get('employee')) |
|||
final = [unit, employee] |
|||
|
|||
return final |
|||
|
|||
@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. |
|||
|
|||
""" |
|||
user_employee = self.env.user.partner_id |
|||
if user_employee.user_has_groups('project.group_project_manager'): |
|||
query = '''SELECT sum(unit_amount) as hour_recorded FROM account_analytic_line |
|||
WHERE timesheet_invoice_type='non_billable_project' ''' |
|||
self._cr.execute(query) |
|||
data = self._cr.dictfetchall() |
|||
hour_recorded = [] |
|||
for record in data: |
|||
hour_recorded.append(record.get('hour_recorded')) |
|||
|
|||
query = '''SELECT sum(unit_amount) as hour_recorde FROM account_analytic_line |
|||
WHERE timesheet_invoice_type='billable_time' ''' |
|||
self._cr.execute(query) |
|||
data = self._cr.dictfetchall() |
|||
hour_recorde = [] |
|||
for record in data: |
|||
hour_recorde.append(record.get('hour_recorde')) |
|||
|
|||
query = '''SELECT sum(unit_amount) as billable_fix FROM account_analytic_line |
|||
WHERE timesheet_invoice_type='billable_fixed' ''' |
|||
self._cr.execute(query) |
|||
data = self._cr.dictfetchall() |
|||
billable_fix = [] |
|||
for record in data: |
|||
billable_fix.append(record.get('billable_fix')) |
|||
|
|||
query = '''SELECT sum(unit_amount) as non_billable FROM account_analytic_line |
|||
WHERE timesheet_invoice_type='non_billable' ''' |
|||
self._cr.execute(query) |
|||
data = self._cr.dictfetchall() |
|||
non_billable = [] |
|||
for record in data: |
|||
non_billable.append(record.get('non_billable')) |
|||
|
|||
query = '''SELECT sum(unit_amount) as total_hr FROM account_analytic_line |
|||
WHERE timesheet_invoice_type='non_billable_project' or |
|||
timesheet_invoice_type='billable_time' |
|||
or timesheet_invoice_type='billable_fixed' or |
|||
timesheet_invoice_type='non_billable' ''' |
|||
self._cr.execute(query) |
|||
data = self._cr.dictfetchall() |
|||
total_hr = [] |
|||
for record in data: |
|||
total_hr.append(record.get('total_hr')) |
|||
return { |
|||
'hour_recorded': hour_recorded, |
|||
'hour_recorde': hour_recorde, |
|||
'billable_fix': billable_fix, |
|||
'non_billable': non_billable, |
|||
'total_hr': total_hr, |
|||
} |
|||
else: |
|||
all_project = self.env['project.project'].search( |
|||
[('user_id', '=', self.env.uid)]).ids |
|||
analytic_project = self.env['account.analytic.line'].search( |
|||
[('project_id', 'in', all_project)]) |
|||
all_hour_recorded = analytic_project.filtered( |
|||
lambda x: x.timesheet_invoice_type == 'non_billable_project') |
|||
all_hour_recorde = analytic_project.filtered( |
|||
lambda x: x.timesheet_invoice_type == 'billable_time') |
|||
all_billable_fix = analytic_project.filtered( |
|||
lambda x: x.timesheet_invoice_type == 'billable_fixed') |
|||
all_non_billable = analytic_project.filtered( |
|||
lambda x: x.timesheet_invoice_type == 'non_billable') |
|||
|
|||
hour_recorded = [sum(all_hour_recorded.mapped('unit_amount'))] |
|||
hour_recorde = [sum(all_hour_recorde.mapped('unit_amount'))] |
|||
billable_fix = [sum(all_billable_fix.mapped('unit_amount'))] |
|||
non_billable = [sum(all_non_billable.mapped('unit_amount'))] |
|||
total_hr = [sum(hour_recorded + hour_recorde + billable_fix + non_billable)] |
|||
|
|||
return { |
|||
'hour_recorded': hour_recorded, |
|||
'hour_recorde': hour_recorde, |
|||
'billable_fix': billable_fix, |
|||
'non_billable': non_billable, |
|||
'total_hr': total_hr, |
|||
} |
|||
|
|||
@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. |
|||
|
|||
""" |
|||
user_employee = self.env.user.partner_id |
|||
if user_employee.user_has_groups('project.group_project_manager'): |
|||
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() |
|||
project_name = [] |
|||
for rec in data: |
|||
project_name.append(list(rec)) |
|||
return { |
|||
'project': project_name |
|||
} |
|||
else: |
|||
all_project = self.env['project.project'].search( |
|||
[('user_id', '=', self.env.uid)]).ids |
|||
all_tasks = self.env['project.task'].search( |
|||
[('project_id', 'in', all_project)]) |
|||
|
|||
task_project = [[task.name, task.project_id.name] for task in |
|||
all_tasks] |
|||
return { |
|||
'project': task_project |
|||
} |
|||
|
|||
@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 = [] |
|||
user_employee = self.env.user.partner_id |
|||
if user_employee.user_has_groups('project.group_project_manager'): |
|||
project_ids = self.env['project.project'].search([]) |
|||
else: |
|||
project_ids = self.env['project.project'].search( |
|||
[('user_id', '=', self.env.uid)]) |
|||
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 |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 589 B |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 967 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 72 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 315 KiB |
After Width: | Height: | Size: 316 KiB |
After Width: | Height: | Size: 208 KiB |
After Width: | Height: | Size: 218 KiB |
After Width: | Height: | Size: 2.2 MiB |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 26 KiB |
@ -0,0 +1,520 @@ |
|||
<div style="background-color: #714B67; height: 810px; width: 100%; padding: 15px; position: relative;"> |
|||
<!-- TITLE BAR --> |
|||
<div class="d-flex align-items-center justify-content-between" style="border-bottom: 1px solid #875A7B; padding: 15px; display: flex; justify-content: space-between; align-items: center;"> |
|||
<img src="assets/misc/cybrosys-logo.png" width="42" height="42" style="width: 42px; height: 42px;" /> |
|||
<div> |
|||
<div style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;" class="mr-2"> |
|||
<i class="fa fa-check mr-1"></i>Community |
|||
</div> |
|||
<div style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;" class="mr-2"> |
|||
<i class="fa fa-check mr-1"></i>Enterprise |
|||
</div> |
|||
<div style="color: #017E84; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;" class="mr-2"> |
|||
<i class="fa fa-check mr-1"></i>Odoo.sh |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END OF TITLE BAR --> |
|||
<div class="container"> |
|||
<div class="row"> |
|||
<div class="col-sm-12 col-md-12 col-lg-12"> |
|||
<!-- APP HERO --> |
|||
<h1 style="color: #FFFFFF; font-weight: bolder; font-size: 50px; text-align: center; margin-top: 50px;"> |
|||
Project Dashboard |
|||
</h1> |
|||
<p style="color:#FFFFFF; padding: 8px 15px; text-align: center; font-size: 24px;">In This Dashboard You Can Get Detailed View for Project.</p> |
|||
<!-- END OF APP HERO --> |
|||
<img src="assets/screenshots/hero.gif" class="img-responsive" style="width: 100%; margin-left: auto; margin-right: auto;" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- NAVIGATION SECTION --> |
|||
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px; margin-top: 300px;"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/compass.png" /> |
|||
</div> |
|||
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Explore This |
|||
Module</h2> |
|||
</div> |
|||
<div class="row my-4" style="font-family: 'Montserrat', sans-serif;"> |
|||
<div class="col-sm-12 col-md-6 my-3"> |
|||
<a href="#overview"> |
|||
<div class="d-flex justify-content-between align-items-center" style="background-color: #f5f5f5; padding: 30px; width: 100%;"> |
|||
<div> |
|||
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Overview</span> |
|||
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">Learn |
|||
more about this |
|||
module</span> |
|||
</div> |
|||
<img src="assets/misc/right-arrow.png" width="36" height="36" /> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div class="col-sm-12 col-md-6 my-3"> |
|||
<a href="#features"> |
|||
<div class="d-flex justify-content-between align-items-center" style="background-color: #f5f5f5; padding: 30px; width: 100%;"> |
|||
<div> |
|||
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Features</span> |
|||
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View |
|||
features of this |
|||
module</span> |
|||
</div> |
|||
<img src="assets/misc/right-arrow.png" width="36" height="36" /> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div class="col-sm-12 col-md-6 my-3"> |
|||
<a href="#screenshots"> |
|||
<div class="d-flex justify-content-between align-items-center" style="background-color: #f5f5f5; padding: 30px; width: 100%;"> |
|||
<div> |
|||
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Screenshots</span> |
|||
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View |
|||
screenshots for this |
|||
module</span> |
|||
</div> |
|||
<img src="assets/misc/right-arrow.png" width="36" height="36" /> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
<!-- END OF NAVIGATION SECTION --> |
|||
|
|||
<!-- OVERVIEW SECTION --> |
|||
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="overview"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/pie-chart.png" /> |
|||
</div> |
|||
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Overview |
|||
</h2> |
|||
</div> |
|||
<div class="row" style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;"> |
|||
<div class="col-sm-12 py-4"> |
|||
In this dashboard you can get all the details about project module. |
|||
</div> |
|||
|
|||
</div> |
|||
<!-- END OF OVERVIEW SECTION --> |
|||
|
|||
<!-- FEATURES SECTION --> |
|||
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="features"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/features.png" /> |
|||
</div> |
|||
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Features |
|||
</h2> |
|||
</div> |
|||
<div class="row" style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;"> |
|||
<div class="col-sm-12 col-md-6"> |
|||
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px"> |
|||
<img src="assets/misc/check-box.png" class="mr-2" /> |
|||
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">User can see all details about project and task through graphs.</span> |
|||
</div> |
|||
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px"> |
|||
<img src="assets/misc/check-box.png" class="mr-2" /> |
|||
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">User can see all details about timesheet through graphs.</span> |
|||
</div> |
|||
</div> |
|||
<div class="col-sm-12 col-md-6"> |
|||
|
|||
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px"> |
|||
<img src="assets/misc/check-box.png" class="mr-2" /> |
|||
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">User can see all projects with stages.</span> |
|||
</div> |
|||
<img src="assets/misc/check-box.png" class="mr-2" /> |
|||
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">User can use filter based on the employee, project and dates.</span> |
|||
</div> |
|||
</div> |
|||
<!-- END OF FEATURES SECTION --> |
|||
|
|||
<!-- SCREENSHOTS SECTION --> |
|||
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="screenshots"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/pictures.png" /> |
|||
</div> |
|||
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Screenshots |
|||
</h2> |
|||
</div> |
|||
<div class="row"> |
|||
<div class="col-sm-12"> |
|||
|
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Dynamic And Clickable Dashboard Tiles |
|||
|
|||
</h3> |
|||
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
|||
User can click the Tiles and States in tile,That shows the detailed view of corresponding tiles. |
|||
</p> |
|||
<img src="assets/screenshots/Screenshot.png" class="img-thumbnail"> |
|||
</div> |
|||
|
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Different Types of Graphs |
|||
</h3> |
|||
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">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-thumbnail"> |
|||
</div> |
|||
|
|||
<div style="display: block; margin: 30px auto;"> |
|||
<img src="assets/screenshots/Screenshot3.png" class="img-thumbnail"> |
|||
</div> |
|||
|
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Project Table |
|||
|
|||
</h3> |
|||
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">User can see all Project ad its current status. |
|||
</p> |
|||
<img src="assets/screenshots/Screenshot4.png" class="img-thumbnail"> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
<!-- END OF SCREENSHOTS SECTION --> |
|||
|
|||
<!-- RELATED PRODUCTS --> |
|||
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/categories.png" /> |
|||
</div> |
|||
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
|||
Related |
|||
Products |
|||
</h2> |
|||
</div> |
|||
<div class="row"> |
|||
<div class="col-sm-12"> |
|||
<div id="demo1" class="row carousel slide" data-ride="carousel"> |
|||
<!-- The slideshow --> |
|||
<div class="carousel-inner" style="padding: 30px;"> |
|||
<div class="carousel-item" style="min-height: 198.656px;"> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/16.0/website_repeat_sale/" target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" style="border-radius: 0px;" src="assets/modules/l1.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/16.0/woo_commerce/" target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" style="border-radius: 0px;" src="assets/modules/l2.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/16.0/shopify_odoo_connector/" target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" style="border-radius: 0px;" src="assets/modules/l3.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
<div class="carousel-item active" style="min-height: 198.656px;"> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/16.0/odoo_dynamic_dashboard/" target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" style="border-radius: 0px;" src="assets/modules/l4.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/16.0/custom_gantt_view/" target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" style="border-radius: 0px;" src="assets/modules/l5.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/16.0/pos_credit_limit/" target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" style="border-radius: 0px;" src="assets/modules/l6.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- Left and right controls --> |
|||
<a class="carousel-control-prev" href="#demo1" data-slide="prev" style="width:35px; color:#000"> <span class="carousel-control-prev-icon"><i class="fa fa-chevron-left" style="font-size:24px"></i></span> |
|||
</a> <a class="carousel-control-next" href="#demo1" data-slide="next" style="width:35px; color:#000"> |
|||
<span class="carousel-control-next-icon"><i class="fa fa-chevron-right" style="font-size:24px"></i></span> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END OF RELATED PRODUCTS --> |
|||
|
|||
<!-- OUR SERVICES --> |
|||
|
|||
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/star.png" /> |
|||
</div> |
|||
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
|||
Our Services |
|||
</h2> |
|||
</div> |
|||
|
|||
<div class="container my-5"> |
|||
<div class="row"> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/cogs.png" class="img-responsive" height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Customization</h6> |
|||
</div> |
|||
|
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/wrench.png" class="img-responsive" height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Implementation</h6> |
|||
</div> |
|||
|
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/lifebuoy.png" class="img-responsive" height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Support</h6> |
|||
</div> |
|||
|
|||
|
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/user.png" class="img-responsive" height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Hire |
|||
Odoo |
|||
Developer</h6> |
|||
</div> |
|||
|
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" style="background-color: #54a0ff !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/puzzle.png" class="img-responsive" height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Integration</h6> |
|||
</div> |
|||
|
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/update.png" class="img-responsive" height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Migration</h6> |
|||
</div> |
|||
|
|||
|
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/consultation.png" class="img-responsive" height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Consultancy</h6> |
|||
</div> |
|||
|
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/training.png" class="img-responsive" height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Implementation</h6> |
|||
</div> |
|||
|
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/license.png" class="img-responsive" height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Licensing Consultancy</h6> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
|
|||
<!-- END OF OUR SERVICES --> |
|||
|
|||
<!-- OUR INDUSTRIES --> |
|||
|
|||
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/corporate.png" /> |
|||
</div> |
|||
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
|||
Our |
|||
Industries |
|||
</h2> |
|||
</div> |
|||
|
|||
<div class="container my-5"> |
|||
<div class="row"> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/trading-black.png" class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Trading |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Easily procure |
|||
and |
|||
sell your products</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/pos-black.png" class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
POS |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Easy |
|||
configuration |
|||
and convivial experience</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/education-black.png" class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Education |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
A platform for |
|||
educational management</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/manufacturing-black.png" class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Manufacturing |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Plan, track and |
|||
schedule your operations</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/ecom-black.png" class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
E-commerce & Website |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Mobile |
|||
friendly, |
|||
awe-inspiring product pages</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/service-black.png" class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Service Management |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Keep track of |
|||
services and invoice</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/restaurant-black.png" class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Restaurant |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Run your bar or |
|||
restaurant methodically</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/hotel-black.png" class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Hotel Management |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
An |
|||
all-inclusive |
|||
hotel management application</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- END OF OUR INDUSTRIES --> |
|||
|
|||
<!-- SUPPORT --> |
|||
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/customer-support.png" /> |
|||
</div> |
|||
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
|||
Support |
|||
</h2> |
|||
</div> |
|||
<div class="container mt-5"> |
|||
<div class="row"> |
|||
<div class="col-sm-12 col-md-6"> |
|||
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;"> |
|||
<div class="mr-4" style="background-color: #714B67; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;"> |
|||
<img src="assets/misc/support.png" height="48" width="48" style="width: 42px; height: 42px;" /> |
|||
</div> |
|||
<div> |
|||
<h4>Need Help?</h4> |
|||
<p style="line-height: 100%;">Got questions or need help? |
|||
Get in touch.</p> |
|||
<a href="mailto:odoo@cybrosys.com"> |
|||
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;"> |
|||
odoo@cybrosys.com</p> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-sm-12 col-md-6"> |
|||
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;"> |
|||
<div class="mr-4" style="background-color: #2AC44D; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;"> |
|||
<img src="assets/misc/whatsapp.png" height="52" width="52" style="width: 52px; height: 52px;" /> |
|||
</div> |
|||
<div> |
|||
<h4>WhatsApp</h4> |
|||
<p style="line-height: 100%;">Say hi to us on WhatsApp!</p> |
|||
<a href="https://api.whatsapp.com/send?phone=918606827707"> |
|||
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;"> |
|||
+91 86068 |
|||
27707</p> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="row"> |
|||
<div class="col-sm-12 my-5 d-flex justify-content-center align-items-center"> |
|||
<img src="assets/misc/logo.png" width="144" height="31" style="width:144px; height: 31px; margin-top: 40px;" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END OF SUPPORT --> |
@ -0,0 +1,426 @@ |
|||
.oh-card h4 { |
|||
font-size: 1.1rem; |
|||
} |
|||
|
|||
.stat-icon { |
|||
display: inline-block; |
|||
} |
|||
|
|||
.stat-widget-one .stat-icon { |
|||
vertical-align: top; |
|||
margin: auto; |
|||
width: 100%; |
|||
} |
|||
|
|||
.stat-widget-one .stat-icon i { |
|||
font-size: 30px; |
|||
font-weight: 900; |
|||
display: inline-block; |
|||
color: #01c490; |
|||
} |
|||
|
|||
.stat-widget-one .stat-text { |
|||
font-size: 14px; |
|||
color: #868e96; |
|||
font-weight: bold; |
|||
|
|||
} |
|||
|
|||
.stat-widget-one .stat-digit { |
|||
font-size: 24px; |
|||
color: #02448b; |
|||
} |
|||
|
|||
.stat_count { |
|||
font-size: 28px !important; |
|||
} |
|||
|
|||
body .text-color { |
|||
color: #00438b; |
|||
} |
|||
/* 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; |
|||
} |
|||
|
|||
.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; |
|||
} |
|||
|
|||
|
|||
/*=====================New Dashboard===========================*/ |
|||
|
|||
.oh_dashboards { |
|||
background-color: #f8faff !important; |
|||
padding: 0px !important; |
|||
|
|||
} |
|||
|
|||
.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; |
|||
|
|||
} |
|||
|
|||
.oh-card { |
|||
|
|||
padding-top: 0px; |
|||
padding: 0px; |
|||
margin-bottom: 1.5rem; |
|||
border-radius: 0px; |
|||
box-shadow: none; |
|||
background: none; |
|||
transition: transform 0.2s ease, box-shadow 0.2s ease; |
|||
will-change: transform, box-shadow; |
|||
|
|||
} |
|||
|
|||
.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; |
|||
|
|||
} |
|||
|
|||
.media-body.employee-name { |
|||
|
|||
background: #466b8d; |
|||
float: left; |
|||
margin: 0; |
|||
width: 100% |
|||
} |
|||
|
|||
.oh-payslip { |
|||
|
|||
margin-top: 1.5%; |
|||
|
|||
} |
|||
|
|||
.oh-payslip .stat-icon { |
|||
|
|||
width: 30%; |
|||
height: 85px; |
|||
text-align: center; |
|||
padding-top: 2%; |
|||
color: #fff; |
|||
|
|||
} |
|||
|
|||
.oh-payslip .oh-card { |
|||
|
|||
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); |
|||
|
|||
} |
|||
|
|||
.stat-widget-one .stat-text { |
|||
|
|||
font-size: 14px; |
|||
color: #ff8762; |
|||
margin-top: 2.3rem; |
|||
margin-left: 1rem; |
|||
|
|||
} |
|||
|
|||
.stat-widget-one .stat-digit { |
|||
|
|||
font-size: 17px; |
|||
color: #000; |
|||
margin-left: 1rem; |
|||
padding-left: 26px; |
|||
|
|||
} |
|||
|
|||
.stat-widget-one .stat-icon i { |
|||
font-size: 32px; |
|||
display: inline-block; |
|||
color: #000; |
|||
top: 16px; |
|||
position: relative; |
|||
} |
|||
|
|||
.stat-widget-one { |
|||
|
|||
background-color: white; |
|||
text-align: inherit !important; |
|||
|
|||
} |
|||
|
|||
.stat-widget-one { |
|||
width: 100%; |
|||
} |
|||
|
|||
.oh-payslip .stat-icon { |
|||
|
|||
width: 30%; |
|||
height: 85px; |
|||
text-align: center; |
|||
padding-top: 2%; |
|||
|
|||
} |
|||
|
|||
|
|||
h4 .stat-count { |
|||
font-size: 17px; |
|||
text-align: center; |
|||
color: #000 !important; |
|||
margin-top: 0px; |
|||
width: 100%; |
|||
float: left; |
|||
margin: 0; |
|||
} |
|||
|
|||
.hr-chart-1 { |
|||
margin: 15px 0px; |
|||
background: #fff; |
|||
padding: 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); |
|||
} |
|||
|
|||
.hr-chart-1:hover { |
|||
transform: translateY(-2px) translateZ(0) !important; |
|||
box-shadow: 0 10px 10px 0 rgba(62, 57, 107, 0.12), 0 0 0 transparent !important; |
|||
} |
|||
|
|||
.stat-head { |
|||
text-align: center !important; |
|||
font-weight: 300; |
|||
font-size: 21px; |
|||
margin-bottom: 12px; |
|||
margin-left: 2px; |
|||
} |
|||
|
|||
|
|||
.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: 757px; |
|||
margin-bottom: 15px; |
|||
} |
|||
|
|||
.hr_notification .media { |
|||
border-bottom: 1px solid #e6e6e6; |
|||
padding-bottom: 6px; |
|||
margin-bottom: 10px; |
|||
} |
|||
|
|||
.hr_notification .text-color.display-6 { |
|||
margin: 0px 0 3px; |
|||
color: #2d2d2d; |
|||
} |
|||
|
|||
.hr_notification p { |
|||
margin: 0 0 1px; |
|||
color: #666; |
|||
font-size: 10px; |
|||
} |
|||
|
|||
.hr_notification_head { |
|||
font-size: 17px; |
|||
text-align: center; |
|||
padding: 12px 0; |
|||
color: #fff; |
|||
font-weight: 300; |
|||
background: #5ebade; |
|||
margin-bottom: 9px; |
|||
} |
|||
|
|||
.hr-chart-1 { |
|||
margin: 15px 0px; |
|||
background: #fff; |
|||
padding: 0px !important; |
|||
padding-top: 0px; |
|||
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-top: 3px !important; |
|||
} |
|||
|
|||
/* width */ |
|||
.hr_notification::-webkit-scrollbar { |
|||
width: 4px; |
|||
} |
|||
|
|||
/* Track */ |
|||
.hr_notification::-webkit-scrollbar-track { |
|||
background: #f1f1f1; |
|||
} |
|||
|
|||
/* Handle */ |
|||
.hr_notification::-webkit-scrollbar-thumb { |
|||
background: #495057; |
|||
; |
|||
} |
|||
|
|||
/* Handle on hover */ |
|||
.hr_notification::-webkit-scrollbar-thumb:hover { |
|||
background: #598da1; |
|||
} |
|||
|
|||
.oh-card-body { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
} |
|||
|
|||
.text-align { |
|||
margin-left: 17px; |
|||
} |
|||
|
|||
.inner_select { |
|||
min-width: 150px |
|||
} |
|||
|
|||
#table_status { |
|||
width: 90%; |
|||
margin-left: 5%; |
|||
font-family: Arial, Helvetica, sans-serif; |
|||
} |
|||
|
|||
#table_status tr:nth-child(even) { |
|||
background-color: #f2f2f2; |
|||
} |
|||
|
|||
#table_status tr:hover { |
|||
background-color: #ddd; |
|||
} |
|||
|
|||
.fleet-pill { |
|||
align-items: center; |
|||
font-family: "Open Sans", Arial, Verdana, sans-serif; |
|||
font-weight: bold; |
|||
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; |
|||
} |
|||
|
|||
.inner_select p { |
|||
margin-left: 20px |
|||
} |
@ -0,0 +1,483 @@ |
|||
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 web_client = require('web.web_client'); |
|||
var ProjectDashboard = AbstractAction.extend({ |
|||
template: 'ProjectDashboard', |
|||
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', |
|||
'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.today_sale = []; |
|||
}, |
|||
willStart: function() { |
|||
var self = this; |
|||
return $.when(this._super()).then(function() { |
|||
return self.fetch_data(); |
|||
}); |
|||
}, |
|||
start: function() { |
|||
var self = this; |
|||
this.set("title", 'Dashboard'); |
|||
return this._super().then(function() { |
|||
self.render_dashboards(); |
|||
self.render_graphs(); |
|||
self.render_filter(); |
|||
}); |
|||
}, |
|||
/** |
|||
rendering the dashboard |
|||
*/ |
|||
render_dashboards: function() { |
|||
var self = this; |
|||
_.each(this.dashboards_templates, function(template) { |
|||
self.$('.o_pj_dashboard').append(QWeb.render(template, { |
|||
widget: self |
|||
})); |
|||
}); |
|||
}, |
|||
/** |
|||
function for getting values to the filters |
|||
*/ |
|||
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>"); |
|||
}); |
|||
}) |
|||
}, |
|||
/** |
|||
function for getting values to the filters |
|||
*/ |
|||
_onchangeFilter: function() { |
|||
this.flag = 1 |
|||
var start_date = $('#start_date').val(); |
|||
var end_date = $('#end_date').val(); |
|||
var self = this; |
|||
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) { |
|||
self.tot_hrs = data['list_hours_recorded'] |
|||
self.tot_employee = data['total_emp'] |
|||
self.tot_project = data['total_project'] |
|||
self.tot_task = data['total_task'] |
|||
self.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 |
|||
}) |
|||
}, |
|||
/** |
|||
rendering the graph |
|||
*/ |
|||
render_graphs: function() { |
|||
var self = this; |
|||
self.render_project_task(); |
|||
self.render_top_employees_graph(); |
|||
}, |
|||
on_reverse_breadcrumb: function() { |
|||
var self = this; |
|||
web_client.do_push_state({}); |
|||
this.fetch_data().then(function() { |
|||
self.$('.o_pj_dashboard').empty(); |
|||
self.render_dashboards(); |
|||
self.render_graphs(); |
|||
}); |
|||
}, |
|||
/** |
|||
function for getting values to project graph |
|||
*/ |
|||
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' |
|||
}, |
|||
cutoutPercentage: 40, |
|||
responsive: true, |
|||
} |
|||
}); |
|||
}) |
|||
}, |
|||
/** |
|||
for opening project view |
|||
*/ |
|||
tot_projects: function(e) { |
|||
var self = this; |
|||
e.stopPropagation(); |
|||
e.preventDefault(); |
|||
var options = { |
|||
on_reverse_breadcrumb: this.on_reverse_breadcrumb, |
|||
}; |
|||
if (this.flag == 0) { |
|||
this.do_action({ |
|||
name: _t("Projects"), |
|||
type: 'ir.actions.act_window', |
|||
res_model: 'project.project', |
|||
domain: [ |
|||
["id", "in", this.total_projects_ids] |
|||
], |
|||
view_mode: 'kanban,form', |
|||
views: [ |
|||
[false, 'kanban'], |
|||
[false, 'form'] |
|||
], |
|||
target: 'current' |
|||
}, options) |
|||
} else { |
|||
if (this.tot_project) { |
|||
this.do_action({ |
|||
name: _t("Projects"), |
|||
type: 'ir.actions.act_window', |
|||
res_model: 'project.project', |
|||
domain: [ |
|||
["id", "in", this.tot_project] |
|||
], |
|||
view_mode: 'kanban,form', |
|||
views: [ |
|||
[false, 'kanban'], |
|||
[false, 'form'] |
|||
], |
|||
target: 'current' |
|||
}, options) |
|||
} |
|||
} |
|||
}, |
|||
/** |
|||
for opening project task view |
|||
*/ |
|||
tot_tasks: function(e) { |
|||
var self = this; |
|||
e.stopPropagation(); |
|||
e.preventDefault(); |
|||
var options = { |
|||
on_reverse_breadcrumb: this.on_reverse_breadcrumb, |
|||
}; |
|||
this.do_action({ |
|||
name: _t("Tasks"), |
|||
type: 'ir.actions.act_window', |
|||
res_model: 'project.task', |
|||
domain: [ |
|||
["id", "in", self.tot_task] |
|||
], |
|||
view_mode: 'tree,kanban,form', |
|||
views: [ |
|||
[false, 'list'], |
|||
[false, 'form'] |
|||
], |
|||
target: 'current' |
|||
}, options) |
|||
}, |
|||
/** |
|||
for opening margin view |
|||
*/ |
|||
tot_profitability: function(e) { |
|||
var self = this; |
|||
e.stopPropagation(); |
|||
e.preventDefault(); |
|||
var options = { |
|||
on_reverse_breadcrumb: this.on_reverse_breadcrumb, |
|||
}; |
|||
this.do_action({ |
|||
name: _t("Profitability"), |
|||
type: 'ir.actions.act_window', |
|||
res_model: 'project.project', |
|||
view_mode: 'pivot', |
|||
views: [ |
|||
[false, 'pivot'], |
|||
[false, 'graph'] |
|||
], |
|||
target: 'current' |
|||
}, options) |
|||
}, |
|||
/** |
|||
for opening account analytic line view |
|||
*/ |
|||
hr_recorded: function(e) { |
|||
var self = this; |
|||
e.stopPropagation(); |
|||
e.preventDefault(); |
|||
var options = { |
|||
on_reverse_breadcrumb: this.on_reverse_breadcrumb, |
|||
}; |
|||
if (this.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'] |
|||
], |
|||
target: 'current' |
|||
}, options) |
|||
} else { |
|||
if (this.tot_hrs) { |
|||
this.do_action({ |
|||
name: _t("Timesheets"), |
|||
type: 'ir.actions.act_window', |
|||
res_model: 'account.analytic.line', |
|||
domain: [ |
|||
["id", "in", this.tot_hrs] |
|||
], |
|||
view_mode: 'tree,form', |
|||
views: [ |
|||
[false, 'list'] |
|||
], |
|||
target: 'current' |
|||
}, options) |
|||
} |
|||
} |
|||
}, |
|||
/** |
|||
for opening sale order view |
|||
*/ |
|||
tot_sale: function(e) { |
|||
var self = this; |
|||
e.stopPropagation(); |
|||
e.preventDefault(); |
|||
var options = { |
|||
on_reverse_breadcrumb: this.on_reverse_breadcrumb, |
|||
}; |
|||
this.do_action({ |
|||
name: _t("Sale Order"), |
|||
type: 'ir.actions.act_window', |
|||
res_model: 'sale.order', |
|||
domain: [ |
|||
["id", "in", this.tot_so] |
|||
], |
|||
view_mode: 'tree,form', |
|||
views: [ |
|||
[false, 'list'], |
|||
[false, 'form'] |
|||
], |
|||
target: 'current' |
|||
}, options) |
|||
}, |
|||
/** |
|||
for opening total hr employee view |
|||
*/ |
|||
tot_emp: function(e) { |
|||
var self = this; |
|||
e.stopPropagation(); |
|||
e.preventDefault(); |
|||
var options = { |
|||
on_reverse_breadcrumb: this.on_reverse_breadcrumb, |
|||
}; |
|||
if (this.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'] |
|||
], |
|||
target: 'current' |
|||
}, options) |
|||
} else { |
|||
this.do_action({ |
|||
name: _t("Employees"), |
|||
type: 'ir.actions.act_window', |
|||
res_model: 'hr.employee', |
|||
domain: [ |
|||
["id", "in", this.tot_employee] |
|||
], |
|||
view_mode: 'tree,form', |
|||
views: [ |
|||
[false, 'list'], |
|||
[false, 'form'] |
|||
], |
|||
target: 'current' |
|||
}, options) |
|||
|
|||
} |
|||
}, |
|||
/** |
|||
function for getting values to employee graph |
|||
*/ |
|||
render_top_employees_graph: function() { |
|||
var self = this |
|||
var ctx = self.$(".top_selling_employees"); |
|||
rpc.query({ |
|||
model: "project.project", |
|||
method: 'get_top_timesheet_employees', |
|||
}).then(function(arrays) { |
|||
var data = { |
|||
labels: arrays[1], |
|||
datasets: [{ |
|||
label: "Hours Spent", |
|||
data: arrays[0], |
|||
backgroundColor: [ |
|||
"rgba(190, 27, 75,1)", |
|||
"rgba(31, 241, 91,1)", |
|||
"rgba(103, 23, 252,1)", |
|||
"rgba(158, 106, 198,1)", |
|||
"rgba(250, 217, 105,1)", |
|||
"rgba(255, 98, 31,1)", |
|||
"rgba(255, 31, 188,1)", |
|||
"rgba(75, 192, 192,1)", |
|||
"rgba(153, 102, 255,1)", |
|||
"rgba(10,20,30,1)" |
|||
], |
|||
borderColor: [ |
|||
"rgba(190, 27, 75, 0.2)", |
|||
"rgba(190, 223, 122, 0.2)", |
|||
"rgba(103, 23, 252, 0.2)", |
|||
"rgba(158, 106, 198, 0.2)", |
|||
"rgba(250, 217, 105, 0.2)", |
|||
"rgba(255, 98, 31, 0.2)", |
|||
"rgba(255, 31, 188, 0.2)", |
|||
"rgba(75, 192, 192, 0.2)", |
|||
"rgba(153, 102, 255, 0.2)", |
|||
"rgba(10,20,30,0.3)" |
|||
], |
|||
borderWidth: 1 |
|||
}, |
|||
|
|||
] |
|||
}; |
|||
//options
|
|||
var options = { |
|||
responsive: true, |
|||
title: { |
|||
display: true, |
|||
position: "top", |
|||
text: " Time by Employees", |
|||
fontSize: 18, |
|||
fontColor: "#111" |
|||
}, |
|||
legend: { |
|||
display: false, |
|||
}, |
|||
scales: { |
|||
yAxes: [{ |
|||
ticks: { |
|||
min: 0 |
|||
} |
|||
}] |
|||
} |
|||
}; |
|||
//create Chart class object
|
|||
var chart = new Chart(ctx, { |
|||
type: 'bar', |
|||
data: data, |
|||
options: options |
|||
}); |
|||
|
|||
}); |
|||
}, |
|||
/** |
|||
function for getting values when page is loaded |
|||
*/ |
|||
fetch_data: function() { |
|||
this.flag = 0 |
|||
var self = this; |
|||
var def1 = this._rpc({ |
|||
model: 'project.project', |
|||
method: 'get_tiles_data' |
|||
}).then(function(result) { |
|||
if (result['flag'] == 1) { |
|||
self.total_projects = result['total_projects'] |
|||
self.total_tasks = result['total_tasks'] |
|||
self.tot_task = result['total_tasks_ids'] |
|||
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.project_stage_list = result['project_stage_list'] |
|||
self.tot_so = result['sale_orders_ids'] |
|||
self.flag_user = result['flag'] |
|||
self.total_projects_ids = result['total_projects_ids'] |
|||
} else { |
|||
self.tot_task = result['total_tasks_ids'] |
|||
self.total_projects = result['total_projects'] |
|||
self.total_tasks = result['total_tasks'] |
|||
self.total_hours = result['total_hours'] |
|||
self.total_sale_orders = result['total_sale_orders'] |
|||
self.project_stage_list = result['project_stage_list'] |
|||
self.flag_user = result['flag'] |
|||
self.tot_so = result['sale_orders_ids'] |
|||
self.total_projects_ids = result['total_projects_ids'] |
|||
} |
|||
}); |
|||
/** |
|||
function for getting values to hours table |
|||
*/ |
|||
var def3 = self._rpc({ |
|||
model: "project.project", |
|||
method: "get_hours_data", |
|||
}) |
|||
.then(function(res) { |
|||
self.hour_recorded = res['hour_recorded']; |
|||
self.hour_recorde = res['hour_recorde']; |
|||
self.billable_fix = res['billable_fix']; |
|||
self.non_billable = res['non_billable']; |
|||
self.total_hr = res['total_hr']; |
|||
}); |
|||
|
|||
var def4 = self._rpc({ |
|||
model: "project.project", |
|||
method: "get_task_data", |
|||
}) |
|||
.then(function(res) { |
|||
self.task_data = res['project']; |
|||
}); |
|||
return $.when(def1, def3, def4); |
|||
}, |
|||
}); |
|||
core.action_registry.add('project_dashboard', ProjectDashboard); |
|||
return ProjectDashboard; |
|||
}); |
@ -0,0 +1,322 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<!-- Template for the project dashboard --> |
|||
<templates id="template" xml:space="preserve"> |
|||
<t t-name="ProjectDashboard"> |
|||
<div class="oh_dashboards" style="margin-top: 20px; overflow-y: scroll;vertical-align: middle;overflow-x: clip;max-height: -webkit-fill-available;"> |
|||
<div class="container-fluid o_pj_dashboard" style="margin-left:4%;"> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
<t t-name="DashboardProject"> |
|||
<div class="row main-section"> |
|||
<t t-if="widget.flag_user == 1"> |
|||
<div class="inner_select" style="display: flex;"> |
|||
<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> |
|||
</t> |
|||
<div class="col-md-4 col-sm-6 oh-payslip"> |
|||
<div class="oh-card" style="width: 410px;"> |
|||
<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> |
|||
<t t-if="widget.flag_user == 1"> |
|||
<div class="col-md-4 col-sm-6 oh-payslip"> |
|||
<div class="oh-card" style="width: 410px;"> |
|||
<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> |
|||
</t> |
|||
<div class="col-md-4 col-sm-6 oh-payslip"> |
|||
<div class="oh-card" style="width: 410px;"> |
|||
<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> |
|||
<t t-if="widget.flag_user == 1"> |
|||
<div class="col-md-4 col-sm-6 oh-payslip"> |
|||
<div class="oh-card" style="width: 410px;"> |
|||
<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> |
|||
</t> |
|||
<t t-if="widget.flag_user == 1"> |
|||
<div class="col-md-4 col-sm-6 oh-payslip"> |
|||
<div class="oh-card" style="width: 410px;"> |
|||
<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 Margin</div> |
|||
<div class="stat_count" style="padding: 4%;width: 30%;" id="tot_margin"> |
|||
<t t-esc="widget.total_profitability" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
<div class="col-md-4 col-sm-6 oh-payslip"> |
|||
<div class="oh-card" style="width: 410px;"> |
|||
<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> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
|
|||
<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="graph_view" style="box-shadow:5px 11px 30px;"> |
|||
<div class="text-color hr-chart-1"> |
|||
<div class="oh-card-body pb-0" style="text-align:center;"> |
|||
<h2 style="margin-left:45%;padding-top:2%;">Project Task Analysis</h2> |
|||
</div> |
|||
<canvas id="project_doughnut" style="background:#fff;" width="200" height="120" /> |
|||
</div> |
|||
</div> |
|||
<div class="selling_product_graph_view" style="box-shadow:5px 11px 30px;"> |
|||
<div class="oh-card text-color"> |
|||
<canvas class="top_selling_employees" style="background:#fff;" width="200" height="120" /> |
|||
</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: 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" style="overflow-y: auto;height: 704px;"> |
|||
<div class="media-body"> |
|||
<table class="table table-sm"> |
|||
<thead> |
|||
<tr> |
|||
<th rowspan="14">Project Name</th> |
|||
<th rowspan="14">Task Name</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
<t t-foreach="widget.task_data" t-as="proj"> |
|||
<tr> |
|||
<td> |
|||
<t t-if="widget.flag_user == 1"> |
|||
<t t-esc="proj[1]['en_US']" /> |
|||
</t> |
|||
<t t-els=""> |
|||
<t t-esc="proj[1]" /> |
|||
</t> |
|||
</td> |
|||
<td> |
|||
<t t-esc="proj[0]" /> |
|||
</td> |
|||
</tr> |
|||
</t> |
|||
</tbody> |
|||
</table> |
|||
</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: 356px;margin-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;"> |
|||
Hours Recorded |
|||
</div> |
|||
<div class="col-sm-12 col-lg-12" style="padding:0;"> |
|||
<div class="text-color"> |
|||
<div class=""> |
|||
<div class="media"> |
|||
<div class="media-body"> |
|||
<table class="table table-sm"> |
|||
<thead> |
|||
<tr> |
|||
<th rowspan="14">Billed on Timesheet</th> |
|||
</tr> |
|||
|
|||
</thead> |
|||
<tbody> |
|||
<t t-foreach="widget.hour_recorde" t-as="hour_recorde"> |
|||
<tr> |
|||
<td> |
|||
<h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;"> |
|||
<t t-esc="hour_recorde" /> |
|||
</h2> |
|||
</td> |
|||
</tr> |
|||
</t> |
|||
</tbody> |
|||
</table> |
|||
<table class="table table-sm"> |
|||
<thead> |
|||
<tr> |
|||
<th rowspan="14">Billed at a Fixed price</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
<t t-foreach="widget.billable_fix" t-as="billable_fix"> |
|||
<tr> |
|||
<td> |
|||
<h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;"> |
|||
<t t-esc="billable_fix" /> |
|||
</h2> |
|||
</td> |
|||
</tr> |
|||
</t> |
|||
</tbody> |
|||
</table> |
|||
<table class="table table-sm"> |
|||
<thead> |
|||
<tr> |
|||
<th rowspan="14">No task found</th> |
|||
</tr> |
|||
|
|||
</thead> |
|||
<tbody> |
|||
<t t-foreach="widget.hour_recorded" t-as="hour_recorded"> |
|||
<tr> |
|||
|
|||
<td> |
|||
<h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;"> |
|||
|
|||
<t t-esc="hour_recorded" /> |
|||
</h2> |
|||
</td> |
|||
</tr> |
|||
</t> |
|||
</tbody> |
|||
</table> |
|||
<table class="table table-sm"> |
|||
<thead> |
|||
<tr> |
|||
<th rowspan="14">Non Billable Tasks</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
<t t-foreach="widget.non_billable" t-as="non_billable"> |
|||
<tr> |
|||
<td> |
|||
<h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;"> |
|||
|
|||
<t t-esc="non_billable" /> |
|||
</h2> |
|||
</td> |
|||
</tr> |
|||
</t> |
|||
</tbody> |
|||
</table> |
|||
<table class="table table-sm"> |
|||
<thead> |
|||
<tr> |
|||
<th rowspan="14" style="padding-left: 24.3rem;">Total:</th> |
|||
</tr> |
|||
|
|||
</thead> |
|||
<tbody> |
|||
<t t-foreach="widget.total_hr" t-as="total_hr"> |
|||
<tr> |
|||
|
|||
<td> |
|||
<h2 class="text-color display-6" style="font-size: 15px;margin-left: 400px;margin-top: -30px;"> |
|||
|
|||
<t t-esc="total_hr" /> |
|||
</h2> |
|||
</td> |
|||
</tr> |
|||
</t> |
|||
</tbody> |
|||
</table> |
|||
</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="fleet-pill" t-esc="data['projects']" /> |
|||
</td> |
|||
</tr> |
|||
</t> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
</templates> |
@ -0,0 +1,16 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<data> |
|||
<!-- action for project dashboard--> |
|||
<record id="project_action_dashboard" model="ir.actions.client"> |
|||
<field name="name">Dashboard</field> |
|||
<field name="tag">project_dashboard</field> |
|||
</record> |
|||
<!-- Dashboard menu item --> |
|||
<menuitem id="menu_project_dashboard" |
|||
name="Dashboard" |
|||
action="project_action_dashboard" |
|||
parent="project.menu_main_pm" |
|||
sequence="1"/> |
|||
</data> |
|||
</odoo> |