diff --git a/cor_custom/models/analytic_test.py b/cor_custom/models/analytic_test.py new file mode 100755 index 0000000..8f87219 --- /dev/null +++ b/cor_custom/models/analytic_test.py @@ -0,0 +1,218 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details + +from odoo import api, exceptions, fields, models, tools, _ +from odoo.exceptions import UserError, AccessError, ValidationError +from odoo.osv import expression +import math +from datetime import datetime, time, timedelta +from odoo.tools.float_utils import float_round +from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, ustr +import dateutil.parser +import pytz + + +class AccountAnalyticLine(models.Model): + _inherit = 'account.analytic.line' + + start_time = fields.Float(string='Start Time', digits=(16, 2)) + end_time = fields.Float(string='End Time', digits=(16, 2)) + unit_amount = fields.Float('Duration', default=0.0) + parent_project = fields.Many2one('project.project', string='Parent Project') + + + def _default_start_datetime(self): + return fields.Datetime.to_string(datetime.combine(fields.Datetime.now(), datetime.min.time())) + + def _default_end_datetime(self): + return fields.Datetime.to_string(datetime.combine(fields.Datetime.now(), datetime.max.time())) + + start_datetime = fields.Datetime("Start Time", required=True, default=_default_start_datetime) + end_datetime = fields.Datetime("End Time", required=True, default=_default_end_datetime) + + + @api.onchange('project_id') + def _onchange_parent_project_id(self): + if self.project_id: + parent_project = self.env['project.project'].search([('sub_project', '=', self.project_id.id)], limit=1) + if parent_project: + self.parent_project = parent_project.id + else: + self.parent_project = False + else: + self.parent_project = False + + + @api.onchange('employee_id') + def _onchange_employee_id(self): + domain = [] + if self.employee_id and self.employee_id.user_id: + manager_id = self.env['project.project'].search( + [('user_id', '=', self.employee_id.user_id.id), ('allow_timesheets', '=', True)]).ids + emp_project_ids = self.env['project.project'].search( + [('privacy_visibility', 'in', ('employees', 'portal')), ('allow_timesheets', '=', True)]).ids + project_ids = self.env['project.project'].search( + [('privacy_visibility', '=', 'followers'), ('allow_timesheets', '=', True), + ('allowed_internal_user_ids', 'in', self.employee_id.user_id.id)]).ids + consul_ids = self.env['project.sale.line.employee.map'].search([('employee_id', '=', self.employee_id.id)]) + consul_project_ids = [val.project_id.id for val in consul_ids] + emp_all_project_ids = manager_id + emp_project_ids + project_ids + consul_project_ids + domain = [('id', 'in', list(set(emp_all_project_ids)))] + result = { + 'domain': {'project_id': domain}, + } + return result + + @api.onchange('project_id') + def _onchange_project_id(self): + domain = [] if not self.project_id else [('project_id', '=', self.project_id.id)] + cuser = [] + manager_id = [] + user_ids = [] + consul_project_ids = [] + if not self.project_id: + cuser = self.env['hr.employee'].search([('user_id', '=', self.env.user.id)]).ids + if self.project_id: + consul_ids = self.env['project.sale.line.employee.map'].search([('project_id', '=', self.project_id.id)]) + consul_project_ids = [val.employee_id.id for val in consul_ids] + if self.project_id and self.project_id.user_id: + manager_id = self.env['hr.employee'].search([('user_id', '=', self.project_id.user_id.id)]).ids + if self.project_id and self.project_id.privacy_visibility in ('employees', 'portal'): + user_ids = self.env['hr.employee'].search([('user_id', '!=', False)]).ids + if self.project_id and self.project_id.privacy_visibility == 'followers': + user_ids = self.env['hr.employee'].search( + [('user_id', 'in', self.project_id.allowed_internal_user_ids.ids)]).ids + project_all_emp_ids = cuser + manager_id + user_ids + consul_project_ids + result = { + 'domain': {'task_id': domain, 'employee_id': [('id', 'in', project_all_emp_ids)]}, + } + if self.project_id != self.task_id.project_id: + # reset task when changing project + self.task_id = False + return result + + _sql_constraints = [ + ('check_start_time_lower_than_24', 'CHECK(start_time <= 24)', 'You cannot have a start hour greater than 24'), + ('check_start_time_positive', 'CHECK(start_time >= 0)', 'Start hour must be a positive number'), + ('check_end_time_lower_than_24', 'CHECK(end_time <= 24)', 'You cannot have a end hour greater than 24'), + ('check_end_time_positive', 'CHECK(end_time >= 0)', 'End hour must be a positive number'), + ] + + @api.constrains('start_time', 'end_time') + def _check_validity_start_time_end_time(self): + for rec in self: + if rec.start_time and rec.end_time: + if rec.end_time < rec.start_time: + raise exceptions.ValidationError(_('End time cannot be earlier than Start time')) + + @api.onchange('start_time', 'end_time', 'start_datetime', 'end_datetime') + def _onchange_start_end_time(self): + if self.start_time > 0 and self.end_time > 0: + res = self.end_time - self.start_time + if res <= 0: + raise ValidationError(_("End time cannot be earlier than Start time")) + self.unit_amount = res + # if self.start_datetime and self.end_datetime: + # res1 = self.end_datetime - self.start_datetime + # print('ressssssssss', res1) + # self.unit_amount = res1 + + def utc_to_usertz(self, datetime_value, rtype=None): + print("datetime_value>>>>>>>>>>>>>>>>>>>>>>>>>>", datetime_value, type(datetime_value), datetime_value, str(datetime_value)) + user = self.env.user + utc_tz = pytz.timezone('UTC') + user_tz = pytz.timezone(user.tz) + dt_datetime = datetime.strptime(str(datetime_value), "%Y-%m-%d %H:%M:%S") + print("ddddd_tttdatetime>>>>>>>>>>>>>>>>", dt_datetime, type(dt_datetime)) + utctz_dt = utc_tz.localize(dt_datetime, is_dst=None) + #user_datetime = user_tz.localize(datetime_value).astimezone(utc_tz).replace(tzinfo=None) + #user_datetime = dt_utctz.astimezone(user_tz).replace(tzinfo=None) + user_datetime = utctz_dt.astimezone(user_tz) + res_datetime = user_datetime.strftime('%d/%m/%Y %H:%M') + print("res_datetime>>>>>>>>>>>>>>>", datetime_value, user_tz, res_datetime) + """user = self.env.user + user_tz = pytz.timezone(user.tz) + utc_tz = pytz.timezone('UTC') + dt_datetime = datetime.strftime(datetime_value, "%Y-%m-%d %H:%M:%S") + dt_utctz = utc_tz.localize(dt_datetime, is_dst=None) + print("dt_utctz", dt_utctz, type(dt_utctz)) + + db_dt = dt_utctz.astimezone(user_tz) + res_datetime = db_dt.strftime('%m/%d/%Y %H:%M') + print("res_datetime", res_datetime, type(res_datetime)) + user_datetime = dt_utctz.astimezone(user_tz).replace(tzinfo=None) + s_datetime = user_datetime.strftime('%m/%d/%Y %H:%M') + if rtype == 'Str': + res_datetime = s_datetime + if rtype == 'Datetime': + res_datetime = user_datetime""" + return res_datetime + + @api.model + def export_data(self, fields): + index = range(len(fields)) + fields_name = dict(zip(fields, index)) + res = super(AccountAnalyticLine, self).export_data(fields) + for index, val in enumerate(res['datas']): + #print("task_id", fields_name) + if fields_name.get('date') and fields_name.get('date') >= 0: + tdateindex = fields_name.get('date') + tdate = res['datas'][index][tdateindex] + if tdate: + res['datas'][index][tdateindex] = datetime.strftime(tdate, "%d/%m/%Y") + if fields_name.get('start_datetime') and fields_name.get('start_datetime') >= 0: + start_datetime_index = fields_name.get('start_datetime') + start_datetime = res['datas'][index][start_datetime_index] + if start_datetime: + #res['datas'][index][start_datetime_index] = self.utc_to_usertz(start_datetime, rtype='Str') + #res['datas'][index][start_datetime_index] = self.utc_to_usertz(start_datetime, rtype='Str') + res['datas'][index][start_datetime_index] = datetime.strftime(start_datetime, "%d/%m/%Y %H:%M") + if fields_name.get('end_datetime') and fields_name.get('end_datetime') >= 0: + end_datetime_index = fields_name.get('end_datetime') + end_datetime= res['datas'][index][end_datetime_index] + if end_datetime: + res['datas'][index][end_datetime_index] = datetime.strftime(end_datetime, "%d/%m/%Y %H:%M") + if fields_name.get('task_id') and fields_name.get('task_id') >= 0: + taskindex = fields_name.get('task_id') + ttask = res['datas'][index][taskindex] + if type(ttask) == bool: + res['datas'][index][taskindex] = '' + if fields_name.get('start_time') and fields_name.get('start_time') >= 0: + starttimeindex = fields_name.get('start_time') + starttime = float(res['datas'][index][starttimeindex]) + if starttime: + start_time = tools.format_duration(starttime) + res['datas'][index][starttimeindex] = start_time + if fields_name.get('end_time') and fields_name.get('end_time') >= 0: + endtimeindex = fields_name.get('end_time') + endtime = float(res['datas'][index][endtimeindex]) + if endtime: + end_time = tools.format_duration(endtime) + res['datas'][index][endtimeindex] = end_time + return res + + @api.model + def create(self, vals): + if vals.get('unit_amount') == 0.0: + raise ValidationError(_("Your can not fill 0.0 hour entry")) + if vals.get('unit_amount') >= 24.0: + raise ValidationError(_("Your can not fill more than 24.0 hour entry")) + value = super(AccountAnalyticLine, self).create(vals) + if value and value.project_id: + value.project_id._onchange_calculate_timesheet_hours() + value.project_id._compute_calc() + return value + + + def write(self, vals): + if vals.get('unit_amount') == 0.0: + raise ValidationError(_("Your can not fill 0.0 hour entry")) + res = super(AccountAnalyticLine, self).write(vals) + if self.project_id: + self.project_id._onchange_calculate_timesheet_hours() + return res + + @api.onchange('start_datetime', 'end_datetime') + def _onchange_start_end_date(self): + if self.start_datetime: + self.date = self.start_datetime.date() diff --git a/cor_custom/models/project.py b/cor_custom/models/project.py index dff23db..2ee620a 100755 --- a/cor_custom/models/project.py +++ b/cor_custom/models/project.py @@ -196,6 +196,12 @@ class Project(models.Model): val.consultant_timesheet_hrs = False # val.consultant_timesheet_hrs = False + def action_view_custom_project_consultant_hrs_report(self): + action = self.env["ir.actions.actions"]._for_xml_id("cor_custom.action_project_consultant_hrs_report") + action['context'] = {'search_default_project_id': self.id, 'search_default_project': 1, + 'search_default_consultant': 1, 'search_default_group_by_hours_type': 1, + 'default_res_model': 'project.consultant.hrs.report'} + return action class ProjectConsultantTimesheetHrs(models.Model): _name = 'consultant.timesheet.hrs' diff --git a/cor_custom/report/project_hours_report_view.xml b/cor_custom/report/project_hours_report_view.xml index cce1b1b..ea8d4ba 100755 --- a/cor_custom/report/project_hours_report_view.xml +++ b/cor_custom/report/project_hours_report_view.xml @@ -105,7 +105,7 @@
-