# -*- coding: utf-8 -*- from datetime import timedelta from odoo import api, fields, models, _ from odoo.exceptions import UserError, ValidationError class ProjectPhaseType(models.Model): _name = "project.phase.type" _description = 'Phase Type' name = fields.Char(string="Name") company_id = fields.Many2one('res.company', string="Company", default=lambda self: self.env.user.company_id) class ProjectPhase(models.Model): _name = 'project.phase' _description = 'Phase' _inherit = ['mail.thread', 'mail.activity.mixin'] _order = 'project_id,start_date' name = fields.Char(string='Phase Name', compute='_compute_name', store=True) phase_id = fields.Many2one('project.phase.type', string="Phase") sequence = fields.Integer(string='Sequence') project_id = fields.Many2one('project.project', string='Project',ondelete="restrict", default=lambda self: self.env.context.get('default_project_id')) start_date = fields.Date(string='Start Date', copy=True) end_date = fields.Date(string='End Date', copy=True) estimated_hours = fields.Float("Allocated By",copy=False) company_id = fields.Many2one('res.company', related="project_id.company_id", string='Company') task_count = fields.Integer(compute="get_task", string='Tasks') task_ids = fields.One2many("project.task",'phase_id',string='Tasks') weight = fields.Float(string="Weight") progress = fields.Float(compute="get_progress", store=True, string="Progress") notes = fields.Text(string='Notes',copy=False) state = fields.Selection([ ('draft', 'Draft'), ('open', 'Running'), ('close', 'Closed')], string='Status', copy=False, default='draft', required=True, readonly=True, tracking=True) # phase_id = fields.Many2one('project.phase', string="Stage") allowed_internal_user_ids = fields.Many2many('res.users', 'project_phase_allowed_internal_users_rel', string="Allowed Internal Users", default=lambda self: self.env.user, domain=[('share', '=', False)]) allowed_portal_user_ids = fields.Many2many('res.users', 'project_phase_allowed_portal_users_rel', string="Allowed Portal Users", domain=[('share', '=', True)]) # allowed_user_ids = fields.Many2many('res.users', compute='_compute_allowed_users', inverse='_inverse_allowed_user') # @api.depends('allowed_internal_user_ids', 'allowed_portal_user_ids') # def _compute_allowed_users(self): # for project in self: # users = project.allowed_internal_user_ids | project.allowed_portal_user_ids # project.allowed_user_ids = users # def _inverse_allowed_user(self): # for project in self: # allowed_users = project.allowed_user_ids # project.allowed_portal_user_ids = allowed_users.filtered('share') # project.allowed_internal_user_ids = allowed_users - project.allowed_portal_user_ids def write(self, values): if 'start_date' in values or 'end_date' in values: #send notification to pm to edit ivoice date if self.project_id.user_id: users = [self.project_id.user_id] notification_ids = [(0, 0, { 'res_partner_id': user.partner_id.id, 'notification_type': 'inbox' } ) for user in users if user.partner_id] if notification_ids: self.env['mail.message'].create({ 'message_type': "notification", 'body': _( "The Stage %s Dates for project %s Edit ,edit invoice dates accordingly") % (self.display_name,self.project_id.display_name), 'subject': _("Stage Dates has been updated"), 'partner_ids': [(4, user.partner_id.id) for user in users if users], 'model': self._name, 'res_id': self.id, 'notification_ids': notification_ids, 'author_id': self.env.user.partner_id and self.env.user.partner_id.id }) if self._context.get('open_from',False): if self._context.get('open_from',False) == 'vo': vo_id = self._context.get('vo_id',[]) vo = self.env['project.variation.order'].browse(vo_id) message = str('from ' + (vo and vo.name or "VO")) if self._context.get('edit_reasone',False): message = message + _(" For Reasone: %s"%(self._context.get('edit_reasone'," "))) else: message = _("From Project For Reasone: %s"%(self._context.get('edit_reasone'," "))) body = _("

Project Phase updated %s

" self.env['mail.message'].create({ 'body': body, 'model': 'project.phase', 'res_id': self.id, 'subtype_id': '2', }) return super(ProjectPhase, self).write(values) def unlink(self): for rec in self: invoice_ids = self.env['project.invoice'].search([('phase_id','=',rec.id), ('project_id', '=', rec.project_id.id)]) invoice_ids.unlink() super(ProjectPhase, self).unlink() @api.depends('task_ids.weight', 'task_ids.task_progress','task_ids') def get_progress(self): for rec in self: progress = 0.0 if rec.task_ids: done_task = self.env['project.task'].search([('phase_id', '=', rec.id)]) # import pdb # pdb.set_trace() progress = ((sum([x.weight * x.task_progress for x in done_task])) / 100) # progress = round(100.0 * float((len(done_task) / len(rec.task_ids))), 2) rec.progress = progress @api.constrains('start_date', 'end_date') def _check_dates(self): for rec in self: if rec.start_date and rec.end_date and rec.start_date > rec.end_date: raise ValidationError(_('Phase start date must be earlier than Phase end date.')) project = rec.project_id if not project.start or not project.date: continue if rec.start_date and (rec.start_date < project.start or rec.start_date > project.date): raise ValidationError(_('Phase dates must be between project dates.')) if rec.end_date and (rec.end_date < project.start or rec.end_date > project.date): raise ValidationError(_('Phase dates must be between project dates.')) def action_draft(self): return self.write({'state': 'draft'}) def action_confirm(self): for rec in self: if not rec.start_date or not rec.end_date: raise ValidationError(_('Make sure that stage dates is set.')) return self.write({'state': 'open'}) def action_close(self): return self.write({'state': 'close'}) def action_reopen(self): return self.write({'state': 'open'}) @api.depends('phase_id') def _compute_name(self): for rec in self: rec.name = rec.phase_id.name def action_project_phase_task(self): self.ensure_one() return { 'name': 'Tasks', 'type': 'ir.actions.act_window', 'view_mode': 'tree,form', 'res_model': 'project.task', 'domain': [('phase_id', '=', self.id)], } def action_view_project_invoice(self): self.ensure_one() action_window = { "type": "ir.actions.act_window", "res_model": "project.invoice", "name": "Invoice Requests", 'view_type': 'form', 'view_mode': 'tree,form', "context": {"create": False, "edit": False}, "domain": [('phase_id', '=', self.id), ('project_id', '=', self.project_id.id)] } return action_window def get_task(self): for rec in self: records = self.env['project.task'].search([('phase_id', '=', rec.id)]) rec.task_count = len(records)