[IMP] project_issue: added a menuitem for tags in configuration
[odoo/odoo.git] / addons / project / project.py
index 49b8b48..f89ce83 100644 (file)
 #
 ##############################################################################
 
-import time
-from lxml import etree
 from datetime import datetime, date
+from lxml import etree
+import time
 
-import tools
-from base_status.base_stage import base_stage
-from osv import fields, osv
-from openerp.addons.resource.faces import task as Task
-from tools.translate import _
 from openerp import SUPERUSER_ID
+from openerp import tools
+from openerp.osv import fields, osv
+from openerp.tools.translate import _
+
+from openerp.addons.base_status.base_stage import base_stage
+from openerp.addons.resource.faces import task as Task
 
 _TASK_STATE = [('draft', 'New'),('open', 'In Progress'),('pending', 'Pending'), ('done', 'Done'), ('cancelled', 'Cancelled')]
 
@@ -39,22 +40,29 @@ class project_task_type(osv.osv):
     _columns = {
         'name': fields.char('Stage Name', required=True, size=64, translate=True),
         'description': fields.text('Description'),
-        'sequence': fields.char('Sequence'),
-        'case_default': fields.boolean('Common to All Projects',
+        'sequence': fields.integer('Sequence'),
+        'case_default': fields.boolean('Default for New Projects',
                         help="If you check this field, this stage will be proposed by default on each new project. It will not assign this stage to existing projects."),
         'project_ids': fields.many2many('project.project', 'project_task_type_rel', 'type_id', 'project_id', 'Projects'),
         'state': fields.selection(_TASK_STATE, 'Related Status', required=True,
                         help="The status of your document is automatically changed regarding the selected stage. " \
                             "For example, if a stage is related to the status 'Close', when your document reaches this stage, it is automatically closed."),
-        'fold': fields.boolean('Hide in views if empty',
+        'fold': fields.boolean('Folded by Default',
                         help="This stage is not visible, for example in status bar or kanban view, when there are no records in that stage to display."),
     }
+    def _get_default_project_id(self, cr, uid, ctx={}):
+        proj = ctx.get('default_project_id', False)
+        if type(proj) is int:
+            return [proj]
+        return proj
     _defaults = {
-        'sequence': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'project.task.type'),
+        'sequence': 1,
         'state': 'open',
         'fold': False,
-        'case_default': True,
+        'case_default': False,
+        'project_ids': _get_default_project_id
     }
+    _order = 'sequence'
 
 def short_name(name):
         """Keep first word(s) of name to make it small enough
@@ -183,10 +191,10 @@ class project(osv.osv):
         attachment = self.pool.get('ir.attachment')
         task = self.pool.get('project.task')
         for id in ids:
-            project_attachments = attachment.search(cr, uid, [('res_model', '=', 'project.project'), ('res_id', 'in', [id])], context=context, count=True)
-            task_ids = task.search(cr, uid, [('project_id', 'in', [id])], context=context)
+            project_attachments = attachment.search(cr, uid, [('res_model', '=', 'project.project'), ('res_id', '=', id)], context=context, count=True)
+            task_ids = task.search(cr, uid, [('project_id', '=', id)], context=context)
             task_attachments = attachment.search(cr, uid, [('res_model', '=', 'project.task'), ('res_id', 'in', task_ids)], context=context, count=True)
-            res[id] = project_attachments or 0 + task_attachments or 0
+            res[id] = (project_attachments or 0) + (task_attachments or 0)
         return res
         
     def _task_count(self, cr, uid, ids, field_name, arg, context=None):
@@ -199,7 +207,7 @@ class project(osv.osv):
     def _get_alias_models(self, cr, uid, context=None):
         """Overriden in project_issue to offer more options"""
         return [('project.task', "Tasks")]
-    
+
     def attachment_tree_view(self, cr, uid, ids, context):
         task_ids = self.pool.get('project.task').search(cr, uid, [('project_id', 'in', ids)])
         domain = [
@@ -268,7 +276,7 @@ class project(osv.osv):
         ids = self.pool.get('project.task.type').search(cr, uid, [('case_default','=',1)], context=context)
         return ids
 
-    _order = "sequence"
+    _order = "sequence, id"
     _defaults = {
         'active': True,
         'type': 'contract',
@@ -301,32 +309,22 @@ class project(osv.osv):
         task_obj = self.pool.get('project.task')
         task_ids = task_obj.search(cr, uid, [('project_id', 'in', ids), ('state', 'not in', ('cancelled', 'done'))])
         task_obj.case_close(cr, uid, task_ids, context=context)
-        self.write(cr, uid, ids, {'state':'close'}, context=context)
-        self.set_close_send_note(cr, uid, ids, context=context)
-        return True
+        return self.write(cr, uid, ids, {'state':'close'}, context=context)
 
     def set_cancel(self, cr, uid, ids, context=None):
         task_obj = self.pool.get('project.task')
         task_ids = task_obj.search(cr, uid, [('project_id', 'in', ids), ('state', '!=', 'done')])
         task_obj.case_cancel(cr, uid, task_ids, context=context)
-        self.write(cr, uid, ids, {'state':'cancelled'}, context=context)
-        self.set_cancel_send_note(cr, uid, ids, context=context)
-        return True
+        return self.write(cr, uid, ids, {'state':'cancelled'}, context=context)
 
     def set_pending(self, cr, uid, ids, context=None):
-        self.write(cr, uid, ids, {'state':'pending'}, context=context)
-        self.set_pending_send_note(cr, uid, ids, context=context)
-        return True
+        return self.write(cr, uid, ids, {'state':'pending'}, context=context)
 
     def set_open(self, cr, uid, ids, context=None):
-        self.write(cr, uid, ids, {'state':'open'}, context=context)
-        self.set_open_send_note(cr, uid, ids, context=context)
-        return True
+        return self.write(cr, uid, ids, {'state':'open'}, context=context)
 
     def reset_project(self, cr, uid, ids, context=None):
-        res = self.setActive(cr, uid, ids, value=True, context=context)
-        self.set_open_send_note(cr, uid, ids, context=context)
-        return res
+        return self.setActive(cr, uid, ids, value=True, context=context)
 
     def map_tasks(self, cr, uid, old_project_id, new_project_id, context=None):
         """ copy and map tasks from old to new project """
@@ -349,6 +347,7 @@ class project(osv.osv):
 
         context['active_test'] = False
         default['state'] = 'open'
+        default['line_ids'] = []
         default['tasks'] = []
         default.pop('alias_name', None)
         default.pop('alias_id', None)
@@ -531,7 +530,7 @@ def Project():
         # Prevent double project creation when 'use_tasks' is checked!
         context = dict(context, project_creation_in_progress=True)
         mail_alias = self.pool.get('mail.alias')
-        if not vals.get('alias_id'):
+        if not vals.get('alias_id') and vals.get('name', False):
             vals.pop('alias_name', None) # prevent errors during copy()
             alias_id = mail_alias.create_unique_alias(cr, uid,
                           # Using '+' allows using subaddressing for those who don't
@@ -540,27 +539,12 @@ def Project():
                           model_name=vals.get('alias_model', 'project.task'),
                           context=context)
             vals['alias_id'] = alias_id
-        vals['type'] = 'contract'
+        if vals.get('type', False) not in ('template','contract'):
+            vals['type'] = 'contract'
         project_id = super(project, self).create(cr, uid, vals, context)
         mail_alias.write(cr, uid, [vals['alias_id']], {'alias_defaults': {'project_id': project_id} }, context)
-        self.create_send_note(cr, uid, [project_id], context=context)
         return project_id
 
-    def create_send_note(self, cr, uid, ids, context=None):
-        return self.message_post(cr, uid, ids, body=_("Project has been <b>created</b>."), context=context)
-
-    def set_open_send_note(self, cr, uid, ids, context=None):
-        return self.message_post(cr, uid, ids, body=_("Project has been <b>opened</b>."), context=context)
-
-    def set_pending_send_note(self, cr, uid, ids, context=None):
-        return self.message_post(cr, uid, ids, body=_("Project is now <b>pending</b>."), context=context)
-
-    def set_cancel_send_note(self, cr, uid, ids, context=None):
-        return self.message_post(cr, uid, ids, body=_("Project has been <b>canceled</b>."), context=context)
-
-    def set_close_send_note(self, cr, uid, ids, context=None):
-        return self.message_post(cr, uid, ids, body=_("Project has been <b>closed</b>."), context=context)
-
     def write(self, cr, uid, ids, vals, context=None):
         # if alias_model has been changed, update alias_model_id accordingly
         if vals.get('alias_model'):
@@ -574,6 +558,20 @@ class task(base_stage, osv.osv):
     _date_name = "date_start"
     _inherit = ['mail.thread', 'ir.needaction_mixin']
 
+    _track = {
+        'state': {
+            'project.mt_task_new': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'new',
+            'project.mt_task_started': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'open',
+            'project.mt_task_closed': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'done',
+        },
+        'stage_id': {
+            'project.mt_task_stage': lambda self, cr, uid, obj, ctx=None: obj['state'] not in ['new', 'done', 'open'],
+        },
+        'kanban_state': {  # kanban state: tracked, but only block subtype
+            'project.mt_task_blocked': lambda self, cr, uid, obj, ctx=None: obj['kanban_state'] == 'blocked',
+        },
+    }
+
     def _get_default_project_id(self, cr, uid, context=None):
         """ Gives default section by checking if present in the context """
         return (self._resolve_project_id_from_context(cr, uid, context=context) or False)
@@ -602,18 +600,13 @@ class task(base_stage, osv.osv):
         stage_obj = self.pool.get('project.task.type')
         order = stage_obj._order
         access_rights_uid = access_rights_uid or uid
-        # lame way to allow reverting search, should just work in the trivial case
         if read_group_order == 'stage_id desc':
             order = '%s desc' % order
-        # retrieve section_id from the context and write the domain
-        # - ('id', 'in', 'ids'): add columns that should be present
-        # - OR ('case_default', '=', True), ('fold', '=', False): add default columns that are not folded
-        # - OR ('project_ids', 'in', project_id), ('fold', '=', False) if project_id: add project columns that are not folded
         search_domain = []
         project_id = self._resolve_project_id_from_context(cr, uid, context=context)
         if project_id:
             search_domain += ['|', ('project_ids', '=', project_id)]
-        search_domain += ['|', ('id', 'in', ids), ('case_default', '=', True)]
+        search_domain += [('id', 'in', ids)]
         stage_ids = stage_obj._search(cr, uid, search_domain, order=order, access_rights_uid=access_rights_uid, context=context)
         result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context)
         # restore order of the search
@@ -646,16 +639,6 @@ class task(base_stage, osv.osv):
         'user_id': _read_group_user_id,
     }
 
-    def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False):
-        obj_project = self.pool.get('project.project')
-        for domain in args:
-            if domain[0] == 'project_id' and (not isinstance(domain[2], str)):
-                id = isinstance(domain[2], list) and domain[2][0] or domain[2]
-                if id and isinstance(id, (long, int)):
-                    if obj_project.read(cr, user, id, ['state'])['state'] == 'template':
-                        args.append(('active', '=', False))
-        return super(task, self).search(cr, user, args, offset=offset, limit=limit, order=order, context=context, count=count)
-
     def _str_get(self, task, level=0, border='***', context=None):
         return border+' '+(task.user_id and task.user_id.name.upper() or '')+(level and (': L'+str(level)) or '')+(' - %.1fh / %.1fh'%(task.effective_hours or 0.0,task.planned_hours))+' '+border+'\n'+ \
             border[0]+' '+(task.name or '')+'\n'+ \
@@ -748,8 +731,8 @@ class task(base_stage, osv.osv):
         'description': fields.text('Description'),
         'priority': fields.selection([('4','Very Low'), ('3','Low'), ('2','Medium'), ('1','Important'), ('0','Very important')], 'Priority', select=True),
         'sequence': fields.integer('Sequence', select=True, help="Gives the sequence order when displaying a list of tasks."),
-        'stage_id': fields.many2one('project.task.type', 'Stage',
-                        domain="['&', ('fold', '=', False), '|', ('project_ids', '=', project_id), ('case_default', '=', True)]"),
+        'stage_id': fields.many2one('project.task.type', 'Stage', track_visibility='onchange',
+                        domain="['&', ('fold', '=', False), ('project_ids', '=', project_id)]"),
         'state': fields.related('stage_id', 'state', type="selection", store=True,
                 selection=_TASK_STATE, string="Status", readonly=True,
                 help='The status is set to \'Draft\', when a case is created.\
@@ -759,6 +742,7 @@ class task(base_stage, osv.osv):
                       set to \'Pending\'.'),
         'categ_ids': fields.many2many('project.category', string='Tags'),
         'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready for next stage')], 'Kanban State',
+                                         track_visibility='onchange',
                                          help="A task's kanban state indicates special situations affecting it:\n"
                                               " * Normal is the default situation\n"
                                               " * Blocked indicates something is preventing the progress of this task\n"
@@ -768,7 +752,7 @@ class task(base_stage, osv.osv):
         'date_start': fields.datetime('Starting Date',select=True),
         'date_end': fields.datetime('Ending Date',select=True),
         'date_deadline': fields.date('Deadline',select=True),
-        'project_id': fields.many2one('project.project', 'Project', ondelete='set null', select="1"),
+        'project_id': fields.many2one('project.project', 'Project', ondelete='set null', select="1", track_visibility='onchange'),
         'parent_ids': fields.many2many('project.task', 'project_task_parent_rel', 'task_id', 'parent_id', 'Parent Tasks'),
         'child_ids': fields.many2many('project.task', 'project_task_parent_rel', 'parent_id', 'task_id', 'Delegated Tasks'),
         'notes': fields.text('Notes'),
@@ -794,7 +778,7 @@ class task(base_stage, osv.osv):
                 'project.task': (lambda self, cr, uid, ids, c={}: ids, ['work_ids', 'remaining_hours', 'planned_hours'], 10),
                 'project.task.work': (_get_task, ['hours'], 10),
             }),
-        'user_id': fields.many2one('res.users', 'Assigned to'),
+        'user_id': fields.many2one('res.users', 'Assigned to', track_visibility='onchange'),
         'delegated_user_id': fields.related('child_ids', 'user_id', type='many2one', relation='res.users', string='Delegated To'),
         'partner_id': fields.many2one('res.partner', 'Customer'),
         'work_ids': fields.one2many('project.task.work', 'task_id', 'Work done'),
@@ -817,25 +801,15 @@ class task(base_stage, osv.osv):
     }
     _order = "priority, sequence, date_start, name, id"
 
-    def set_priority(self, cr, uid, ids, priority, *args):
-        """Set task priority
-        """
-        return self.write(cr, uid, ids, {'priority' : priority})
-
-    def set_very_high_priority(self, cr, uid, ids, *args):
-        """Set task priority to very high
-        """
-        return self.set_priority(cr, uid, ids, '0')
-    
     def set_high_priority(self, cr, uid, ids, *args):
         """Set task priority to high
         """
-        return self.set_priority(cr, uid, ids, '1')
+        return self.write(cr, uid, ids, {'priority' : '0'})
 
     def set_normal_priority(self, cr, uid, ids, *args):
         """Set task priority to normal
         """
-        return self.set_priority(cr, uid, ids, '2')
+        return self.write(cr, uid, ids, {'priority' : '2'})
 
     def _check_recursion(self, cr, uid, ids, context=None):
         for id in ids:
@@ -935,14 +909,11 @@ class task(base_stage, osv.osv):
         for task in cases:
             if task.project_id:
                 section_ids.append(task.project_id.id)
-        # OR all section_ids and OR with case_default
         search_domain = []
         if section_ids:
-            search_domain += [('|')] * len(section_ids)
+            search_domain = [('|')] * (len(section_ids)-1)
             for section_id in section_ids:
                 search_domain.append(('project_ids', '=', section_id))
-        search_domain.append(('case_default', '=', True))
-        # AND with the domain in parameter
         search_domain += list(domain)
         # perform search, return the first found
         stage_ids = self.pool.get('project.task.type').search(cr, uid, search_domain, order=order, context=context)
@@ -992,14 +963,12 @@ class task(base_stage, osv.osv):
             if not task.date_end:
                 vals['date_end'] = fields.datetime.now()
             self.case_set(cr, uid, [task.id], 'done', vals, context=context)
-            self.case_close_send_note(cr, uid, [task.id], context=context)
         return True
 
     def do_reopen(self, cr, uid, ids, context=None):
         for task in self.browse(cr, uid, ids, context=context):
             project = task.project_id
             self.case_set(cr, uid, [task.id], 'open', {}, context=context)
-            self.case_open_send_note(cr, uid, [task.id], context)
         return True
 
     def do_cancel(self, cr, uid, ids, context=None):
@@ -1011,7 +980,6 @@ class task(base_stage, osv.osv):
         self._check_child_task(cr, uid, ids, context=context)
         for task in tasks:
             self.case_set(cr, uid, [task.id], 'cancelled', {'remaining_hours': 0.0}, context=context)
-            self.case_cancel_send_note(cr, uid, [task.id], context=context)
         return True
 
     def do_open(self, cr, uid, ids, context=None):
@@ -1020,26 +988,21 @@ class task(base_stage, osv.osv):
 
     def case_open(self, cr, uid, ids, context=None):
         if not isinstance(ids,list): ids = [ids]
-        self.case_set(cr, uid, ids, 'open', {'date_start': fields.datetime.now()}, context=context)
-        self.case_open_send_note(cr, uid, ids, context)
-        return True
+        return self.case_set(cr, uid, ids, 'open', {'date_start': fields.datetime.now()}, context=context)
 
     def do_draft(self, cr, uid, ids, context=None):
         """ Compatibility when changing to case_draft. """
         return self.case_draft(cr, uid, ids, context=context)
 
     def case_draft(self, cr, uid, ids, context=None):
-        self.case_set(cr, uid, ids, 'draft', {}, context=context)
-        self.case_draft_send_note(cr, uid, ids, context=context)
-        return True
+        return self.case_set(cr, uid, ids, 'draft', {}, context=context)
 
     def do_pending(self, cr, uid, ids, context=None):
         """ Compatibility when changing to case_pending. """
         return self.case_pending(cr, uid, ids, context=context)
 
     def case_pending(self, cr, uid, ids, context=None):
-        self.case_set(cr, uid, ids, 'pending', {}, context=context)
-        return self.case_pending_send_note(cr, uid, ids, context=context)
+        return self.case_set(cr, uid, ids, 'pending', {}, context=context)
 
     def _delegate_task_attachments(self, cr, uid, task_id, delegated_task_id, context=None):
         attachment = self.pool.get('ir.attachment')
@@ -1079,7 +1042,6 @@ class task(base_stage, osv.osv):
                 self.do_pending(cr, uid, [task.id], context=context)
             elif delegate_data['state'] == 'done':
                 self.do_close(cr, uid, [task.id], context=context)
-            self.do_delegation_send_note(cr, uid, [task.id], context)
             delegated_tasks[task.id] = delegated_task_id
         return delegated_tasks
 
@@ -1103,12 +1065,10 @@ class task(base_stage, osv.osv):
         return self.set_remaining_time(cr, uid, ids, 10.0, context)
 
     def set_kanban_state_blocked(self, cr, uid, ids, context=None):
-        self.write(cr, uid, ids, {'kanban_state': 'blocked'}, context=context)
-        return False
+        return self.write(cr, uid, ids, {'kanban_state': 'blocked'}, context=context)
 
     def set_kanban_state_normal(self, cr, uid, ids, context=None):
-        self.write(cr, uid, ids, {'kanban_state': 'normal'}, context=context)
-        return False
+        return self.write(cr, uid, ids, {'kanban_state': 'normal'}, context=context)
 
     def set_kanban_state_done(self, cr, uid, ids, context=None):
         self.write(cr, uid, ids, {'kanban_state': 'done'}, context=context)
@@ -1128,38 +1088,16 @@ class task(base_stage, osv.osv):
             }, context=context)
         return True
 
-    def _subscribe_project_followers_to_task(self, cr, uid, task_id, context=None):
-        """ TDE note: not the best way to do this, we could override _get_followers
-            of task, and perform a better mapping of subtypes than a mapping
-            based on names.
-            However we will keep this implementation, maybe to be refactored
-            in 7.1 of future versions. """
-        # task followers are project followers, with matching subtypes
-        task_record = self.browse(cr, uid, task_id, context=context)
-        subtype_obj = self.pool.get('mail.message.subtype')
-        follower_obj = self.pool.get('mail.followers')
-        if task_record.project_id:
-            # create mapping
-            task_subtype_ids = subtype_obj.search(cr, uid, ['|', ('res_model', '=', False), ('res_model', '=', self._name)], context=context)
-            task_subtypes = subtype_obj.browse(cr, uid, task_subtype_ids, context=context)
-            # fetch subscriptions
-            follower_ids = follower_obj.search(cr, uid, [('res_model', '=', 'project.project'), ('res_id', '=', task_record.project_id.id)], context=context)
-            # copy followers
-            for follower in follower_obj.browse(cr, uid, follower_ids, context=context):
-                if not follower.subtype_ids:
-                    continue
-                project_subtype_names = [project_subtype.name for project_subtype in follower.subtype_ids]
-                task_subtype_ids = [task_subtype.id for task_subtype in task_subtypes if task_subtype.name in project_subtype_names]
-                self.message_subscribe(cr, uid, [task_id], [follower.partner_id.id],
-                    subtype_ids=task_subtype_ids, context=context)
-
     def create(self, cr, uid, vals, context=None):
+        if context is None:
+            context = {}
+        if not vals.get('stage_id'):
+            ctx = context.copy()
+            if  vals.get('project_id'):
+                ctx['default_project_id'] = vals['project_id']
+            vals['stage_id'] = self._get_default_stage_id(cr, uid, context=ctx)
         task_id = super(task, self).create(cr, uid, vals, context=context)
-        # subscribe project followers to the task
-        self._subscribe_project_followers_to_task(cr, uid, task_id, context=context)
-
         self._store_history(cr, uid, [task_id], context=context)
-        self.create_send_note(cr, uid, [task_id], context=context)
         return task_id
 
     # Overridden to reset the kanban_state to normal whenever
@@ -1167,6 +1105,11 @@ class task(base_stage, osv.osv):
     def write(self, cr, uid, ids, vals, context=None):
         if isinstance(ids, (int, long)):
             ids = [ids]
+        if vals.get('project_id'):
+            project_id = self.pool.get('project.project').browse(cr, uid, vals.get('project_id'), context=context)
+            if project_id:
+                vals.setdefault('message_follower_ids', [])
+                vals['message_follower_ids'] += [(6, 0,[follower.id]) for follower in project_id.message_follower_ids]
         if vals and not 'kanban_state' in vals and 'stage_id' in vals:
             new_stage = vals.get('stage_id')
             vals_reset_kstate = dict(vals, kanban_state='normal')
@@ -1177,17 +1120,11 @@ class task(base_stage, osv.osv):
                     #raise osv.except_osv(_('Warning!'), _('Stage is not defined in the project.'))
                 write_vals = vals_reset_kstate if t.stage_id != new_stage else vals
                 super(task, self).write(cr, uid, [t.id], write_vals, context=context)
-                self.stage_set_send_note(cr, uid, [t.id], new_stage, context=context)
             result = True
         else:
             result = super(task, self).write(cr, uid, ids, vals, context=context)
         if ('stage_id' in vals) or ('remaining_hours' in vals) or ('user_id' in vals) or ('state' in vals) or ('kanban_state' in vals):
             self._store_history(cr, uid, ids, context=context)
-
-        # subscribe new project followers to the task
-        if vals.get('project_id'):
-            for id in ids:
-                self._subscribe_project_followers_to_task(cr, uid, id, context=context)
         return result
 
     def unlink(self, cr, uid, ids, context=None):
@@ -1228,14 +1165,20 @@ class task(base_stage, osv.osv):
     # Mail gateway
     # ---------------------------------------------------
 
+    def message_get_reply_to(self, cr, uid, ids, context=None):
+        """ Override to get the reply_to of the parent project. """
+        return [task.project_id.message_get_reply_to()[0] if task.project_id else False
+                    for task in self.browse(cr, uid, ids, context=context)]
+
     def message_new(self, cr, uid, msg, custom_values=None, context=None):
         """ Override to updates the document according to the email. """
         if custom_values is None: custom_values = {}
-        custom_values.update({
+        defaults = {
             'name': msg.get('subject'),
             'planned_hours': 0.0,
-        })
-        return super(task,self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
+        }
+        defaults.update(custom_values)
+        return super(task,self).message_new(cr, uid, msg, custom_values=defaults, context=context)
 
     def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
         """ Override to update the task according to the email. """
@@ -1260,51 +1203,8 @@ class task(base_stage, osv.osv):
                     act = 'do_%s' % res.group(2).lower()
         if act:
             getattr(self,act)(cr, uid, ids, context=context)
-        return super(task,self).message_update(cr, uid, msg, update_vals=update_vals, context=context)
+        return super(task,self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context)
 
-    # ---------------------------------------------------
-    # OpenChatter methods and notifications
-    # ---------------------------------------------------
-
-    def case_get_note_msg_prefix(self, cr, uid, id, context=None):
-        """ Override of default prefix for notifications. """
-        return 'Task'
-
-    def get_needaction_user_ids(self, cr, uid, ids, context=None):
-        """ Returns the user_ids that have to perform an action.
-            Add to the previous results given by super the document responsible
-            when in draft mode.
-            :return: dict { record_id: [user_ids], }
-        """
-        result = super(task, self).get_needaction_user_ids(cr, uid, ids, context=context)
-        for obj in self.browse(cr, uid, ids, context=context):
-            if obj.state == 'draft' and obj.user_id:
-                result[obj.id].append(obj.user_id.id)
-        return result
-
-    def message_get_monitored_follower_fields(self, cr, uid, ids, context=None):
-        """ Add 'user_id' and 'manager_id' to the monitored fields """
-        res = super(task, self).message_get_monitored_follower_fields(cr, uid, ids, context=context)
-        return res + ['user_id', 'manager_id']
-
-    def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
-        """ Override of the (void) default notification method. """
-        stage_name = self.pool.get('project.task.type').name_get(cr, uid, [stage_id], context=context)[0][1]
-        return self.message_post(cr, uid, ids, body=_("Stage changed to <b>%s</b>.") % (stage_name),
-            context=context)
-
-    def create_send_note(self, cr, uid, ids, context=None):
-        return self.message_post(cr, uid, ids, body=_("Task has been <b>created</b>."), context=context)
-
-    def case_draft_send_note(self, cr, uid, ids, context=None):
-        return self.message_post(cr, uid, ids, body=_('Task has been set as <b>draft</b>.'), context=context)
-
-    def do_delegation_send_note(self, cr, uid, ids, context=None):
-        for task in self.browse(cr, uid, ids, context=context):
-            msg = _('Task has been <b>delegated</b> to <em>%s</em>.') % (task.user_id.name)
-            self.message_post(cr, uid, [task.id], body=msg, context=context)
-        return True
-   
     def project_task_reevaluate(self, cr, uid, ids, context=None):
         if self.pool.get('res.users').has_group(cr, uid, 'project.group_time_work_estimation_tasks'):
             return {
@@ -1387,6 +1287,7 @@ class account_analytic_account(osv.osv):
             project_values = {
                 'name': vals.get('name'),
                 'analytic_account_id': analytic_account_id,
+                'type': vals.get('type','contract'),
             }
             return project_pool.create(cr, uid, project_values, context=context)
         return False
@@ -1405,6 +1306,8 @@ class account_analytic_account(osv.osv):
         for account in self.browse(cr, uid, ids, context=context):
             if not name:
                 vals['name'] = account.name
+            if not vals.get('type'):
+                vals['type'] = account.type
             self.project_create(cr, uid, account.id, vals, context=context)
         return super(account_analytic_account, self).write(cr, uid, ids, vals, context=context)