From 4f2601e9fbdb5eaab57111681344a077c65792b9 Mon Sep 17 00:00:00 2001 From: projectsodoo Date: Tue, 19 Jan 2021 10:13:33 +0530 Subject: [PATCH] Added file --- cor_custom/__manifest__.py | 2 +- cor_custom/models/project_hours.py | 122 ++++++++++++++++++++ cor_custom/security/cor_custom_security.xml | 70 +++++++++++ cor_custom/wizard/__init__.py | 2 +- 4 files changed, 194 insertions(+), 2 deletions(-) create mode 100755 cor_custom/models/project_hours.py create mode 100755 cor_custom/security/cor_custom_security.xml diff --git a/cor_custom/__manifest__.py b/cor_custom/__manifest__.py index d7f7409..7450cb6 100755 --- a/cor_custom/__manifest__.py +++ b/cor_custom/__manifest__.py @@ -25,7 +25,7 @@ # always loaded 'data': [ 'security/ir.model.access.csv', - #'security/cor_custom_security.xml', + 'security/cor_custom_security.xml', 'views/crm_view.xml', 'views/sale_views.xml', 'views/project_view.xml', diff --git a/cor_custom/models/project_hours.py b/cor_custom/models/project_hours.py new file mode 100755 index 0000000..d0314fa --- /dev/null +++ b/cor_custom/models/project_hours.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- + +from odoo import api, fields, models, _ +from odoo.exceptions import UserError, AccessError, ValidationError +from dateutil.relativedelta import relativedelta + +#class Project(models.Model): + #_inherit = 'project.project' + + #project_cons_hrs = fields.One2many('project.consultant.hrs', 'project_id', 'Project Hours') + +class ProjectConsultantHrs(models.Model): + _name = 'project.consultant.hrs' + _description = 'Project Consultant Hours' + _order = 'employee_id, end_date desc' + + project_id = fields.Many2one('project.project', string="Project", required=True) + employee_id = fields.Many2one('hr.employee', string="Consultant", required=True) + start_date = fields.Date('Start Date', required=True) + end_date = fields.Date('End Date', required=True) + percentage = fields.Float("Percentage (%)") + budgeted_hours = fields.Float("Budgeted Hours", compute='_compute_budgeted_hours', store=True) + actual_hours = fields.Float("Actual Hours", compute='_compute_actual_hours', store=True) + #hours_type = fields.Selection([('Budgeted Hours', 'Budgeted Hours'), ('Actual Hours', 'Actual Hours')], default="Budgeted Hours", string="Type") + + @api.constrains('start_date', 'end_date') + def _check_dates(self): + for rec in self: + if rec.end_date < rec.start_date: + raise ValidationError(_('Start date must be earlier than end date.')) + + @api.constrains('employee_id', 'percentage') + def _check_percent(self): + for val in self: + if val.employee_id and val.percentage: + rec = self.search([('employee_id','=',val.employee_id.id),('project_id','=',val.project_id.id)]) + per = [r.percentage for r in rec] + if sum(per) > 100: + raise ValidationError(_('Consultant total percentage should not be greater than 100')) + if (val.percentage <= 0.0 or val.percentage > 100.0): + raise ValidationError(_('Percentage must be between 1 and 100.')) + + @api.constrains('start_date', 'end_date') + def _check_date(self): + for val in self: + #if 'project_id' in self.env.context: + if not self.project_id.date_start or not self.project_id.date: + raise UserError(_('Project start date and end date should not be blank')) + if self.project_id.date_start and self.start_date: + if not (self.project_id.date_start <= self.start_date <= self.project_id.date): + raise ValidationError("Start date should be between project start date and End Date") + if self.end_date: + if not (self.project_id.date_start <= self.end_date <= self.project_id.date): + raise ValidationError("End date should be between project start date and End Date") + domain = [ + ('start_date', '<=', val.end_date), + ('end_date', '>=', val.start_date), + ('project_id', '=', val.project_id.id), + ('employee_id', '=', val.employee_id.id), + ('id', '!=', val.id) + ] + res = self.search_count(domain) + if res > 0: + raise ValidationError(_('Same Consultant can not have 2 same date that overlaps on same day!')) + + @api.depends('project_id', 'employee_id', 'project_id.sale_line_employee_ids', 'percentage') + def _compute_budgeted_hours(self): + for val in self: + if val.project_id and val.employee_id and val.percentage > 0: + budgeted = 0 + for emp in val.project_id.sale_line_employee_ids: + if emp.employee_id.id == val.employee_id.id: + budgeted = emp.budgeted_qty + val.budgeted_hours = (budgeted * val.percentage / 100) + else: + val.budgeted_hours = 0 + + @api.depends('project_id', 'start_date', 'end_date', 'project_id.timesheet_ids') + def _compute_actual_hours(self): + Timesheet = self.env['account.analytic.line'] + for val in self: + if val.project_id and val.employee_id and val.start_date and val.end_date: + domain = [ + ('project_id','=',val.project_id.id), + ('employee_id', '=', val.employee_id.id), + ('date', '>=', val.start_date), + ('date', '<=', val.end_date) + ] + timesheets = Timesheet.search(domain) + val.actual_hours = sum(timesheet.unit_amount for timesheet in timesheets) + else: + val.actual_hours = 0 + + @api.onchange('start_date') + def onchange_start_date(self): + if self.start_date: + self.end_date = self.start_date + relativedelta(days=6) + + @api.onchange('employee_id') + def onchange_employee_id(self): + res = {} + emp_ids = [emp.employee_id.id for emp in self.project_id.sale_line_employee_ids] + res['domain'] = {'employee_id': [('id', 'in', emp_ids)]} + if 'project_id' in self.env.context: + #if not self.env.context['project_id']: + #raise UserError(_('Please save record before add a line')) + if not emp_ids: + raise UserError(_('Please add consultant at Invoicing tab before add a line')) + res['domain'] = {'employee_id': [('id','in',emp_ids)]} + return res + + """@api.onchange('employee_id', 'percentage') + def onchange_employee_id(self): + if self.employee_id and self.percentage > 0: + cons = [emp.budgeted_qty if emp.employee_id.id == self.employee_id.id else 0 for emp in self.project_id.sale_line_employee_ids] + budgeted = cons and cons[0] or 0 + if budgeted > 0: + #record.employee_per = 100 - record.manager_per + self.budgeted_hours = (budgeted * self.percentage / 100) + else: + self.budgeted_hours = 0""" + diff --git a/cor_custom/security/cor_custom_security.xml b/cor_custom/security/cor_custom_security.xml new file mode 100755 index 0000000..1d80a04 --- /dev/null +++ b/cor_custom/security/cor_custom_security.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + account.analytic.line.timesheet.user + + [ + ('user_id', '=', user.id), + ('project_id', '!=', False), + '|', '|','|', + ('project_id.privacy_visibility', '!=', 'followers'), + ('project_id.allowed_internal_user_ids', 'in', user.ids), + ('task_id.allowed_user_ids', 'in', user.ids), + ('project_id.sale_line_employee_ids.employee_id.user_id', 'in', user.ids), + + ] + + + + + + + + + + + + + account.analytic.line.timesheet.approver + + [ + ('project_id', '!=', False), + '|','|', + ('project_id.privacy_visibility', '!=', 'followers'), + ('project_id.allowed_internal_user_ids', 'in', user.ids), + ('project_id.sale_line_employee_ids.employee_id.user_id', 'in', user.ids), + ] + + + + + diff --git a/cor_custom/wizard/__init__.py b/cor_custom/wizard/__init__.py index 57b8bbc..1c8169b 100755 --- a/cor_custom/wizard/__init__.py +++ b/cor_custom/wizard/__init__.py @@ -3,4 +3,4 @@ from . import project_create_sale_order from . import crm_opportunity_to_quotation -from . import project_multi_budget_assign +from . import project_multi_budget_assign