diff --git a/cor_custom/models/project.py b/cor_custom/models/project.py index 0ccbb0f..26f7b1e 100755 --- a/cor_custom/models/project.py +++ b/cor_custom/models/project.py @@ -51,6 +51,8 @@ class Project(models.Model): consultant_cost = fields.Float("Actual Cost", compute='_compute_calc') actual_revenue = fields.Float("Actual Revenue", compute='_compute_calc') other_expenses = fields.Float(string='Other Expenses', related='expenses_amt') + other_emp_hour = fields.Float("Other Employee Hour", compute='_compute_other_employee_cost') + other_emp_cost = fields.Float("Other Employee Cost", compute='_compute_other_employee_cost') total_expenses = fields.Float(string='Total Expenses', digits=(16, 2), compute='_compute_calc', store=True) hourly_rate = fields.Float("Hourly Rate", default=0.0) hourly_rate2 = fields.Float("Hourly Ratee") @@ -72,6 +74,7 @@ class Project(models.Model): project_cons_hrs = fields.One2many('project.consultant.hrs', 'project_id', 'Consultant Allocation', copy=False) comment = fields.Text(string='Comment') tag_ids = fields.Many2many('custom.project.tags', string='Tags') + is_check = fields.Boolean() @api.onchange('allowed_internal_user_ids') def onchange_add_allowed_internal_users(self): @@ -93,7 +96,7 @@ class Project(models.Model): if self._origin.id: if self.pricing_type == 'employee_rate': self.sale_line_employee_ids.create({'project_id': self._origin.id, - 'employee_id': employee}) + 'employee_id': employee}) def _onchange_calculate_timesheet_hours(self): self.consultant_timesheet_hrs = [(6, 0, False)] @@ -109,7 +112,28 @@ class Project(models.Model): 'employee_id': rec[1], 'timesheet_hour': rec[2]}) - @api.depends('cost', 'expenses_amt', 'budgeted_revenue') + def _compute_other_employee_cost(self): + for val in self: + #######Code for order line consultant + list1 = [] + if val.sale_line_employee_ids: + for record1 in val.sale_line_employee_ids: + list1.append(record1.employee_id.id) + if val._origin.id: + self._cr.execute('''SELECT project_id, employee_id, SUM(unit_amount), SUM(amount) FROM account_analytic_line + where project_id = %(project_id)s + GROUP BY project_id, employee_id''', {'project_id': val._origin.id}) + res = self._cr.fetchall() + hour = 0.0 + cost = 0.0 + for record2 in res: + if record2[1] not in list1: + hour = hour + record2[2] + cost = cost + abs(record2[3]) + val.other_emp_hour = hour + val.other_emp_cost = cost + + @api.depends('cost', 'expenses_amt', 'budgeted_revenue', 'is_check') def _compute_calc(self): for record in self: consultant_cost = 0.0 @@ -132,15 +156,16 @@ class Project(models.Model): record.actual_revenue = record.hourly_rate * timesheet_hour record.budgeted_hours = hour record.timesheet_hour = timesheet_hour - total_exp = record.consultant_cost + record.expenses_amt + #total_exp = record.consultant_cost + record.expenses_amt + total_exp = record.consultant_cost + record.other_emp_cost + record.expenses_amt record.total_expenses = total_exp - #record.profit_amt = record.budgeted_revenue - total_exp + # record.profit_amt = record.budgeted_revenue - total_exp # if record.profit_amt > 0 and record.budgeted_revenue > 0: # record.profit_per = (record.profit_amt / record.budgeted_revenue) * 100 ##### CR Changes - record.profit_amt = record.actual_revenue - record.consultant_cost - if record.profit_amt > 0: + record.profit_amt = record.actual_revenue - record.total_expenses + if record.actual_revenue > 0.0: record.profit_per = (record.profit_amt / record.actual_revenue) * 100 ######################## if record.project_type == 'hours_in_consultant' and record.budgeted_hours > 0.0: @@ -216,6 +241,7 @@ class Project(models.Model): 'default_res_model': 'project.consultant.hrs.report'} return action + class ProjectConsultantTimesheetHrs(models.Model): _name = 'consultant.timesheet.hrs' _description = 'Project Consultant Timesheet Hrs' @@ -354,4 +380,3 @@ class InheritProjectTask(models.Model): for stage in self: stage.write({'stage_id': stage_id.id, 'active': False}) - diff --git a/cor_custom/views/project_view.xml b/cor_custom/views/project_view.xml index f424b6f..f4dc19a 100755 --- a/cor_custom/views/project_view.xml +++ b/cor_custom/views/project_view.xml @@ -59,6 +59,7 @@ + @@ -110,6 +111,7 @@ + @@ -121,6 +123,7 @@ + diff --git a/project_report/__manifest__.py b/project_report/__manifest__.py index 8cae31e..902e0cd 100755 --- a/project_report/__manifest__.py +++ b/project_report/__manifest__.py @@ -21,6 +21,10 @@ 'report/project_budget_amt_analysis_views.xml', 'report/project_timeline_report_views.xml', 'report/project_timesheet_report_views.xml', + 'report/project_revenue_custom_report_views.xml', + 'report/project_revenue_custom_report2_views.xml', + 'report/project_consultant_custom_report_views.xml', + #'report/cor_project_report_views.xml', ], 'qweb': [ "static/src/xml/base.xml", diff --git a/project_report/report/__init__.py b/project_report/report/__init__.py index d635724..f1d2540 100755 --- a/project_report/report/__init__.py +++ b/project_report/report/__init__.py @@ -5,3 +5,7 @@ from . import project_budget_hrs_analysis from . import project_budget_amt_analysis from . import project_timeline_report from . import project_timesheet_report +from . import project_revenue_custom_report +from . import project_revenue_custom_report2 +from . import project_consultant_custom_report +#from . import cor_project_report diff --git a/project_report/report/cor_project_report.py b/project_report/report/cor_project_report.py new file mode 100755 index 0000000..6dcb1cc --- /dev/null +++ b/project_report/report/cor_project_report.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import fields, models, tools, api + + +class CorProjectReport(models.Model): + _name = "cor.project.report" + _description = "COR Project Report" + # _order = 'project_id' + _auto = False + + project_id = fields.Many2one('project.project', string='Project', readonly=True) + employee_id = fields.Many2one('hr.employee', string='Consultant', readonly=True) + #hours_type = fields.Char(string="Hours Type", readonly=True) + price_unit = fields.Float("Hourly Rate") + budgeted_qty = fields.Float(string='Budgeted Hours', digits=(16, 2)) + cost = fields.Float("Budgeted Revenue", default=0.0, store=True) + hours = fields.Float("Timesheet Hour", digits=(16, 2), readonly=True, group_operator="sum") + employee_price = fields.Float(string="Consultant Price") + consultant_cost = fields.Float("Actual Cost") + actual_revenue = fields.Float("Actual Revenue") + profit = fields.Float('Profit', digits=(16, 2)) + profit_per = fields.Float('Porfit(%)', digits=(16, 2)) + # 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, + aa.project_id AS project_id, + aa.employee_id AS employee_id, + bb.price_unit AS price_unit, + bb.budgeted_qty AS budgeted_qty, + bb.cost AS cost, + bb.employee_price AS employee_price, + SUM(aa.unit_amount) AS hours, + (SUM(aa.unit_amount) * bb.employee_price) AS consultant_cost, + (SUM(aa.unit_amount) * bb.price_unit) AS actual_revenue, + ((SUM(aa.unit_amount) * bb.price_unit)- (SUM(aa.unit_amount) * bb.employee_price)) AS profit, + ((((SUM(aa.unit_amount) * bb.price_unit)- (SUM(aa.unit_amount) * bb.employee_price))/(SUM(aa.unit_amount) * bb.price_unit))*100) AS profit_per + FROM account_analytic_line aa + Left JOIN project_sale_line_employee_map bb ON bb.project_id = aa.project_id and bb.employee_id = aa.employee_id + GROUP BY aa.project_id, aa.employee_id,bb.price_unit,bb.budgeted_qty,bb.cost,bb.employee_price + )""" % (self._table,)) diff --git a/project_report/report/cor_project_report_views.xml b/project_report/report/cor_project_report_views.xml new file mode 100755 index 0000000..3eefb93 --- /dev/null +++ b/project_report/report/cor_project_report_views.xml @@ -0,0 +1,79 @@ + + + + + cor.project.report.pivot + cor.project.report + + + + + + + + + + + cor.project.report.graph + cor.project.report + + + + + + + + + + + cor.project.report.tree + cor.project.report + + + + + + + + + + + + + + + + + + + + cor.project.report.search + cor.project.report + + + + + + + + + + + + + + + COR Project Report + cor.project.report + tree,pivot,graph + + {'search_default_group_by_project': 1, 'default_res_model': 'cor.project.report'} + + + + + diff --git a/project_report/report/project_budget_amt_analysis.py b/project_report/report/project_budget_amt_analysis.py index 70b411c..c5dce57 100755 --- a/project_report/report/project_budget_amt_analysis.py +++ b/project_report/report/project_budget_amt_analysis.py @@ -158,6 +158,4 @@ class BudgetAmtAnalysis(models.Model): project_id, amount_type desc --group by Pro.id, PRO.partner_id, Pro.budgeted_revenue, AAL.amount - )""" % (self._table,)) - - + )""" % (self._table,)) \ No newline at end of file diff --git a/project_report/report/project_budget_amt_analysis_views.xml b/project_report/report/project_budget_amt_analysis_views.xml index 2ae84af..4b9c9af 100755 --- a/project_report/report/project_budget_amt_analysis_views.xml +++ b/project_report/report/project_budget_amt_analysis_views.xml @@ -89,4 +89,4 @@ name="Projects Revenue Acutal Vs Budget" sequence="50"/> - + \ No newline at end of file diff --git a/project_report/report/project_consultant_custom_report.py b/project_report/report/project_consultant_custom_report.py new file mode 100755 index 0000000..2d5966e --- /dev/null +++ b/project_report/report/project_consultant_custom_report.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import fields, models, tools + + +class ProjectConsultantCustomReport(models.Model): + + _name = "project.consultant.custom.report" + _description = "Project Consultant Custom Analysis report" + #_order = 'project_id' + _auto = False + + project_id = fields.Many2one('project.project', string='Project', readonly=True) + parent_project = fields.Many2one('project.project', string='Parent Project', readonly=True) + partner_id = fields.Many2one('res.partner', string='Client', readonly=True) + employee_id = fields.Many2one('hr.employee', string='Consultant', readonly=True) + start_date = fields.Date(string='Start Date', readonly=True) + end_date = fields.Date(string='End Date', readonly=True) + percentage = fields.Float("Budgeted Percentage (%)") + budgeted_hours = fields.Float("Budgeted Hours for period", compute='_compute_budgeted_hours', store=True) + actual_percentage = fields.Float("Actual Percentage (%)", compute='_compute_actual_calc', store=True) + actual_hours = fields.Float("Actual Hours for period", compute='_compute_actual_calc', store=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, + employee_id, + partner_id, + start_date, + end_date, + percentage, + budgeted_hours, + actual_percentage, + actual_hours + 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.partner_id AS partner_id, + consult.employee_id AS employee_id, + consult.start_date as start_date, + consult.end_date as end_date, + consult.percentage percentage, + consult.budgeted_hours AS budgeted_hours, + consult.percentage AS actual_percentage, + consult.actual_percentage AS actual_hours + FROM project_project PRO + right JOIN project_consultant_hrs consult ON PRO.id = consult.project_id + WHERE PRO.active = 't' and PRO.pricing_type='employee_rate' and PRO.project_type='hours_in_consultant' + ) res + )""" % (self._table,)) + + diff --git a/project_report/report/project_consultant_custom_report_views.xml b/project_report/report/project_consultant_custom_report_views.xml new file mode 100755 index 0000000..e62272a --- /dev/null +++ b/project_report/report/project_consultant_custom_report_views.xml @@ -0,0 +1,82 @@ + + + + + project.consultant.custom.report.pivot + project.consultant.custom.report + + + + + + + + + + + + + project.consultant.custom.report.graph + project.consultant.custom.report + + + + + + + + + + + project.consultant.custom.report.tree + project.consultant.custom.report + + + + + + + + + + + + + + + + + + project.consultant.custom.report.search + project.consultant.custom.report + + + + + + + + + + + + + + + + + + Consultant Allocation Reports + project.consultant.custom.report + pivot,tree,graph + + {'search_default_group_project': 1,'search_default_group_employee': 1} + + + + + diff --git a/project_report/report/project_revenue_custom_report.py b/project_report/report/project_revenue_custom_report.py new file mode 100755 index 0000000..33624ed --- /dev/null +++ b/project_report/report/project_revenue_custom_report.py @@ -0,0 +1,264 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models, tools + +class ProjectRevenueCustomReport(models.Model): + + _name = "project.revenue.custom.report" + _description = "Project Revenue Custom Analysis report" + #_order = 'project_id' + _auto = False + + project_id = fields.Many2one('project.project', string='Project', readonly=True) + parent_project = fields.Many2one('project.project', string='Parent Project', readonly=True) + partner_id = fields.Many2one('res.partner', string='Client', readonly=True) + 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) + employee_id = fields.Many2one('hr.employee', string='Consultant', readonly=True) + #start_date = fields.Date(string='Start Date', readonly=True) + #end_date = fields.Date(string='End Date', readonly=True) + timesheet_sdatetime = fields.Datetime(string='Timesheet Start Time', readonly=True) + unit_amount = fields.Float('Timesheet Hours', digits=(16, 2)) + timesheet_cost = fields.Float('Consultant Price', digits=(16, 2)) + profit_per = fields.Float(string='Profit (%)', digits=(16, 2)) + profit_amt = fields.Float(string='Profit Amount', digits=(16, 2)) + expenses_amt = fields.Float(string='Expenses Amount', digits=(16, 2)) + pro_hourly_rate = fields.Float("Hourly Rate", digits=(16, 2), group_operator="sum") + budgeted_hours = fields.Float("Budgeted Hours", digits=(16, 2), readonly=True, group_operator="sum") + budgeted_revenue = fields.Float("Budgeted Revenue", digits=(16, 2), readonly=True, group_operator="sum") + actual_revenue = fields.Float("Actual Revenue", digits=(16, 2), readonly=True, group_operator="sum") + actual_cost = fields.Float("Actual Cost", digits=(16, 2), readonly=True, group_operator="sum") + overall_budgeted_revenue = fields.Float("Overall Budgeted Rev.", digits=(16, 2), readonly=True, group_operator="sum") + overall_hourly_rate = fields.Float("Overall Hourly Rate", digits=(16, 2), group_operator="sum") + + + """def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True): + if 'pro_hourly_rate' in fields: + print("fields", fields) + #fields.remove('pro_hourly_rate') + res = super().read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) + return res""" + + 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, + project_type, + pricing_type, + employee_id, + overall_budgeted_revenue, + partner_id, + budgeted_revenue, + budgeted_hours, + pro_hourly_rate, + overall_hourly_rate, + actual_revenue, + actual_cost, + expenses_amt, + profit_amt, + profit_per, + unit_amount, + timesheet_cost, + timesheet_sdatetime + 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.partner_id AS partner_id, + pro.project_type AS project_type, + pro.pricing_type as pricing_type, + AAL.employee_id AS employee_id, + 0.0 AS overall_budgeted_revenue, + 0.0 AS budgeted_revenue, + 0.0 AS budgeted_hours, + 0.0 AS pro_hourly_rate, + 0.0 AS overall_hourly_rate, + 0.0 AS actual_revenue, + (AAL.amount * -1) AS actual_cost, + 0.0 AS expenses_amt, + 0.0 - (AAL.amount * -1) AS profit_amt, + 0.0 AS profit_per, + AAL.unit_amount, + ((AAL.amount * -1)/NULLIF(AAL.unit_amount, 0)) as timesheet_cost, + AAL.start_datetime AS timesheet_sdatetime + FROM project_project PRO + RIGHT JOIN account_analytic_account AA ON PRO.analytic_account_id = AA.id + RIGHT JOIN account_analytic_line AAL ON AAL.account_id = AA.id and AAL.project_id = PRO.id + WHERE PRO.active = 't' and PRO.pricing_type = 'fixed_rate' + UNION + 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.partner_id AS partner_id, + pro.project_type AS project_type, + pro.pricing_type as pricing_type, + null::int AS employee_id, + 0.0 AS overall_budgeted_revenue, + pro.budgeted_revenue AS budgeted_revenue, + pro.budgeted_hours2 AS budgeted_hours, + pro.hourly_rate AS pro_hourly_rate, + 0.0 AS overall_hourly_rate, + 0.0 AS actual_revenue, + 0.0 AS actual_cost, + pro.expenses_amt AS expenses_amt, + 0.0 AS profit_amt, + 0.0 AS profit_per, + 0.0 as unit_amount, + 0.0 as timesheet_cost, + null::timestamp as timesheet_sdatetime + FROM project_project PRO + WHERE PRO.active = 't' and PRO.pricing_type = 'employee_rate' and PRO.project_type='hours_no_limit' + UNION + 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.partner_id AS partner_id, + pro.project_type AS project_type, + pro.pricing_type as pricing_type, + AAL.employee_id AS employee_id, + 0.0 AS overall_budgeted_revenue, + 0.0 AS budgeted_revenue, + 0.0 AS budgeted_hours, + 0.0 AS pro_hourly_rate, + 0.0 AS overall_hourly_rate, + (AAL.unit_amount * pro.hourly_rate) AS actual_revenue, + (AAL.amount * -1) AS actual_cost, + 0.0 AS expenses_amt, + ((AAL.unit_amount * pro.hourly_rate) - (AAL.amount * -1)) AS profit_amt, + ((AAL.unit_amount * pro.hourly_rate) - (AAL.amount * -1))/NULLIF((AAL.unit_amount * pro.hourly_rate),0) AS profit_per, + AAL.unit_amount, + ((AAL.amount * -1)/NULLIF(AAL.unit_amount, 0)) as timesheet_cost, + AAL.start_datetime AS timesheet_sdatetime + FROM project_project PRO + RIGHT JOIN account_analytic_account AA ON PRO.analytic_account_id = AA.id + RIGHT JOIN account_analytic_line AAL ON AAL.account_id = AA.id and AAL.project_id = PRO.id + WHERE PRO.active = 't' and PRO.pricing_type = 'employee_rate' and PRO.project_type='hours_no_limit' + UNION + 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.partner_id AS partner_id, + pro.project_type AS project_type, + pro.pricing_type as pricing_type, + pro_emp.employee_id AS employee_id, + 0.0 AS overall_budgeted_revenue, + pro_emp.cost AS budgeted_revenue, + pro_emp.budgeted_qty AS budgeted_hours, + COALESCE(pro_emp.price_unit, 0) as pro_hourly_rate, + 0.0 AS overall_hourly_rate, + 0.0 AS actual_revenue, + 0.0 AS actual_cost, + 0.0 AS expenses_amt, + 0.0 as profit_amt, + 0.0 as profit_per, + 0.0 as unit_amount, + 0.0 as timesheet_cost, + null::timestamp as timesheet_sdatetime + 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' and PRO.project_type='hours_in_consultant' + UNION + 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.partner_id AS partner_id, + pro.project_type AS project_type, + pro.pricing_type as pricing_type, + null::int AS employee_id, + pro.budgeted_revenue AS overall_budgeted_revenue, + 0.0 AS budgeted_revenue, + 0.0 AS budgeted_hours, + 0.0 as pro_hourly_rate, + pro.hourly_rate AS overall_hourly_rate, + 0.0 AS actual_revenue, + 0.0 AS actual_cost, + pro.expenses_amt AS expenses_amt, + 0.0 as profit_amt, + 0.0 as profit_per, + 0.0 as unit_amount, + 0.0 as timesheet_cost, + null::timestamp as timesheet_sdatetime + FROM project_project PRO + WHERE PRO.active = 't' and PRO.pricing_type='employee_rate' and PRO.project_type='hours_in_consultant' + UNION + 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.partner_id AS partner_id, + pro.project_type AS project_type, + pro.pricing_type as pricing_type, + AAL.employee_id AS employee_id, + 0.0 AS overall_budgeted_revenue, + 0.0 AS budgeted_revenue, + 0.0 AS budgeted_hours, + 0.0 AS pro_hourly_rate, + 0.0 AS overall_hourly_rate, + (AAL.unit_amount * pro_emp.price_unit) AS actual_revenue, + case when pro_emp.employee_price is null then (AAL.amount * -1) else (AAL.unit_amount * pro_emp.employee_price) end as actual_cost, + 0.0 AS expenses_amt, + (AAL.unit_amount * pro_emp.price_unit) - case when pro_emp.employee_price is null then (AAL.amount * -1) else (AAL.unit_amount * pro_emp.employee_price) end + as profit_amt, + (((AAL.unit_amount * pro_emp.price_unit) - case when pro_emp.employee_price is null then (AAL.amount * -1) else (AAL.unit_amount * pro_emp.employee_price) end) + / NULLIF((AAL.unit_amount * pro_emp.price_unit), 0)) * 100 as profit_per, + AAL.unit_amount, + case when pro_emp.employee_price is null then ((AAL.amount * -1)/NULLIF(AAL.unit_amount, 0)) else pro_emp.employee_price end as timesheet_cost, + AAL.start_datetime AS timesheet_sdatetime + 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 + Left JOIN project_sale_line_employee_map pro_emp ON pro_emp.project_id = pro.id and AAL.employee_id = pro_emp.employee_id + LEFT JOIN hr_employee EMP ON AAL.employee_id = EMP.id + WHERE PRO.active = 't' and PRO.pricing_type='employee_rate' and PRO.project_type='hours_in_consultant' + ) res + )""" % (self._table,)) + + @api.model + def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True): + res = super(ProjectRevenueCustomReport, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) + hourly_rate = 0 + actual_cost = 0 + for line in res: + try: + if 'actual_cost' in line: + actual_cost = line['actual_cost'] + if 'pro_hourly_rate' in line: + hourly_rate = line['pro_hourly_rate'] + if 'unit_amount' in line: # and 'pro_hourly_rate' in line and 'id' in line + if hourly_rate != 0: + line['actual_revenue'] = hourly_rate * line['unit_amount'] + if 'unit_amount' in line and 'timesheet_cost' in line: + line['actual_cost'] = line['timesheet_cost'] * line['unit_amount'] + if 'overall_budgeted_revenue' in line and 'budgeted_hours' in line: + if line['budgeted_hours'] > 0: + line['overall_hourly_rate'] = line['overall_budgeted_revenue'] / line['budgeted_hours'] + if 'pro_hourly_rate' in line and 'budgeted_hours' in line: + if line['budgeted_hours'] > 0: + line['pro_hourly_rate'] = line['budgeted_revenue'] / line['budgeted_hours'] + if 'actual_revenue' in line and 'actual_cost' in line and 'expenses_amt' in line: + line['profit_amt'] = line['actual_revenue'] - line['actual_cost'] - line['expenses_amt'] + if 'profit_amt' in line and 'actual_revenue' in line: + try: + line['profit_per'] = (line['profit_amt'] / line['actual_revenue']) * 100 + except ZeroDivisionError: + pass + if 'unit_amount' in line: + try: + line['timesheet_cost'] = actual_cost / line['unit_amount'] + except ZeroDivisionError: + pass + except Exception: + pass + return res + diff --git a/project_report/report/project_revenue_custom_report2.py b/project_report/report/project_revenue_custom_report2.py new file mode 100755 index 0000000..5361ede --- /dev/null +++ b/project_report/report/project_revenue_custom_report2.py @@ -0,0 +1,255 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models, tools + +class ProjectRevenueCustomReport2(models.Model): + + _name = "project.revenue.custom.report2" + _description = "Project Revenue Custom Analysis report2" + #_order = 'project_id' + _auto = False + + project_id = fields.Many2one('project.project', string='Project', readonly=True) + parent_project = fields.Many2one('project.project', string='Parent Project', readonly=True) + partner_id = fields.Many2one('res.partner', string='Client', readonly=True) + 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) + employee_id = fields.Many2one('hr.employee', string='Consultant', readonly=True) + timesheet_sdatetime = fields.Datetime(string='Timesheet Start Time', readonly=True) + unit_amount = fields.Float('Timesheet Hours', digits=(16, 2)) + timesheet_cost = fields.Float('Hourly Cost', digits=(16, 2)) + profit_per = fields.Float(string='Profit (%)', digits=(16, 2)) + profit_amt = fields.Float(string='Profit Amount', digits=(16, 2)) + expenses_amt = fields.Float(string='Expenses Amount', digits=(16, 2)) + pro_hourly_rate = fields.Float("Hourly Revenue", digits=(16, 2), group_operator="max") + budgeted_hours = fields.Float("Budgeted Hours", digits=(16, 2), readonly=True, group_operator="sum") + budgeted_revenue = fields.Float("Budgeted Revenue", digits=(16, 2), readonly=True, group_operator="sum") + actual_revenue = fields.Float("Actual Revenue", digits=(16, 2), readonly=True, group_operator="sum") + actual_cost = fields.Float("Actual Cost", digits=(16, 2), readonly=True, group_operator="sum") + overall_budgeted_revenue = fields.Float("Overall Budgeted Rev.", digits=(16, 2), readonly=True, group_operator="sum") + overall_hourly_rate = fields.Float("Overall Hourly Rate", digits=(16, 2), group_operator="sum") + + + 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, + project_type, + pricing_type, + employee_id, + overall_budgeted_revenue, + partner_id, + budgeted_revenue, + budgeted_hours, + pro_hourly_rate, + overall_hourly_rate, + actual_revenue, + actual_cost, + expenses_amt, + profit_amt, + profit_per, + unit_amount, + timesheet_cost, + timesheet_sdatetime + 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.partner_id AS partner_id, + pro.project_type AS project_type, + pro.pricing_type as pricing_type, + AAL.employee_id AS employee_id, + 0.0 AS overall_budgeted_revenue, + 0.0 AS budgeted_revenue, + 0.0 AS budgeted_hours, + 0.0 AS overall_hourly_rate, + AAL.unit_amount, + 0.0 AS pro_hourly_rate, + ((AAL.amount * -1)/NULLIF(AAL.unit_amount, 0)) as timesheet_cost, + 0.0 AS actual_revenue, + (AAL.amount * -1) AS actual_cost, + 0.0 AS expenses_amt, + 0.0 - (AAL.amount * -1) AS profit_amt, + 0.0 AS profit_per, + AAL.start_datetime AS timesheet_sdatetime + FROM project_project PRO + RIGHT JOIN account_analytic_account AA ON PRO.analytic_account_id = AA.id + RIGHT JOIN account_analytic_line AAL ON AAL.account_id = AA.id and AAL.project_id = PRO.id + WHERE PRO.active = 't' and PRO.pricing_type = 'fixed_rate' + UNION + 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.partner_id AS partner_id, + pro.project_type AS project_type, + pro.pricing_type as pricing_type, + null::int AS employee_id, + 0.0 AS overall_budgeted_revenue, + pro.budgeted_revenue AS budgeted_revenue, + pro.budgeted_hours2 AS budgeted_hours, + 0.0 AS overall_hourly_rate, + 0.0 as unit_amount, + 0.0 AS pro_hourly_rate, + 0.0 as timesheet_cost, + 0.0 AS actual_revenue, + 0.0 AS actual_cost, + pro.expenses_amt AS expenses_amt, + 0.0 AS profit_amt, + 0.0 AS profit_per, + null::timestamp as timesheet_sdatetime + FROM project_project PRO + WHERE PRO.active = 't' and PRO.pricing_type = 'employee_rate' and PRO.project_type='hours_no_limit' + UNION + 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.partner_id AS partner_id, + pro.project_type AS project_type, + pro.pricing_type as pricing_type, + AAL.employee_id AS employee_id, + 0.0 AS overall_budgeted_revenue, + 0.0 AS budgeted_revenue, + 0.0 AS budgeted_hours, + 0.0 AS overall_hourly_rate, + AAL.unit_amount, + pro.hourly_rate AS pro_hourly_rate, + ((AAL.amount * -1)/NULLIF(AAL.unit_amount, 0)) as timesheet_cost, + (AAL.unit_amount * pro.hourly_rate) AS actual_revenue, + (AAL.amount * -1) AS actual_cost, + 0.0 AS expenses_amt, + ((AAL.unit_amount * pro.hourly_rate) - (AAL.amount * -1)) AS profit_amt, + ((AAL.unit_amount * pro.hourly_rate) - (AAL.amount * -1))/NULLIF((AAL.unit_amount * pro.hourly_rate),0) AS profit_per, + AAL.start_datetime AS timesheet_sdatetime + FROM project_project PRO + RIGHT JOIN account_analytic_account AA ON PRO.analytic_account_id = AA.id + RIGHT JOIN account_analytic_line AAL ON AAL.account_id = AA.id and AAL.project_id = PRO.id + WHERE PRO.active = 't' and PRO.pricing_type = 'employee_rate' and PRO.project_type='hours_no_limit' + UNION + 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.partner_id AS partner_id, + pro.project_type AS project_type, + pro.pricing_type as pricing_type, + pro_emp.employee_id AS employee_id, + 0.0 AS overall_budgeted_revenue, + pro_emp.cost AS budgeted_revenue, + pro_emp.budgeted_qty AS budgeted_hours, + 0.0 as timesheet_cost, + 0.0 AS overall_hourly_rate, + 0.0 as unit_amount, + 0.0 AS pro_hourly_rate, + 0.0 AS actual_revenue, + 0.0 AS actual_cost, + 0.0 AS expenses_amt, + 0.0 as profit_amt, + 0.0 as profit_per, + null::timestamp as timesheet_sdatetime + 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' and PRO.project_type='hours_in_consultant' + UNION + 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.partner_id AS partner_id, + pro.project_type AS project_type, + pro.pricing_type as pricing_type, + null::int AS employee_id, + pro.budgeted_revenue AS overall_budgeted_revenue, + 0.0 AS budgeted_revenue, + 0.0 AS budgeted_hours, + pro.hourly_rate AS overall_hourly_rate, + 0.0 as unit_amount, + 0.0 as pro_hourly_rate, + 0.0 as timesheet_cost, + 0.0 AS actual_revenue, + 0.0 AS actual_cost, + pro.expenses_amt AS expenses_amt, + 0.0 as profit_amt, + 0.0 as profit_per, + null::timestamp as timesheet_sdatetime + FROM project_project PRO + WHERE PRO.active = 't' and PRO.pricing_type='employee_rate' and PRO.project_type='hours_in_consultant' + UNION + 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.partner_id AS partner_id, + pro.project_type AS project_type, + pro.pricing_type as pricing_type, + AAL.employee_id AS employee_id, + 0.0 AS overall_budgeted_revenue, + 0.0 AS budgeted_revenue, + 0.0 AS budgeted_hours, + 0.0 AS overall_hourly_rate, + AAL.unit_amount, + COALESCE(pro_emp.price_unit, 0) as pro_hourly_rate, + case when pro_emp.employee_price is null then ((AAL.amount * -1)/NULLIF(AAL.unit_amount, 0)) else pro_emp.employee_price end as timesheet_cost, + (AAL.unit_amount * pro_emp.price_unit) AS actual_revenue, + case when pro_emp.employee_price is null then (AAL.amount * -1) else (AAL.unit_amount * pro_emp.employee_price) end as actual_cost, + 0.0 AS expenses_amt, + (AAL.unit_amount * pro_emp.price_unit) - case when pro_emp.employee_price is null then (AAL.amount * -1) else (AAL.unit_amount * pro_emp.employee_price) end + as profit_amt, + (((AAL.unit_amount * pro_emp.price_unit) - case when pro_emp.employee_price is null then (AAL.amount * -1) else (AAL.unit_amount * pro_emp.employee_price) end) + / NULLIF((AAL.unit_amount * pro_emp.price_unit), 0)) * 100 as profit_per, + AAL.start_datetime AS timesheet_sdatetime + 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 + Left JOIN project_sale_line_employee_map pro_emp ON pro_emp.project_id = pro.id and AAL.employee_id = pro_emp.employee_id + LEFT JOIN hr_employee EMP ON AAL.employee_id = EMP.id + WHERE PRO.active = 't' and PRO.pricing_type='employee_rate' and PRO.project_type='hours_in_consultant' + ) res + )""" % (self._table,)) + + @api.model + def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True): + res = super(ProjectRevenueCustomReport2, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) + hourly_rate = 0 + actual_cost = 0 + for line in res: + try: + if 'actual_cost' in line: + actual_cost = line['actual_cost'] + """if 'pro_hourly_rate' in line: + hourly_rate = line['pro_hourly_rate'] + if 'unit_amount' in line: # and 'pro_hourly_rate' in line and 'id' in line + if hourly_rate != 0: + line['actual_revenue'] = hourly_rate * line['unit_amount'] + if 'unit_amount' in line and 'timesheet_cost' in line: + line['actual_cost'] = line['timesheet_cost'] * line['unit_amount']""" + if 'overall_budgeted_revenue' in line and 'budgeted_hours' in line: + if line['budgeted_hours'] > 0: + line['overall_hourly_rate'] = line['overall_budgeted_revenue'] / line['budgeted_hours'] + if 'pro_hourly_rate' in line and 'budgeted_hours' in line: + if line['budgeted_hours'] > 0: + line['pro_hourly_rate'] = line['budgeted_revenue'] / line['budgeted_hours'] + if 'actual_revenue' in line and 'actual_cost' in line and 'expenses_amt' in line: + line['profit_amt'] = line['actual_revenue'] - line['actual_cost'] - line['expenses_amt'] + if 'profit_amt' in line and 'actual_revenue' in line: + try: + line['profit_per'] = (line['profit_amt'] / line['actual_revenue']) * 100 + except ZeroDivisionError: + pass + if 'unit_amount' in line: + try: + line['timesheet_cost'] = actual_cost / line['unit_amount'] + except ZeroDivisionError: + pass + except Exception: + pass + return res + diff --git a/project_report/report/project_revenue_custom_report2_views.xml b/project_report/report/project_revenue_custom_report2_views.xml new file mode 100755 index 0000000..04ce35b --- /dev/null +++ b/project_report/report/project_revenue_custom_report2_views.xml @@ -0,0 +1,103 @@ + + + + + project.revenue.custom.report2.pivot + project.revenue.custom.report2 + + + + + + + + + + + + + + + + + + + + + project.revenue.custom.report2.graph + project.revenue.custom.report2 + + + + + + + + + + + + project.revenue.custom.report2.tree + project.revenue.custom.report2 + + + + + + + + + + + + + + + + + + + + + project.revenue.custom.report2.search + project.revenue.custom.report2 + + + + + + + + + + + + + + + + + + + + + + Projects Revenue + project.revenue.custom.report2 + pivot,tree,graph + + {'search_default_group_project': 1,'search_default_group_employee': 1,'search_default_group_t_starttime': 1} + + + + + + diff --git a/project_report/report/project_revenue_custom_report_views.xml b/project_report/report/project_revenue_custom_report_views.xml new file mode 100755 index 0000000..9ca1c76 --- /dev/null +++ b/project_report/report/project_revenue_custom_report_views.xml @@ -0,0 +1,97 @@ + + + + + project.revenue.custom.report.pivot + project.revenue.custom.report + + + + + + + + + + + + + + + + + + + + + project.revenue.custom.report.graph + project.revenue.custom.report + + + + + + + + + + + + project.revenue.custom.report.tree + project.revenue.custom.report + + + + + + + + + + + + + + + + + + + + + project.revenue.custom.report.search + project.revenue.custom.report + + + + + + + + + + + + + + + + + + + + + Projects Revenue + project.revenue.custom.report + pivot,tree,graph + + {'search_default_group_project': 1,'search_default_group_employee': 1,'search_default_group_t_starttime': 1} + + + + + diff --git a/project_report/security/ir.model.access.csv b/project_report/security/ir.model.access.csv index d29c722..6699481 100755 --- a/project_report/security/ir.model.access.csv +++ b/project_report/security/ir.model.access.csv @@ -8,4 +8,12 @@ access_project_create_expense_user,access_project_create_expense_project_user,mo 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 access_project_timesheet_report_manager,project.timesheet.report,model_project_timesheet_report,project.group_project_manager,1,1,1,1 -access_project_timesheet_report_user,project.timesheet.report,model_project_timesheet_report,project.group_project_user,1,0,0,0 \ No newline at end of file +access_project_timesheet_report_user,project.timesheet.report,model_project_timesheet_report,project.group_project_user,1,0,0,0 +access_project_revenue_custom_report_manager,project_revenue_custom_report_manager,model_project_revenue_custom_report,project.group_project_manager,1,1,1,1 +access_project_revenue_custom_report_user,project_revenue_custom_report_user,model_project_revenue_custom_report,project.group_project_user,1,0,0,0 +access_project_consultant_custom_report_manager,project_consultant_custom_report_manager,model_project_consultant_custom_report,project.group_project_manager,1,1,1,1 +access_project_consultant_custom_report_user,project_consultant_custom_report_user,model_project_consultant_custom_report,project.group_project_user,1,0,0,0 +access_project_revenue_custom_report2_manager,project_revenue_custom_report2_manager,model_project_revenue_custom_report2,project.group_project_manager,1,1,1,1 +access_project_revenue_custom_report2_user,project_revenue_custom_report2_user,model_project_revenue_custom_report2,project.group_project_user,1,0,0,0 + + diff --git a/sticky_pivot_view/README.rst b/sticky_pivot_view/README.rst new file mode 100755 index 0000000..f79b1d7 --- /dev/null +++ b/sticky_pivot_view/README.rst @@ -0,0 +1,14 @@ +Sticky Pivot View V14 +====================== + +This module will helps to stick the pivot view header (Row and Column) . + + +Credits +------- +* Developer: +(v14) Shahil @ Cybrosys + +Contacts +-------- +* Mail Contact : odoo@cybrosys.com diff --git a/sticky_pivot_view/__manifest__.py b/sticky_pivot_view/__manifest__.py new file mode 100755 index 0000000..15c91e6 --- /dev/null +++ b/sticky_pivot_view/__manifest__.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2021-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +{ + 'name': 'Sticky Pivot View', + 'version': '14.0.1.0.0', + 'summary': 'Helps to stick the pivot view (Row and Column)', + 'description': 'Helps to stick the pivot view (Row and Column)', + 'category': 'Tools', + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': 'https://www.cybrosys.com', + 'license': 'LGPL-3', + 'images': ['static/description/banner.png'], + 'depends': ['base', 'web'], + 'qweb': [ + 'static/src/xml/pivot.xml', + ], + 'data': [ + 'views/assets.xml', + ], + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/sticky_pivot_view/doc/RELEASE_NOTES.md b/sticky_pivot_view/doc/RELEASE_NOTES.md new file mode 100755 index 0000000..006fc03 --- /dev/null +++ b/sticky_pivot_view/doc/RELEASE_NOTES.md @@ -0,0 +1,5 @@ +## Module + +#### 13.08.2021 +#### Version 14.0.1.0.0 +#### ADD Initial Commit for sticky_pivot_view diff --git a/sticky_pivot_view/static/description/assets/icons/check.png b/sticky_pivot_view/static/description/assets/icons/check.png new file mode 100755 index 0000000..c8e85f5 Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/check.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/chevron.png b/sticky_pivot_view/static/description/assets/icons/chevron.png new file mode 100755 index 0000000..2089293 Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/chevron.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/cogs.png b/sticky_pivot_view/static/description/assets/icons/cogs.png new file mode 100755 index 0000000..95d0bad Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/cogs.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/consultation.png b/sticky_pivot_view/static/description/assets/icons/consultation.png new file mode 100755 index 0000000..8319d4b Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/consultation.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/ecom-black.png b/sticky_pivot_view/static/description/assets/icons/ecom-black.png new file mode 100755 index 0000000..a9385ff Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/ecom-black.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/education-black.png b/sticky_pivot_view/static/description/assets/icons/education-black.png new file mode 100755 index 0000000..3eb09b2 Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/education-black.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/hotel-black.png b/sticky_pivot_view/static/description/assets/icons/hotel-black.png new file mode 100755 index 0000000..130f613 Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/hotel-black.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/license.png b/sticky_pivot_view/static/description/assets/icons/license.png new file mode 100755 index 0000000..a586979 Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/license.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/lifebuoy.png b/sticky_pivot_view/static/description/assets/icons/lifebuoy.png new file mode 100755 index 0000000..658d56c Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/lifebuoy.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/logo.png b/sticky_pivot_view/static/description/assets/icons/logo.png new file mode 100755 index 0000000..478462d Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/logo.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/manufacturing-black.png b/sticky_pivot_view/static/description/assets/icons/manufacturing-black.png new file mode 100755 index 0000000..697eb0e Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/manufacturing-black.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/pos-black.png b/sticky_pivot_view/static/description/assets/icons/pos-black.png new file mode 100755 index 0000000..97c0f90 Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/pos-black.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/puzzle.png b/sticky_pivot_view/static/description/assets/icons/puzzle.png new file mode 100755 index 0000000..65cf854 Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/puzzle.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/restaurant-black.png b/sticky_pivot_view/static/description/assets/icons/restaurant-black.png new file mode 100755 index 0000000..4a35eb9 Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/restaurant-black.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/service-black.png b/sticky_pivot_view/static/description/assets/icons/service-black.png new file mode 100755 index 0000000..301ab51 Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/service-black.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/trading-black.png b/sticky_pivot_view/static/description/assets/icons/trading-black.png new file mode 100755 index 0000000..9398ba2 Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/trading-black.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/training.png b/sticky_pivot_view/static/description/assets/icons/training.png new file mode 100755 index 0000000..884ca02 Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/training.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/update.png b/sticky_pivot_view/static/description/assets/icons/update.png new file mode 100755 index 0000000..ecbc5a0 Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/update.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/user.png b/sticky_pivot_view/static/description/assets/icons/user.png new file mode 100755 index 0000000..6ffb23d Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/user.png differ diff --git a/sticky_pivot_view/static/description/assets/icons/wrench.png b/sticky_pivot_view/static/description/assets/icons/wrench.png new file mode 100755 index 0000000..6c04dea Binary files /dev/null and b/sticky_pivot_view/static/description/assets/icons/wrench.png differ diff --git a/sticky_pivot_view/static/description/assets/modules/approval_image.png b/sticky_pivot_view/static/description/assets/modules/approval_image.png new file mode 100755 index 0000000..84fe94e Binary files /dev/null and b/sticky_pivot_view/static/description/assets/modules/approval_image.png differ diff --git a/sticky_pivot_view/static/description/assets/modules/budget_image.png b/sticky_pivot_view/static/description/assets/modules/budget_image.png new file mode 100755 index 0000000..fe6aa6f Binary files /dev/null and b/sticky_pivot_view/static/description/assets/modules/budget_image.png differ diff --git a/sticky_pivot_view/static/description/assets/modules/export_image.png b/sticky_pivot_view/static/description/assets/modules/export_image.png new file mode 100755 index 0000000..4e4ea0e Binary files /dev/null and b/sticky_pivot_view/static/description/assets/modules/export_image.png differ diff --git a/sticky_pivot_view/static/description/assets/modules/magento_image.png b/sticky_pivot_view/static/description/assets/modules/magento_image.png new file mode 100755 index 0000000..39de082 Binary files /dev/null and b/sticky_pivot_view/static/description/assets/modules/magento_image.png differ diff --git a/sticky_pivot_view/static/description/assets/modules/pos_image.png b/sticky_pivot_view/static/description/assets/modules/pos_image.png new file mode 100755 index 0000000..c593289 Binary files /dev/null and b/sticky_pivot_view/static/description/assets/modules/pos_image.png differ diff --git a/sticky_pivot_view/static/description/assets/modules/shopify_image.png b/sticky_pivot_view/static/description/assets/modules/shopify_image.png new file mode 100755 index 0000000..c6d92c1 Binary files /dev/null and b/sticky_pivot_view/static/description/assets/modules/shopify_image.png differ diff --git a/sticky_pivot_view/static/description/assets/screenshots/hero.png b/sticky_pivot_view/static/description/assets/screenshots/hero.png new file mode 100755 index 0000000..3ad5be9 Binary files /dev/null and b/sticky_pivot_view/static/description/assets/screenshots/hero.png differ diff --git a/sticky_pivot_view/static/description/assets/screenshots/sticky_pivot_view.png b/sticky_pivot_view/static/description/assets/screenshots/sticky_pivot_view.png new file mode 100755 index 0000000..88c35e5 Binary files /dev/null and b/sticky_pivot_view/static/description/assets/screenshots/sticky_pivot_view.png differ diff --git a/sticky_pivot_view/static/description/banner.png b/sticky_pivot_view/static/description/banner.png new file mode 100755 index 0000000..1484de9 Binary files /dev/null and b/sticky_pivot_view/static/description/banner.png differ diff --git a/sticky_pivot_view/static/description/icon.png b/sticky_pivot_view/static/description/icon.png new file mode 100755 index 0000000..ee9610e Binary files /dev/null and b/sticky_pivot_view/static/description/icon.png differ diff --git a/sticky_pivot_view/static/description/index.html b/sticky_pivot_view/static/description/index.html new file mode 100755 index 0000000..aae7abc --- /dev/null +++ b/sticky_pivot_view/static/description/index.html @@ -0,0 +1,531 @@ +
+
+
+
+ +
+
+
+ Community +
+ +
+
+
+
+ +
+
+
+

+ Sticky Pivot View

+

+ Helps to stick the pivot view while scrolling Horizontally and Vertically +

+ +
+
+ + + + +
+
+

+ Overview +

+
+ +
+

+ This module will ensure sticky pivot view and enhance the user experience so that the user will + never lose the headers while scrolling (Horizontally and Vertically) the report.

+ +
+
+ + +
+
+

+ Features +

+
+ +
+
+ +
+
+

+ Helps to stick the pivot view while scrolling

+
+
+ +
+ +
+
+

+ Screenshots +

+
+
+

+ Sticky header in pivot view

+

+ Helps to stick the pivot view while scrolling Horizontally and Vertically

+ +
+
+ + +
+
+

Suggested Products

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

Our Services

+
+
+ +
+
+ +
+
+ Odoo + Customization
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Support
+
+ + +
+
+ +
+
+ Hire + Odoo + Developer
+
+ +
+
+ +
+
+ Odoo + Integration
+
+ +
+
+ +
+
+ Odoo + Migration
+
+ + +
+
+ +
+
+ Odoo + Consultancy
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Licensing Consultancy
+
+
+
+ + + +
+
+
+

Our Industries

+
+
+ +
+
+ +
+ Trading +
+

+ Easily procure + and + sell your products

+
+
+ +
+
+ +
+ POS +
+

+ Easy + configuration + and convivial experience

+
+
+ +
+
+ +
+ Education +
+

+ A platform for + educational management

+
+
+ +
+
+ +
+ Manufacturing +
+

+ Plan, track and + schedule your operations

+
+
+ +
+
+ +
+ E-commerce & Website +
+

+ Mobile + friendly, + awe-inspiring product pages

+
+
+ +
+
+ +
+ Service Management +
+

+ Keep track of + services and invoice

+
+
+ +
+
+ +
+ Restaurant +
+

+ Run your bar or + restaurant methodically

+
+
+ +
+
+ +
+ Hotel Management +
+

+ An + all-inclusive + hotel management application

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

Need Help?

+
+
+
+ + +
+ +
+ +
+ +
+ WhatsApp +
+
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+
+
+ + +
\ No newline at end of file diff --git a/sticky_pivot_view/static/src/css/main.css b/sticky_pivot_view/static/src/css/main.css new file mode 100755 index 0000000..905abd7 --- /dev/null +++ b/sticky_pivot_view/static/src/css/main.css @@ -0,0 +1,34 @@ +.cb_sticky { + position: sticky; + top: 0; + z-index : 10; +} + +.cb_sticky tr th{ + outline: 1px solid #dee2e6; + border: none; + outline-offset: -1px; + left: 0; + position: sticky !important; +} + +.cb_sticky_first_child{ + z-index: 10; +} + +tbody .o_pivot_header_cell_opened { + position: sticky; + left : 0; + outline: 1px solid #dee2e6; +} + +tbody .o_pivot_header_cell_closed { + position: sticky; + left : 0; + outline: 1px solid #dee2e6; +} + +tbody .dropdown > .dropdown-menu.o_pivot_field_menu.show { + left : 104%; + margin: -20px 0px 0px 0px; +} \ No newline at end of file diff --git a/sticky_pivot_view/static/src/xml/pivot.xml b/sticky_pivot_view/static/src/xml/pivot.xml new file mode 100755 index 0000000..c29a8b1 --- /dev/null +++ b/sticky_pivot_view/static/src/xml/pivot.xml @@ -0,0 +1,13 @@ + + + + + + cb_sticky + + + cb_sticky_first_child + + + + \ No newline at end of file diff --git a/sticky_pivot_view/views/assets.xml b/sticky_pivot_view/views/assets.xml new file mode 100755 index 0000000..1566aad --- /dev/null +++ b/sticky_pivot_view/views/assets.xml @@ -0,0 +1,8 @@ + + + +