From 073e06ab8fe0efcb83245720c428cef0ba39ebb5 Mon Sep 17 00:00:00 2001
From: FHenry <florian.henry.mail@gmail.com>
Date: Fri, 27 Apr 2012 11:03:01 +0200
Subject: [PATCH] Feature Clone project (357) and other tricks Fix variable
 date property name, to be compliant with variable naming convention (create)
 Add feature to shift task date when change project start date (option) Add
 project start/end date on Project->Task View

---
 htdocs/projet/class/project.class.php | 395 ++++++++++++++++++++++++--
 htdocs/projet/class/task.class.php    | 238 ++++++++++++++++
 htdocs/projet/fiche.php               | 129 +++++++--
 htdocs/projet/tasks.php               |  14 +-
 htdocs/projet/tasks/document.php      |   8 +-
 htdocs/projet/tasks/note.php          |  20 +-
 6 files changed, 742 insertions(+), 62 deletions(-)

diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php
index 483d2034553..435c59d395d 100644
--- a/htdocs/projet/class/project.class.php
+++ b/htdocs/projet/class/project.class.php
@@ -1,8 +1,8 @@
 <?php
 
 /* Copyright (C) 2002-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
- * Copyright (C) 2005-2012 Laurent Destailleur  <eldy@users.sourceforge.net>
- * Copyright (C) 2005-2012 Regis Houssin        <regis@dolibarr.fr>
+ * Copyright (C) 2005-2008 Laurent Destailleur  <eldy@users.sourceforge.net>
+ * Copyright (C) 2005-2010 Regis Houssin        <regis@dolibarr.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -39,8 +39,6 @@ class Project extends CommonObject
     var $description;
     var $statut;
     var $title;
-    var $date_c;
-    var $date_m;
     var $date_start;
     var $date_end;
     var $socid;
@@ -83,7 +81,7 @@ class Project extends CommonObject
         if (!trim($this->ref))
         {
             $this->error = 'ErrorFieldsRequired';
-            dol_syslog("Project::Create error -1 ref null", LOG_ERR);
+            dol_syslog(get_class($this)."::Create error -1 ref null", LOG_ERR);
             return -1;
         }
 
@@ -109,13 +107,13 @@ class Project extends CommonObject
         $sql.= ", " . $user->id;
         $sql.= ", 0";
         $sql.= ", " . ($this->public ? 1 : 0);
-        $sql.= ", " . ($this->datec != '' ? $this->db->idate($this->datec) : 'null');
-        $sql.= ", " . ($this->dateo != '' ? $this->db->idate($this->dateo) : 'null');
-        $sql.= ", " . ($this->datee != '' ? $this->db->idate($this->datee) : 'null');
+        $sql.= ", " . $this->db->idate(dol_now());
+        $sql.= ", " . ($this->date_start != '' ? $this->db->idate($this->date_start) : 'null');
+        $sql.= ", " . ($this->date_end != '' ? $this->db->idate($this->date_end) : 'null');
         $sql.= ", ".$conf->entity;
         $sql.= ")";
 
-        dol_syslog("Project::create sql=" . $sql, LOG_DEBUG);
+        dol_syslog(get_class($this)."::create sql=" . $sql, LOG_DEBUG);
         $resql = $this->db->query($sql);
         if ($resql)
         {
@@ -140,7 +138,7 @@ class Project extends CommonObject
         {
             $this->error = $this->db->lasterror();
             $this->errno = $this->db->lasterrno();
-            dol_syslog("Project::Create error -2 " . $this->error, LOG_ERR);
+            dol_syslog(get_class($this)."::Create error -2 " . $this->error, LOG_ERR);
             $error++;
         }
 
@@ -193,7 +191,7 @@ class Project extends CommonObject
             $sql.= ", datee=" . ($this->date_end != '' ? $this->db->idate($this->date_end) : 'null');
             $sql.= " WHERE rowid = " . $this->id;
 
-            dol_syslog("Project::Update sql=" . $sql, LOG_DEBUG);
+            dol_syslog(get_class($this)."::Update sql=" . $sql, LOG_DEBUG);
             if ($this->db->query($sql))
             {
                 if (!$notrigger)
@@ -215,13 +213,13 @@ class Project extends CommonObject
             else
             {
                 $this->error = $this->db->lasterror();
-                dol_syslog("Project::Update error -2 " . $this->error, LOG_ERR);
+                dol_syslog(get_class($this)."::Update error -2 " . $this->error, LOG_ERR);
                 $result = -2;
             }
         }
         else
         {
-            dol_syslog("Project::Update ref null");
+            dol_syslog(get_class($this)."::Update ref null");
             $result = -1;
         }
 
@@ -245,7 +243,7 @@ class Project extends CommonObject
         if ($ref) $sql.= " WHERE ref='" . $ref . "'";
         else $sql.= " WHERE rowid=" . $id;
 
-        dol_syslog("Project::fetch sql=" . $sql, LOG_DEBUG);
+        dol_syslog(get_class($this)."::fetch sql=" . $sql, LOG_DEBUG);
         $resql = $this->db->query($sql);
         if ($resql)
         {
@@ -284,7 +282,7 @@ class Project extends CommonObject
         else
         {
             $this->error = $this->db->lasterror();
-            dol_syslog("Project::fetch " . $this->error, LOG_ERR);
+            dol_syslog(get_class($this)."::fetch " . $this->error, LOG_ERR);
             return -1;
         }
     }
@@ -364,7 +362,7 @@ class Project extends CommonObject
         if (! $sql) return -1;
 
         //print $sql;
-        dol_syslog("Project::get_element_list sql=" . $sql);
+        dol_syslog(get_class($this)."::get_element_list sql=" . $sql);
         $result = $this->db->query($sql);
         if ($result)
         {
@@ -499,7 +497,7 @@ class Project extends CommonObject
             $sql.= " WHERE rowid = " . $this->id;
             $sql.= " AND entity = " . $conf->entity;
 
-            dol_syslog("Project::setValid sql=" . $sql);
+            dol_syslog(get_class($this)."::setValid sql=" . $sql);
             $resql = $this->db->query($sql);
             if ($resql)
             {
@@ -523,7 +521,7 @@ class Project extends CommonObject
                 {
                     $this->db->rollback();
                     $this->error = join(',', $this->errors);
-                    dol_syslog("Project::setValid " . $this->error, LOG_ERR);
+                    dol_syslog(get_class($this)."::setValid " . $this->error, LOG_ERR);
                     return -1;
                 }
             }
@@ -531,7 +529,7 @@ class Project extends CommonObject
             {
                 $this->db->rollback();
                 $this->error = $this->db->lasterror();
-                dol_syslog("Project::setValid " . $this->error, LOG_ERR);
+                dol_syslog(get_class($this)."::setValid " . $this->error, LOG_ERR);
                 return -1;
             }
         }
@@ -559,7 +557,7 @@ class Project extends CommonObject
             $sql.= " AND entity = " . $conf->entity;
             $sql.= " AND fk_statut = 1";
 
-            dol_syslog("Project::setClose sql=" . $sql);
+            dol_syslog(get_class($this)."::setClose sql=" . $sql);
             $resql = $this->db->query($sql);
             if ($resql)
             {
@@ -583,7 +581,7 @@ class Project extends CommonObject
                 {
                     $this->db->rollback();
                     $this->error = join(',', $this->errors);
-                    dol_syslog("Project::setClose " . $this->error, LOG_ERR);
+                    dol_syslog(get_class($this)."::setClose " . $this->error, LOG_ERR);
                     return -1;
                 }
             }
@@ -591,7 +589,7 @@ class Project extends CommonObject
             {
                 $this->db->rollback();
                 $this->error = $this->db->lasterror();
-                dol_syslog("Project::setClose " . $this->error, LOG_ERR);
+                dol_syslog(get_class($this)."::setClose " . $this->error, LOG_ERR);
                 return -1;
             }
         }
@@ -882,6 +880,359 @@ class Project extends CommonObject
 
         return $projects;
     }
+    
+     /**	Load an object from its id and create a new one in database
+	 *
+	 *	@param	int		$fromid     	Id of object to clone
+	 *	@param	bool	$clone_contact	clone contact of project
+	 *	@param	bool	$clone_ref		clone ref of project
+	 *	@param	bool	$clone_task		clone task of project
+	 *	@param	bool	$clone_file		clone file of project
+	 *	@param	bool	$clone_note		clone note of project
+	 * 	@return	int						New id of clone
+	 */
+	function createFromClone($fromid,$clone_contact=false,$clone_task=true,$clone_file=true,$clone_note=true)
+	{
+		global $user,$langs,$conf;
+
+		$error=0;
+		
+		$now = dol_mktime(0,0,0,idate('m',dol_now()),idate('d',dol_now()),idate('Y',dol_now()));
+
+		$clone_project=new Project($this->db);
+
+		$this->db->begin();
+
+		// Load source object
+		$clone_project->fetch($fromid);
+		
+		$orign_dt_start=$clone_project->date_start;
+	   
+		
+		$orign_project_ref=$clone_project->ref;
+		
+		$clone_project->id=0;
+        $clone_project->date_start = $now;
+        if (!(empty($clone_project->date_end)))
+        {
+        	//Calculate new project end date ragarding difference between original project start date and new start date (now)
+        	$datetime_start = new DateTime();
+    		$datetime_start->setTimestamp($orign_dt_start);
+			$datetime_now = new DateTime();
+			$datetime_now->setTimestamp($now);
+			$diff_dt = $datetime_start->diff($datetime_now);
+			
+        	$datetime_end = new DateTime();
+        	$datetime_end->setTimestamp($clone_project->date_end);
+        	$datetime_end->add($diff_dt);
+        	$clone_project->date_end = $datetime_end->getTimestamp();	
+        }
+        
+        $clone_project->datec = $now;
+
+        if (!$clone_note)
+        {
+        	    $clone_project->note_private='';
+    			$clone_project->note_public='';
+        }
+		
+		//Generate next ref
+		$defaultref='';
+    	$obj = empty($conf->global->PROJECT_ADDON)?'mod_project_simple':$conf->global->PROJECT_ADDON;
+    	if (! empty($conf->global->PROJECT_ADDON) && is_readable(DOL_DOCUMENT_ROOT ."/core/modules/project/".$conf->global->PROJECT_ADDON.".php"))
+    	{
+    		
+        	require_once(DOL_DOCUMENT_ROOT ."/core/modules/project/".$conf->global->PROJECT_ADDON.".php");
+        	$modProject = new $obj;
+        	$defaultref = $modProject->getNextValue($clone_project->societe->id,$clone_project);
+    	}
+		
+    	if (is_numeric($defaultref) && $defaultref <= 0) $defaultref='';
+    	
+		$clone_project->ref=$defaultref;
+
+		// Create clone
+		$result=$clone_project->create($user);
+
+		// Other options
+		if ($result < 0)
+		{
+			$this->error.=$clone_project->error;
+			$error++;
+		}
+
+		if (! $error)
+		{
+			$this->db->commit();
+			
+			//Get the new project id
+			$clone_project_id=$clone_project->id;
+			
+			//Note Update
+			if (!$clone_note)
+       		{
+        	    $clone_project->note_private='';
+    			$clone_project->note_public='';
+        	}
+        	else
+        	{
+        		$this->db->begin();
+				$res=$clone_project->update_note_public(dol_html_entity_decode($clone_project->note_public, ENT_QUOTES));
+				if ($res < 0)
+				{
+					$this->error.=$clone_project->error;
+					$error++;
+					$this->db->rollback();
+				}
+				else
+				{
+					$this->db->commit();
+				}
+				
+				$this->db->begin();
+				$res=$clone_project->update_note(dol_html_entity_decode($clone_project->note_private, ENT_QUOTES));
+				if ($res < 0)
+				{
+					$this->error.=$clone_project->error;
+					$error++;
+					$this->db->rollback();
+				}
+				else
+				{
+					$this->db->commit();
+				}
+        	}
+			
+			//Duplicate contact
+			if ($clone_contact)
+			{	
+				$origin_project = new Project($this->db);
+				$origin_project->fetch($fromid);
+				
+				foreach(array('internal','external') as $source)
+				{
+					$tab = $origin_project->liste_contact(-1,$source);
+					
+					foreach ($tab as $contacttoadd)
+					{
+						$clone_project->add_contact($contacttoadd['id'], $contacttoadd['code'], $contacttoadd['source']);
+						if ($clone_project->error == 'DB_ERROR_RECORD_ALREADY_EXISTS')
+						{
+							$langs->load("errors");
+							$this->error.=$langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType");
+							$error++;
+						}
+						else
+						{ 
+							if ($clone_project->error!='')
+							{
+								$this->error.=$clone_project->error;
+								$error++;
+							}
+						}
+					}
+				}
+			}
+			
+			//Duplicate file
+			if ($clone_file)
+			{	
+				require_once(DOL_DOCUMENT_ROOT."/core/lib/files.lib.php");
+				
+				$clone_project_dir = $conf->projet->dir_output . "/" . dol_sanitizeFileName($defaultref);
+				$ori_project_dir = $conf->projet->dir_output . "/" . dol_sanitizeFileName($orign_project_ref);
+				
+				if (dol_mkdir($clone_project_dir) >= 0)
+				{
+					$filearray=dol_dir_list($ori_project_dir,"files",0,'','\.meta$','',SORT_ASC,1);
+					foreach($filearray as $key => $file)
+					{
+						$rescopy = dol_copy($ori_project_dir . '/' . $file['name'], $clone_project_dir . '/' . $file['name'],0,1);
+						if (is_numeric($rescopy) && $rescopy < 0)
+						{
+							$this->error.=$langs->trans("ErrorFailToCopyFile",$ori_project_dir . '/' . $file['name'],$clone_project_dir . '/' . $file['name']);
+							$error++;
+						}
+					}
+				}
+				else
+				{
+					$this->error.=$langs->trans('ErrorInternalErrorDetected').':dol_mkdir';
+					$error++;
+				}
+			}
+			
+			//Duplicate task
+			if ($clone_task)
+			{	
+				$taskstatic = new Task($this->db);
+				
+				// Security check
+				$socid=0;
+				if ($user->societe_id > 0) $socid = $user->societe_id;
+				
+				$tasksarray=$taskstatic->getTasksArray(0, 0, $fromid, $socid, 0);
+			
+				//manage new parent clone task id
+				$tab_conv_child_parent=array();
+
+			    foreach ($tasksarray as $tasktoclone)
+			    {
+					$result_clone = $taskstatic->createFromClone($tasktoclone->id,$clone_project_id,$tasktoclone->fk_parent,true,true,false,true,true,false);
+					if ($result_clone <= 0)
+				    {
+				    	$this->error.=$result_clone->error;
+						$error++;
+				    }
+				    else
+				    {
+				    	$new_task_id=$result_clone;
+				    	$taskstatic->fetch($tasktoclone->id);
+				    	
+				    	//manage new parent clone task id
+				    	// if the current task has child we store the original task id and the equivalent clone task id
+						if (($taskstatic->hasChildren()) && !array_key_exists($tasktoclone->id,$tab_conv_child_parent))
+						{
+							$tab_conv_child_parent[$tasktoclone->id] =  $new_task_id;
+						}
+				    }
+					
+			    }
+			    
+			    //Parse all clone node to be sure to update new parent
+			    $tasksarray=$taskstatic->getTasksArray(0, 0, $clone_project_id, $socid, 0);	    
+			    foreach ($tasksarray as $task_cloned)
+			    {
+			    	$taskstatic->fetch($task_cloned->id);
+			    	if ($taskstatic->fk_task_parent!=0)
+			    	{
+			    		$taskstatic->fk_task_parent=$tab_conv_child_parent[$taskstatic->fk_task_parent];
+			    	}
+			    	$res=$taskstatic->update($user);
+			    	if ($result_clone <= 0)
+				    {
+				    	$this->error.=$taskstatic->error;
+						$error++;
+				    }
+			    }
+			}
+			
+			
+			
+			if (! $error)
+			{
+				return $clone_project_id;
+			}
+			else
+			{
+				dol_syslog(get_class($this)."::createFromClone nbError: ".$error." error : " . $this->error, LOG_ERR);
+				return -1;
+			}
+			
+		}
+		else
+		{
+			$this->db->rollback();
+			return -1;
+		}
+	}
+	
+	
+	 /**	Shift project task date from current date to delta
+	 *
+	 *	@param	timestamp		$old_project_dt_start	old project start date
+	 * 	@return	int					1 if OK or < 0 if KO
+	 */
+	function shiftTaskDate($old_project_dt_start)
+	{
+		global $user,$langs,$conf;
+
+		$error=0;
+		
+		$taskstatic = new Task($this->db);
+				
+		// Security check
+		$socid=0;
+		if ($user->societe_id > 0) $socid = $user->societe_id;
+		
+		//convert timestamp to datetime
+		$old_project_dt_st = new DateTime();
+		$old_project_dt_st->setTimestamp($old_project_dt_start);
+		$old_project_dt_st->setTime(0,0,0); //Use 00:00:00 as time to be sure to not have side
+		
+		$tasksarray=$taskstatic->getTasksArray(0, 0, $this->id, $socid, 0);
+
+	    foreach ($tasksarray as $tasktoshiftdate)
+	    {
+	    	$to_update=false;
+	    	// Fetch only if update of date will be made
+	    	if ((!empty($tasktoshiftdate->date_start)) || (!empty($tasktoshiftdate->date_end)))
+	    	{
+	    		//dol_syslog(get_class($this)."::shiftTaskDate to_update", LOG_DEBUG);
+	    		$to_update=true;
+		    	$task = new Task($this->db);
+		    	$result = $task->fetch($tasktoshiftdate->id);
+		    	if (!$result)
+		    	{
+		    		$error++;
+		    		$this->error.=$task->error;
+		    	}
+	    	}
+
+	    	//Calcultate new task start date with difference between old proj start date and origin task start date
+	    	if (!empty($tasktoshiftdate->date_start))
+	    	{	    		
+	    		dol_syslog(get_class($this)."::shiftTaskDate to_update", LOG_DEBUG);
+		    	$orign_task_datetime_start = new DateTime();
+	    		$orign_task_datetime_start->setTimestamp($tasktoshiftdate->date_start);
+	    		$orign_task_datetime_start->setTime(0,0,0); //Use 00:00:00 as time to be sure to not have side effect
+				$diff_dt_st = $old_project_dt_st->diff($orign_task_datetime_start);
+				
+				//Project new start date
+				$datetime_start = new DateTime();
+				$datetime_start->setTimestamp($this->date_start);
+				$datetime_start->setTime(0,0,0); //Use 00:00:00 as time to be sure to not have side
+				
+        		//New task start date
+				$datetime_start->add($diff_dt_st);
+				$task->date_start			= $datetime_start->getTimestamp();
+	    	}
+	    	
+	    	//Calcultate new task end date with difference between origin proj end date and origin task end date
+	    	if (!empty($tasktoshiftdate->date_end))
+	    	{
+        		$orign_task_datetime_end = new DateTime();
+	    		$orign_task_datetime_end->setTimestamp($tasktoshiftdate->date_end);
+	    		$orign_task_datetime_end->setTime(0,0,0); //Use 00:00:00 as hour to be sure to not have side effect
+	    		
+				$diff_dt_end = $old_project_dt_st->diff($orign_task_datetime_end);
+				
+				//Project new start date
+				$datetime_end = new DateTime();
+				$datetime_end->setTimestamp($this->date_start);
+				$datetime_end->setTime(0,0,0); //Use 00:00:00 as time to be sure to not have side
+				
+        		//New task start date
+				$datetime_end->add($diff_dt_end);
+				$task->date_end			= $datetime_end->getTimestamp();
+	    	}
+
+			if ($to_update)
+			{
+		    	$result = $task->update($user);
+		    	if (!$result)
+		    	{
+		    		$error++;
+		    		$this->error.=$task->error;
+		    	}
+			}
+	    }
+	    if ($error!=0)
+	    {
+	    	return -1;	
+	    }
+	    return $result;
+	} 
 
 }
 
diff --git a/htdocs/projet/class/task.class.php b/htdocs/projet/class/task.class.php
index a2b9e337f26..6aefb92ec6c 100644
--- a/htdocs/projet/class/task.class.php
+++ b/htdocs/projet/class/task.class.php
@@ -934,6 +934,244 @@ class Task extends CommonObject
             return 1;
         }
     }
+    
+     /**	Load an object from its id and create a new one in database
+	 *
+	 *	@param	int		$fromid     			Id of object to clone
+	 *  @param	int		$project_id				Id of project to attach clone task
+	 *  @param	int		$parent_task_id			Id of task to attach clone task
+	 *  @param	bool	$clone_change_dt		recalculate date of task regarding new project start date
+	 *	@param	bool	$clone_affectation		clone affectation of project
+	 *	@param	bool	$clone_task				clone task of project
+	 *	@param	bool	$clone_time				clone time of project
+	 *	@param	bool	$clone_file				clone file of project
+	 *  @param	bool	$clone_note				clone note of project
+	 *	@param	bool	$clone_prog				clone progress of project
+	 * 	@return	int								New id of clone
+	 */
+	function createFromClone($fromid,$project_id,$parent_task_id,$clone_change_dt=false,$clone_affectation=false,$clone_time=false,$clone_file=false,$clone_note=false,$clone_prog=false)
+	{
+		global $user,$langs,$conf;
+
+		$error=0;
+		
+		$now = dol_mktime(0,0,0,idate('m',mktime()),idate('d',mktime()),idate('Y',mktime()));
+
+		$clone_task=new Task($this->db);
+
+		$this->db->begin();
+
+		// Load source object
+		$clone_task->fetch($fromid);
+		
+		$ori_project_id					= $clone_task->fk_project;
+		
+		$clone_task->id					= 0;
+        $clone_task->fk_project			= $project_id;
+        $clone_task->fk_task_parent		= $parent_task_id;
+        $clone_task->date_c				= $now;
+        
+        //Manage Task Date
+        if ($clone_change_dt)
+        {
+        	$projectstatic=new Project($this->db);
+        	$projectstatic->fetch($ori_project_id);
+        	
+        	//Origin project strat date
+        	$orign_project_dt_start = new DateTime();
+	    	$orign_project_dt_start->setTimestamp($projectstatic->date_start);
+	    	
+	    	//Calcultate new task start date with difference between origin proj start date and origin task start date
+	    	if (!empty($clone_task->date_start))
+	    	{
+		    	$orign_task_datetime_start = new DateTime();
+	    		$orign_task_datetime_start->setTimestamp($clone_task->date_start);
+	    		$orign_task_datetime_start->setTime(0,0,0); //Use 00:00:00 as hour to be sure to not have side effect
+				$diff_dt_st = $orign_project_dt_start->diff($orign_task_datetime_start);
+				
+				//cloned project start date
+        		$datetime_start = new DateTime();
+        		$datetime_start->setTimestamp($now);
+        		
+        		//New task start date
+				$datetime_start->add($diff_dt_st);
+				$clone_task->date_start			= $datetime_start->getTimestamp();
+	    	}
+	    	
+	    	//Calcultate new task end date with difference between origin proj end date and origin task end date
+	    	if (!empty($clone_task->date_end))
+	    	{
+        		$orign_task_datetime_end = new DateTime();
+	    		$orign_task_datetime_end->setTimestamp($clone_task->date_end);
+	    		$orign_task_datetime_end->setTime(0,0,0); //Use 00:00:00 as hour to be sure to not have side effect
+				$diff_dt_end = $orign_project_dt_start->diff($orign_task_datetime_end);
+				
+				//cloned project start date
+        		$datetime_end = new DateTime();
+        		$datetime_end->setTimestamp($now);
+        		
+        		//New task start date
+				$datetime_end->add($diff_dt_end);
+				$clone_task->date_end			= $datetime_end->getTimestamp();
+	    	}
+	    	
+        }
+	
+		if (!$clone_prog)
+        {
+        	    $clone_task->progress=0;
+        }
+
+		// Create clone
+		$result=$clone_task->create($user);
+
+		// Other options
+		if ($result < 0)
+		{
+			$this->error=$clone_task->error;
+			$error++;
+		}
+
+		// End
+		if (! $error)
+		{
+			$this->db->commit();
+			
+			$clone_task_id=$clone_task->id;
+			     		
+       		//Note Update
+			if (!$clone_note)
+       		{
+        	    $clone_task->note_private='';
+    			$clone_task->note_public='';
+        	}
+        	else
+        	{
+        		$this->db->begin();
+				$res=$clone_task->update_note_public(dol_html_entity_decode($clone_task->note_public, ENT_QUOTES));
+				if ($res < 0)
+				{
+					$this->error.=$clone_task->error;
+					$error++;
+					$this->db->rollback();
+				}
+				else
+				{
+					$this->db->commit();
+				}
+				
+				$this->db->begin();
+				$res=$clone_task->update_note(dol_html_entity_decode($clone_task->note_private, ENT_QUOTES));
+				if ($res < 0)
+				{
+					$this->error.=$clone_task->error;
+					$error++;
+					$this->db->rollback();
+				}
+				else
+				{
+					$this->db->commit();
+				}
+        	}
+       		
+			//Duplicate file
+			if ($clone_file)
+			{	
+				require_once(DOL_DOCUMENT_ROOT."/core/lib/files.lib.php");
+				
+				//retreive project origin ref to know folder to copy
+				$projectstatic=new Project($this->db);
+	        	$projectstatic->fetch($ori_project_id);
+	        	$ori_project_ref=$projectstatic->ref;
+	        	
+	        	if ($ori_project_id!=$project_id)
+	        	{
+	        		$projectstatic->fetch($project_id);
+	        		$clone_project_ref=$projectstatic->ref;
+	        	} 
+	        	else
+	        	{
+	        		$clone_project_ref=$ori_project_ref;
+	        	}
+				
+				$clone_task_dir = $conf->projet->dir_output . "/" . dol_sanitizeFileName($clone_project_ref). "/" . dol_sanitizeFileName($clone_task_id);
+				$ori_task_dir = $conf->projet->dir_output . "/" . dol_sanitizeFileName($ori_project_ref). "/" . dol_sanitizeFileName($fromid);
+				
+				$filearray=dol_dir_list($ori_task_dir,"files",0,'','\.meta$','',SORT_ASC,1);
+				foreach($filearray as $key => $file)
+				{
+					if (!file_exists($clone_task_dir))
+					{
+						if (dol_mkdir($clone_task_dir) < 0)
+						{
+							$this->error.=$langs->trans('ErrorInternalErrorDetected').':dol_mkdir';
+							$error++;							
+						}
+					}
+					
+					$rescopy = dol_copy($ori_task_dir . '/' . $file['name'], $clone_task_dir . '/' . $file['name'],0,1);
+					if (is_numeric($rescopy) && $rescopy < 0)
+					{
+						$this->error.=$langs->trans("ErrorFailToCopyFile",$ori_task_dir . '/' . $file['name'],$clone_task_dir . '/' . $file['name']);
+						$error++;
+					}
+				}		
+			}
+			
+			// clone affectation
+			if ($clone_affectation)
+			{
+				$origin_task = new Task($this->db);
+				$origin_task->fetch($fromid);
+				
+				foreach(array('internal','external') as $source)
+				{
+					$tab = $origin_task->liste_contact(-1,$source);
+					$num=count($tab);
+					$i = 0;
+					while ($i < $num)
+					{
+						$clone_task->add_contact($tab[$i]['id'], $tab[$i]['code'], $tab[$i]['source']);
+						if ($clone_task->error == 'DB_ERROR_RECORD_ALREADY_EXISTS')
+						{
+							$langs->load("errors");
+							$this->error.=$langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType");
+							$error++;
+						}
+						else
+						{
+							if ($clone_task->error!='')
+							{
+								$this->error.=$clone_task->error;
+								$error++;
+							}
+						}
+						$i++;
+					}
+				}
+			}
+			
+			if($clone_time)
+			{
+				//TODO clone time of affectation
+			}
+			
+			if (! $error)
+			{
+				return $clone_task_id;
+			}
+			else
+			{
+				dol_syslog(get_class($this)."::createFromClone nbError: ".$error." error : " . $this->error, LOG_ERR);
+				return -1;
+			}
+		}
+		else
+		{
+			$this->db->rollback();
+			return -1;
+		}
+	}
 
 }
 ?>
diff --git a/htdocs/projet/fiche.php b/htdocs/projet/fiche.php
index 925f93e0465..f84dca56cbe 100644
--- a/htdocs/projet/fiche.php
+++ b/htdocs/projet/fiche.php
@@ -34,7 +34,7 @@ $langs->load("projects");
 $langs->load('companies');
 
 $id=GETPOST('id','int');
-$ref = GETPOST('ref','alpha');
+$ref=GETPOST('ref','alpha');
 $action=GETPOST('action','alpha');
 $backtopage=GETPOST('backtopage','alpha');
 
@@ -58,10 +58,44 @@ $result = restrictedArea($user, 'projet', $id);
 // Cancel
 if (GETPOST("cancel") && ! empty($backtopage))
 {
+	if (GETPOST("comefromclone")==1)
+	{
+		$project = new Project($db);
+	    $project->fetch($id);
+	    $result=$project->delete($user);
+	    if ($result > 0)
+	    {
+	        Header("Location: index.php");
+	        exit;
+	    }
+	    else
+	    {
+	        dol_syslog($project->error,LOG_DEBUG);
+	        $mesg='<div class="error">'.$langs->trans("CantRemoveProject").'</div>';
+	    }
+	}
     header("Location: ".$backtopage);
     exit;
 }
 
+//if cancel and come from clone then delete the cloned project
+if (GETPOST("cancel") && (GETPOST("comefromclone")==1))
+{	
+	$project = new Project($db);
+    $project->fetch($id);
+    $result=$project->delete($user);
+    if ($result > 0)
+    {
+        Header("Location: index.php");
+        exit;
+    }
+    else
+    {
+        dol_syslog($project->error,LOG_DEBUG);
+        $mesg='<div class="error">'.$langs->trans("CantRemoveProject").'</div>';
+    }
+}
+
 if ($action == 'add' && $user->rights->projet->creer)
 {
     $error=0;
@@ -84,14 +118,14 @@ if ($action == 'add' && $user->rights->projet->creer)
 
         $project = new Project($db);
 
-        $project->ref             = $_POST["ref"];
-        $project->title           = $_POST["title"];
-        $project->socid           = $_POST["socid"];
-        $project->description     = $_POST["description"];
-        $project->public          = $_POST["public"];
+        $project->ref             = GETPOST('ref','alpha');
+        $project->title           = GETPOST('title','alpha');
+        $project->socid           = GETPOST('socid','int');
+        $project->description     = GETPOST('description','alpha');
+        $project->public          = GETPOST('public','alpha');
         $project->datec=dol_now();
-        $project->dateo=dol_mktime(12,0,0,$_POST['projectmonth'],$_POST['projectday'],$_POST['projectyear']);
-        $project->datee=dol_mktime(12,0,0,$_POST['projectendmonth'],$_POST['projectendday'],$_POST['projectendyear']);
+        $project->date_start=dol_mktime(12,0,0,GETPOST('projectmonth','int'),GETPOST('projectday','int'),GETPOST('projectyear','int'));
+        $project->date_end=dol_mktime(12,0,0,GETPOST('projectendmonth','int'),GETPOST('projectendday','int'),GETPOST('projectendyear','int'));
 
         $result = $project->create($user);
         if ($result > 0)
@@ -151,19 +185,31 @@ if ($action == 'update' && ! $_POST["cancel"] && $user->rights->projet->creer)
     if (! $error)
     {
         $project = new Project($db);
-        $project->fetch($_POST["id"]);
+        $project->fetch($id);
 
-        $project->ref          = $_POST["ref"];
-        $project->title        = $_POST["title"];
-        $project->socid        = $_POST["socid"];
-        $project->description  = $_POST["description"];
-        $project->public       = $_POST["public"];
-        $project->date_start   = empty($_POST["project"])?'':dol_mktime(12,0,0,$_POST['projectmonth'],$_POST['projectday'],$_POST['projectyear']);
-        $project->date_end     = empty($_POST["projectend"])?'':dol_mktime(12,0,0,$_POST['projectendmonth'],$_POST['projectendday'],$_POST['projectendyear']);
+		$old_start_date = $project->date_start;
+
+        $project->ref             = GETPOST('ref','alpha');
+        $project->title           = GETPOST('title','alpha');
+        $project->socid           = GETPOST('socid','int');
+        $project->description     = GETPOST('description','alpha');
+        $project->public          = GETPOST('public','alpha');
+        $project->date_start   = empty($_POST["project"])?'':dol_mktime(0,0,0,GETPOST('projectmonth'),GETPOST('projectday'),GETPOST('projectyear'));
+        $project->date_end     = empty($_POST["projectend"])?'':dol_mktime(0,0,0,GETPOST('projectendmonth'),GETPOST('projectendday'),GETPOST('projectendyear'));
 
         $result=$project->update($user);
 
         $id=$project->id;  // On retourne sur la fiche projet
+        
+        if (GETPOST("reportdate") && ($project->date_start!=$old_start_date))
+        {
+        	$result=$project->shiftTaskDate($old_start_date);
+        	if (!$result)
+        	{
+        		$error++;
+        		$mesg='<div class="error">'.$langs->trans("ErrorShiftTaskDate").':'.$project->error.'</div>';
+        	}
+        }
     }
     else
     {
@@ -251,6 +297,24 @@ if ($action == 'confirm_delete' && GETPOST("confirm") == "yes" && $user->rights-
     }
 }
 
+if ($action == 'confirm_clone' && $user->rights->projet->creer && GETPOST('confirm') == 'yes')
+{
+	$idtoclone=$id;
+	$project = new Project($db);
+    $project->fetch($idtoclone);
+    $result=$project->createFromClone($idtoclone,true,true,true,true);
+    if ($result <= 0)
+    {
+        $mesg='<div class="error">'.$project->error.'</div>';
+    }
+    else
+    {
+    	$id=$result;
+    	$action='edit';
+    	$comefromclone=true;
+    }
+}
+
 
 /*
  *	View
@@ -395,14 +459,20 @@ else
         $ret=$form->form_confirm($_SERVER["PHP_SELF"]."?id=".$project->id,$langs->trans("DeleteAProject"),$text,"confirm_delete",'','',1);
         if ($ret == 'html') print '<br>';
     }
-
-
+    // Clone confirmation
+    if ($action == 'clone')
+    {
+        $ret=$form->form_confirm($_SERVER["PHP_SELF"]."?id=".$project->id,$langs->trans("CloneProject"),$langs->trans("ConfirmCloneProject"),"confirm_clone",'','',1);
+        if ($ret == 'html') print '<br>';
+    }
+    
     if ($action == 'edit' && $userWrite > 0)
     {
         print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
         print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
         print '<input type="hidden" name="action" value="update">';
         print '<input type="hidden" name="id" value="'.$project->id.'">';
+        print '<input type="hidden" name="comefromclone" value="'.$comefromclone.'">';
 
         print '<table class="border" width="100%">';
 
@@ -433,6 +503,9 @@ else
         // Date start
         print '<tr><td>'.$langs->trans("DateStart").'</td><td>';
         print $form->select_date($project->date_start,'project');
+        print '<input type="checkbox" name="reportdate" value="yes" ';
+        if ($comefromclone){print ' checked="checked" ';} 
+		print '/>'. $langs->trans("ProjectReportDate");
         print '</td></tr>';
 
         // Date end
@@ -450,8 +523,8 @@ else
 
         print '<div align="center"><br>';
         print '<input name="update" class="button" type="submit" value="'.$langs->trans("Modify").'"> &nbsp; ';
-        print '<input type="submit" class="button" name="cancel" Value="'.$langs->trans("Cancel").'"></div>';
-
+        print '<input type="submit" class="button" name="cancel" value="'.$langs->trans("Cancel").'"></div>';
+        
         print '</form>';
     }
     else
@@ -514,7 +587,7 @@ else
 
     if ($action != "edit" )
     {
-        // Validate
+    	// Validate
         if ($project->statut == 0 && $user->rights->projet->creer)
         {
             if ($userWrite > 0)
@@ -565,6 +638,19 @@ else
                 print '<a class="butActionRefused" href="#" title="'.$langs->trans("NotOwnerOfProject").'">'.$langs->trans('ReOpen').'</a>';
             }
         }
+        
+        // Clone
+        if ($user->rights->projet->creer)
+        {
+            if ($userWrite > 0)
+            {
+                print '<a class="butAction" href="fiche.php?id='.$project->id.'&action=clone">'.$langs->trans('ToClone').'</a>';
+            }
+            else
+            {
+                print '<a class="butActionRefused" href="#" title="'.$langs->trans("NotOwnerOfProject").'">'.$langs->trans('ToClone').'</a>';
+            }
+        }
 
         // Delete
         if ($user->rights->projet->supprimer)
@@ -611,7 +697,6 @@ else
 
         print '</td></tr></table>';
     }
-
 }
 
 llxFooter();
diff --git a/htdocs/projet/tasks.php b/htdocs/projet/tasks.php
index 6c4ccb733fa..a65ff6b10b6 100644
--- a/htdocs/projet/tasks.php
+++ b/htdocs/projet/tasks.php
@@ -65,8 +65,8 @@ if ($action == 'createtask' && $user->rights->projet->creer)
 {
 	$error=0;
 
-	$date_start = dol_mktime(12,0,0,$_POST['dateomonth'],$_POST['dateoday'],$_POST['dateoyear']);
-    $date_end = dol_mktime(12,0,0,$_POST['dateemonth'],$_POST['dateeday'],$_POST['dateeyear']);
+	$date_start = dol_mktime(0,0,0,$_POST['dateomonth'],$_POST['dateoday'],$_POST['dateoyear']);
+    $date_end = dol_mktime(0,0,0,$_POST['dateemonth'],$_POST['dateeday'],$_POST['dateeyear']);
 
 	if (empty($_POST["cancel"]))
 	{
@@ -198,6 +198,16 @@ if ($id > 0 || ! empty($ref))
     print '<tr><td>'.$langs->trans("Visibility").'</td><td>';
     if ($object->public) print $langs->trans('SharedProject');
     else print $langs->trans('PrivateProject');
+    print '</td></tr>';
+
+ 	// Date start
+    print '<tr><td>'.$langs->trans("DateStart").'</td><td>';
+    print dol_print_date($object->date_start,'day'); 
+    print '</td></tr>';
+
+    // Date end
+    print '<tr><td>'.$langs->trans("DateEnd").'</td><td>';
+    print dol_print_date($object->date_end,'day');
     print '</td></tr>';
 
     // Statut
diff --git a/htdocs/projet/tasks/document.php b/htdocs/projet/tasks/document.php
index 65a758ee137..26f8d574480 100644
--- a/htdocs/projet/tasks/document.php
+++ b/htdocs/projet/tasks/document.php
@@ -1,7 +1,7 @@
 <?php
 /* Copyright (C) 2010-2012 Regis Houssin <regis@dolibarr.fr>
  * Copyright (C) 2006-2012 Laurent Destailleur  <eldy@users.sourceforge.net>
- * Copyright (C) 2012      Florian Henry
+ * Copyright (C) 2012      Florian Henry <florian.henry@open-concept.pro>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -60,13 +60,9 @@ $pagenext = $page + 1;
 if (! $sortorder) $sortorder="ASC";
 if (! $sortfield) $sortfield="name";
 
-
 $object = new Task($db);
 $projectstatic = new Project($db);
 
-
-
-
 /*
  * Actions
  */
@@ -287,4 +283,4 @@ else
 llxFooter();
 
 $db->close();
-?>
\ No newline at end of file
+?>
diff --git a/htdocs/projet/tasks/note.php b/htdocs/projet/tasks/note.php
index 11cf96ca9c7..9108952c2c3 100644
--- a/htdocs/projet/tasks/note.php
+++ b/htdocs/projet/tasks/note.php
@@ -46,17 +46,17 @@ if (!$user->rights->projet->lire) accessforbidden();
 $object = new Task($db);
 $projectstatic = new Project($db);
 
-if ($id > 0 || ! empty($ref))
-{
-	if ($object->fetch($id,$ref) > 0)
-	{
+if ($id > 0 || ! empty($ref))
+{
+	if ($object->fetch($id,$ref) > 0)
+	{
 		$projectstatic->fetch($object->fk_project);
-		if (! empty($projectstatic->socid)) $projectstatic->societe->fetch($projectstatic->socid);
-	}
-	else
-	{
-		dol_print_error($db);
-	}
+		if (! empty($projectstatic->socid)) $projectstatic->societe->fetch($projectstatic->socid);
+	}
+	else
+	{
+		dol_print_error($db);
+	}
 }
 
 
-- 
GitLab