first push message
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
# -- coding: utf-8 --
|
||||
# Part of BrowseInfo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import project
|
||||
from . import task_update
|
||||
from . import project_task
|
||||
from . import res
|
||||
from . import task
|
||||
from . import project_custom_checklist
|
||||
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,204 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of BrowseInfo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError,ValidationError
|
||||
from datetime import datetime, timedelta,date
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
|
||||
|
||||
class ProjectInherit(models.Model):
|
||||
_inherit = "project.project"
|
||||
_description = "Projects"
|
||||
|
||||
sub_project_ids = fields.One2many('sub.project', 'project_id', string="Sub Projects")
|
||||
sub_task_count = fields.Integer(compute="compute_sub_task_count")
|
||||
privacy_visibility = fields.Selection([
|
||||
('followers', 'Invited employees'),
|
||||
('employees', 'All employees'),
|
||||
('portal', 'Portal users and all employees'),
|
||||
],
|
||||
string='Visibility', required=True,
|
||||
default='followers',
|
||||
help="Defines the visibility of the tasks of the project:\n"
|
||||
"- Invited employees: employees may only see the followed project and tasks.\n"
|
||||
"- All employees: employees may see all project and tasks.\n"
|
||||
"- Portal users and all employees: employees may see everything."
|
||||
" Portal users may see project and tasks followed by.\n"
|
||||
" them or by someone of their company.")
|
||||
task_auto_assign_ids = fields.One2many('task.auto.assign', 'project_id')
|
||||
task_sequence_id = fields.Many2one('ir.sequence',string="Task Entry Sequence")
|
||||
seq1 = fields.Char("Number")
|
||||
seq2 = fields.Char(string="Add Prefix")
|
||||
order_id = fields.Many2one('sale.order', string="Sale Order ")
|
||||
sale_order_ids = fields.Many2many('sale.order', 'sales_order_project_project_rel', string="Sale Orders")
|
||||
|
||||
def compute_sub_task_count(self):
|
||||
for rec in self:
|
||||
rec.sub_task_count = len(rec.sub_project_ids)
|
||||
|
||||
def unlink(self):
|
||||
for remove in self:
|
||||
if len(remove.sub_project_ids) > 0:
|
||||
raise UserError(_("Sorry !!! You cannot delete this project, because it has sub project(s)"))
|
||||
return super(ProjectInherit, self).unlink()
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields):
|
||||
res = super(ProjectInherit, self).default_get(fields)
|
||||
stages_lines = []
|
||||
task_ids = self.env['project.task.type'].search([])
|
||||
stages = [x.id for x in task_ids]
|
||||
stages_lines += [(0, 0, {'type_ids': stages})]
|
||||
project_stage_ids = self.env['project.task.type'].search([('dft_for_new_project', '=', True)])
|
||||
stage_list = []
|
||||
if project_stage_ids:
|
||||
for stage in project_stage_ids:
|
||||
values = {}
|
||||
values.update({'stage_id': stage.id, 'user_ids': stage.dft_assign_user_id.id})
|
||||
stage_list.append((0, 0, values))
|
||||
|
||||
res.update({'task_auto_assign_ids': stage_list})
|
||||
return res
|
||||
|
||||
# validation on blank user and stage.
|
||||
@api.constrains('task_auto_assign_ids')
|
||||
def onchange_auto_assign_ids(self):
|
||||
if self.task_auto_assign_ids:
|
||||
for each in self.task_auto_assign_ids:
|
||||
if not each.user_ids or not each.stage_id:
|
||||
raise ValidationError(_(" Please enter valid Users and Stages.!"))
|
||||
|
||||
|
||||
# if default new is true then new created project is automatically add.
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
project_obj = self.env['project.project'].search(
|
||||
[('task_auto_assign_ids.stage_id.dft_for_new_project', '=', True)])
|
||||
plist = []
|
||||
for vals in vals_list:
|
||||
vals['seq1'] = self.env['ir.sequence'].next_by_code('project.project') or _('New')
|
||||
record = super(ProjectInherit, self).create(vals)
|
||||
plist.append(record.id)
|
||||
for p in project_obj:
|
||||
plist.append(p.id)
|
||||
stage_obj = self.env['project.task.type'].search([('dft_for_new_project', '=', True)])
|
||||
for stage in stage_obj:
|
||||
stage.write({'project_ids': [(6, 0, plist)]})
|
||||
return record
|
||||
|
||||
class SubProject(models.Model):
|
||||
_name = 'sub.project'
|
||||
_description = "Sub Projects"
|
||||
|
||||
user_id = fields.Many2one('res.users', "Project Manager")
|
||||
partner_id = fields.Many2one('res.partner', string='Customer')
|
||||
project_id = fields.Many2one('project.project', string='Project', store=True)
|
||||
p_project_id = fields.Many2one('project.project', string='Project ', store=True)
|
||||
|
||||
@api.onchange('p_project_id')
|
||||
def set_sub_project_vals(self):
|
||||
if self.p_project_id:
|
||||
self.user_id = self.p_project_id.user_id
|
||||
self.partner_id = self.p_project_id.partner_id
|
||||
|
||||
def unlink(self):
|
||||
for remove in self:
|
||||
if len(remove.p_project_id.task_ids) > 0:
|
||||
raise UserError(_("Sorry !!! You cannot delete this project, because it has Task(s)"))
|
||||
return super(SubProject, self).unlink()
|
||||
|
||||
class CalenderEvent(models.Model):
|
||||
_inherit = 'calendar.event'
|
||||
|
||||
task_id = fields.Many2one('project.task', string="Task", readonly=True)
|
||||
project_id = fields.Many2one('project.project',string="Project")
|
||||
task_count = fields.Integer('Tasks', compute='_compute_task',)
|
||||
|
||||
# count task
|
||||
@api.depends('task_id')
|
||||
def _compute_task(self):
|
||||
self.task_count = self.env['project.task'].search_count([('meeting_id','=',self.id)])
|
||||
|
||||
class MeetingDate(models.TransientModel):
|
||||
_name = 'meeting.date'
|
||||
_description = "Create Meeting from Task"
|
||||
|
||||
start_date = fields.Datetime('Meeting Date', required=True)
|
||||
|
||||
def get_data(self):
|
||||
task_obj= self.env['project.task'].browse(self._context.get('active_ids'))
|
||||
calendar_obj = self.env['calendar.event'].create({'name':"Meeting from : "+task_obj.name , 'start':str(self.start_date),'duration':1, 'stop':self.start_date + timedelta(hours=1),'task_id':task_obj.id, 'project_id':task_obj.project_id.id})
|
||||
task_obj.write({'meeting_id':calendar_obj.id})
|
||||
|
||||
class TaskAutoAssign(models.Model):
|
||||
_name = "task.auto.assign"
|
||||
_description = "Task Auto Assign"
|
||||
|
||||
project_id = fields.Many2one('project.project', string='Project')
|
||||
stage_id = fields.Many2one('project.task.type')
|
||||
user_ids = fields.Many2one('res.users')
|
||||
|
||||
_sql_constraints = [('project_stage_uniq', 'unique (project_id,stage_id,user_ids)',
|
||||
'Duplicate entry is not allowed !')]
|
||||
|
||||
# add project in stages from project using add stages and user
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
project_obj = self.env['project.project'].search([])
|
||||
stage_obj = self.env['project.task.type'].search([])
|
||||
get_stage = vals.get('stage_id')
|
||||
plist = []
|
||||
record = super(TaskAutoAssign, self).create(vals)
|
||||
proj_list = []
|
||||
for each in project_obj:
|
||||
if each.task_auto_assign_ids:
|
||||
proj_list.append(each.id)
|
||||
for p in proj_list:
|
||||
for stage in stage_obj:
|
||||
if stage.id == get_stage:
|
||||
plist.append(p)
|
||||
stage.write({'project_ids': [(6, 0, plist)]})
|
||||
return record
|
||||
|
||||
|
||||
class SaleOrderInherit(models.Model):
|
||||
_inherit = 'sale.order'
|
||||
|
||||
@api.depends('project_id', 'task_ids')
|
||||
def _total_task_count(self):
|
||||
for order in self:
|
||||
|
||||
order.task_count = len(order.task_ids)
|
||||
|
||||
|
||||
|
||||
task_count = fields.Integer('Task Count', compute='_total_task_count',)
|
||||
project_id = fields.Many2one('project.project', string="Project", readonly=True, copy=False)
|
||||
task_ids = fields.One2many('project.task', 'order_id', string="Tasks ", readonly=True, copy=False)
|
||||
order_task_created = fields.Boolean(string='Order Task Created', default=False, copy=False)
|
||||
|
||||
def add_task(self):
|
||||
action = self.env.ref('bi_all_in_one_project_management_system.action_task_create_create').sudo().read()[0]
|
||||
return action
|
||||
|
||||
def action_view_project(self):
|
||||
domain = []
|
||||
if self.order_task_created:
|
||||
domain = [('id','in',self.task_ids.ids)]
|
||||
action = self.with_context(active_id=self.project_id.id).env.ref('bi_all_in_one_project_management_system.act_project_project_2_project_task_my').sudo().read()[0]
|
||||
if action.get('context'):
|
||||
eval_context = self.env['ir.actions.actions']._get_eval_context()
|
||||
eval_context.update({'active_id': self.project_id.id,'search_default_my_tasks' : 1})
|
||||
action['context'] = safe_eval(action['context'], eval_context)
|
||||
action['domain'] = [('is_empty','=',False)] + domain
|
||||
return action
|
||||
|
||||
|
||||
class CrmTeam(models.Model):
|
||||
_inherit = 'crm.team'
|
||||
|
||||
order_project_id = fields.Many2one('project.project', string="Order Related Project")
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of BrowseInfo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
|
||||
|
||||
class ProjectChecklist(models.Model):
|
||||
_name = "project.checklist"
|
||||
_description = "Project checklist"
|
||||
|
||||
sequence = fields.Integer(string="Sequence")
|
||||
name = fields.Char(string="Name")
|
||||
description = fields.Char(string="Description")
|
||||
|
||||
|
||||
class ProjectChecklistLine(models.Model):
|
||||
_name = "project.checklist.line"
|
||||
_description = "Project checklist Line"
|
||||
|
||||
sequence = fields.Integer(string="Sequence")
|
||||
name = fields.Char(string="Name")
|
||||
checklist_id = fields.Many2one('project.checklist', string="name")
|
||||
project_id = fields.Many2one("project.project", string="project id")
|
||||
description = fields.Char(string="Description")
|
||||
date = fields.Date(default=fields.Date.today)
|
||||
state = fields.Selection([
|
||||
('new', 'New'),
|
||||
('complete', 'Complete'),
|
||||
('cancel', 'Cancel')], string='State',
|
||||
copy=False, default="new")
|
||||
|
||||
@api.onchange('checklist_id')
|
||||
def _onchange_checklist_id(self):
|
||||
for checklist in self:
|
||||
description = ''
|
||||
if checklist.checklist_id:
|
||||
description = checklist.checklist_id.description
|
||||
checklist.update({
|
||||
'description' : description
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
def action_complete(self):
|
||||
for rec in self:
|
||||
rec.state = 'complete'
|
||||
checklist_len = len(rec.project_id.checklist_line_ids)
|
||||
completed_progress = len(rec.project_id.checklist_line_ids.filtered(lambda x : x.state == 'complete'))
|
||||
|
||||
rec.project_id.write({
|
||||
'checklist_progress' : (completed_progress * 100) / (checklist_len or 1)
|
||||
})
|
||||
|
||||
|
||||
def action_cancel(self):
|
||||
for rec in self:
|
||||
rec.state = 'cancel'
|
||||
checklist_len = len(rec.project_id.checklist_line_ids)
|
||||
completed_progress = len(rec.project_id.checklist_line_ids.filtered(lambda x : x.state == 'complete'))
|
||||
|
||||
rec.project_id.write({
|
||||
'checklist_progress' : (completed_progress * 100) / (checklist_len or 1)
|
||||
})
|
||||
|
||||
|
||||
def unlink(self):
|
||||
for rec in self:
|
||||
project = rec.project_id
|
||||
project.checklist_line_ids -= rec
|
||||
checklist_len = len(project.checklist_line_ids)
|
||||
completed_progress = len(project.checklist_line_ids.filtered(lambda x: x.state == 'complete'))
|
||||
project.write({
|
||||
'checklist_progress': (completed_progress * 100) / max((checklist_len or 1), 1)
|
||||
})
|
||||
return super(ProjectChecklistLine, self).unlink()
|
||||
|
||||
|
||||
|
||||
class ProjectChecklistTemplate(models.Model):
|
||||
_name = "project.checklist.template"
|
||||
_description = "Project Checklist Template"
|
||||
_rec_name = "template_name"
|
||||
|
||||
sequence = fields.Integer(string="Sequence")
|
||||
template_name = fields.Char(string="Name")
|
||||
checklist_ids = fields.Many2many('project.checklist', string="Checklist Template")
|
||||
|
||||
|
||||
class ProjectProject(models.Model):
|
||||
_inherit = "project.project"
|
||||
|
||||
checklist_progress = fields.Integer(string='Checklist Progress', store=True, default=0.0)
|
||||
checklist_template = fields.Many2many('project.checklist.template', string='Project Checklist template')
|
||||
checklist_line_ids = fields.One2many('project.checklist.line', 'project_id', string='Checklist')
|
||||
|
||||
@api.onchange('checklist_template')
|
||||
def onchange_checklist_template(self):
|
||||
|
||||
if self.checklist_template:
|
||||
checklist = []
|
||||
for i in self.checklist_template:
|
||||
for j in i.checklist_ids:
|
||||
checklist.append((0,0,{
|
||||
'checklist_id' : j._origin.id,
|
||||
'description' : j.description,
|
||||
'project_id' : self.id,
|
||||
}))
|
||||
self.update({'checklist_line_ids':False})
|
||||
self.update({"checklist_line_ids" : checklist})
|
||||
|
||||
|
||||
@api.constrains('checklist_template')
|
||||
def _check_checklist_templated(self):
|
||||
if not self.checklist_template:
|
||||
for lines in self.checklist_line_ids:
|
||||
lines.unlink()
|
||||
@@ -0,0 +1,929 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of BrowseInfo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from datetime import datetime, timedelta,date
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.tools import float_is_zero, float_compare, DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from odoo import SUPERUSER_ID
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from odoo.http import request
|
||||
import time
|
||||
|
||||
class ProjectTaskUserTime(models.Model):
|
||||
_name = 'project.task.user.time'
|
||||
_description = 'Task User Time Tracking'
|
||||
|
||||
user_id = fields.Many2one('res.users', string='User', required=True)
|
||||
task_id = fields.Many2one('project.task', string='Task', required=True)
|
||||
start_time = fields.Datetime(string='Start Time')
|
||||
end_time = fields.Datetime(string='End Time')
|
||||
duration = fields.Float(string='Duration', compute='_compute_duration')
|
||||
|
||||
@api.depends('start_time', 'end_time')
|
||||
def _compute_duration(self):
|
||||
for record in self:
|
||||
if record.start_time and record.end_time:
|
||||
duration = record.end_time - record.start_time
|
||||
record.duration = duration.total_seconds() / 3600.0
|
||||
else:
|
||||
record.duration = 0.0
|
||||
|
||||
|
||||
class Projecttask(models.Model):
|
||||
_name = "project.task"
|
||||
_inherit = ["project.task", 'mail.thread']
|
||||
|
||||
task_stage = fields.Boolean(string='Task Complete',compute='check_task_completed')
|
||||
date_start= fields.Datetime(string="Date")
|
||||
|
||||
def task_timesheet_reminder(self):
|
||||
current_user = self.env['res.users'].search([('active', '=', True)])
|
||||
for user in current_user:
|
||||
task_obj = self.env['project.task'].search([('user_ids','=',user.id)])
|
||||
for task in task_obj:
|
||||
if task.total_hours_spent > task.allocated_hours:
|
||||
template_id = self.env['ir.model.data']._xmlid_lookup(
|
||||
'bi_all_in_one_project_management_system.email_template_task_timesheet_reminder')[1]
|
||||
email_template_obj = self.env['mail.template'].browse(template_id)
|
||||
if template_id:
|
||||
values = email_template_obj._generate_template(task.ids,
|
||||
[
|
||||
'subject',
|
||||
'body_html',
|
||||
'email_from',
|
||||
'email_to',
|
||||
'partner_to',
|
||||
'email_cc',
|
||||
'reply_to',
|
||||
'scheduled_date',
|
||||
'res_id',
|
||||
])
|
||||
|
||||
for res_id, val in list(values.items()):
|
||||
val['email_from'] = user.email
|
||||
val['res_id'] = False
|
||||
val['author_id'] = user.partner_id.id
|
||||
mail_mail_obj = self.env['mail.mail']
|
||||
mail_create_id = mail_mail_obj.sudo().create(val)
|
||||
if mail_create_id:
|
||||
mail_create_id.sudo().send()
|
||||
return True
|
||||
|
||||
|
||||
@api.model
|
||||
def _cron_task_reminder(self):
|
||||
sus_id = self.env['res.partner'].browse(SUPERUSER_ID)
|
||||
for task in self.env['project.task'].search([]):
|
||||
for tasks_id in self.env['res.config.settings'].sudo().search([],order="id desc", limit=1):
|
||||
if task.date_deadline != False:
|
||||
if task.reminder != False:
|
||||
reminder_date = task.date_deadline
|
||||
today = datetime.now().date()
|
||||
if tasks_id.first_date != today:
|
||||
# if tasks_id.second_date == today:
|
||||
if task:
|
||||
template_id = self.env['ir.model.data']._xmlid_lookup(
|
||||
'bi_all_in_one_project_management_system.email_template_edi_task_reminder1')[1]
|
||||
email_template_obj = self.env['mail.template'].browse(template_id)
|
||||
if template_id:
|
||||
values = email_template_obj._generate_template(task.ids,
|
||||
[
|
||||
'subject',
|
||||
'body_html',
|
||||
'email_from',
|
||||
'email_to',
|
||||
'partner_to',
|
||||
'email_cc',
|
||||
'reply_to',
|
||||
'scheduled_date',
|
||||
'res_id',
|
||||
])
|
||||
|
||||
for res_id, val in list(values.items()):
|
||||
emails = {user.email for user in task.user_ids if user.email}
|
||||
|
||||
val['email_from'] = sus_id.email
|
||||
val['email_to'] = ','.join(emails) if emails else '' # Handle case with no emails
|
||||
val['res_id'] = False
|
||||
val['author_id'] = self.env['res.users'].sudo().browse(request.env.uid).partner_id.id
|
||||
|
||||
mail_mail_obj = self.env['mail.mail']
|
||||
msg_id = mail_mail_obj.sudo().create(val)
|
||||
if msg_id:
|
||||
msg_id.sudo().send()
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
||||
@api.model
|
||||
def _cron_task_second_reminder(self):
|
||||
su_id = self.env['res.partner'].browse(SUPERUSER_ID)
|
||||
for task in self.env['project.task'].search([]):
|
||||
for tasks_id in self.env['res.config.settings'].sudo().search([],order="id desc", limit=1):
|
||||
if task.date_deadline != False:
|
||||
if task.reminder != False:
|
||||
reminder_date = task.date_deadline
|
||||
today = datetime.now().date()
|
||||
if tasks_id.second_date == today:
|
||||
if task:
|
||||
template_id = self.env['ir.model.data']._xmlid_lookup(
|
||||
'bi_all_in_one_project_management_system.email_template_edi_task_reminder1')[1]
|
||||
email_template_obj = self.env['mail.template'].browse(template_id)
|
||||
if template_id:
|
||||
values = email_template_obj._generate_template(task.ids,
|
||||
[
|
||||
'subject',
|
||||
'body_html',
|
||||
'email_from',
|
||||
'email_to',
|
||||
'partner_to',
|
||||
'email_cc',
|
||||
'reply_to',
|
||||
'scheduled_date',
|
||||
'res_id',
|
||||
])
|
||||
|
||||
for res_id, val in list(values.items()):
|
||||
emails = {user.email for user in task.user_ids if user.email}
|
||||
|
||||
val['email_from'] = su_id.email
|
||||
val['email_to'] = ','.join(emails) if emails else '' # Handle case with no emails
|
||||
val['res_id'] = False
|
||||
val['author_id'] = self.env['res.users'].sudo().browse(request.env.uid).partner_id.id
|
||||
|
||||
mail_mail_obj = self.env['mail.mail']
|
||||
msg_id = mail_mail_obj.sudo().create(val)
|
||||
if msg_id:
|
||||
msg_id.sudo().send()
|
||||
return True
|
||||
|
||||
|
||||
|
||||
def _cron_post_deadline(self):
|
||||
for task in self.search([('is_task_done','=',False)]):
|
||||
schedule_task = '3 Tomorrow'
|
||||
|
||||
today = datetime.now()
|
||||
next_day = today + timedelta(days=1)
|
||||
|
||||
last_day_of_week = today + timedelta(days=5 - today.weekday())
|
||||
start_day_of_next_week = last_day_of_week + timedelta(days=1)
|
||||
last_day_of_next_week = start_day_of_next_week + timedelta(days=6)
|
||||
later_day = last_day_of_next_week + timedelta(days=1)
|
||||
if task.date_deadline:
|
||||
if task.is_task_done:
|
||||
schedule_task = '7 Done'
|
||||
elif task.date_deadline < today:
|
||||
schedule_task = '1 Overdue'
|
||||
elif task.date_deadline == today:
|
||||
schedule_task = '2 Today'
|
||||
elif task.date_deadline == next_day:
|
||||
schedule_task = '3 Tomorrow'
|
||||
elif task.date_deadline > next_day and task.date_deadline <= last_day_of_week:
|
||||
schedule_task = '4 This Week'
|
||||
elif task.date_deadline >= start_day_of_next_week and task.date_deadline <= last_day_of_next_week:
|
||||
schedule_task = '5 Next Week'
|
||||
elif task.date_deadline > last_day_of_next_week:
|
||||
schedule_task = '6 Later'
|
||||
|
||||
task.update({
|
||||
'schedule_task' : schedule_task
|
||||
})
|
||||
|
||||
def set_task_done(self):
|
||||
res = {}
|
||||
for task in self:
|
||||
if task.is_task_done == False:
|
||||
stage_id = self.env['project.task.type'].search([('name','=','Done'),('project_ids','in',self.project_id.ids)],limit=1)
|
||||
task.write({
|
||||
'is_task_done' : True,
|
||||
'stage_id' : stage_id.id
|
||||
})
|
||||
|
||||
task.message_post(body=_("The Task is Set to Done"))
|
||||
else:
|
||||
stage_id = self.env['project.task.type'].search([('name','=','New')])
|
||||
for stage in stage_id:
|
||||
task.write({
|
||||
'is_task_done' : False,
|
||||
'stage_id' : stage.id,
|
||||
})
|
||||
task.message_post(body=_("The Task is Set to New"))
|
||||
|
||||
|
||||
|
||||
@api.depends('date_deadline','is_task_done')
|
||||
def check_schedule(self):
|
||||
for task in self:
|
||||
schedule_task = '3 Tomorrow'
|
||||
|
||||
today = datetime.now()
|
||||
next_day = today + timedelta(days=1)
|
||||
|
||||
last_day_of_week = today + timedelta(days=5 - today.weekday())
|
||||
start_day_of_next_week = last_day_of_week + timedelta(days=1)
|
||||
last_day_of_next_week = start_day_of_next_week + timedelta(days=6)
|
||||
later_day = last_day_of_next_week + timedelta(days=1)
|
||||
if task.date_deadline:
|
||||
if task.is_task_done:
|
||||
schedule_task = '7 Done'
|
||||
elif task.date_deadline < today:
|
||||
schedule_task = '1 Overdue'
|
||||
elif task.date_deadline == today:
|
||||
schedule_task = '2 Today'
|
||||
elif task.date_deadline == next_day:
|
||||
schedule_task = '3 Tomorrow'
|
||||
elif task.date_deadline > next_day and task.date_deadline <= last_day_of_week:
|
||||
schedule_task = '4 This Week'
|
||||
elif task.date_deadline >= start_day_of_next_week and task.date_deadline <= last_day_of_next_week:
|
||||
schedule_task = '5 Next Week'
|
||||
elif task.date_deadline > last_day_of_next_week:
|
||||
schedule_task = '6 Later'
|
||||
|
||||
task.update({
|
||||
'schedule_task' : schedule_task
|
||||
})
|
||||
|
||||
|
||||
is_task_done = fields.Boolean(string='Task Done',default=False)
|
||||
schedule_task = fields.Selection([
|
||||
('1 Overdue','Overdue'),
|
||||
('2 Today','Today'),
|
||||
('3 Tomorrow','Tomorrow'),
|
||||
('4 This Week','This Week'),
|
||||
('5 Next Week','Next Week'),
|
||||
('6 Later','Later'),
|
||||
('7 Done','Done')], default='3 Tomorrow', compute="check_schedule", store=True)
|
||||
|
||||
user_ids = fields.Many2many('res.users', relation='project_task_user_rel', column1='task_id', column2='user_id')
|
||||
task_completed = fields.Boolean(string="Task Completed")
|
||||
start_date = fields.Date(string='Start Date', index=True, copy=False, tracking=True)
|
||||
state_type_name = fields.Char('Status ', related="stage_id.name")
|
||||
user_in_subtask = fields.Many2one('res.users','Current User', default=lambda self: self.env.user)
|
||||
subtask_check = fields.Boolean(string="Subtask", default=False)
|
||||
subtask_count = fields.Integer(string='Count')
|
||||
|
||||
done_stage_id = fields.Boolean('Is Done',default=False,store=True)
|
||||
todo_stage_id = fields.Boolean('Is ToDo',default=False,store=True)
|
||||
cancel_stage_id = fields.Boolean('Is Cancel',default=False,store=True)
|
||||
wiz_id = fields.Many2one('subtask.wizard', string="Wiz Parent Id")
|
||||
task_parent_id = fields.Many2one('project.task', string="Parent Id")
|
||||
subtask_ids = fields.One2many('project.task', 'task_parent_id', string="Subtask ")
|
||||
des = fields.Char('Task Description')
|
||||
is_subtask = fields.Boolean('Is a subtask')
|
||||
is_task_done = fields.Boolean(string='Task Done',default=False)
|
||||
schedule_task = fields.Selection([
|
||||
('1 Overdue','Overdue'),
|
||||
('2 Today','Today'),
|
||||
('3 Tomorrow','Tomorrow'),
|
||||
('4 This Week','This Week'),
|
||||
('5 Next Week','Next Week'),
|
||||
('6 Later','Later'),
|
||||
('7 Done','Done')], default='3 Tomorrow', compute="check_schedule", store=True)
|
||||
meeting_id = fields.Many2one('calendar.event', string="Meeting", readonly=True)
|
||||
meeting_count = fields.Integer('Meeting ',compute='_compute_meeting')
|
||||
seq3 = fields.Char('Number')
|
||||
order_id = fields.Many2one('sale.order', string="Sale Order ")
|
||||
order_task_created = fields.Boolean(string='Order Task Created', default=False, copy=False)
|
||||
is_empty = fields.Boolean(string='Empty Task')
|
||||
task_product_ids = fields.Many2many('product.template',string='Products')
|
||||
task_product_id = fields.Many2one('product.template',string='Product')
|
||||
reminder = fields.Boolean(string='Reminder')
|
||||
task_Start = fields.Boolean(string='Task Start', default=False, readonly=True)
|
||||
end_time = fields.Datetime(
|
||||
string='End Date ',
|
||||
)
|
||||
start_time = fields.Datetime(
|
||||
string='Start Date ',
|
||||
)
|
||||
time_left = fields.Float(string='Real Timer')
|
||||
priority = fields.Selection(selection_add= [
|
||||
('0', 'Normal'),
|
||||
('1', 'Important'),
|
||||
('2', 'Good'),
|
||||
('3', 'Excellent'),
|
||||
])
|
||||
user_times = fields.One2many('project.task.user.time', 'task_id', string='User Times')
|
||||
task_Start = fields.Boolean(string='Task Start', default=False, readonly=True, compute='_compute_task_start')
|
||||
|
||||
@api.depends('user_times.task_id')
|
||||
def _compute_task_start(self):
|
||||
for task in self:
|
||||
current_user = self.env.user
|
||||
user_time = self.env['project.task.user.time'].search([
|
||||
('task_id', '=', task.id),
|
||||
('user_id', '=', current_user.id),
|
||||
('end_time', '=', False)
|
||||
], limit=1)
|
||||
task.task_Start = bool(user_time)
|
||||
|
||||
def start_task_button(self):
|
||||
allow_multi_task = self.env.company.allow_multi_task
|
||||
current_user = self.env.user
|
||||
user_time = self.env['project.task.user.time'].search([
|
||||
('task_id', '=', self.id),
|
||||
('user_id', '=', current_user.id),
|
||||
('end_time', '=', False)
|
||||
], limit=1)
|
||||
if allow_multi_task:
|
||||
if self.env.user.has_group(
|
||||
'bi_all_in_one_project_management_system.all_project_user') or self.env.user.has_group(
|
||||
'bi_all_in_one_project_management_system.group_project_manager'):
|
||||
if not user_time:
|
||||
self.env['project.task.user.time'].create({
|
||||
'task_id': self.id,
|
||||
'user_id': current_user.id,
|
||||
'start_time': datetime.now(),
|
||||
})
|
||||
self.task_Start = True
|
||||
elif self.env.user.has_group('project.group_project_user'):
|
||||
if self.env.user in self.user_ids:
|
||||
if not user_time:
|
||||
self.env['project.task.user.time'].create({
|
||||
'task_id': self.id,
|
||||
'user_id': current_user.id,
|
||||
'start_time': datetime.now(),
|
||||
})
|
||||
self.task_Start = True
|
||||
else:
|
||||
raise UserError(_("User can only start his own task"))
|
||||
else:
|
||||
active_user_task = self.env['project.task.user.time'].search([
|
||||
('user_id', '=', current_user.id),
|
||||
('end_time', '=', False)
|
||||
], limit=1)
|
||||
if active_user_task:
|
||||
raise ValidationError(_('You can start only one task.....'))
|
||||
else:
|
||||
if self.env.user.has_group(
|
||||
'bi_all_in_one_project_management_system.all_project_user') or self.env.user.has_group(
|
||||
'bi_all_in_one_project_management_system.group_project_manager'):
|
||||
if not user_time:
|
||||
self.env['project.task.user.time'].create({
|
||||
'task_id': self.id,
|
||||
'user_id': current_user.id,
|
||||
'start_time': datetime.now(),
|
||||
})
|
||||
self.task_Start = True
|
||||
|
||||
elif self.env.user.has_group('project.group_project_user'):
|
||||
if self.env.user in self.user_ids:
|
||||
if not user_time:
|
||||
self.env['project.task.user.time'].create({
|
||||
'task_id': self.id,
|
||||
'user_id': current_user.id,
|
||||
'start_time': datetime.now(),
|
||||
})
|
||||
self.task_Start = True
|
||||
else:
|
||||
raise UserError(_("User can only start his own task"))
|
||||
|
||||
# count meeting
|
||||
|
||||
@api.depends('meeting_id')
|
||||
def _compute_meeting(self):
|
||||
for rec in self:
|
||||
rec.meeting_count = self.env['calendar.event'].search_count([('task_id','=',rec.id)])
|
||||
|
||||
|
||||
|
||||
@api.onchange('stage_id')
|
||||
def _get_project_stage(self):
|
||||
if self.stage_id.name == 'Done':
|
||||
self.task_completed = True
|
||||
else:
|
||||
self.task_completed = False
|
||||
if self.project_id:
|
||||
for each in self.project_id.task_auto_assign_ids:
|
||||
if self.stage_id.id == each.stage_id.id and self.project_id.id == each.project_id.id:
|
||||
self.user_ids = each.user_ids
|
||||
|
||||
|
||||
|
||||
@api.model
|
||||
def _run_delay_deadline_notification(self):
|
||||
su_id = self.env['res.partner'].browse(SUPERUSER_ID)
|
||||
for task in self.env['project.task'].search([('date_deadline', '!=', None), ('user_ids', '!=', None),('stage_id','not in','Done'),('stage_id','not in','Cancelled')]):
|
||||
for tasks_id in self.env['res.config.settings'].sudo().search([],order="id desc", limit=1):
|
||||
count_day = tasks_id.delay_count
|
||||
reminder_date = task.date_deadline + relativedelta(days=count_day)
|
||||
today = datetime.now()
|
||||
if reminder_date < today and tasks_id.delay_notification:
|
||||
if task:
|
||||
template_id = self.env['ir.model.data']._xmlid_lookup('bi_all_in_one_project_management_system.email_template_edi_remainder_delay_overdue_notification')[1]
|
||||
email_template_obj = self.env['mail.template'].browse(template_id)
|
||||
if template_id:
|
||||
values = email_template_obj._generate_template([task.id],('subject', 'body_html', 'email_from', 'email_to', 'partner_to', 'email_cc', 'reply_to'),)[task.id]
|
||||
values['email_from'] = su_id.email
|
||||
values['res_id'] = False
|
||||
values['author_id'] = self.env['res.users'].browse(request.env.uid).partner_id.id
|
||||
mail_mail_obj = self.env['mail.mail']
|
||||
msg_id = mail_mail_obj.sudo().create(values)
|
||||
if msg_id:
|
||||
msg_id.sudo().send()
|
||||
return True
|
||||
|
||||
|
||||
|
||||
@api.model
|
||||
def _run_delay_start_notification(self):
|
||||
su_id = self.env['res.partner'].browse(SUPERUSER_ID)
|
||||
for task in self.env['project.task'].search([('start_date', '!=', None),('stage_id','not in','In Progress'),('stage_id','not in','Done'),('stage_id','not in','Cancelled')]):
|
||||
for tasks_id in self.env['res.config.settings'].sudo().search([],order="id desc", limit=1):
|
||||
count_day = tasks_id.start_count
|
||||
reminder_date = task.start_date + relativedelta(days=count_day)
|
||||
today = datetime.now().date()
|
||||
if reminder_date < today and tasks_id.start_notification:
|
||||
if task:
|
||||
template_id = self.env['ir.model.data']._xmlid_lookup('bi_all_in_one_project_management_system.email_template_edi_remainder_delay_start_notification')[1]
|
||||
email_template_obj = self.env['mail.template'].browse(template_id)
|
||||
if template_id:
|
||||
values = email_template_obj._generate_template([task.id],('subject', 'body_html', 'email_from','email_to','partner_to', 'email_cc', 'reply_to'))[task.id]
|
||||
values['email_from'] = su_id.email
|
||||
values['email_to'] = task.user_ids.email
|
||||
values['res_id'] = False
|
||||
values['author_id'] = self.env['res.users'].browse(request.env.uid).partner_id.id
|
||||
mail_mail_obj = self.env['mail.mail']
|
||||
msg_id = mail_mail_obj.sudo().create(values)
|
||||
if msg_id:
|
||||
msg_id.sudo().send()
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def default_get(self, field_vals):
|
||||
res = super(Projecttask, self).default_get(field_vals);
|
||||
|
||||
if 'recurrence_id' not in res and 'recurrence_id' in field_vals:
|
||||
res['recurrence_id'] = False
|
||||
|
||||
project = self.env["project.project"].browse(res.get("project_id",[]));
|
||||
if project:
|
||||
res["priority"] = project.priority
|
||||
current_stage = self._context.get('default_stage_id')
|
||||
current_project = self._context.get('default_project_id')
|
||||
project = self.env['project.project'].search([('id', '=', current_project)])
|
||||
project_stage_ids = self.env['project.task.type'].search([('dft_for_new_project', '=', True)])
|
||||
if project_stage_ids:
|
||||
for rec in project_stage_ids:
|
||||
if rec.id == current_stage:
|
||||
res.update({'user_ids': [(4, rec.dft_assign_user_id.id)]})
|
||||
|
||||
if project.task_auto_assign_ids:
|
||||
for stage in project.task_auto_assign_ids:
|
||||
if stage.stage_id.id == current_stage:
|
||||
res.update({'user_ids': [(4, stage.user_ids.id)]})
|
||||
else:
|
||||
pass
|
||||
|
||||
order_id = self.env['sale.order'].browse(self._context.get('active_id'))
|
||||
if not order_id.exists():
|
||||
order_id = False
|
||||
if order_id:
|
||||
team_id = order_id.team_id
|
||||
project = self.env['project.project'].search([('id', '=', current_project)])
|
||||
date = fields.Date.context_today(self)
|
||||
|
||||
date_deadline = date + relativedelta(days=1)
|
||||
|
||||
if project :
|
||||
res.update({
|
||||
'project_id': project.id,
|
||||
'date_deadline': date_deadline
|
||||
})
|
||||
|
||||
return res
|
||||
|
||||
def _find_mail_template(self, force_confirmation_template=False):
|
||||
template_id = False
|
||||
template_id = self.env['ir.model.data']._xmlid_to_res_id('bi_all_in_one_project_management_system.mail_template_task', raise_if_not_found=False)
|
||||
return template_id
|
||||
|
||||
|
||||
def action_send_task(self):
|
||||
''' Opens a wizard to compose an email, with relevant mail template loaded by default '''
|
||||
self.ensure_one()
|
||||
template_id = self._find_mail_template()
|
||||
lang = self.env.context.get('lang')
|
||||
template = self.env['mail.template'].browse(template_id)
|
||||
attachments = self.env['ir.attachment'].search([('res_model','=','project.task'),('res_id','=',self.id)])
|
||||
attachments_ids=[]
|
||||
for attachment in attachments:
|
||||
attachments_ids.append(attachment.id)
|
||||
ctx = {
|
||||
'default_model': 'project.task',
|
||||
'default_res_ids': self.ids,
|
||||
'default_use_template': bool(template_id),
|
||||
'default_template_id': template_id,
|
||||
'default_attachment_ids': ([(6,0,attachments_ids)]),
|
||||
'default_composition_mode': 'comment',
|
||||
'custom_layout': "mail.mail_notification_paynow",
|
||||
'force_email': True,
|
||||
}
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'mail.compose.message',
|
||||
'views': [(False, 'form')],
|
||||
'view_id': False,
|
||||
'target': 'new',
|
||||
'context': ctx,
|
||||
}
|
||||
|
||||
|
||||
@api.depends('wiz_id.subtask_lines')
|
||||
def sub_task_found(self):
|
||||
for each in self:
|
||||
each.subtask_count = 0
|
||||
|
||||
def action_done(self):
|
||||
done_stage_search = self.env['res.config.settings'].search([], limit=1, order="id desc").done_stage_ckecklist
|
||||
if not done_stage_search:
|
||||
raise UserError('You can not move stage, Please Configure Done stage.')
|
||||
else:
|
||||
self.write({'stage_id' : done_stage_search.id,'done_stage_id' : True,'todo_stage_id' : False})
|
||||
|
||||
def action_cancel(self):
|
||||
cancel_stage_search = self.env['res.config.settings'].search([], limit=1, order="id desc").cancel_stage_ckecklist
|
||||
if not cancel_stage_search:
|
||||
raise UserError('You can not move stage, Please Configure Cancel stage.')
|
||||
else:
|
||||
self.write({'stage_id' : cancel_stage_search.id,'cancel_stage_id' : True})
|
||||
|
||||
def action_todo(self):
|
||||
todo_stage_search = self.env['res.config.settings'].search([], limit=1, order="id desc").todo_stage_ckecklist
|
||||
if not todo_stage_search:
|
||||
raise UserError('You can not move stage, Please To Do stage.')
|
||||
else:
|
||||
self.write({'stage_id' : todo_stage_search.id, 'todo_stage_id' : True,'done_stage_id' : False})
|
||||
|
||||
@api.depends('stage_id', 'stage_id.task_completed')
|
||||
def check_task_completed(self):
|
||||
for rec in self:
|
||||
if rec.stage_id and rec.stage_id.task_completed:
|
||||
rec.task_stage = True
|
||||
rec.date_deadline = False
|
||||
else:
|
||||
rec.task_stage = False
|
||||
|
||||
|
||||
@api.depends('stage_id')
|
||||
def _inverse_task_stage(self):
|
||||
for rec in self:
|
||||
if rec.stage_id and rec.stage_id.task_completed:
|
||||
rec.task_stage = True
|
||||
rec.date_deadline = False
|
||||
else:
|
||||
rec.task_stage = False
|
||||
|
||||
|
||||
|
||||
|
||||
@api.onchange('task_stage')
|
||||
def _inverse_task_completed(self):
|
||||
for rec in self:
|
||||
if rec.task_stage and rec.project_id and rec.project_id.type_id.task_completed:
|
||||
rec.date_deadline = False
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
project = vals.get('project_id')
|
||||
project_id = self.env['project.project'].browse(project)
|
||||
|
||||
task_sq_code = project_id.task_sequence_id.code
|
||||
if project_id.seq2 and project_id.task_sequence_id:
|
||||
combine_seq = project_id.seq2 + "/" + str(self.env['ir.sequence'].sudo().next_by_code(task_sq_code))
|
||||
else:
|
||||
combine_seq = self.env['ir.sequence'].sudo().next_by_code('project.task') or _('New')
|
||||
vals.update({'seq3': combine_seq})
|
||||
rec = super(Projecttask, self).create(vals_list)
|
||||
for p_task in self:
|
||||
for task in p_task.subtask_ids:
|
||||
if task.state_type_name:
|
||||
msg = task.state_type_name + ':' + task.name
|
||||
else:
|
||||
msg = task.name
|
||||
|
||||
p_task.message_post(body=msg)
|
||||
return rec
|
||||
|
||||
|
||||
def write(self, vals):
|
||||
old_ids = []
|
||||
if 'project_id' in vals:
|
||||
project = vals.get('project_id')
|
||||
project_id = self.env['project.project'].browse(project)
|
||||
task_sq_code = project_id.task_sequence_id.code
|
||||
if project_id.seq2 and project_id.task_sequence_id:
|
||||
combine_seq = project_id.seq2 + "/" + str(self.env['ir.sequence'].next_by_code(task_sq_code))
|
||||
else:
|
||||
combine_seq = self.env['ir.sequence'].next_by_code('project.task') or _('New')
|
||||
vals.update({'seq3': combine_seq})
|
||||
for p_task in self:
|
||||
for task in p_task.subtask_ids:
|
||||
if task.state_type_name:
|
||||
msg = task.state_type_name + ':' + task.name
|
||||
else:
|
||||
msg = task.name
|
||||
p_task.message_post(body=msg)
|
||||
for j in p_task.tag_ids:
|
||||
old_ids.append(j.name)
|
||||
res = super(Projecttask, self).write(vals)
|
||||
for task in self:
|
||||
if 'stage_id' in vals and vals['stage_id'] and task.stage_id.name == 'Done':
|
||||
task.date_deadline = False
|
||||
elif 'stage_id' in vals and vals['stage_id'] and task.stage_id.name != 'Done':
|
||||
task.date_deadline = task.date_start
|
||||
for obj in self:
|
||||
new_ids = []
|
||||
if vals.get('tag_ids', False):
|
||||
all_ids = vals.get('tag_ids')
|
||||
if all_ids[0][1] == False:
|
||||
for i in all_ids[0][2]:
|
||||
tag_obj = self.env['project.tags'].search([('id', '=', i)]).name
|
||||
new_ids.append(tag_obj)
|
||||
|
||||
final_new = str(new_ids)[1:-1]
|
||||
final_old = str(old_ids)[1:-1]
|
||||
|
||||
obj.message_post(body=_("Tags added: %s --> %s ") % (final_old, final_new))
|
||||
else:
|
||||
for i in all_ids:
|
||||
tag_obj = self.env['project.tags'].search([('id', '=', i[1])]).name
|
||||
new_ids.append(tag_obj)
|
||||
|
||||
final_new = str(new_ids)[1:-1]
|
||||
final_old = str(old_ids)[1:-1]
|
||||
|
||||
obj.message_post(body=_("Tags added: %s --> %s ") % (final_old, final_new))
|
||||
if vals.get('stage_id'):
|
||||
task_type_search = self.env['res.config.settings'].search([], limit=1, order="id desc").warning_child_task
|
||||
if task_type_search:
|
||||
if vals.get('stage_id'):
|
||||
stage_name = self.env['project.task.type'].browse(vals.get('stage_id')).name
|
||||
if self.is_task_done == False:
|
||||
vals.update({
|
||||
'state' : '1_done'
|
||||
|
||||
})
|
||||
|
||||
else:
|
||||
vals.update({
|
||||
'state' : '04_waiting_normal',
|
||||
})
|
||||
|
||||
if stage_name in ['Archive']:
|
||||
vals.update({
|
||||
'active':False
|
||||
})
|
||||
|
||||
if vals.get('task_product_id'):
|
||||
new_task_product_id = self.env['product.template'].browse(int(vals.get('task_product_id')))
|
||||
old_task_product_id = self.task_product_id
|
||||
|
||||
new_task_product_id.write({
|
||||
'task_ids' : [(4, self.id)],
|
||||
'project_id' : self.project_id.id
|
||||
})
|
||||
|
||||
if old_task_product_id:
|
||||
old_task_product_id.write({
|
||||
'task_ids' : [(3, self.id)],
|
||||
})
|
||||
return res
|
||||
|
||||
# @api.returns('self', lambda value: value.id)
|
||||
def copy(self, default=None):
|
||||
rec = super(Projecttask, self).copy(default)
|
||||
return rec
|
||||
|
||||
def action_get_attachment_view(self):
|
||||
self.ensure_one()
|
||||
res = self.env['ir.actions.act_window'].for_xml_id('base', 'action_attachment')
|
||||
res['domain'] = [('res_model', '=', 'project.task'), ('res_id', 'in', self.ids)]
|
||||
res['context'] = {'default_res_model': 'project.task', 'default_res_id': self.id}
|
||||
return res
|
||||
|
||||
|
||||
|
||||
def duplicate_task(self):
|
||||
for task in self:
|
||||
task.copy(default={
|
||||
'name' : task.name + ' (Copy)',
|
||||
'stage_id' : task.stage_id and task.stage_id.id,
|
||||
|
||||
})
|
||||
|
||||
@api.onchange('parent_id')
|
||||
def button_disable(self):
|
||||
if self.parent_id:
|
||||
self.is_subtask = True
|
||||
self.task_parent_id = self.parent_id.id
|
||||
self.project_id = self.parent_id.project_id
|
||||
else:
|
||||
self.is_subtask = False
|
||||
self.task_parent_id = self.id
|
||||
# self.project_id = False
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class subtask_wizard(models.Model):
|
||||
_name = 'subtask.wizard'
|
||||
_description = "Subtask Wizard"
|
||||
|
||||
subtask_lines = fields.One2many('project.task', 'wiz_id', string="Task Line")
|
||||
|
||||
def create_subtask(self):
|
||||
list_of_stage = []
|
||||
project_task_id = self.env['project.task'].browse(self._context.get('active_id'))
|
||||
for stage in project_task_id.project_id.type_ids:
|
||||
stage_ids = self.env['project.task.type'].search([('id', '=', stage.id)])
|
||||
list_of_stage.append(stage_ids.id)
|
||||
for task in self.subtask_lines:
|
||||
task.task_parent_id = self._context.get('active_id')
|
||||
task.description = task.des
|
||||
task.is_subtask = True
|
||||
task.project_id = project_task_id.project_id.id
|
||||
task.subtask_check = True
|
||||
if task.state_type_name:
|
||||
msg = task.state_type_name + ' ' +':' + ' ' + task.name
|
||||
else:
|
||||
msg = 'new' + ' ' +':' + ' ' + task.name
|
||||
for t in task.task_parent_id:
|
||||
t.sudo().message_post(body=msg)
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
||||
class ProjectTaskType(models.Model):
|
||||
_inherit= 'project.task.type'
|
||||
|
||||
|
||||
task_completed = fields.Boolean(string='Task Completed')
|
||||
dft_assign_user_id = fields.Many2one('res.users', string="Default Assigned User")
|
||||
dft_for_new_project = fields.Boolean(string="Default for New Project")
|
||||
|
||||
|
||||
|
||||
class Project(models.Model):
|
||||
_inherit = 'project.project'
|
||||
|
||||
|
||||
priority = fields.Selection([
|
||||
('0', 'Normal'),
|
||||
('1', 'Important'),
|
||||
('2', 'Good'),
|
||||
('3', 'Excellent'),
|
||||
], index=True, string="Priority")
|
||||
|
||||
@api.onchange('priority')
|
||||
def onchange_priority(self):
|
||||
project_task = self.env['project.task'].search([('project_id','in',self.ids)])
|
||||
for i in project_task:
|
||||
i.priority=self.priority
|
||||
|
||||
|
||||
|
||||
class AnalyticLine(models.Model):
|
||||
_inherit = 'account.analytic.line'
|
||||
|
||||
end_time = fields.Datetime(
|
||||
string='End Date',
|
||||
)
|
||||
start_time = fields.Datetime(
|
||||
string='Start Date',
|
||||
)
|
||||
|
||||
|
||||
|
||||
class Calculate_time(models.TransientModel):
|
||||
_name = 'project.task.timer.wizard'
|
||||
_description="Calculate Time"
|
||||
|
||||
|
||||
description=fields.Char(string='Description')
|
||||
|
||||
end_time = fields.Datetime(string='End Date', readonly=True)
|
||||
start_time = fields.Datetime(string='Start Date', readonly=True)
|
||||
duration = fields.Float(string='Duration',readonly=True)
|
||||
|
||||
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields):
|
||||
res = super(Calculate_time, self).default_get(fields)
|
||||
active_ids = self.env.context.get('active_ids')
|
||||
current_task_id = self.env['project.task'].browse(active_ids[0])
|
||||
|
||||
current_user = self.env.user
|
||||
user_time = self.env['project.task.user.time'].search([
|
||||
('task_id', '=', current_task_id.id),
|
||||
('user_id', '=', current_user.id),
|
||||
('end_time', '=', False)
|
||||
], limit=1)
|
||||
|
||||
if user_time:
|
||||
diff = datetime.now() - user_time.start_time
|
||||
hours, remainder = divmod(diff.total_seconds(), 3600)
|
||||
minutes, _ = divmod(remainder, 60)
|
||||
|
||||
time_float = hours + minutes / 60.0
|
||||
|
||||
res.update({
|
||||
'start_time': user_time.start_time,
|
||||
'end_time': datetime.now(),
|
||||
'duration': time_float,
|
||||
})
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def end_task_kanban(self):
|
||||
active_ids = self.env.context.get('active_ids')
|
||||
current_task_id = self.env['project.task'].browse(active_ids)
|
||||
current_user = self.env.user
|
||||
for task in current_task_id:
|
||||
user_time = self.env['project.task.user.time'].search([
|
||||
('task_id', '=', task.id),
|
||||
('user_id', '=', current_user.id),
|
||||
('end_time', '=', False)
|
||||
], limit=1)
|
||||
if user_time:
|
||||
user_time.end_time = datetime.now()
|
||||
user_time._compute_duration()
|
||||
task.task_Start = False
|
||||
if self.env.user.has_group(
|
||||
'bi_all_in_one_project_management_system.all_project_user') or self.env.user.has_group(
|
||||
'bi_all_in_one_project_management_system.group_project_manager'):
|
||||
timesheet = self.env['account.analytic.line']
|
||||
vals = {
|
||||
'date': user_time.start_time,
|
||||
'name': self.description,
|
||||
'project_id': task.project_id.id,
|
||||
'task_id': task.id,
|
||||
'unit_amount': user_time.duration,
|
||||
'end_time': user_time.end_time,
|
||||
}
|
||||
|
||||
timesheet.create(vals)
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'reload',
|
||||
}
|
||||
else:
|
||||
raise ValidationError("You cannot end this task.")
|
||||
else:
|
||||
raise ValidationError("No active task found to end for this user")
|
||||
|
||||
def end_task(self):
|
||||
active_ids = self.env.context.get('active_ids')
|
||||
current_task_id = self.env['project.task'].browse(active_ids)
|
||||
current_user = self.env.user
|
||||
|
||||
for task in current_task_id:
|
||||
user_time = self.env['project.task.user.time'].search([
|
||||
('task_id', '=', task.id),
|
||||
('user_id', '=', current_user.id),
|
||||
('end_time', '=', False)
|
||||
], limit=1)
|
||||
if user_time:
|
||||
user_time.end_time = datetime.now()
|
||||
user_time._compute_duration()
|
||||
task.task_Start = False
|
||||
if self.env.user.has_group(
|
||||
'bi_all_in_one_project_management_system.all_project_user') or self.env.user.has_group(
|
||||
'bi_all_in_one_project_management_system.group_project_manager'):
|
||||
timesheet = self.env['account.analytic.line']
|
||||
vals = {
|
||||
'date': user_time.start_time,
|
||||
'name': self.description,
|
||||
'project_id': task.project_id.id,
|
||||
'task_id': task.id,
|
||||
'unit_amount': user_time.duration,
|
||||
'end_time': user_time.end_time,
|
||||
}
|
||||
|
||||
timesheet.create(vals)
|
||||
|
||||
elif self.env.user.has_group('project.group_project_user'):
|
||||
|
||||
if self.env.user in current_task_id.user_ids:
|
||||
timesheet = self.env['account.analytic.line']
|
||||
vals = {
|
||||
'date': user_time.start_time,
|
||||
'name': self.description,
|
||||
'project_id': task.project_id.id,
|
||||
'task_id': task.id,
|
||||
'unit_amount': user_time.duration,
|
||||
'end_time': user_time.end_time,
|
||||
}
|
||||
timesheet.create(vals)
|
||||
|
||||
else:
|
||||
raise ValidationError("You can not end this task.")
|
||||
@@ -0,0 +1,85 @@
|
||||
# -- coding: utf-8 --
|
||||
# Part of BrowseInfo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields , models , api , _
|
||||
from ast import literal_eval
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools import float_is_zero, float_compare, DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class ResCompany(models.Model):
|
||||
_inherit = 'res.company'
|
||||
|
||||
start_notification = fields.Boolean(string='Delay Task Start Notification', default=False)
|
||||
delay_notification = fields.Boolean(string='Delay Task Deadline/Overdue Notification', default=False)
|
||||
start_count = fields.Integer(string='Delay Day(s)', default=0)
|
||||
delay_count = fields.Integer(string='Delay Deadline Day(s)', default=0)
|
||||
done_stage_ckecklist = fields.Many2one('project.task.type', 'Done Stage')
|
||||
todo_stage_ckecklist = fields.Many2one('project.task.type', 'To Do Stage')
|
||||
cancel_stage_ckecklist = fields.Many2one('project.task.type', 'Cancel Stage')
|
||||
warning_child_task = fields.Many2one('project.task.type',
|
||||
'Prevent stage to change until all tasks on the same stage')
|
||||
|
||||
first_reminder = fields.Float(string='First Reminder (Days)')
|
||||
second_reminder = fields.Float(string='Second Reminder (Days)')
|
||||
first_date = fields.Date(compute='convert_first_date')
|
||||
second_date = fields.Date(compute='convert_second_date')
|
||||
allow_multi_task = fields.Boolean(string='Allow Multi Task')
|
||||
|
||||
|
||||
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = "res.config.settings"
|
||||
_description="Res config Settings"
|
||||
|
||||
start_notification = fields.Boolean(string='Delay Task Start Notification', related='company_id.start_notification', default=False, readonly=False)
|
||||
delay_notification = fields.Boolean(string='Delay Task Deadline/Overdue Notification', related='company_id.delay_notification', default=False, readonly=False)
|
||||
start_count = fields.Integer(string='Delay Day(s)', related='company_id.start_count', default=0, readonly=False)
|
||||
delay_count = fields.Integer(string='Delay Deadline Day(s)', related='company_id.delay_count', default=0, readonly=False)
|
||||
done_stage_ckecklist = fields.Many2one('project.task.type', string='Done Stage', related='company_id.done_stage_ckecklist', readonly=False)
|
||||
todo_stage_ckecklist = fields.Many2one('project.task.type', string='To Do Stage', related='company_id.todo_stage_ckecklist' , readonly=False)
|
||||
cancel_stage_ckecklist = fields.Many2one('project.task.type', string='Cancel Stage', related='company_id.cancel_stage_ckecklist', readonly=False)
|
||||
warning_child_task = fields.Many2one('project.task.type', string='Prevent stage to change until all tasks on the same stage', related='company_id.warning_child_task' , readonly=False)
|
||||
|
||||
first_reminder = fields.Float(string='First Reminder (Days)', related='company_id.first_reminder', readonly=False)
|
||||
second_reminder = fields.Float(string='Second Reminder (Days)', related='company_id.second_reminder', readonly=False)
|
||||
first_date = fields.Date(string='First Reminder Date', related='company_id.first_date', readonly=False)
|
||||
second_date = fields.Date(string='Second Reminder Date', related='company_id.second_date', readonly=False)
|
||||
allow_multi_task = fields.Boolean(string='Allow Multi Task', related='company_id.allow_multi_task', readonly=False)
|
||||
|
||||
|
||||
def validate_date(self):
|
||||
if self.first_reminder > self.second_reminder:
|
||||
return True
|
||||
else:
|
||||
raise UserError(_('First Reminder(Days) should be greater than Second Reminder(Days)'))
|
||||
return False
|
||||
|
||||
|
||||
@api.onchange('first_reminder')
|
||||
def convert_first_date(self):
|
||||
self.first_date = None
|
||||
for tasks in self.env['project.task'].search([]):
|
||||
if tasks.date_deadline !=False:
|
||||
reminder_date = datetime.strptime(tasks.date_deadline.strftime("%Y/%m/%d %H:%M:%S"),"%Y/%m/%d %H:%M:%S")
|
||||
first = reminder_date - timedelta(days=self.first_reminder)
|
||||
then = datetime.strptime(str(first), '%Y-%m-%d %H:%M:%S').date()
|
||||
today = datetime.now().date()
|
||||
if then == today:
|
||||
self.first_date = then
|
||||
|
||||
|
||||
@api.onchange('second_reminder')
|
||||
def convert_second_date(self):
|
||||
self.second_date = None
|
||||
for proj_task in self.env['project.task'].search([]):
|
||||
if proj_task.date_deadline !=False:
|
||||
reminders_date = datetime.strptime(proj_task.date_deadline.strftime("%Y/%m/%d %H:%M:%S"),"%Y/%m/%d %H:%M:%S")
|
||||
second = reminders_date - timedelta(days=self.second_reminder)
|
||||
now = datetime.strptime(str(second), '%Y-%m-%d %H:%M:%S').date()
|
||||
today = datetime.now().date()
|
||||
if now == today:
|
||||
self.second_date = now
|
||||
@@ -0,0 +1,168 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of BrowseInfo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import time
|
||||
import tempfile
|
||||
import binascii
|
||||
import xlrd
|
||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT
|
||||
from datetime import date, datetime
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
from odoo import models, fields, exceptions, api, _
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
import io
|
||||
from io import StringIO
|
||||
|
||||
try:
|
||||
import csv
|
||||
except ImportError:
|
||||
_logger.debug('Cannot `import csv`.')
|
||||
try:
|
||||
import xlwt
|
||||
except ImportError:
|
||||
_logger.debug('Cannot `import xlwt`.')
|
||||
try:
|
||||
import cStringIO
|
||||
except ImportError:
|
||||
_logger.debug('Cannot `import cStringIO`.')
|
||||
try:
|
||||
import base64
|
||||
except ImportError:
|
||||
_logger.debug('Cannot `import base64`.')
|
||||
|
||||
|
||||
class import_task(models.TransientModel):
|
||||
_name = "import.task"
|
||||
_description = "Import Task"
|
||||
|
||||
file = fields.Binary('File')
|
||||
import_option = fields.Selection([('csv', 'CSV File'), ('xls', 'XLS File')], string='Select', default='csv')
|
||||
|
||||
def create_task(self, values):
|
||||
project_task_obj = self.env['project.task']
|
||||
|
||||
project_id = self.find_project(values.get('project_id'))
|
||||
user_ids = self.find_user(values.get('user_ids'))
|
||||
tag_ids = self.find_tags(values.get('tag_ids'))
|
||||
if values.get('date_deadline') != '':
|
||||
deadline_date = self.find_deadline_date(values.get('date_deadline'))
|
||||
else:
|
||||
deadline_date = False
|
||||
|
||||
vals = {
|
||||
'name': values.get('name'),
|
||||
'project_id': project_id.id,
|
||||
'user_ids': [(6, 0, [x.id for x in user_ids])],
|
||||
'tag_ids': [(6, 0, [x.id for x in tag_ids])],
|
||||
'date_deadline': deadline_date,
|
||||
'description': values.get('description'),
|
||||
}
|
||||
res = project_task_obj.create(vals)
|
||||
return res
|
||||
|
||||
def find_project(self, name):
|
||||
project_obj = self.env['project.project']
|
||||
project_search = project_obj.search([('name', '=', name)])
|
||||
if project_search:
|
||||
return project_search
|
||||
else:
|
||||
project_id = project_obj.create({
|
||||
'name': name})
|
||||
return project_id
|
||||
|
||||
def find_tags(self, name):
|
||||
project_tags_obj = self.env['project.tags']
|
||||
project_tags_search = project_tags_obj.search([('name', '=', name)])
|
||||
if project_tags_search:
|
||||
return project_tags_search
|
||||
else:
|
||||
raise ValidationError(_(' "%s" Tags is not available.') % name)
|
||||
|
||||
def find_user(self, name):
|
||||
user_obj = self.env['res.users']
|
||||
user_search = user_obj.search([('name', '=', name)])
|
||||
if user_search:
|
||||
return user_search
|
||||
else:
|
||||
raise ValidationError(_(' "%s" User is not available.') % name)
|
||||
|
||||
def find_deadline_date(self, date):
|
||||
project_task_obj = self.env['project.task']
|
||||
DATETIME_FORMAT = "%Y-%m-%d"
|
||||
if date:
|
||||
try:
|
||||
i_date = datetime.strptime(date, DATETIME_FORMAT)
|
||||
return i_date
|
||||
except Exception:
|
||||
raise ValidationError(_('Wrong Date Format. Date Should be in format YYYY-MM-DD.'))
|
||||
|
||||
def import_task(self):
|
||||
|
||||
if self.import_option == 'csv':
|
||||
print('if called=============')
|
||||
keys = ['name', 'project_id', 'user_ids', 'tag_ids', 'date_deadline', 'description']
|
||||
try:
|
||||
csv_data = base64.b64decode(self.file)
|
||||
data_file = io.StringIO(csv_data.decode("utf-8"))
|
||||
data_file.seek(0)
|
||||
file_reader = []
|
||||
csv_reader = csv.reader(data_file, delimiter=',')
|
||||
file_reader.extend(csv_reader)
|
||||
|
||||
except Exception:
|
||||
raise exceptions.ValidationError(_("Please select CSV/XLS file or You have selected invalid file "))
|
||||
values = {}
|
||||
for i in range(len(file_reader)):
|
||||
field = list(map(str, file_reader[i]))
|
||||
values = dict(zip(keys, field))
|
||||
if values:
|
||||
if i == 0:
|
||||
continue
|
||||
else:
|
||||
res = self.create_task(values)
|
||||
elif self.import_option == 'xls':
|
||||
print('elif called============')
|
||||
try:
|
||||
fp = tempfile.NamedTemporaryFile(delete=False, suffix=".xls")
|
||||
fp.write(base64.b64decode(self.file))
|
||||
fp.seek(0)
|
||||
workbook = xlrd.open_workbook(fp.name)
|
||||
sheet = workbook.sheet_by_index(0)
|
||||
except Exception:
|
||||
raise ValidationError(_("Please select CSV/XLS file or You have selected invalid file "))
|
||||
|
||||
for row_no in range(1, sheet.nrows): # skip header
|
||||
line = [str(cell.value).strip() for cell in sheet.row(row_no)]
|
||||
|
||||
# Safely handle date field
|
||||
date_string = False
|
||||
if line[4]:
|
||||
try:
|
||||
if isinstance(sheet.cell(row_no, 4).value, (int, float)):
|
||||
# Excel date number
|
||||
a1_as_datetime = datetime(
|
||||
*xlrd.xldate_as_tuple(sheet.cell(row_no, 4).value, workbook.datemode))
|
||||
date_string = a1_as_datetime.strftime('%Y-%m-%d')
|
||||
else:
|
||||
# String date (manual input)
|
||||
date_string = datetime.strptime(line[4], '%Y-%m-%d').strftime('%Y-%m-%d')
|
||||
except Exception:
|
||||
raise ValidationError(_('Wrong Date Format. Date Should be in format YYYY-MM-DD.'))
|
||||
|
||||
values = {
|
||||
'name': line[0],
|
||||
'project_id': line[1],
|
||||
'user_ids': line[2],
|
||||
'tag_ids': line[3],
|
||||
'date_deadline': date_string,
|
||||
'description': line[5] if len(line) > 5 else '',
|
||||
}
|
||||
|
||||
self.create_task(values)
|
||||
return True
|
||||
else:
|
||||
raise ValidationError(_("Invalid import option selected."))
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of BrowseInfo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import SUPERUSER_ID
|
||||
from odoo import api, fields, models, _
|
||||
from datetime import datetime, timedelta ,date
|
||||
import calendar
|
||||
|
||||
class ResUsers(models.Model):
|
||||
_inherit = "res.users"
|
||||
|
||||
assign_update_ids = fields.One2many('task.update','assign_task_id')
|
||||
created_task_ids = fields.One2many('task.update','create_task_id')
|
||||
|
||||
def task_update_email(self):
|
||||
superuser_id = self.env['res.partner'].browse(SUPERUSER_ID)
|
||||
|
||||
user_ids = self.env['res.users'].search([('active','=',True),('share','=',False)])
|
||||
|
||||
for user in user_ids:
|
||||
create_task_ids = self.env['task.update']
|
||||
task_list_ids = self.env['task.update']
|
||||
|
||||
task_ids = self.env['project.task'].search(['|',('user_ids','=',user.id),('create_uid','=',user.id)])
|
||||
|
||||
if task_ids:
|
||||
for task in task_ids.filtered(lambda x : x.user_ids == user):
|
||||
today = datetime.now().date()
|
||||
overdue_days = ''
|
||||
if task.date_deadline:
|
||||
days=today -task.date_deadline.date()
|
||||
overdue_days=days.days
|
||||
task_list_ids += self.env['task.update'].create({'name':task.name,
|
||||
'date_deadline':task.date_deadline,
|
||||
'stage_id':task.stage_id.id,
|
||||
'dueday':overdue_days,
|
||||
'assign_task_id' : user.id
|
||||
})
|
||||
|
||||
for task in task_ids.filtered(lambda x : x.create_uid == user):
|
||||
today = datetime.now().date()
|
||||
overdue_days = ''
|
||||
if task.date_deadline:
|
||||
days=today -task.date_deadline.date()
|
||||
overdue_days=days.days
|
||||
create_task_ids += self.env['task.update'].create({'name':task.name,
|
||||
'date_deadline':task.date_deadline,
|
||||
'stage_id':task.stage_id.id,
|
||||
'dueday':overdue_days,
|
||||
'create_task_id' : user.id
|
||||
})
|
||||
|
||||
user.sudo().write({
|
||||
'created_task_ids' : [(6,0,create_task_ids.ids)],
|
||||
'assign_update_ids' : [(6,0,task_list_ids.ids)]
|
||||
})
|
||||
|
||||
template_id = self.env['ir.model.data']._xmlid_lookup(
|
||||
'bi_all_in_one_project_management_system.email_template_task_update')[1]
|
||||
email_template_obj = self.env['mail.template'].browse(template_id)
|
||||
if template_id:
|
||||
values = email_template_obj._generate_template([user.id],('subject', 'body_html', 'email_from', 'email_to', 'partner_to', 'email_cc', 'reply_to', 'scheduled_date'))[user.id]
|
||||
values['email_to'] = user.partner_id.email
|
||||
values['res_id'] = False
|
||||
values['author_id'] = user.partner_id.id
|
||||
mail_mail_obj = self.env['mail.mail']
|
||||
mail_create_id = mail_mail_obj.sudo().create(values)
|
||||
if mail_create_id:
|
||||
mail_create_id.sudo().send()
|
||||
return True
|
||||
|
||||
|
||||
|
||||
def weekly_task_update_email(self):
|
||||
superuser_id = self.env['res.partner'].browse(SUPERUSER_ID)
|
||||
|
||||
user_ids = self.env['res.users'].search([('active', '=', True), ('share', '=', False)])
|
||||
|
||||
for user in user_ids:
|
||||
create_task_ids = self.env['task.update']
|
||||
task_list_ids = self.env['task.update']
|
||||
|
||||
task_ids = self.env['project.task'].search(['|', ('user_ids', '=', user.id), ('create_uid', '=', user.id)])
|
||||
|
||||
if task_ids:
|
||||
today = datetime.now().date() # Get today's date
|
||||
|
||||
for task in task_ids.filtered(lambda x: x.user_ids == user):
|
||||
overdue_days = ''
|
||||
if task.date_deadline:
|
||||
days = today - task.date_deadline.date() # Ensure date comparison
|
||||
overdue_days = days.days
|
||||
task_list_ids += self.env['task.update'].create({
|
||||
'name': task.name,
|
||||
'date_deadline': task.date_deadline,
|
||||
'stage_id': task.stage_id.id,
|
||||
'dueday': overdue_days,
|
||||
'assign_task_id': user.id
|
||||
})
|
||||
|
||||
for task in task_ids.filtered(lambda x: x.create_uid == user):
|
||||
overdue_days = ''
|
||||
if task.date_deadline:
|
||||
days = today - task.date_deadline.date() # Ensure date comparison
|
||||
overdue_days = days.days
|
||||
create_task_ids += self.env['task.update'].create({
|
||||
'name': task.name,
|
||||
'date_deadline': task.date_deadline,
|
||||
'stage_id': task.stage_id.id,
|
||||
'dueday': overdue_days,
|
||||
'create_task_id': user.id
|
||||
})
|
||||
|
||||
user.sudo().write({
|
||||
'created_task_ids': [(6, 0, create_task_ids.ids)],
|
||||
'assign_update_ids': [(6, 0, task_list_ids.ids)]
|
||||
})
|
||||
|
||||
template_id = self.env['ir.model.data']._xmlid_lookup(
|
||||
'bi_all_in_one_project_management_system.email_template_task_update')[1]
|
||||
email_template_obj = self.env['mail.template'].browse(template_id)
|
||||
if template_id:
|
||||
values = email_template_obj._generate_template(
|
||||
[user.id], ('subject', 'body_html', 'email_from', 'email_to',
|
||||
'partner_to', 'email_cc', 'reply_to', 'scheduled_date')
|
||||
)[user.id]
|
||||
values['email_to'] = user.partner_id.email
|
||||
values['res_id'] = False
|
||||
values['author_id'] = user.partner_id.id
|
||||
mail_mail_obj = self.env['mail.mail']
|
||||
mail_create_id = mail_mail_obj.sudo().create(values)
|
||||
if mail_create_id:
|
||||
mail_create_id.sudo().send()
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Task_updates(models.Model):
|
||||
_name='task.update'
|
||||
_description="Task Updates"
|
||||
|
||||
name=fields.Char(string='name')
|
||||
date_deadline=fields.Date(string='Date Deadline')
|
||||
stage_id = fields.Many2one('project.task.type', string='Stage')
|
||||
dueday=fields.Char(string='Overdue')
|
||||
assign_task_id=fields.Many2one('res.users')
|
||||
create_task_id=fields.Many2one('res.users')
|
||||
Reference in New Issue
Block a user