New Project timeline report added
This commit is contained in:
parent
efb5cd0836
commit
ab52aa7ff4
|
@ -19,6 +19,7 @@
|
|||
#'views/project_view.xml',
|
||||
'report/project_budget_hrs_analysis_views.xml',
|
||||
'report/project_budget_amt_analysis_views.xml',
|
||||
'report/project_timeline_report_views.xml',
|
||||
],
|
||||
'qweb': [
|
||||
"static/src/xml/base.xml",
|
||||
|
|
|
@ -3,3 +3,4 @@
|
|||
|
||||
from . import project_budget_hrs_analysis
|
||||
from . import project_budget_amt_analysis
|
||||
from . import project_timeline_report
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models, tools, api
|
||||
|
||||
|
||||
class ProjectTimelineReport(models.Model):
|
||||
|
||||
_name = "project.timeline.report"
|
||||
_description = "Project Timeline Report"
|
||||
#_order = 'project_id'
|
||||
_auto = False
|
||||
|
||||
#analytic_account_id = fields.Many2one('account.analytic.account', string='Analytic Account', readonly=True)
|
||||
project_id = fields.Many2one('project.project', string='Project', readonly=True)
|
||||
parent_project = fields.Many2one('project.project', string='Parent Project', readonly=True)
|
||||
#is_sub_project = fields.Boolean("Is Sub Project", readonly=True)
|
||||
#sub_project = fields.Many2one('project.project', string='Sub Project', readonly=True)
|
||||
start_date = fields.Date(string='Start Date', readonly=True)
|
||||
end_date = fields.Date(string='End Date', readonly=True)
|
||||
partner_id = fields.Many2one('res.partner', string='Client', readonly=True)
|
||||
employee_id = fields.Many2one('hr.employee', string='Consultant', readonly=True)
|
||||
timeline_type = fields.Char(string="Timeline Type", readonly=True)
|
||||
timeline = fields.Float("Timeline", digits=(16, 2), readonly=True, group_operator="sum")
|
||||
pricing_type = fields.Selection([
|
||||
('fixed_rate', 'Fixed rate'),
|
||||
('employee_rate', 'Consultant rate')
|
||||
], string="Pricing", readonly=True)
|
||||
project_type = fields.Selection([
|
||||
('hours_in_consultant', 'Hours are budgeted according to a consultant'),
|
||||
('hours_no_limit', 'Total hours are budgeted without division to consultant'),
|
||||
], string="Project Type", readonly=True)
|
||||
|
||||
def init(self):
|
||||
'''Create the view'''
|
||||
tools.drop_view_if_exists(self._cr, self._table)
|
||||
self._cr.execute("""
|
||||
CREATE OR REPLACE VIEW %s AS (
|
||||
SELECT
|
||||
ROW_NUMBER() OVER() as id,
|
||||
project_id,
|
||||
parentproject as parent_project,
|
||||
startdate as start_date,
|
||||
enddate as end_date,
|
||||
pricing_type as pricing_type,
|
||||
project_type as project_type,
|
||||
partner_id,
|
||||
employee_id,
|
||||
timeline_type,
|
||||
timeline from (
|
||||
SELECT
|
||||
pro.id AS project_id,
|
||||
(select project_id from project_subproject_rel as par where pro.id=par.id limit 1) as parentproject,
|
||||
pro_emp.employee_id AS employee_id,
|
||||
date_start AS startdate,
|
||||
date AS enddate,
|
||||
'Budgeted' as timeline_type,
|
||||
--DATE_PART('day', AGE(date, date_start)) AS timeline,
|
||||
pro_emp.budgeted_qty as timeline,
|
||||
pro.*
|
||||
FROM
|
||||
project_project PRO
|
||||
Left JOIN project_sale_line_employee_map pro_emp ON pro_emp.project_id = pro.id
|
||||
Where
|
||||
pro.active = 't'
|
||||
and PRO.pricing_type = 'employee_rate' and PRO.project_type = 'hours_in_consultant'
|
||||
Union all
|
||||
SELECT
|
||||
pro.id AS project_id,
|
||||
(select project_id from project_subproject_rel as par where pro.id=par.id limit 1) as parentproject,
|
||||
null::int AS employee_id,
|
||||
date_start AS startdate,
|
||||
date AS enddate,
|
||||
'Budgeted' as timeline_type,
|
||||
--DATE_PART('day', AGE(date, date_start)) AS timeline,
|
||||
pro.budgeted_hours2 as timeline,
|
||||
pro.*
|
||||
FROM
|
||||
project_project PRO
|
||||
Where
|
||||
pro.active = 't'
|
||||
and PRO.pricing_type = 'employee_rate' and PRO.project_type = 'hours_no_limit'
|
||||
Union all
|
||||
SELECT
|
||||
pro.id AS project_id,
|
||||
(select project_id from project_subproject_rel as par where pro.id=par.id limit 1) as parentproject,
|
||||
AAL.employee_id AS employee_id,
|
||||
start_datetime::DATE AS startdate,
|
||||
end_datetime::DATE AS enddate,
|
||||
'Actual' as timeline_type,
|
||||
--DATE_PART('day', AGE(end_datetime, start_datetime)) AS timeline,
|
||||
unit_amount as timeline,
|
||||
pro.*
|
||||
FROM project_project PRO
|
||||
Left JOIN project_sale_line_employee_map pro_emp ON pro_emp.project_id = pro.id
|
||||
LEFT JOIN account_analytic_account AA ON PRO.analytic_account_id = AA.id
|
||||
LEFT JOIN account_analytic_line AAL ON AAL.account_id = AA.id and AAL.project_id = PRO.id and AAL.employee_id = pro_emp.employee_id
|
||||
Where
|
||||
PRO.active = 't' and PRO.pricing_type = 'employee_rate'
|
||||
Union all
|
||||
SELECT
|
||||
pro.id AS project_id,
|
||||
(select project_id from project_subproject_rel as par where pro.id=par.id limit 1) as parentproject,
|
||||
AAL.employee_id AS employee_id,
|
||||
start_datetime::DATE AS startdate,
|
||||
end_datetime::DATE AS enddate,
|
||||
'Actual' as timeline_type,
|
||||
--DATE_PART('day', AGE(end_datetime, start_datetime)) AS timeline,
|
||||
unit_amount as timeline,
|
||||
pro.*
|
||||
FROM project_project PRO
|
||||
LEFT JOIN account_analytic_account AA ON PRO.analytic_account_id = AA.id
|
||||
LEFT JOIN account_analytic_line AAL ON AAL.account_id = AA.id and AAL.project_id = PRO.id
|
||||
--and AAL.employee_id = pro_emp.employee_id
|
||||
Where
|
||||
PRO.active = 't'
|
||||
and PRO.pricing_type = 'fixed_rate'
|
||||
) as res
|
||||
order by
|
||||
project_id desc,
|
||||
--start_date,
|
||||
--end_date desc,
|
||||
--pricing_type,
|
||||
--project_type,
|
||||
timeline_type desc
|
||||
--employee_id
|
||||
)""" % (self._table,))
|
||||
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="project_timeline_report_view_pivot" model="ir.ui.view">
|
||||
<field name="name">project.timeline.report.pivot</field>
|
||||
<field name="model">project.timeline.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Budget Analysis" disable_linking="True" sample="1"> <!-- display_quantity="true" -->
|
||||
<field name="project_id" type="col"/>
|
||||
<field name="timeline_type" type="col"/>
|
||||
<field name="timeline" type="measure"/>
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="project_timeline_report_view_graph" model="ir.ui.view">
|
||||
<field name="name">project.timeline.report.graph</field>
|
||||
<field name="model">project.timeline.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Budget Analysis" type="bar" stacked="False" sample="1" disable_linking="1">
|
||||
<field name="project_id" type="row"/>
|
||||
<field name="timeline_type" type="row"/>
|
||||
<field name="timeline" type="measure"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="project_timeline_report_view_tree" model="ir.ui.view">
|
||||
<field name="name">project.timeline.report.tree</field>
|
||||
<field name="model">project.timeline.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Budget Analysis" create="false" edit="false" delete="false">
|
||||
<field name="project_id"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
<field name="employee_id"/>
|
||||
<!--<field name="timesheet_date" optional="hide"/>-->
|
||||
<field name="timeline_type"/>
|
||||
<field name="timeline"/>
|
||||
<field name="parent_project" optional="hide"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="project_timeline_report_view_search" model="ir.ui.view">
|
||||
<field name="name">project.timeline.report.search</field>
|
||||
<field name="model">project.timeline.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Budget Analysis">
|
||||
<field name="project_id"/>
|
||||
<field name="partner_id" filter_domain="[('partner_id', 'child_of', self)]"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
<!--<field name="timesheet_date"/>-->
|
||||
<filter string="Fixed rate" name="fixed" domain="[('pricing_type','=','fixed_rate')]"/>
|
||||
<filter string="Hours are budgeted according to a consultant" name="cons" domain="[('project_type','=','hours_in_consultant')]"/>
|
||||
<filter string="Total hours are budgeted without division to consultant" name="limit" domain="[('project_type','=','hours_no_limit')]"/>
|
||||
<!--<filter string="Sub Project" name="subproject" domain="[('is_sub_project','=',True)]"/>-->
|
||||
<group expand="1" string="Group By">
|
||||
<filter string="Project" name="group_by_project" context="{'group_by':'project_id'}"/>
|
||||
<filter string="Client" name="group_by_partner_id" context="{'group_by':'partner_id'}"/>
|
||||
<filter string="Consultant" name="group_by_employee_id" context="{'group_by':'employee_id'}"/>
|
||||
<filter string="Start Date" name="sdate" domain="[]" context="{'group_by':'start_date:month'}"/>
|
||||
<filter string="End Date" name="edate" domain="[]" context="{'group_by':'end_date:month'}"/>
|
||||
<!--<filter string="Timesheet Date" name="tdate" domain="[]" context="{'group_by':'timesheet_date:day'}"/>-->
|
||||
<filter string="Hours type" name="group_by_timeline_type" context="{'group_by':'timeline_type'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="project_timeline_report_view_action" model="ir.actions.act_window">
|
||||
<field name="name">Projects Timeline Acutal Vs Budget</field>
|
||||
<field name="res_model">project.timeline.report</field>
|
||||
<field name="view_mode">graph,tree,pivot</field>
|
||||
<field name="search_view_id" ref="project_timeline_report_view_search"/>
|
||||
<field name="context">{'search_default_group_by_project': 1,'search_default_sdate': 1,'search_default_edate': 1,'search_default_group_by_timeline_type': 1, 'default_res_model':'project.timeline.report'}</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_project_timeline_report"
|
||||
parent="project.menu_project_report"
|
||||
action="project_timeline_report_view_action"
|
||||
name="Projects Timeline Acutal Vs Budget"
|
||||
sequence="60"/>
|
||||
|
||||
</odoo>
|
|
@ -5,3 +5,5 @@ access_project_create_expense_manager,access_project_create_expense_project_mana
|
|||
access_project_budget_hrs_report_user,project.budget.hrs.report.user,model_project_budget_hrs_report,project.group_project_user,1,0,0,0
|
||||
access_project_budget_amt_report_user,project.budget.amt.report.user,model_project_budget_amt_report,project.group_project_user,1,0,0,0
|
||||
access_project_create_expense_user,access_project_create_expense_project_user,model_project_create_expense,project.group_project_user,1,0,0,0
|
||||
access_project_timeline_report_manager,project.timeline.report,model_project_timeline_report,project.group_project_manager,1,1,1,1
|
||||
access_project_timeline_report_user,project.timeline.report,model_project_timeline_report,project.group_project_user,1,0,0,0
|
|
|
@ -348,7 +348,6 @@ var MAX_LEGEND_LENGTH = 25 * (1 + config.device.size_class);
|
|||
_getTooltipItems: function (tooltipModel) {
|
||||
var self = this;
|
||||
var data = this.chart.config.data;
|
||||
|
||||
var orderedItems = tooltipModel.dataPoints.sort(function (dPt1, dPt2) {
|
||||
return dPt2.yLabel - dPt1.yLabel;
|
||||
});
|
||||
|
@ -578,6 +577,7 @@ var MAX_LEGEND_LENGTH = 25 * (1 + config.device.size_class);
|
|||
var self = this;
|
||||
|
||||
// prepare data
|
||||
//console.log("datappppppppppp", dataPoints);
|
||||
var data = this._prepareData(dataPoints);
|
||||
|
||||
// this.title = 'Time Line';
|
||||
|
@ -658,6 +658,9 @@ var MAX_LEGEND_LENGTH = 25 * (1 + config.device.size_class);
|
|||
// used when stacked
|
||||
dataset.stack = self.state.stacked ? self.state.origins[dataset.originIndex] : undefined;
|
||||
// set dataset color
|
||||
if (self.state.stacked && dataset.label.includes("Actual")) {
|
||||
dataset.stack = 1;
|
||||
}
|
||||
if (self.resModel == 'project.budget.hrs.report') {
|
||||
//if (dataset.label.indexOf("Actual Hours") === -1 && dataset.label.toLowerCase().indexOf("Budgeted Hours") === -1) {
|
||||
if (dataset.label.indexOf("Actual") === -1 && dataset.label.toLowerCase().indexOf("Budgeted") === -1) {
|
||||
|
@ -715,6 +718,8 @@ var MAX_LEGEND_LENGTH = 25 * (1 + config.device.size_class);
|
|||
// prepare data
|
||||
var data = this._prepareData(dataPoints);
|
||||
|
||||
//console.log("datappppppppppp", dataPoints);
|
||||
|
||||
if (self.resModel == 'project.budget.hrs.report') {
|
||||
//var groupedData = _.groupBy(data.datasets, x => x.label.replace('Actual Hours', '').replace('Budgeted Hours', '').split("/")[0]);
|
||||
var groupedData = _.groupBy(data.datasets, x => x.label.replace('Actual', '').replace('Budgeted', '').split("/")[0]);
|
||||
|
@ -785,6 +790,9 @@ var MAX_LEGEND_LENGTH = 25 * (1 + config.device.size_class);
|
|||
// used when stacked
|
||||
dataset.stack = self.state.stacked ? self.state.origins[dataset.originIndex] : undefined;
|
||||
// set dataset color
|
||||
if (self.state.stacked && dataset.label.includes("Actual")) {
|
||||
dataset.stack = 1;
|
||||
}
|
||||
if (self.resModel == 'project.budget.hrs.report') {
|
||||
if (dataset.label.indexOf("Actual") === -1 && dataset.label.toLowerCase().indexOf("Budgeted") === -1) {
|
||||
var color = self._getColor(index);
|
||||
|
|
Loading…
Reference in New Issue