[MERGE]: Merge with lp:~openerp-dev/openobject-addons/trunk-import_sugarcrm
[odoo/odoo.git] / addons / project / project.py
index 3828820..14ee94e 100644 (file)
@@ -205,20 +205,38 @@ class project(osv.osv):
         if context is None:
             context = {}
 
-        proj = self.browse(cr, uid, id, context=context)
         default = default or {}
         context['active_test'] = False
         default['state'] = 'open'
+        proj = self.browse(cr, uid, id, context=context)
         if not default.get('name', False):
             default['name'] = proj.name + _(' (copy)')
+
         res = super(project, self).copy(cr, uid, id, default, context)
+        return res
+
+
+    def template_copy(self, cr, uid, id, default={}, context=None):
+        task_obj = self.pool.get('project.task')
+        proj = self.browse(cr, uid, id, context=context)
+
+        default['tasks'] = [] #avoid to copy all the task automaticly
+        res = self.copy(cr, uid, id, default=default, context=context)
+
+        #copy all the task manually
+        map_task_id = {}
+        for task in proj.tasks:
+            map_task_id[task.id] =  task_obj.copy(cr, uid, task.id, {}, context=context)
+
+        self.write(cr, uid, res, {'tasks':[(6,0, map_task_id.values())]})
+        task_obj.duplicate_task(cr, uid, map_task_id, context=context)
 
         return res
 
     def duplicate_template(self, cr, uid, ids, context=None):
         if context is None:
             context = {}
-        project_obj = self.pool.get('project.project')
+        task_pool = self.pool.get('project.task')
         data_obj = self.pool.get('ir.model.data')
         result = []
         for proj in self.browse(cr, uid, ids, context=context):
@@ -231,7 +249,7 @@ class project(osv.osv):
                 end_date = date(*time.strptime(proj.date,'%Y-%m-%d')[:3])
                 new_date_end = (datetime(*time.strptime(new_date_start,'%Y-%m-%d')[:3])+(end_date-start_date)).strftime('%Y-%m-%d')
             context.update({'copy':True})
-            new_id = project_obj.copy(cr, uid, proj.id, default = {
+            new_id = self.template_copy(cr, uid, proj.id, default = {
                                     'name': proj.name +_(' (copy)'),
                                     'state':'open',
                                     'date_start':new_date_start,
@@ -332,7 +350,7 @@ class task(osv.osv):
 
     def onchange_planned(self, cr, uid, ids, planned = 0.0, effective = 0.0):
         return {'value':{'remaining_hours': planned - effective}}
-    
+
     def onchange_project(self, cr, uid, id, project_id):
         if not project_id:
             return {}
@@ -341,7 +359,7 @@ class task(osv.osv):
         if partner_id:
             return {'value':{'partner_id':partner_id.id}}
         return {}
-    
+
     def _default_project(self, cr, uid, context=None):
         if context is None:
             context = {}
@@ -349,6 +367,25 @@ class task(osv.osv):
             return int(context['project_id'])
         return False
 
+    def duplicate_task(self, cr, uid, map_ids, context=None):
+        for new in map_ids.values():
+            task = self.browse(cr, uid, new, context)
+            child_ids = [ ch.id for ch in task.child_ids]
+            if task.child_ids:
+                for child in task.child_ids:
+                    if child.id in map_ids.keys():
+                        child_ids.remove(child.id)
+                        child_ids.append(map_ids[child.id])
+
+            parent_ids = [ ch.id for ch in task.parent_ids]
+            if task.parent_ids:
+                for parent in task.parent_ids:
+                    if parent.id in map_ids.keys():
+                        parent_ids.remove(parent.id)
+                        parent_ids.append(map_ids[parent.id])
+            #FIXME why there is already the copy and the old one
+            self.write(cr, uid, new, {'parent_ids':[(6,0,set(parent_ids))], 'child_ids':[(6,0, set(child_ids))]})
+
     def copy_data(self, cr, uid, id, default={}, context=None):
         default = default or {}
         default.update({'work_ids':[], 'date_start': False, 'date_end': False, 'date_deadline': False})
@@ -360,7 +397,7 @@ class task(osv.osv):
             default['name'] = self.browse(cr, uid, id, context=context).name or ''
             if not context.get('copy',False):
                  new_name = _("%s (copy)")%default.get('name','')
-                 default.update({'name':new_name})            
+                 default.update({'name':new_name})
         return super(task, self).copy_data(cr, uid, id, default, context)
 
     def _check_dates(self, cr, uid, ids, context=None):
@@ -389,7 +426,7 @@ class task(osv.osv):
         'active': fields.function(_is_template, method=True, store=True, string='Not a Template Task', type='boolean', help="This field is computed automatically and have the same behavior than the boolean 'active' field: if the task is linked to a template or unactivated project, it will be hidden unless specifically asked."),
         'name': fields.char('Task Summary', size=128, required=True),
         'description': fields.text('Description'),
-        'priority': fields.selection([('4','Very Low'), ('3','Low'), ('2','Medium'), ('1','Urgent'), ('0','Very urgent')], 'Priority'),
+        'priority': fields.selection([('4','Very Low'), ('3','Low'), ('2','Medium'), ('1','Important'), ('0','Very important')], 'Priority'),
         'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of tasks."),
         'type_id': fields.many2one('project.task.type', 'Stage'),
         'state': fields.selection([('draft', 'Draft'),('open', 'In Progress'),('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')], 'State', readonly=True, required=True,
@@ -448,27 +485,33 @@ class task(osv.osv):
     _order = "sequence,priority, date_start, name, id"
 
     def _check_recursion(self, cr, uid, ids, context=None):
-        obj_task = self.browse(cr, uid, ids[0], context=context)
-        parent_ids = [x.id for x in obj_task.parent_ids]
-        children_ids = [x.id for x in obj_task.child_ids]
+        for id in ids:
+            visited_branch = set()
+            visited_node = set()
+            res = self._check_cycle(cr, uid, id, visited_branch, visited_node, context=context)
+            if not res:
+                return False
+
+        return True
 
-        if (obj_task.id in children_ids) or (obj_task.id in parent_ids):
+    def _check_cycle(self, cr, uid, id, visited_branch, visited_node, context=None):
+        if id in visited_branch: #Cycle
             return False
 
-        while(ids):
-            cr.execute('SELECT DISTINCT task_id '\
-                       'FROM project_task_parent_rel '\
-                       'WHERE parent_id IN %s', (tuple(ids),))
-            child_ids = map(lambda x: x[0], cr.fetchall())
-            c_ids = child_ids
-            if (list(set(parent_ids).intersection(set(c_ids)))) or (obj_task.id in c_ids):
+        if id in visited_node: #Already tested don't work one more time for nothing
+            return True
+
+        visited_branch.add(id)
+        visited_node.add(id)
+
+        #visit child using DFS
+        task = self.browse(cr, uid, id, context=context)
+        for child in task.child_ids:
+            res = self._check_cycle(cr, uid, child.id, visited_branch, visited_node, context=context)
+            if not res:
                 return False
-            while len(c_ids):
-                s_ids = self.search(cr, uid, [('parent_ids', 'in', c_ids)])
-                if (list(set(parent_ids).intersection(set(s_ids)))):
-                    return False
-                c_ids = s_ids
-            ids = child_ids
+
+        visited_branch.remove(id)
         return True
 
     def _check_dates(self, cr, uid, ids, context=None):
@@ -478,9 +521,9 @@ class task(osv.osv):
         start = obj_task.date_start or False
         end = obj_task.date_end or False
         if start and end :
-            if start > end:        
+            if start > end:
                 return False
-        return True           
+        return True
 
     _constraints = [
         (_check_recursion, 'Error ! You cannot create recursive tasks.', ['parent_ids']),