[IMP]improve code and add tooltip on task_management
[odoo/odoo.git] / addons / project / project.py
index e7af9f4..ab02cc8 100644 (file)
@@ -165,14 +165,29 @@ class project(osv.osv):
             res[task.project_id.id] += 1
         return res
 
+    def _get_followers(self, cr, uid, ids, name, arg, context=None):
+        '''
+        Functional field that computes the users that are 'following' a thread.
+        '''
+        res = {}
+        for project in self.browse(cr, uid, ids, context=context):
+            l = set()
+            for message in project.message_ids:
+                l.add(message.user_id and message.user_id.id or False)
+            res[project.id] = list(filter(None, l))
+        return res
+
+    def _search_followers(self, cr, uid, obj, name, args, context=None):
+        project_obj = self.pool.get('project.project')
+        project_ids = project_obj.search(cr, uid, [('message_ids.user_id.id', 'in', args[0][2])], context=context)
+        return [('id', 'in', project_ids)]
+
     _columns = {
         'complete_name': fields.function(_complete_name, string="Project Name", type='char', size=250),
         'active': fields.boolean('Active', help="If the active field is set to False, it will allow you to hide the project without removing it."),
         'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of Projects."),
         'analytic_account_id': fields.many2one('account.analytic.account', 'Analytic Account', help="Link this project to an analytic account if you need financial management on projects. It enables you to connect projects with budgets, planning, cost and revenue analysis, timesheets on projects, etc.", ondelete="cascade", required=True),
         'priority': fields.integer('Sequence', help="Gives the sequence order when displaying the list of projects"),
-        'warn_manager': fields.boolean('Notify Manager', help="If you check this field, the project manager will receive an email each time a task is completed by his team.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
-
         'members': fields.many2many('res.users', 'project_user_rel', 'project_id', 'uid', 'Project Members',
             help="Project's members are users who can have an access to the tasks related to this project.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
         'tasks': fields.one2many('project.task', 'project_id', "Task Activities"),
@@ -197,19 +212,18 @@ class project(osv.osv):
                 'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'state'], 20),
             }),
         'resource_calendar_id': fields.many2one('resource.calendar', 'Working Time', help="Timetable working hours to adjust the gantt diagram report", states={'close':[('readonly',True)]} ),
-        'warn_customer': fields.boolean('Warn Partner', help="If you check this, the user will have a popup when closing a task that propose a message to send by email to the customer.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
-        'warn_header': fields.text('Mail Header', help="Header added at the beginning of the email for the warning message sent to the customer when a task is closed.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
-        'warn_footer': fields.text('Mail Footer', help="Footer added at the beginning of the email for the warning message sent to the customer when a task is closed.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
         'type_ids': fields.many2many('project.task.type', 'project_task_type_rel', 'project_id', 'type_id', 'Tasks Stages', states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
-        'use_tasks': fields.boolean('Use Tasks', help="Check this field if this project is aimed at managing tasks"),
         'task_count': fields.function(_task_count, type='integer', string="Open Tasks"),
         'color': fields.integer('Color Index'),
-        'company_uom_id': fields.related('company_id', 'project_time_mode_id', type='many2one', relation='product.uom'),
+        'privacy_visibility': fields.selection([('public','Public'), ('followers','Followers Only')], 'Privacy / Visibility'),
+        'state': fields.selection([('template', 'Template'),('draft','New'),('open','In Progress'), ('cancelled', 'Cancelled'),('pending','Pending'),('close','Closed')], 'Status', required=True,),
+        'followers': fields.function(_get_followers, method=True, fnct_search=_search_followers,
+                        type='many2many', relation='res.users', string='Followers'),
      }
     
     def dummy(self, cr, uid, ids, context):
         return True
-       
+
     def _get_type_common(self, cr, uid, context):
         ids = self.pool.get('project.task.type').search(cr, uid, [('case_default','=',1)], context=context)
         return ids
@@ -217,10 +231,11 @@ class project(osv.osv):
     _order = "sequence"
     _defaults = {
         'active': True,
+        'type': 'contract',
+        'state': 'open',
         'priority': 1,
         'sequence': 10,
         'type_ids': _get_type_common,
-        'use_tasks': True,
     }
 
     # TODO: Why not using a SQL contraints ?
@@ -818,7 +833,7 @@ class task(base_stage, osv.osv):
     #
     def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
         users_obj = self.pool.get('res.users')
-
+        if context is None: context = {}
         # read uom as admin to avoid access rights issues, e.g. for portal/share users,
         # this should be safe (no context passed to avoid side-effects)
         obj_tm = users_obj.browse(cr, 1, uid, context=context).company_id.project_time_mode_id
@@ -894,28 +909,12 @@ class task(base_stage, osv.osv):
         return True
 
     def action_close(self, cr, uid, ids, context=None):
-        """ This action closes the task, then opens the wizard to send an 
-            email to the partner or the project manager.
+        """ This action closes the task 
         """
         task_id = len(ids) and ids[0] or False
         self._check_child_task(cr, uid, ids, context=context)
         if not task_id: return False
-        task = self.browse(cr, uid, task_id, context=context)
-        project = task.project_id
-        res = self.do_close(cr, uid, [task_id], context=context)
-        if project.warn_manager or project.warn_customer:
-            return {
-                'name': _('Send Email after close task'),
-                'view_type': 'form',
-                'view_mode': 'form',
-                'res_model': 'mail.compose.message',
-                'type': 'ir.actions.act_window',
-                'target': 'new',
-                'nodestroy': True,
-                'context': {'active_id': task.id,
-                            'active_model': 'project.task'}
-           }
-        return res
+        return self.do_close(cr, uid, [task_id], context=context)
 
     def do_close(self, cr, uid, ids, context=None):
         """ Compatibility when changing to case_close. """
@@ -923,7 +922,6 @@ class task(base_stage, osv.osv):
     
     def case_close(self, cr, uid, ids, context=None):
         """ Closes Task """
-        request = self.pool.get('res.request')
         if not isinstance(ids, list): ids = [ids]
         for task in self.browse(cr, uid, ids, context=context):
             vals = {}
@@ -956,7 +954,6 @@ class task(base_stage, osv.osv):
         return self.case_cancel(cr, uid, ids, context=context)
     
     def case_cancel(self, cr, uid, ids, context=None):
-        request = self.pool.get('res.request')
         tasks = self.browse(cr, uid, ids, context=context)
         self._check_child_task(cr, uid, ids, context=context)
         for task in tasks:
@@ -1219,16 +1216,49 @@ class project_work(osv.osv):
 
 
 class account_analytic_account(osv.osv):
-
     _inherit = 'account.analytic.account'
     _description = 'Analytic Account'
+    _columns = {
+        'use_tasks': fields.boolean('Tasks Management',help="If check,this contract will be available in the project menu and you will be able to manage tasks or track issues"),
+        'company_uom_id': fields.related('company_id', 'project_time_mode_id', type='many2one', relation='product.uom'),
+    }
+
+    def _trigger_project_creation(self, cr, uid, vals, context=None):
+        '''
+        This function is used to decide if a project needs to be automatically created or not when an analytic account is created. It returns True if it needs to be so, False otherwise.
+        '''
+        return vals.get('use_tasks')
+
+    def project_create(self, cr, uid, analytic_account_id, vals, context=None):
+        '''
+        This function is called at the time of analytic account creation and is used to create a project automatically linked to it if the conditions are meet.
+        '''
+        project_pool = self.pool.get('project.project')
+        project_id = project_pool.search(cr, uid, [('analytic_account_id','=', analytic_account_id)])
+        if not project_id and self._trigger_project_creation(cr, uid, vals, context=context):
+            project_values = {
+                'name': vals.get('name'),
+                'analytic_account_id': analytic_account_id,
+            }
+            return project_pool.create(cr, uid, project_values, context=context)
+        return False
 
     def create(self, cr, uid, vals, context=None):
         if context is None:
             context = {}
         if vals.get('child_ids', False) and context.get('analytic_project_copy', False):
             vals['child_ids'] = []
-        return super(account_analytic_account, self).create(cr, uid, vals, context=context)
+        analytic_account_id = super(account_analytic_account, self).create(cr, uid, vals, context=context)
+        self.project_create(cr, uid, analytic_account_id, vals, context=context)
+        return analytic_account_id
+
+    def write(self, cr, uid, ids, vals, context=None):
+        name = vals.get('name')
+        for account in self.browse(cr, uid, ids, context=context):
+            if not name:
+                vals['name'] = account.name
+            self.project_create(cr, uid, account.id, vals, context=context)
+        return super(account_analytic_account, self).write(cr, uid, ids, vals, context=context)
 
     def unlink(self, cr, uid, ids, *args, **kwargs):
         project_obj = self.pool.get('project.project')