diff --git a/ChangeLog b/ChangeLog
index 6ac794b974eba678666e5d954f03465d6f7bb328..15c1dc404f5e7bdfcb15a78b5b64f2d1e80419e1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -22,6 +22,26 @@ Following changes may create regression for some external modules, but were nece
 * Removed the trigger file of PAYPAL module that stored data that was not used by Dolibarr. The trigger event still
   exists, but if an external module need action on it, it must provides itself its trigger file.
 
+***** ChangeLog for 5.0.3 compared to 5.0.2 *****
+FIX: #6677 Expired contracts dashboard box does not show the name of the thirdparty
+FIX: #6813
+FIX: 6863
+FIX: #6877
+FIX: #6881
+FIX: Better sanitizing of search all parameter.
+FIX: Correction with author and validator user on orders
+FIX: dialog window with md theme must not be hidden by left menu part.
+FIX: doactions hook missing in invoice model page
+FIX: Fullname when member is a moral entity with no name.
+FIX: Link to files on bank account tab broken with multicompany FIX: Link to preview on thirdparty broken with multicompany
+FIX: New vat code not correctly implemented if "1 price per customer".
+FIX: Pagination of invoices
+FIX: pagination on resources
+FIX: REST API not possible to add agendaevents
+FIX: situation invoice broken due to the all percent application form inside addline form
+FIX: SQL injection on user/index.php parameter search_statut.
+FIX: XSS
+
 ***** ChangeLog for 5.0.2 compared to 5.0.1 *****
 FIX: #6468 + Fix missing translation
 FIX: #6517 #6525 Autocompletion of thirdparty after n chars not implemented
diff --git a/build/debian/README.howto b/build/debian/README.howto
index c94309ec2ef7ea21f44e3bbb9223911443ae8cfe..1632e95423785a656b677a60c3b0a61826b74bfc 100644
--- a/build/debian/README.howto
+++ b/build/debian/README.howto
@@ -444,3 +444,4 @@ Note that package 3.5.7 contains not only fixed for bugs reported to debian. It
 so it is a better solution to validate this maintenance release than applying a patch of the only CVE-2015-3935. 
 After discussion with ..., it appears that security holes are enough to request this unblock request."
 
+Note: If there is a response to ask more information, don't forget to remove the tag during answer.
diff --git a/build/debian/source/lintian-overrides b/build/debian/source/lintian-overrides
index b4c0956e90f896ac1d53d96549da222bdb5741b4..c878035b4821d8fa0a9d25c51e467e596c18426f 100644
--- a/build/debian/source/lintian-overrides
+++ b/build/debian/source/lintian-overrides
@@ -4,7 +4,12 @@ dolibarr: source-contains-prebuilt-javascript-object htdocs/includes/jsgantt/*
 dolibarr: source-contains-prebuilt-javascript-object htdocs/includes/jstz/*
 # Those are false positives, the files are their own sources since
 # they are not minified
-source-is-missing htdocs/includes/jsgantt/jsgantt.js *
-source-is-missing htdocs/includes/jquery/plugins/colorpicker/jquery.colorpicker.js *
-source-is-missing htdocs/includes/jquery/plugins/select2/select2.js *
-source-is-missing htdocs/includes/jquery/plugins/select2/select2_locale_ar.js *
+source-is-missing htdocs/includes/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/*.js
+source-is-missing htdocs/includes/ckeditor/ckeditor/plugins/specialchar/dialogs/lang/*.js
+source-is-missing htdocs/includes/ckeditor/ckeditor/lang/*.js
+source-is-missing htdocs/includes/ckeditor/ckeditor/plugins/*/dialogs/*.js
+source-is-missing htdocs/includes/ckeditor/ckeditor/plugins/*/filter/*.js
+source-is-missing htdocs/includes/ckeditor/ckeditor/plugins/templates/templates/default.js
+source-is-missing htdocs/includes/mobiledetect/mobiledetectlib/Mobile_Detect.json
+source-is-missing htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/*.js
+
diff --git a/htdocs/admin/agenda_other.php b/htdocs/admin/agenda_other.php
index bd9587a4440538f0f1ffec3b0353f9d02ec47963..44ec3ade8895a028f83b7ba3b2a01107c7acacc5 100644
--- a/htdocs/admin/agenda_other.php
+++ b/htdocs/admin/agenda_other.php
@@ -49,6 +49,8 @@ $type = 'action';
  *	Actions
  */
 
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
+
 if (preg_match('/set_(.*)/',$action,$reg))
 {
 	$code=$reg[1];
@@ -77,21 +79,6 @@ if (preg_match('/del_(.*)/',$action,$reg))
 		dol_print_error($db);
 	}
 }
-// Define constants for submodules that contains parameters (forms with param1, param2, ... and value1, value2, ...)
-if ($action == 'setModuleOptions')
-{
-
-	if ($param) $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity);
-	if (! $res > 0) $error++;
-	if (! $error)
-	{
-		setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
-	}
-	else
-	{
-        setEventMessages($langs->trans("Error"), null, 'errors');
-	}
-}
 if ($action == 'set')
 {
 	dolibarr_set_const($db, 'AGENDA_USE_EVENT_TYPE_DEFAULT', GETPOST('AGENDA_USE_EVENT_TYPE_DEFAULT'), 'chaine', 0, '', $conf->entity);
@@ -233,7 +220,7 @@ else
 if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
 {
     print load_fiche_titre($langs->trans("AgendaModelModule"),'','');
-    
+
     print '<table class="noborder" width="100%">'."\n";
     print '<tr class="liste_titre">'."\n";
     print '<td width="100">'.$langs->trans("Name").'</td>'."\n";
@@ -243,13 +230,13 @@ if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
     print '<td align="center" width="40">'.$langs->trans("ShortInfo").'</td>';
     print '<td align="center" width="40">'.$langs->trans("Preview").'</td>';
     print '</tr>'."\n";
-    
+
     clearstatcache();
-    
+
     foreach ($dirmodels as $reldir)
     {
     	$dir = dol_buildpath($reldir."core/modules/action/doc/");
-    
+
         if (is_dir($dir))
         {
             $handle=opendir($dir);
@@ -261,10 +248,10 @@ if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
                     {
             			$name = substr($file, 4, dol_strlen($file) -16);
             			$classname = substr($file, 0, dol_strlen($file) -12);
-            			
+
             			require_once $dir.'/'.$file;
-            			$module = new $classname($db, new ActionComm($db));           			
-            			
+            			$module = new $classname($db, new ActionComm($db));
+
             			print '<tr class="oddeven">'."\n";
             			print "<td>";
             			print (empty($module->name)?$name:$module->name);
@@ -272,16 +259,16 @@ if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
             			print "<td>\n";
             			require_once $dir.$file;
             			$module = new $classname($db,$specimenthirdparty);
-            			if (method_exists($module,'info')) 
+            			if (method_exists($module,'info'))
             				print $module->info($langs);
-            			else 
+            			else
             				print $module->description;
             			print "</td>\n";
-            			
+
             			// Active
             			if (in_array($name, $def))
             			{
-            			    
+
             			print '<td align="center">'."\n";
             			if ($conf->global->ACTION_EVENT_ADDON_PDF != "$name")
             			{
@@ -301,7 +288,7 @@ if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
             				print '<a href="'.$_SERVER["PHP_SELF"].'?action=setmodel&amp;value='.$name.'&amp;scandir='.$module->scandir.'&amp;label='.urlencode($module->name).'&amp;type=action">'.img_picto($langs->trans("Disabled"),'switch_off').'</a>';
             				print "</td>";
             			}
-            			
+
             			// Default
             			print '<td align="center">';
             			if ($conf->global->ACTION_EVENT_ADDON_PDF == "$name")
@@ -313,7 +300,7 @@ if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
             				print '<a href="'.$_SERVER["PHP_SELF"].'?action=setdoc&amp;value='.$name.'&amp;scandir='.$module->scandir.'&amp;label='.urlencode($module->name).'&amp;type=action"" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"),'off').'</a>';
             			}
             			print '</td>';
-            			
+
             			// Info
             			$htmltooltip =    ''.$langs->trans("Name").': '.$module->name;
             			$htmltooltip.='<br>'.$langs->trans("Type").': '.($module->type?$module->type:$langs->trans("Unknown"));
@@ -326,7 +313,7 @@ if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
             			print '<td align="center">';
             			print '<a href="'.$_SERVER["PHP_SELF"].'?action=specimen&amp;module='.$name.'">'.img_object($langs->trans("Preview"),'order').'</a>';
             			print '</td>';
-            			
+
             			print "</tr>\n";
                     }
                 }
@@ -366,7 +353,7 @@ print '</td></tr>'."\n";
 
 if (! empty($conf->global->AGENDA_USE_EVENT_TYPE))
 {
-    
+
     print '<!-- AGENDA_USE_EVENT_TYPE_DEFAULT -->';
     print '<tr class="oddeven">'."\n";
     print '<td>'.$langs->trans("AGENDA_USE_EVENT_TYPE_DEFAULT").'</td>'."\n";
@@ -404,30 +391,30 @@ print '</td></tr>'."\n";
 // AGENDA NOTIFICATION
 if ($conf->global->MAIN_FEATURES_LEVEL > 0)
 {
-    
+
     print '<tr class="oddeven">'."\n";
     print '<td>'.$langs->trans('AGENDA_NOTIFICATION').'</td>'."\n";
     print '<td align="center">&nbsp;</td>'."\n";
     print '<td align="right">'."\n";
-    
+
     if (empty($conf->global->AGENDA_NOTIFICATION)) {
         print '<a href="'.$_SERVER['PHP_SELF'].'?action=set_AGENDA_NOTIFICATION">'.img_picto($langs->trans('Disabled'),'switch_off').'</a>';
         print '</td></tr>'."\n";
     } else {
         print '<a href="'.$_SERVER['PHP_SELF'].'?action=del_AGENDA_NOTIFICATION">'.img_picto($langs->trans('Enabled'),'switch_on').'</a>';
         print '</td></tr>'."\n";
-    	
+
         print '<tr class="oddeven">'."\n";
         print '<td>'.$langs->trans('AGENDA_NOTIFICATION_SOUND').'</td>'."\n";
         print '<td align="center">&nbsp;</td>'."\n";
         print '<td align="right">'."\n";
-    
+
         if (empty($conf->global->AGENDA_NOTIFICATION_SOUND)) {
             print '<a href="'.$_SERVER['PHP_SELF'].'?action=set_AGENDA_NOTIFICATION_SOUND">'.img_picto($langs->trans('Disabled'),'switch_off').'</a>';
         } else {
             print '<a href="'.$_SERVER['PHP_SELF'].'?action=del_AGENDA_NOTIFICATION_SOUND">'.img_picto($langs->trans('Enabled'),'switch_on').'</a>';
         }
-    
+
         print '</td></tr>'."\n";
     }
 }
diff --git a/htdocs/admin/barcode.php b/htdocs/admin/barcode.php
index db81c9a325f0cf99e8e0880d17d22fa6c47159b1..ba649fe92236e5d4d6633da0e3428cc72c83f944 100644
--- a/htdocs/admin/barcode.php
+++ b/htdocs/admin/barcode.php
@@ -39,6 +39,8 @@ $action = GETPOST('action','alpha');
  * Actions
  */
 
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
+
 if ($action == 'setbarcodeproducton')
 {
 	$res=dolibarr_set_const($db, "BARCODE_PRODUCT_ADDON_NUM", GETPOST('value'), 'chaine', 0, '', $conf->entity);
@@ -72,33 +74,7 @@ else if ($action == 'update')
 else if ($action == 'updateengine')
 {
     // TODO Update engines.
-    
-}
-
-// define constants for models generator that need parameters
-if ($action == 'setModuleOptions')
-{
-    $post_size=count($_POST);
-
-    for($i=0;$i < $post_size;$i++)
-    {
-        if (array_key_exists('param'.$i,$_POST))
-        {
-            $param=GETPOST("param".$i,'alpha');
-            $value=GETPOST("value".$i,'alpha');
-            if ($param) $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity);
-        }
-    }
-	if (! $res > 0) $error++;
 
- 	if (! $error)
-    {
-        setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
-    }
-    else
-    {
-        setEventMessages($langs->trans("Error"), null, 'errors');
-    }
 }
 
 if ($action && $action != 'setcoder' && $action != 'setModuleOptions')
@@ -276,7 +252,7 @@ if ($resql)
 		print '<td align="center">';
 		print $formbarcode->setBarcodeEncoder($obj->coder,$barcodelist,$obj->rowid,'form'.$i);
 		print "</td></tr>\n";
-		
+
 		$i++;
 	}
 }
@@ -312,7 +288,7 @@ print '</tr>';
 // Chemin du binaire genbarcode sous linux
 if (! isset($_SERVER['WINDIR']))
 {
-	
+
 	print '<tr class="oddeven">';
 	print '<td>'.$langs->trans("GenbarcodeLocation").'</td>';
 	print '<td width="60" align="center">';
@@ -328,7 +304,7 @@ if (! isset($_SERVER['WINDIR']))
 // Module products
 if (! empty($conf->product->enabled))
 {
-	
+
 	print '<tr class="oddeven">';
 	print '<td>'.$langs->trans("SetDefaultBarcodeTypeProducts").'</td>';
 	print '<td width="60" align="right">';
@@ -339,7 +315,7 @@ if (! empty($conf->product->enabled))
 // Module thirdparty
 if (! empty($conf->societe->enabled))
 {
-	
+
 	print '<tr class="oddeven">';
 	print '<td>'.$langs->trans("SetDefaultBarcodeTypeThirdParties").'</td>';
 	print '<td width="60" align="right">';
diff --git a/htdocs/admin/chequereceipts.php b/htdocs/admin/chequereceipts.php
index bc55eb4b9f648418476e02de3ff9e41c72788f93..f88dfc6f5a6784c05ffa21c8389d8cba036af5bb 100644
--- a/htdocs/admin/chequereceipts.php
+++ b/htdocs/admin/chequereceipts.php
@@ -77,7 +77,7 @@ if ($action == 'setmod')
 
 if ($action == 'set_BANK_CHEQUERECEIPT_FREE_TEXT')
 {
-	$freetext = GETPOST('BANK_CHEQUERECEIPT_FREE_TEXT');	// No alpha here, we want exact string
+	$freetext = GETPOST('BANK_CHEQUERECEIPT_FREE_TEXT','none');	// No alpha here, we want exact string
 
     $res = dolibarr_set_const($db, "BANK_CHEQUERECEIPT_FREE_TEXT",$freetext,'chaine',0,'',$conf->entity);
 
diff --git a/htdocs/admin/commande.php b/htdocs/admin/commande.php
index 6d92ad21999b8d8dbbd70b5734a29f59c83b9817..f4104e2007fee609846e3cca775702771b017c48 100644
--- a/htdocs/admin/commande.php
+++ b/htdocs/admin/commande.php
@@ -54,6 +54,8 @@ $type = 'order';
  * Actions
  */
 
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
+
 if ($action == 'updateMask')
 {
 	$maskconstorder=GETPOST('maskconstorder','alpha');
@@ -118,35 +120,6 @@ else if ($action == 'specimen')
 	}
 }
 
-// Define constants for submodules that contains parameters (forms with param1, param2, ... and value1, value2, ...)
-if ($action == 'setModuleOptions')
-{
-	$post_size=count($_POST);
-
-	$db->begin();
-
-	for($i=0;$i < $post_size;$i++)
-	{
-		if (array_key_exists('param'.$i,$_POST))
-		{
-			$param=GETPOST("param".$i,'alpha');
-			$value=GETPOST("value".$i,'alpha');
-			if ($param) $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity);
-			if (! $res > 0) $error++;
-		}
-	}
-	if (! $error)
-	{
-		$db->commit();
-		setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
-	}
-	else
-	{
-		$db->rollback();
-		setEventMessages($langs->trans("Error"), null, 'errors');
-	}
-}
-
 // Activate a model
 else if ($action == 'set')
 {
@@ -207,7 +180,7 @@ else if ($action == 'set_COMMANDE_DRAFT_WATERMARK')
 
 else if ($action == 'set_ORDER_FREE_TEXT')
 {
-	$freetext = GETPOST("ORDER_FREE_TEXT");	// No alpha here, we want exact string
+	$freetext = GETPOST("ORDER_FREE_TEXT",'none');	// No alpha here, we want exact string
 
 	$res = dolibarr_set_const($db, "ORDER_FREE_TEXT",$freetext,'chaine',0,'',$conf->entity);
 
diff --git a/htdocs/admin/contract.php b/htdocs/admin/contract.php
index 47e53a05048ce120e439bea895aa994de1f75576..e2f865f61f6006e31f58630b627350bce270207c 100644
--- a/htdocs/admin/contract.php
+++ b/htdocs/admin/contract.php
@@ -50,6 +50,8 @@ if (empty($conf->global->CONTRACT_ADDON))
  * Actions
  */
 
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
+
 if ($action == 'updateMask')
 {
     $maskconst = GETPOST('maskconstcontract','alpha');
@@ -113,35 +115,6 @@ else if ($action == 'specimen') // For contract
 	}
 }
 
-// Define constants for submodules that contains parameters (forms with param1, param2, ... and value1, value2, ...)
-if ($action == 'setModuleOptions')
-{
-	$post_size=count($_POST);
-
-	$db->begin();
-
-	for($i=0;$i < $post_size;$i++)
-	{
-		if (array_key_exists('param'.$i,$_POST))
-		{
-			$param=GETPOST("param".$i,'alpha');
-			$value=GETPOST("value".$i,'alpha');
-			if ($param) $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity);
-			if (! $res > 0) $error++;
-		}
-	}
-	if (! $error)
-	{
-		$db->commit();
-		setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
-	}
-	else
-	{
-		$db->rollback();
-        setEventMessages($langs->trans("Error"), null, 'errors');
-	}
-}
-
 // Activate a model
 else if ($action == 'set')
 {
@@ -185,7 +158,7 @@ else if ($action == 'setmod')
 
 else if ($action == 'set_other')
 {
-	$freetext= GETPOST('CONTRACT_FREE_TEXT');	// No alpha here, we want exact string
+	$freetext= GETPOST('CONTRACT_FREE_TEXT','none');	// No alpha here, we want exact string
 	$res1 = dolibarr_set_const($db, "CONTRACT_FREE_TEXT",$freetext,'chaine',0,'',$conf->entity);
 
 	$draft= GETPOST('CONTRACT_DRAFT_WATERMARK','alpha');
@@ -501,7 +474,7 @@ print '<td align="center" width="60">'.$langs->trans("Value").'</td>';
 print "</tr>\n";
 $var=true;
 
-$substitutionarray=pdf_getSubstitutionArray($langs);
+$substitutionarray=pdf_getSubstitutionArray($langs, array('objectamount'));
 $substitutionarray['__(AnyTranslationKey)__']=$langs->trans("Translation");
 $htmltext = '<i>'.$langs->trans("AvailableVariables").':<br>';
 foreach($substitutionarray as $key => $val)	$htmltext.=$key.'<br>';
diff --git a/htdocs/admin/expedition.php b/htdocs/admin/expedition.php
index e9a9aaedb1878d06b86f2bff06996d11f4fd45f6..12d0b7951d5df55f88fc17811d5e9b9ed27fc050 100644
--- a/htdocs/admin/expedition.php
+++ b/htdocs/admin/expedition.php
@@ -57,6 +57,9 @@ if (empty($conf->global->EXPEDITION_ADDON_NUMBER))
 /*
  * Actions
  */
+
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
+
 if ($action == 'updateMask')
 {
 	$maskconst=GETPOST('maskconstexpedition','alpha');
@@ -75,7 +78,7 @@ if ($action == 'updateMask')
 
 else if ($action == 'set_param')
 {
-	$freetext=GETPOST('SHIPPING_FREE_TEXT');	// No alpha here, we want exact string
+	$freetext=GETPOST('SHIPPING_FREE_TEXT','none');	// No alpha here, we want exact string
 	$res = dolibarr_set_const($db, "SHIPPING_FREE_TEXT",$freetext,'chaine',0,'',$conf->entity);
 	if ($res <= 0)
 	{
@@ -142,35 +145,6 @@ else if ($action == 'specimen')
 	}
 }
 
-// Define constants for submodules that contains parameters (forms with param1, param2, ... and value1, value2, ...)
-else if ($action == 'setModuleOptions')
-{
-	$post_size=count($_POST);
-
-	$db->begin();
-
-	for($i=0;$i < $post_size;$i++)
-	{
-		if (array_key_exists('param'.$i,$_POST))
-		{
-			$param=GETPOST("param".$i,'alpha');
-			$value=GETPOST("value".$i,'alpha');
-			if ($param) $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity);
-			if (! $res > 0) $error++;
-		}
-	}
-	if (! $error)
-	{
-		$db->commit();
-		setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
-	}
-	else
-	{
-		$db->rollback();
-		setEventMessages($langs->trans("Error"), null, 'errors');
-	}
-}
-
 // Activate a model
 else if ($action == 'set')
 {
diff --git a/htdocs/admin/expensereport.php b/htdocs/admin/expensereport.php
index 92ba93759270c8ca8475f988677df0aa2a29c62a..24aaeede5b49b446b7e6b153442f718ff1436150 100644
--- a/htdocs/admin/expensereport.php
+++ b/htdocs/admin/expensereport.php
@@ -51,6 +51,9 @@ $type='expensereport';
 /*
  * Actions
  */
+
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
+
 if ($action == 'updateMask')
 {
 	$maskconst=GETPOST('maskconst','alpha');
@@ -116,35 +119,6 @@ else if ($action == 'specimen') // For fiche inter
 	}
 }
 
-// Define constants for submodules that contains parameters (forms with param1, param2, ... and value1, value2, ...)
-if ($action == 'setModuleOptions')
-{
-	$post_size=count($_POST);
-
-	$db->begin();
-
-	for($i=0;$i < $post_size;$i++)
-	{
-		if (array_key_exists('param'.$i,$_POST))
-		{
-			$param=GETPOST("param".$i,'alpha');
-			$value=GETPOST("value".$i,'alpha');
-			if ($param) $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity);
-			if (! $res > 0) $error++;
-		}
-	}
-	if (! $error)
-	{
-		$db->commit();
-		setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
-	}
-	else
-	{
-		$db->rollback();
-		setEventMessages($langs->trans("Error"), null, 'errors');
-	}
-}
-
 // Activate a model
 else if ($action == 'set')
 {
@@ -194,7 +168,7 @@ else if ($action == 'setoptions')
 {
     $db->begin();
 
-	$freetext= GETPOST('EXPENSEREPORT_FREE_TEXT');	// No alpha here, we want exact string
+	$freetext= GETPOST('EXPENSEREPORT_FREE_TEXT','none');	// No alpha here, we want exact string
 	$res1 = dolibarr_set_const($db, "EXPENSEREPORT_FREE_TEXT",$freetext,'chaine',0,'',$conf->entity);
 
 	$draft= GETPOST('EXPENSEREPORT_DRAFT_WATERMARK','alpha');
diff --git a/htdocs/admin/facture.php b/htdocs/admin/facture.php
index 64ae1abdde6d8fd992f8e7098cde157a33ab252b..df371639cde6d3dcb4c6d8cfdaf06b32840336c3 100644
--- a/htdocs/admin/facture.php
+++ b/htdocs/admin/facture.php
@@ -51,6 +51,8 @@ $type='invoice';
  * Actions
  */
 
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
+
 if ($action == 'updateMask')
 {
     $maskconstinvoice=GETPOST('maskconstinvoice','alpha');
@@ -123,31 +125,6 @@ if ($action == 'specimen')
     }
 }
 
-// define constants for models generator that need parameters
-if ($action == 'setModuleOptions')
-{
-    $post_size=count($_POST);
-    for($i=0;$i < $post_size;$i++)
-    {
-        if (array_key_exists('param'.$i,$_POST))
-        {
-            $param=GETPOST("param".$i,'alpha');
-            $value=GETPOST("value".$i,'alpha');
-            if ($param) $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity);
-        }
-    }
-	if (! $res > 0) $error++;
-
- 	if (! $error)
-    {
-        setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
-    }
-    else
-    {
-        setEventMessages($langs->trans("Error"), null, 'errors');
-    }
-}
-
 // Activate a model
 else if ($action == 'set')
 {
@@ -229,7 +206,7 @@ if ($action == 'set_FACTURE_DRAFT_WATERMARK')
 
 if ($action == 'set_INVOICE_FREE_TEXT')
 {
-	$freetext = GETPOST('INVOICE_FREE_TEXT');	// No alpha here, we want exact string
+	$freetext = GETPOST('INVOICE_FREE_TEXT','none');	// No alpha here, we want exact string
 
     $res = dolibarr_set_const($db, "INVOICE_FREE_TEXT",$freetext,'chaine',0,'',$conf->entity);
 
diff --git a/htdocs/admin/fichinter.php b/htdocs/admin/fichinter.php
index e3000231c38a4f497baff7e3f72516a4304cff0f..43ad7ad8178163bc6ced6265b96f214667caa38f 100644
--- a/htdocs/admin/fichinter.php
+++ b/htdocs/admin/fichinter.php
@@ -51,6 +51,9 @@ $type='ficheinter';
 /*
  * Actions
  */
+
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
+
 if ($action == 'updateMask')
 {
 	$maskconst=GETPOST('maskconst','alpha');
@@ -114,35 +117,6 @@ else if ($action == 'specimen') // For fiche inter
 	}
 }
 
-// Define constants for submodules that contains parameters (forms with param1, param2, ... and value1, value2, ...)
-if ($action == 'setModuleOptions')
-{
-	$post_size=count($_POST);
-
-	$db->begin();
-
-	for($i=0;$i < $post_size;$i++)
-	{
-		if (array_key_exists('param'.$i,$_POST))
-		{
-			$param=GETPOST("param".$i,'alpha');
-			$value=GETPOST("value".$i,'alpha');
-			if ($param) $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity);
-			if (! $res > 0) $error++;
-		}
-	}
-	if (! $error)
-	{
-		$db->commit();
-		setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
-	}
-	else
-	{
-		$db->rollback();
-		setEventMessages($langs->trans("Error"), null, 'errors');
-	}
-}
-
 // Activate a model
 else if ($action == 'set')
 {
@@ -186,7 +160,7 @@ else if ($action == 'setmod')
 
 else if ($action == 'set_FICHINTER_FREE_TEXT')
 {
-	$freetext= GETPOST('FICHINTER_FREE_TEXT');	// No alpha here, we want exact string
+	$freetext= GETPOST('FICHINTER_FREE_TEXT','none');	// No alpha here, we want exact string
 	$res = dolibarr_set_const($db, "FICHINTER_FREE_TEXT",$freetext,'chaine',0,'',$conf->entity);
 
 	if (! $res > 0) $error++;
diff --git a/htdocs/admin/livraison.php b/htdocs/admin/livraison.php
index cf97b397e444b7761528af3e7e3460949c16ca8a..0136f6cc9d93c5f02bec99fb3af46795bcb5974a 100644
--- a/htdocs/admin/livraison.php
+++ b/htdocs/admin/livraison.php
@@ -47,10 +47,13 @@ $label   = GETPOST('label','alpha');
 $scandir = GETPOST('scandir','alpha');
 $type='delivery';
 
+
 /*
  * Actions
  */
 
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
+
 if ($action == 'updateMask')
 {
     $maskconstdelivery=GETPOST('maskconstdelivery','alpha');
@@ -71,7 +74,7 @@ if ($action == 'updateMask')
 
 if ($action == 'set_DELIVERY_FREE_TEXT')
 {
-    $free=GETPOST('DELIVERY_FREE_TEXT');	// No alpha here, we want exact string
+    $free=GETPOST('DELIVERY_FREE_TEXT','none');	// No alpha here, we want exact string
     $res=dolibarr_set_const($db, "DELIVERY_FREE_TEXT",$free,'chaine',0,'',$conf->entity);
 
     if (! $res > 0) $error++;
@@ -131,35 +134,6 @@ if ($action == 'specimen')
     }
 }
 
-// Define constants for submodules that contains parameters (forms with param1, param2, ... and value1, value2, ...)
-if ($action == 'setModuleOptions')
-{
-	$post_size=count($_POST);
-
-	$db->begin();
-
-	for($i=0;$i < $post_size;$i++)
-	{
-		if (array_key_exists('param'.$i,$_POST))
-		{
-			$param=GETPOST("param".$i,'alpha');
-			$value=GETPOST("value".$i,'alpha');
-			if ($param) $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity);
-			if (! $res > 0) $error++;
-		}
-	}
-	if (! $error)
-	{
-		$db->commit();
-		setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
-	}
-	else
-	{
-		$db->rollback();
-		setEventMessages($langs->trans("Error"), null, 'errors');
-	}
-}
-
 if ($action == 'set')
 {
     $ret = addDocumentModel($value, $type, $label, $scandir);
diff --git a/htdocs/admin/payment.php b/htdocs/admin/payment.php
index 88f2d8cd1c163963c19f336a9567f466b69bced4..061b9d50f6a877138b7dddc1307b8d3adb0af35e 100644
--- a/htdocs/admin/payment.php
+++ b/htdocs/admin/payment.php
@@ -71,7 +71,7 @@ if ($action == 'setmod')
 
 if ($action == 'setparams')
 {
-	$freetext = GETPOST('FACTURE_PAYMENTS_ON_DIFFERENT_THIRDPARTIES_BILLS');	// No alpha here, we want exact string
+	$freetext = GETPOST('FACTURE_PAYMENTS_ON_DIFFERENT_THIRDPARTIES_BILLS','none');	// No alpha here, we want exact string
 
 	$res = dolibarr_set_const($db, "FACTURE_PAYMENTS_ON_DIFFERENT_THIRDPARTIES_BILLS",$freetext,'chaine',0,'',$conf->entity);
 
@@ -81,24 +81,11 @@ if ($action == 'setparams')
 	{
 		setEventMessages($langs->trans("Error"), null, 'errors');
 	}
-	
-	/*
-	$freetext = GETPOST('INVOICE_AUTO_FILLJS');	// No alpha here, we want exact string
-	
-	$res = dolibarr_set_const($db, "INVOICE_AUTO_FILLJS",$freetext,'chaine',0,'',$conf->entity);
-	
-	if (! $res > 0) $error++;
-	
-	if ($error)
-	{
-	    setEventMessages($langs->trans("Error"), null, 'errors');
-	}*/
-
 	if (! $error)
 	{
 	    setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
 	}
-	
+
 }
 
 
diff --git a/htdocs/admin/propal.php b/htdocs/admin/propal.php
index e0dc1d3b5b471c636fa55ac63c2ad217e4e03e49..8acbf19f939d509d0eb40284c84394b5a8ad1ba8 100644
--- a/htdocs/admin/propal.php
+++ b/htdocs/admin/propal.php
@@ -49,6 +49,9 @@ $type='propal';
 /*
  * Actions
  */
+
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
+
 $error=0;
 if ($action == 'updateMask')
 {
@@ -132,7 +135,7 @@ if ($action == 'set_PROPALE_DRAFT_WATERMARK')
 
 if ($action == 'set_PROPOSAL_FREE_TEXT')
 {
-	$freetext = GETPOST('PROPOSAL_FREE_TEXT');	// No alpha here, we want exact string
+	$freetext = GETPOST('PROPOSAL_FREE_TEXT','none');	// No alpha here, we want exact string
 
 	$res = dolibarr_set_const($db, "PROPOSAL_FREE_TEXT",$freetext,'chaine',0,'',$conf->entity);
 
@@ -180,35 +183,6 @@ if ($action == 'set_BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL')
     }
 }
 
-// Define constants for submodules that contains parameters (forms with param1, param2, ... and value1, value2, ...)
-if ($action == 'setModuleOptions')
-{
-	$post_size=count($_POST);
-
-	$db->begin();
-
-	for($i=0;$i < $post_size;$i++)
-	{
-		if (array_key_exists('param'.$i,$_POST))
-		{
-			$param=GETPOST("param".$i,'alpha');
-			$value=GETPOST("value".$i,'alpha');
-			if ($param) $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity);
-			if (! $res > 0) $error++;
-		}
-	}
-	if (! $error)
-	{
-		$db->commit();
-		setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
-	}
-	else
-	{
-		$db->rollback();
-		setEventMessages($langs->trans("Error"), null, 'errors');
-	}
-}
-
 // Activate a model
 if ($action == 'set')
 {
diff --git a/htdocs/admin/supplier_invoice.php b/htdocs/admin/supplier_invoice.php
index 549bb93809b165efe8768946df9705f3b9d74490..17501cdb4f910b1b0637d1ef178d4c151faf0c7a 100644
--- a/htdocs/admin/supplier_invoice.php
+++ b/htdocs/admin/supplier_invoice.php
@@ -172,7 +172,7 @@ if ($action == 'addcat')
 
 if ($action == 'set_SUPPLIER_INVOICE_FREE_TEXT')
 {
-    $freetext = GETPOST('SUPPLIER_INVOICE_FREE_TEXT');	// No alpha here, we want exact string
+    $freetext = GETPOST('SUPPLIER_INVOICE_FREE_TEXT','none');	// No alpha here, we want exact string
 
     $res = dolibarr_set_const($db, "SUPPLIER_INVOICE_FREE_TEXT",$freetext,'chaine',0,'',$conf->entity);
 
diff --git a/htdocs/admin/supplier_order.php b/htdocs/admin/supplier_order.php
index 55e4e4b3d07be8bcbb46fa48e1eb2dacb2c68bf4..13499af551a9ce13a3d2f4c78532e32882c62d2c 100644
--- a/htdocs/admin/supplier_order.php
+++ b/htdocs/admin/supplier_order.php
@@ -169,7 +169,7 @@ else if ($action == 'addcat')
 
 else if ($action == 'set_SUPPLIER_ORDER_OTHER')
 {
-    $freetext = GETPOST('SUPPLIER_ORDER_FREE_TEXT');	// No alpha here, we want exact string
+    $freetext = GETPOST('SUPPLIER_ORDER_FREE_TEXT','none');	// No alpha here, we want exact string
 	$doubleapproval = GETPOST('SUPPLIER_ORDER_3_STEPS_TO_BE_APPROVED','alpha');
 	$doubleapproval = price2num($doubleapproval );
 
diff --git a/htdocs/admin/supplier_payment.php b/htdocs/admin/supplier_payment.php
index adaa114b1ca2d77830ba50cc174d2d70ae38145a..4227f4d42215ec86a9e08e7281cd34ac86029d86 100644
--- a/htdocs/admin/supplier_payment.php
+++ b/htdocs/admin/supplier_payment.php
@@ -47,6 +47,8 @@ $type='supplier_payment';
  * Actions
  */
 
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
+
 if ($action == 'updateMask')
 {
     $maskconstsupplierpayment=GETPOST('maskconstsupplierpayment','alpha');
@@ -68,31 +70,6 @@ if ($action == 'updateMask')
     dolibarr_set_const($db, "SUPPLIER_PAYMENT_ADDON", $value, 'chaine', 0, '', $conf->entity);
 }
 
-// define constants for models generator that need parameters
-else if ($action == 'setModuleOptions')
-{
-    $post_size=count($_POST);
-    for($i=0;$i < $post_size;$i++)
-    {
-        if (array_key_exists('param'.$i,$_POST))
-        {
-            $param=GETPOST("param".$i,'alpha');
-            $value=GETPOST("value".$i,'alpha');
-            if ($param) $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity);
-        }
-    }
-	if (! $res > 0) $error++;
-
- 	if (! $error)
-    {
-        setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
-    }
-    else
-    {
-        setEventMessages($langs->trans("Error"), null, 'errors');
-    }
-}
-
 // Activate a model
 else if ($action == 'set')
 {
@@ -195,7 +172,7 @@ dol_fiche_head($head, 'supplierpayment', $langs->trans("Suppliers"), -1, 'compan
  */
 
 if (empty($conf->global->SUPPLIER_PAYMENT_ADDON)) $conf->global->SUPPLIER_PAYMENT_ADDON = 'mod_supplier_payment_bronan';
-    
+
 print load_fiche_titre($langs->trans("PaymentsNumberingModule"), '', '');
 
 // Load array def with activated templates
@@ -265,7 +242,7 @@ foreach ($dirmodels as $reldir)
                         require_once $dir.$filebis;
 
                         $module = new $classname($db);
-						
+
                         // Show modules according to features level
                         if ($module->version == 'development'  && $conf->global->MAIN_FEATURES_LEVEL < 2) continue;
                         if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) continue;
@@ -375,7 +352,7 @@ foreach ($dirmodels as $reldir)
         {
             while (($file = readdir($handle))!==false)
             {
-                if (preg_match('/\.modules\.php$/i',$file) && preg_match('/^(pdf_|doc_)/',$file))            	
+                if (preg_match('/\.modules\.php$/i',$file) && preg_match('/^(pdf_|doc_)/',$file))
                 {
                     $name = substr($file, 4, dol_strlen($file) -16);
                     $classname = substr($file, 0, dol_strlen($file) -12);
@@ -383,7 +360,7 @@ foreach ($dirmodels as $reldir)
 	                require_once $dir.'/'.$file;
 	                $module = new $classname($db, new PaiementFourn($db));
 
-                    
+
                     print "<tr class=\"oddeven\">\n";
                     print "<td>";
 	                print (empty($module->name)?$name:$module->name);
diff --git a/htdocs/admin/supplier_proposal.php b/htdocs/admin/supplier_proposal.php
index 82eeddd594c1bab5626598b5948d5e8ae5576e6f..8c52ee83dda5b0b563aeba024467f571d937e2d8 100644
--- a/htdocs/admin/supplier_proposal.php
+++ b/htdocs/admin/supplier_proposal.php
@@ -41,10 +41,15 @@ $label = GETPOST('label','alpha');
 $scandir = GETPOST('scandir','alpha');
 $type='supplier_proposal';
 
+$error=0;
+
+
 /*
  * Actions
  */
-$error=0;
+
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
+
 if ($action == 'updateMask')
 {
 	$maskconstsupplier_proposal=GETPOST('maskconstsupplier_proposal','alpha');
@@ -127,7 +132,7 @@ if ($action == 'set_SUPPLIER_PROPOSAL_DRAFT_WATERMARK')
 
 if ($action == 'set_SUPPLIER_PROPOSAL_FREE_TEXT')
 {
-	$freetext = GETPOST('SUPPLIER_PROPOSAL_FREE_TEXT');	// No alpha here, we want exact string
+	$freetext = GETPOST('SUPPLIER_PROPOSAL_FREE_TEXT','none');	// No alpha here, we want exact string
 
 	$res = dolibarr_set_const($db, "SUPPLIER_PROPOSAL_FREE_TEXT",$freetext,'chaine',0,'',$conf->entity);
 
@@ -159,35 +164,6 @@ if ($action == 'set_BANK_ASK_PAYMENT_BANK_DURING_SUPPLIER_PROPOSAL')
     }
 }
 
-// Define constants for submodules that contains parameters (forms with param1, param2, ... and value1, value2, ...)
-if ($action == 'setModuleOptions')
-{
-	$post_size=count($_POST);
-
-	$db->begin();
-
-	for($i=0;$i < $post_size;$i++)
-	{
-		if (array_key_exists('param'.$i,$_POST))
-		{
-			$param=GETPOST("param".$i,'alpha');
-			$value=GETPOST("value".$i,'alpha');
-			if ($param) $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity);
-			if (! $res > 0) $error++;
-		}
-	}
-	if (! $error)
-	{
-		$db->commit();
-		setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
-	}
-	else
-	{
-		$db->rollback();
-		setEventMessages($langs->trans("Error"), null, 'errors');
-	}
-}
-
 // Activate a model
 if ($action == 'set')
 {
diff --git a/htdocs/admin/user.php b/htdocs/admin/user.php
index 0c7574b7ec4da40ede76b99aed6e3736987a8a91..31efcb224741cba9eb2cfe1ea313b738e032f354 100644
--- a/htdocs/admin/user.php
+++ b/htdocs/admin/user.php
@@ -47,37 +47,9 @@ $type='user';
  * Action
  */
 
-// Activate a model
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
 
-// Define constants for submodules that contains parameters (forms with param1, param2, ... and value1, value2, ...)
-if ($action == 'setModuleOptions')
-{
-	$post_size=count($_POST);
-
-	$db->begin();
-
-	for($i=0;$i < $post_size;$i++)
-    {
-    	if (array_key_exists('param'.$i,$_POST))
-    	{
-    		$param=GETPOST("param".$i,'alpha');
-    		$value=GETPOST("value".$i,'alpha');
-    		if ($param) $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity);
-	    	if (! $res > 0) $error++;
-    	}
-    }
-	if (! $error)
-    {
-        $db->commit();
-	    setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
-    }
-    else
-    {
-        $db->rollback();
-	    setEventMessages($langs->trans("Error"), null, 'errors');
-	}
-}
-elseif ($action == 'set_default')
+if ($action == 'set_default')
 {
 	$ret = addDocumentModel($value, $type, $label, $scandir);
 	$res = true;
diff --git a/htdocs/admin/usergroup.php b/htdocs/admin/usergroup.php
index 4642e6d3183e3069620f87ef58fb6212c79e27ae..8d098ee6923398516133e1732f39ed874085b916 100644
--- a/htdocs/admin/usergroup.php
+++ b/htdocs/admin/usergroup.php
@@ -47,37 +47,9 @@ $type='group';
  * Action
  */
 
-// Activate a model
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
 
-// Define constants for submodules that contains parameters (forms with param1, param2, ... and value1, value2, ...)
-if ($action == 'setModuleOptions')
-{
-	$post_size=count($_POST);
-
-	$db->begin();
-
-	for($i=0;$i < $post_size;$i++)
-    {
-    	if (array_key_exists('param'.$i,$_POST))
-    	{
-    		$param=GETPOST("param".$i,'alpha');
-    		$value=GETPOST("value".$i,'alpha');
-    		if ($param) $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity);
-	    	if (! $res > 0) $error++;
-    	}
-    }
-	if (! $error)
-    {
-        $db->commit();
-	    setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
-    }
-    else
-    {
-        $db->rollback();
-	    setEventMessages($langs->trans("Error"), null, 'errors');
-	}
-}
-elseif ($action == 'set_default')
+if ($action == 'set_default')
 {
 	$ret = addDocumentModel($value, $type, $label, $scandir);
 	$res = true;
diff --git a/htdocs/comm/action/card.php b/htdocs/comm/action/card.php
index 02ee84dc2de91f49accbf0b1e7aac0548b87bf05..eb2eddb31979a7b011bdcdff88e0061484ee588d 100644
--- a/htdocs/comm/action/card.php
+++ b/htdocs/comm/action/card.php
@@ -1208,7 +1208,7 @@ if ($id > 0)
 		$out.=img_picto($langs->trans("ViewCal"),'object_calendar','class="hideonsmartphone pictoactionview"');
 		$out.='<a href="'.DOL_URL_ROOT.'/comm/action/index.php?action=show_month&year='.dol_print_date($object->datep,'%Y').'&month='.dol_print_date($object->datep,'%m').'&day='.dol_print_date($object->datep,'%d').'">'.$langs->trans("ViewCal").'</a>';
 		$out.=img_picto($langs->trans("ViewWeek"),'object_calendarweek','class="hideonsmartphone pictoactionview"');
-		$out.='<a href="'.DOL_URL_ROOT.'/comm/action/index.php?action=show_day&year='.dol_print_date($object->datep,'%Y').'&month='.dol_print_date($object->datep,'%m').'&day='.dol_print_date($object->datep,'%d').'">'.$langs->trans("ViewWeek").'</a>';
+		$out.='<a href="'.DOL_URL_ROOT.'/comm/action/index.php?action=show_week&year='.dol_print_date($object->datep,'%Y').'&month='.dol_print_date($object->datep,'%m').'&day='.dol_print_date($object->datep,'%d').'">'.$langs->trans("ViewWeek").'</a>';
 		$out.=img_picto($langs->trans("ViewDay"),'object_calendarday','class="hideonsmartphone pictoactionview"');
 		$out.='<a href="'.DOL_URL_ROOT.'/comm/action/index.php?action=show_day&year='.dol_print_date($object->datep,'%Y').'&month='.dol_print_date($object->datep,'%m').'&day='.dol_print_date($object->datep,'%d').'">'.$langs->trans("ViewDay").'</a>';
 		$linkback.=$out;
diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php
index e46b5718d22b18f841785af15e1ce20a884e6b2f..babeb241de042a708053c869c803d1460654d994 100644
--- a/htdocs/compta/facture/class/facture.class.php
+++ b/htdocs/compta/facture/class/facture.class.php
@@ -54,7 +54,7 @@ class Facture extends CommonInvoice
 	public $fk_element = 'fk_facture';
 	protected $ismultientitymanaged = 1;	// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
 	public $picto='bill';
-	
+
 	/**
 	 * {@inheritdoc}
 	 */
@@ -243,7 +243,7 @@ class Facture extends CommonInvoice
 		if (! $this->mode_reglement_id) $this->mode_reglement_id = 0;
 		$this->brouillon = 1;
         if (empty($this->entity)) $this->entity = $conf->entity;
-        
+
 		// Multicurrency (test on $this->multicurrency_tx because we sould take the default rate only if not using origin rate)
 		if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) list($this->fk_multicurrency,$this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code);
 		else $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code);
@@ -280,7 +280,7 @@ class Facture extends CommonInvoice
 		if ($this->fac_rec > 0)
 		{
 		    $this->fk_fac_rec_source = $this->fac_rec;
-		    
+
 			require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture-rec.class.php';
 			$_facrec = new FactureRec($this->db);
 			$result=$_facrec->fetch($this->fac_rec);
@@ -288,7 +288,7 @@ class Facture extends CommonInvoice
 
 			$this->socid 		     = $_facrec->socid;  // Invoice created on same thirdparty than template
 			$this->entity            = $_facrec->entity; // Invoice created in same entity than template
-			
+
 			// Fields coming from GUI (priority on template). TODO Value of template should be used as default value on GUI so we can use here always value from GUI
 			$this->fk_project        = GETPOST('projectid','int') > 0 ? GETPOST('projectid','int') : $_facrec->fk_project;
 			$this->note_public       = GETPOST('note_public') ? GETPOST('note_public') : $_facrec->note_public;
@@ -301,7 +301,7 @@ class Facture extends CommonInvoice
 			// Set here to have this defined for substitution into notes, should be recalculated after adding lines to get same result
 			$this->total_ht          = $_facrec->total_ht;
 			$this->total_ttc         = $_facrec->total_ttc;
-				
+
 			// Fields always coming from template
 			$this->remise_absolue    = $_facrec->remise_absolue;
 			$this->remise_percent    = $_facrec->remise_percent;
@@ -360,9 +360,10 @@ class Facture extends CommonInvoice
 			    '__INVOICE_YEAR__' => dol_print_date($this->date, '%Y'),
 			    '__INVOICE_NEXT_YEAR__' => dol_print_date(dol_time_plus_duree($this->date, 1, 'y'), '%Y'),
 			);
-			
+
+			$substitutionisok=true;
 			complete_substitutions_array($substitutionarray, $outputlangs);
-			
+
 			$this->note_public=make_substitutions($this->note_public,$substitutionarray);
 			$this->note_private=make_substitutions($this->note_private,$substitutionarray);
 		}
@@ -472,7 +473,7 @@ class Facture extends CommonInvoice
 				    }
 				}
 			}
-			
+
 			if (! $error && $this->id && ! empty($conf->global->MAIN_PROPAGATE_CONTACTS_FROM_ORIGIN) && ! empty($this->origin) && ! empty($this->origin_id))   // Get contact from origin object
 			{
 				$originforcontact = $this->origin;
@@ -483,7 +484,7 @@ class Facture extends CommonInvoice
 				    $exp = new Expedition($this->db);
 				    $exp->fetch($this->origin_id);
 				    $exp->fetchObjectLinked();
-				    if (count($exp->linkedObjectsIds['commande']) > 0) 
+				    if (count($exp->linkedObjectsIds['commande']) > 0)
 				    {
 				        foreach ($exp->linkedObjectsIds['commande'] as $key => $value)
 				        {
@@ -493,10 +494,10 @@ class Facture extends CommonInvoice
 				        }
 				    }
 				}
-				
+
 				$sqlcontact = "SELECT ctc.code, ctc.source, ec.fk_socpeople FROM ".MAIN_DB_PREFIX."element_contact as ec, ".MAIN_DB_PREFIX."c_type_contact as ctc";
 				$sqlcontact.= " WHERE element_id = ".$originidforcontact." AND ec.fk_c_type_contact = ctc.rowid AND ctc.element = '".$originforcontact."'";
-	
+
 				$resqlcontact = $this->db->query($sqlcontact);
 				if ($resqlcontact)
 				{
@@ -555,11 +556,11 @@ class Facture extends CommonInvoice
 				foreach ($this->lines as $i => $val)
 				{
                 	$line = $this->lines[$i];
-                	
+
                 	// Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
 				    //if (! is_object($line)) $line=json_decode(json_encode($line), FALSE);  // convert recursively array into object.
                 	if (! is_object($line)) $line = (object) $line;
-				    
+
 				    if (($line->info_bits & 0x01) == 0)	// We keep only lines with first bit = 0
 					{
 						// Reset fk_parent_line for no child products and special product
@@ -1060,7 +1061,7 @@ class Facture extends CommonInvoice
 		if ($this->type == self::TYPE_CREDIT_NOTE) $picto.='a';	// Credit note
 		if ($this->type == self::TYPE_DEPOSIT) $picto.='d';	// Deposit invoice
         $label='';
-        
+
         if ($user->rights->facture->lire) {
             $label = '<u>' . $langs->trans("ShowInvoice") . '</u>';
             if (! empty($this->ref))
@@ -1079,7 +1080,7 @@ class Facture extends CommonInvoice
     		if ($this->type == self::TYPE_SITUATION) $label=$langs->transnoentitiesnoconv("ShowInvoiceSituation").': '.$this->ref;
     		if ($moretitle) $label.=' - '.$moretitle;
         }
-        
+
 		$linkclose='';
 		if (empty($notooltip) && $user->rights->facture->lire)
 		{
@@ -1113,7 +1114,7 @@ class Facture extends CommonInvoice
     		    $result.='</span>';
 		    }
 		}
-		
+
 		return $result;
 	}
 
@@ -1321,7 +1322,7 @@ class Facture extends CommonInvoice
 				$line->qty              = $objp->qty;
 				$line->subprice         = $objp->subprice;
 
-                $line->vat_src_code     = $objp->vat_src_code; 
+                $line->vat_src_code     = $objp->vat_src_code;
 				$line->tva_tx           = $objp->tva_tx;
 				$line->localtax1_tx     = $objp->localtax1_tx;
 				$line->localtax2_tx     = $objp->localtax2_tx;
@@ -1574,7 +1575,7 @@ class Facture extends CommonInvoice
     			$arraytmp=$formmargin->getMarginInfosArray($srcinvoice, false);
         		$facligne->pa_ht = $arraytmp['pa_total'];
 			}
-			
+
 			$facligne->total_ht  = -$remise->amount_ht;
 			$facligne->total_tva = -$remise->amount_tva;
 			$facligne->total_ttc = -$remise->amount_ttc;
@@ -1628,7 +1629,7 @@ class Facture extends CommonInvoice
 	function set_ref_client($ref_client, $notrigger=0)
 	{
 	    global $user;
-	    
+
 		$error=0;
 
 		$this->db->begin();
@@ -2457,7 +2458,7 @@ class Facture extends CommonInvoice
 		if (! isset($situation_percent) || $situation_percent > 100 || (string) $situation_percent == '') $situation_percent = 100;
 
 		$localtaxes_type=getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
-			
+
 		// Clean vat code
 		$vat_src_code='';
 		if (preg_match('/\((.*)\)/', $txtva, $reg))
@@ -2465,7 +2466,7 @@ class Facture extends CommonInvoice
 		    $vat_src_code = $reg[1];
 		    $txtva = preg_replace('/\s*\(.*\)/', '', $txtva);    // Remove code into vatrate.
 		}
-		
+
 		$remise_percent=price2num($remise_percent);
 		$qty=price2num($qty);
 		$pu_ht=price2num($pu_ht);
@@ -2650,7 +2651,7 @@ class Facture extends CommonInvoice
 	 * 	@param		double		$pu_ht_devise		Unit price in currency
 	 *  @return    	int             				< 0 if KO, > 0 if OK
 	 */
-	function updateline($rowid, $desc, $pu, $qty, $remise_percent, $date_start, $date_end, $txtva, $txlocaltax1=0, $txlocaltax2=0, $price_base_type='HT', $info_bits=0, $type= self::TYPE_STANDARD, $fk_parent_line=0, $skip_update_total=0, $fk_fournprice=null, $pa_ht=0, $label='', $special_code=0, $array_options=0, $situation_percent=0, $fk_unit = null, $pu_ht_devise = 0)
+	function updateline($rowid, $desc, $pu, $qty, $remise_percent, $date_start, $date_end, $txtva, $txlocaltax1=0, $txlocaltax2=0, $price_base_type='HT', $info_bits=0, $type= self::TYPE_STANDARD, $fk_parent_line=0, $skip_update_total=0, $fk_fournprice=null, $pa_ht=0, $label='', $special_code=0, $array_options=0, $situation_percent=100, $fk_unit = null, $pu_ht_devise = 0)
 	{
 		global $conf,$user;
 		// Deprecation warning
@@ -2770,14 +2771,14 @@ class Facture extends CommonInvoice
 			$this->line->label				= $label;
 			$this->line->desc				= $desc;
 			$this->line->qty				= ($this->type==self::TYPE_CREDIT_NOTE?abs($qty):$qty);	// For credit note, quantity is always positive and unit price negative
-            
+
 			$this->line->vat_src_code       = $vat_src_code;
 			$this->line->tva_tx				= $txtva;
 			$this->line->localtax1_tx		= $txlocaltax1;
 			$this->line->localtax2_tx		= $txlocaltax2;
 			$this->line->localtax1_type		= $localtaxes_type[0];
 			$this->line->localtax2_type		= $localtaxes_type[2];
-			
+
 			$this->line->remise_percent		= $remise_percent;
 			$this->line->subprice			= ($this->type==2?-abs($pu_ht):$pu_ht); // For credit note, unit price always negative, always positive otherwise
 			$this->line->date_start			= $date_start;
@@ -2896,7 +2897,7 @@ class Facture extends CommonInvoice
 	function deleteline($rowid)
 	{
         global $user;
-        
+
 		dol_syslog(get_class($this)."::deleteline rowid=".$rowid, LOG_DEBUG);
 
 		if (! $this->brouillon)
@@ -2922,13 +2923,13 @@ class Facture extends CommonInvoice
 		}
 
 		$line=new FactureLigne($this->db);
-		
+
         $line->context = $this->context;
 
 		// For triggers
 		$result = $line->fetch($rowid);
 		if (! ($result > 0)) dol_print_error($db, $line->error, $line->errors);
-		
+
 		if ($line->delete($user) > 0)
 		{
 			$result=$this->update_price(1);
@@ -4292,7 +4293,7 @@ class FactureLigne extends CommonInvoiceLine
 			$this->fk_unit				= $objp->fk_unit;
 			$this->fk_user_modif		= $objp->fk_user_modif;
 			$this->fk_user_author		= $objp->fk_user_author;
-			
+
 			$this->situation_percent    = $objp->situation_percent;
 			$this->fk_prev_id           = $objp->fk_prev_id;
 
diff --git a/htdocs/compta/prelevement/class/bonprelevement.class.php b/htdocs/compta/prelevement/class/bonprelevement.class.php
index 90ba6a2243126ec02118ac3f97f12061009aab91..ab04278ea846e6f21242cf0800073d2c7908b307 100644
--- a/htdocs/compta/prelevement/class/bonprelevement.class.php
+++ b/htdocs/compta/prelevement/class/bonprelevement.class.php
@@ -252,7 +252,7 @@ class BonPrelevement extends CommonObject
     function getErrorString($error)
     {
         global $langs;
-        
+
         $errors = array();
 
         $errors[1027] = $langs->trans("DateInvalid");
@@ -813,7 +813,7 @@ class BonPrelevement extends CommonObject
                 dol_syslog(__METHOD__."::Read invoices error ".$this->db->error(), LOG_ERR);
             }
         }
-        
+
         if (! $error)
         {
             require_once DOL_DOCUMENT_ROOT . '/societe/class/companybankaccount.class.php';
@@ -834,7 +834,7 @@ class BonPrelevement extends CommonObject
                         {
                         	$bac = new CompanyBankAccount($this->db);
                         	$bac->fetch(0,$soc->id);
-                        	
+
                             if ($bac->verif() >= 1)
                             //if (true)
                             {
@@ -867,7 +867,7 @@ class BonPrelevement extends CommonObject
         }
 
         $ok=0;
-        
+
         // Withdraw invoices in factures_prev array
         $out=count($factures_prev)." invoices will be withdrawn.";
         //print $out."\n";
@@ -920,7 +920,7 @@ class BonPrelevement extends CommonObject
 
 					$dir=$conf->prelevement->dir_output.'/receipts';
 					if (! is_dir($dir)) dol_mkdir($dir);
-					
+
 					$this->filename = $dir.'/'.$ref.'.xml';
 
 	                // Create withdraw receipt in database
@@ -1028,7 +1028,7 @@ class BonPrelevement extends CommonObject
                         $this->emetteur_bic                = $account->bic;
 
                         $this->emetteur_ics                = $conf->global->PRELEVEMENT_ICS;		// Ex: PRELEVEMENT_ICS = "FR78ZZZ123456";
-    
+
                         $this->raison_sociale              = $account->proprio;
                     }
 
@@ -1272,16 +1272,6 @@ class BonPrelevement extends CommonObject
 			 * section Debiteur (sepa Debiteurs bloc lines)
 			 */
 
-			/*$tmp_invoices = array();
-
-			$sql = "SELECT f.facnumber as fac FROM ".MAIN_DB_PREFIX."prelevement_lignes as pl, ".MAIN_DB_PREFIX."facture as f, ".MAIN_DB_PREFIX."prelevement_facture as pf, ".MAIN_DB_PREFIX."societe as soc, ".MAIN_DB_PREFIX."c_country as p, ".MAIN_DB_PREFIX."societe_rib as rib WHERE pl.fk_prelevement_bons = ".$this->id." AND pl.rowid = pf.fk_prelevement_lignes AND pf.fk_facture = f.rowid AND soc.fk_pays = p.rowid AND soc.rowid = f.fk_soc AND rib.fk_soc = f.fk_soc AND rib.default_rib = 1";
-			$resql=$this->db->query($sql);
-			if ($resql) {
-				while ($objfac = $this->db->fetch_object($resql)) {
-					$tmp_invoices[] = $objfac->fac;
-				}
-			}*/
-
 			$sql = "SELECT soc.code_client as code, soc.address, soc.zip, soc.town, c.code as country_code,";
 			$sql.= " pl.client_nom as nom, pl.code_banque as cb, pl.code_guichet as cg, pl.number as cc, pl.amount as somme,";
 			$sql.= " f.facnumber as fac, pf.fk_facture as idfac, rib.datec, rib.iban_prefix as iban, rib.bic as bic, rib.rowid as drum";
@@ -1365,35 +1355,6 @@ class BonPrelevement extends CommonObject
 			fputs($this->file, '		</PmtInf>'.$CrLf);
 			fputs($this->file, '	</CstmrDrctDbtInitn>'.$CrLf);
 			fputs($this->file, '</Document>'.$CrLf);
-
-			/*$sql = "SELECT pl.amount";
-			$sql.= " FROM";
-			$sql.= " ".MAIN_DB_PREFIX."prelevement_lignes as pl,";
-			$sql.= " ".MAIN_DB_PREFIX."facture as f,";
-			$sql.= " ".MAIN_DB_PREFIX."prelevement_facture as pf";
-			$sql.= " WHERE pl.fk_prelevement_bons = ".$this->id;
-			$sql.= " AND pl.rowid = pf.fk_prelevement_lignes";
-			$sql.= " AND pf.fk_facture = f.rowid";
-
-			//Lines
-			$i = 0;
-			$resql=$this->db->query($sql);
-			if ($resql)
-			{
-				$num = $this->db->num_rows($resql);
-
-				while ($i < $num)
-				{
-					$obj = $this->db->fetch_object($resql);
-					$this->total = $this->total + $obj->amount;
-					$i++;
-				}
-			}
-			else
-			{
-				$result = -2;
-			}*/
-
         }
 
         // Build file for Other Countries with unknow format
@@ -1580,11 +1541,11 @@ class BonPrelevement extends CommonObject
 		$XML_DEBITOR .='					</FinInstnId>'.$CrLf;
 		$XML_DEBITOR .='				</DbtrAgt>'.$CrLf;
 		$XML_DEBITOR .='				<Dbtr>'.$CrLf;
-		$XML_DEBITOR .='					<Nm>'.strtoupper(dol_string_unaccent($row_nom)).'</Nm>'.$CrLf;
+		$XML_DEBITOR .='					<Nm>'.dolEscapeXML(strtoupper(dol_string_unaccent($row_nom))).'</Nm>'.$CrLf;
 		$XML_DEBITOR .='					<PstlAdr>'.$CrLf;
 		$XML_DEBITOR .='						<Ctry>'.$row_country_code.'</Ctry>'.$CrLf;
-		$XML_DEBITOR .='						<AdrLine>'.dol_string_unaccent(strtr($row_address, array(CHR(13) => ", ", CHR(10) => ""))).'</AdrLine>'.$CrLf;
-		$XML_DEBITOR .='						<AdrLine>'.dol_string_unaccent($row_zip.' '.$row_town).'</AdrLine>'.$CrLf;
+		$XML_DEBITOR .='						<AdrLine>'.dolEscapeXML(dol_trunc(dol_string_unaccent(strtr($row_address, array(CHR(13) => ", ", CHR(10) => ""))),70,'right','UTF-8',true)).'</AdrLine>'.$CrLf;
+		$XML_DEBITOR .='						<AdrLine>'.dolEscapeXML(dol_string_unaccent($row_zip.' '.$row_town)).'</AdrLine>'.$CrLf;
 		$XML_DEBITOR .='					</PstlAdr>'.$CrLf;
 		$XML_DEBITOR .='				</Dbtr>'.$CrLf;
 		$XML_DEBITOR .='				<DbtrAcct>'.$CrLf;
@@ -1679,7 +1640,7 @@ class BonPrelevement extends CommonObject
      *	@return	string					String with SEPA Sender
      */
     function EnregEmetteurSEPA($configuration, $ladate, $nombre, $total, $CrLf='\n')
-    {	
+    {
         // SEPA INITIALISATION
 		global $conf;
 
@@ -1698,12 +1659,12 @@ class BonPrelevement extends CommonObject
 		    $this->emetteur_number_key		   = $account->cle_rib;
 		    $this->emetteur_iban               = $account->iban;
 		    $this->emetteur_bic                = $account->bic;
-		
+
 		    $this->emetteur_ics                = $conf->global->PRELEVEMENT_ICS;		// Ex: PRELEVEMENT_ICS = "FR78ZZZ123456";
-		
+
 		    $this->raison_sociale              = $account->proprio;
 		}
-		
+
 		// Récupération info demandeur
 		$sql = "SELECT rowid, ref";
 		$sql.= " FROM";
diff --git a/htdocs/contrat/class/contrat.class.php b/htdocs/contrat/class/contrat.class.php
index db6464edb6ae955474a8be8b9e6ddb4242d86db2..8b9b0dd0c7564d4053326343caa4b7a7050830cc 100644
--- a/htdocs/contrat/class/contrat.class.php
+++ b/htdocs/contrat/class/contrat.class.php
@@ -46,7 +46,7 @@ class Contrat extends CommonObject
 	public $fk_element='fk_contrat';
 	protected $ismultientitymanaged = 1;	// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
     public $picto='contract';
-    
+
 	/**
 	 * {@inheritdoc}
 	 */
@@ -530,7 +530,7 @@ class Contrat extends CommonObject
 				$this->fin_validite				= $this->db->jdate($result["fin_validite"]);
 				$this->date_cloture				= $this->db->jdate($result["date_cloture"]);
 
-				
+
 				$this->user_author_id			= $result["fk_user_author"];
 
 				$this->commercial_signature_id	= $result["fk_commercial_signature"];
@@ -613,7 +613,7 @@ class Contrat extends CommonObject
 
 		$this->lines=array();
         $pos = 0;
-		
+
 		// Selectionne les lignes contrats liees a un produit
 		$sql = "SELECT p.label as product_label, p.description as product_desc, p.ref as product_ref,";
 		$sql.= " d.rowid, d.fk_contrat, d.statut, d.description, d.price_ht, d.vat_src_code, d.tva_tx, d.localtax1_tx, d.localtax2_tx, d.localtax1_type, d.localtax2_type, d.qty, d.remise_percent, d.subprice, d.fk_product_fournisseur_price as fk_fournprice, d.buy_price_ht as pa_ht,";
@@ -1858,7 +1858,7 @@ class Contrat extends CommonObject
 		$url = DOL_URL_ROOT.'/contrat/card.php?id='.$this->id;
         $picto = 'contract';
         $label = '';
-        
+
         if ($user->rights->contrat->lire) {
             $label = '<u>'.$langs->trans("ShowContract").'</u>';
             $label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
@@ -1874,7 +1874,7 @@ class Contrat extends CommonObject
                 $label .= '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
             }
         }
-        
+
         $linkclose='';
         if (empty($notooltip) && $user->rights->contrat->lire)
         {
@@ -1890,7 +1890,7 @@ class Contrat extends CommonObject
 		$linkstart = '<a href="'.$url.'"';
 		$linkstart.=$linkclose.'>';
 		$linkend='</a>';
-		
+
 		if ($withpicto) $result.=($linkstart.img_object(($notooltip?'':$label), $picto, ($notooltip?'':'class="classfortooltip"'), 0, 0, $notooltip?0:1).$linkend);
 		if ($withpicto && $withpicto != 2) $result.=' ';
 		$result.=$linkstart.$this->ref.$linkend;
@@ -2225,7 +2225,11 @@ class Contrat extends CommonObject
 			$line->total_ht=90;
 			$line->total_ttc=107.64;	// 90 * 1.196
 			$line->total_tva=17.64;
-            if ($num_prods > 0)
+			$line->date_ouverture = dol_now() - 200000;
+			$line->date_ouverture_prevue = dol_now() - 500000;
+			$line->date_fin_validite = dol_now() + 500000;
+			$line->date_cloture = dol_now() - 100000;
+			if ($num_prods > 0)
             {
 				$prodid = mt_rand(1, $num_prods);
 				$line->fk_product=$prodids[$prodid];
@@ -2233,11 +2237,6 @@ class Contrat extends CommonObject
 			$this->lines[$xnbp]=$line;
 			$xnbp++;
 		}
-
-		$this->amount_ht      = $xnbp*100;
-		$this->total_ht       = $xnbp*100;
-		$this->total_tva      = $xnbp*19.6;
-		$this->total_ttc      = $xnbp*119.6;
 	}
 
 	/**
@@ -2750,6 +2749,8 @@ class ContratLigne extends CommonObjectLine
 		if (empty($this->total_ht)) $this->total_ht = 0;
 		if (empty($this->total_tva)) $this->total_tva = 0;
 		if (empty($this->total_ttc)) $this->total_ttc = 0;
+		if (empty($this->localtax1_tx)) $this->localtax1_tx = 0;
+		if (empty($this->localtax2_tx)) $this->localtax2_tx = 0;
 
 		// Check parameters
 		// Put here code to add control on parameters values
diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php
index 92d1011b92350f3c97313402984a5e871b9bd44c..fde828fd6d498af48327111ebe4a2b3d6d591eef 100644
--- a/htdocs/core/actions_massactions.inc.php
+++ b/htdocs/core/actions_massactions.inc.php
@@ -24,20 +24,22 @@
 
 // $massaction must be defined
 // $objectclass and $$objectlabel must be defined
-// $uploaddir (example $conf->projet->dir_output . "/";)
+// $parameters, $object, $action must be defined for the hook.
+
+// $uploaddir may be defined (example to $conf->projet->dir_output."/";)
 // $toselect may be defined
 
 
 // Protection
-if (empty($objectclass) || empty($uploaddir)) 
+if (empty($objectclass) || empty($uploaddir))
 {
     dol_print_error(null, 'include of actions_massactions.inc.php is done but var $massaction or $objectclass or $uploaddir was not defined');
     exit;
 }
 
 
-// Mass actions. Controls on number of lines checked
-$maxformassaction=1000;
+// Mass actions. Controls on number of lines checked.
+$maxformassaction=(empty($conf->global->MAIN_LIMIT_FOR_MASS_ACTIONS)?1000:$conf->global->MAIN_LIMIT_FOR_MASS_ACTIONS);
 if (! empty($massaction) && count($toselect) < 1)
 {
     $error++;
@@ -87,7 +89,7 @@ if (! $error && $massaction == 'confirm_presend')
             }
         }
         //var_dump($listofobjectthirdparties);exit;
-        	
+
         foreach ($listofobjectthirdparties as $thirdpartyid)
         {
             $result = $thirdparty->fetch($thirdpartyid);
@@ -144,7 +146,7 @@ if (! $error && $massaction == 'confirm_presend')
             {
                 //var_dump($object);
                 //var_dump($thirdpartyid.' - '.$objectid.' - '.$object->statut);
-                	
+
                 if ($objectclass == 'Facture' && $object->statut != Facture::STATUS_VALIDATED)
                 {
                     $nbignored++;
@@ -157,7 +159,7 @@ if (! $error && $massaction == 'confirm_presend')
                     $resaction.='<div class="error">'.$langs->trans('ErrorOnlyOrderNotDraftCanBeSentInMassAction',$object->ref).'</div><br>';
                     continue;
                 }
-                
+
                 // Read document
                 // TODO Use future field $object->fullpathdoc to know where is stored default file
                 // TODO If not defined, use $object->modelpdf (or defaut invoice config) to know what is template to use to regenerate doc.
@@ -202,7 +204,7 @@ if (! $error && $massaction == 'confirm_presend')
                     dol_syslog('Failed to read file: '.$file, LOG_WARNING);
                     continue;
                 }
-                	
+
                 //var_dump($listofqualifiedref);
             }
 
@@ -252,9 +254,9 @@ if (! $error && $massaction == 'confirm_presend')
                 $filepath = $attachedfiles['paths'];
                 $filename = $attachedfiles['names'];
                 $mimetype = $attachedfiles['mimes'];
-                	
+
                 //var_dump($filepath);
-                	
+
                 // Send mail
                 require_once(DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php');
                 $mailfile = new CMailFile($subject,$sendto,$from,$message,$filepath,$mimetype,$filename,$sendtocc,$sendtobcc,$deliveryreceipt,-1);
@@ -280,7 +282,7 @@ if (! $error && $massaction == 'confirm_presend')
                             if ($objectclass == 'Supplier_Proposal') $actiontypecode='AC_SUP_PRO';
                             if ($objectclass == 'CommandeFournisseur') $actiontypecode='AC_SUP_ORD';
                             if ($objectclass == 'FactureFournisseur') $actiontypecode='AC_SUP_INV';*/
-                            
+
                             $actionmsg=$langs->transnoentities('MailSentBy').' '.$from.' '.$langs->transnoentities('To').' '.$sendto;
                             if ($message)
                             {
@@ -290,7 +292,7 @@ if (! $error && $massaction == 'confirm_presend')
                                 $actionmsg = dol_concatdesc($actionmsg, $message);
                             }
                             $actionmsg2='';
-                            
+
                             // Initialisation donnees
                             $object->sendtoid		= 0;
                             $object->actionmsg		= $actionmsg;  // Long text
@@ -335,7 +337,7 @@ if (! $error && $massaction == 'confirm_presend')
         $resaction.=$langs->trans("NbSelected").': '.count($toselect)."\n<br>";
         $resaction.=$langs->trans("NbIgnored").': '.($nbignored?$nbignored:0)."\n<br>";
         $resaction.=$langs->trans("NbSent").': '.($nbsent?$nbsent:0)."\n<br>";
-        	
+
         if ($nbsent)
         {
             $action='';	// Do not show form post if there was at least one successfull sent
@@ -359,7 +361,7 @@ if (! $error && $massaction == "builddoc" && $permtoread && ! GETPOST('button_se
     require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
     require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
     require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
-     
+
     $objecttmp=new $objectclass($db);
     $listofobjectid=array();
     $listofobjectthirdparties=array();
@@ -425,21 +427,21 @@ if (! $error && $massaction == "builddoc" && $permtoread && ! GETPOST('button_se
 
     	if (count($files)>0)
     	{
-    	
+
     		$now=dol_now();
     		$file=$diroutputmassaction.'/'.$filename.'_'.dol_print_date($now,'dayhourlog').'.pdf';
-    		
+
     		$input_files = '';
     		foreach($files as $f) {
     			$input_files.=' '.escapeshellarg($f);
     		}
-    		
+
     		$cmd = 'pdftk '.$input_files.' cat output '.escapeshellarg($file);
     		exec($cmd);
-    		
+
     		if (! empty($conf->global->MAIN_UMASK))
     			@chmod($file, octdec($conf->global->MAIN_UMASK));
-    			
+
     			$langs->load("exports");
     			setEventMessages($langs->trans('FileSuccessfullyBuilt',$filename.'_'.dol_print_date($now,'dayhourlog')), null, 'mesgs');
     	}
@@ -447,7 +449,7 @@ if (! $error && $massaction == "builddoc" && $permtoread && ! GETPOST('button_se
     	{
     		setEventMessages($langs->trans('NoPDFAvailableForDocGenAmongChecked'), null, 'errors');
     	}
-    	
+
     }
     else {
 	    // Create empty PDF
@@ -481,7 +483,7 @@ if (! $error && $massaction == "builddoc" && $permtoread && ! GETPOST('button_se
 	    // Defined name of merged file
 	    $filename=strtolower(dol_sanitizeFileName($langs->transnoentities($objectlabel)));
 	    $filename=preg_replace('/\s/','_',$filename);
-	    
+
 	    // Save merged file
 	    if ($filter=='paye:0')
 	    {
@@ -565,6 +567,11 @@ if (! $error && $massaction == 'delete' && $permtodelete)
     //var_dump($listofobjectthirdparties);exit;
 }
 
+$parameters['toselect']=$toselect;
+$parameters['uploaddir']=$uploaddir;
+
+$reshook=$hookmanager->executeHooks('doMassActions',$parameters, $object, $action);    // Note that $action and $object may have been modified by some hooks
+if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
 
 
 
diff --git a/htdocs/core/actions_setmoduleoptions.inc.php b/htdocs/core/actions_setmoduleoptions.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..03b33b19eb1d525d3da78db44c196cb4804b3be3
--- /dev/null
+++ b/htdocs/core/actions_setmoduleoptions.inc.php
@@ -0,0 +1,86 @@
+<?php
+/* Copyright (C) 2014 Laurent Destailleur  <eldy@users.sourceforge.net>
+ *
+ * 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
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * or see http://www.gnu.org/
+ */
+
+/**
+ *	\file			htdocs/core/actions_setnotes.inc.php
+ *  \brief			Code for actions on setting notes of object page
+ */
+
+
+// $action must be defined
+// $_FILES may be defined
+// $nomessageinsetmoduleoptions can be set to 1
+
+// Define constants for submodules that contains parameters (forms with param1, param2, ... and value1, value2, ...)
+if ($action == 'setModuleOptions')
+{
+    $db->begin();
+
+    // Process common param fields
+    foreach($_POST as $key => $val)
+    {
+        if (preg_match('/^param(\d*)$/', $key, $reg))    // Works for POST['param'], POST['param1'], POST['param2'], ...
+        {
+            $param=GETPOST("param".$reg[1],'alpha');
+            $value=GETPOST("value".$reg[1],'alpha');
+            if ($param)
+            {
+                $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity);
+                if (! $res > 0) $error++;
+            }
+        }
+    }
+
+    // Process upload fields
+    if (GETPOST('upload','alpha') && GETPOST('keyforuploaddir','aZ09'))
+    {
+        include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
+        $keyforuploaddir=GETPOST('keyforuploaddir','aZ09');
+        $listofdir=explode(',',preg_replace('/[\r\n]+/',',',trim($conf->global->$keyforuploaddir)));
+        foreach($listofdir as $key=>$tmpdir)
+        {
+            $tmpdir=trim($tmpdir);
+            $tmpdir=preg_replace('/DOL_DATA_ROOT/',DOL_DATA_ROOT,$tmpdir);
+            if (! $tmpdir) {
+                unset($listofdir[$key]); continue;
+            }
+            if (! is_dir($tmpdir)) $texttitle.=img_warning($langs->trans("ErrorDirNotFound",$tmpdir),0);
+            else
+            {
+                $upload_dir=$tmpdir;
+            }
+        }
+        if ($upload_dir)
+        {
+            $result = dol_add_file_process($upload_dir, 0, 1, 'uploadfile', '');
+            if ($result <= 0) $error++;
+        }
+    }
+
+    if (! $error)
+    {
+        $db->commit();
+        if (empty($nomessageinsetmoduleoptions)) setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
+    }
+    else
+    {
+        $db->rollback();
+        if (empty($nomessageinsetmoduleoptions)) setEventMessages($langs->trans("SetupNotSaved"), null, 'errors');
+    }
+}
+
diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php
index c89fc5937454e99385edaf59b0c77b3aaad9e1b2..bd1daca8886a7d042dde3dc556060d87dd865851 100644
--- a/htdocs/core/class/extrafields.class.php
+++ b/htdocs/core/class/extrafields.class.php
@@ -1681,7 +1681,7 @@ class ExtraFields
 					// Clean parameters
 					$value_key=dol_mktime($_POST[$keysuffix."options_".$key.$keyprefix."hour"], $_POST[$keysuffix."options_".$key.$keyprefix."min"], 0, $_POST[$keysuffix."options_".$key.$keyprefix."month"], $_POST[$keysuffix."options_".$key.$keyprefix."day"], $_POST[$keysuffix."options_".$key.$keyprefix."year"]);
 				}
-				else if (in_array($key_type,array('checkbox')))
+				else if (in_array($key_type,array('checkbox', 'chkbxlst')))
 				{
 					$value_arr=GETPOST($keysuffix."options_".$key.$keyprefix);
 					// Make sure we get an array even if there's only one checkbox
diff --git a/htdocs/core/class/hookmanager.class.php b/htdocs/core/class/hookmanager.class.php
index 590f806029666983d9efd24dff7ca8bc54ce3fd6..40ed41530608e1f68f9654a89cd98502fb5186b0 100644
--- a/htdocs/core/class/hookmanager.class.php
+++ b/htdocs/core/class/hookmanager.class.php
@@ -133,11 +133,14 @@ class HookManager
 		if (in_array(
 			$method,
 			array(
-				'addMoreActionsButtons',
+                'addCalendarChoice',
+			    'addMoreActionsButtons',
+			    'addMoreMassActions',
 			    'addSearchEntry',
 				'addStatisticLine',
-				'deleteFile',
+			    'deleteFile',
 				'doActions',
+			    'doMassActions',
 				'formCreateThirdpartyOptions',
 				'formObjectOptions',
 				'formattachOptions',
@@ -169,7 +172,6 @@ class HookManager
 				'printSearchForm',
 				'printTabsHead',
 				'formatEvent',
-                'addCalendarChoice',
                 'printObjectLine',
                 'printObjectSubLine',
 				'createDictionaryFieldList',
@@ -181,14 +183,16 @@ class HookManager
 
         if ($method == 'insertExtraFields')
         {
-        	$hooktype='returnvalue';	// deprecated. TODO Remove all code with "executeHooks('insertExtraFields'" as soon as there is a trigger available.
+        	$hooktype='returnvalue';	// @deprecated. TODO Remove all code with "executeHooks('insertExtraFields'" as soon as there is a trigger available.
         	dol_syslog("Warning: The hook 'insertExtraFields' is deprecated and must not be used. Use instead trigger on CRUD event (ask it to dev team if not implemented)", LOG_WARNING);
         }
 
+        // Init return properties
+        $this->resPrint=''; $this->resArray=array();
+
         // Loop on each hook to qualify modules that have declared context
         $modulealreadyexecuted=array();
         $resaction=0; $error=0; $result='';
-		$this->resPrint=''; $this->resArray=array();
         foreach($this->hooks as $context => $modules)    // $this->hooks is an array with context as key and value is an array of modules that handle this context
         {
             if (! empty($modules))
@@ -202,9 +206,9 @@ class HookManager
 
                     // test to avoid running twice a hook, when a module implements several active contexts
                     if (in_array($module,$modulealreadyexecuted)) continue;
-                    
+
                     dol_syslog(get_class($this).'::executeHooks a qualified hook was found for method='.$method.' module='.$module." action=".$action." context=".$context);
-                    
+
                     $modulealreadyexecuted[$module]=$module; // Use the $currentcontext in method to avoid running twice
 
                     // Clean class (an error may have been set from a previous call of another method for same module/hook)
diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php
index cf6ae18f568e3c1d318f3b0da737b9219bc58998..b14f72a1b7bb5c011dcf5a22c82625b44f9eadc3 100644
--- a/htdocs/core/class/html.form.class.php
+++ b/htdocs/core/class/html.form.class.php
@@ -545,11 +545,20 @@ class Form
     	$disabled=0;
     	$ret='<div class="centpercent center">';
     	$ret.='<select data-role="none" class="flat'.(empty($conf->use_javascript_ajax)?'':' hideobject').' massaction massactionselect" name="massaction"'.($disabled?' disabled="disabled"':'').'>';
-    	$ret.='<option value="0"'.($disabled?' disabled="disabled"':'').'>-- '.$langs->trans("SelectAction").' --</option>';
-    	foreach($arrayofaction as $code => $label)
-    	{
-    		$ret.='<option value="'.$code.'"'.($disabled?' disabled="disabled"':'').'>'.$label.'</option>';
-    	}
+
+        // Complete list with data from external modules. THe module can use $_SERVER['PHP_SELF'] to know on which page we are, or use the $parameters['currentcontext'] completed by executeHooks.
+    	$parameters=array();
+    	$reshook=$hookmanager->executeHooks('addMoreMassActions',$parameters);    // Note that $action and $object may have been modified by hook
+        if (empty($reshook))
+        {
+        	$ret.='<option value="0"'.($disabled?' disabled="disabled"':'').'>-- '.$langs->trans("SelectAction").' --</option>';
+        	foreach($arrayofaction as $code => $label)
+        	{
+        		$ret.='<option value="'.$code.'"'.($disabled?' disabled="disabled"':'').'>'.$label.'</option>';
+        	}
+        }
+        $ret.=$hookmanager->resPrint;
+
     	$ret.='</select>';
     	// Warning: if you set submit button to disabled, post using 'Enter' will no more work.
     	$ret.='<input type="submit" data-role="none" name="confirmmassaction" class="button'.(empty($conf->use_javascript_ajax)?'':' hideobject').' massaction massactionconfirmed" value="'.dol_escape_htmltag($langs->trans("Confirm")).'">';
@@ -1391,7 +1400,7 @@ class Form
      *  @deprecated
      *  @see select_dolusers()
      */
-    function select_users($selected='',$htmlname='userid',$show_empty=0,$exclude='',$disabled=0,$include='',$enableonly='',$force_entity=0)
+    function select_users($selected='',$htmlname='userid',$show_empty=0,$exclude=null,$disabled=0,$include='',$enableonly='',$force_entity=0)
     {
         print $this->select_dolusers($selected,$htmlname,$show_empty,$exclude,$disabled,$include,$enableonly,$force_entity);
     }
@@ -1411,13 +1420,13 @@ class Form
      *  @param	int		$showstatus		0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status
      *  @param	string	$morefilter		Add more filters into sql request
      *  @param	integer	$show_every		0=default list, 1=add also a value "Everybody" at beginning of list
-     *  @param	string	$enableonlytext	If option $enableonly is set, we use this text to explain into label why record is disabled. Not used if enableonly is empty.
+     *  @param	string	$enableonlytext	If option $enableonlytext is set, we use this text to explain into label why record is disabled. Not used if enableonly is empty.
      *  @param	string	$morecss		More css
      *  @param  int     $noactive       Show only active users (this will also happened whatever is this option if USER_HIDE_INACTIVE_IN_COMBOBOX is on).
      * 	@return	string					HTML select string
      *  @see select_dolgroups
      */
-    function select_dolusers($selected='', $htmlname='userid', $show_empty=0, $exclude='', $disabled=0, $include='', $enableonly='', $force_entity=0, $maxlength=0, $showstatus=0, $morefilter='', $show_every=0, $enableonlytext='', $morecss='', $noactive=0)
+    function select_dolusers($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity=0, $maxlength=0, $showstatus=0, $morefilter='', $show_every=0, $enableonlytext='', $morecss='', $noactive=0)
     {
         global $conf,$user,$langs;
 
@@ -1613,7 +1622,7 @@ class Form
      * 	@return	string					HTML select string
      *  @see select_dolgroups
      */
-    function select_dolusers_forevent($action='', $htmlname='userid', $show_empty=0, $exclude='', $disabled=0, $include='', $enableonly='', $force_entity=0, $maxlength=0, $showstatus=0, $morefilter='')
+    function select_dolusers_forevent($action='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity=0, $maxlength=0, $showstatus=0, $morefilter='')
     {
         global $conf,$user,$langs;
 
diff --git a/htdocs/core/class/html.formcompany.class.php b/htdocs/core/class/html.formcompany.class.php
index bcff0981a70627c96d949350a7b797f08fbb212b..88ebb816a315b0613a071cea750cbaf9e9927efd 100644
--- a/htdocs/core/class/html.formcompany.class.php
+++ b/htdocs/core/class/html.formcompany.class.php
@@ -358,7 +358,7 @@ class FormCompany
 	 *
 	 *  @param  string	$selected   	Title preselected
 	 * 	@param	string	$htmlname		Name of HTML select combo field
-	 *  @param  string  $morecss        Add more css on SELECT element      
+	 *  @param  string  $morecss        Add more css on SELECT element
 	 *  @return	string					String with HTML select
 	 */
 	function select_civility($selected='',$htmlname='civility_id',$morecss='maxwidth100')
@@ -563,11 +563,11 @@ class FormCompany
 			$events=array();
 			// Add an entry 'method' to say 'yes, we must execute url with param action = method';
 			// Add an entry 'url' to say which url to execute
-			// Add an entry htmlname to say which element we must change once url is called 
-			// Add entry params => array('cssid' => 'attr') to say to remov or add attribute attr if answer of url return  0 or >0 lines 
+			// Add an entry htmlname to say which element we must change once url is called
+			// Add entry params => array('cssid' => 'attr') to say to remov or add attribute attr if answer of url return  0 or >0 lines
 			// To refresh contacts list on thirdparty list change
 			$events[]=array('method' => 'getContacts', 'url' => dol_buildpath('/core/ajax/contacts.php',1), 'htmlname' => 'contactid', 'params' => array('add-customer-contact' => 'disabled'));
-			
+
 			if (count($events))	// If there is some ajax events to run once selection is done, we add code here to run events
 			{
 				print '<script type="text/javascript">
@@ -583,7 +583,7 @@ class FormCompany
 						/* Clean contact */
 						$("div#s2id_contactid>a>span").html(\'\');
 					});
-								    
+
 					// Function used to execute events when search_htmlname change
 					function runJsCodeForEvent'.$htmlname.'(obj) {
 						var id = $("#'.$htmlname.'").val();
@@ -693,16 +693,17 @@ class FormCompany
      *  @param  string		$source			Source ('internal' or 'external')
      *  @param  string		$sortorder		Sort criteria ('position', 'code', ...)
      *  @param  int			$showempty      1=Add en empty line
+     *  @param  string      $morecss        Add more css to select component
      *  @return	void
      */
-	function selectTypeContact($object, $selected, $htmlname = 'type', $source='internal', $sortorder='position', $showempty=0)
+	function selectTypeContact($object, $selected, $htmlname = 'type', $source='internal', $sortorder='position', $showempty=0, $morecss='')
 	{
 	    global $user, $langs;
-	    
+
 		if (is_object($object) && method_exists($object, 'liste_type_contact'))
 		{
 			$lesTypes = $object->liste_type_contact($source, $sortorder, 0, 1);
-			print '<select class="flat valignmiddle" name="'.$htmlname.'" id="'.$htmlname.'">';
+			print '<select class="flat valignmiddle'.($morecss?' '.$morecss:'').'" name="'.$htmlname.'" id="'.$htmlname.'">';
 			if ($showempty) print '<option value="0"></option>';
 			foreach($lesTypes as $key=>$value)
 			{
@@ -791,7 +792,7 @@ class FormCompany
 
         $maxlength=$formlength;
         if (empty($formlength)) { $formlength=24; $maxlength=128; }
-        
+
         $out = '<input type="text" '.($morecss?'class="'.$morecss.'" ':'').'name="'.$htmlname.'" id="'.$htmlname.'" maxlength="'.$maxlength.'" value="'.$selected.'">';
 
         return $out;
diff --git a/htdocs/core/class/html.formprojet.class.php b/htdocs/core/class/html.formprojet.class.php
index 304814971634777b66bd2644cb7dc6a08f7210c8..93ebbf71ddd18b4c32e713154656684891fac100 100644
--- a/htdocs/core/class/html.formprojet.class.php
+++ b/htdocs/core/class/html.formprojet.class.php
@@ -68,7 +68,7 @@ class FormProjets
 		global $langs,$conf,$form;
 
 		$out='';
-		
+
 		if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->PROJECT_USE_SEARCH_TO_SELECT))
 		{
 			$placeholder='';
@@ -92,7 +92,7 @@ class FormProjets
 		else
 		{
 			$out.=$this->select_projects_list($socid, $selected, $htmlname, $maxlength, $option_only, $show_empty, $discard_closed, $forcefocus, $disabled, 0, $filterkey, 1, $forceaddid, $htmlid);
-			if ($discard_closed) 
+			if ($discard_closed)
 			{
 			    if (class_exists('Form'))
 			    {
@@ -101,8 +101,8 @@ class FormProjets
 			    }
 			}
 		}
-		
-		if (empty($nooutput)) 
+
+		if (empty($nooutput))
 		{
 		    print $out;
 		    return '';
@@ -136,10 +136,10 @@ class FormProjets
 		require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
 
 		if (empty($htmlid)) $htmlid = $htmlname;
-		
+
 		$out='';
         $outarray=array();
-        
+
 		$hideunselectables = false;
 		if (! empty($conf->global->PROJECT_HIDE_UNSELECTABLES)) $hideunselectables = true;
 
@@ -170,21 +170,19 @@ class FormProjets
 		$resql=$this->db->query($sql);
 		if ($resql)
 		{
-			$minmax='maxwidth500';
+			$morecss='maxwidth500';
 
 			// Use select2 selector
-			$nodatarole='';
 			if (! empty($conf->use_javascript_ajax))
 			{
 				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
 	           	$comboenhancement = ajax_combobox($htmlid, array(), 0, $forcefocus);
             	$out.=$comboenhancement;
-            	$nodatarole=($comboenhancement?' data-role="none"':'');
-            	$minmax='minwidth100 maxwidth300';
+            	$morecss='minwidth100 maxwidth300';
 			}
 
 			if (empty($option_only)) {
-				$out.= '<select class="flat'.($minmax?' '.$minmax:'').'"'.($disabled?' disabled="disabled"':'').' id="'.$htmlid.'" name="'.$htmlname.'"'.$nodatarole.'>';
+				$out.= '<select class="flat'.($morecss?' '.$morecss:'').'"'.($disabled?' disabled="disabled"':'').' id="'.$htmlid.'" name="'.$htmlname.'">';
 			}
 			if (!empty($show_empty)) {
 				$out.= '<option value="0">&nbsp;</option>';
@@ -213,12 +211,12 @@ class FormProjets
 						//if ($obj->public) $labeltoshow.=' ('.$langs->trans("SharedProject").')';
 						//else $labeltoshow.=' ('.$langs->trans("Private").')';
 						$labeltoshow.=', '.dol_trunc($obj->title, $maxlength);
-						if ($obj->name) 
+						if ($obj->name)
 						{
 						    $labeltoshow.=' - '.$obj->name;
 						    if ($obj->name_alias) $labeltoshow.=' ('.$obj->name_alias.')';
 						}
-						
+
 						$disabled=0;
 						if ($obj->fk_statut == 0)
 						{
@@ -277,7 +275,7 @@ class FormProjets
 
 			if (!$mode) {
 				if (empty($option_only)) $out.= '</select>';
-				if (empty($nooutput)) 
+				if (empty($nooutput))
 				{
 				    print $out;
 				    return '';
@@ -302,13 +300,14 @@ class FormProjets
 	 *	@param  string	$htmlname   	Name of HTML select
 	 *	@param	int		$maxlength		Maximum length of label
 	 *	@param	int		$option_only	Return only html options lines without the select tag
-	 *	@param	int		$show_empty		Add an empty line
+	 *	@param	string	$show_empty		Add an empty line ('1' or string to show for empty line)
 	 *  @param	int		$discard_closed Discard closed projects (0=Keep,1=hide completely,2=Disable)
      *  @param	int		$forcefocus		Force focus on field (works with javascript only)
      *  @param	int		$disabled		Disabled
+	 *  @param	string	$morecss        More css added to the select component
 	 *	@return int         			Nbr of project if OK, <0 if KO
 	 */
-	function selectTasks($socid=-1, $selected='', $htmlname='taskid', $maxlength=24, $option_only=0, $show_empty=1, $discard_closed=0, $forcefocus=0, $disabled=0)
+	function selectTasks($socid=-1, $selected='', $htmlname='taskid', $maxlength=24, $option_only=0, $show_empty='1', $discard_closed=0, $forcefocus=0, $disabled=0, $morecss='maxwidth500')
 	{
 		global $user,$conf,$langs;
 
@@ -339,28 +338,26 @@ class FormProjets
 		if ($socid > 0)  $sql.= " AND (p.fk_soc=".$socid." OR p.fk_soc IS NULL)";
 		$sql.= " ORDER BY p.ref, t.ref ASC";
 
-		dol_syslog(__METHOD__, LOG_DEBUG);
 		$resql=$this->db->query($sql);
 		if ($resql)
 		{
-			$minmax='maxwidth500';
-
 			// Use select2 selector
-			$nodatarole='';
 			if (! empty($conf->use_javascript_ajax))
 			{
 				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
 	           	$comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus);
             	$out.=$comboenhancement;
-            	$nodatarole=($comboenhancement?' data-role="none"':'');
-            	$minmax='minwidth200 maxwidth500';
+            	$morecss='minwidth200 maxwidth500';
 			}
 
 			if (empty($option_only)) {
-				$out.= '<select class="valignmiddle flat'.($minmax?' '.$minmax:'').'"'.($disabled?' disabled="disabled"':'').' id="'.$htmlname.'" name="'.$htmlname.'"'.$nodatarole.'>';
+				$out.= '<select class="valignmiddle flat'.($morecss?' '.$morecss:'').'"'.($disabled?' disabled="disabled"':'').' id="'.$htmlname.'" name="'.$htmlname.'">';
 			}
-			if (!empty($show_empty)) {
-				$out.= '<option value="0">&nbsp;</option>';
+			if (! empty($show_empty)) {
+				$out.= '<option value="0" class="optiongrey">';
+				if (! is_numeric($show_empty)) $out.=$show_empty;
+				else $out.='&nbsp;';
+				$out.= '</option>';
 			}
 			$num = $this->db->num_rows($resql);
 			$i = 0;
@@ -370,7 +367,7 @@ class FormProjets
 				{
 					$obj = $this->db->fetch_object($resql);
 					// If we ask to filter on a company and user has no permission to see all companies and project is linked to another company, we hide project.
-					if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && ! $user->rights->societe->lire)
+					if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && empty($user->rights->societe->lire))
 					{
 						// Do nothing
 					}
@@ -382,7 +379,7 @@ class FormProjets
 							continue;
 						}
 
-						$labeltoshow=dol_trunc($obj->ref,18);
+						$labeltoshow=dol_trunc($obj->ref,18);     // Project ref
 						//if ($obj->public) $labeltoshow.=' ('.$langs->trans("SharedProject").')';
 						//else $labeltoshow.=' ('.$langs->trans("Private").')';
 						$labeltoshow.=' '.dol_trunc($obj->title,$maxlength);
@@ -532,7 +529,6 @@ class FormProjets
 		$sql.= " ORDER BY ref DESC";
 
 		dol_syslog(get_class($this).'::select_element', LOG_DEBUG);
-
 		$resql=$this->db->query($sql);
 		if ($resql)
 		{
diff --git a/htdocs/core/class/interfaces.class.php b/htdocs/core/class/interfaces.class.php
index cd4a56f417430022266ffd8082af923ecb86acf1..625b30e3ac22a4fbcdbcbdd497aa14fd85a63124 100644
--- a/htdocs/core/class/interfaces.class.php
+++ b/htdocs/core/class/interfaces.class.php
@@ -76,14 +76,14 @@ class Interfaces
             global $db;
             $user = new User($db);
         }
-        
+
         $nbfile = $nbtotal = $nbok = $nbko = 0;
 
         $files = array();
         $modules = array();
         $orders = array();
 		$i=0;
-		
+
 		$dirtriggers=array_merge(array('/core/triggers'),$conf->modules_parts['triggers']);
         foreach($dirtriggers as $reldir)
         {
@@ -106,7 +106,7 @@ class Interfaces
 						$part3=$reg[3];
 
                         $nbfile++;
-                        
+
                         // Check if trigger file is disabled by name
                         if (preg_match('/NORUN$/i',$file)) continue;
                         // Check if trigger file is for a particular module
@@ -132,7 +132,7 @@ class Interfaces
                             dol_syslog(get_class($this)."::run_triggers action=".$action." ".$langs->trans("ErrorDuplicateTrigger", $newdir."/".$file, $fullpathfiles[$modName]), LOG_WARNING);
                             continue;
                         }
-                        
+
                         try {
                             //print 'Todo for '.$modName." : ".$newdir.'/'.$file."\n";
                             include_once $newdir.'/'.$file;
@@ -142,7 +142,7 @@ class Interfaces
                         {
                             dol_syslog('ko for '.$modName." ".$e->getMessage()."\n", LOG_ERR);
                         }
-                        
+
                         $modules[$i] = $modName;
                         $files[$i] = $file;
                         $fullpathfiles[$modName] = $newdir.'/'.$file;
@@ -155,7 +155,7 @@ class Interfaces
         }
 
         asort($orders);
-        
+
         // Loop on each trigger
         foreach ($orders as $key => $value)
         {
@@ -246,7 +246,7 @@ class Interfaces
         {
         	$dirtriggers=$forcedirtriggers;
         }
-        	
+
         foreach($dirtriggers as $reldir)
         {
             $dir=dol_buildpath($reldir,0);
diff --git a/htdocs/core/js/timesheet.js b/htdocs/core/js/timesheet.js
index ea0e07827677cafa31a268f1a3ac359a928fd945..5541f348c9fb6699f1aaec0f4e6e2ae3f7d5e250 100644
--- a/htdocs/core/js/timesheet.js
+++ b/htdocs/core/js/timesheet.js
@@ -1,5 +1,5 @@
-/* Copyright (C) 2014 delcroip <delcroip@gmail.com>
- * Laurent Destailleur 2015 <eldy@users.sourceforge.net>
+/* Copyright (C) 2014      delcroip            <delcroip@gmail.com>
+ * Copyright (C) 2015-2017 Laurent Destailleur <eldy@users.sourceforge.net>
  *
  * 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
diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php
index 95fca68aa5d0ab91b6321e677e6a8d29541362b1..85aace9db0b4a597a09bd4afc1140b68e0640bc4 100644
--- a/htdocs/core/lib/files.lib.php
+++ b/htdocs/core/lib/files.lib.php
@@ -44,7 +44,7 @@ function dol_basename($pathfile)
  *  @param	string		$path        	Starting path from which to search. This is a full path.
  *  @param	string		$types        	Can be "directories", "files", or "all"
  *  @param	int			$recursive		Determines whether subdirectories are searched
- *  @param	string		$filter        	Regex filter to restrict list. This regex value must be escaped for '/' by doing preg_quote($var,'/'), since this char is used for preg_match function, 
+ *  @param	string		$filter        	Regex filter to restrict list. This regex value must be escaped for '/' by doing preg_quote($var,'/'), since this char is used for preg_match function,
  *                                      but must not contains the start and end '/'. Filter is checked into basename only.
  *  @param	array		$excludefilter  Array of Regex for exclude filter (example: array('(\.meta|_preview.*\.png)$','^\.')). Exclude is checked into fullpath.
  *  @param	string		$sortcriteria	Sort criteria ("","fullname","name","date","size")
@@ -71,9 +71,9 @@ function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefil
 
 	$reshook = 0;
 	$file_list = array();
-	
+
 	$hookmanager->resArray=array();
-	
+
 	if (! $nohook)
 	{
 		$hookmanager->initHooks(array('fileslib'));
@@ -196,9 +196,9 @@ function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefil
 			}
 		}
 	}
-	
+
 	$file_list = array_merge($file_list, $hookmanager->resArray);
-	
+
 	return $file_list;
 }
 
@@ -219,7 +219,7 @@ function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefil
 function dol_dir_list_in_database($path, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0)
 {
     global $conf, $db;
-    
+
     $sql=" SELECT rowid, label, entity, filename, filepath, fullpath_orig, keywords, cover, gen_or_uploaded, extraparams, date_c, date_m, fk_user_c, fk_user_m, acl, position";
     if ($mode) $sql.=", description";
     $sql.=" FROM ".MAIN_DB_PREFIX."ecm_files";
@@ -234,7 +234,7 @@ function dol_dir_list_in_database($path, $filter="", $excludefilter=null, $sortc
         $i = 0;
         while ($i < $num)
         {
-            $obj = $db->fetch_object($resql);            
+            $obj = $db->fetch_object($resql);
             if ($obj)
             {
                 preg_match('/([^\/]+)\/[^\/]+$/',DOL_DATA_ROOT.'/'.$obj->filepath.'/'.$obj->filename,$reg);
@@ -258,7 +258,7 @@ function dol_dir_list_in_database($path, $filter="", $excludefilter=null, $sortc
             }
             $i++;
         }
-        
+
         // Obtain a list of columns
         if (! empty($sortcriteria))
         {
@@ -270,7 +270,7 @@ function dol_dir_list_in_database($path, $filter="", $excludefilter=null, $sortc
             // Sort the data
             if ($sortorder) array_multisort($myarray, $sortorder, $file_list);
         }
-        
+
         return $file_list;
     }
     else
@@ -279,7 +279,7 @@ function dol_dir_list_in_database($path, $filter="", $excludefilter=null, $sortc
         return array();
     }
 }
-    
+
 
 /**
  * Fast compare of 2 files identified by their properties ->name, ->date and ->size
@@ -460,10 +460,10 @@ function dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask=0,
 
     if (empty($srcfile)) return -1;
     if (empty($destfile)) $destfile=$srcfile;
-    
+
     $destexists=dol_is_file($destfile);
     if (($destfile != $srcfile) && $destexists) return 0;
-    
+
     $tmpdestfile=$destfile.'.tmp';
 
     $newpathofsrcfile=dol_osencode($srcfile);
@@ -481,17 +481,17 @@ function dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask=0,
         dol_syslog("files.lib.php::dolReplaceInFile failed Permission denied to write into target directory ".$newdirdestfile, LOG_WARNING);
         return -2;
     }
-   
+
     dol_delete_file($tmpdestfile);
-    
+
     // Create $newpathoftmpdestfile from $newpathofsrcfile
     $content=file_get_contents($newpathofsrcfile, 'r');
-    
+
     $content = make_substitutions($content, $arrayreplacement, null);
-    
+
     file_put_contents($newpathoftmpdestfile, $content);
     @chmod($newpathoftmpdestfile, octdec($newmask));
-    
+
     // Rename
     $result=dol_move($newpathoftmpdestfile, $newpathofdestfile, $newmask, (($destfile == $srcfile)?1:0), 0, $indexdatabase);
     if (! $result)
@@ -589,7 +589,7 @@ function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayrep
 
 	$destexists=dol_is_dir($destfile);
 	//if (! $overwriteifexists && $destexists) return 0;	// The overwriteifexists is for files only, so propagated to dol_copy only.
-    
+
     if (! $destexists)
     {
         // We must set mask just before creating dir, becaause it can be set differently by dol_copy
@@ -599,7 +599,7 @@ function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayrep
         $dirmaskdec |= octdec('0200');  // Set w bit required to be able to create content for recursive subdirs files
         dol_mkdir($destfile, '', decoct($dirmaskdec));
     }
-    
+
 	$ossrcfile=dol_osencode($srcfile);
 	$osdestfile=dol_osencode($destfile);
 
@@ -639,7 +639,7 @@ function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayrep
                     $result=$tmpresult;
                 }
                 if ($result < 0) break;
-                
+
             }
         }
         closedir($dir_handle);
@@ -656,10 +656,10 @@ function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayrep
 
 /**
  * Move a file into another name.
- * Note: 
+ * Note:
  *  - This function differs from dol_move_uploaded_file, because it can be called in any context.
  *  - Database of files is updated.
- *  - Test on antivirus is done only if param testvirus is provided and an antivirus was set. 
+ *  - Test on antivirus is done only if param testvirus is provided and an antivirus was set.
  *
  * @param	string  $srcfile            Source file (can't be a directory. use native php @rename() to move a directory)
  * @param   string	$destfile           Destination file (can't be a directory. use native php @rename() to move a directory)
@@ -679,12 +679,12 @@ function dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvi
     $srcexists=dol_is_file($srcfile);
     $destexists=dol_is_file($destfile);
 
-    if (! $srcexists) 
+    if (! $srcexists)
     {
         dol_syslog("files.lib.php::dol_move srcfile does not exists. we ignore the move request.");
         return false;
     }
-    
+
     if ($overwriteifexists || ! $destexists)
     {
         $newpathofsrcfile=dol_osencode($srcfile);
@@ -695,7 +695,7 @@ function dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvi
         if ($testvirus)
         {
             $testvirusarray=dolCheckVirus($newpathofsrcfile);
-            if (count($testvirusarray)) 
+            if (count($testvirusarray))
             {
                 dol_syslog("files.lib.php::dol_move canceled because a virus was found into source file. we ignore the move request.", LOG_WARNING);
                 return false;
@@ -729,14 +729,14 @@ function dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvi
 
                 dol_syslog("Try to rename also entries in database for full relative path before = ".$rel_filetorenamebefore." after = ".$rel_filetorenameafter, LOG_DEBUG);
                 include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
-                
+
                 $ecmfiletarget=new EcmFiles($db);
                 $resultecmtarget = $ecmfiletarget->fetch(0, '', $rel_filetorenameafter);
                 if ($resultecmtarget > 0)   // An entry for target name already exists for target, we delete it, a new one will be created.
                 {
                     $ecmfiletarget->delete($user);
                 }
-                
+
                 $ecmfile=new EcmFiles($db);
                 $resultecm = $ecmfile->fetch(0, '', $rel_filetorenamebefore);
                 if ($resultecm > 0)   // If an entry was found for src file, we use it to move entry
@@ -745,7 +745,7 @@ function dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvi
                     $rel_dir = dirname($rel_filetorenameafter);
                     $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
                     $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
-                    
+
                     $ecmfile->filepath = $rel_dir;
                     $ecmfile->filename = $filename;
                     $resultecm = $ecmfile->update($user);
@@ -756,7 +756,7 @@ function dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvi
                     $rel_dir = dirname($rel_filetorenameafter);
                     $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
                     $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
-                    	
+
                     $ecmfile->filepath = $rel_dir;
                     $ecmfile->filename = $filename;
                     $ecmfile->label = md5_file(dol_osencode($destfile));        // $destfile is a full path to file
@@ -774,12 +774,12 @@ function dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvi
                 {
                     setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
                 }
-                
+
                 if ($resultecm > 0) $result=true;
                 else $result = false;
-            }        
+            }
         }
-        
+
         if (empty($newmask)) $newmask=empty($conf->global->MAIN_UMASK)?'0755':$conf->global->MAIN_UMASK;
         $newmaskdec=octdec($newmask);
         // Currently method is restricted to files (dol_delete_files previously used is for files, and mask usage if for files too)
@@ -809,14 +809,14 @@ function dol_unescapefile($filename)
 
 /**
  * Check virus into a file
- * 
+ *
  * @param   string      $src_file       Source file to check
  * @return  array                       Array of errors or empty array if not virus found
  */
 function dolCheckVirus($src_file)
 {
     global $conf;
-    
+
     if (! empty($conf->global->MAIN_ANTIVIRUS_COMMAND))
     {
         if (! class_exists('AntiVir')) {
@@ -837,10 +837,10 @@ function dolCheckVirus($src_file)
 /**
  *	Make control on an uploaded file from an GUI page and move it to final destination.
  * 	If there is errors (virus found, antivir in error, bad filename), file is not moved.
- *  Note: 
+ *  Note:
  *  - This function can be used only into a HTML page context. Use dol_move if you are outside.
- *  - Database of files is not updated.
  *  - Test on antivirus is always done (if antivirus set).
+ *  - Database of files is NOT updated.
  *
  *	@param	string	$src_file			Source full path filename ($_FILES['field']['tmp_name'])
  *	@param	string	$dest_file			Target full path filename  ($_FILES['field']['name'])
@@ -867,7 +867,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable
 		$parameters=array('dest_file' => $dest_file, 'src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite);
 		$reshook=$hookmanager->executeHooks('moveUploadedFile', $parameters, $object);
 	}
-    
+
 	if (empty($reshook))
 	{
     	// If an upload error has been reported
@@ -897,7 +897,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable
     	            break;
     	    }
     	}
-    	
+
     	// If we need to make a virus scan
     	if (empty($disablevirusscan) && file_exists($src_file))
     	{
@@ -908,7 +908,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable
     	       return 'ErrorFileIsInfectedWithAVirus: '.join(',',$checkvirusarray);
     	    }
     	}
-    	
+
     	// Security:
     	// Disallow file with some extensions. We renamed them.
     	// Car si on a mis le rep documents dans un rep de la racine web (pas bien), cela permet d'executer du code a la demande.
@@ -916,7 +916,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable
     	{
     	    $file_name.= '.noexe';
     	}
-    	
+
     	// Security:
     	// We refuse cache files/dirs, upload using .. and pipes into filenames.
     	if (preg_match('/^\./',$src_file) || preg_match('/\.\./',$src_file) || preg_match('/[<>|]/',$src_file))
@@ -924,7 +924,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable
     	    dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
     	    return -1;
     	}
-    	
+
     	// Security:
     	// On interdit fichiers caches, remontees de repertoire ainsi que les pipe dans les noms de fichiers.
     	if (preg_match('/^\./',$dest_file) || preg_match('/\.\./',$dest_file) || preg_match('/[<>|]/',$dest_file))
@@ -933,7 +933,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable
     	    return -2;
     	}
 	}
-	
+
 	if ($reshook < 0)	// At least one blocking error returned by one hook
 	{
 		$errmsg = join(',', $hookmanager->errors);
@@ -1005,7 +1005,7 @@ function dol_delete_file($file,$disableglob=0,$nophperrors=0,$nohook=0,$object=n
         dol_syslog("Refused to delete file ".$file, LOG_WARNING);
 	    return False;
 	}
-	
+
 	if (empty($nohook))
 	{
 		$hookmanager->initHooks(array('fileslib'));
@@ -1042,16 +1042,16 @@ function dol_delete_file($file,$disableglob=0,$nophperrors=0,$nohook=0,$object=n
 				{
 					if ($nophperrors) $ok=@unlink($filename);
 					else $ok=unlink($filename);
-					if ($ok) 
+					if ($ok)
 					{
 					    dol_syslog("Removed file ".$filename, LOG_DEBUG);
-					    
+
 	                    // Delete entry into ecm database
     				    $rel_filetodelete = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $filename);
     				    if (! preg_match('/(\/temp\/|\/thumbs\/|\.meta$)/', $rel_filetodelete))     // If not a tmp file
     				    {
     				        $rel_filetodelete = preg_replace('/^[\\/]/', '', $rel_filetodelete);
-    				        
+
     				        dol_syslog("Try to remove also entries in database for full relative path = ".$rel_filetodelete, LOG_DEBUG);
         				    include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
         				    $ecmfile=new EcmFiles($db);
@@ -1079,7 +1079,7 @@ function dol_delete_file($file,$disableglob=0,$nophperrors=0,$nohook=0,$object=n
 			if ($nophperrors) $ok=@unlink($file_osencoded);
 			else $ok=unlink($file_osencoded);
 			if ($ok) dol_syslog("Removed file ".$file_osencoded, LOG_DEBUG);
-			else dol_syslog("Failed to remove file ".$file_osencoded, LOG_WARNING);      
+			else dol_syslog("Failed to remove file ".$file_osencoded, LOG_WARNING);
 		}
 
 		return $ok;
@@ -1104,7 +1104,7 @@ function dol_delete_dir($dir,$nophperrors=0)
         dol_syslog("Refused to delete dir ".$dir, LOG_WARNING);
 	    return False;
 	}
-	
+
     $dir_osencoded=dol_osencode($dir);
     return ($nophperrors?@rmdir($dir_osencoded):rmdir($dir_osencoded));
 }
@@ -1340,7 +1340,7 @@ function dol_add_file_process($upload_dir, $allowoverwrite=0, $donotupdatesessio
 	global $db,$user,$conf,$langs;
 
 	$res = 0;
-	
+
 	if (! empty($_FILES[$varfiles])) // For view $_FILES[$varfiles]['error']
 	{
 		dol_syslog('dol_add_file_process upload_dir='.$upload_dir.' allowoverwrite='.$allowoverwrite.' donotupdatesession='.$donotupdatesession.' savingdocmask='.$savingdocmask, LOG_DEBUG);
@@ -1354,17 +1354,17 @@ function dol_add_file_process($upload_dir, $allowoverwrite=0, $donotupdatesessio
 					$val = array($val);
 				}
 			}
-			
+
 			$nbfile = count($TFile['name']);
-			
+
 			for ($i = 0; $i < $nbfile; $i++)
 			{
 				// Define $destfull (path to file including filename) and $destfile (only filename)
 				$destfull=$upload_dir . "/" . $TFile['name'][$i];
 				$destfile=$TFile['name'][$i];
-	
+
 				$savingdocmask = dol_sanitizeFileName($savingdocmask);
-	
+
 				if ($savingdocmask)
 				{
 					$destfull=$upload_dir . "/" . preg_replace('/__file__/',$TFile['name'][$i],$savingdocmask);
@@ -1378,26 +1378,26 @@ function dol_add_file_process($upload_dir, $allowoverwrite=0, $donotupdatesessio
 				$destfile = $info['filename'].'.'.strtolower($info['extension']);
 
 				$resupload = dol_move_uploaded_file($TFile['tmp_name'][$i], $destfull, $allowoverwrite, 0, $TFile['error'][$i], 0, $varfiles);
-				
+
 				if (is_numeric($resupload) && $resupload > 0)   // $resupload can be 'ErrorFileAlreadyExists'
 				{
 					global $maxwidthsmall, $maxheightsmall, $maxwidthmini, $maxheightmini;
-				
+
 					include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
-					
+
 					// Generate thumbs.
 					if (image_format_supported($destfull) == 1)
 					{
 					    // Create thumbs
 					    // We can't use $object->addThumbs here because there is no $object known
-					
+
 					    // Used on logon for example
 					    $imgThumbSmall = vignette($destfull, $maxwidthsmall, $maxheightsmall, '_small', 50, "thumbs");
 					    // Create mini thumbs for image (Ratio is near 16/9)
 					    // Used on menu or for setup page for example
 					    $imgThumbMini = vignette($destfull, $maxwidthmini, $maxheightmini, '_mini', 50, "thumbs");
 					}
-					
+
 					// Update session
 					if (empty($donotupdatesession))
 					{
@@ -1406,18 +1406,18 @@ function dol_add_file_process($upload_dir, $allowoverwrite=0, $donotupdatesessio
 						$formmail->trackid = $trackid;
 						$formmail->add_attached_files($destfull, $destfile, $TFile['type'][$i]);
 					}
-					
+
 					// Update table of files
-					if ($donotupdatesession) 
+					if ($donotupdatesession)
 					{
 					    $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $upload_dir);
-				    
+
 					    if (! preg_match('/[\\/]temp[\\/]/', $rel_dir))     // If not a tmp dir
 					    {
 					        $filename = basename($destfile);
 					        $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
 					        $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
-    					    
+
     					    include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
     					    $ecmfile=new EcmFiles($db);
     					    $ecmfile->filepath = $rel_dir;
@@ -1455,7 +1455,7 @@ function dol_add_file_process($upload_dir, $allowoverwrite=0, $donotupdatesessio
 					}
 				}
 			}
-			
+
 		}
 	} elseif ($link) {
 		require_once DOL_DOCUMENT_ROOT . '/core/class/link.class.php';
@@ -1478,7 +1478,7 @@ function dol_add_file_process($upload_dir, $allowoverwrite=0, $donotupdatesessio
 		$langs->load("errors");
 		setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("File")), null, 'errors');
 	}
-	
+
 	return $res;
 }
 
@@ -1718,11 +1718,11 @@ function dol_compress_dir($inputdir, $outputfile, $mode="zip")
             if (class_exists('ZipArchive'))
             {
                 $foundhandler=1;
-                
+
                 // Initialize archive object
                 $zip = new ZipArchive();
                 $zip->open($outputfile, ZipArchive::CREATE | ZipArchive::OVERWRITE);
-                
+
                 // Create recursive directory iterator
                 /** @var SplFileInfo[] $files */
                 $files = new RecursiveIteratorIterator(
@@ -1738,15 +1738,15 @@ function dol_compress_dir($inputdir, $outputfile, $mode="zip")
                         // Get real and relative path for current file
                         $filePath = $file->getRealPath();
                         $relativePath = substr($filePath, strlen($inputdir) + 1);
-                
+
                         // Add current file to archive
                         $zip->addFile($filePath, $relativePath);
                     }
                 }
-                
+
                 // Zip archive will be created only after closing object
-                $zip->close();                
-    
+                $zip->close();
+
                 return 1;
             }
         }
@@ -1793,7 +1793,7 @@ function dol_most_recent_file($dir,$regexfilter='',$excludefilter=array('(\.meta
  * @param	string	$entity				Restrict onto entity (0=no restriction)
  * @param  	User	$fuser				User object (forced)
  * @param	string	$refname			Ref of object to check permission for external users (autodetect if not provided)
- * @param   string  $mode               Check permission for 'read' or 'write'               
+ * @param   string  $mode               Check permission for 'read' or 'write'
  * @return	mixed						Array with access information : 'accessallowed' & 'sqlprotectagainstexternals' & 'original_file' (as a full path name)
  * @see restrictedArea
  */
@@ -1801,7 +1801,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity,
 {
 	global $user, $conf, $db;
 	global $dolibarr_main_data_root;
-	
+
 	if (! is_object($fuser)) $fuser=$user;
 
 	if (empty($modulepart)) return 'ErrorBadParameter';
@@ -1823,7 +1823,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity,
 	{
 	    $lire='creer'; $read='write'; $download='upload';
 	}
-	 
+
 	// Wrapping for some images
 	if (($modulepart == 'mycompany' || $modulepart == 'companylogo') && !empty($conf->mycompany->dir_output))
 	{
@@ -2022,7 +2022,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity,
 	    }
 	    $original_file=$conf->user->dir_output.'/'.$original_file;
 	}
-	
+
 	// Wrapping for third parties
 	else if (($modulepart == 'company' || $modulepart == 'societe') && !empty($conf->societe->dir_output))
 	{
@@ -2119,7 +2119,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity,
 	    }
 	    $original_file=$conf->fournisseur->facture->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
 	}
-	
+
 	// Wrapping for interventions
 	else if (($modulepart == 'fichinter' || $modulepart == 'ficheinter') && !empty($conf->ficheinter->dir_output))
 	{
@@ -2185,7 +2185,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity,
 	}
 
 	// Wrapping pour les commandes fournisseurs
-	else if (($modulepart == 'commande_fournisseur' || $modulepart == 'order_supplier') && !empty($conf->fournisseur->commande->dir_output)) 
+	else if (($modulepart == 'commande_fournisseur' || $modulepart == 'order_supplier') && !empty($conf->fournisseur->commande->dir_output))
 	{
 		if ($fuser->rights->fournisseur->commande->{$lire} || preg_match('/^specimen/i',$original_file))
 		{
@@ -2317,7 +2317,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity,
 		}
 		$original_file=$conf->resource->dir_output.'/'.$original_file;
 	}
-	
+
 	// Wrapping pour les remises de cheques
 	else if ($modulepart == 'remisecheque' && !empty($conf->banque->dir_output))
 	{
@@ -2361,14 +2361,14 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity,
 		$accessallowed=1;
 		$original_file=$conf->fckeditor->dir_output.'/'.$original_file;
 	}
-	
+
 	// Wrapping for miscellaneous medias files
 	elseif ($modulepart == 'medias' && !empty($dolibarr_main_data_root))
 	{
 	    $accessallowed=1;
 	    $original_file=$dolibarr_main_data_root.'/medias/'.$original_file;
 	}
-	
+
 	// Wrapping for backups
 	else if ($modulepart == 'systemtools' && !empty($conf->admin->dir_output))
 	{
@@ -2416,7 +2416,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity,
     // If modulepart=module				Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart
     else
 	{
-	    if (preg_match('/^specimen/i',$original_file))	$accessallowed=1;    // If link to a file called specimen. Test must be done before changing $original_file int full path. 
+	    if (preg_match('/^specimen/i',$original_file))	$accessallowed=1;    // If link to a file called specimen. Test must be done before changing $original_file int full path.
 	    if ($fuser->admin) $accessallowed=1;    // If user is admin
 
 		// Define $accessallowed
diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php
index a18b9e1411027e5da26581ff0c80e0c91ed51d44..5113c9f1d9671707463743ff2f34df32d9f510e9 100644
--- a/htdocs/core/lib/functions.lib.php
+++ b/htdocs/core/lib/functions.lib.php
@@ -239,7 +239,7 @@ function dol_shutdown()
 /**
  *  Return value of a param into GET or POST supervariable.
  *  Use the property $user->default_values[path]['creatform'] and/or $user->default_values[path]['filters'] and/or $user->default_values[path]['sortorder']
- *  Note: The property $user->default_values is loaded by the main when loading the user.
+ *  Note: The property $user->default_values is loaded by main.php when loading the user.
  *
  *  @param	string	$paramname   Name of parameter to found
  *  @param	string	$check	     Type of check
@@ -359,32 +359,34 @@ function GETPOST($paramname, $check='', $method=0, $filter=NULL, $options=NULL)
 
 	if (! empty($check))
 	{
-	    // Replace vars like __DAY__, __MONTH__, __YEAR__, __MYCOUNTRYID__, __USERID__, __ENTITYID__, ...
-	    if (! is_array($out))
+	    // Substitution variables for GETPOST (used to get final url with variable parameters or final default value with variable paramaters)
+	    // Example of variables: __DAY__, __MONTH__, __YEAR__, __MYCOUNTRYID__, __USERID__, __ENTITYID__, ...
+	    // We do this only if var is a GET. If it is a POST, may be we want to post the text with vars as the setup text.
+	    if (! is_array($out) && empty($_POST[$paramname]))
 	    {
 	        $maxloop=20; $loopnb=0;    // Protection against infinite loop
 	        while (preg_match('/__([A-Z0-9]+_?[A-Z0-9]+)__/i', $out, $reg) && ($loopnb < $maxloop))    // Detect '__ABCDEF__' as key 'ABCDEF' and '__ABC_DEF__' as key 'ABC_DEF'. Detection is also correct when 2 vars are side by side.
 	        {
 	            $loopnb++; $newout = '';
 
-    	        if ($reg[1] == 'DAY')       { $tmp=dol_getdate(dol_now(), true); $newout = $tmp['mday']; }
-    	        elseif ($reg[1] == 'MONTH') { $tmp=dol_getdate(dol_now(), true); $newout = $tmp['mon'];  }
-    	        elseif ($reg[1] == 'YEAR')  { $tmp=dol_getdate(dol_now(), true); $newout = $tmp['year']; }
+    	        if ($reg[1] == 'DAY')                { $tmp=dol_getdate(dol_now(), true); $newout = $tmp['mday']; }
+    	        elseif ($reg[1] == 'MONTH')          { $tmp=dol_getdate(dol_now(), true); $newout = $tmp['mon'];  }
+    	        elseif ($reg[1] == 'YEAR')           { $tmp=dol_getdate(dol_now(), true); $newout = $tmp['year']; }
     	    	elseif ($reg[1] == 'PREVIOUS_DAY')   { $tmp=dol_getdate(dol_now(), true); $tmp2=dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']); $newout = $tmp2['day']; }
     	        elseif ($reg[1] == 'PREVIOUS_MONTH') { $tmp=dol_getdate(dol_now(), true); $tmp2=dol_get_prev_month($tmp['mday'], $tmp['mon'], $tmp['year']); $newout = $tmp2['month']; }
     	        elseif ($reg[1] == 'PREVIOUS_YEAR')  { $tmp=dol_getdate(dol_now(), true); $newout = ($tmp['year'] - 1); }
-    	    	elseif ($reg[1] == 'NEXT_DAY')   { $tmp=dol_getdate(dol_now(), true); $tmp2=dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']); $newout = $tmp2['day']; }
-    	        elseif ($reg[1] == 'NEXT_MONTH') { $tmp=dol_getdate(dol_now(), true); $tmp2=dol_get_next_month($tmp['mday'], $tmp['mon'], $tmp['year']); $newout = $tmp2['month']; }
-    	        elseif ($reg[1] == 'NEXT_YEAR')  { $tmp=dol_getdate(dol_now(), true); $newout = ($tmp['year'] + 1); }
-    	        elseif ($reg[1] == 'MYCOUNTRYID')
+    	    	elseif ($reg[1] == 'NEXT_DAY')       { $tmp=dol_getdate(dol_now(), true); $tmp2=dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']); $newout = $tmp2['day']; }
+    	        elseif ($reg[1] == 'NEXT_MONTH')     { $tmp=dol_getdate(dol_now(), true); $tmp2=dol_get_next_month($tmp['mday'], $tmp['mon'], $tmp['year']); $newout = $tmp2['month']; }
+    	        elseif ($reg[1] == 'NEXT_YEAR')      { $tmp=dol_getdate(dol_now(), true); $newout = ($tmp['year'] + 1); }
+    	        elseif ($reg[1] == 'MYCOUNTRY_ID' || $reg[1] == 'MYCOUNTRYID')
     	        {
     	            $newout = $mysoc->country_id;
     	        }
-    	        elseif ($reg[1] == 'USERID')
+    	        elseif ($reg[1] == 'USER_ID' || $reg[1] == 'USERID')
     	        {
     	            $newout = $user->id;
     	        }
-    	    	elseif ($reg[1] == 'SUPERVISORID')
+    	    	elseif ($reg[1] == 'SUPERVISOR_ID' || $reg[1] == 'SUPERVISORID')
     	        {
     	            $newout = $user->fk_user;
     	        }
@@ -1586,7 +1588,8 @@ function dol_print_date($time,$format='',$tzoutput='tzserver',$outputlangs='',$e
 	if (preg_match('/__b__/i',$format))
 	{
 		// Here ret is string in PHP setup language (strftime was used). Now we convert to $outputlangs.
-		$month=adodb_strftime('%m',$time+$offsettz+$offsetdst);					// TODO Remove this
+		$month=adodb_strftime('%m',$time+$offsettz+$offsetdst);					// TODO Replace this with function Date PHP. We also should not use anymore offsettz and offsetdst but only offsettzstring.
+        $month=sprintf("%02d", $month);                             // $month may be return with format '06' on some installation and '6' on other, so we force it to '06'.
 		if ($encodetooutput)
 		{
 			$monthtext=$outputlangs->transnoentities('Month'.$month);
@@ -2554,6 +2557,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $
 			$picto = $regs[1];
 			$path = $regs[2];	// $path is $mymodule
 		}
+
 		// Clean parameters
 		if (! preg_match('/(\.png|\.gif)$/i',$picto)) $picto .= '.png';
 		// If alt path are defined, define url where img file is, according to physical path
@@ -2792,7 +2796,7 @@ function img_printer($titlealt = "default", $other='')
 }
 
 /**
- *  Show delete logo
+ *  Show split logo
  *
  *  @param	string	$titlealt   Text on alt and title of image. Alt only if param notitle is set to 1. If text is "TextA:TextB", use Text A on alt and Text B on title.
  *	@param  string	$other      Add more attributes on img
@@ -3233,15 +3237,19 @@ function dol_print_error($db='',$error='',$errors=null)
  * Show a public email and error code to contact if technical error
  *
  * @param	string	$prefixcode		Prefix of public error code
+ * @param   string  $errormessage   Complete error message
  * @return	void
  */
-function dol_print_error_email($prefixcode)
+function dol_print_error_email($prefixcode, $errormessage='')
 {
 	global $langs,$conf;
 
 	$langs->load("errors");
 	$now=dol_now();
-	print '<br><div class="error">'.$langs->trans("ErrorContactEMail", $conf->global->MAIN_INFO_SOCIETE_MAIL, $prefixcode.dol_print_date($now,'%Y%m%d')).'</div>';
+	print '<br><div class="center login_main_message"><div class="error">';
+	print $langs->trans("ErrorContactEMail", $conf->global->MAIN_INFO_SOCIETE_MAIL, $prefixcode.dol_print_date($now,'%Y%m%d'));
+	if ($errormessage) print '<br><br>'.$errormessage;
+	print '</div></div>';
 }
 
 /**
@@ -5020,7 +5028,7 @@ function dol_concatdesc($text1,$text2,$forxml=false)
  *
  * @param	Translate	$outputlangs	Output language
  * @param   int         $onlykey        Do not calculate heavy values of keys (performance enhancement when we need only the keys)
- * @param   array       $exclude        Array of family keys we want to exclude. For example array('mycompany', 'object', 'date', 'user', ...)
+ * @param   array       $exclude        Array of family keys we want to exclude. For example array('mycompany', 'objectamount', 'date', 'user', ...)
  * @param   Object      $object         Object for keys on object
  * @return	array						Array of substitutions
  */
@@ -5045,7 +5053,7 @@ function getCommonSubstitutionArray($outputlangs, $onlykey=0, $exclude=null, $ob
             '__MYCOMPANY_COUNTRY_ID__' => $mysoc->country_id
         ));
     }
-    if (empty($exclude) || ! in_array('object', $exclude))
+    if (empty($exclude) || ! in_array('objectamount', $exclude))
     {
         if (is_object($object))       // For backward compatibility
         {
diff --git a/htdocs/core/lib/pdf.lib.php b/htdocs/core/lib/pdf.lib.php
index 8c48e2301e3953ff9e39e5a4fc8d53e8c20348a6..9220725dc8e97080cc9adf4212ff04bfedbf8cff 100644
--- a/htdocs/core/lib/pdf.lib.php
+++ b/htdocs/core/lib/pdf.lib.php
@@ -591,12 +591,13 @@ function pdf_pagehead(&$pdf,$outputlangs,$page_height)
  *   	Return array of possible substitutions for PDF content (without external module substitutions).
  *
  *		@param	Translate	$outputlangs	Output language
+ *      @param  array       $exclude        Array of family keys we want to exclude. For example array('mycompany', 'object', 'date', 'user', ...)
  *      @param  Object      $object         Object
  *      @return	array						Array of substitutions
  */
-function pdf_getSubstitutionArray($outputlangs, $object=null)
+function pdf_getSubstitutionArray($outputlangs, $exclude=null, $object=null)
 {
-    $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, null, $object);
+    $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, $exclude, $object);
     $substitutionarray['__FROM_NAME__']='__FROM_NAME__';
     $substitutionarray['__FROM_EMAIL__']='__FROM_EMAIL__';
     return $substitutionarray;
@@ -625,9 +626,9 @@ function pdf_watermark(&$pdf, $outputlangs, $h, $w, $unit, $text)
 	elseif ($unit=='in') $k=72;
 
 	// Make substitution
-	$substitutionarray=pdf_getSubstitutionArray($outputlangs,null);
-	complete_substitutions_array($substitutionarray,$outputlangs,null);
-	$text=make_substitutions($text,$substitutionarray,$outputlangs);
+	$substitutionarray=pdf_getSubstitutionArray($outputlangs, null, null);
+	complete_substitutions_array($substitutionarray, $outputlangs, null);
+	$text=make_substitutions($text, $substitutionarray, $outputlangs);
 	$text=$outputlangs->convToOutputCharset($text);
 
 	$savx=$pdf->getX(); $savy=$pdf->getY();
@@ -854,12 +855,12 @@ function pdf_pagefoot(&$pdf,$outputlangs,$paramfreetext,$fromcompany,$marge_bass
 	// Line of free text
 	if (empty($hidefreetext) && ! empty($conf->global->$paramfreetext))
 	{
-		$substitutionarray=pdf_getSubstitutionArray($outputlangs, $object);
+		$substitutionarray=pdf_getSubstitutionArray($outputlangs, null, $object);
 		// More substitution keys
 		$substitutionarray['__FROM_NAME__']=$fromcompany->name;
 		$substitutionarray['__FROM_EMAIL__']=$fromcompany->email;
-		complete_substitutions_array($substitutionarray,$outputlangs,$object);
-		$newfreetext=make_substitutions($conf->global->$paramfreetext,$substitutionarray,$outputlangs);
+		complete_substitutions_array($substitutionarray, $outputlangs, $object);
+		$newfreetext=make_substitutions($conf->global->$paramfreetext, $substitutionarray, $outputlangs);
 		$line.=$outputlangs->convToOutputCharset($newfreetext);
 	}
 
diff --git a/htdocs/core/lib/project.lib.php b/htdocs/core/lib/project.lib.php
index 38f78dd8333b251a149060b88eac86cfa3ca076b..c3583e72ac8e7273f1f2c3ff6fcfc140af73dfa0 100644
--- a/htdocs/core/lib/project.lib.php
+++ b/htdocs/core/lib/project.lib.php
@@ -35,7 +35,7 @@ require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
 function project_prepare_head($object)
 {
 	global $db, $langs, $conf, $user;
-	
+
 	$h = 0;
 	$head = array();
 
@@ -119,7 +119,7 @@ function project_prepare_head($object)
     }
 	$head[$h][2] = 'agenda';
 	$h++;
-	
+
 	complete_head_from_modules($conf,$langs,$object,$head,$h,'project','remove');
 
 	return $head;
@@ -163,7 +163,7 @@ function task_prepare_head($object)
 	    if ($obj) $nbTimeSpent=1;
 	}
 	else dol_print_error($db);
-	
+
 	$head[$h][0] = DOL_URL_ROOT.'/projet/tasks/time.php?id='.$object->id.(GETPOST('withproject')?'&withproject=1':'');
 	$head[$h][1] = $langs->trans("TimeSpent");
 	if ($nbTimeSpent > 0) $head[$h][1].= ' <span class="badge">...</span>';
@@ -208,9 +208,10 @@ function task_prepare_head($object)
  * Prepare array with list of tabs
  *
  * @param	string	$mode		Mode
+ * @param   string  $fuser      Filter on user
  * @return  array				Array of tabs to show
  */
-function project_timesheet_prepare_head($mode)
+function project_timesheet_prepare_head($mode, $fuser=null)
 {
 	global $langs, $conf, $user;
 	$h = 0;
@@ -218,9 +219,13 @@ function project_timesheet_prepare_head($mode)
 
 	$h = 0;
 
+	$param='';
+	$param.=($mode?'&mode='.$mode:'');
+	if (is_object($fuser) && $fuser->id > 0 && $fuser->id != $user->id) $param.='&search_usertoprocessid='.$fuser->id;
+
 	if (empty($conf->global->PROJECT_DISABLE_TIMESHEET_PERWEEK))
 	{
-		$head[$h][0] = DOL_URL_ROOT."/projet/activity/perweek.php".($mode?'?mode='.$mode:'');
+		$head[$h][0] = DOL_URL_ROOT."/projet/activity/perweek.php".($param?'?'.$param:'');
 		$head[$h][1] = $langs->trans("InputPerWeek");
 		$head[$h][2] = 'inputperweek';
 		$h++;
@@ -228,7 +233,7 @@ function project_timesheet_prepare_head($mode)
 
 	if (empty($conf->global->PROJECT_DISABLE_TIMESHEET_PERTIME))
 	{
-		$head[$h][0] = DOL_URL_ROOT."/projet/activity/perday.php".($mode?'?mode='.$mode:'');
+		$head[$h][0] = DOL_URL_ROOT."/projet/activity/perday.php".($param?'?'.$param:'');
 		$head[$h][1] = $langs->trans("InputPerDay");
 		$head[$h][2] = 'inputperday';
 		$h++;
@@ -507,7 +512,7 @@ function projectLinesa(&$inc, $parent, &$lines, &$level, $var, $showproject, &$t
     				if ($lines[$i]->id) projectLinesa($inc, $lines[$i]->id, $lines, $level, $var, $showproject, $taskrole, $projectsListId, $addordertick);
     				$level--;
 				}
-				
+
 				$total_projectlinesa_spent += $lines[$i]->duration;
 				$total_projectlinesa_planned += $lines[$i]->planned_workload;
 				if ($lines[$i]->planned_workload) $total_projectlinesa_spent_if_planned += $lines[$i]->duration;
@@ -571,9 +576,9 @@ function projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsr
 	$lastprojectid=0;
 	$workloadforid=array();
 	$lineswithoutlevel0=array();
-	
+
 	$numlines=count($lines);
-	
+
 	// Create a smaller array with sublevels only to be used later. This increase dramatically performances.
 	if ($parent == 0) // Always and only if at first level
 	{
@@ -581,7 +586,7 @@ function projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsr
 	    {
 	        if ($lines[$i]->fk_task_parent) $lineswithoutlevel0[]=$lines[$i];
 	    }
-	}	
+	}
 
     //dol_syslog('projectLinesPerDay inc='.$inc.' preselectedday='.$preselectedday.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0));
 	for ($i = 0 ; $i < $numlines ; $i++)
@@ -594,7 +599,7 @@ function projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsr
 			if (empty($mine) || ! empty($tasksrole[$lines[$i]->id]))
 			{
                 //dol_syslog("projectLinesPerWeek Found line ".$i.", a qualified task (i have role or want to show all tasks) with id=".$lines[$i]->id." project id=".$lines[$i]->fk_project);
-                
+
 				// Break on a new project
         		if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid)
         		{
@@ -604,7 +609,7 @@ function projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsr
         				$projectstatic->id = $lines[$i]->fk_project;
         			}
         		}
-			    
+
 			    if (empty($workloadforid[$projectstatic->id]))
 			    {
     				if ($preselectedday)
@@ -613,7 +618,7 @@ function projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsr
 	       		        $workloadforid[$projectstatic->id]=1;
     				}
 			    }
-			     
+
 				$projectstatic->id=$lines[$i]->fk_project;
 				$projectstatic->ref=$lines[$i]->projectref;
 				$projectstatic->title=$lines[$i]->projectlabel;
@@ -621,7 +626,12 @@ function projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsr
 
 				$taskstatic->id=$lines[$i]->id;
 
-				print "<tr ".$bc[$var].">\n";
+				print '<tr class="oddeven">'."\n";
+
+				// User
+				print '<td class="nowrap">';
+				print $fuser->getNomUrl(1, 'withproject', 'time');
+				print '</td>';
 
 				// Ref
 				print '<td>';
@@ -656,7 +666,7 @@ function projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsr
 				    print $thirdpartystatic->getNomUrl(1, 'project', 10);
 				    print '</td>';
 				}
-				
+
 				// Planned Workload
 				print '<td align="right">';
 				if ($lines[$i]->planned_workload) print convertSecondToTime($lines[$i]->planned_workload,'allhourmin');
@@ -707,7 +717,10 @@ function projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsr
 				print '<td class="nowrap" align="center">';
 				$tableCell=$form->select_date($preselectedday,$lines[$i]->id,1,1,2,"addtime",0,0,1,$disabledtask);
 				print $tableCell;
-				print '</td><td align="right">';
+				print '</td>';
+
+				// Duration
+				print '<td align="right">';
 
 				$dayWorkLoad = $projectstatic->weekWorkLoadPerTask[$preselectedday][$lines[$i]->id];
 		        $alreadyspent='';
@@ -723,24 +736,25 @@ function projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsr
 				print '</td>';
 
 				print '<td align="right">';
-				if ((! $lines[$i]->public) && $disabledproject) print $form->textwithpicto('',$langs->trans("YouAreNotContactOfProject"));
-				else if ($disabledtask) print $form->textwithpicto('',$langs->trans("TaskIsNotAffectedToYou"));
+				print '<textarea name="'.$lines[$i]->id.'note" rows="'.ROWS_2.'" id="'.$lines[$i]->id.'note"'.($disabledtask?' disabled="disabled"':'').'>';
+				print '</textarea>';
 				print '</td>';
 
+				// Warning
 				print '<td align="right">';
-				print '<textarea name="'.$lines[$i]->id.'note" rows="2" id="note">';
-				print '</textarea>';
+   				if ((! $lines[$i]->public) && $disabledproject) print $form->textwithpicto('',$langs->trans("UserIsNotContactOfProject"));
+   				else if ($disabledtask) print $form->textwithpicto('',$langs->trans("TaskIsNotAssignedToUser", $langs->transnoentitiesnoconv("AssignTaskToUser", '...')));
 				print '</td>';
-				
+
 				print "</tr>\n";
 			}
 
 			$inc++;
 			$level++;
-			if ($lines[$i]->id > 0) 
+			if ($lines[$i]->id > 0)
 			{
 			    if ($parent == 0) projectLinesPerDay($inc, $lines[$i]->id, $fuser, $lineswithoutlevel0, $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $preselectedday, $var);
-			    else projectLinesPerDay($inc, $lines[$i]->id, $fuser, $lines, $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $preselectedday, $var); 
+			    else projectLinesPerDay($inc, $lines[$i]->id, $fuser, $lines, $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $preselectedday, $var);
 			}
 			$level--;
 		}
@@ -781,7 +795,7 @@ function projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$
 	$lastprojectid=0;
 	$workloadforid=array();
 	$lineswithoutlevel0=array();
-	
+
 	// Create a smaller array with sublevels only to be used later. This increase dramatically performances.
 	if ($parent == 0) // Always and only if at first level
 	{
@@ -792,18 +806,18 @@ function projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$
 	}
 
     //dol_syslog('projectLinesPerWeek inc='.$inc.' firstdaytoshow='.$firstdaytoshow.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0));
-	
+
 	for ($i = 0 ; $i < $numlines ; $i++)
 	{
 		if ($parent == 0) $level = 0;
-		
+
 		if ($lines[$i]->fk_task_parent == $parent)
 		{
 			// If we want all or we have a role on task, we show it
 			if (empty($mine) || ! empty($tasksrole[$lines[$i]->id]))
 			{
 			    //dol_syslog("projectLinesPerWeek Found line ".$i.", a qualified task (i have role or want to show all tasks) with id=".$lines[$i]->id." project id=".$lines[$i]->fk_project);
-			    
+
 			    // Break on a new project
     			if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid)
     			{
@@ -811,14 +825,19 @@ function projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$
     				$lastprojectid=$lines[$i]->fk_project;
     				$projectstatic->id = $lines[$i]->fk_project;
     			}
-			    
+
 			    if (empty($workloadforid[$projectstatic->id]))
 			    {
 				    $projectstatic->loadTimeSpent($firstdaytoshow, 0, $fuser->id);	// Load time spent from table projet_task_time for the project into this->weekWorkLoad and this->weekWorkLoadPerTask for all days of a week
                     $workloadforid[$projectstatic->id]=1;
 			    }
-			    
-				print "<tr ".$bc[$var].">\n";
+
+				print '<tr class="oddeven">'."\n";
+
+				// User
+				print '<td class="nowrap">';
+				print $fuser->getNomUrl(1, 'withproject', 'time');
+				print '</td>';
 
 				// Ref
 				print '<td class="nowrap">';
@@ -842,7 +861,7 @@ function projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$
 				print "</td>\n";
 
 				// Project
-				print '<td class="nowrap">'.$var;
+				print '<td class="nowrap">';
 				$projectstatic->id=$lines[$i]->fk_project;
 				$projectstatic->ref=$lines[$i]->projectref;
 				$projectstatic->title=$lines[$i]->projectlabel;
@@ -860,7 +879,7 @@ function projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$
 				    print $thirdpartystatic->getNomUrl(1, 'project');
 				    print '</td>';
 				}
-				
+
 				// Planned Workload
 				print '<td align="right">';
 				if ($lines[$i]->planned_workload) print convertSecondToTime($lines[$i]->planned_workload,'allhourmin');
@@ -908,7 +927,7 @@ function projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$
 				}
 
 				//var_dump($projectstatic->weekWorkLoadPerTask);
-				
+
 				// Fields to show current time
 				$tableCell=''; $modeinput='hours';
 				for ($idw = 0; $idw < 7; $idw++)
@@ -919,7 +938,7 @@ function projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$
 		        	$alreadyspent='';
 		        	if ($dayWorkLoad > 0) $alreadyspent=convertSecondToTime($dayWorkLoad,'allhourmin');
                     $alttitle=$langs->trans("AddHereTimeSpentForDay",$tmparray['day'],$tmparray['mon']);
-		        	
+
                     $tableCell ='<td align="center" class="hide'.$idw.'">';
                     if ($alreadyspent)
                     {
@@ -934,10 +953,11 @@ function projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$
                     $tableCell.='</td>';
                     print $tableCell;
 		        }
-		        
+
+		        // Warning
 				print '<td align="right">';
-				if ((! $lines[$i]->public) && $disabledproject) print $form->textwithpicto('',$langs->trans("YouAreNotContactOfProject"));
-				else if ($disabledtask) print $form->textwithpicto('',$langs->trans("TaskIsNotAffectedToYou"));
+   				if ((! $lines[$i]->public) && $disabledproject) print $form->textwithpicto('',$langs->trans("UserIsNotContactOfProject"));
+   				else if ($disabledtask) print $form->textwithpicto('',$langs->trans("TaskIsNotAssignedToUser", $langs->transnoentitiesnoconv("AssignTaskToUser", '...')));
 				print '</td>';
 
 		        print "</tr>\n";
@@ -946,7 +966,7 @@ function projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$
 			// Call to show task with a lower level (task under the current task)
 			$inc++;
 			$level++;
-			if ($lines[$i]->id > 0) 
+			if ($lines[$i]->id > 0)
 			{
 			    if ($parent == 0) projectLinesPerWeek($inc, $firstdaytoshow, $fuser, $lines[$i]->id, $lineswithoutlevel0, $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $var);
 			    else projectLinesPerWeek($inc, $firstdaytoshow, $fuser, $lines[$i]->id, $lines, $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $var);
@@ -1020,7 +1040,7 @@ function print_projecttasks_array($db, $form, $socid, $projectsListId, $mytasks=
 
 	$projectstatic=new Project($db);
     $thirdpartystatic=new Societe($db);
-    
+
 	$sortfield='';
 	$sortorder='';
 	$project_year_filter=0;
@@ -1029,7 +1049,7 @@ function print_projecttasks_array($db, $form, $socid, $projectsListId, $mytasks=
 	if (strcmp($statut, '') && $statut >= 0) $title=$langs->trans("Projects").' '.$langs->trans($projectstatic->statuts_long[$statut]);
 
 	$arrayidtypeofcontact=array();
-	
+
 	print '<table class="noborder" width="100%">';
 
 	$sql.= " FROM ".MAIN_DB_PREFIX."projet as p";
@@ -1072,11 +1092,11 @@ function print_projecttasks_array($db, $form, $socid, $projectsListId, $mytasks=
 			$sql.= " AND (p.datee IS NULL OR p.datee >= ".$db->idate(dol_get_first_day($project_year_filter,1,false)).")";
 		}
 	}
-	
+
 	// Get id of project we must show tasks
 	$arrayidofprojects=array();
 	$sql1 = "SELECT p.rowid as projectid";
-	$sql1.= $sql; 
+	$sql1.= $sql;
 	$resql = $db->query($sql1);
 	if ($resql)
 	{
@@ -1091,7 +1111,7 @@ function print_projecttasks_array($db, $form, $socid, $projectsListId, $mytasks=
 	}
 	else dol_print_error($db);
 	if (empty($arrayidofprojects)) $arrayidofprojects[0]=-1;
-	
+
 	// Get list of project with calculation on tasks
 	$sql2 = "SELECT p.rowid as projectid, p.ref, p.title, p.fk_soc, s.nom as socname, p.fk_user_creat, p.public, p.fk_statut as status, p.fk_opp_status as opp_status, p.opp_amount,";
 	$sql2.= " p.dateo, p.datee,";
@@ -1122,7 +1142,7 @@ function print_projecttasks_array($db, $form, $socid, $projectsListId, $mytasks=
     		print_liste_field_titre($langs->trans("OpportunityAmount"),"","","","",'align="right"',$sortfield,$sortorder);
     		print_liste_field_titre($langs->trans("OpportunityStatus"),"","","","",'align="right"',$sortfield,$sortorder);
     	}
-    	if (empty($conf->global->PROJECT_HIDE_TASKS)) 
+    	if (empty($conf->global->PROJECT_HIDE_TASKS))
     	{
             print_liste_field_titre($langs->trans("Tasks"),"","","","",'align="right"',$sortfield,$sortorder);
             if (! in_array('plannedworkload', $hiddenfields))  print_liste_field_titre($langs->trans("PlannedWorkload"),"","","","",'align="right"',$sortfield,$sortorder);
@@ -1130,7 +1150,7 @@ function print_projecttasks_array($db, $form, $socid, $projectsListId, $mytasks=
     	}
     	print_liste_field_titre($langs->trans("Status"),"","","","",'align="right"',$sortfield,$sortorder);
     	print "</tr>\n";
-		
+
 		while ($i < $num)
 		{
 			$objp = $db->fetch_object($resql);
@@ -1148,8 +1168,8 @@ function print_projecttasks_array($db, $form, $socid, $projectsListId, $mytasks=
 			    $projectstatic->title = $objp->title;
 			    $projectstatic->datee = $db->jdate($objp->datee);
 			    $projectstatic->dateo = $db->jdate($objp->dateo);
-			     
-				
+
+
 				print '<tr class="oddeven">';
 				print '<td>';
 				print $projectstatic->getNomUrl(1);
@@ -1174,17 +1194,17 @@ function print_projecttasks_array($db, $form, $socid, $projectsListId, $mytasks=
         			if ($code) print $langs->trans("OppStatus".$code);
 					print '</td>';
 				}
-				if (empty($conf->global->PROJECT_HIDE_TASKS)) 
+				if (empty($conf->global->PROJECT_HIDE_TASKS))
 				{
 				    print '<td align="right">'.$objp->nb.'</td>';
-    	       
+
     				$plannedworkload=$objp->planned_workload;
     				$total_plannedworkload+=$plannedworkload;
     				if (! in_array('plannedworkload', $hiddenfields))
     				{
     				    print '<td align="right">'.($plannedworkload?convertSecondToTime($plannedworkload):'').'</td>';
     				}
-    				if (! in_array('declaredprogress', $hiddenfields)) 
+    				if (! in_array('declaredprogress', $hiddenfields))
     				{
     				    $declaredprogressworkload=$objp->declared_progess_workload;
         				$total_declaredprogressworkload+=$declaredprogressworkload;
@@ -1194,7 +1214,7 @@ function print_projecttasks_array($db, $form, $socid, $projectsListId, $mytasks=
         				print '</td>';
     				}
 				}
-				
+
 				print '<td align="right">'.$projectstatic->getLibStatut(3).'</td>';
 				print "</tr>\n";
 
@@ -1213,7 +1233,7 @@ function print_projecttasks_array($db, $form, $socid, $projectsListId, $mytasks=
 			print '<td class="liste_total" align="right">'.price($total_opp_amount, 0, '', 1, -1, -1, $conf->currency).'</td>';
 			print '<td class="liste_total" align="right">'.$form->textwithpicto(price($ponderated_opp_amount, 0, '', 1, -1, -1, $conf->currency), $langs->trans("OpportunityPonderatedAmountDesc"), 1).'</td>';
 		}
-		if (empty($conf->global->PROJECT_HIDE_TASKS)) 
+		if (empty($conf->global->PROJECT_HIDE_TASKS))
 		{
             print '<td class="liste_total" align="right">'.$total_task.'</td>';
             if (! in_array('plannedworkload', $hiddenfields))  print '<td class="liste_total" align="right">'.($total_plannedworkload?convertSecondToTime($total_plannedworkload):'').'</td>';
@@ -1221,7 +1241,7 @@ function print_projecttasks_array($db, $form, $socid, $projectsListId, $mytasks=
 		}
 		print '<td class="liste_total"></td>';
         print '</tr>';
-        
+
 		$db->free($resql);
 	}
 	else
diff --git a/htdocs/core/lib/security.lib.php b/htdocs/core/lib/security.lib.php
index 6993ad496eae4d46808ce6c2b0c6d8f9cdf982fa..2a2b224194ffbf4709b4714fd6daf245d8280260 100644
--- a/htdocs/core/lib/security.lib.php
+++ b/htdocs/core/lib/security.lib.php
@@ -345,7 +345,7 @@ function restrictedArea($user, $features, $objectid=0, $tableandshare='', $featu
  * This function is also called by restrictedArea
  *
  * @param User		$user			User to check
- * @param array		$featuresarray	Features/modules to check. Example: ('user','service')
+ * @param array		$featuresarray	Features/modules to check. Example: ('user','service','member','project','task',...)
  * @param int		$objectid		Object ID if we want to check a particular record (optional) is linked to a owned thirdparty (optional).
  * @param string	$tableandshare	'TableName&SharedElement' with Tablename is table where object is stored. SharedElement is an optional key to define where to check entity for multicompany modume. Param not used if objectid is null (optional).
  * @param string	$feature2		Feature to check, second level of permission (optional). Can be or check with 'level1|level2'.
@@ -369,11 +369,14 @@ function checkUserAccessToObject($user, $featuresarray, $objectid=0, $tableandsh
 
 		// For backward compatibility
 		if ($feature == 'member') $feature='adherent';
+		if ($feature == 'project') $feature='projet';
+		if ($feature == 'task') $feature='projet_task';
 
 		$check = array('adherent','banque','user','usergroup','produit','service','produit|service','categorie'); // Test on entity only (Objects with no link to company)
 		$checksoc = array('societe');	 // Test for societe object
 		$checkother = array('contact');	 // Test on entity and link to societe. Allowed if link is empty (Ex: contacts...).
-		$checkproject = array('projet'); // Test for project object
+		$checkproject = array('projet','project'); // Test for project object
+		$checktask = array('projet_task');
 		$nocheck = array('barcode','stock','fournisseur');	// No test
 		$checkdefault = 'all other not already defined'; // Test on entity and link to third party. Not allowed if link is empty (Ex: invoice, orders...).
 
@@ -453,7 +456,7 @@ function checkUserAccessToObject($user, $featuresarray, $objectid=0, $tableandsh
 		}
 		else if (in_array($feature,$checkproject))
 		{
-			if (! empty($conf->projet->enabled) && ! $user->rights->projet->all->lire)
+			if (! empty($conf->projet->enabled) && empty($user->rights->projet->all->lire))
 			{
 				include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
 				$projectstatic=new Project($db);
@@ -469,6 +472,27 @@ function checkUserAccessToObject($user, $featuresarray, $objectid=0, $tableandsh
 				$sql.= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
 			}
 		}
+		else if (in_array($feature,$checktask))
+		{
+			if (! empty($conf->projet->enabled) && empty($user->rights->projet->all->lire))
+			{
+			    $task = new Task($db);
+			    $task->fetch($objectid);
+
+				include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
+				$projectstatic=new Project($db);
+				$tmps=$projectstatic->getProjectsAuthorizedForUser($user,0,1,0);
+				$tmparray=explode(',',$tmps);
+				if (! in_array($task->fk_project,$tmparray)) return false;
+			}
+			else
+			{
+				$sql = "SELECT dbt.".$dbt_select;
+				$sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
+				$sql.= " WHERE dbt.".$dbt_select." = ".$objectid;
+				$sql.= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
+			}
+		}
 		else if (! in_array($feature,$nocheck))	// By default we check with link to third party
 		{
 			// If external user: Check permission for external users
diff --git a/htdocs/core/menus/init_menu_auguria.sql b/htdocs/core/menus/init_menu_auguria.sql
index 9106c345fdac8082542c931818915676ff8ed43c..7a60f330727914e9d4af73b543ce2a0e022cb7aa 100644
--- a/htdocs/core/menus/init_menu_auguria.sql
+++ b/htdocs/core/menus/init_menu_auguria.sql
@@ -288,6 +288,7 @@ insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, left
 insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->projet->enabled', __HANDLER__, 'left', 3701__+MAX_llx_menu__, 'project', '', 3700__+MAX_llx_menu__, '/projet/tasks.php?leftmenu=projects&amp;action=create', 'NewTask', 1, 'projects', '$user->rights->projet->creer', '', 2, 1, __ENTITY__);
 insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->projet->enabled', __HANDLER__, 'left', 3702__+MAX_llx_menu__, 'project', '', 3700__+MAX_llx_menu__, '/projet/tasks/list.php?leftmenu=projects', 'List', 1, 'projects', '$user->rights->projet->lire', '', 2, 2, __ENTITY__);
 insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->projet->enabled', __HANDLER__, 'left', 3703__+MAX_llx_menu__, 'project', '', 3700__+MAX_llx_menu__, '/projet/activity/perweek.php?leftmenu=projects', 'NewTimeSpent', 1, 'projects', '$user->rights->projet->lire', '', 2, 3, __ENTITY__);
+insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->projet->enabled', __HANDLER__, 'left', 3704__+MAX_llx_menu__, 'project', '', 3600__+MAX_llx_menu__, '/projet/tasks/stats/index.php?leftmenu=projects', 'Statistics', 1, 'projects', '$user->rights->projet->lire', '', 2, 4, __ENTITY__);
 
 -- Project - Categories
 insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->categorie->enabled', __HANDLER__, 'left', 3804__+MAX_llx_menu__, 'project', 'cat', 3__+MAX_llx_menu__, '/categories/index.php?leftmenu=cat&amp;type=6', 'Categories', 0, 'categories', '$user->rights->categorie->lire', '', 2, 4, __ENTITY__);
diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php
index 9245a481aff631e019d70dab9ad1e0bf1344db8f..8b167e3a6f602333b89139946ec55555a7fd6286 100644
--- a/htdocs/core/menus/standard/eldy.lib.php
+++ b/htdocs/core/menus/standard/eldy.lib.php
@@ -52,7 +52,7 @@ function print_eldy_menu($db,$atarget,$type_user,&$tabMenu,&$menu,$noout=0,$mode
 	if (empty($noout)) print_start_menu_array();
 
 	$usemenuhider = (GETPOST('testmenuhider','int') || ! empty($conf->global->MAIN_TESTMENUHIDER));
-	
+
 	// Show/Hide vertical menu
 	if ($mode != 'jmobile' && $mode != 'topnb' && $usemenuhider && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
 	{
@@ -437,7 +437,7 @@ function print_end_menu_array()
 /**
  * Core function to output left menu eldy
  * Fill &$menu (example with $forcemainmenu='home' $forceleftmenu='all', return left menu tree of Home)
- * 
+ *
  * @param	DoliDB		$db                 Database handler
  * @param 	array		$menu_array_before  Table of menu entries to show before entries of menu handler (menu->liste filled with menu->add)
  * @param   array		$menu_array_after   Table of menu entries to show after entries of menu handler (menu->liste filled with menu->add)
@@ -445,7 +445,7 @@ function print_end_menu_array()
  * @param	Menu		$menu				Object Menu to return back list of menu entries
  * @param	int			$noout				Disable output (Initialise &$menu only).
  * @param	string		$forcemainmenu		'x'=Force mainmenu to mainmenu='x'
- * @param	string		$forceleftmenu		'all'=Force leftmenu to '' (= all). If value come being '', we change it to value in session and 'none' if not efined in session. 
+ * @param	string		$forceleftmenu		'all'=Force leftmenu to '' (= all). If value come being '', we change it to value in session and 'none' if not efined in session.
  * @param	array		$moredata			An array with more data to output
  * @return	int								nb of menu entries
  */
@@ -459,7 +459,7 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
 	$leftmenu=($forceleftmenu?'':(empty($_SESSION["leftmenu"])?'none':$_SESSION["leftmenu"]));
 
 	$usemenuhider = (GETPOST('testmenuhider','int') || ! empty($conf->global->MAIN_TESTMENUHIDER));
-	
+
 	// Show logo company
 	if (empty($conf->global->MAIN_MENU_INVERT) && empty($noout) && ! empty($conf->global->MAIN_SHOW_LOGO) && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
 	{
@@ -503,7 +503,7 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
 	    print '</div>'."\n";
 	    print "<!-- End Bookmarks -->\n";
 	}
-	
+
 	/**
 	 * We update newmenu with entries found into database
 	 * --------------------------------------------------
@@ -605,7 +605,7 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
 					$newmenu->add("/user/group/index.php?leftmenu=users", $langs->trans("ListOfGroups"), 2, ($conf->global->MAIN_USE_ADVANCED_PERMS?$user->rights->user->group_advance->read:$user->rights->user->user->lire) || $user->admin);
 				}
 			}
-			
+
 		}
 
 
@@ -839,7 +839,7 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
 				}
 
 				$newmenu->add("/fourn/facture/paiement.php", $langs->trans("Payments"),1,$user->rights->fournisseur->facture->lire);
-				
+
 				$newmenu->add("/fourn/facture/rapport.php",$langs->trans("Reportings"),2,$user->rights->fournisseur->facture->lire);
 
 				$newmenu->add("/compta/facture/stats/index.php?mode=supplier", $langs->trans("Statistics"),1,$user->rights->fournisseur->facture->lire);
@@ -957,29 +957,29 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
 				if ($usemenuhider || empty($leftmenu) || preg_match('/accountancy_admin/',$leftmenu)) $newmenu->add("/accountancy/admin/account.php?mainmenu=accountancy&leftmenu=accountancy_admin", $langs->trans("Chartofaccounts"),2, $user->rights->accounting->chartofaccount, '', $mainmenu, 'accountancy_admin_chart', 30);
 				if ($usemenuhider || empty($leftmenu) || preg_match('/accountancy_admin/',$leftmenu)) $newmenu->add("/accountancy/admin/categories_list.php?id=32&search_country_id=".$mysoc->country_id."&mainmenu=accountancy&leftmenu=accountancy_admin", $langs->trans("AccountingCategory"),2, $user->rights->accounting->chartofaccount, '', $mainmenu, 'accountancy_admin_chart', 31);
 				if ($usemenuhider || empty($leftmenu) || preg_match('/accountancy_admin/',$leftmenu)) $newmenu->add("/accountancy/admin/defaultaccounts.php?mainmenu=accountancy&leftmenu=accountancy_admin", $langs->trans("MenuDefaultAccounts"),2, $user->rights->accounting->chartofaccount, '', $mainmenu, 'accountancy_admin_default', 40);
-				if (! empty($conf->facture->enabled) || ! empty($conf->fournisseur->enabled)) 
+				if (! empty($conf->facture->enabled) || ! empty($conf->fournisseur->enabled))
 				{
 				    if ($usemenuhider || empty($leftmenu) || preg_match('/accountancy_admin/',$leftmenu)) $newmenu->add("/admin/dict.php?id=10&from=accountancy&search_country_id=".$mysoc->country_id."&mainmenu=accountancy&leftmenu=accountancy_admin", $langs->trans("MenuVatAccounts"),2, $user->rights->accounting->chartofaccount, '', $mainmenu, 'accountancy_admin_default', 50);
 				}
-				if (! empty($conf->tax->enabled)) 
+				if (! empty($conf->tax->enabled))
 				{
 				    if ($usemenuhider || empty($leftmenu) || preg_match('/accountancy_admin/',$leftmenu)) $newmenu->add("/admin/dict.php?id=7&from=accountancy&search_country_id=".$mysoc->country_id."&mainmenu=accountancy&leftmenu=accountancy_admin", $langs->trans("MenuTaxAccounts"),2, $user->rights->accounting->chartofaccount, '', $mainmenu, 'accountancy_admin_default', 50);
 				}
-				if (! empty($conf->expensereport->enabled)) 
+				if (! empty($conf->expensereport->enabled))
 				{
 				    if (preg_match('/accountancy_admin/',$leftmenu)) $newmenu->add("/admin/dict.php?id=17&from=accountancy&mainmenu=accountancy&leftmenu=accountancy_admin", $langs->trans("MenuExpenseReportAccounts"),2, $user->rights->accounting->chartofaccount, '', $mainmenu, 'accountancy_admin_default', 50);
 				}
 				/* not required yet, already supported by default account
-				if (! empty($conf->loan->enabled)) 
+				if (! empty($conf->loan->enabled))
 				{
 				    if ($usemenuhider || empty($leftmenu) || preg_match('/accountancy_admin/',$leftmenu)) $newmenu->add("/admin/loan.php?mainmenu=accountancy&amp;leftmenu=accountancy_admin", $langs->trans("MenuLoanAccounts"), 2, $user->rights->accounting->chartofaccount, '', $mainmenu, 'accountancy_admin_loan', 45);
 				}
-				if (! empty($conf->don->enabled)) 
+				if (! empty($conf->don->enabled))
 				{
 				    if (preg_match('/accountancy_admin/',$leftmenu)) $newmenu->add("/don/admin/donation.php?from=accountancy&mainmenu=accountancy&amp;leftmenu=accountancy_admin", $langs->trans("MenuDonationAccounts"), 2, $user->rights->accounting->chartofaccount, '', $mainmenu, 'accountancy_admin_donation', 47);
 				}*/
 				if ($usemenuhider || empty($leftmenu) || preg_match('/accountancy_admin/',$leftmenu)) $newmenu->add("/accountancy/admin/productaccount.php?mainmenu=accountancy&amp;leftmenu=accountancy_admin", $langs->trans("MenuProductsAccounts"), 2, $user->rights->accounting->chartofaccount, '', $mainmenu, 'accountancy_admin_product', 60);
-				
+
 				// Binding
 				if ($usemenuhider || empty($leftmenu) || preg_match('/accountancy/',$leftmenu)) $newmenu->add("/accountancy/customer/index.php?leftmenu=accountancy_dispatch_customer&amp;mainmenu=accountancy",$langs->trans("CustomersVentilation"),1,$user->rights->accounting->bind->write, '', $mainmenu, 'dispatch_customer');
 			    if ($usemenuhider || empty($leftmenu) || preg_match('/accountancy_dispatch_customer/',$leftmenu)) $newmenu->add("/accountancy/customer/list.php?mainmenu=accountancy&amp;leftmenu=accountancy_dispatch_customer",$langs->trans("ToBind"),2,$user->rights->accounting->bind->write);
@@ -1275,7 +1275,7 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
     				$newmenu->add("/product/inventory/list.php", $langs->trans("List"), 1, $user->rights->stock->lire);
     			}
 			}
-			
+
 			// Expeditions
 			if (! empty($conf->expedition->enabled))
 			{
@@ -1299,9 +1299,9 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
 			if (! empty($conf->projet->enabled))
 			{
 				$langs->load("projects");
-				
+
 				$search_project_user = GETPOST('search_project_user','int');
-				
+
 				// Project affected to user
 				$newmenu->add("/projet/index.php?leftmenu=projects".($search_project_user?'&search_project_user='.$search_project_user:''), $langs->trans("Projects"), 0, $user->rights->projet->lire, '', $mainmenu, 'projects');
 				$newmenu->add("/projet/card.php?leftmenu=projects&action=create".($search_project_user?'&search_project_user='.$search_project_user:''), $langs->trans("NewProject"), 1, $user->rights->projet->creer);
@@ -1314,7 +1314,7 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
 				$newmenu->add("/projet/list.php?leftmenu=projects&search_status=99", $langs->trans("List"), 1, $user->rights->projet->lire && $user->rights->projet->lire);
                 */
 				$newmenu->add("/projet/stats/index.php?leftmenu=projects", $langs->trans("Statistics"), 1, $user->rights->projet->lire);
-				
+
 				if (empty($conf->global->PROJECT_HIDE_TASKS))
 				{
 					// Project affected to user
@@ -1322,6 +1322,7 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
 					$newmenu->add("/projet/tasks.php?leftmenu=tasks&action=create", $langs->trans("NewTask"), 1, $user->rights->projet->creer);
 					$newmenu->add("/projet/tasks/list.php?leftmenu=tasks".($search_project_user?'&search_project_user='.$search_project_user:''), $langs->trans("List"), 1, $user->rights->projet->lire);
 					$newmenu->add("/projet/activity/perweek.php?leftmenu=tasks".($search_project_user?'&search_project_user='.$search_project_user:''), $langs->trans("NewTimeSpent"), 1, $user->rights->projet->lire);
+				    $newmenu->add("/projet/tasks/stats/index.php?leftmenu=projects", $langs->trans("Statistics"), 1, $user->rights->projet->lire);
 
 					// All project i have permission on
 					/*$newmenu->add("/projet/activity/index.php", $langs->trans("Activities"), 0, $user->rights->projet->lire && $user->rights->projet->lire);
@@ -1445,7 +1446,7 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
 				$newmenu->add("/adherents/stats/index.php?leftmenu=members",$langs->trans("MenuMembersStats"),1,$user->rights->adherent->lire);
 				if (! empty($conf->global->MEMBER_LINK_TO_HTPASSWDFILE) && ($usemenuhider || empty($leftmenu) || $leftmenu=="export")) $newmenu->add("/adherents/htpasswd.php?leftmenu=export",$langs->trans("Filehtpasswd"),1,$user->rights->adherent->export);
 				if ($usemenuhider || empty($leftmenu) || $leftmenu=="export") $newmenu->add("/adherents/cartes/carte.php?leftmenu=export",$langs->trans("MembersCards"),1,$user->rights->adherent->export);
-				
+
 				$newmenu->add("/adherents/index.php?leftmenu=members&amp;mainmenu=members",$langs->trans("Subscriptions"),0,$user->rights->adherent->cotisation->lire);
 				$newmenu->add("/adherents/list.php?leftmenu=members&amp;statut=-1,1&amp;mainmenu=members",$langs->trans("NewSubscription"),1,$user->rights->adherent->cotisation->creer);
 				$newmenu->add("/adherents/subscription/list.php?leftmenu=members",$langs->trans("List"),1,$user->rights->adherent->cotisation->lire);
diff --git a/htdocs/core/modules/DolibarrModules.class.php b/htdocs/core/modules/DolibarrModules.class.php
index 71de341a76996c9b59193395a4d02feea3096d35..a79f17b1fdc5b659cb385bda220ab4894dcb1b8a 100644
--- a/htdocs/core/modules/DolibarrModules.class.php
+++ b/htdocs/core/modules/DolibarrModules.class.php
@@ -50,13 +50,13 @@ class DolibarrModules           // Can not be abstract, because we need to insta
      * @since 4.0.0
      */
     public $editor_name;
-    
+
     /**
      * @var string URL of module at publisher site
      * @since 4.0.0
      */
     public $editor_url;
-    
+
     /**
      * @var string Family
      * @see familyinfo
@@ -80,13 +80,13 @@ class DolibarrModules           // Can not be abstract, because we need to insta
      *
      */
     public $familyinfo;
-    
+
     /**
      * @var int Module position
      * @since 3.9.0
      */
     public $module_position=500;
-    
+
     /**
      * @var string Module name
      *
@@ -214,7 +214,7 @@ class DolibarrModules           // Can not be abstract, because we need to insta
      * HTML content supported.
      */
     public $descriptionlong;
-    
+
     /**
      * @var string Module export code
      */
@@ -249,7 +249,7 @@ class DolibarrModules           // Can not be abstract, because we need to insta
      * @var bool Module is enabled globally (Multicompany support)
      */
     public $core_enabled;
-    
+
     /**
      * @var string Relative path to module style sheet
      * @deprecated
@@ -286,7 +286,7 @@ class DolibarrModules           // Can not be abstract, because we need to insta
 	 */
 	public $config_page_url;
 
-	
+
 	/**
 	 * @var string[] List of module class names that must be enabled if this module is enabled.
 	 *
@@ -309,22 +309,22 @@ class DolibarrModules           // Can not be abstract, because we need to insta
      * @var string[] Module language files
      */
     public $langfiles;
-    
+
     /**
      * @var string[] Array of warnings to show when we activate the module
-     * 
+     *
      * array('always'='text') or array('FR'='text')
      */
     public $warnings_activation;
-    
+
     /**
      * @var string[] Array of warnings to show when we activate an external module
-     * 
+     *
      * array('always'='text') or array('FR'='text')
      */
     public $warnings_activation_ext;
-    
-	
+
+
 	/**
 	 * @var array() Minimum version of PHP required by module.
 	 * e.g.: PHP ≥ 5.3 = array(5, 3)
@@ -342,7 +342,7 @@ class DolibarrModules           // Can not be abstract, because we need to insta
 	 */
 	public $hidden = false;
 
-	
+
 	/**
 	 * Constructor. Define names, constants, directories, boxes, permissions
 	 *
@@ -538,8 +538,8 @@ class DolibarrModules           // Can not be abstract, because we need to insta
             return $langs->trans("Module".$this->numero."Name");
         }
         else
-       {
-            // If module name translation using it's unique id does not exists, we take use its name to find translation
+        {
+            // If module name translation using it's unique id does not exists, we try to use its name to find translation
             if (is_array($this->langfiles))
             {
                 foreach($this->langfiles as $val)
@@ -547,6 +547,14 @@ class DolibarrModules           // Can not be abstract, because we need to insta
                     if ($val) $langs->load($val);
                 }
             }
+
+            if ($langs->trans("Module".$this->name."Name") != ("Module".$this->name."Name"))
+            {
+                // If module name translation exists
+                return $langs->trans("Module".$this->name."Name");
+            }
+
+            // Last change with simple product label
             return $langs->trans($this->name);
         }
     }
@@ -591,13 +599,13 @@ class DolibarrModules           // Can not be abstract, because we need to insta
     {
         global $langs;
         $langs->load("admin");
-        
+
         include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
         include_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
 
         $filefound= false;
-        
-        // Define path to file README.md. 
+
+        // Define path to file README.md.
         // First check README-la_LA.md then README.md
         $pathoffile = dol_buildpath(strtolower($this->name).'/README-'.$langs->defaultlang.'.md', 0);
         if (dol_is_file($pathoffile))
@@ -612,11 +620,11 @@ class DolibarrModules           // Can not be abstract, because we need to insta
                 $filefound = true;
             }
         }
-        
+
         if ($filefound)     // Mostly for external modules
         {
             $content = file_get_contents($pathoffile);
-    
+
             if ((float) DOL_VERSION >= 6.0)
             {
                 @include_once DOL_DOCUMENT_ROOT.'/core/lib/parsemd.lib.php';
@@ -638,14 +646,14 @@ class DolibarrModules           // Can not be abstract, because we need to insta
                         if ($val) $langs->load($val);
                     }
                 }
-            
+
                 $content = $langs->trans($this->descriptionlong);
             }
         }
-    
+
         return $content;
     }
-    
+
     /**
      * Gives the publisher name
      *
@@ -655,7 +663,7 @@ class DolibarrModules           // Can not be abstract, because we need to insta
     {
         return $this->editor_name;
     }
-    
+
     /**
      * Gives the publisher url
      *
@@ -665,7 +673,7 @@ class DolibarrModules           // Can not be abstract, because we need to insta
     {
         return $this->editor_url;
     }
-    
+
     /**
      * Gives module version (translated if param $translated is on)
      * For 'experimental' modules, gives 'experimental' translation
@@ -768,7 +776,7 @@ class DolibarrModules           // Can not be abstract, because we need to insta
         }
     }
 
-    
+
     /**
      * Gives the last date of activation
      *
@@ -777,11 +785,11 @@ class DolibarrModules           // Can not be abstract, because we need to insta
     function getLastActivationDate()
     {
         global $conf;
-        
+
         $sql = "SELECT tms FROM ".MAIN_DB_PREFIX."const";
         $sql.= " WHERE ".$this->db->decrypt('name')." = '".$this->db->escape($this->const_name)."'";
         $sql.= " AND entity IN (0, ".$conf->entity.")";
-        
+
         dol_syslog(get_class($this)."::getLastActiveDate", LOG_DEBUG);
         $resql=$this->db->query($sql);
         if (! $resql) $err++;
@@ -790,11 +798,11 @@ class DolibarrModules           // Can not be abstract, because we need to insta
             $obj=$this->db->fetch_object($resql);
             if ($obj) return $this->db->jdate($obj->tms);
         }
-        
+
         return '';
     }
-    
-    
+
+
     /**
      * Gives the last author of activation
      *
@@ -803,11 +811,11 @@ class DolibarrModules           // Can not be abstract, because we need to insta
     function getLastActivationInfo()
     {
         global $conf;
-        
+
         $sql = "SELECT tms, note FROM ".MAIN_DB_PREFIX."const";
         $sql.= " WHERE ".$this->db->decrypt('name')." = '".$this->db->escape($this->const_name)."'";
         $sql.= " AND entity IN (0, ".$conf->entity.")";
-        
+
         dol_syslog(get_class($this)."::getLastActiveDate", LOG_DEBUG);
         $resql=$this->db->query($sql);
         if (! $resql) $err++;
@@ -821,11 +829,11 @@ class DolibarrModules           // Can not be abstract, because we need to insta
             }
             if ($obj) return array('authorid'=>$tmp['authorid'], 'ip'=>$tmp['ip'], 'lastactivationdate'=>$this->db->jdate($obj->tms));
         }
-        
+
         return array();
     }
-    
-    
+
+
     /**
      * Insert constants for module activation
      *
@@ -929,7 +937,7 @@ class DolibarrModules           // Can not be abstract, because we need to insta
                         $files[] = $file;
                     }
                     sort($files);
-                    foreach ($files as $file) 
+                    foreach ($files as $file)
                     {
                         if (preg_match('/\.sql$/i',$file) && ! preg_match('/\.key\.sql$/i',$file) && substr($file,0,4) == 'llx_' && substr($file,0,4) != 'data')
                         {
@@ -947,7 +955,7 @@ class DolibarrModules           // Can not be abstract, because we need to insta
                         $files[] = $file;
                     }
                     sort($files);
-                    foreach ($files as $file) 
+                    foreach ($files as $file)
                     {
                         if (preg_match('/\.key\.sql$/i',$file) && substr($file,0,4) == 'llx_' && substr($file,0,4) != 'data')
                         {
@@ -965,7 +973,7 @@ class DolibarrModules           // Can not be abstract, because we need to insta
                         $files[] = $file;
                     }
                     sort($files);
-                    foreach ($files as $file) 
+                    foreach ($files as $file)
                     {
                         if (preg_match('/\.sql$/i',$file) && ! preg_match('/\.key\.sql$/i',$file) && substr($file,0,4) == 'data')
                         {
@@ -983,7 +991,7 @@ class DolibarrModules           // Can not be abstract, because we need to insta
                         $files[] = $file;
                     }
                     sort($files);
-                    foreach ($files as $file) 
+                    foreach ($files as $file)
                     {
                         if (preg_match('/\.sql$/i',$file) && ! preg_match('/\.key\.sql$/i',$file) && substr($file,0,6) == 'update')
                         {
@@ -1123,19 +1131,19 @@ class DolibarrModules           // Can not be abstract, because we need to insta
                 //$titre = $this->boxes[$key][0];
                 $file  = $this->boxes[$key]['file'];
                 //$note  = $this->boxes[$key][2];
-                
+
                 // TODO If the box is also included by another module and the other module is still on, we should not remove it.
                 // For the moment, we manage this with hard coded exception
                 //print "Remove box ".$file.'<br>';
                 if ($file == 'box_graph_product_distribution.php')
                 {
-                    if (! empty($conf->produit->enabled) || ! empty($conf->service->enabled)) 
+                    if (! empty($conf->produit->enabled) || ! empty($conf->service->enabled))
                     {
                         dol_syslog("We discard disabling of module ".$file." because another module still active require it.");
                         continue;
                     }
                 }
-                
+
                 if (empty($file)) $file  = isset($this->boxes[$key][1])?$this->boxes[$key][1]:'';	// For backward compatibility
 
                 if ($this->db->type == 'sqlite3') {
@@ -1210,7 +1218,7 @@ class DolibarrModules           // Can not be abstract, because we need to insta
                 $status = isset($this->cronjobs[$key]['status'])?$this->cronjobs[$key]['status']:'';
                 $priority = isset($this->cronjobs[$key]['priority'])?$this->cronjobs[$key]['priority']:'';
                 $test = isset($this->cronjobs[$key]['test'])?$this->cronjobs[$key]['test']:'';                              // Line must be visible
-                
+
                 // Search if boxes def already present
                 $sql = "SELECT count(*) as nb FROM ".MAIN_DB_PREFIX."cronjob";
                 $sql.= " WHERE module_name = '".$this->db->escape($this->rights_class)."'";
@@ -1645,7 +1653,7 @@ class DolibarrModules           // Can not be abstract, because we need to insta
 
     /**
      * Removes access rights
-     * 
+     *
      * @return  int                     Error count (0 if OK)
      */
     function delete_permissions()
@@ -1678,7 +1686,7 @@ class DolibarrModules           // Can not be abstract, because we need to insta
         global $user;
 
         if (! is_array($this->menu) || empty($this->menu)) return 0;
-        
+
         require_once DOL_DOCUMENT_ROOT . '/core/class/menubase.class.php';
 
         $err=0;
diff --git a/htdocs/core/modules/contract/doc/doc_generic_contract_odt.modules.php b/htdocs/core/modules/contract/doc/doc_generic_contract_odt.modules.php
index a58d00455e89874dd49f4025058fec896762169b..64d0da9b5fd911acaa26c2851a9ebec8204468cd 100644
--- a/htdocs/core/modules/contract/doc/doc_generic_contract_odt.modules.php
+++ b/htdocs/core/modules/contract/doc/doc_generic_contract_odt.modules.php
@@ -102,16 +102,10 @@ class doc_generic_contract_odt extends ModelePDFContract
 		$form = new Form($this->db);
 
 		$texte = $this->description.".<br>\n";
-		$texte.= '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
+		$texte.= '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" enctype="multipart/form-data">';
 		$texte.= '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
 		$texte.= '<input type="hidden" name="action" value="setModuleOptions">';
 		$texte.= '<input type="hidden" name="param1" value="CONTRACT_ADDON_PDF_ODT_PATH">';
-		if ($conf->global->MAIN_PROPAL_CHOOSE_ODT_DOCUMENT > 0)
-		{
-			$texte.= '<input type="hidden" name="param2" value="CONTRACT_ADDON_PDF_ODT_DEFAULT">';
-			$texte.= '<input type="hidden" name="param3" value="CONTRACT_ADDON_PDF_ODT_TOBILL">';
-			$texte.= '<input type="hidden" name="param4" value="CONTRACT_ADDON_PDF_ODT_CLOSED">';
-		}
 		$texte.= '<table class="nobordernopadding" width="100%">';
 
 		// List of directories area
@@ -144,40 +138,21 @@ class doc_generic_contract_odt extends ModelePDFContract
 		$texte.=$conf->global->CONTRACT_ADDON_PDF_ODT_PATH;
 		$texte.= '</textarea>';
 		$texte.= '</div><div style="display: inline-block; vertical-align: middle;">';
-		$texte.= '<input type="submit" class="button" value="'.$langs->trans("Modify").'" name="Button">';
+		$texte.= '<input type="submit" class="button" value="'.dol_escape_htmltag($langs->trans("Modify")).'" name="Button">';
 		$texte.= '<br></div></div>';
 
 		// Scan directories
 		if (count($listofdir))
 		{
 			$texte.=$langs->trans("NumberOfModelFilesFound").': <b>'.count($listoffiles).'</b>';
-
-			if ($conf->global->MAIN_PROPAL_CHOOSE_ODT_DOCUMENT > 0)
-			{
-				// Model for creation
-				$liste=ModelePDFContract::liste_modeles($this->db);
-				$texte.= '<table width="50%;">';
-				$texte.= '<tr>';
-				$texte.= '<td width="60%;">'.$langs->trans("DefaultModelPropalCreate").'</td>';
-				$texte.= '<td colspan="">';
-				$texte.= $form->selectarray('value2',$liste,$conf->global->CONTRACT_ADDON_PDF_ODT_DEFAULT);
-				$texte.= "</td></tr>";
-
-				$texte.= '<tr>';
-				$texte.= '<td width="60%;">'.$langs->trans("DefaultModelPropalToBill").'</td>';
-				$texte.= '<td colspan="">';
-				$texte.= $form->selectarray('value3',$liste,$conf->global->CONTRACT_ADDON_PDF_ODT_TOBILL);
-				$texte.= "</td></tr>";
-				$texte.= '<tr>';
-
-				$texte.= '<td width="60%;">'.$langs->trans("DefaultModelPropalClosed").'</td>';
-				$texte.= '<td colspan="">';
-				$texte.= $form->selectarray('value4',$liste,$conf->global->CONTRACT_ADDON_PDF_ODT_CLOSED);
-				$texte.= "</td></tr>";
-				$texte.= '</table>';
-			}
 		}
 
+		// Add select to upload a new template file. TODO Copy this feature on other admin pages.
+		$texte.= '<div>'.$langs->trans("UploadNewTemplate").' <input type="file" name="uploadfile">';
+		$texte.= '<input type="hidden" value="CONTRACT_ADDON_PDF_ODT_PATH" name="keyforuploaddir">';
+		$texte.= '<input type="submit" class="button" value="'.dol_escape_htmltag($langs->trans("Upload")).'" name="upload">';
+        $texte.= '</div>';
+
 		$texte.= '</td>';
 
 		$texte.= '<td valign="top" rowspan="2" class="hideonsmartphone">';
diff --git a/htdocs/core/modules/contract/doc/pdf_strato.modules.php b/htdocs/core/modules/contract/doc/pdf_strato.modules.php
index 411b3deadf37e8c625e9d8f41906ad2f39c70ca8..c06882fa1214ea5a4474df407ba02e34408966aa 100644
--- a/htdocs/core/modules/contract/doc/pdf_strato.modules.php
+++ b/htdocs/core/modules/contract/doc/pdf_strato.modules.php
@@ -294,22 +294,25 @@ class pdf_strato extends ModelePDFContract
 						} else {
 							$datere = $langs->trans("Unknown");
 						}
-						
+
 						$txtpredefinedservice='';
-                        $txtpredefinedservice = $objectligne->product_ref;
+                        $txtpredefinedservice = $objectligne->product_label;
                         if ($objectligne->product_label)
                         {
                         	$txtpredefinedservice .= ' - ';
                         	$txtpredefinedservice .= $objectligne->product_label;
                         }
 
-						$txt='<strong>'.dol_htmlentitiesbr($outputlangs->transnoentities("DateStartPlannedShort")." : ".$datei." - ".$outputlangs->transnoentities("DateEndPlanned")." : ".$datee,1,$outputlangs->charset_output).'</strong>';
+						$desc=dol_htmlentitiesbr($objectligne->desc,1);   // Desc (not empty for free lines)
+						$txt='';
+						$txt.=$outputlangs->transnoentities("Quantity").' : <strong>'.$objectligne->qty.'</strong> - '.$outputlangs->transnoentities("UnitPrice").' : <strong>'.price($objectligne->subprice).'</strong>';   // Desc (not empty for free lines)
+						$txt.='<br>';
+						$txt.=$outputlangs->transnoentities("DateStartPlannedShort")." : <strong>".$datei."</strong> - ".$outputlangs->transnoentities("DateEndPlanned")." : <strong>".$datee.'</strong>';
 						$txt.='<br>';
-						$txt.='<strong>'.dol_htmlentitiesbr($outputlangs->transnoentities("DateStartRealShort")." : ".$daters,1,$outputlangs->charset_output);
-						if ($objectligne->date_cloture) $txt.=dol_htmlentitiesbr(" - ".$outputlangs->transnoentities("DateEndRealShort")." : ".$datere,1,$outputlangs->charset_output).'</strong>';
-						$desc=dol_htmlentitiesbr($objectligne->desc,1);
+                        $txt.=$outputlangs->transnoentities("DateStartRealShort")." : <strong>".$daters.'</strong>';
+						if ($objectligne->date_cloture) $txt.=" - ".$outputlangs->transnoentities("DateEndRealShort")." : '<strong>'".$datere.'</strong>';
 
-						$pdf->writeHTMLCell(0, 0, $curX, $curY, dol_concatdesc($txt,dol_concatdesc($txtpredefinedservice,$desc)), 0, 1, 0);
+						$pdf->writeHTMLCell(0, 0, $curX, $curY, dol_concatdesc($txtpredefinedservice, dol_concatdesc($txt, $desc)), 0, 1, 0);
 
 						$nexY = $pdf->GetY() + 2;
 						$pageposafter=$pdf->getPage();
diff --git a/htdocs/don/admin/donation.php b/htdocs/don/admin/donation.php
index c8d8be2461de9cdcf28b695199417df0c75236c2..2ca1cba1083932d090c20dfac151a47898aaeeb6 100644
--- a/htdocs/don/admin/donation.php
+++ b/htdocs/don/admin/donation.php
@@ -121,7 +121,7 @@ else if ($action == 'del')
 // Options
 if ($action == 'set_DONATION_ACCOUNTINGACCOUNT')
 {
-	$account = GETPOST('DONATION_ACCOUNTINGACCOUNT');	// No alpha here, we want exact string
+	$account = GETPOST('DONATION_ACCOUNTINGACCOUNT','alpha');
 
     $res = dolibarr_set_const($db, "DONATION_ACCOUNTINGACCOUNT",$account,'chaine',0,'',$conf->entity);
 
@@ -139,7 +139,7 @@ if ($action == 'set_DONATION_ACCOUNTINGACCOUNT')
 
 if ($action == 'set_DONATION_MESSAGE')
 {
-	$freemessage = GETPOST('DONATION_MESSAGE');	// No alpha here, we want exact string
+	$freemessage = GETPOST('DONATION_MESSAGE','none');	// No alpha here, we want exact string
 
     $res = dolibarr_set_const($db, "DONATION_MESSAGE",$freemessage,'chaine',0,'',$conf->entity);
 
diff --git a/htdocs/filefunc.inc.php b/htdocs/filefunc.inc.php
index c7268680f19adda88de437d5af6d7d6b6a042ac0..2bb2121411f6f527b7143bf0f111773bc4a4059a 100644
--- a/htdocs/filefunc.inc.php
+++ b/htdocs/filefunc.inc.php
@@ -31,7 +31,7 @@
  */
 
 if (! defined('DOL_APPLICATION_TITLE')) define('DOL_APPLICATION_TITLE','Dolibarr');
-if (! defined('DOL_VERSION')) define('DOL_VERSION','6.0.0-alpha');		// a.b.c-alpha, a.b.c-beta, a.b.c-rcX or a.b.c
+if (! defined('DOL_VERSION')) define('DOL_VERSION','6.0.0-beta');		// a.b.c-alpha, a.b.c-beta, a.b.c-rcX or a.b.c
 
 if (! defined('EURO')) define('EURO',chr(128));
 
diff --git a/htdocs/install/mysql/migration/5.0.0-6.0.0.sql b/htdocs/install/mysql/migration/5.0.0-6.0.0.sql
index f8b638b079a0508f25a02c98e78c5980b3d7b5b1..d7e683465110ee9b809d992735ea47ba1d00d8f6 100644
--- a/htdocs/install/mysql/migration/5.0.0-6.0.0.sql
+++ b/htdocs/install/mysql/migration/5.0.0-6.0.0.sql
@@ -159,6 +159,9 @@ CREATE TABLE llx_product_attribute_combination
 
 ALTER TABLE llx_bank_account drop foreign key bank_fk_accountancy_journal;
 
+-- Fix missing entity column after init demo
+ALTER TABLE llx_accounting_journal ADD COLUMN entity integer DEFAULT 1;
+
 -- Add journal entries
 INSERT INTO llx_accounting_journal (rowid, code, label, nature, active) VALUES (1,'VT', 'Sale journal', 2, 1);
 INSERT INTO llx_accounting_journal (rowid, code, label, nature, active) VALUES (2,'AC', 'Purchase journal', 3, 1);
@@ -348,5 +351,31 @@ ALTER TABLE llx_facture ADD COLUMN fk_fac_rec_source integer;
 
 DELETE from llx_c_actioncomm where code in ('AC_PROP','AC_COM','AC_FAC','AC_SHIP','AC_SUP_ORD','AC_SUP_INV') AND id NOT IN (SELECT DISTINCT fk_action FROM llx_actioncomm);
 
+-- Fix: delete orphelin category.
+delete from llx_categorie_product where fk_categorie not in (select rowid from llx_categorie where type = 0);
+delete from llx_categorie_societe where fk_categorie not in (select rowid from llx_categorie where type in (1, 2));
+delete from llx_categorie_member where fk_categorie not in (select rowid from llx_categorie where type = 3);
+delete from llx_categorie_contact where fk_categorie not in (select rowid from llx_categorie where type = 4);
+delete from llx_categorie_project where fk_categorie not in (select rowid from llx_categorie where type = 5);
+
+ALTER TABLE llx_inventory ADD COLUMN ref varchar(48);
+
+create table llx_loan_schedule
+(
+  rowid				integer AUTO_INCREMENT PRIMARY KEY,
+  fk_loan			integer,
+  datec				datetime,         
+  tms				timestamp,
+  datep				datetime,         
+  amount_capital	real DEFAULT 0,
+  amount_insurance	real DEFAULT 0,
+  amount_interest	real DEFAULT 0,
+  fk_typepayment	integer NOT NULL,
+  num_payment		varchar(50),
+  note_private      text,
+  note_public       text,
+  fk_bank			integer NOT NULL,
+  fk_user_creat		integer,          
+  fk_user_modif		integer           
+)ENGINE=innodb;
 
-ALTER TABLE llx_inventory ADD COLUMN ref varchar(48);
\ No newline at end of file
diff --git a/htdocs/install/mysql/migration/repair.sql b/htdocs/install/mysql/migration/repair.sql
index 6ff7356847f8abcba7aafc84d05d112b79266c0c..c748f38acb3ec9f07d0a232cf74209b4b4895edc 100755
--- a/htdocs/install/mysql/migration/repair.sql
+++ b/htdocs/install/mysql/migration/repair.sql
@@ -28,7 +28,7 @@
 
 
 
--- Requests to clean corrupted database
+-- Requests to clean corrupted data
 
 
 UPDATE llx_user set api_key = null where api_key = '';
@@ -124,6 +124,7 @@ delete from llx_categorie_product where fk_categorie not in (select rowid from l
 delete from llx_categorie_societe where fk_categorie not in (select rowid from llx_categorie where type in (1, 2));
 delete from llx_categorie_member where fk_categorie not in (select rowid from llx_categorie where type = 3);
 delete from llx_categorie_contact where fk_categorie not in (select rowid from llx_categorie where type = 4);
+delete from llx_categorie_project where fk_categorie not in (select rowid from llx_categorie where type = 5);
 
 
 -- Fix: delete orphelin deliveries. Note: deliveries are linked to shipment by llx_element_element only. No other links.
@@ -337,3 +338,8 @@ drop table tmp_c_shipment_mode;
 -- VMYSQL4.1 update llx_expensereport_det as ed set date = (select date_debut from llx_expensereport as e where ed.fk_expensereport = e.rowid) where DATE(STR_TO_DATE(date, '%Y-%m-%d')) < '1000-00-00';
 -- VMYSQL4.1 SET sql_mode = 'NO_ZERO_DATE';
 
+
+-- Backport a change of value into the hourly rate. 
+-- update llx_projet_task_time as ptt set ptt.thm = (SELECT thm from llx_user as u where ptt.fk_user = u.rowid) where (ptt.thm is null)
+
+  
\ No newline at end of file
diff --git a/htdocs/install/mysql/tables/llx_advtargetemailing.sql b/htdocs/install/mysql/tables/llx_advtargetemailing.sql
index d22503bb54836e6a3ed0abe876d87c15506043c5..7e95f6b80976333b3b70dd6afbc3e32a6fd6a741 100644
--- a/htdocs/install/mysql/tables/llx_advtargetemailing.sql
+++ b/htdocs/install/mysql/tables/llx_advtargetemailing.sql
@@ -28,4 +28,4 @@ CREATE TABLE llx_advtargetemailing
   datec datetime NOT NULL,
   fk_user_mod integer NOT NULL,
   tms timestamp NOT NULL
-)ENGINE=InnoDB;
+)ENGINE=innodb;
diff --git a/htdocs/install/mysql/tables/llx_loan_schedule.sql b/htdocs/install/mysql/tables/llx_loan_schedule.sql
new file mode 100644
index 0000000000000000000000000000000000000000..c682b22f276150f132f13275976e0f11bd397d45
--- /dev/null
+++ b/htdocs/install/mysql/tables/llx_loan_schedule.sql
@@ -0,0 +1,37 @@
+-- ===================================================================
+-- Copyright (C) 2014		Alexandre Spangaro   <aspangaro.dolibarr@gmail.com>
+-- Copyright (C) 2015       Frederic France      <frederic.france@free.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
+-- the Free Software Foundation; either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see <http://www.gnu.org/licenses/>.
+--
+-- ===================================================================
+
+create table llx_loan_schedule
+(
+  rowid				integer AUTO_INCREMENT PRIMARY KEY,
+  fk_loan			integer,
+  datec				datetime,         -- creation date
+  tms				timestamp,
+  datep				datetime,         -- payment date
+  amount_capital	real DEFAULT 0,
+  amount_insurance	real DEFAULT 0,
+  amount_interest	real DEFAULT 0,
+  fk_typepayment	integer NOT NULL,
+  num_payment		varchar(50),
+  note_private      text,
+  note_public       text,
+  fk_bank			integer NOT NULL,
+  fk_user_creat		integer,          -- creation user
+  fk_user_modif		integer           -- last modification user
+)ENGINE=innodb;
diff --git a/htdocs/install/mysql/tables/llx_product_attribute.sql b/htdocs/install/mysql/tables/llx_product_attribute.sql
index 77c045327b8d6d38f87417c00f8951219fab9aba..cb655508e89b553103f818aeaaef7ee7c0e6e5fb 100644
--- a/htdocs/install/mysql/tables/llx_product_attribute.sql
+++ b/htdocs/install/mysql/tables/llx_product_attribute.sql
@@ -23,4 +23,4 @@ CREATE TABLE llx_product_attribute
   label VARCHAR(255) NOT NULL,
   rang INT DEFAULT 0 NOT NULL,
   entity INT DEFAULT 1 NOT NULL
-);
+)ENGINE=innodb;
diff --git a/htdocs/install/mysql/tables/llx_product_attribute_combination.sql b/htdocs/install/mysql/tables/llx_product_attribute_combination.sql
index fae38f8403d9cdd4e4146010523f49e6c29a1dab..85c46706014a4399598e159f68846eb63f3928e1 100644
--- a/htdocs/install/mysql/tables/llx_product_attribute_combination.sql
+++ b/htdocs/install/mysql/tables/llx_product_attribute_combination.sql
@@ -25,4 +25,4 @@ CREATE TABLE llx_product_attribute_combination
   variation_price_percentage INT NULL,
   variation_weight FLOAT NOT NULL,
   entity INT DEFAULT 1 NOT NULL
-);
\ No newline at end of file
+)ENGINE=innodb;
\ No newline at end of file
diff --git a/htdocs/install/mysql/tables/llx_product_attribute_combination2val.sql b/htdocs/install/mysql/tables/llx_product_attribute_combination2val.sql
index a64230923e60cbab732a77e65bb24436943e41b7..af0da7f710d504b313ae78c4ab26e8867aef6d84 100644
--- a/htdocs/install/mysql/tables/llx_product_attribute_combination2val.sql
+++ b/htdocs/install/mysql/tables/llx_product_attribute_combination2val.sql
@@ -22,4 +22,4 @@ CREATE TABLE llx_product_attribute_combination2val
   fk_prod_combination INT NOT NULL,
   fk_prod_attr INT NOT NULL,
   fk_prod_attr_val INT NOT NULL
-);
\ No newline at end of file
+)ENGINE=innodb;
\ No newline at end of file
diff --git a/htdocs/install/mysql/tables/llx_product_attribute_value.sql b/htdocs/install/mysql/tables/llx_product_attribute_value.sql
index ebd2cf8bb4928c6e5c44851b56dbd6fb330cf1cc..8ca6888d91b7fef7c5b0b6b9b70403ca7295d7ba 100644
--- a/htdocs/install/mysql/tables/llx_product_attribute_value.sql
+++ b/htdocs/install/mysql/tables/llx_product_attribute_value.sql
@@ -23,4 +23,4 @@ CREATE TABLE llx_product_attribute_value
   ref VARCHAR(255) DEFAULT NULL,
   value VARCHAR(255) DEFAULT NULL,
   entity INT DEFAULT 1 NOT NULL
-);
\ No newline at end of file
+)ENGINE=innodb;
\ No newline at end of file
diff --git a/htdocs/install/mysql/tables/llx_product_pricerules.sql b/htdocs/install/mysql/tables/llx_product_pricerules.sql
index 3e3dfc02ed19394e610d68ec027761fe13e13e84..3cf58c9585f52152df4385e1b0e826019c41dc60 100644
--- a/htdocs/install/mysql/tables/llx_product_pricerules.sql
+++ b/htdocs/install/mysql/tables/llx_product_pricerules.sql
@@ -23,4 +23,4 @@ CREATE TABLE llx_product_pricerules
     fk_level INT NOT NULL, -- Price variations are made over price of X
     var_percent FLOAT NOT NULL, -- Price variation over based price
     var_min_percent FLOAT NOT NULL -- Min price discount over general price
-);
\ No newline at end of file
+)ENGINE=innodb;
diff --git a/htdocs/install/upgrade2.php b/htdocs/install/upgrade2.php
index 264a45bca9146980bda0a8ff28dc4b1a88baf213..19195e170009f18ac2f3332306fa6a2e8fd85fd1 100644
--- a/htdocs/install/upgrade2.php
+++ b/htdocs/install/upgrade2.php
@@ -413,10 +413,10 @@ if (! GETPOST('action','aZ09') || preg_match('/upgrade/i',GETPOST('action','aZ09
         {
             // Migrate to add entity value into llx_societe_remise
             migrate_remise_entity($db,$langs,$conf);
-        
+
             // Migrate to add entity value into llx_societe_remise_except
             migrate_remise_except_entity($db,$langs,$conf);
-        
+
             // Reload modules (this must be always and only into last targeted version)
             $listofmodule=array(
                 'MAIN_MODULE_ACCOUNTING'=>'newboxdefonly',
@@ -441,11 +441,11 @@ if (! GETPOST('action','aZ09') || preg_match('/upgrade/i',GETPOST('action','aZ09
                 'MAIN_MODULE_USER'=>'newboxdefonly',
             );
             migrate_reload_modules($db,$langs,$conf,$listofmodule);
-        
+
             // Reload menus (this must be always and only into last targeted version)
             migrate_reload_menu($db,$langs,$conf,$versionto);
         }
-        
+
         // Can force activation of some module during migration with third paramater = MAIN_MODULE_XXX,MAIN_MODULE_YYY,...
         if ($enablemodules)
         {
@@ -471,8 +471,8 @@ if (! GETPOST('action','aZ09') || preg_match('/upgrade/i',GETPOST('action','aZ09
         // Actions for all versions (not in database)
         migrate_delete_old_files($db, $langs, $conf);
         migrate_delete_old_dir($db, $langs, $conf);
-        
-        
+
+
         dol_mkdir(DOL_DATA_ROOT.'/bank');
         migrate_directories($db, $langs, $conf, '/banque/bordereau', '/bank/checkdeposits');
     }
@@ -3942,10 +3942,13 @@ function migrate_delete_old_files($db,$langs,$conf)
     DOL_DOCUMENT_ROOT.'/core/modules/mailings/kiwi.modules.php',
     DOL_DOCUMENT_ROOT.'/core/modules/facture/pdf_crabe.modules.php',
     DOL_DOCUMENT_ROOT.'/core/modules/facture/pdf_oursin.modules.php',
-    
+
     DOL_DOCUMENT_ROOT.'/compta/facture/class/api_invoice.class.php',
     DOL_DOCUMENT_ROOT.'/commande/class/api_commande.class.php',
-    DOL_DOCUMENT_ROOT.'/user/class/api_user.class.php'
+    DOL_DOCUMENT_ROOT.'/user/class/api_user.class.php',
+    DOL_DOCUMENT_ROOT.'/product/class/api_product.class.php',
+    DOL_DOCUMENT_ROOT.'/societe/class/api_contact.class.php',
+    DOL_DOCUMENT_ROOT.'/societe/class/api_thirdparty.class.php'
     );
 
     foreach ($filetodeletearray as $filetodelete)
diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang
index fe54793190808e189f571eca24b6e74b7689719e..fe292db145dade0150c9e2340125ee8dcf5c22d4 100644
--- a/htdocs/langs/en_US/admin.lang
+++ b/htdocs/langs/en_US/admin.lang
@@ -48,6 +48,7 @@ InternalUsers=Internal users
 ExternalUsers=External users
 GUISetup=Display
 SetupArea=Setup area
+UploadNewTemplate=Upload new template(s)
 FormToTestFileUploadForm=Form to test file upload (according to setup)
 IfModuleEnabled=Note: yes is effective only if module <b>%s</b> is enabled
 RemoveLock=Remove file <b>%s</b> if it exists to allow usage of the update tool.
@@ -613,7 +614,7 @@ Permission32=Create/modify products
 Permission34=Delete products
 Permission36=See/manage hidden products
 Permission38=Export products
-Permission41=Read projects and tasks (shared project and projects i'm contact for). Can also enter time consumed on assigned tasks (timesheet)
+Permission41=Read projects and tasks (shared project and projects i'm contact for). Can also enter time consumed, for me or my hierarchy, on assigned tasks (Timesheet)
 Permission42=Create/modify projects (shared project and projects i'm contact for). Can also create tasks and assign users to project and tasks
 Permission44=Delete projects (shared project and projects i'm contact for)
 Permission45=Export projects
@@ -873,6 +874,7 @@ DictionaryProspectStatus=Prospection status
 DictionaryHolidayTypes=Types of leaves
 DictionaryOpportunityStatus=Opportunity status for project/lead
 SetupSaved=Setup saved
+SetupNotSaved=Setup not saved
 BackToModuleList=Back to modules list
 BackToDictionaryList=Back to dictionaries list
 VATManagement=VAT Management
diff --git a/htdocs/langs/en_US/errors.lang b/htdocs/langs/en_US/errors.lang
index 740397a5044c9149340cba3ae8d7320f8b96b7f4..0f49bd832d6c6ea44473eb903eca8ef9214287f9 100644
--- a/htdocs/langs/en_US/errors.lang
+++ b/htdocs/langs/en_US/errors.lang
@@ -190,6 +190,7 @@ ErrorModuleFileSeemsToHaveAWrongFormat=The module package seems to have a wrong
 ErrorFilenameDosNotMatchDolibarrPackageRules=The name of the module package (<strong>%s</strong>) does not match expected name syntax: <strong>%s</strong>
 ErrorDuplicateTrigger=Error, duplicate trigger name %s. Already loaded from %s.
 ErrorNoWarehouseDefined=Error, no warehouses defined.
+ErrorBadLinkSourceSetButBadValueForRef=The link you use is not valid. A 'source' for payment is defined, but value for 'ref' is not valid. 
 
 # Warnings
 WarningPasswordSetWithNoAccount=A password was set for this member. However, no user account was created. So this password is stored but can't be used to login to Dolibarr. It may be used by an external module/interface but if you don't need to define any login nor password for a member, you can disable option "Manage a login for each member" from Member module setup. If you need to manage a login but don't need any password, you can keep this field empty to avoid this warning. Note: Email can also be used as a login if the member is linked to a user.  
diff --git a/htdocs/langs/en_US/loan.lang b/htdocs/langs/en_US/loan.lang
index 927aab2abf4a86ad3a97b04ed4c65202d99277f6..d00b11738be75484b24da384c4695e3211f8064c 100644
--- a/htdocs/langs/en_US/loan.lang
+++ b/htdocs/langs/en_US/loan.lang
@@ -50,3 +50,4 @@ ConfigLoan=Configuration of the module loan
 LOAN_ACCOUNTING_ACCOUNT_CAPITAL=Accounting account capital by default
 LOAN_ACCOUNTING_ACCOUNT_INTEREST=Accounting account interest by default
 LOAN_ACCOUNTING_ACCOUNT_INSURANCE=Accounting account insurance by default
+CreateCalcSchedule=Créer / Modifier échéancier de pret
diff --git a/htdocs/langs/en_US/projects.lang b/htdocs/langs/en_US/projects.lang
index c98c2120e2198ca80f35e1652faa0742f56c801c..b3317df9c8efddb47bf33dc8796a34b1cc324231 100644
--- a/htdocs/langs/en_US/projects.lang
+++ b/htdocs/langs/en_US/projects.lang
@@ -41,6 +41,7 @@ ShowProject=Show project
 SetProject=Set project
 NoProject=No project defined or owned
 NbOfProjects=Nb of projects
+NbOfTasks=Nb of tasks
 TimeSpent=Time spent
 TimeSpentByYou=Time spent by you
 TimeSpentByUser=Time spent by user
@@ -53,7 +54,7 @@ TaskTimeNote=Note
 TaskTimeDate=Date
 TasksOnOpenedProject=Tasks on open projects
 WorkloadNotDefined=Workload not defined
-NewTimeSpent=New time spent
+NewTimeSpent=Time spent
 MyTimeSpent=My time spent
 Tasks=Tasks
 Task=Task
@@ -107,6 +108,7 @@ ConfirmReOpenAProject=Are you sure you want to re-open this project?
 ProjectContact=Project contacts
 ActionsOnProject=Events on project
 YouAreNotContactOfProject=You are not a contact of this private project
+UserIsNotContactOfProject=User is not a contact of this private project
 DeleteATimeSpent=Delete time spent
 ConfirmDeleteATimeSpent=Are you sure you want to delete this time spent?
 DoNotShowMyTasksOnly=See also tasks not assigned to me
@@ -115,7 +117,7 @@ TaskRessourceLinks=Resources
 ProjectsDedicatedToThisThirdParty=Projects dedicated to this third party
 NoTasks=No tasks for this project
 LinkedToAnotherCompany=Linked to other third party
-TaskIsNotAffectedToYou=Task not assigned to you
+TaskIsNotAssignedToUser=Task not assigned to user. Use button '<strong>%s</strong>' to assign task now. 
 ErrorTimeSpentIsEmpty=Time spent is empty
 ThisWillAlsoRemoveTasks=This action will also delete all tasks of project (<b>%s</b> tasks at the moment) and all inputs of time spent.
 IfNeedToUseOhterObjectKeepEmpty=If some objects (invoice, order, ...), belonging to another third party, must be linked to the project to create, keep this empty to have the project being multi third parties.
@@ -166,26 +168,30 @@ FirstAddRessourceToAllocateTime=Assign a user resource to task to allocate time
 InputPerDay=Input per day
 InputPerWeek=Input per week
 InputPerAction=Input per action
-TimeAlreadyRecorded=Time spent already recorded for this task/day and user %s
+TimeAlreadyRecorded=This is time spent already recorded for this task/day and user %s
 ProjectsWithThisUserAsContact=Projects with this user as contact
 TasksWithThisUserAsContact=Tasks assigned to this user
 ResourceNotAssignedToProject=Not assigned to project
 ResourceNotAssignedToTheTask=Not assigned to the task
 TasksAssignedTo=Tasks assigned to
 AssignTaskToMe=Assign task to me
+AssignTaskToUser=Assign task to %s
+SelectTaskToAssign=Select task to assign...
 AssignTask=Assign
 ProjectOverview=Overview
 ManageTasks=Use projects to follow tasks and time
 ManageOpportunitiesStatus=Use projects to follow leads/opportinuties
 ProjectNbProjectByMonth=Nb of created projects by month
+ProjectNbTaskByMonth=Nb of created tasks by month
 ProjectOppAmountOfProjectsByMonth=Amount of opportunities by month
 ProjectWeightedOppAmountOfProjectsByMonth=Weighted amount of opportunities by month
 ProjectOpenedProjectByOppStatus=Open project/lead by opportunity status
 ProjectsStatistics=Statistics on projects/leads
+TasksStatistics=Statistics on project/lead tasks
 TaskAssignedToEnterTime=Task assigned. Entering time on this task should be possible.
 IdTaskTime=Id task time
 YouCanCompleteRef=If you want to complete the ref with some information (to use it as search filters), it is recommanded to add a - character to separate it, so the automatic numbering will still work correctly for next projects. For example %s-ABC. You may also prefer to add search keys into label. But best practice may be to add a dedicated field, also called complementary attributes.
-OpenedProjectsByThirdparties=Open projects by thirdparties
+OpenedProjectsByThirdparties=Open projects by third parties
 OnlyOpportunitiesShort=Only opportunities
 OpenedOpportunitiesShort=Open opportunities
 NotAnOpportunityShort=Not an opportunity
diff --git a/htdocs/loan/calcmens.php b/htdocs/loan/calcmens.php
new file mode 100644
index 0000000000000000000000000000000000000000..96c8b5204b88d402ed89c844d62d74b19791b9c6
--- /dev/null
+++ b/htdocs/loan/calcmens.php
@@ -0,0 +1,72 @@
+<?php
+/* TVI
+ * Copyright (C) 2015	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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * \file tvi/ajax/list.php
+ * \brief File to return datables output
+ */
+if (! defined('NOTOKENRENEWAL'))
+	define('NOTOKENRENEWAL', '1'); // Disables token renewal
+if (! defined('NOREQUIREMENU'))
+	define('NOREQUIREMENU', '1');
+	// if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML','1');
+if (! defined('NOREQUIREAJAX'))
+	define('NOREQUIREAJAX', '1');
+	// if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC','1');
+	// if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN','1');
+
+
+require '../main.inc.php';
+require DOL_DOCUMENT_ROOT.'/loan/class/loanschedule.class.php';
+
+$mens=GETPOST('mens');
+$capital=GETPOST('capital');
+$rate=GETPOST('rate');
+$echance=GETPOST('echeance');
+$nbterm=GETPOST('nbterm');
+
+top_httphead();
+
+$output=array();
+
+$object = new LoanSchedule($db);
+
+$int = ($capital*($rate/12));
+$int = round($int,2,PHP_ROUND_HALF_UP);
+$cap_rest = round($capital - ($mens-$int),2,PHP_ROUND_HALF_UP);
+$output[$echance]=array('cap_rest'=>$cap_rest,'cap_rest_str'=>price($cap_rest),'interet'=>$int,'interet_str'=>price($int,0,'',1),'mens'=>$mens);
+
+$echance++;
+$capital=$cap_rest;
+while ($echance<=$nbterm) {
+
+	$mens = round($object->calc_mens($capital,$rate,$nbterm-$echance+1),2,PHP_ROUND_HALF_UP);
+
+	$int = ($capital*($rate/12));
+	$int = round($int,2,PHP_ROUND_HALF_UP);
+	$cap_rest = round($capital - ($mens-$int),2,PHP_ROUND_HALF_UP);
+
+	$output[$echance]=array('cap_rest'=>$cap_rest,'cap_rest_str'=>price($cap_rest),'interet'=>$int,'interet_str'=>price($int,0,'',1),'mens'=>$mens);
+
+	$capital=$cap_rest;
+	$echance++;
+}
+
+echo json_encode($output);
+
diff --git a/htdocs/loan/card.php b/htdocs/loan/card.php
index 81d43e46ab0bcd0d78b0d42ac8ce92131ba72151..557d48be6802a2e1622ce7debd6eff2ca7f4881b 100644
--- a/htdocs/loan/card.php
+++ b/htdocs/loan/card.php
@@ -72,7 +72,7 @@ if (empty($reshook))
             setEventMessages($loan->error, null, 'errors');
         }
     }
-    
+
     // Delete loan
     if ($action == 'confirm_delete' && $confirm == 'yes')
     {
@@ -89,7 +89,7 @@ if (empty($reshook))
     		setEventMessages($loan->error, null, 'errors');
     	}
     }
-    
+
     // Add loan
     if ($action == 'add' && $user->rights->loan->write)
     {
@@ -99,7 +99,7 @@ if (empty($reshook))
     		$dateend	= dol_mktime(12, 0, 0, GETPOST('endmonth','int'), GETPOST('endday','int'), GETPOST('endyear','int'));
     		$capital 	= price2num(GETPOST('capital'));
             $rate       = GETPOST('rate');
-            
+
     		if (! $capital)
     		{
     		    $error++; $action = 'create';
@@ -120,7 +120,7 @@ if (empty($reshook))
     		    $error++; $action = 'create';
     		    setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Rate")), null, 'errors');
     		}
-    		
+
     		if (! $error)
     		{
     			$object->label					= GETPOST('label');
@@ -133,15 +133,15 @@ if (empty($reshook))
     			$object->note_private 			= GETPOST('note_private');
     			$object->note_public 			= GETPOST('note_public');
     			$object->fk_project 			= GETPOST('fk_project');
-    			
+
     			$accountancy_account_capital	= GETPOST('accountancy_account_capital');
     			$accountancy_account_insurance	= GETPOST('accountancy_account_insurance');
     			$accountancy_account_interest	= GETPOST('accountancy_account_interest');
-    
+
     			if ($accountancy_account_capital <= 0) { $object->account_capital = ''; } else { $object->account_capital = $accountancy_account_capital; }
     			if ($accountancy_account_insurance <= 0) { $object->account_insurance = ''; } else { $object->account_insurance = $accountancy_account_insurance; }
     			if ($accountancy_account_interest <= 0) { $object->account_interest = ''; } else { $object->account_interest = $accountancy_account_interest; }
-    
+
     			$id=$object->create($user);
     			if ($id <= 0)
     			{
@@ -157,7 +157,7 @@ if (empty($reshook))
     		exit();
     	}
     }
-    
+
     // Update record
     else if ($action == 'update' && $user->rights->loan->write)
     {
@@ -168,7 +168,7 @@ if (empty($reshook))
     		$datestart	= dol_mktime(12, 0, 0, GETPOST('startmonth','int'), GETPOST('startday','int'), GETPOST('startyear','int'));
     		$dateend	= dol_mktime(12, 0, 0, GETPOST('endmonth','int'), GETPOST('endday','int'), GETPOST('endyear','int'));
     		$capital 	= price2num(GETPOST('capital'));
-    
+
     		if (! $capital)
     		{
     			setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("LoanCapital")), null, 'errors');
@@ -185,14 +185,14 @@ if (empty($reshook))
 				$accountancy_account_capital	= GETPOST('accountancy_account_capital');
 				$accountancy_account_insurance	= GETPOST('accountancy_account_insurance');
 				$accountancy_account_interest	= GETPOST('accountancy_account_interest');
-	
+
 				if ($accountancy_account_capital <= 0) { $object->account_capital = ''; } else { $object->account_capital = $accountancy_account_capital; }
 				if ($accountancy_account_insurance <= 0) { $object->account_insurance = ''; } else { $object->account_insurance = $accountancy_account_insurance; }
 				if ($accountancy_account_interest <= 0) { $object->account_interest = ''; } else { $object->account_interest = $accountancy_account_interest; }
     		}
-    
+
             $result = $object->update($user);
-    
+
             if ($result > 0)
             {
                 header("Location: " . $_SERVER["PHP_SELF"] . "?id=" . $id);
@@ -209,7 +209,7 @@ if (empty($reshook))
             exit;
         }
     }
-    
+
 	// Link to a project
 	if ($action == 'classin' && $user->rights->loan->write)
 	{
@@ -307,12 +307,12 @@ if ($action == 'create')
 		$langs->load("projects");
 
     	print '<tr><td>'.$langs->trans("Project").'</td><td>';
-        
+
         $numproject=$formproject->select_projects(-1,GETPOST("fk_project"),'fk_project',16,0,1,1);
-        
+
         print '</td></tr>';
     }
-    
+
     // Note Private
     print '<tr>';
     print '<td class="tdtop">'.$langs->trans('NotePrivate').'</td>';
@@ -352,7 +352,7 @@ if ($action == 'create')
 		print $formaccounting->select_account($object->accountancy_account_interest, 'accountancy_account_interest', 1, '', 0, 1);
         print '</td></tr>';
 	}
-	else // For external software 
+	else // For external software
 	{
         // Accountancy_account_capital
         print '<tr><td class="titlefieldcreate">'.$langs->trans("LoanAccountancyCapitalCode").'</td>';
@@ -417,10 +417,22 @@ if ($id > 0)
 
 		dol_fiche_head($head, 'card', $langs->trans("Loan"), 0, 'bill');
 
+		print '<script type="text/javascript">' . "\n";
+		print '  	function popEcheancier() {' . "\n";
+		print '  		$div = $(\'<div id="popCalendar"><iframe width="100%" height="100%" frameborder="0" src="createschedule.php?loanid=' . $object->id . '"></iframe></div>\');' . "\n";
+		print '  		$div.dialog({' . "\n";
+		print '  			modal:true' . "\n";
+		print '  			,width:"90%"' . "\n";
+		print '  			,height:$(window).height() - 150' . "\n";
+		print '  		});' . "\n";
+		print '  	}' . "\n";
+		print '</script>';
+
+
 		// Loan card
-		
+
 		$linkback = '<a href="' . DOL_URL_ROOT . '/loan/index.php">' . $langs->trans("BackToList") . '</a>';
-		
+
 		$morehtmlref='<div class="refidno">';
 		// Ref loan
 		$morehtmlref.=$form->editfieldkey("Label", 'label', $object->label, $object, $user->rights->loan->write, 'string', '', 0, 1);
@@ -458,7 +470,7 @@ if ($id > 0)
 	        }
 	    }
 	    $morehtmlref.='</div>';
-		
+
 		$object->totalpaid = $totalpaid;   // To give a chance to dol_banner_tab to use already paid amount to show correct status
 
 		dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'ref', $morehtmlref, '', 0, '', $morehtmlright);
@@ -652,7 +664,7 @@ if ($id > 0)
 			while ($i < $num)
 			{
 				$objp = $db->fetch_object($resql);
-				
+
 				print '<tr class="oddeven">';
 				print '<td><a href="'.DOL_URL_ROOT.'/loan/payment/card.php?id='.$objp->rowid.'">'.img_object($langs->trans("Payment"),"payment").' '.$objp->rowid.'</a></td>';
 				print '<td>'.dol_print_date($db->jdate($objp->dp),'day')."</td>\n";
@@ -713,31 +725,33 @@ if ($id > 0)
  			if (empty($reshook))
             {
                 print '<div class="tabsAction">';
-    
+
     			// Edit
     			if ($user->rights->loan->write)
     			{
+    				print '<a href="javascript:popEcheancier()" class="butAction">'.$langs->trans('CreateCalcSchedule').'</a>';
+
     				print '<a class="butAction" href="'.DOL_URL_ROOT.'/loan/card.php?id='.$object->id.'&amp;action=edit">'.$langs->trans("Modify").'</a>';
     			}
-    
+
     			// Emit payment
     			if ($object->paid == 0 && ((price2num($object->capital) > 0 && round($staytopay) < 0) || (price2num($object->capital) > 0 && round($staytopay) > 0)) && $user->rights->loan->write)
     			{
     				print '<a class="butAction" href="'.DOL_URL_ROOT.'/loan/payment/payment.php?id='.$object->id.'&amp;action=create">'.$langs->trans("DoPayment").'</a>';
     			}
-    
+
     			// Classify 'paid'
     			if ($object->paid == 0 && round($staytopay) <=0 && $user->rights->loan->write)
     			{
     				print '<a class="butAction" href="'.DOL_URL_ROOT.'/loan/card.php?id='.$object->id.'&amp;action=paid">'.$langs->trans("ClassifyPaid").'</a>';
     			}
-    
+
     			// Delete
     			if ($user->rights->loan->delete)
     			{
     				print '<a class="butActionDelete" href="'.DOL_URL_ROOT.'/loan/card.php?id='.$object->id.'&amp;action=delete">'.$langs->trans("Delete").'</a>';
     			}
-    
+
     			print "</div>";
             }
 		}
diff --git a/htdocs/loan/class/loanschedule.class.php b/htdocs/loan/class/loanschedule.class.php
new file mode 100644
index 0000000000000000000000000000000000000000..fb6df8fcb6c9116a58062c33362782177e6c6682
--- /dev/null
+++ b/htdocs/loan/class/loanschedule.class.php
@@ -0,0 +1,542 @@
+<?php
+/* Copyright (C) 2017	Florian HENRY <florian.henry@atm-consulting.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
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ *      \file       htdocs/loan/class/loanschedule.class.php
+ *		\ingroup    facture
+ *		\brief      File of class to manage schedule of loans
+ */
+
+require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
+
+
+/**
+ *		Class to manage Schedule of loans
+ */
+class LoanSchedule extends CommonObject
+{
+	public $element='loan_schedule';			//!< Id that identify managed objects
+	public $table_element='loan_schedule';	//!< Name of table without prefix where object is stored
+
+	var $fk_loan;
+	var $datec='';
+	var $tms='';
+	var $datep='';
+    var $amounts=array();   // Array of amounts
+    var $amount_capital;    // Total amount of payment
+	var $amount_insurance;
+	var $amount_interest;
+	var $fk_typepayment;
+	var $num_payment;
+	var $fk_bank;
+	var $fk_user_creat;
+	var $fk_user_modif;
+	var $lines=array();
+
+	/**
+	 * @deprecated
+	 * @see amount, amounts
+	 */
+	var $total;
+
+	/**
+	 *	Constructor
+	 *
+	 *  @param		DoliDB		$db      Database handler
+	 */
+	function __construct($db)
+	{
+		$this->db = $db;
+	}
+
+	/**
+	 *  Create payment of loan into database.
+     *  Use this->amounts to have list of lines for the payment
+     *
+	 *  @param      User		$user   User making payment
+	 *  @return     int     			<0 if KO, id of payment if OK
+	 */
+	function create($user)
+	{
+		global $conf, $langs;
+
+		$error=0;
+
+        $now=dol_now();
+
+        // Validate parameters
+		if (! $this->datepaid)
+		{
+			$this->error='ErrorBadValueForParameter';
+			return -1;
+		}
+
+		// Clean parameters
+		if (isset($this->fk_loan)) 			$this->fk_loan = trim($this->fk_loan);
+		if (isset($this->amount_capital))	$this->amount_capital = trim($this->amount_capital?$this->amount_capital:0);
+		if (isset($this->amount_insurance))	$this->amount_insurance = trim($this->amount_insurance?$this->amount_insurance:0);
+		if (isset($this->amount_interest))	$this->amount_interest = trim($this->amount_interest?$this->amount_interest:0);
+		if (isset($this->fk_typepayment))	$this->fk_typepayment = trim($this->fk_typepayment);
+		if (isset($this->fk_bank))			$this->fk_bank = trim($this->fk_bank);
+		if (isset($this->fk_user_creat))	$this->fk_user_creat = trim($this->fk_user_creat);
+		if (isset($this->fk_user_modif))	$this->fk_user_modif = trim($this->fk_user_modif);
+
+        $totalamount = $this->amount_capital + $this->amount_insurance + $this->amount_interest;
+        $totalamount = price2num($totalamount);
+
+        // Check parameters
+        if ($totalamount == 0) {
+        	$this->errors[]='step1';
+        	return -1; // Negative amounts are accepted for reject prelevement but not null
+        }
+
+
+		$this->db->begin();
+
+		if ($totalamount != 0)
+		{
+			$sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (fk_loan, datec, datep, amount_capital, amount_insurance, amount_interest,";
+			$sql.= " fk_typepayment, fk_user_creat, fk_bank)";
+			$sql.= " VALUES (".$this->fk_loan.", '".$this->db->idate($now)."',";
+			$sql.= " '".$this->db->idate($this->datepaid)."',";
+			$sql.= " ".$this->amount_capital.",";
+			$sql.= " ".$this->amount_insurance.",";
+			$sql.= " ".$this->amount_interest.",";
+			$sql.= " ".$this->fk_typepayment.", ";
+			$sql.= " ".$user->id.",";
+			$sql.= " ".$this->fk_bank . ")";
+
+			dol_syslog(get_class($this)."::create", LOG_DEBUG);
+			$resql=$this->db->query($sql);
+			if ($resql)
+			{
+				$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."payment_loan");
+			}
+			else
+			{
+                $this->error=$this->db->lasterror();
+				$error++;
+			}
+
+		}
+
+		if ($totalamount != 0 && ! $error)
+		{
+		    $this->amount_capital=$totalamount;
+            $this->total=$totalamount;    // deprecated
+		    $this->db->commit();
+			return $this->id;
+		}
+		else
+		{
+			$this->errors[]=$this->db->lasterror();
+			$this->db->rollback();
+			return -1;
+		}
+	}
+
+	/**
+	 *  Load object in memory from database
+	 *
+	 *  @param	int		$id         Id object
+	 *  @return int         		<0 if KO, >0 if OK
+	 */
+	function fetch($id)
+	{
+		global $langs;
+		$sql = "SELECT";
+		$sql.= " t.rowid,";
+		$sql.= " t.fk_loan,";
+		$sql.= " t.datec,";
+		$sql.= " t.tms,";
+		$sql.= " t.datep,";
+		$sql.= " t.amount_capital,";
+		$sql.= " t.amount_insurance,";
+		$sql.= " t.amount_interest,";
+		$sql.= " t.fk_typepayment,";
+		$sql.= " t.num_payment,";
+        $sql.= " t.note_private,";
+        $sql.= " t.note_public,";
+		$sql.= " t.fk_bank,";
+		$sql.= " t.fk_user_creat,";
+		$sql.= " t.fk_user_modif,";
+		$sql.= " pt.code as type_code, pt.libelle as type_libelle,";
+		$sql.= ' b.fk_account';
+		$sql.= " FROM (".MAIN_DB_PREFIX."c_paiement as pt, ".MAIN_DB_PREFIX.$this->table_element." as t)";
+		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank as b ON t.fk_bank = b.rowid';
+		$sql.= " WHERE t.rowid = ".$id." AND t.fk_typepayment = pt.id";
+
+		dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
+		$resql=$this->db->query($sql);
+		if ($resql)
+	{
+		if ($this->db->num_rows($resql))
+		{
+			$obj = $this->db->fetch_object($resql);
+
+			$this->id = $obj->rowid;
+			$this->ref = $obj->rowid;
+
+			$this->fk_loan = $obj->fk_loan;
+			$this->datec = $this->db->jdate($obj->datec);
+			$this->tms = $this->db->jdate($obj->tms);
+			$this->datep = $this->db->jdate($obj->datep);
+			$this->amount_capital = $obj->amount_capital;
+			$this->amount_insurance = $obj->amount_insurance;
+			$this->amount_interest = $obj->amount_interest;
+			$this->fk_typepayment = $obj->fk_typepayment;
+			$this->num_payment = $obj->num_payment;
+			$this->note_private = $obj->note_private;
+			$this->note_public = $obj->note_public;
+			$this->fk_bank = $obj->fk_bank;
+			$this->fk_user_creat = $obj->fk_user_creat;
+			$this->fk_user_modif = $obj->fk_user_modif;
+
+			$this->type_code = $obj->type_code;
+			$this->type_libelle = $obj->type_libelle;
+
+			$this->bank_account   = $obj->fk_account;
+			$this->bank_line      = $obj->fk_bank;
+		}
+		$this->db->free($resql);
+
+			return 1;
+		}
+		else
+		{
+			$this->error="Error ".$this->db->lasterror();
+			return -1;
+		}
+	}
+
+
+	/**
+	 *  Update database
+	 *
+	 *  @param	User	$user        	User that modify
+	 *  @param  int		$notrigger	    0=launch triggers after, 1=disable triggers
+	 *  @return int         			<0 if KO, >0 if OK
+	 */
+	function update($user=0, $notrigger=0)
+	{
+		global $conf, $langs;
+		$error=0;
+
+		// Clean parameters
+		if (isset($this->fk_loan)) $this->fk_loan=trim($this->fk_loan);
+		if (isset($this->amount_capital)) $this->amount_capital=trim($this->amount_capital);
+		if (isset($this->amount_insurance)) $this->amount_insurance=trim($this->amount_insurance);
+		if (isset($this->amount_interest)) $this->amount_interest=trim($this->amount_interest);
+		if (isset($this->fk_typepayment)) $this->fk_typepayment=trim($this->fk_typepayment);
+		if (isset($this->num_payment)) $this->num_payment=trim($this->num_payment);
+		if (isset($this->note_private)) $this->note_private=trim($this->note_private);
+		if (isset($this->note_public)) $this->note_public=trim($this->note_public);
+		if (isset($this->fk_bank)) $this->fk_bank=trim($this->fk_bank);
+		if (isset($this->fk_user_creat)) $this->fk_user_creat=trim($this->fk_user_creat);
+		if (isset($this->fk_user_modif)) $this->fk_user_modif=trim($this->fk_user_modif);
+
+		// Check parameters
+		// Put here code to add control on parameters values
+
+		// Update request
+		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
+
+		$sql.= " fk_loan=".(isset($this->fk_loan)?$this->fk_loan:"null").",";
+		$sql.= " datec=".(dol_strlen($this->datec)!=0 ? "'".$this->db->idate($this->datec)."'" : 'null').",";
+		$sql.= " tms=".(dol_strlen($this->tms)!=0 ? "'".$this->db->idate($this->tms)."'" : 'null').",";
+		$sql.= " datep=".(dol_strlen($this->datep)!=0 ? "'".$this->db->idate($this->datep)."'" : 'null').",";
+		$sql.= " amount_capital=".(isset($this->amount_capital)?$this->amount_capital:"null").",";
+		$sql.= " amount_insurance=".(isset($this->amount_insurance)?$this->amount_insurance:"null").",";
+		$sql.= " amount_interest=".(isset($this->amount_interest)?$this->amount_interest:"null").",";
+		$sql.= " fk_typepayment=".(isset($this->fk_typepayment)?$this->fk_typepayment:"null").",";
+		$sql.= " num_payment=".(isset($this->num_payment)?"'".$this->db->escape($this->num_payment)."'":"null").",";
+		$sql.= " note_private=".(isset($this->note_private)?"'".$this->db->escape($this->note_private)."'":"null").",";
+		$sql.= " note_public=".(isset($this->note_public)?"'".$this->db->escape($this->note_public)."'":"null").",";
+		$sql.= " fk_bank=".(isset($this->fk_bank)?$this->fk_bank:"null").",";
+		$sql.= " fk_user_creat=".(isset($this->fk_user_creat)?$this->fk_user_creat:"null").",";
+		$sql.= " fk_user_modif=".(isset($this->fk_user_modif)?$this->fk_user_modif:"null")."";
+
+		$sql.= " WHERE rowid=".$this->id;
+
+		$this->db->begin();
+
+		dol_syslog(get_class($this)."::update", LOG_DEBUG);
+		$resql = $this->db->query($sql);
+		if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); }
+
+		if (! $error)
+		{
+			if (! $notrigger)
+			{
+				// Uncomment this and change MYOBJECT to your own tag if you
+				// want this action call a trigger.
+
+				//// Call triggers
+				//include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
+				//$interface=new Interfaces($this->db);
+				//$result=$interface->run_triggers('MYOBJECT_MODIFY',$this,$user,$langs,$conf);
+				//if ($result < 0) { $error++; $this->errors=$interface->errors; }
+				//// End call triggers
+			}
+		}
+
+		// Commit or rollback
+		if ($error)
+		{
+			$this->db->rollback();
+			return -1*$error;
+		}
+		else
+		{
+			$this->db->commit();
+			return 1;
+		}
+	}
+
+
+	/**
+	 *  Delete object in database
+	 *
+	 *  @param	User	$user        	User that delete
+	 *  @param  int		$notrigger		0=launch triggers after, 1=disable triggers
+	 *  @return int						<0 if KO, >0 if OK
+	 */
+	function delete($user, $notrigger=0)
+	{
+		global $conf, $langs;
+		$error=0;
+
+		$this->db->begin();
+
+	    if (! $error)
+		{
+			$sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element;
+			$sql.= " WHERE rowid=".$this->id;
+
+			dol_syslog(get_class($this)."::delete", LOG_DEBUG);
+			$resql = $this->db->query($sql);
+			if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); }
+		}
+
+		if (! $error)
+		{
+			if (! $notrigger)
+			{
+				// Uncomment this and change MYOBJECT to your own tag if you
+				// want this action call a trigger.
+
+				//// Call triggers
+				//include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
+				//$interface=new Interfaces($this->db);
+				//$result=$interface->run_triggers('MYOBJECT_DELETE',$this,$user,$langs,$conf);
+				//if ($result < 0) { $error++; $this->errors=$interface->errors; }
+				//// End call triggers
+			}
+		}
+
+		// Commit or rollback
+		if ($error)
+		{
+			foreach($this->errors as $errmsg)
+			{
+				dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
+				$this->error.=($this->error?', '.$errmsg:$errmsg);
+			}
+			$this->db->rollback();
+			return -1*$error;
+		}
+		else
+		{
+			$this->db->commit();
+			return 1;
+		}
+	}
+
+	function calc_mens($capital,$rate,$nbterm)
+	{
+		$result='';
+
+		if (!empty($capital)&&!empty($rate)&&!empty($nbterm))
+		{
+			$result=($capital*($rate/12))/(1-pow((1+($rate/12)),($nbterm*-1)));
+		}
+
+		return $result;
+	}
+
+
+	/**
+	 *  Load all object in memory from database
+	 *
+	 *  @param	int		$loanid     Id object
+	 *  @return int         		<0 if KO, >0 if OK
+	 */
+	function fetchall($loanid)
+	{
+		global $langs;
+
+		$sql = "SELECT";
+		$sql.= " t.rowid,";
+		$sql.= " t.fk_loan,";
+		$sql.= " t.datec,";
+		$sql.= " t.tms,";
+		$sql.= " t.datep,";
+		$sql.= " t.amount_capital,";
+		$sql.= " t.amount_insurance,";
+		$sql.= " t.amount_interest,";
+		$sql.= " t.fk_typepayment,";
+		$sql.= " t.num_payment,";
+		$sql.= " t.note_private,";
+		$sql.= " t.note_public,";
+		$sql.= " t.fk_bank,";
+		$sql.= " t.fk_user_creat,";
+		$sql.= " t.fk_user_modif";
+		$sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
+		$sql.= " WHERE t.fk_loan = ".$loanid;
+
+		dol_syslog(get_class($this)."::fetchall", LOG_DEBUG);
+		$resql=$this->db->query($sql);
+
+		if ($resql)
+		{
+			while($obj = $this->db->fetch_object($resql))
+			{
+				$line = New LoanSchedule($this->db);
+				$line->id = $obj->rowid;
+				$line->ref = $obj->rowid;
+
+				$line->fk_loan = $obj->fk_loan;
+				$line->datec = $this->db->jdate($obj->datec);
+				$line->tms = $this->db->jdate($obj->tms);
+				$line->datep = $this->db->jdate($obj->datep);
+				$line->amount_capital = $obj->amount_capital;
+				$line->amount_insurance = $obj->amount_insurance;
+				$line->amount_interest = $obj->amount_interest;
+				$line->fk_typepayment = $obj->fk_typepayment;
+				$line->num_payment = $obj->num_payment;
+				$line->note_private = $obj->note_private;
+				$line->note_public = $obj->note_public;
+				$line->fk_bank = $obj->fk_bank;
+				$line->fk_user_creat = $obj->fk_user_creat;
+				$line->fk_user_modif = $obj->fk_user_modif;
+
+				$this->lines[] = $line;
+			}
+			$this->db->free($resql);
+			return 1;
+		}
+		else
+		{
+			$this->error="Error ".$this->db->lasterror();
+			return -1;
+		}
+	}
+
+	/**
+	 *  trans_paiment
+	 *
+	 *  @return void
+	 */
+	function trans_paiment()
+	{
+		require_once DOL_DOCUMENT_ROOT.'/loan/class/loan.class.php';
+		require_once DOL_DOCUMENT_ROOT.'/core/lib/loan.lib.php';
+		require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
+
+		$toinsert = array();
+
+		$sql = "SELECT l.rowid";
+		$sql.= " FROM ".MAIN_DB_PREFIX."loan as l ";
+		$sql.= " WHERE l.paid = 0";
+		$resql=$this->db->query($sql);
+
+		if($resql){
+			while($obj = $this->db->fetch_object($resql)){
+				$lastrecorded = $this->lastpaiment($obj->rowid);
+				$toinsert = $this->paimenttorecord($obj->rowid, $lastrecorded);
+				if(count($toinsert)>0){
+					foreach ($toinsert as $echid){
+						$this->db->begin();
+						$sql = "INSERT INTO " .MAIN_DB_PREFIX . "payment_loan ";
+						$sql.= "(fk_loan,datec,tms,datep,amount_capital,amount_insurance,amount_interest,fk_typepayment,num_payment,note_private,note_public,fk_bank,fk_user_creat,fk_user_modif) ";
+						$sql.= "SELECT fk_loan,datec,tms,datep,amount_capital,amount_insurance,amount_interest,fk_typepayment,num_payment,note_private,note_public,fk_bank,fk_user_creat,fk_user_modif FROM " . MAIN_DB_PREFIX . "loan_schedule WHERE rowid =" .$echid;
+						$res=$this->db->query($sql);
+						if($res){
+							$this->db->commit();
+						}else {
+							$this->db->rollback();
+						}
+					}
+				}
+			}
+		}
+	}
+
+
+	/**
+	 *  trans_paiment
+	 *
+	 *  @param  int    $loanid     Loan id
+	 *  @return int                < 0 if KO, Date > 0 if OK
+	 */
+	function lastpaiment($loanid)
+	{
+		$sql = "SELECT p.datep";
+		$sql.= " FROM ".MAIN_DB_PREFIX."payment_loan as p ";
+		$sql.= " WHERE p.fk_loan = " . $loanid;
+		$sql.= " ORDER BY p.datep DESC ";
+		$sql.= " LIMIT 1 ";
+
+		$resql=$this->db->query($sql);
+
+		if($resql){
+			$obj = $this->db->fetch_object($resql);
+			return $this->db->jdate($obj->datep);
+		}else{
+			return -1;
+		}
+	}
+
+	/**
+	 *  paimenttorecord
+	 *
+	 *  @param  int        $loanid     Loan id
+	 *  @param  int        $datemax    Date max
+	 *  @return array                  Array of id
+	 */
+	function paimenttorecord($loanid, $datemax)
+	{
+		$sql = "SELECT p.rowid";
+		$sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element." as p ";
+		$sql.= " WHERE p.fk_loan = " . $loanid;
+		if (!empty($datemax)) { $sql.= " AND p.datep > '" . $this->db->idate($datemax) ."'";}
+		$sql.= " AND p.datep <= '" . $this->db->idate(dol_now()). "'";
+
+		$resql=$this->db->query($sql);
+
+		if($resql){
+			while($obj = $this->db->fetch_object($resql))
+			{
+				$result[] = $obj->rowid;
+			}
+
+		}
+
+		return $result;
+	}
+}
+
diff --git a/htdocs/loan/createschedule.php b/htdocs/loan/createschedule.php
new file mode 100644
index 0000000000000000000000000000000000000000..596cc9fd536865426ee4eed197c75f023ddd67d9
--- /dev/null
+++ b/htdocs/loan/createschedule.php
@@ -0,0 +1,208 @@
+<?php
+/* Copyright (C) 2017	Franck Moreau   <franck.moreau@theobald.com>
+ *
+ * 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
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ *      \file       htdocs/loan/createecheancier.php
+ *		\ingroup    loan
+ *		\brief      Schedule card
+ */
+
+require '../main.inc.php';
+
+require_once DOL_DOCUMENT_ROOT.'/loan/class/loan.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/loan.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/loan/class/loanschedule.class.php';
+
+global $user;
+
+$loanid = GETPOST('loanid', 'int');
+$action = GETPOST('action');
+
+$object = new Loan($db);
+$object->fetch($loanid);
+
+$langs->load('loan');
+
+if ($action == 'createecheancier') {
+
+	$i=1;
+	while($i <$object->nbterm+1){
+
+		$date =  GETPOST('hi_date'.$i,'int');
+		$mens = GETPOST('mens'.$i);
+		$int = GETPOST('hi_interets'.$i);
+
+		$echeance = new LoanSchedule($db);
+
+		$echeance->fk_loan = $object->id;
+		$echeance->datec = dol_now();
+		$echeance->tms = dol_now();
+		$echeance->datepaid = $date;
+		$echeance->amount_capital = $mens-$int;
+		$echeance->amount_insurance = 0;
+		$echeance->amount_interest = $int;
+		$echeance->fk_typepayment = 3;
+		$echeance->fk_bank = 1;
+		$echeance->fk_user_creat = $user->id;
+		$echeance->fk_user_modif = $user->id;
+		$result=$echeance->create($user);
+		if ($result<0) {
+			setEventMessages(null, $echeance->errors,'errors');
+		}
+		$i++;
+	}
+}
+
+if ($action == 'updateecheancier') {
+
+	$i=1;
+	while($i <$object->nbterm+1){
+
+		$mens = GETPOST('mens'.$i);
+		$int = GETPOST('hi_interets'.$i);
+		$id = GETPOST('hi_rowid'.$i);
+		$echeance = new LoanSchedule($db);
+		$echeance->fetch($id);
+		$echeance->tms = dol_now();
+		$echeance->amount_capital = $mens-$int;
+		$echeance->amount_insurance = 0;
+		$echeance->amount_interest = $int;
+		$echeance->fk_user_modif = $user->id;
+		$result= $echeance->update($user,0);
+		if ($result<0) {
+			setEventMessages(null, $echeance->errors,'errors');
+		}
+		$i++;
+	}
+}
+
+$echeance = new LoanSchedule($db);
+$echeance->fetchall($object->id);
+
+top_htmlhead('', '');
+$var = ! $var;
+
+
+?>
+<script type="text/javascript" language="javascript">
+$(document).ready(function() {
+	$('[name^="mens"]').focusout(function() {
+		var echeance=$(this).attr('ech');
+		var mens=$(this).val();
+		var idcap=echeance-1;
+		idcap = '#hi_capital'+idcap;
+		var capital=$(idcap).val();
+		$.ajax({
+			  dataType: 'json',
+			  url: 'calcmens.php',
+			  data: { echeance: echeance, mens: mens, capital:capital, rate:<?php echo $object->rate/100;?> , nbterm : <?php echo $object->nbterm;?>},
+			  success: function(data) {
+				$.each(data, function(index, element) {
+					var idcap_res='#hi_capital'+index;
+					var idcap_res_srt='#capital'+index;
+					var interet_res='#hi_interets'+index;
+					var interet_res_str='#interets'+index;
+					var men_res='#mens'+index;
+					$(idcap_res).val(element.cap_rest);
+					$(idcap_res_srt).text(element.cap_rest_str+' €');
+					$(interet_res).val(element.interet);
+					$(interet_res_str).text(element.interet_str+' €');
+					$(men_res).val(element.mens);
+				});
+			}
+		});
+	});
+});
+</script>
+<?php
+
+
+print '<form name="createecheancier" action="' . $_SERVER["PHP_SELF"] . '" method="POST">';
+print '<input type="hidden" name="token" value="' . $_SESSION['newtoken'] . '">';
+print '<input type="hidden" name="loanid" value="' . $loanid . '">';
+if(count($echeance->lines)>0){
+	print '<input type="hidden" name="action" value="updateecheancier">';
+}else{
+	print '<input type="hidden" name="action" value="createecheancier">';
+}
+print '<table class="border" width="100%">';
+print '<tr class="liste_titre">';
+print '<th align="center" colspan="5">' . "Création d'échéancier</th>";
+print '</tr>';
+
+print '<tr class="liste_titre">';
+Print '<th width="10%" align="center"> Echéance </th>';
+Print '<th width="10%" align="center"> Date </th>';
+Print '<th width="10%" align="center"> Montant </th>';
+Print '<th width="20%" align="center"> Intérêts </th>';
+Print '<th width="40%" align="center"> Capital restant du </th>';
+print '</tr>';
+
+if ($object->nbterm > 0 && count($echeance->lines)==0)
+{
+	$i=1;
+	$capital = $object->capital;
+	while($i <$object->nbterm+1){
+		$mens = round($echeance->calc_mens($capital, $object->rate/100, $object->nbterm-$i+1),2,PHP_ROUND_HALF_UP);
+		$int = ($capital*($object->rate/12))/100;
+		$int = round($int,2,PHP_ROUND_HALF_UP);
+		$cap_rest = round($capital - ($mens-$int),2,PHP_ROUND_HALF_UP);
+		print '<tr>';
+		print '<td align="center" id="n'.$i.'">' . $i .'</td>';
+		print '<td align="center" id ="date' .$i .'"><input type="hidden" name="hi_date' .$i .'" id ="hi_date' .$i .'" value="' . dol_time_plus_duree($object->datestart, $i-1, 'm') . '">' . dol_print_date(dol_time_plus_duree($object->datestart, $i-1, 'm'),'day') . '</td>';
+		print '<td align="center"><input name="mens'.$i.'" id="mens'.$i.'" size="5" value="'.$mens.'" ech="'.$i.'"> €</td>';
+		print '<td align="center" id="interets'.$i.'">'.price($int,0,'',1).' €</td><input type="hidden" name="hi_interets' .$i .'" id ="hi_interets' .$i .'" value="' . $int . '">';
+		print '<td align="center" id="capital'.$i.'">'.price($cap_rest).' €</td><input type="hidden" name="hi_capital' .$i .'" id ="hi_capital' .$i .'" value="' . $cap_rest . '">';
+		print '</tr>';
+		$i++;
+		$capital = $cap_rest;
+	}
+}elseif(count($echeance->lines)>0){
+	$i=1;
+	$capital = $object->capital;
+	foreach ($echeance->lines as $line){
+		$mens = $line->amount_capital+$line->amount_insurance+$line->amount_interest;
+		$int = $line->amount_interest;
+		$cap_rest = round($capital - ($mens-$int),2,PHP_ROUND_HALF_UP);
+		print '<tr>';
+		print '<td align="center" id="n'.$i.'"><input type="hidden" name="hi_rowid' .$i .'" id ="hi_rowid' .$i .'" value="' . $line->id . '">' . $i .'</td>';
+		print '<td align="center" id ="date' .$i .'"><input type="hidden" name="hi_date' .$i .'" id ="hi_date' .$i .'" value="' . $line->datep . '">' . dol_print_date($line->datep,'day') . '</td>';
+		if($line->datep > dol_now()){
+			print '<td align="center"><input name="mens'.$i.'" id="mens'.$i.'" size="5" value="'.$mens.'" ech="'.$i.'"> €</td>';
+		}else{
+			print '<td align="center">' . price($mens) . ' €</td><input type="hidden" name="mens' .$i .'" id ="mens' .$i .'" value="' . $mens . '">';
+		}
+		print '<td align="center" id="interets'.$i.'">'.price($int,0,'',1).' €</td><input type="hidden" name="hi_interets' .$i .'" id ="hi_interets' .$i .'" value="' . $int . '">';
+		print '<td align="center" id="capital'.$i.'">'.price($cap_rest).' €</td><input type="hidden" name="hi_capital' .$i .'" id ="hi_capital' .$i .'" value="' . $cap_rest . '">';
+		print '</tr>';
+		$i++;
+		$capital = $cap_rest;
+	}
+}
+
+print '</table>';
+print '</br>';
+print '</br>';
+print '<div align="center"><input class="button" type="submit" value="'.$langs->trans("Save").'"></div>';
+print '</form>';
+
+llxFooter();
+$db->close();
+
+
+
diff --git a/htdocs/modulebuilder/template/admin/setup.php b/htdocs/modulebuilder/template/admin/setup.php
index 63b92bc6468ddbd78fdaaf12f577545ab6540aa5..b3f2cc87d73af349a1eb3745456b2dc410c19769 100644
--- a/htdocs/modulebuilder/template/admin/setup.php
+++ b/htdocs/modulebuilder/template/admin/setup.php
@@ -39,20 +39,23 @@ require_once '../lib/mymodule.lib.php';
 $langs->load("mymodule@mymodule");
 
 // Access control
-if (! $user->admin) {
-	accessforbidden();
-}
+if (! $user->admin) accessforbidden();
 
 // Parameters
 $action = GETPOST('action', 'alpha');
 
+
 /*
  * Actions
  */
 
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
+
+
 /*
  * View
  */
+
 $page_name = "MyModuleSetup";
 llxHeader('', $langs->trans($page_name));
 
diff --git a/htdocs/modulebuilder/template/class/actions_mymodule.class.php b/htdocs/modulebuilder/template/class/actions_mymodule.class.php
index f3ce5963aa6193d5f62e68f6d4628133f836518a..7f1897c80ae021df7e1826d3260d4c1ba51ca0ad 100644
--- a/htdocs/modulebuilder/template/class/actions_mymodule.class.php
+++ b/htdocs/modulebuilder/template/class/actions_mymodule.class.php
@@ -62,24 +62,101 @@ class ActionsMyModule
 	 */
 	public function doActions($parameters, &$object, &$action, $hookmanager)
 	{
+		global $conf, $user, $langs;
+
 		$error = 0; // Error counter
-		$myvalue = 'test'; // A result value
 
+        /*
 		print_r($parameters);
-		echo "action: " . $action;
 		print_r($object);
+		echo "action: " . $action;
+        */
+
+	    if (in_array($parameters['currentcontext'], array('somecontext1','somecontext2'))) {    // do something only for the context 'somecontext1' or 'somecontext2'
+
 
-		if (in_array('somecontext', explode(':', $parameters['context']))) {
-		  // do something only for the context 'somecontext'
 		}
 
 		if (! $error) {
-			$this->results = array('myreturn' => $myvalue);
+			$this->results = array('myreturn' => 999);
 			$this->resprints = 'A text to show';
-			return 0; // or return 1 to replace standard code
+			return 0;                                    // or return 1 to replace standard code
 		} else {
 			$this->errors[] = 'Error message';
 			return -1;
 		}
 	}
+
+
+	/**
+	 * Overloading the doActions function : replacing the parent's function with the one below
+	 *
+	 * @param   array()         $parameters     Hook metadatas (context, etc...)
+	 * @param   CommonObject    $object         The object to process (an invoice if you are in invoice module, a propale in propale's module, etc...)
+	 * @param   string          $action         Current action (if set). Generally create or edit or null
+	 * @param   HookManager     $hookmanager    Hook manager propagated to allow calling another hook
+	 * @return  int                             < 0 on error, 0 on success, 1 to replace standard code
+	 */
+	public function doMassActions($parameters, &$object, &$action, $hookmanager)
+	{
+	    global $conf, $user, $langs;
+
+	    $error = 0; // Error counter
+
+        /*
+	    print_r($parameters);
+	    print_r($object);
+	    echo "action: " . $action;
+        */
+
+	    if (in_array($parameters['currentcontext'], array('somecontext1','somecontext2'))) {  // do something only for the context 'somecontext1' or 'somecontext2'
+
+	        foreach($parameters['toselect'] as $objectid)
+	        {
+	            // Do action on each object id
+
+	        }
+	    }
+
+	    if (! $error) {
+	        $this->results = array('myreturn' => 999);
+	        $this->resprints = 'A text to show';
+	        return 0;                                    // or return 1 to replace standard code
+	    } else {
+	        $this->errors[] = 'Error message';
+	        return -1;
+	    }
+	}
+
+
+	/**
+	 * Overloading the addMoreMassActions function : replacing the parent's function with the one below
+	 *
+	 * @param   array()         $parameters     Hook metadatas (context, etc...)
+	 * @param   CommonObject    $object         The object to process (an invoice if you are in invoice module, a propale in propale's module, etc...)
+	 * @param   string          $action         Current action (if set). Generally create or edit or null
+	 * @param   HookManager     $hookmanager    Hook manager propagated to allow calling another hook
+	 * @return  int                             < 0 on error, 0 on success, 1 to replace standard code
+	 */
+	public function addMoreMassActions($parameters, &$object, &$action, $hookmanager)
+	{
+	    global $conf, $user, $langs;
+
+	    $error = 0; // Error counter
+
+	    if (in_array($parameters['currentcontext'], array('somecontext1','somecontext2')))  // do something only for the context 'somecontext'
+	    {
+	        $this->resprints = '<option value="0"'.($disabled?' disabled="disabled"':'').'>'.$langs->trans("MyModuleMassAction").'</option>';
+	    }
+
+	    if (! $error) {
+	        return 0;                                    // or return 1 to replace standard code
+	    } else {
+	        $this->errors[] = 'Error message';
+	        return -1;
+	    }
+	}
+
+
+
 }
diff --git a/htdocs/modulebuilder/template/img/object_mytest.png b/htdocs/modulebuilder/template/img/object_mytest.png
new file mode 100644
index 0000000000000000000000000000000000000000..5a307bfc62f85df909a3cf024f27ee87d44be275
Binary files /dev/null and b/htdocs/modulebuilder/template/img/object_mytest.png differ
diff --git a/htdocs/modulebuilder/template/langs/en_US/mymodule.lang b/htdocs/modulebuilder/template/langs/en_US/mymodule.lang
index 53c6205386c57379f07ed1d043ab16e75e2314ff..c33f2453fc43f54f527900793dc474738e20f3f1 100644
--- a/htdocs/modulebuilder/template/langs/en_US/mymodule.lang
+++ b/htdocs/modulebuilder/template/langs/en_US/mymodule.lang
@@ -18,12 +18,10 @@
 # Generic
 #
 
-# Module label 'ModuleXXXName'
-# (where XXX is value of numeric property 'numero' of module)
-Module500000Name = My module
-# Module description 'ModuleXXXDesc'
-# (where XXX is value of numeric property 'numero' of module)
-Module500000Desc = My module description
+# Module label 'ModuleMyModuleName'
+ModuleMyModuleName = My module
+# Module description 'ModuleMyModuleDesc'
+ModuleMyModuleDesc = My module description
 
 #
 # Admin page
diff --git a/htdocs/modulebuilder/template/langs/fr_FR/mymodule.lang b/htdocs/modulebuilder/template/langs/fr_FR/mymodule.lang
index d15d37f0ebf1e60a1040c41f15b0e055f6296546..06e7ba3388524cc0cb9bedf5c5cc3b8fc80b4eb6 100644
--- a/htdocs/modulebuilder/template/langs/fr_FR/mymodule.lang
+++ b/htdocs/modulebuilder/template/langs/fr_FR/mymodule.lang
@@ -18,12 +18,10 @@
 # Générique
 #
 
-# Module label 'ModuleXXXName'
-# (where XXX is value of numeric property 'numero' of module)
-Module500000Name = Mon module
-# Module description 'ModuleXXXDesc'
-# (where XXX is value of numeric property 'numero' of module)
-Module500000Desc = Description de mon module
+# Module label 'ModuleMyModuleName'
+ModuleMyModuleName = Mon module
+# Module description 'ModuleMyModuleDesc'
+ModuleMyModuleDesc = Description de mon module
 
 #
 # Page d'administration
diff --git a/htdocs/product/admin/product.php b/htdocs/product/admin/product.php
index 5183eeb338282ddae61219880fc9184db5d34248..172bdd9354cce00328a9c28b45a8ff425b3d1145 100644
--- a/htdocs/product/admin/product.php
+++ b/htdocs/product/admin/product.php
@@ -74,6 +74,9 @@ $error = 0;
  * Actions
  */
 
+$nomessageinsetmoduleoptions=1;
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
+
 if ($action == 'setcodeproduct')
 {
 	if (dolibarr_set_const($db, "PRODUCT_CODEPRODUCT_ADDON",$value,'chaine',0,'',$conf->entity) > 0)
@@ -87,36 +90,6 @@ if ($action == 'setcodeproduct')
 	}
 }
 
-// Define constants for submodules that contains parameters (forms with param1, param2, ... and value1, value2, ...)
-if ($action == 'setModuleOptions')
-{
-	$post_size=count($_POST);
-
-	$db->begin();
-
-	for($i=0;$i < $post_size;$i++)
-    {
-    	if (array_key_exists('param'.$i,$_POST))
-    	{
-    		$param=GETPOST("param".$i,'alpha');
-    		$value=GETPOST("value".$i,'alpha');
-    		if ($param) $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity);
-	    	if (! $res > 0) $error++;
-    	}
-    }
-	if (! $error)
-    {
-        $db->commit();
-	//setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
-    }
-    else
-    {
-        $db->rollback();
-	// message yet present at the bottom if($action)
-	//setEventMessages($langs->trans("Error"), null, 'errors');
-	}
-}
-
 if ($action == 'other' && GETPOST('value_PRODUIT_LIMIT_SIZE') >= 0)
 {
 	$res = dolibarr_set_const($db, "PRODUIT_LIMIT_SIZE", GETPOST('value_PRODUIT_LIMIT_SIZE'),'chaine',0,'',$conf->entity);
@@ -278,7 +251,7 @@ if ($action)
     }
     else
     {
-	    setEventMessages($langs->trans("Error"), null, 'errors');
+	    setEventMessages($langs->trans("SetupNotError"), null, 'errors');
     }
 }
 
@@ -543,7 +516,7 @@ foreach ($dirmodels as $reldir)
 
 print '</table>';
 print "<br>";
-    
+
 /*
  * Other conf
  */
@@ -598,7 +571,7 @@ print '</tr>';
 // multiprix nombre de prix a proposer
 if (! empty($conf->global->PRODUIT_MULTIPRICES))
 {
-	
+
 	print '<tr class="oddeven">';
 	print '<td>'.$langs->trans("MultiPricesNumPrices").'</td>';
 	print '<td align="right"><input size="3" type="text" class="flat" name="value_PRODUIT_MULTIPRICES_LIMIT" value="'.$conf->global->PRODUIT_MULTIPRICES_LIMIT.'"></td>';
@@ -640,7 +613,7 @@ print '</tr>';
 
 if (empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT))
 {
-	
+
 	print '<tr class="oddeven">';
 	print '<td>'.$langs->trans("NumberOfProductShowInSelect").'</td>';
 	print '<td align="right"><input size="3" type="text" class="flat" name="value_PRODUIT_LIMIT_SIZE" value="'.$conf->global->PRODUIT_LIMIT_SIZE.'"></td>';
@@ -681,7 +654,7 @@ print '</tr>';
 // View product description in thirdparty language
 if (! empty($conf->global->MAIN_MULTILANGS))
 {
-	
+
 	print '<tr class="oddeven">';
 	print '<td>'.$langs->trans("ViewProductDescInThirdpartyLanguageAbility").'</td>';
 	print '<td width="60" align="right">';
@@ -723,7 +696,7 @@ if (! empty($conf->global->PRODUCT_CANVAS_ABILITY))
 
     				if ($conf->$module->enabled)
     				{
-    					
+
     					print "<tr ".$bc[$var]."><td>";
 
     					print $object->description;
diff --git a/htdocs/projet/activity/perday.php b/htdocs/projet/activity/perday.php
index a2b3f1cc667e157aa7eadd62ac3ae73b728ac0b4..9cda69560d59c2f17826f0b742a167aa50596b77 100644
--- a/htdocs/projet/activity/perday.php
+++ b/htdocs/projet/activity/perday.php
@@ -34,6 +34,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
 
 $langs->load('projects');
+$langs->load('users');
 
 $action=GETPOST('action','aZ09');
 $mode=GETPOST("mode");
@@ -62,6 +63,8 @@ $month=GETPOST('remonth')?GETPOST('remonth'):(GETPOST("month","int")?GETPOST("mo
 $day=GETPOST('reday')?GETPOST('reday'):(GETPOST("day","int")?GETPOST("day","int"):date("d"));
 $day = (int) $day;
 $week=GETPOST("week","int")?GETPOST("week","int"):date("W");
+
+$search_usertoprocessid=GETPOST('search_usertoprocessid', 'int');
 $search_task_ref=GETPOST('search_task_ref', 'alpha');
 $search_task_label=GETPOST('search_task_label', 'alpha');
 $search_project_ref=GETPOST('search_project_ref', 'alpha');
@@ -75,6 +78,17 @@ $daytoparse = $now;
 if ($yearofday && $monthofday && $dayofday) $daytoparse=dol_mktime(0, 0, 0, $monthofday, $dayofday, $yearofday);	// xxxofday is value of day after submit action 'addtime'
 else if ($year && $month && $day) $daytoparse=dol_mktime(0, 0, 0, $month, $day, $year);							// this are value submited after submit of action 'submitdateselect'
 
+if (empty($search_usertoprocessid) || $search_usertoprocessid == $user->id)
+{
+    $usertoprocess=$user;
+}
+else
+{
+    $usertoprocess=new User($db);
+    $usertoprocess->fetch($search_usertoprocessid);
+}
+$search_usertoprocessid=$usertoprocess->id;
+
 $object=new Task($db);
 
 
@@ -83,9 +97,10 @@ $object=new Task($db);
  */
 
 // Purge criteria
-if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") || GETPOST("button_removefilter")) // Both test are required to be compatible with all browsers
+if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") || GETPOST("button_removefilter")) // All tests are required to be compatible with all browsers
 {
     $action = '';
+    $search_usertoprocessid = '';
     $search_task_ref = '';
     $search_task_label = '';
     $search_project_ref = '';
@@ -125,7 +140,7 @@ if ($action == 'addtime' && $user->rights->projet->lire && GETPOST('assigntask')
     }
     if (! $error)
     {
-    	$idfortaskuser=$user->id;
+    	$idfortaskuser=$usertoprocess->id;
 		$result = $object->add_contact($idfortaskuser, GETPOST("type"), 'internal');
 
     	if ($result >= 0 || $result == -2)	// Contact add ok or already contact of task
@@ -143,7 +158,7 @@ if ($action == 'addtime' && $user->rights->projet->lire && GETPOST('assigntask')
     				$project->fetch($object->fk_project);
     				// Get type
     				$listofprojcontact=$project->liste_type_contact('internal');
-    				
+
     				if (count($listofprojcontact))
     				{
     					$typeforprojectcontact=reset(array_keys($listofprojcontact));
@@ -151,7 +166,7 @@ if ($action == 'addtime' && $user->rights->projet->lire && GETPOST('assigntask')
     				}
     			}
     		}
-    		else 
+    		else
     		{
     			dol_print_error($db);
     		}
@@ -175,6 +190,7 @@ if ($action == 'addtime' && $user->rights->projet->lire && GETPOST('assigntask')
 	if (! $error)
 	{
 		setEventMessages("TaskAssignedToEnterTime", null);
+		$taskid=0;
 	}
 
 	$action='';
@@ -247,12 +263,12 @@ if ($action == 'addtime' && $user->rights->projet->lire)
 	    	setEventMessages($langs->trans("RecordSaved"), null, 'mesgs');
 
     	    // Redirect to avoid submit twice on back
-        	header('Location: '.$_SERVER["PHP_SELF"].($projectid?'?id='.$projectid:'?').($mode?'&mode='.$mode:'').'&year='.$yearofday.'&month='.$monthofday.'&day='.$dayofday);
+        	header('Location: '.$_SERVER["PHP_SELF"].'?'.($projectid?'id='.$projectid:'').($search_usertoprocessid?'&search_usertoprocessid='.$search_usertoprocessid:'').($mode?'&mode='.$mode:'').'&year='.$yearofday.'&month='.$monthofday.'&day='.$dayofday);
         	exit;
     	}
     }
-    else    
-    {   
+    else
+    {
    	    setEventMessages($langs->trans("ErrorTimeSpentIsEmpty"), null, 'errors');
     }
 }
@@ -286,8 +302,6 @@ $next_day   = $next['mday'];
 $title=$langs->trans("TimeSpent");
 if ($mine) $title=$langs->trans("MyTimeSpent");
 
-$usertoprocess = $user;
-
 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertoprocess,0,1);  // Return all project i have permission on. I want my tasks and some of my task may be on a public projet that is not my project
 
 if ($id)
@@ -314,8 +328,9 @@ llxHeader("",$title,"");
 print_barre_liste($title, $page, $_SERVER["PHP_SELF"], "", $sortfield, $sortorder, "", $num, '', 'title_project');
 
 $param='';
-$param.=($mode?'&amp;mode='.$mode:'');
-$param.=($search_project_ref?'&amp;search_project_ref='.$search_project_ref:'');
+$param.=($mode?'&mode='.$mode:'');
+$param.=($search_project_ref?'&search_project_ref='.$search_project_ref:'');
+$param.=($search_userassignedid > 0?'&search_userassignedid='.$search_usertoprocessid:'');
 
 // Show navigation bar
 $nav ='<a class="inline-block valignmiddle" href="?year='.$prev_year."&amp;month=".$prev_month."&amp;day=".$prev_day.$param.'">'.img_previous($langs->trans("Previous"))."</a>\n";
@@ -337,7 +352,7 @@ print '<input type="hidden" name="addtimeyear" value="'.$tmp['year'].'">';
 print '<input type="hidden" name="addtimemonth" value="'.$tmp['mon'].'">';
 print '<input type="hidden" name="addtimeday" value="'.$tmp['mday'].'">';
 
-$head=project_timesheet_prepare_head($mode);
+$head=project_timesheet_prepare_head($mode, $usertoprocess);
 dol_fiche_head($head, 'inputperday', '', -1, 'task');
 
 // Show description of content
@@ -360,45 +375,17 @@ print '</div>';
 
 dol_fiche_end();
 
-
-// Filter on user
-/*	dol_fiche_head('');
-	print '<table class="border" width="100%"><tr><td width="25%">'.$langs->trans("User").'</td>';
-	print '<td>';
-	if ($mine) print $user->getLoginUrl(1);
-	print '</td>';
-	print '</tr></table>';
-	dol_fiche_end();
-*/
-
-// Filter on user
-/*	dol_fiche_head('');
-	print '<table class="border" width="100%"><tr><td width="25%">'.$langs->trans("User").'</td>';
-	print '<td>';
-	if ($mine) print $user->getLoginUrl(1);
-	print '</td>';
-	print '</tr></table>';
-	dol_fiche_end();
-*/
-
-
-// Add a new project/task
-//print '<br>';
-//print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
-//print '<input type="hidden" name="action" value="assigntask">';
-//print '<input type="hidden" name="mode" value="'.$mode.'">';
-//print '<input type="hidden" name="year" value="'.$year.'">';
-//print '<input type="hidden" name="month" value="'.$month.'">';
-//print '<input type="hidden" name="day" value="'.$day.'">';
-
-print '<div class="floatright right">'.$nav.'</div>';     // We move this before the assign to components so, the default submit button is not the assign to.
+print '<div class="floatright right'.($conf->dol_optimize_smallscreen?' centpercent':'').'">'.$nav.'</div>';     // We move this before the assign to components so, the default submit button is not the assign to.
 
 print '<div class="float valignmiddle">';
-print $langs->trans("AssignTaskToMe").'<br>';
+$titleassigntask = $langs->trans("AssignTaskToMe");
+if ($usertoprocess->id != $user->id) $titleassigntask = $langs->trans("AssignTaskToUser", $usertoprocess->getFullName($langs));
+print '<div class="taskiddiv inline-block">';
 $formproject->selectTasks($socid?$socid:-1, $taskid, 'taskid', 32, 0, 1, 1);
-print $formcompany->selectTypeContact($object, '', 'type','internal','rowid', 0);
-print '<input type="submit" class="button valignmiddle" name="assigntask" value="'.$langs->trans("AssignTask").'">';
-//print '</form>';
+print '</div>';
+print ' ';
+print $formcompany->selectTypeContact($object, '', 'type','internal','rowid', 0, 'maxwidth200');
+print '<input type="submit" class="button valignmiddle" name="assigntask" value="'.dol_escape_htmltag($titleassigntask).'">';
 print '</div>';
 
 print '<div class="clearboth" style="padding-bottom: 8px;"></div>';
@@ -408,6 +395,11 @@ print '<div class="div-table-responsive">';
 print '<table class="tagtable liste'.($moreforfilter?" listwithfilterbefore":"").'" id="tablelines3">'."\n";
 
 print '<tr class="liste_titre_filter">';
+print '<td class="liste_titre">';
+$usersettoshow='hierarchyme';
+if ($user->rights->projet->all->lire) $usersettoshow='';
+print $form->select_dolusers($usertoprocess->id, 'search_usertoprocessid', 0, null, 0, $usersettoshow, 0, 0, 0, 1, '', 0, '', 'maxwidth150');
+print '</td>';
 print '<td class="liste_titre"><input type="text" size="4" name="search_task_ref" value="'.dol_escape_htmltag($search_task_ref).'"></td>';
 print '<td class="liste_titre"><input type="text" size="4" name="search_task_label" value="'.dol_escape_htmltag($search_task_label).'"></td>';
 print '<td class="liste_titre"><input type="text" size="4" name="search_project_ref" value="'.dol_escape_htmltag($search_project_ref).'"></td>';
@@ -427,6 +419,7 @@ print '</td>';
 print "</tr>\n";
 
 print '<tr class="liste_titre">';
+print '<td>'.$langs->trans("User").'</td>';
 print '<td>'.$langs->trans("RefTask").'</td>';
 print '<td>'.$langs->trans("LabelTask").'</td>';
 print '<td>'.$langs->trans("ProjectRef").'</td>';
@@ -436,12 +429,15 @@ if (! empty($conf->global->PROJECT_LINES_PERDAY_SHOW_THIRDPARTY))
 }
 print '<td align="right" class="maxwidth100">'.$langs->trans("PlannedWorkload").'</td>';
 print '<td align="right" class="maxwidth100">'.$langs->trans("ProgressDeclared").'</td>';
-print '<td align="right" class="maxwidth100">'.$langs->trans("TimeSpent").'</td>';
+/*print '<td align="right" class="maxwidth100">'.$langs->trans("TimeSpent").'</td>';
 if ($usertoprocess->id == $user->id) print '<td align="right" class="maxwidth100">'.$langs->trans("TimeSpentByYou").'</td>';
-else print '<td align="right" class="maxwidth100">'.$langs->trans("TimeSpentByUser").'</td>';
+else print '<td align="right" class="maxwidth100">'.$langs->trans("TimeSpentByUser").'</td>';*/
+print '<td align="right" class="maxwidth100">'.$langs->trans("TimeSpent").'<br>('.$langs->trans("Everybody").')</td>';
+print '<td align="right" class="maxwidth100">'.$langs->trans("TimeSpent").'</td>';
 print '<td align="center">'.$langs->trans("HourStart").'</td>';
-print '<td align="center" colspan="2">'.$langs->trans("Duration").'</td>';
+print '<td align="center">'.$langs->trans("Duration").'</td>';
 print '<td align="right">'.$langs->trans("Note").'</td>';
+print '<td align="center"></td>';
 print "</tr>\n";
 
 
@@ -455,7 +451,7 @@ if (count($tasksarray) > 0)
 }
 else
 {
-	print '<tr><td colspan="10">'.$langs->trans("NoTasks").'</td></tr>';
+	print '<tr><td colspan="14">'.$langs->trans("NoTasks").'</td></tr>';
 }
 print "</table>";
 print '</div>';
diff --git a/htdocs/projet/activity/perweek.php b/htdocs/projet/activity/perweek.php
index da5303511ad76b9742e897ffed6db11d931a59a0..4a2156430af51940cb9388063f1fa7896d60c609 100644
--- a/htdocs/projet/activity/perweek.php
+++ b/htdocs/projet/activity/perweek.php
@@ -58,11 +58,14 @@ $nowtmp=dol_getdate($now);
 $nowday=$nowtmp['mday'];
 $nowmonth=$nowtmp['mon'];
 $nowyear=$nowtmp['year'];
+
 $year=GETPOST('reyear')?GETPOST('reyear','int'):(GETPOST("year")?GETPOST("year","int"):date("Y"));
 $month=GETPOST('remonth')?GETPOST('remonth','int'):(GETPOST("month")?GETPOST("month","int"):date("m"));
 $day=GETPOST('reday')?GETPOST('reday','int'):(GETPOST("day")?GETPOST("day","int"):date("d"));
 $day = (int) $day;
 $week=GETPOST("week","int")?GETPOST("week","int"):date("W");
+
+$search_usertoprocessid=GETPOST('search_usertoprocessid', 'int');
 $search_task_ref=GETPOST('search_task_ref', 'alpha');
 $search_task_label=GETPOST('search_task_label', 'alpha');
 $search_project_ref=GETPOST('search_project_ref', 'alpha');
@@ -88,7 +91,16 @@ $next_day   = $next['day'];
 $firstdaytoshow=dol_mktime(0,0,0,$first_month,$first_day,$first_year);
 $lastdaytoshow=dol_time_plus_duree($firstdaytoshow, 7, 'd');
 
-$usertoprocess=$user;
+if (empty($search_usertoprocessid) || $search_usertoprocessid == $user->id)
+{
+    $usertoprocess=$user;
+}
+else
+{
+    $usertoprocess=new User($db);
+    $usertoprocess->fetch($search_usertoprocessid);
+}
+$search_usertoprocessid=$usertoprocess->id;
 
 $object=new Task($db);
 
@@ -98,9 +110,10 @@ $object=new Task($db);
  */
 
 // Purge criteria
-if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") || GETPOST("button_removefilter")) // Both test are required to be compatible with all browsers
+if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") || GETPOST("button_removefilter")) // All tests are required to be compatible with all browsers
 {
     $action = '';
+    $search_usertoprocessid = '';
     $search_task_ref = '';
     $search_task_label = '';
     $search_project_ref = '';
@@ -137,13 +150,13 @@ if ($action == 'addtime' && $user->rights->projet->lire && GETPOST('assigntask')
     	setEventMessages($langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), '', 'errors');
     	$error++;
     }
-    
+
     if (! $error)
     {
-    	$idfortaskuser=$user->id;
+    	$idfortaskuser=$usertoprocess->id;
     	$result = $object->add_contact($idfortaskuser, GETPOST("type"), 'internal');
 
-    	if (! $result || $result == -2)	// Contact add ok or already contact of task
+    	if ($result >= 0 || $result == -2)	// Contact add ok or already contact of task
     	{
     		// Test if we are already contact of the project (should be rare but sometimes we can add as task contact without being contact of project, like when admin user has been removed from contact of project)
     		$sql='SELECT ec.rowid FROM '.MAIN_DB_PREFIX.'element_contact as ec, '.MAIN_DB_PREFIX.'c_type_contact as tc WHERE tc.rowid = ec.fk_c_type_contact';
@@ -158,7 +171,7 @@ if ($action == 'addtime' && $user->rights->projet->lire && GETPOST('assigntask')
     				$project->fetch($object->fk_project);
     				// Get type
     				$listofprojcontact=$project->liste_type_contact('internal');
-    				
+
     				if (count($listofprojcontact))
     				{
     					$typeforprojectcontact=reset(array_keys($listofprojcontact));
@@ -166,7 +179,7 @@ if ($action == 'addtime' && $user->rights->projet->lire && GETPOST('assigntask')
     				}
     			}
     		}
-    		else 
+    		else
     		{
     			dol_print_error($db);
     		}
@@ -190,6 +203,7 @@ if ($action == 'addtime' && $user->rights->projet->lire && GETPOST('assigntask')
 	if (! $error)
 	{
 		setEventMessages("TaskAssignedToEnterTime", null);
+		$taskid=0;
 	}
 
 	$action='';
@@ -233,16 +247,16 @@ if ($action == 'addtime' && $user->rights->projet->lire)
 							$error++;
 							break;
 						}
-						
+
 						$updateoftaskdone++;
 		        	}
 		        }
 			}
-			
+
 			if (! $updateoftaskdone)  // Check to update progress if no update were done on task.
 			{
 			    $object->fetch($taskid);
-                //var_dump($object->progress);var_dump(GETPOST($taskid . 'progress', 'int')); exit;			    
+                //var_dump($object->progress);var_dump(GETPOST($taskid . 'progress', 'int')); exit;
 			    if ($object->progress != GETPOST($taskid . 'progress', 'int'))
 			    {
 			        $object->progress = GETPOST($taskid . 'progress', 'int');
@@ -262,7 +276,7 @@ if ($action == 'addtime' && $user->rights->projet->lire)
 	    	setEventMessages($langs->trans("RecordSaved"), null, 'mesgs');
 
 	   	    // Redirect to avoid submit twice on back
-	       	header('Location: '.$_SERVER["PHP_SELF"].($projectid?'?id='.$projectid:'?').($mode?'&mode='.$mode:'').($day?'&day='.$day:'').($month?'&month='.$month:'').($year?'&year='.$year:''));
+	       	header('Location: '.$_SERVER["PHP_SELF"].'?'.($projectid?'id='.$projectid:'').($search_usertoprocessid?'&search_usertoprocessid='.$search_usertoprocessid:'').($mode?'&mode='.$mode:'').($day?'&day='.$day:'').($month?'&month='.$month:'').($year?'&year='.$year:''));
 	       	exit;
 	   	}
 	}
@@ -312,14 +326,15 @@ llxHeader("",$title,"",'','','',array('/core/js/timesheet.js'));
 print_barre_liste($title, $page, $_SERVER["PHP_SELF"], "", $sortfield, $sortorder, "", $num, '', 'title_project');
 
 $param='';
-$param.=($mode?'&amp;mode='.$mode:'');
-$param.=($search_project_ref?'&amp;search_project_ref='.$search_project_ref:'');
+$param.=($mode?'&mode='.$mode:'');
+$param.=($search_project_ref?'&search_project_ref='.$search_project_ref:'');
+$param.=($search_usertoprocessid > 0?'&search_usertoprocessid='.$search_usertoprocessid:'');
 
 // Show navigation bar
-$nav ='<a class="inline-block valignmiddle" href="?year='.$prev_year."&amp;month=".$prev_month."&amp;day=".$prev_day.$param.'">'.img_previous($langs->trans("Previous"))."</a>\n";
+$nav ='<a class="inline-block valignmiddle" href="?year='.$prev_year."&month=".$prev_month."&day=".$prev_day.$param.'">'.img_previous($langs->trans("Previous"))."</a>\n";
 $nav.=" <span id=\"month_name\">".dol_print_date(dol_mktime(0,0,0,$first_month,$first_day,$first_year),"%Y").", ".$langs->trans("WeekShort")." ".$week." </span>\n";
-$nav.='<a class="inline-block valignmiddle" href="?year='.$next_year."&amp;month=".$next_month."&amp;day=".$next_day.$param.'">'.img_next($langs->trans("Next"))."</a>\n";
-$nav.=" &nbsp; (<a href=\"?year=".$nowyear."&amp;month=".$nowmonth."&amp;day=".$nowday.$param."\">".$langs->trans("Today")."</a>)";
+$nav.='<a class="inline-block valignmiddle" href="?year='.$next_year."&month=".$next_month."&day=".$next_day.$param.'">'.img_next($langs->trans("Next"))."</a>\n";
+$nav.=" &nbsp; (<a href=\"?year=".$nowyear."&month=".$nowmonth."&day=".$nowday.$param."\">".$langs->trans("Today")."</a>)";
 $nav.='<br>'.$form->select_date(-1,'',0,0,2,"addtime",1,0,1).' ';
 $nav.=' <input type="submit" name="submitdateselect" class="button" value="'.$langs->trans("Refresh").'">';
 
@@ -333,7 +348,7 @@ print '<input type="hidden" name="day" value="'.$day.'">';
 print '<input type="hidden" name="month" value="'.$month.'">';
 print '<input type="hidden" name="year" value="'.$year.'">';
 
-$head=project_timesheet_prepare_head($mode);
+$head=project_timesheet_prepare_head($mode, $usertoprocess);
 dol_fiche_head($head, 'inputperweek', '', -1, 'task');
 
 // Show description of content
@@ -356,44 +371,17 @@ print '</div>';
 
 dol_fiche_end();
 
-// Filter on user
-/*	dol_fiche_head('');
-	print '<table class="border" width="100%"><tr><td width="25%">'.$langs->trans("User").'</td>';
-	print '<td>';
-	if ($mine) print $user->getLoginUrl(1);
-	print '</td>';
-	print '</tr></table>';
-	dol_fiche_end();
-*/
-
-// Filter on user
-/*	dol_fiche_head('');
-	print '<table class="border" width="100%"><tr><td width="25%">'.$langs->trans("User").'</td>';
-	print '<td>';
-	if ($mine) print $user->getLoginUrl(1);
-	print '</td>';
-	print '</tr></table>';
-	dol_fiche_end();
-*/
-
-
-// Add a new project/task
-//print '<br>';
-//print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
-//print '<input type="hidden" name="action" value="assigntask">';
-//print '<input type="hidden" name="mode" value="'.$mode.'">';
-//print '<input type="hidden" name="year" value="'.$year.'">';
-//print '<input type="hidden" name="month" value="'.$month.'">';
-//print '<input type="hidden" name="day" value="'.$day.'">';
-
-print '<div class="floatright right">'.$nav.'</div>';     // We move this before the assign to components so, the default submit button is not the assign to.
+print '<div class="floatright right'.($conf->dol_optimize_smallscreen?' centpercent':'').'">'.$nav.'</div>';     // We move this before the assign to components so, the default submit button is not the assign to.
 
 print '<div class="float valignmiddle">';
-print $langs->trans("AssignTaskToMe").'<br>';
+$titleassigntask = $langs->trans("AssignTaskToMe");
+if ($usertoprocess->id != $user->id) $titleassigntask = $langs->trans("AssignTaskToUser", $usertoprocess->getFullName($langs));
+print '<div class="taskiddiv inline-block">';
 $formproject->selectTasks($socid?$socid:-1, $taskid, 'taskid', 32, 0, 1, 1);
-print $formcompany->selectTypeContact($object, '', 'type','internal','rowid', 0);
-print '<input type="submit" class="button valignmiddle" name="assigntask" value="'.$langs->trans("AssignTask").'">';
-//print '</form>';
+print '</div>';
+print ' ';
+print $formcompany->selectTypeContact($object, '', 'type','internal','rowid', 0, 'maxwidth200');
+print '<input type="submit" class="button valignmiddle" name="assigntask" value="'.dol_escape_htmltag($titleassigntask).'">';
 print '</div>';
 
 print '<div class="clearboth" style="padding-bottom: 8px;"></div>';
@@ -403,6 +391,11 @@ print '<div class="div-table-responsive">';
 print '<table class="tagtable liste'.($moreforfilter?" listwithfilterbefore":"").'" id="tablelines3">'."\n";
 
 print '<tr class="liste_titre_filter">';
+print '<td class="liste_titre">';
+$usersettoshow='hierarchyme';
+if ($user->rights->projet->all->lire) $usersettoshow='';
+print $form->select_dolusers($usertoprocess->id, 'search_usertoprocessid', 0, null, 0, $usersettoshow, 0, 0, 0, 1, '', 0, '', 'maxwidth150');
+print '</td>';
 print '<td class="liste_titre"><input type="text" size="4" name="search_task_ref" value="'.dol_escape_htmltag($search_task_ref).'"></td>';
 print '<td class="liste_titre"><input type="text" size="4" name="search_task_label" value="'.dol_escape_htmltag($search_task_label).'"></td>';
 print '<td class="liste_titre"><input type="text" size="4" name="search_project_ref" value="'.dol_escape_htmltag($search_project_ref).'"></td>';
@@ -423,6 +416,7 @@ print '</td>';
 print "</tr>\n";
 
 print '<tr class="liste_titre">';
+print '<td>'.$langs->trans("User").'</td>';
 print '<td>'.$langs->trans("RefTask").'</td>';
 print '<td>'.$langs->trans("LabelTask").'</td>';
 print '<td>'.$langs->trans("ProjectRef").'</td>';
@@ -432,9 +426,11 @@ if (! empty($conf->global->PROJECT_LINES_PERWEEK_SHOW_THIRDPARTY))
 }
 print '<td align="right" class="maxwidth75">'.$langs->trans("PlannedWorkload").'</td>';
 print '<td align="right" class="maxwidth75">'.$langs->trans("ProgressDeclared").'</td>';
+/*print '<td align="right" class="maxwidth75">'.$langs->trans("TimeSpent").'</td>';
+ if ($usertoprocess->id == $user->id) print '<td align="right" class="maxwidth75">'.$langs->trans("TimeSpentByYou").'</td>';
+ else print '<td align="right" class="maxwidth75">'.$langs->trans("TimeSpentByUser").'</td>';*/
+print '<td align="right" class="maxwidth75">'.$langs->trans("TimeSpent").'<br>('.$langs->trans("Everybody").')</td>';
 print '<td align="right" class="maxwidth75">'.$langs->trans("TimeSpent").'</td>';
-if ($usertoprocess->id == $user->id) print '<td align="right" class="maxwidth75">'.$langs->trans("TimeSpentByYou").'</td>';
-else print '<td align="right" class="maxwidth75">'.$langs->trans("TimeSpentByUser").'</td>';
 
 $startday=dol_mktime(12, 0, 0, $startdayarray['first_month'], $startdayarray['first_day'], $startdayarray['first_year']);
 
@@ -452,16 +448,16 @@ if (count($tasksarray) > 0)
 {
     //var_dump($tasksarray);
     //var_dump($tasksrole);
-    
+
 	$j=0;
 	$level=0;
 	projectLinesPerWeek($j, $firstdaytoshow, $usertoprocess, 0, $tasksarray, $level, $projectsrole, $tasksrole, $mine, $restrictviewformytask);
 
-	$colspan=7;
+	$colspan=8;
 	if (! empty($conf->global->PROJECT_LINES_PERWEEK_SHOW_THIRDPARTY)) $colspan++;
-	
+
 	print '<tr class="liste_total">
-                <td class="liste_total" colspan="'.$colspan.'" align="right">'.$langs->trans("Total").'</td>
+                <td class="liste_total" colspan="'.$colspan.'">'.$langs->trans("Total").'</td>
                 <td class="liste_total hide0" align="center"><div id="totalDay[0]">&nbsp;</div></td>
                 <td class="liste_total hide1" align="center"><div id="totalDay[1]">&nbsp;</div></td>
                 <td class="liste_total hide2" align="center"><div id="totalDay[2]">&nbsp;</div></td>
@@ -474,7 +470,7 @@ if (count($tasksarray) > 0)
 }
 else
 {
-	print '<tr><td colspan="11">'.$langs->trans("NoTasks").'</td></tr>';
+	print '<tr><td colspan="16">'.$langs->trans("NoTasks").'</td></tr>';
 }
 print "</table>";
 print '</div>';
diff --git a/htdocs/projet/admin/project.php b/htdocs/projet/admin/project.php
index fbcecf032cf7f1be200aeaf9619c8d691f990b1f..9e35ea77e0bca38a898e812c709ef8ec705f6e6b 100644
--- a/htdocs/projet/admin/project.php
+++ b/htdocs/projet/admin/project.php
@@ -51,6 +51,8 @@ $type='project';
  * Actions
  */
 
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
+
 if ($action == 'setmainoptions')
 {
 	if (GETPOST('PROJECT_USE_OPPORTUNITIES')) dolibarr_set_const($db, "PROJECT_USE_OPPORTUNITIES",GETPOST('PROJECT_USE_OPPORTUNITIES'),'chaine',0,'',$conf->entity);
@@ -104,7 +106,7 @@ else if ($action == 'specimen')
 
 	$project = new Project($db);
 	$project->initAsSpecimen();
-    
+
 	// Search template files
 	$file=''; $classname=''; $filefound=0;
 	$dirmodels=array_merge(array('/'),(array) $conf->modules_parts['models']);
@@ -188,35 +190,6 @@ else if ($action == 'specimentask')
 	}
 }
 
-// Define constants for submodules that contains parameters (forms with param1, param2, ... and value1, value2, ...)
-if ($action == 'setModuleOptions')
-{
-	$post_size=count($_POST);
-
-	$db->begin();
-
-	for($i=0;$i < $post_size;$i++)
-	{
-		if (array_key_exists('param'.$i,$_POST))
-		{
-			$param=GETPOST("param".$i,'alpha');
-			$value=GETPOST("value".$i,'alpha');
-			if ($param) $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity);
-			if (! $res > 0) $error++;
-		}
-	}
-	if (! $error)
-	{
-		$db->commit();
-		setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
-	}
-	else
-	{
-		$db->rollback();
-        setEventMessages($langs->trans("Error"), null, 'errors');
-	}
-}
-
 // Activate a model
 else if ($action == 'set')
 {
@@ -414,7 +387,7 @@ foreach ($dirmodels as $reldir)
 
 					if ($module->isEnabled())
 					{
-						
+
 						print '<tr class="oddeven"><td>'.$module->name."</td><td>\n";
 						print $module->info();
 						print '</td>';
@@ -518,7 +491,7 @@ if (empty($conf->global->PROJECT_HIDE_TASKS))
 
 						if ($module->isEnabled())
 						{
-							
+
 							print '<tr class="oddeven"><td>'.$module->name."</td><td>\n";
 							print $module->info();
 							print '</td>';
@@ -660,7 +633,7 @@ foreach ($dirmodels as $reldir)
 
 							if ($modulequalified)
 							{
-								
+
 								print '<tr class="oddeven"><td width="100">';
 								print (empty($module->name)?$name:$module->name);
 								print "</td><td>\n";
diff --git a/htdocs/projet/card.php b/htdocs/projet/card.php
index f6355ec556698199563d3d394a1a50d04a2e14df..0b45a0d0696b95fde1d53f56244d2215fa32ae39 100644
--- a/htdocs/projet/card.php
+++ b/htdocs/projet/card.php
@@ -134,7 +134,7 @@ if (empty($reshook))
 	        $error++;
 	        setEventMessages($langs->trans("ErrorOppStatusRequiredIfAmount"), null, 'errors');
 	    }
-	    
+
 	    if (! $error)
 	    {
 	        $error=0;
@@ -308,8 +308,8 @@ if (empty($reshook))
 			    setEventMessages($langs->trans("FailedToCloseProject").':'.$object->error, $object->errors, 'errors');
 	        }
 	    }
-	    
-	    
+
+
 	    if ($error)
 	    {
 			$db->rollback();
@@ -322,7 +322,7 @@ if (empty($reshook))
 			if (GETPOST('socid','int') > 0) $object->fetch_thirdparty(GETPOST('socid','int'));
 			else unset($object->thirdparty);
 	    }
-	    
+
 	}
 
 	// Build doc
@@ -623,7 +623,7 @@ if ($action == 'create' && $user->rights->projet->creer)
     {
         print ' &nbsp; &nbsp; ';
         print '<input type="button" class="button" value="' . $langs->trans("Cancel") . '" onClick="javascript:history.go(-1)">';
-    }    
+    }
     print '</div>';
 
     print '</form>';
@@ -645,12 +645,12 @@ if ($action == 'create' && $user->rights->projet->creer)
         });
         </script>';
 }
-elseif ($object->id > 0) 
+elseif ($object->id > 0)
 {
     /*
      * Show or edit
      */
-    
+
     $res=$object->fetch_optionals($object->id,$extralabels);
 
     // To verify role of users
@@ -711,10 +711,11 @@ elseif ($object->id > 0)
     print '<input type="hidden" name="comefromclone" value="'.$comefromclone.'">';
 
     $head=project_prepare_head($object);
-    dol_fiche_head($head, 'project', $langs->trans("Project"), -1, ($object->public?'projectpub':'project'));
 
     if ($action == 'edit' && $userWrite > 0)
     {
+        dol_fiche_head($head, 'project', $langs->trans("Project"), 0, ($object->public?'projectpub':'project'));
+
         print '<table class="border" width="100%">';
 
         // Ref
@@ -835,27 +836,30 @@ elseif ($object->id > 0)
     }
     else
     {
+        dol_fiche_head($head, 'project', $langs->trans("Project"), -1, ($object->public?'projectpub':'project'));
+
         // Project card
-        
+
         $linkback = '<a href="'.DOL_URL_ROOT.'/projet/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
-        
+
         $morehtmlref='<div class="refidno">';
         // Title
         $morehtmlref.=$object->title;
         // Thirdparty
-        if ($object->thirdparty->id > 0) 
+        $morehtmlref.='<br>'.$langs->trans('ThirdParty') . ' : ';
+        if ($object->thirdparty->id > 0)
         {
-            $morehtmlref.='<br>'.$langs->trans('ThirdParty') . ' : ' . $object->thirdparty->getNomUrl(1, 'project');
+            $morehtmlref .= $object->thirdparty->getNomUrl(1, 'project');
         }
         $morehtmlref.='</div>';
-        
+
         // Define a complementary filter for search of next/prev ref.
         if (! $user->rights->projet->all->lire)
         {
             $objectsListId = $object->getProjectsAuthorizedForUser($user,0,0);
             $object->next_prev_filter=" rowid in (".(count($objectsListId)?join(',',array_keys($objectsListId)):'0').")";
         }
-        
+
 	    dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
 
 
@@ -889,7 +893,7 @@ elseif ($object->id > 0)
 	        if (strcmp($object->opp_amount,'')) print price($object->opp_amount,0,$langs,1,0,0,$conf->currency);
 	        print '</td></tr>';
 	    }
-    
+
         // Date start - end
         print '<tr><td>'.$langs->trans("DateStart").' - '.$langs->trans("DateEnd").'</td><td>';
 		$start = dol_print_date($object->date_start,'dayhour');
@@ -899,7 +903,7 @@ elseif ($object->id > 0)
 		print ($end?$end:'?');
 		if ($object->hasDelay()) print img_warning("Late");
         print '</td></tr>';
-    	     
+
         // Budget
         print '<tr><td>'.$langs->trans("Budget").'</td><td>';
         if (strcmp($object->budget_amount, '')) print price($object->budget_amount,0,$langs,1,0,0,$conf->currency);
@@ -908,16 +912,16 @@ elseif ($object->id > 0)
         // Other attributes
         $cols = 2;
         include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php';
-        
+
         print '</table>';
-        
+
         print '</div>';
         print '<div class="fichehalfright">';
         print '<div class="ficheaddleft">';
         print '<div class="underbanner clearboth"></div>';
-        
+
         print '<table class="border" width="100%">';
-        
+
         // Description
         print '<td class="titlefield tdtop">'.$langs->trans("Description").'</td><td>';
         print nl2br($object->description);
@@ -929,13 +933,13 @@ elseif ($object->id > 0)
             print $form->showCategories($object->id,'project',1);
             print "</td></tr>";
         }
-        
+
         print '</table>';
-        
+
         print '</div>';
         print '</div>';
         print '</div>';
-        
+
         print '<div class="clearboth"></div>';
     }
 
@@ -954,9 +958,10 @@ elseif ($object->id > 0)
     // Change probability from status
     if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->PROJECT_USE_OPPORTUNITIES))
     {
+        // Default value to close or not when we set opp to 'WON'.
         $defaultcheckedwhenoppclose=1;
         if (empty($conf->global->PROJECT_HIDE_TASKS)) $defaultcheckedwhenoppclose=0;
-        
+
         print '<!-- Javascript to manage opportunity status change -->';
         print '<script type="text/javascript" language="javascript">
             jQuery(document).ready(function() {
@@ -969,13 +974,17 @@ elseif ($object->id > 0)
                     var oldpercent = \''.dol_escape_js($object->opp_percent).'\';
 
                     console.log("We select "+elemcode);
-                    if (elemcode == \'LOST\') defaultcloseproject = 1;
-                    jQuery("#divtocloseproject").show();
-                    if (defaultcloseproject) jQuery("#inputcloseproject").prop("checked", true);
+
+                    /* Define if checkbox to close is checked or not */
+                    var closeproject = 0;
+                    if (elemcode == \'LOST\') closeproject = 1;
+                    if (elemcode == \'WON\') closeproject = defaultcloseproject;
+                    if (closeproject) jQuery("#inputcloseproject").prop("checked", true);
                     else jQuery("#inputcloseproject").prop("checked", false);
-                        
-                    /* Make close project visible or not */
-                    if (elemcode == \'WON\' || elemcode == \'LOST\') 
+
+                    /* Make the close project checkbox visible or not */
+                    console.log("closeproject="+closeproject);
+                    if (elemcode == \'WON\' || elemcode == \'LOST\')
                     {
                         jQuery("#divtocloseproject").show();
                     }
@@ -983,7 +992,7 @@ elseif ($object->id > 0)
                     {
                         jQuery("#divtocloseproject").hide();
                     }
-                        
+
                     /* Change percent of default percent of new status is higher */
                     if (parseFloat(jQuery("#opp_percent").val()) != parseFloat(defaultpercent))
                     {
@@ -1010,7 +1019,7 @@ elseif ($object->id > 0)
     {
 	    if ($action != "edit" )
 	    {
-	        
+
         	// Create event
         	if ($conf->agenda->enabled && ! empty($conf->global->MAIN_ADD_EVENT_ON_ELEMENT_CARD)) 				// Add hidden condition because this is not a
             	// "workflow" action so should appears somewhere else on
diff --git a/htdocs/projet/class/api_projects.class.php b/htdocs/projet/class/api_projects.class.php
index 0f4f85c05af0e470a8ac523f0f4c900e0e5a4e3d..8586f0c89ce9050c39dd7851b67a348fab87e98e 100644
--- a/htdocs/projet/class/api_projects.class.php
+++ b/htdocs/projet/class/api_projects.class.php
@@ -20,7 +20,7 @@
 
  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
  require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
- 
+
 /**
  * API class for projects
  *
@@ -83,8 +83,8 @@ class Projects extends DolibarrApi
 		return $this->_cleanObjectDatas($this->project);
     }
 
-    
-   
+
+
     /**
      * List projects
      *
@@ -102,7 +102,7 @@ class Projects extends DolibarrApi
         global $db, $conf;
 
         $obj_ret = array();
-        
+
         // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
         $socids = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : $thirdparty_ids;
 
@@ -126,7 +126,7 @@ class Projects extends DolibarrApi
             $sql .= " AND sc.fk_user = ".$search_sale;
         }
         // Add sql filters
-        if ($sqlfilters) 
+        if ($sqlfilters)
         {
             if (! DolibarrApi::_checkFilters($sqlfilters))
             {
@@ -135,7 +135,7 @@ class Projects extends DolibarrApi
 	        $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
             $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
         }
-        
+
         $sql.= $db->order($sortfield, $sortorder);
         if ($limit)	{
             if ($page < 0)
@@ -228,7 +228,7 @@ class Projects extends DolibarrApi
       }
       $this->project->getLinesArray(DolibarrApiAccess::$user);
       $result = array();
-      foreach ($this->project->lines as $line)      // $line is a task 
+      foreach ($this->project->lines as $line)      // $line is a task
       {
           if ($includetimespent == 1)
           {
@@ -244,7 +244,7 @@ class Projects extends DolibarrApi
       return $result;
     }
 
-    
+
     /**
      * Get roles a user is assigned to a project with
      *
@@ -257,20 +257,20 @@ class Projects extends DolibarrApi
      */
     function getRoles($id, $userid=0) {
         global $db;
-        
+
         if(! DolibarrApiAccess::$user->rights->projet->lire) {
             throw new RestException(401);
         }
-    
+
         $result = $this->project->fetch($id);
         if( ! $result ) {
             throw new RestException(404, 'Project not found');
         }
-    
+
         if( ! DolibarrApi::_checkAccessToResource('project',$this->project->id)) {
             throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
         }
-        
+
         require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
         $taskstatic=new Task($this->db);
         $userp = DolibarrApiAccess::$user;
@@ -286,8 +286,8 @@ class Projects extends DolibarrApi
         }
         return $result;
     }
-    
-    
+
+
     /**
      * Add a task to given project
      *
@@ -348,7 +348,7 @@ class Projects extends DolibarrApi
       return false;
     }
     */
-    
+
     /**
      * Update a task to given project
      *
@@ -406,9 +406,9 @@ class Projects extends DolibarrApi
       }
       return false;
     }*/
-    
 
-    
+
+
     /**
      * Update project general fields (won't touch lines of project)
      *
@@ -483,7 +483,7 @@ class Projects extends DolibarrApi
      * Validate a project.
      * You can test this API with the following input message
      * { "notrigger": 0 }
-     * 
+     *
      * @param   int $id             Project ID
      * @param   int $notrigger      1=Does not execute triggers, 0= execute triggers
      *
@@ -527,7 +527,7 @@ class Projects extends DolibarrApi
         );
     }
 
-    
+
     /**
      * Clean sensible object datas
      *
@@ -535,9 +535,12 @@ class Projects extends DolibarrApi
      * @return    array    Array of cleaned object properties
      */
     function _cleanObjectDatas($object) {
-    
+
         $object = parent::_cleanObjectDatas($object);
-    
+
+        unset($object->titre);
+        unset($object->datec);
+        unset($object->datem);
         unset($object->barcode_type);
         unset($object->barcode_type_code);
         unset($object->barcode_type_label);
@@ -559,21 +562,21 @@ class Projects extends DolibarrApi
         unset($object->country);
         unset($object->country_id);
         unset($object->country_code);
-        
+
         unset($object->weekWorkLoad);
         unset($object->weekWorkLoad);
-        
+
         //unset($object->lines);            // for task we use timespent_lines, but for project we use lines
-        
+
         unset($object->total_ht);
         unset($object->total_tva);
         unset($object->total_localtax1);
         unset($object->total_localtax2);
         unset($object->total_ttc);
-        
+
         return $object;
     }
-    
+
     /**
      * Validate fields before create or update object
      *
@@ -592,8 +595,8 @@ class Projects extends DolibarrApi
         }
         return $object;
     }
-    
-    
+
+
     // TODO
     // getSummaryOfTimeSpent
 }
diff --git a/htdocs/projet/class/projectstats.class.php b/htdocs/projet/class/projectstats.class.php
index 4485117fb0f0523a4a29ce5cb7e3359a3062ba7f..a47d28d1b43cb91795331abb2b013044aac4aa52 100644
--- a/htdocs/projet/class/projectstats.class.php
+++ b/htdocs/projet/class/projectstats.class.php
@@ -28,8 +28,8 @@ class ProjectStats extends Stats
 	public $userid;
 	public $socid;
 	public $year;
-	
-	function __construct($db) 
+
+	function __construct($db)
 	{
 		global $conf, $user;
 
@@ -41,7 +41,7 @@ class ProjectStats extends Stats
 
 
 	/**
-	 * Return all leads grouped by status.
+	 * Return all leads grouped by opportunity status.
 	 * Warning: There is no filter on WON/LOST because we want this for statistics.
 	 *
 	 * @param  int             $limit Limit results
@@ -56,7 +56,10 @@ class ProjectStats extends Stats
 
 		$sql = "SELECT";
 		$sql .= " SUM(t.opp_amount), t.fk_opp_status, cls.code, cls.label";
-		$sql .= " FROM " . MAIN_DB_PREFIX . "projet as t, ".MAIN_DB_PREFIX."c_lead_status as cls";
+		$sql .= " FROM " . MAIN_DB_PREFIX . "projet as t";
+		if (! $user->rights->societe->client->voir && ! $user->socid)
+			$sql .= " INNER JOIN " . MAIN_DB_PREFIX . "societe_commerciaux as sc ON sc.fk_soc=t.fk_soc AND sc.fk_user=" . $user->id;
+		$sql .= ", ".MAIN_DB_PREFIX."c_lead_status as cls";
 		$sql .= $this->buildWhere();
 		$sql .= " AND t.fk_opp_status = cls.rowid";
 		$sql .= " AND t.fk_statut <> 0";     // We want historic also, so all projects not draft
@@ -112,11 +115,11 @@ class ProjectStats extends Stats
 		$datay = array ();
 
 		$wonlostfilter=0; // No filter on status WON/LOST
-		
+
 		$sql = "SELECT date_format(t.datec,'%Y') as year, COUNT(t.rowid) as nb, SUM(t.opp_amount) as total, AVG(t.opp_amount) as avg,";
 		$sql.= " SUM(t.opp_amount * ".$this->db->ifsql("t.opp_percent IS NULL".($wonlostfilter?" OR cls.code IN ('WON','LOST')":""), '0', 't.opp_percent')." / 100) as weighted";
 		$sql.= " FROM " . MAIN_DB_PREFIX . "projet as t LEFT JOIN ".MAIN_DB_PREFIX."c_lead_status as cls ON cls.rowid = t.fk_opp_status";
-		if (! $user->rights->societe->client->voir && ! $user->societe_id)
+		if (! $user->rights->societe->client->voir && ! $user->soc_id)
 			$sql .= " INNER JOIN " . MAIN_DB_PREFIX . "societe_commerciaux as sc ON sc.fk_soc=t.fk_soc AND sc.fk_user=" . $user->id;
 		$sql.= $this->buildWhere();
 		$sql.= " GROUP BY year";
@@ -124,14 +127,14 @@ class ProjectStats extends Stats
 
 		return $this->_getAllByYear($sql);
 	}
-	
-	
+
+
 	/**
 	 * Build the where part
-	 * 
+	 *
 	 * @return string
 	 */
-	public function buildWhere() 
+	public function buildWhere()
 	{
 		$sqlwhere_str = '';
 		$sqlwhere = array();
@@ -163,7 +166,7 @@ class ProjectStats extends Stats
 	 * @param int $year scan
 	 * @return array of values
 	 */
-	function getNbByMonth($year) 
+	function getNbByMonth($year)
 	{
 		global $user;
 
@@ -171,7 +174,7 @@ class ProjectStats extends Stats
 
 		$sql = "SELECT date_format(t.datec,'%m') as dm, COUNT(*) as nb";
 		$sql .= " FROM " . MAIN_DB_PREFIX . "projet as t";
-		if (! $user->rights->societe->client->voir && ! $user->societe_id)
+		if (! $user->rights->societe->client->voir && ! $user->soc_id)
 			$sql .= " INNER JOIN " . MAIN_DB_PREFIX . "societe_commerciaux as sc ON sc.fk_soc=t.fk_soc AND sc.fk_user=" . $user->id;
 		$sql .= $this->buildWhere();
 		$sql .= " GROUP BY dm";
@@ -190,7 +193,7 @@ class ProjectStats extends Stats
 	 * @param int $year scan
 	 * @return array with amount by month
 	 */
-	function getAmountByMonth($year) 
+	function getAmountByMonth($year)
 	{
 		global $user;
 
@@ -198,7 +201,7 @@ class ProjectStats extends Stats
 
 		$sql = "SELECT date_format(t.datec,'%m') as dm, SUM(t.opp_amount)";
 		$sql .= " FROM " . MAIN_DB_PREFIX . "projet as t";
-		if (! $user->rights->societe->client->voir && ! $user->societe_id)
+		if (! $user->rights->societe->client->voir && ! $user->soc_id)
 			$sql .= " INNER JOIN " . MAIN_DB_PREFIX . "societe_commerciaux as sc ON sc.fk_soc=t.fk_soc AND sc.fk_user=" . $user->id;
 		$sql .= $this->buildWhere();
 		$sql .= " GROUP BY dm";
@@ -313,7 +316,7 @@ class ProjectStats extends Stats
 	 * @param  int $wonlostfilter      Add a filter on status won/lost
 	 * @return array                   Array with amount by month
 	 */
-	function getWeightedAmountByMonth($year, $wonlostfilter=1) 
+	function getWeightedAmountByMonth($year, $wonlostfilter=1)
 	{
 		global $user;
 
@@ -321,7 +324,7 @@ class ProjectStats extends Stats
 
 		$sql = "SELECT date_format(t.datec,'%m') as dm, SUM(t.opp_amount * ".$this->db->ifsql("t.opp_percent IS NULL".($wonlostfilter?" OR cls.code IN ('WON','LOST')":""), '0', 't.opp_percent')." / 100)";
 		$sql .= " FROM " . MAIN_DB_PREFIX . "projet as t LEFT JOIN ".MAIN_DB_PREFIX.'c_lead_status as cls ON t.fk_opp_status = cls.rowid';
-		if (! $user->rights->societe->client->voir && ! $user->societe_id)
+		if (! $user->rights->societe->client->voir && ! $user->soc_id)
 			$sql .= " INNER JOIN " . MAIN_DB_PREFIX . "societe_commerciaux as sc ON sc.fk_soc=t.fk_soc AND sc.fk_user=" . $user->id;
 		$sql .= $this->buildWhere();
 		$sql .= " GROUP BY dm";
@@ -421,7 +424,7 @@ class ProjectStats extends Stats
 	 * @param int $year scan
 	 * @return array with amount by month
 	 */
-	function getTransformRateByMonth($year) 
+	function getTransformRateByMonth($year)
 	{
 		global $user;
 
@@ -429,7 +432,7 @@ class ProjectStats extends Stats
 
 		$sql = "SELECT date_format(t.datec,'%m') as dm, count(t.opp_amount)";
 		$sql .= " FROM " . MAIN_DB_PREFIX . "projet as t";
-		if (! $user->rights->societe->client->voir && ! $user->societe_id)
+		if (! $user->rights->societe->client->voir && ! $user->soc_id)
 			$sql .= " INNER JOIN " . MAIN_DB_PREFIX . "societe_commerciaux as sc ON sc.fk_soc=t.fk_soc AND sc.fk_user=" . $user->id;
 		$sql .= $this->buildWhere();
 		$sql .= " GROUP BY dm";
@@ -441,7 +444,7 @@ class ProjectStats extends Stats
 
 		$sql = "SELECT date_format(t.datec,'%m') as dm, count(t.opp_amount)";
 		$sql .= " FROM " . MAIN_DB_PREFIX . "projet as t";
-		if (! $user->rights->societe->client->voir && ! $user->societe_id)
+		if (! $user->rights->societe->client->voir && ! $user->soc_id)
 			$sql .= " INNER JOIN " . MAIN_DB_PREFIX . "societe_commerciaux as sc ON sc.fk_soc=t.fk_soc AND sc.fk_user=" . $user->id;
 		$sql .= $this->buildWhere();
 		$sql .= " GROUP BY dm";
diff --git a/htdocs/projet/class/taskstats.class.php b/htdocs/projet/class/taskstats.class.php
new file mode 100644
index 0000000000000000000000000000000000000000..b71c88f3d6b6cc37919815b18929813fb834e0e7
--- /dev/null
+++ b/htdocs/projet/class/taskstats.class.php
@@ -0,0 +1,184 @@
+<?php
+/* Lead
+ * Copyright (C) 2014-2015 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
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+include_once DOL_DOCUMENT_ROOT . '/core/class/stats.class.php';
+include_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
+
+
+/**
+ * Class to manage statistics on project tasks
+ */
+class TaskStats extends Stats
+{
+	private $project;
+	public $userid;
+	public $socid;
+	public $year;
+
+	function __construct($db)
+	{
+		global $conf, $user;
+
+		$this->db = $db;
+
+		require_once 'task.class.php';
+		$this->task = new Task($this->db);
+	}
+
+
+	/**
+	 * Return all tasks grouped by status.
+	 *
+	 * @param  int             $limit Limit results
+	 * @return array|int       Array with value or -1 if error
+	 * @throws Exception
+	 */
+	function getAllTaskByStatus($limit = 5)
+	{
+		global $conf, $user, $langs;
+
+		$datay = array();
+
+		$sql = "SELECT";
+		$sql .= " COUNT(t.rowid), t.priority";
+		$sql.= " FROM ". MAIN_DB_PREFIX . "projet_task as t INNER JOIN " . MAIN_DB_PREFIX . "projet as p ON p.rowid = t.fk_projet";
+		if (! $user->rights->societe->client->voir && ! $user->soc_id)
+			$sql .= " INNER JOIN " . MAIN_DB_PREFIX . "societe_commerciaux as sc ON sc.fk_soc=t.fk_soc AND sc.fk_user=" . $user->id;
+		$sql .= $this->buildWhere();
+		//$sql .= " AND t.fk_statut <> 0";     // We want historic also, so all task not draft
+		$sql .= " GROUP BY t.priority";
+
+		$result = array ();
+		$res = array ();
+
+		dol_syslog(get_class($this) . '::' . __METHOD__ . "", LOG_DEBUG);
+		$resql = $this->db->query($sql);
+		if ($resql) {
+			$num = $this->db->num_rows($resql);
+			$i = 0;
+			$other = 0;
+			while ( $i < $num ) {
+				$row = $this->db->fetch_row($resql);
+				if ($i < $limit || $num == $limit)
+				{
+					$result[$i] = array(
+						$row[1],
+						$row[0]
+					);
+				}
+				else
+					$other += $row[1];
+				$i++;
+			}
+			if ($num > $limit)
+				$result[$i] = array (
+						$langs->transnoentitiesnoconv("Other"),
+						$other
+				);
+			$this->db->free($resql);
+		} else {
+			$this->error = "Error " . $this->db->lasterror();
+			dol_syslog(get_class($this) . '::' . __METHOD__ . ' ' . $this->error, LOG_ERR);
+			return -1;
+		}
+
+		return $result;
+	}
+
+	/**
+	 * Return count, and sum of products
+	 *
+	 * @return array of values
+	 */
+	function getAllByYear()
+	{
+		global $conf, $user, $langs;
+
+		$datay = array ();
+
+		$wonlostfilter=0; // No filter on status WON/LOST
+
+		$sql = "SELECT date_format(t.datec,'%Y') as year, COUNT(t.rowid) as nb";
+		$sql.= " FROM ". MAIN_DB_PREFIX . "projet_task as t INNER JOIN " . MAIN_DB_PREFIX . "projet as p ON p.rowid = t.fk_projet";
+		if (! $user->rights->societe->client->voir && ! $user->soc_id)
+			$sql .= " INNER JOIN " . MAIN_DB_PREFIX . "societe_commerciaux as sc ON sc.fk_soc=t.fk_soc AND sc.fk_user=" . $user->id;
+		$sql.= $this->buildWhere();
+		$sql.= " GROUP BY year";
+		$sql.= $this->db->order('year', 'DESC');
+
+		return $this->_getAllByYear($sql);
+	}
+
+
+	/**
+	 * Build the where part
+	 *
+	 * @return string
+	 */
+	public function buildWhere()
+	{
+		$sqlwhere_str = '';
+		$sqlwhere = array();
+
+		$sqlwhere[] = ' t.entity IN (' . getEntity('project') . ')';
+
+		if (! empty($this->userid))
+			$sqlwhere[] = ' t.fk_user_resp=' . $this->userid;
+		if (! empty($this->socid))
+			$sqlwhere[] = ' t.fk_soc=' . $this->socid;
+		if (! empty($this->year) && empty($this->yearmonth))
+			$sqlwhere[] = " date_format(t.datec,'%Y')='" . $this->db->escape($this->year) . "'";
+		if (! empty($this->yearmonth))
+			$sqlwhere[] = " t.datec BETWEEN '" . $this->db->idate(dol_get_first_day($this->yearmonth)) . "' AND '" . $this->db->idate(dol_get_last_day($this->yearmonth)) . "'";
+
+		if (! empty($this->status))
+			$sqlwhere[] = " t.priority IN (" . $this->priority . ")";
+
+		if (count($sqlwhere) > 0) {
+			$sqlwhere_str = ' WHERE ' . implode(' AND ', $sqlwhere);
+		}
+
+		return $sqlwhere_str;
+	}
+
+	/**
+	 * Return Task number by month for a year
+	 *
+	 * @param int $year scan
+	 * @return array of values
+	 */
+	function getNbByMonth($year)
+	{
+		global $user;
+
+		$this->yearmonth = $year;
+
+		$sql = "SELECT date_format(t.datec,'%m') as dm, COUNT(t.rowid) as nb";
+		$sql.= " FROM ". MAIN_DB_PREFIX . "projet_task as t INNER JOIN " . MAIN_DB_PREFIX . "projet as p ON p.rowid = t.fk_projet";
+		if (! $user->rights->societe->client->voir && ! $user->soc_id)
+			$sql .= " INNER JOIN " . MAIN_DB_PREFIX . "societe_commerciaux as sc ON sc.fk_soc=t.fk_soc AND sc.fk_user=" . $user->id;
+		$sql .= $this->buildWhere();
+		$sql .= " GROUP BY dm";
+		$sql .= $this->db->order('dm', 'DESC');
+
+		$this->yearmonth=0;
+
+		$res = $this->_getNbByMonth($year, $sql);
+		// var_dump($res);print '<br>';
+		return $res;
+	}
+}
diff --git a/htdocs/projet/tasks/list.php b/htdocs/projet/tasks/list.php
index 4e31434dbc4a797be5ef849530606f8695384500..4af874ce21ebe0aa715cdd6fbb22a6c77c1c3a1e 100644
--- a/htdocs/projet/tasks/list.php
+++ b/htdocs/projet/tasks/list.php
@@ -43,7 +43,7 @@ $id=GETPOST('id','int');
 $search_all=GETPOST('search_all', 'alphanohtml');
 $search_categ=GETPOST("search_categ",'alpha');
 $search_project=GETPOST('search_project');
-if (! isset($_GET['search_projectstatus']) && ! isset($_POST['search_projectstatus'])) 
+if (! isset($_GET['search_projectstatus']) && ! isset($_POST['search_projectstatus']))
 {
     if ($search_all != '') $search_projectstatus=-1;
     else $search_projectstatus=1;
@@ -173,14 +173,14 @@ if (empty($reshook))
         $toselect='';
         $search_array_options=array();
     }
-    
+
     // Mass actions
     $objectclass='Task';
     $objectlabel='Tasks';
     $permtoread = $user->rights->projet->lire;
     $permtodelete = $user->rights->projet->supprimer;
     $uploaddir = $conf->projet->dir_output.'/tasks';
-    include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';    
+    include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';
 }
 
 if (empty($search_projectstatus) && $search_projectstatus == '') $search_projectstatus=1;
@@ -322,7 +322,7 @@ foreach ($search_array_options as $key => $val)
     $typ=$extrafields->attribute_type[$tmpkey];
     $mode=0;
     if (in_array($typ, array('int','double'))) $mode=1;    // Search on a numeric
-    if ($val && ( ($crit != '' && ! in_array($typ, array('select'))) || ! empty($crit))) 
+    if ($val && ( ($crit != '' && ! in_array($typ, array('select'))) || ! empty($crit)))
     {
         $sql .= natural_search('ef.'.$tmpkey, $crit, $mode);
     }
@@ -396,7 +396,7 @@ foreach ($search_array_options as $key => $val)
     $tmpkey=preg_replace('/search_options_/','',$key);
     if ($val != '') $param.='&search_options_'.$tmpkey.'='.urlencode($val);
 }
-    
+
 // List of mass actions available
 $arrayofmassactions =  array(
 //    'presend'=>$langs->trans("SendByMail"),
@@ -544,7 +544,7 @@ if (! empty($arrayfields['t.progress']['checked'])) print '<td class="liste_titr
 // Extra fields
 if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label))
 {
-    foreach($extrafields->attribute_label as $key => $val) 
+    foreach($extrafields->attribute_label as $key => $val)
     {
         if (! empty($arrayfields["ef.".$key]['checked']))
         {
@@ -649,7 +649,7 @@ while ($i < min($num,$limit))
 	$projectstatic->public = $obj->public;
 	$projectstatic->statut = $obj->projectstatus;
 	$projectstatic->datee = $db->jdate($obj->projectdatee);
-	
+
 	$userAccess = $projectstatic->restrictedProjectArea($user);    // why this ?
 	if ($userAccess >= 0)
 	{
@@ -663,7 +663,7 @@ while ($i < min($num,$limit))
     		if ($object->hasDelay()) print img_warning("Late");
     	    print '</td>';
 		    if (! $i) $totalarray['nbfield']++;
-    	}        	 
+    	}
 	    // Label
     	if (! empty($arrayfields['t.label']['checked']))
     	{
@@ -730,7 +730,7 @@ while ($i < min($num,$limit))
     	    print '</td>';
     	    if (! $i) $totalarray['nbfield']++;
     	}
-    	
+
     	// Planned workload
     	if (! empty($arrayfields['t.planned_workload']['checked']))
     	{
@@ -764,7 +764,7 @@ while ($i < min($num,$limit))
             if (! $i) $totalarray['nbfield']++;
 		    if (! $i) $totalarray['totaldurationeffectivefield']=$totalarray['nbfield'];
 		    $totalarray['totaldurationeffective'] += $obj->duration_effective;
-    	}    		
+    	}
 	    // Calculated progress
     	if (! empty($arrayfields['t.progress_calculated']['checked']))
     	{
@@ -777,7 +777,7 @@ while ($i < min($num,$limit))
     		print '</td>';
             if (! $i) $totalarray['nbfield']++;
             if (! $i) $totalarray['totalprogress_calculated']=$totalarray['nbfield'];
-    	}    		
+    	}
 	    // Declared progress
     	if (! empty($arrayfields['t.progress']['checked']))
     	{
@@ -843,13 +843,13 @@ while ($i < min($num,$limit))
         }
         print '</td>';
         if (! $i) $totalarray['nbfield']++;
-		
+
 		print "</tr>\n";
-    
+
 		//print projectLinesa();
 	}
 
-	$i++;    
+	$i++;
 }
 
 // Show total line
diff --git a/htdocs/projet/tasks/stats/index.php b/htdocs/projet/tasks/stats/index.php
new file mode 100644
index 0000000000000000000000000000000000000000..b03d01a80065c5ef017d44e8e084e24789e87e4a
--- /dev/null
+++ b/htdocs/projet/tasks/stats/index.php
@@ -0,0 +1,218 @@
+<?php
+/* Copyright (C) 2014-2015 Florian HENRY       <florian.henry@open-concept.pro>
+ * Copyright (C) 2015      Laurent Destailleur <ldestailleur@users.sourceforge.net>
+ *
+ * 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
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ *       \file       htdocs/projet/tasks/stats/index.php
+ *       \ingroup    project
+ *       \brief      Page for tasks statistics
+ */
+
+require '../../../main.inc.php';
+require_once DOL_DOCUMENT_ROOT.'/core/class/dolgraph.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/projet/class/taskstats.class.php';
+
+// Security check
+if (! $user->rights->projet->lire)
+	accessforbidden();
+
+
+$WIDTH=DolGraph::getDefaultGraphSizeForStats('width');
+$HEIGHT=DolGraph::getDefaultGraphSizeForStats('height');
+
+$userid=GETPOST('userid','int');
+$socid=GETPOST('socid','int');
+// Security check
+if ($user->societe_id > 0)
+{
+	$action = '';
+	$socid = $user->societe_id;
+}
+$nowyear=strftime("%Y", dol_now());
+$year = GETPOST('year')>0?GETPOST('year'):$nowyear;
+//$startyear=$year-2;
+$startyear=$year-1;
+$endyear=$year;
+
+$langs->load('companies');
+$langs->load('projects');
+
+
+/*
+ * View
+ */
+
+$form=new Form($db);
+
+$includeuserlist=array();
+
+
+llxHeader('', $langs->trans('Tasks'));
+
+$title=$langs->trans("TasksStatistics");
+$dir=$conf->projet->dir_output.'/temp';
+
+print load_fiche_titre($title,'','title_project.png');
+
+dol_mkdir($dir);
+
+
+$stats_tasks= new TaskStats($db);
+if (!empty($userid) && $userid!=-1) $stats_tasks->userid=$userid;
+if (!empty($socid)  && $socid!=-1) $stats_tasks->socid=$socid;
+if (!empty($year)) $stats_tasks->year=$year;
+
+
+
+// Build graphic number of object
+// $data = array(array('Lib',val1,val2,val3),...)
+$data = $stats_tasks->getNbByMonthWithPrevYear($endyear,$startyear);
+//var_dump($data);
+
+$filenamenb = $conf->project->dir_output . "/stats/tasknbprevyear-".$year.".png";
+$fileurlnb = DOL_URL_ROOT . '/viewimage.php?modulepart=taskstats&amp;file=tasknbprevyear-'.$year.'.png';
+
+$px1 = new DolGraph();
+$mesg = $px1->isGraphKo();
+if (! $mesg)
+{
+	$px1->SetData($data);
+	$px1->SetPrecisionY(0);
+	$i=$startyear;$legend=array();
+	while ($i <= $endyear)
+	{
+		$legend[]=$i;
+		$i++;
+	}
+	$px1->SetLegend($legend);
+	$px1->SetMaxValue($px1->GetCeilMaxValue());
+	$px1->SetWidth($WIDTH);
+	$px1->SetHeight($HEIGHT);
+	$px1->SetYLabel($langs->trans("ProjectNbTask"));
+	$px1->SetShading(3);
+	$px1->SetHorizTickIncrement(1);
+	$px1->SetPrecisionY(0);
+	$px1->mode='depth';
+	$px1->SetTitle($langs->trans("ProjectNbTaskByMonth"));
+
+	$px1->draw($filenamenb,$fileurlnb);
+}
+
+
+// Show array
+$stats_tasks->year=0;
+$data_all_year = $stats_tasks->getAllByYear();
+
+if (!empty($year)) $stats_tasks->year=$year;
+$arrayyears=array();
+foreach($data_all_year as $val) {
+	$arrayyears[$val['year']]=$val['year'];
+}
+if (! count($arrayyears)) $arrayyears[$nowyear]=$nowyear;
+
+
+$h=0;
+$head = array();
+$head[$h][0] = DOL_URL_ROOT . '/projet/tasks/stats/index.php?mode='.$mode;
+$head[$h][1] = $langs->trans("ByMonthYear");
+$head[$h][2] = 'byyear';
+$h++;
+
+complete_head_from_modules($conf,$langs,null,$head,$h,$type);
+
+dol_fiche_head($head,'byyear',$langs->trans("Statistics"), -1, '');
+
+
+print '<div class="fichecenter"><div class="fichethirdleft">';
+
+print '<form name="stats" method="POST" action="'.$_SERVER["PHP_SELF"].'">';
+
+print '<table class="noborder" width="100%">';
+print '<tr class="liste_titre"><td class="liste_titre" colspan="2">'.$langs->trans("Filter").'</td></tr>';
+// Company
+/*print '<tr><td>'.$langs->trans("ThirdParty").'</td><td>';
+if ($mode == 'customer') $filter='s.client in (1,2,3)';
+if ($mode == 'supplier') $filter='s.fournisseur = 1';
+print $form->select_company($socid,'socid',$filter,1,0,0,array(),0,'','style="width: 95%"');
+print '</td></tr>';
+*/
+// User
+/*print '<tr><td>'.$langs->trans("ProjectCommercial").'</td><td>';
+print $form->select_dolusers($userid, 'userid', 1, array(),0,$includeuserlist);
+print '</td></tr>';*/
+// Year
+print '<tr><td>'.$langs->trans("Year").'</td><td>';
+if (! in_array($year,$arrayyears)) $arrayyears[$year]=$year;
+if (! in_array($nowyear,$arrayyears)) $arrayyears[$nowyear]=$nowyear;
+arsort($arrayyears);
+print $form->selectarray('year',$arrayyears,$year,0);
+print '</td></tr>';
+print '<tr><td align="center" colspan="2"><input type="submit" name="submit" class="button" value="'.$langs->trans("Refresh").'"></td></tr>';
+print '</table>';
+print '</form>';
+print '<br><br>';
+
+print '<table class="noborder" width="100%">';
+print '<tr class="liste_titre" height="24">';
+print '<td align="center">'.$langs->trans("Year").'</td>';
+print '<td align="right">'.$langs->trans("NbOfTasks").'</td>';
+print '</tr>';
+
+$oldyear=0;
+$var=true;
+foreach ($data_all_year as $val)
+{
+	$year = $val['year'];
+	while ($year && $oldyear > $year+1)
+	{	// If we have empty year
+		$oldyear--;
+
+		print '<tr '.$bc[$var].' height="24">';
+		print '<td align="center"><a href="'.$_SERVER["PHP_SELF"].'?year='.$oldyear.'&amp;mode='.$mode.($socid>0?'&socid='.$socid:'').($userid>0?'&userid='.$userid:'').'">'.$oldyear.'</a></td>';
+		print '<td align="right">0</td>';
+		print '</tr>';
+	}
+
+	print '<tr '.$bc[$var].' height="24">';
+	print '<td align="center"><a href="'.$_SERVER["PHP_SELF"].'?year='.$year.'&amp;mode='.$mode.($socid>0?'&socid='.$socid:'').($userid>0?'&userid='.$userid:'').'">'.$year.'</a></td>';
+	print '<td align="right">'.$val['nb'].'</td>';
+	print '</tr>';
+	$oldyear=$year;
+}
+
+print '</table>';
+
+print '</div><div class="fichetwothirdright"><div class="ficheaddleft">';
+
+$stringtoshow.= '<table class="border" width="100%"><tr valign="top"><td align="center">';
+if ($mesg) { print $mesg; }
+else {
+	$stringtoshow.= $px1->show();
+	$stringtoshow.= "<br>\n";
+}
+$stringtoshow.= '</td></tr></table>';
+
+print $stringtoshow;
+
+
+print '</div></div></div>';
+print '<div style="clear:both"></div>';
+
+
+llxFooter();
+$db->close();
diff --git a/htdocs/public/onlinesign/newonlinesign.php b/htdocs/public/onlinesign/newonlinesign.php
new file mode 100644
index 0000000000000000000000000000000000000000..73d9f41eab005c0b587e9ec87749b06439c2caee
--- /dev/null
+++ b/htdocs/public/onlinesign/newonlinesign.php
@@ -0,0 +1,640 @@
+<?php
+/* Copyright (C) 2001-2002	Rodolphe Quiedeville	<rodolphe@quiedeville.org>
+ * Copyright (C) 2006-2017	Laurent Destailleur		<eldy@users.sourceforge.net>
+ * Copyright (C) 2009-2012	Regis Houssin			<regis.houssin@capnetworks.com>
+ *
+ * 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
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * For paypal test: https://developer.paypal.com/
+ * For paybox test: ???
+ */
+
+/**
+ *     	\file       htdocs/public/onlinesign/newsign.php
+ *		\ingroup    core
+ *		\brief      File to offer a way to make an online signature for a particular Dolibarr entity
+ */
+
+define("NOLOGIN",1);		// This means this output page does not require to be logged.
+define("NOCSRFCHECK",1);	// We accept to go on this page from external web site.
+
+// For MultiCompany module.
+// Do not use GETPOST here, function is not defined and define must be done before including main.inc.php
+// TODO This should be useless. Because entity must be retreive from object ref and not from url.
+$entity=(! empty($_GET['entity']) ? (int) $_GET['entity'] : (! empty($_POST['entity']) ? (int) $_POST['entity'] : 1));
+if (is_numeric($entity)) define("DOLENTITY", $entity);
+
+require '../../main.inc.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
+
+// Security check
+// No check on module enabled. Done later according to $validpaymentmethod
+
+$langs->load("main");
+$langs->load("other");
+$langs->load("dict");
+$langs->load("bills");
+$langs->load("companies");
+$langs->load("errors");
+$langs->load("paybox");     // File with generic data
+
+$action=GETPOST('action','alpha');
+
+// Input are:
+// type ('invoice','order','contractline'),
+// id (object id),
+// amount (required if id is empty),
+// tag (a free text, required if type is empty)
+// currency (iso code)
+
+$suffix=GETPOST("suffix",'alpha');
+$SOURCE=GETPOST("source",'alpha');
+$ref=$REF=GETPOST("ref",'alpha');
+
+if (! $action)
+{
+    if ($source && ! $ref)
+    {
+    	dol_print_error('',$langs->trans('ErrorBadParameters')." - ref");
+    	exit;
+    }
+}
+
+
+$paymentmethod='';
+$validpaymentmethod=array();
+
+
+
+
+// Define $urlwithroot
+//$urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root));
+//$urlwithroot=$urlwithouturlroot.DOL_URL_ROOT;		// This is to use external domain name found into config file
+$urlwithroot=DOL_MAIN_URL_ROOT;						// This is to use same domain name than current. For Paypal payment, we can use internal URL like localhost.
+
+
+// Complete urls for post treatment
+$SECUREKEY=GETPOST("securekey");	        // Secure key
+
+if (! empty($SOURCE))
+{
+    $urlok.='source='.urlencode($SOURCE).'&';
+    $urlko.='source='.urlencode($SOURCE).'&';
+}
+if (! empty($REF))
+{
+    $urlok.='ref='.urlencode($REF).'&';
+    $urlko.='ref='.urlencode($REF).'&';
+}
+if (! empty($SECUREKEY))
+{
+    $urlok.='securekey='.urlencode($SECUREKEY).'&';
+    $urlko.='securekey='.urlencode($SECUREKEY).'&';
+}
+if (! empty($entity))
+{
+	$urlok.='entity='.urlencode($entity).'&';
+	$urlko.='entity='.urlencode($entity).'&';
+}
+$urlok=preg_replace('/&$/','',$urlok);  // Remove last &
+$urlko=preg_replace('/&$/','',$urlko);  // Remove last &
+
+
+
+
+/*
+ * Actions
+ */
+
+
+if ($action == 'dosign')
+{
+    // TODO
+
+}
+
+
+/*
+ * View
+ */
+
+$head='';
+if (! empty($conf->global->MAIN_SIGN_CSS_URL)) $head='<link rel="stylesheet" type="text/css" href="'.$conf->global->MAIN_SIGN_CSS_URL.'?lang='.$langs->defaultlang.'">'."\n";
+
+$conf->dol_hide_topmenu=1;
+$conf->dol_hide_leftmenu=1;
+
+llxHeader($head, $langs->trans("OnlineSignature"), '', '', 0, 0, '', '', '', 'onlinepaymentbody');
+
+// Check link validity
+if (! empty($SOURCE) && in_array($ref, array('member_ref', 'contractline_ref', 'invoice_ref', 'order_ref', '')))
+{
+    $langs->load("errors");
+    dol_print_error_email('BADREFINONLINESIGNFORM', $langs->trans("ErrorBadLinkSourceSetButBadValueForRef", $SOURCE, $ref));
+    llxFooter();
+    $db->close();
+    exit;
+}
+
+print '<span id="dolpaymentspan"></span>'."\n";
+print '<div class="center">'."\n";
+print '<form id="dolpaymentform" class="center" name="paymentform" action="'.$_SERVER["PHP_SELF"].'" method="POST">'."\n";
+print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">'."\n";
+print '<input type="hidden" name="action" value="dosign">'."\n";
+print '<input type="hidden" name="tag" value="'.GETPOST("tag",'alpha').'">'."\n";
+print '<input type="hidden" name="suffix" value="'.GETPOST("suffix",'alpha').'">'."\n";
+print '<input type="hidden" name="securekey" value="'.$SECUREKEY.'">'."\n";
+print '<input type="hidden" name="entity" value="'.$entity.'" />';
+print "\n";
+print '<!-- Form to sign -->'."\n";
+
+print '<table id="dolpaymenttable" summary="Payment form" class="center">'."\n";
+
+// Show logo (search order: logo defined by PAYBOX_LOGO_suffix, then PAYBOX_LOGO, then small company logo, large company logo, theme logo, common logo)
+$width=0;
+// Define logo and logosmall
+$logosmall=$mysoc->logo_small;
+$logo=$mysoc->logo;
+$paramlogo='ONLINE_SIGN_LOGO_'.$suffix;
+if (! empty($conf->global->$paramlogo)) $logosmall=$conf->global->$paramlogo;
+else if (! empty($conf->global->ONLINE_SIGN_LOGO)) $logosmall=$conf->global->ONLINE_SIGN_LOGO;
+//print '<!-- Show logo (logosmall='.$logosmall.' logo='.$logo.') -->'."\n";
+// Define urllogo
+$urllogo='';
+if (! empty($logosmall) && is_readable($conf->mycompany->dir_output.'/logos/thumbs/'.$logosmall))
+{
+	$urllogo=DOL_URL_ROOT.'/viewimage.php?modulepart=mycompany&amp;file='.urlencode('thumbs/'.$logosmall);
+}
+elseif (! empty($logo) && is_readable($conf->mycompany->dir_output.'/logos/'.$logo))
+{
+	$urllogo=DOL_URL_ROOT.'/viewimage.php?modulepart=mycompany&amp;file='.urlencode($logo);
+	$width=96;
+}
+// Output html code for logo
+if ($urllogo)
+{
+	print '<tr>';
+	print '<td align="center"><img id="dolpaymentlogo" title="'.$title.'" src="'.$urllogo.'"';
+	if ($width) print ' width="'.$width.'"';
+	print '></td>';
+	print '</tr>'."\n";
+}
+
+// Output introduction text
+$text='';
+if (! empty($conf->global->ONLINE_SIGN_NEWFORM_TEXT))
+{
+    $langs->load("members");
+    if (preg_match('/^\((.*)\)$/',$conf->global->ONLINE_SIGN_NEWFORM_TEXT,$reg)) $text.=$langs->trans($reg[1])."<br>\n";
+    else $text.=$conf->global->ONLINE_SIGN_NEWFORM_TEXT."<br>\n";
+    $text='<tr><td align="center"><br>'.$text.'<br></td></tr>'."\n";
+}
+if (empty($text))
+{
+    $text.='<tr><td class="textpublicpayment"><br><strong>'.$langs->trans("WelcomeOnOnlineSignaturePage").'</strong><br></td></tr>'."\n";
+    $text.='<tr><td class="textpublicpayment"><br>'.$langs->trans("ThisScreenAllowsYouToSignDocFrom",$creditor).'<br><br></td></tr>'."\n";
+}
+print $text;
+
+// Output payment summary form
+print '<tr><td align="center">';
+print '<table with="100%" id="tablepublicpayment">';
+print '<tr class="liste_total"><td align="left" colspan="2">'.$langs->trans("ThisIsInformationOnDocumentToSign").' :</td></tr>'."\n";
+
+$found=false;
+$error=0;
+$var=false;
+
+// Free payment
+if (! GETPOST("source"))
+{
+	$found=true;
+	$tag=GETPOST("tag");
+	$fulltag=$tag;
+
+	// Creditor
+
+	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
+    print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
+    print '<input type="hidden" name="creditor" value="'.$creditor.'">';
+    print '</td></tr>'."\n";
+
+
+
+    // We do not add fields shipToName, shipToStreet, shipToCity, shipToState, shipToCountryCode, shipToZip, shipToStreet2, phoneNum
+    // as they don't exists (buyer is unknown, tag is free).
+}
+
+
+// Payment on customer order
+if (GETPOST("source") == 'order')
+{
+	$found=true;
+	$langs->load("orders");
+
+	require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
+
+	$order=new Commande($db);
+	$result=$order->fetch('',$ref);
+	if ($result < 0)
+	{
+		$mesg=$order->error;
+		$error++;
+	}
+	else
+	{
+		$result=$order->fetch_thirdparty($order->socid);
+	}
+
+	// Creditor
+
+	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
+    print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
+    print '<input type="hidden" name="creditor" value="'.$creditor.'">';
+    print '</td></tr>'."\n";
+
+	// Debitor
+
+	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("ThirdParty");
+	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$order->thirdparty->name.'</b>';
+
+	// Object
+
+	$text='<b>'.$langs->trans("PaymentOrderRef",$order->ref).'</b>';
+	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Designation");
+	print '</td><td class="CTableRow'.($var?'1':'2').'">'.$text;
+	print '<input type="hidden" name="source" value="'.GETPOST("source",'alpha').'">';
+	print '<input type="hidden" name="ref" value="'.$order->ref.'">';
+	print '</td></tr>'."\n";
+
+
+}
+
+
+// Payment on customer invoice
+if (GETPOST("source") == 'invoice')
+{
+	$found=true;
+	$langs->load("bills");
+
+	require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
+
+	$invoice=new Facture($db);
+	$result=$invoice->fetch('',$ref);
+	if ($result < 0)
+	{
+		$mesg=$invoice->error;
+		$error++;
+	}
+	else
+	{
+		$result=$invoice->fetch_thirdparty($invoice->socid);
+	}
+
+    if ($action != 'dosign') // Do not change amount if we just click on first dosign
+    {
+    	$amount=price2num($invoice->total_ttc - $invoice->getSommePaiement());
+        if (GETPOST("amount",'int')) $amount=GETPOST("amount",'int');
+        $amount=price2num($amount);
+    }
+
+	// Creditor
+
+	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
+    print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
+    print '<input type="hidden" name="creditor" value="'.$creditor.'">';
+    print '</td></tr>'."\n";
+
+	// Debitor
+
+	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("ThirdParty");
+	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$invoice->thirdparty->name.'</b>';
+
+	// Object
+
+	$text='<b>'.$langs->trans("PaymentInvoiceRef",$invoice->ref).'</b>';
+	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Designation");
+	print '</td><td class="CTableRow'.($var?'1':'2').'">'.$text;
+	print '<input type="hidden" name="source" value="'.GETPOST("source",'alpha').'">';
+	print '<input type="hidden" name="ref" value="'.$invoice->ref.'">';
+	print '</td></tr>'."\n";
+
+}
+
+// Payment on contract line
+if (GETPOST("source") == 'contractline')
+{
+	$found=true;
+	$langs->load("contracts");
+
+	require_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
+
+	$contractline=new ContratLigne($db);
+	$result=$contractline->fetch('',$ref);
+	if ($result < 0)
+	{
+		$mesg=$contractline->error;
+		$error++;
+	}
+	else
+	{
+		if ($contractline->fk_contrat > 0)
+		{
+			$contract=new Contrat($db);
+			$result=$contract->fetch($contractline->fk_contrat);
+			if ($result > 0)
+			{
+				$result=$contract->fetch_thirdparty($contract->socid);
+			}
+			else
+			{
+				$mesg=$contract->error;
+				$error++;
+			}
+		}
+		else
+		{
+			$mesg='ErrorRecordNotFound';
+			$error++;
+		}
+	}
+
+    if ($action != 'dosign') // Do not change amount if we just click on first dosign
+    {
+    	$amount=$contractline->total_ttc;
+    	if ($contractline->fk_product)
+    	{
+    		$product=new Product($db);
+    		$result=$product->fetch($contractline->fk_product);
+
+    		// We define price for product (TODO Put this in a method in product class)
+    		if (! empty($conf->global->PRODUIT_MULTIPRICES))
+    		{
+    			$pu_ht = $product->multiprices[$contract->thirdparty->price_level];
+    			$pu_ttc = $product->multiprices_ttc[$contract->thirdparty->price_level];
+    			$price_base_type = $product->multiprices_base_type[$contract->thirdparty->price_level];
+    		}
+    		else
+    		{
+    			$pu_ht = $product->price;
+    			$pu_ttc = $product->price_ttc;
+    			$price_base_type = $product->price_base_type;
+    		}
+
+    		$amount=$pu_ttc;
+    		if (empty($amount))
+    		{
+    			dol_print_error('','ErrorNoPriceDefinedForThisProduct');
+    			exit;
+    		}
+    	}
+        if (GETPOST("amount",'int')) $amount=GETPOST("amount",'int');
+        $amount=price2num($amount);
+    }
+
+	$qty=1;
+	if (GETPOST('qty')) $qty=GETPOST('qty');
+
+	// Creditor
+
+	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
+	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
+    print '<input type="hidden" name="creditor" value="'.$creditor.'">';
+	print '</td></tr>'."\n";
+
+	// Debitor
+
+	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("ThirdParty");
+	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$contract->thirdparty->name.'</b>';
+
+	// Object
+
+	$text='<b>'.$langs->trans("PaymentRenewContractId",$contract->ref,$contractline->ref).'</b>';
+	if ($contractline->fk_product)
+	{
+		$text.='<br>'.$product->ref.($product->label?' - '.$product->label:'');
+	}
+	if ($contractline->description) $text.='<br>'.dol_htmlentitiesbr($contractline->description);
+	//if ($contractline->date_fin_validite) {
+	//	$text.='<br>'.$langs->trans("DateEndPlanned").': ';
+	//	$text.=dol_print_date($contractline->date_fin_validite);
+	//}
+	if ($contractline->date_fin_validite)
+	{
+		$text.='<br>'.$langs->trans("ExpiredSince").': '.dol_print_date($contractline->date_fin_validite);
+	}
+
+	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Designation");
+	print '</td><td class="CTableRow'.($var?'1':'2').'">'.$text;
+	print '<input type="hidden" name="source" value="'.GETPOST("source",'alpha').'">';
+	print '<input type="hidden" name="ref" value="'.$contractline->ref.'">';
+	print '</td></tr>'."\n";
+
+	// Quantity
+
+	$label=$langs->trans("Quantity");
+	$qty=1;
+	$duration='';
+	if ($contractline->fk_product)
+	{
+		if ($product->isService() && $product->duration_value > 0)
+		{
+			$label=$langs->trans("Duration");
+
+			// TODO Put this in a global method
+			if ($product->duration_value > 1)
+			{
+				$dur=array("h"=>$langs->trans("Hours"),"d"=>$langs->trans("DurationDays"),"w"=>$langs->trans("DurationWeeks"),"m"=>$langs->trans("DurationMonths"),"y"=>$langs->trans("DurationYears"));
+			}
+			else
+			{
+				$dur=array("h"=>$langs->trans("Hour"),"d"=>$langs->trans("DurationDay"),"w"=>$langs->trans("DurationWeek"),"m"=>$langs->trans("DurationMonth"),"y"=>$langs->trans("DurationYear"));
+			}
+			$duration=$product->duration_value.' '.$dur[$product->duration_unit];
+		}
+	}
+	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$label.'</td>';
+	print '<td class="CTableRow'.($var?'1':'2').'"><b>'.($duration?$duration:$qty).'</b>';
+	print '<input type="hidden" name="newqty" value="'.dol_escape_htmltag($qty).'">';
+	print '</b></td></tr>'."\n";
+
+	// Amount
+
+	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Amount");
+	if (empty($amount)) print ' ('.$langs->trans("ToComplete").')';
+	print '</td><td class="CTableRow'.($var?'1':'2').'">';
+	if (empty($amount) || ! is_numeric($amount))
+	{
+        print '<input type="hidden" name="amount" value="'.GETPOST("amount",'int').'">';
+	    print '<input class="flat" size=8 type="text" name="newamount" value="'.GETPOST("newamount","int").'">';
+	}
+	else {
+		print '<b>'.price($amount).'</b>';
+        print '<input type="hidden" name="amount" value="'.$amount.'">';
+		print '<input type="hidden" name="newamount" value="'.$amount.'">';
+	}
+	// Currency
+	print ' <b>'.$langs->trans("Currency".$currency).'</b>';
+	print '<input type="hidden" name="currency" value="'.$currency.'">';
+	print '</td></tr>'."\n";
+
+}
+
+// Payment on member subscription
+if (GETPOST("source") == 'membersubscription')
+{
+	$found=true;
+	$langs->load("members");
+
+	require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
+	require_once DOL_DOCUMENT_ROOT.'/adherents/class/subscription.class.php';
+
+	$member=new Adherent($db);
+	$result=$member->fetch('',$ref);
+	if ($result < 0)
+	{
+		$mesg=$member->error;
+		$error++;
+	}
+	else
+	{
+		$subscription=new Subscription($db);
+	}
+
+    if ($action != 'dosign') // Do not change amount if we just click on first dosign
+    {
+    	$amount=$subscription->total_ttc;
+        if (GETPOST("amount",'int')) $amount=GETPOST("amount",'int');
+        $amount=price2num($amount);
+    }
+
+	$fulltag='MEM='.$member->id.'.DAT='.dol_print_date(dol_now(),'%Y%m%d%H%M');
+	if (! empty($TAG)) { $tag=$TAG; $fulltag.='.TAG='.$TAG; }
+	$fulltag=dol_string_unaccent($fulltag);
+
+	// Creditor
+
+	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
+    print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
+    print '<input type="hidden" name="creditor" value="'.$creditor.'">';
+    print '</td></tr>'."\n";
+
+	// Debitor
+
+	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Member");
+	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>';
+	if ($member->morphy == 'mor' && ! empty($member->societe)) print $member->societe;
+	else print $member->getFullName($langs);
+	print '</b>';
+
+	// Object
+
+	$text='<b>'.$langs->trans("PaymentSubscription").'</b>';
+	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Designation");
+	print '</td><td class="CTableRow'.($var?'1':'2').'">'.$text;
+	print '<input type="hidden" name="source" value="'.GETPOST("source",'alpha').'">';
+	print '<input type="hidden" name="ref" value="'.$member->ref.'">';
+	print '</td></tr>'."\n";
+
+	if ($member->last_subscription_date || $member->last_subscription_amount)
+	{
+		// Last subscription date
+
+		print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("LastSubscriptionDate");
+		print '</td><td class="CTableRow'.($var?'1':'2').'">'.dol_print_date($member->last_subscription_date,'day');
+		print '</td></tr>'."\n";
+
+		// Last subscription amount
+
+		print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("LastSubscriptionAmount");
+		print '</td><td class="CTableRow'.($var?'1':'2').'">'.price($member->last_subscription_amount);
+		print '</td></tr>'."\n";
+
+		if (empty($amount) && ! GETPOST('newamount')) $_GET['newamount']=$member->last_subscription_amount;
+	}
+
+	// Amount
+
+	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Amount");
+	if (empty($amount))
+	{
+		print ' ('.$langs->trans("ToComplete");
+		if (! empty($conf->global->MEMBER_EXT_URL_SUBSCRIPTION_INFO)) print ' - <a href="'.$conf->global->MEMBER_EXT_URL_SUBSCRIPTION_INFO.'" rel="external" target="_blank">'.$langs->trans("SeeHere").'</a>';
+		print ')';
+	}
+	print '</td><td class="CTableRow'.($var?'1':'2').'">';
+	if (empty($amount) || ! is_numeric($amount))
+	{
+	    $valtoshow=GETPOST("newamount",'int');
+	    if (! empty($conf->global->MEMBER_MIN_AMOUNT) && $valtoshow) $valtoshow=max($conf->global->MEMBER_MIN_AMOUNT,$valtoshow);
+        print '<input type="hidden" name="amount" value="'.GETPOST("amount",'int').'">';
+	    print '<input class="flat" size="8" type="text" name="newamount" value="'.$valtoshow.'">';
+	}
+	else {
+	    $valtoshow=$amount;
+	    if (! empty($conf->global->MEMBER_MIN_AMOUNT) && $valtoshow) $valtoshow=max($conf->global->MEMBER_MIN_AMOUNT,$valtoshow);
+	    print '<b>'.price($valtoshow).'</b>';
+        print '<input type="hidden" name="amount" value="'.$valtoshow.'">';
+		print '<input type="hidden" name="newamount" value="'.$valtoshow.'">';
+	}
+	// Currency
+	print ' <b>'.$langs->trans("Currency".$currency).'</b>';
+	print '<input type="hidden" name="currency" value="'.$currency.'">';
+	print '</td></tr>'."\n";
+
+}
+
+
+
+
+if (! $found && ! $mesg) $mesg=$langs->trans("ErrorBadParameters");
+
+if ($mesg) print '<tr><td align="center" colspan="2"><br><div class="warning">'.$mesg.'</div></td></tr>'."\n";
+
+print '</table>'."\n";
+print "\n";
+
+if ($action != 'dosign')
+{
+    if ($found && ! $error)	// We are in a management option and no error
+    {
+
+
+    }
+    else
+    {
+    	dol_print_error_email('ERRORNEWONLINESIGNPAYPAL');
+    }
+}
+else
+{
+    // Print
+}
+
+print '</td></tr>'."\n";
+
+print '</table>'."\n";
+print '</form>'."\n";
+print '</div>'."\n";
+print '<br>';
+
+
+htmlPrintOnlinePaymentFooter($mysoc,$langs);
+
+llxFooter('', 'public');
+
+$db->close();
diff --git a/htdocs/public/paybox/newpayment.php b/htdocs/public/paybox/newpayment.php
index c3aff6341cc389c60ea60f87e6cc0d84c74a30a7..97a4c5452ff9c6e7799580c4af41ba2bcf14192f 100644
--- a/htdocs/public/paybox/newpayment.php
+++ b/htdocs/public/paybox/newpayment.php
@@ -135,7 +135,7 @@ if (GETPOST('action','aZ09') == 'dopayment')
     $email=GETPOST("email");
 
     $origfulltag=GETPOST("fulltag",'alpha');
-    
+
 	$mesg='';
 	if (empty($PRICE) || ! is_numeric($PRICE)) $mesg=$langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Amount"));
 	elseif (empty($email))            $mesg=$langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("YourEMail"));
@@ -143,7 +143,7 @@ if (GETPOST('action','aZ09') == 'dopayment')
     elseif (! $origfulltag)           $mesg=$langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("PaymentCode"));
 	elseif (dol_strlen($urlok) > 150) $mesg='Error urlok too long '.$urlok;
     elseif (dol_strlen($urlko) > 150) $mesg='Error urlko too long '.$urlko;
-    
+
 	if (empty($mesg))
 	{
 		dol_syslog("newpayment.php call paybox api and do redirect", LOG_DEBUG);
@@ -169,13 +169,22 @@ $conf->dol_hide_leftmenu=1;
 
 llxHeader($head, $langs->trans("PaymentForm"), '', '', 0, 0, '', '', '', 'onlinepaymentbody');
 
-
 // Common variables
 $creditor=$mysoc->name;
 $paramcreditor='PAYBOX_CREDITOR_'.$suffix;
 if (! empty($conf->global->$paramcreditor)) $creditor=$conf->global->$paramcreditor;
 else if (! empty($conf->global->PAYBOX_CREDITOR)) $creditor=$conf->global->PAYBOX_CREDITOR;
 
+// Check link validity
+if (! empty($SOURCE) && in_array($ref, array('member_ref', 'contractline_ref', 'invoice_ref', 'order_ref', '')))
+{
+    $langs->load("errors");
+    dol_print_error_email('BADREFINPAYMENTFORM', $langs->trans("ErrorBadLinkSourceSetButBadValueForRef", $SOURCE, $ref));
+    llxFooter();
+    $db->close();
+    exit;
+}
+
 print '<span id="dolpaymentspan"></span>'."\n";
 print '<div class="center">';
 print '<form id="dolpaymentform" class="center" name="paymentform" action="'.$_SERVER["PHP_SELF"].'" method="POST">';
@@ -258,14 +267,14 @@ if (! GETPOST("source") && $valid)
     $fulltag=$tag;
 
 	// Creditor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
     print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
     print '<input type="hidden" name="creditor" value="'.$creditor.'">';
     print '</td></tr>'."\n";
 
 	// Amount
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Amount");
 	if (empty($amount)) print ' ('.$langs->trans("ToComplete").')';
 	print '</td><td class="CTableRow'.($var?'1':'2').'">';
@@ -286,7 +295,7 @@ if (! GETPOST("source") && $valid)
 	print '</td></tr>'."\n";
 
 	// Tag
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("PaymentCode");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$fulltag.'</b>';
 	print '<input type="hidden" name="tag" value="'.$tag.'">';
@@ -294,7 +303,7 @@ if (! GETPOST("source") && $valid)
 	print '</td></tr>'."\n";
 
 	// EMail
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("YourEMail");
 	print ' ('.$langs->trans("ToComplete").')';
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><input class="flat" type="text" name="email" size="48" value="'.GETPOST("email").'"></td></tr>'."\n";
@@ -331,19 +340,19 @@ if (GETPOST("source") == 'order' && $valid)
 	$fulltag=dol_string_unaccent($fulltag);
 
 	// Creditor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
     print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
     print '<input type="hidden" name="creditor" value="'.$creditor.'">';
     print '</td></tr>'."\n";
 
 	// Debitor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("ThirdParty");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$order->thirdparty->name.'</b>';
 
 	// Object
-	
+
 	$text='<b>'.$langs->trans("PaymentOrderRef",$order->ref).'</b>';
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Designation");
 	print '</td><td class="CTableRow'.($var?'1':'2').'">'.$text;
@@ -352,7 +361,7 @@ if (GETPOST("source") == 'order' && $valid)
 	print '</td></tr>'."\n";
 
 	// Amount
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Amount");
 	if (empty($amount)) print ' ('.$langs->trans("ToComplete").')';
 	print '</td><td class="CTableRow'.($var?'1':'2').'">';
@@ -372,7 +381,7 @@ if (GETPOST("source") == 'order' && $valid)
 	print '</td></tr>'."\n";
 
 	// Tag
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("PaymentCode");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$fulltag.'</b>';
 	print '<input type="hidden" name="tag" value="'.$tag.'">';
@@ -380,7 +389,7 @@ if (GETPOST("source") == 'order' && $valid)
 	print '</td></tr>'."\n";
 
 	// EMail
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("YourEMail");
 	print ' ('.$langs->trans("ToComplete").')';
 	$email=$order->thirdparty->email;
@@ -419,19 +428,19 @@ if (GETPOST("source") == 'invoice' && $valid)
 	$fulltag=dol_string_unaccent($fulltag);
 
 	// Creditor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
     print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
     print '<input type="hidden" name="creditor" value="'.$creditor.'">';
     print '</td></tr>'."\n";
 
 	// Debitor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("ThirdParty");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$invoice->thirdparty->name.'</b>';
 
 	// Object
-	
+
 	$text='<b>'.$langs->trans("PaymentInvoiceRef",$invoice->ref).'</b>';
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Designation");
 	print '</td><td class="CTableRow'.($var?'1':'2').'">'.$text;
@@ -440,7 +449,7 @@ if (GETPOST("source") == 'invoice' && $valid)
 	print '</td></tr>'."\n";
 
 	// Amount
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Amount");
 	if (empty($amount)) print ' ('.$langs->trans("ToComplete").')';
 	print '</td><td class="CTableRow'.($var?'1':'2').'">';
@@ -460,7 +469,7 @@ if (GETPOST("source") == 'invoice' && $valid)
 	print '</td></tr>'."\n";
 
 	// Tag
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("PaymentCode");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$fulltag.'</b>';
 	print '<input type="hidden" name="tag" value="'.$tag.'">';
@@ -468,7 +477,7 @@ if (GETPOST("source") == 'invoice' && $valid)
 	print '</td></tr>'."\n";
 
 	// EMail
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("YourEMail");
 	print ' ('.$langs->trans("ToComplete").')';
     $email=$invoice->thirdparty->email;
@@ -553,19 +562,19 @@ if (GETPOST("source") == 'contractline' && $valid)
 	if (GETPOST('qty')) $qty=GETPOST('qty');
 
 	// Creditor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
     print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
     print '<input type="hidden" name="creditor" value="'.$creditor.'">';
     print '</td></tr>'."\n";
 
 	// Debitor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("ThirdParty");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$contract->thirdparty->name.'</b>';
 
 	// Object
-	
+
 	$text='<b>'.$langs->trans("PaymentRenewContractId",$contract->ref,$contractline->ref).'</b>';
 	if ($contractline->fk_product)
 	{
@@ -588,7 +597,7 @@ if (GETPOST("source") == 'contractline' && $valid)
 	print '</td></tr>'."\n";
 
 	// Quantity
-	
+
 	$label=$langs->trans("Quantity");
 	$qty=1;
 	$duration='';
@@ -616,7 +625,7 @@ if (GETPOST("source") == 'contractline' && $valid)
 	print '</b></td></tr>'."\n";
 
 	// Amount
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Amount");
 	if (empty($amount)) print ' ('.$langs->trans("ToComplete").')';
 	print '</td><td class="CTableRow'.($var?'1':'2').'">';
@@ -636,7 +645,7 @@ if (GETPOST("source") == 'contractline' && $valid)
 	print '</td></tr>'."\n";
 
 	// Tag
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("PaymentCode");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$fulltag.'</b>';
 	print '<input type="hidden" name="tag" value="'.$tag.'">';
@@ -644,7 +653,7 @@ if (GETPOST("source") == 'contractline' && $valid)
 	print '</td></tr>'."\n";
 
 	// EMail
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("YourEMail");
 	print ' ('.$langs->trans("ToComplete").')';
     $email=$contract->thirdparty->email;
@@ -684,14 +693,14 @@ if (GETPOST("source") == 'membersubscription' && $valid)
 	$fulltag=dol_string_unaccent($fulltag);
 
 	// Creditor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
     print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
     print '<input type="hidden" name="creditor" value="'.$creditor.'">';
     print '</td></tr>'."\n";
 
 	// Debitor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Member");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>';
 	if ($member->morphy == 'mor' && ! empty($member->societe)) print $member->societe;
@@ -699,7 +708,7 @@ if (GETPOST("source") == 'membersubscription' && $valid)
 	print '</b>';
 
 	// Object
-	
+
 	$text='<b>'.$langs->trans("PaymentSubscription").'</b>';
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Designation");
 	print '</td><td class="CTableRow'.($var?'1':'2').'">'.$text;
@@ -710,13 +719,13 @@ if (GETPOST("source") == 'membersubscription' && $valid)
 	if ($member->last_subscription_date || $member->last_subscription_amount)
 	{
 		// Last subscription date
-		
+
 		print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("LastSubscriptionDate");
 		print '</td><td class="CTableRow'.($var?'1':'2').'">'.dol_print_date($member->last_subscription_date,'day');
 		print '</td></tr>'."\n";
 
 		// Last subscription amount
-		
+
 		print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("LastSubscriptionAmount");
 		print '</td><td class="CTableRow'.($var?'1':'2').'">'.price($member->last_subscription_amount);
 		print '</td></tr>'."\n";
@@ -725,7 +734,7 @@ if (GETPOST("source") == 'membersubscription' && $valid)
 	}
 
 	// Amount
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Amount");
 	if (empty($amount)) print ' ('.$langs->trans("ToComplete").')';
 	print '</td><td class="CTableRow'.($var?'1':'2').'">';
@@ -749,7 +758,7 @@ if (GETPOST("source") == 'membersubscription' && $valid)
 	print '</td></tr>'."\n";
 
 	// Tag
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("PaymentCode");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$fulltag.'</b>';
 	print '<input type="hidden" name="tag" value="'.$tag.'">';
@@ -757,7 +766,7 @@ if (GETPOST("source") == 'membersubscription' && $valid)
 	print '</td></tr>'."\n";
 
 	// EMail
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("YourEMail");
     $email=$member->email;
     $email=(GETPOST("email")?GETPOST("email"):(isValidEmail($email)?$email:''));
diff --git a/htdocs/public/payment/newpayment.php b/htdocs/public/payment/newpayment.php
index 788321b62120c014169ec00b6ba8578180b4eac0..cdfaaa2afc683cbfa21f0f765544c04c3ee9703c 100644
--- a/htdocs/public/payment/newpayment.php
+++ b/htdocs/public/payment/newpayment.php
@@ -156,10 +156,10 @@ $urlko=preg_replace('/&$/','',$urlko);  // Remove last &
 if (! empty($conf->paypal->enabled))
 {
 	$langs->load("paypal");
-	
+
 	require_once DOL_DOCUMENT_ROOT.'/paypal/lib/paypal.lib.php';
 	require_once DOL_DOCUMENT_ROOT.'/paypal/lib/paypalfunctions.lib.php';
-	
+
 	$PAYPAL_API_OK="";
 	if ($urlok) $PAYPAL_API_OK=$urlok;
 	$PAYPAL_API_KO="";
@@ -194,7 +194,7 @@ if (! empty($conf->paypal->enabled))
 	        $token = $conf->global->PAYPAL_SECURITY_TOKEN;
 	    }
 		if ($SECUREKEY != $token) $valid=false;
-		
+
 		if (! $valid)
 		{
 	    	print '<div class="error">Bad value for key.</div>';
@@ -202,16 +202,16 @@ if (! empty($conf->paypal->enabled))
 	    	exit;
 		}
 	}
-	
+
     $validpaymentmethod['paypal']='valid';
 }
 
 if (! empty($conf->paybox->enabled))
 {
 	$langs->load("paybox");
-	
+
 	// TODO
-	
+
     $validpaymentmethod['paybox']='valid';
 }
 
@@ -256,10 +256,10 @@ if (empty($validpaymentmethod)) accessforbidden('', 0, 0, 1);
 if ($action == 'dopayment')
 {
 	if ($paymentmethod == 'paypal')
-	{ 
+	{
 		$PAYPAL_API_PRICE=price2num(GETPOST("newamount"),'MT');
 	    $PAYPAL_PAYMENT_TYPE='Sale';
-	
+
 	    $origfulltag=GETPOST("fulltag",'alpha');
 	    $shipToName=GETPOST("shipToName");
 	    $shipToStreet=GETPOST("shipToStreet");
@@ -271,24 +271,24 @@ if ($action == 'dopayment')
 	    $phoneNum=GETPOST("phoneNum");
 	    $email=GETPOST("email");
 	    $desc=GETPOST("desc");
-	
+
 		$mesg='';
 		if (empty($PAYPAL_API_PRICE) || ! is_numeric($PAYPAL_API_PRICE))   $mesg=$langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Amount"));
 		//elseif (empty($EMAIL))          $mesg=$langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("YourEMail"));
 		//elseif (! isValidEMail($EMAIL)) $mesg=$langs->trans("ErrorBadEMail",$EMAIL);
 		elseif (! $origfulltag)        $mesg=$langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("PaymentCode"));
-	
+
 	    //var_dump($_POST);
 		if (empty($mesg))
 		{
 			dol_syslog("newpayment.php call paypal api and do redirect", LOG_DEBUG);
-	
+
 			// Other
 			$PAYPAL_API_DEVISE="USD";
 			//if ($currency == 'EUR') $PAYPAL_API_DEVISE="EUR";
 			//if ($currency == 'USD') $PAYPAL_API_DEVISE="USD";
 	        if (! empty($currency)) $PAYPAL_API_DEVISE=$currency;
-	
+
 		    dol_syslog("Submit Paypal form", LOG_DEBUG);
 		    dol_syslog("PAYPAL_API_USER: $PAYPAL_API_USER", LOG_DEBUG);
 		    //dol_syslog("PAYPAL_API_PASSWORD: $PAYPAL_API_PASSWORD", LOG_DEBUG);  // No password into log files
@@ -308,15 +308,15 @@ if ($action == 'dopayment')
 	        dol_syslog("phoneNum: $phoneNum", LOG_DEBUG);
 	        dol_syslog("email: $email", LOG_DEBUG);
 	        dol_syslog("desc: $desc", LOG_DEBUG);
-	
+
 	        dol_syslog("SCRIPT_URI: ".(empty($_SERVER["SCRIPT_URI"])?'':$_SERVER["SCRIPT_URI"]), LOG_DEBUG);	// If defined script uri must match domain of PAYPAL_API_OK and PAYPAL_API_KO
 		    //$_SESSION["PaymentType"]=$PAYPAL_PAYMENT_TYPE;
 		    //$_SESSION["currencyCodeType"]=$PAYPAL_API_DEVISE;
 		    //$_SESSION["Payment_Amount"]=$PAYPAL_API_PRICE;
-	
+
 		    // A redirect is added if API call successfull
 	        print_paypal_redirect($PAYPAL_API_PRICE,$PAYPAL_API_DEVISE,$PAYPAL_PAYMENT_TYPE,$PAYPAL_API_OK,$PAYPAL_API_KO, $FULLTAG);
-	
+
 			exit;
 		}
 	}
@@ -335,19 +335,28 @@ $conf->dol_hide_leftmenu=1;
 
 llxHeader($head, $langs->trans("PaymentForm"), '', '', 0, 0, '', '', '', 'onlinepaymentbody');
 
+// Check link validity
+if (! empty($SOURCE) && in_array($ref, array('member_ref', 'contractline_ref', 'invoice_ref', 'order_ref', '')))
+{
+    $langs->load("errors");
+    dol_print_error_email('BADREFINPAYMENTFORM', $langs->trans("ErrorBadLinkSourceSetButBadValueForRef", $SOURCE, $ref));
+    llxFooter();
+    $db->close();
+    exit;
+}
 
 if (! empty($conf->paypal->enabled))
 {
-	if (! empty($PAYPAL_API_SANDBOX))
-	{
-		dol_htmloutput_mesg($langs->trans('YouAreCurrentlyInSandboxMode'),'','warning');
-	}
-
 	// Common variables
 	$creditor=$mysoc->name;
 	$paramcreditor='PAYPAL_CREDITOR_'.$suffix;
 	if (! empty($conf->global->$paramcreditor)) $creditor=$conf->global->$paramcreditor;
 	else if (! empty($conf->global->PAYPAL_CREDITOR)) $creditor=$conf->global->PAYPAL_CREDITOR;
+
+	if (! empty($PAYPAL_API_SANDBOX))
+	{
+		dol_htmloutput_mesg($langs->trans('YouAreCurrentlyInSandboxMode'),'','warning');
+	}
 }
 
 print '<span id="dolpaymentspan"></span>'."\n";
@@ -442,14 +451,14 @@ if (! GETPOST("source"))
 	$fulltag=$tag;
 
 	// Creditor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
     print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
     print '<input type="hidden" name="creditor" value="'.$creditor.'">';
     print '</td></tr>'."\n";
 
 	// Amount
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Amount");
 	if (empty($amount)) print ' ('.$langs->trans("ToComplete").')';
 	print '</td><td class="CTableRow'.($var?'1':'2').'">';
@@ -469,7 +478,7 @@ if (! GETPOST("source"))
 	print '</td></tr>'."\n";
 
 	// Tag
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("PaymentCode");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$fulltag.'</b>';
 	print '<input type="hidden" name="tag" value="'.$tag.'">';
@@ -507,26 +516,26 @@ if (GETPOST("source") == 'order')
         if (GETPOST("amount",'int')) $amount=GETPOST("amount",'int');
         $amount=price2num($amount);
     }
-    
+
 	$fulltag='ORD='.$order->ref.'.CUS='.$order->thirdparty->id;
 	//$fulltag.='.NAM='.strtr($order->thirdparty->name,"-"," ");
 	if (! empty($TAG)) { $tag=$TAG; $fulltag.='.TAG='.$TAG; }
 	$fulltag=dol_string_unaccent($fulltag);
 
 	// Creditor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
     print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
     print '<input type="hidden" name="creditor" value="'.$creditor.'">';
     print '</td></tr>'."\n";
 
 	// Debitor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("ThirdParty");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$order->thirdparty->name.'</b>';
 
 	// Object
-	
+
 	$text='<b>'.$langs->trans("PaymentOrderRef",$order->ref).'</b>';
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Designation");
 	print '</td><td class="CTableRow'.($var?'1':'2').'">'.$text;
@@ -535,7 +544,7 @@ if (GETPOST("source") == 'order')
 	print '</td></tr>'."\n";
 
 	// Amount
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Amount");
 	if (empty($amount)) print ' ('.$langs->trans("ToComplete").')';
 	print '</td><td class="CTableRow'.($var?'1':'2').'">';
@@ -555,7 +564,7 @@ if (GETPOST("source") == 'order')
 	print '</td></tr>'."\n";
 
 	// Tag
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("PaymentCode");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$fulltag.'</b>';
 	print '<input type="hidden" name="tag" value="'.$tag.'">';
@@ -617,26 +626,26 @@ if (GETPOST("source") == 'invoice')
         if (GETPOST("amount",'int')) $amount=GETPOST("amount",'int');
         $amount=price2num($amount);
     }
-    
+
 	$fulltag='INV='.$invoice->ref.'.CUS='.$invoice->thirdparty->id;
 	//$fulltag.='.NAM='.strtr($invoice->thirdparty->name,"-"," ");
 	if (! empty($TAG)) { $tag=$TAG; $fulltag.='.TAG='.$TAG; }
 	$fulltag=dol_string_unaccent($fulltag);
 
 	// Creditor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
     print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
     print '<input type="hidden" name="creditor" value="'.$creditor.'">';
     print '</td></tr>'."\n";
 
 	// Debitor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("ThirdParty");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$invoice->thirdparty->name.'</b>';
 
 	// Object
-	
+
 	$text='<b>'.$langs->trans("PaymentInvoiceRef",$invoice->ref).'</b>';
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Designation");
 	print '</td><td class="CTableRow'.($var?'1':'2').'">'.$text;
@@ -645,7 +654,7 @@ if (GETPOST("source") == 'invoice')
 	print '</td></tr>'."\n";
 
 	// Amount
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Amount");
 	if (empty($amount)) print ' ('.$langs->trans("ToComplete").')';
 	print '</td><td class="CTableRow'.($var?'1':'2').'">';
@@ -665,7 +674,7 @@ if (GETPOST("source") == 'invoice')
 	print '</td></tr>'."\n";
 
 	// Tag
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("PaymentCode");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$fulltag.'</b>';
 	print '<input type="hidden" name="tag" value="'.$tag.'">';
@@ -745,7 +754,7 @@ if (GETPOST("source") == 'contractline')
     	{
     		$product=new Product($db);
     		$result=$product->fetch($contractline->fk_product);
-    
+
     		// We define price for product (TODO Put this in a method in product class)
     		if (! empty($conf->global->PRODUIT_MULTIPRICES))
     		{
@@ -759,7 +768,7 @@ if (GETPOST("source") == 'contractline')
     			$pu_ttc = $product->price_ttc;
     			$price_base_type = $product->price_base_type;
     		}
-    
+
     		$amount=$pu_ttc;
     		if (empty($amount))
     		{
@@ -780,19 +789,19 @@ if (GETPOST("source") == 'contractline')
 	if (GETPOST('qty')) $qty=GETPOST('qty');
 
 	// Creditor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
     print '<input type="hidden" name="creditor" value="'.$creditor.'">';
 	print '</td></tr>'."\n";
 
 	// Debitor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("ThirdParty");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$contract->thirdparty->name.'</b>';
 
 	// Object
-	
+
 	$text='<b>'.$langs->trans("PaymentRenewContractId",$contract->ref,$contractline->ref).'</b>';
 	if ($contractline->fk_product)
 	{
@@ -815,7 +824,7 @@ if (GETPOST("source") == 'contractline')
 	print '</td></tr>'."\n";
 
 	// Quantity
-	
+
 	$label=$langs->trans("Quantity");
 	$qty=1;
 	$duration='';
@@ -843,7 +852,7 @@ if (GETPOST("source") == 'contractline')
 	print '</b></td></tr>'."\n";
 
 	// Amount
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Amount");
 	if (empty($amount)) print ' ('.$langs->trans("ToComplete").')';
 	print '</td><td class="CTableRow'.($var?'1':'2').'">';
@@ -863,7 +872,7 @@ if (GETPOST("source") == 'contractline')
 	print '</td></tr>'."\n";
 
 	// Tag
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("PaymentCode");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$fulltag.'</b>';
 	print '<input type="hidden" name="tag" value="'.$tag.'">';
@@ -925,20 +934,20 @@ if (GETPOST("source") == 'membersubscription')
         if (GETPOST("amount",'int')) $amount=GETPOST("amount",'int');
         $amount=price2num($amount);
     }
-    
+
 	$fulltag='MEM='.$member->id.'.DAT='.dol_print_date(dol_now(),'%Y%m%d%H%M');
 	if (! empty($TAG)) { $tag=$TAG; $fulltag.='.TAG='.$TAG; }
 	$fulltag=dol_string_unaccent($fulltag);
 
 	// Creditor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
     print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
     print '<input type="hidden" name="creditor" value="'.$creditor.'">';
     print '</td></tr>'."\n";
 
 	// Debitor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Member");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>';
 	if ($member->morphy == 'mor' && ! empty($member->societe)) print $member->societe;
@@ -946,7 +955,7 @@ if (GETPOST("source") == 'membersubscription')
 	print '</b>';
 
 	// Object
-	
+
 	$text='<b>'.$langs->trans("PaymentSubscription").'</b>';
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Designation");
 	print '</td><td class="CTableRow'.($var?'1':'2').'">'.$text;
@@ -957,13 +966,13 @@ if (GETPOST("source") == 'membersubscription')
 	if ($member->last_subscription_date || $member->last_subscription_amount)
 	{
 		// Last subscription date
-		
+
 		print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("LastSubscriptionDate");
 		print '</td><td class="CTableRow'.($var?'1':'2').'">'.dol_print_date($member->last_subscription_date,'day');
 		print '</td></tr>'."\n";
 
 		// Last subscription amount
-		
+
 		print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("LastSubscriptionAmount");
 		print '</td><td class="CTableRow'.($var?'1':'2').'">'.price($member->last_subscription_amount);
 		print '</td></tr>'."\n";
@@ -972,7 +981,7 @@ if (GETPOST("source") == 'membersubscription')
 	}
 
 	// Amount
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Amount");
 	if (empty($amount))
 	{
@@ -1001,7 +1010,7 @@ if (GETPOST("source") == 'membersubscription')
 	print '</td></tr>'."\n";
 
 	// Tag
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("PaymentCode");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$fulltag.'</b>';
 	print '<input type="hidden" name="tag" value="'.$tag.'">';
@@ -1051,11 +1060,11 @@ if ($action != 'dopayment')
     if ($found && ! $error)	// We are in a management option and no error
     {
         // Buttons for all payments registration methods
-        
+
         if (! empty($conf->paypal->enabled))
         {
         	if (empty($conf->global->PAYPAL_API_INTEGRAL_OR_PAYPALONLY)) $conf->global->PAYPAL_API_INTEGRAL_OR_PAYPALONLY='integral';
-        
+
         	if ($conf->global->PAYPAL_API_INTEGRAL_OR_PAYPALONLY == 'integral')
         	{
         		print '<br><input class="button" type="submit" name="dopayment_paypal" value="'.$langs->trans("PaypalOrCBDoPayment").'">';
@@ -1065,13 +1074,13 @@ if ($action != 'dopayment')
         		print '<br><input class="button" type="submit" name="dopayment_paypal" value="'.$langs->trans("PaypalDoPayment").'">';
         	}
         }
-    
+
         if (! empty($conf->paybox->enabled))
         {
-        
-            
+
+
         }
-        
+
         // TODO Other methods
     }
     else
diff --git a/htdocs/public/paypal/newpayment.php b/htdocs/public/paypal/newpayment.php
index 6de2cb8a4415c0766a3d58ec6859354f8cf98eed..65fbfbd38a7a59446ca066eefa347a9979879685 100644
--- a/htdocs/public/paypal/newpayment.php
+++ b/htdocs/public/paypal/newpayment.php
@@ -265,17 +265,27 @@ $conf->dol_hide_leftmenu=1;
 
 llxHeader($head, $langs->trans("PaymentForm"), '', '', 0, 0, '', '', '', 'onlinepaymentbody');
 
-if (! empty($conf->global->PAYPAL_API_SANDBOX))
-{
-	dol_htmloutput_mesg($langs->trans('YouAreCurrentlyInSandboxMode'),'','warning');
-}
-
 // Common variables
 $creditor=$mysoc->name;
 $paramcreditor='PAYPAL_CREDITOR_'.$suffix;
 if (! empty($conf->global->$paramcreditor)) $creditor=$conf->global->$paramcreditor;
 else if (! empty($conf->global->PAYPAL_CREDITOR)) $creditor=$conf->global->PAYPAL_CREDITOR;
 
+// Check link validity
+if (! empty($SOURCE) && in_array($ref, array('member_ref', 'contractline_ref', 'invoice_ref', 'order_ref', '')))
+{
+    $langs->load("errors");
+    dol_print_error_email('BADREFINPAYMENTFORM', $langs->trans("ErrorBadLinkSourceSetButBadValueForRef", $SOURCE, $ref));
+    llxFooter();
+    $db->close();
+    exit;
+}
+
+if (! empty($conf->global->PAYPAL_API_SANDBOX))
+{
+	dol_htmloutput_mesg($langs->trans('YouAreCurrentlyInSandboxMode'),'','warning');
+}
+
 print '<span id="dopaymentspan"></span>'."\n";
 print '<div class="center">'."\n";
 print '<form id="dolpaymentform" class="center" name="paymentform" action="'.$_SERVER["PHP_SELF"].'" method="POST">'."\n";
@@ -359,14 +369,14 @@ if (! GETPOST("source"))
 	$fulltag=$tag;
 
 	// Creditor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
     print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
     print '<input type="hidden" name="creditor" value="'.$creditor.'">';
     print '</td></tr>'."\n";
 
 	// Amount
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Amount");
 	if (empty($amount)) print ' ('.$langs->trans("ToComplete").')';
 	print '</td><td class="CTableRow'.($var?'1':'2').'">';
@@ -386,7 +396,7 @@ if (! GETPOST("source"))
 	print '</td></tr>'."\n";
 
 	// Tag
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("PaymentCode");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$fulltag.'</b>';
 	print '<input type="hidden" name="tag" value="'.$tag.'">';
@@ -424,26 +434,26 @@ if (GETPOST("source") == 'order')
         if (GETPOST("amount",'int')) $amount=GETPOST("amount",'int');
         $amount=price2num($amount);
     }
-    
+
 	$fulltag='ORD='.$order->ref.'.CUS='.$order->thirdparty->id;
 	//$fulltag.='.NAM='.strtr($order->thirdparty->name,"-"," ");
 	if (! empty($TAG)) { $tag=$TAG; $fulltag.='.TAG='.$TAG; }
 	$fulltag=dol_string_unaccent($fulltag);
 
 	// Creditor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
     print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
     print '<input type="hidden" name="creditor" value="'.$creditor.'">';
     print '</td></tr>'."\n";
 
 	// Debitor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("ThirdParty");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$order->thirdparty->name.'</b>';
 
 	// Object
-	
+
 	$text='<b>'.$langs->trans("PaymentOrderRef",$order->ref).'</b>';
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Designation");
 	print '</td><td class="CTableRow'.($var?'1':'2').'">'.$text;
@@ -452,7 +462,7 @@ if (GETPOST("source") == 'order')
 	print '</td></tr>'."\n";
 
 	// Amount
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Amount");
 	if (empty($amount)) print ' ('.$langs->trans("ToComplete").')';
 	print '</td><td class="CTableRow'.($var?'1':'2').'">';
@@ -472,7 +482,7 @@ if (GETPOST("source") == 'order')
 	print '</td></tr>'."\n";
 
 	// Tag
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("PaymentCode");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$fulltag.'</b>';
 	print '<input type="hidden" name="tag" value="'.$tag.'">';
@@ -534,26 +544,26 @@ if (GETPOST("source") == 'invoice')
         if (GETPOST("amount",'int')) $amount=GETPOST("amount",'int');
         $amount=price2num($amount);
     }
-    
+
 	$fulltag='INV='.$invoice->ref.'.CUS='.$invoice->thirdparty->id;
 	//$fulltag.='.NAM='.strtr($invoice->thirdparty->name,"-"," ");
 	if (! empty($TAG)) { $tag=$TAG; $fulltag.='.TAG='.$TAG; }
 	$fulltag=dol_string_unaccent($fulltag);
 
 	// Creditor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
     print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
     print '<input type="hidden" name="creditor" value="'.$creditor.'">';
     print '</td></tr>'."\n";
 
 	// Debitor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("ThirdParty");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$invoice->thirdparty->name.'</b>';
 
 	// Object
-	
+
 	$text='<b>'.$langs->trans("PaymentInvoiceRef",$invoice->ref).'</b>';
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Designation");
 	print '</td><td class="CTableRow'.($var?'1':'2').'">'.$text;
@@ -562,7 +572,7 @@ if (GETPOST("source") == 'invoice')
 	print '</td></tr>'."\n";
 
 	// Amount
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Amount");
 	if (empty($amount)) print ' ('.$langs->trans("ToComplete").')';
 	print '</td><td class="CTableRow'.($var?'1':'2').'">';
@@ -582,7 +592,7 @@ if (GETPOST("source") == 'invoice')
 	print '</td></tr>'."\n";
 
 	// Tag
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("PaymentCode");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$fulltag.'</b>';
 	print '<input type="hidden" name="tag" value="'.$tag.'">';
@@ -662,7 +672,7 @@ if (GETPOST("source") == 'contractline')
     	{
     		$product=new Product($db);
     		$result=$product->fetch($contractline->fk_product);
-    
+
     		// We define price for product (TODO Put this in a method in product class)
     		if (! empty($conf->global->PRODUIT_MULTIPRICES))
     		{
@@ -676,7 +686,7 @@ if (GETPOST("source") == 'contractline')
     			$pu_ttc = $product->price_ttc;
     			$price_base_type = $product->price_base_type;
     		}
-    
+
     		$amount=$pu_ttc;
     		if (empty($amount))
     		{
@@ -697,19 +707,19 @@ if (GETPOST("source") == 'contractline')
 	if (GETPOST('qty')) $qty=GETPOST('qty');
 
 	// Creditor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
     print '<input type="hidden" name="creditor" value="'.$creditor.'">';
 	print '</td></tr>'."\n";
 
 	// Debitor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("ThirdParty");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$contract->thirdparty->name.'</b>';
 
 	// Object
-	
+
 	$text='<b>'.$langs->trans("PaymentRenewContractId",$contract->ref,$contractline->ref).'</b>';
 	if ($contractline->fk_product)
 	{
@@ -732,7 +742,7 @@ if (GETPOST("source") == 'contractline')
 	print '</td></tr>'."\n";
 
 	// Quantity
-	
+
 	$label=$langs->trans("Quantity");
 	$qty=1;
 	$duration='';
@@ -760,7 +770,7 @@ if (GETPOST("source") == 'contractline')
 	print '</b></td></tr>'."\n";
 
 	// Amount
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Amount");
 	if (empty($amount)) print ' ('.$langs->trans("ToComplete").')';
 	print '</td><td class="CTableRow'.($var?'1':'2').'">';
@@ -780,7 +790,7 @@ if (GETPOST("source") == 'contractline')
 	print '</td></tr>'."\n";
 
 	// Tag
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("PaymentCode");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$fulltag.'</b>';
 	print '<input type="hidden" name="tag" value="'.$tag.'">';
@@ -824,6 +834,7 @@ if (GETPOST("source") == 'membersubscription')
 	require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
 	require_once DOL_DOCUMENT_ROOT.'/adherents/class/subscription.class.php';
 
+
 	$member=new Adherent($db);
 	$result=$member->fetch('',$ref);
 	if ($result < 0)
@@ -842,20 +853,20 @@ if (GETPOST("source") == 'membersubscription')
         if (GETPOST("amount",'int')) $amount=GETPOST("amount",'int');
         $amount=price2num($amount);
     }
-    
+
 	$fulltag='MEM='.$member->id.'.DAT='.dol_print_date(dol_now(),'%Y%m%d%H%M');
 	if (! empty($TAG)) { $tag=$TAG; $fulltag.='.TAG='.$TAG; }
 	$fulltag=dol_string_unaccent($fulltag);
 
 	// Creditor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
     print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
     print '<input type="hidden" name="creditor" value="'.$creditor.'">';
     print '</td></tr>'."\n";
 
 	// Debitor
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Member");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>';
 	if ($member->morphy == 'mor' && ! empty($member->societe)) print $member->societe;
@@ -863,7 +874,7 @@ if (GETPOST("source") == 'membersubscription')
 	print '</b>';
 
 	// Object
-	
+
 	$text='<b>'.$langs->trans("PaymentSubscription").'</b>';
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Designation");
 	print '</td><td class="CTableRow'.($var?'1':'2').'">'.$text;
@@ -874,13 +885,13 @@ if (GETPOST("source") == 'membersubscription')
 	if ($member->last_subscription_date || $member->last_subscription_amount)
 	{
 		// Last subscription date
-		
+
 		print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("LastSubscriptionDate");
 		print '</td><td class="CTableRow'.($var?'1':'2').'">'.dol_print_date($member->last_subscription_date,'day');
 		print '</td></tr>'."\n";
 
 		// Last subscription amount
-		
+
 		print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("LastSubscriptionAmount");
 		print '</td><td class="CTableRow'.($var?'1':'2').'">'.price($member->last_subscription_amount);
 		print '</td></tr>'."\n";
@@ -889,7 +900,7 @@ if (GETPOST("source") == 'membersubscription')
 	}
 
 	// Amount
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Amount");
 	if (empty($amount))
 	{
@@ -918,7 +929,7 @@ if (GETPOST("source") == 'membersubscription')
 	print '</td></tr>'."\n";
 
 	// Tag
-	
+
 	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("PaymentCode");
 	print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$fulltag.'</b>';
 	print '<input type="hidden" name="tag" value="'.$tag.'">';
diff --git a/htdocs/public/stripe/newpayment.php b/htdocs/public/stripe/newpayment.php
index 01ae19c703217aa0421d714e0d99c387216abf1a..af0c880d3c8f42e0a865856bccc42ad1572d228d 100644
--- a/htdocs/public/stripe/newpayment.php
+++ b/htdocs/public/stripe/newpayment.php
@@ -196,7 +196,7 @@ else if (! empty($conf->global->STRIPE_CREDITOR)) $creditor=$conf->global->STRIP
 if ($action == 'dopayment')    // We click on button Create payment
 {
     if (GETPOST('newamount')) $amount = GETPOST('newamount');
-    else 
+    else
     {
         setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Amount")), null, 'errors');
         $action = '';
@@ -209,18 +209,18 @@ if ($action == 'charge')
     // See https://support.stripe.com/questions/which-zero-decimal-currencies-does-stripe-support
     $arrayzerounitcurrency=array('BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF');
     if (! in_array($currency, $arrayzerounitcurrency)) $amount=$amount * 100;
-    
+
     dol_syslog("POST keys  : ".join(',', array_keys($_POST)), LOG_DEBUG, 0, '_stripe');
     dol_syslog("POST values: ".join(',', $_POST), LOG_DEBUG, 0, '_stripe');
-    
+
     $stripeToken = GETPOST("stripeToken",'alpha');
     $email = GETPOST("stripeEmail",'alpha');
 
     dol_syslog("stripeToken = ".$stripeToken, LOG_DEBUG, 0, '_stripe');
     dol_syslog("stripeEmail = ".$stripeEmail, LOG_DEBUG, 0, '_stripe');
-    
+
     $error = 0;
-    
+
     try {
         dol_syslog("Create customer", LOG_DEBUG, 0, '_stripe');
         $customer = \Stripe\Customer::create(array(
@@ -230,7 +230,7 @@ if ($action == 'charge')
             'source'  => $stripeToken           // source can be a token OR array('object'=>'card', 'exp_month'=>xx, 'exp_year'=>xxxx, 'number'=>xxxxxxx, 'cvc'=>xxx, 'name'=>'Cardholder's full name', zip ?)
         ));
         // TODO Add 'business_vat_id' ?
-        
+
         dol_syslog("Create charge", LOG_DEBUG, 0, '_stripe');
         $charge = \Stripe\Charge::create(array(
             'customer' => $customer->id,
@@ -244,14 +244,14 @@ if ($action == 'charge')
         // Since it's a decline, \Stripe\Error\Card will be caught
         $body = $e->getJsonBody();
         $err  = $body['error'];
-    
+
         print('Status is:' . $e->getHttpStatus() . "\n");
         print('Type is:' . $err['type'] . "\n");
         print('Code is:' . $err['code'] . "\n");
         // param is '' in this case
         print('Param is:' . $err['param'] . "\n");
         print('Message is:' . $err['message'] . "\n");
-    
+
         $error++;
         setEventMessages($e->getMessage(), null, 'errors');
         dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe');
@@ -295,7 +295,7 @@ if ($action == 'charge')
         setEventMessages($e->getMessage(), null, 'errors');
         $action='';
     }
-        
+
 	$_SESSION["onlinetoken"] = $stripeToken;
     $_SESSION["FinalPaymentAmt"] = $amount;
     $_SESSION["currencyCodeType"] = $currency;
@@ -303,12 +303,12 @@ if ($action == 'charge')
     $_SESSION['ipaddress'] = $_SERVER['REMOTE_ADDR'];  // Payer ip
     $_SESSION['payerID'] = is_object($customer)?$customer->id:'';
     $_SESSION['TRANSACTIONID'] = is_object($charge)?$charge->id:'';
-    
+
     dol_syslog("Action charge stripe result=".$error." ip=".$_SESSION['ipaddress'], LOG_DEBUG, 0, '_stripe');
     dol_syslog("onlinetoken=".$_SESSION["onlinetoken"]." FinalPaymentAmt=".$_SESSION["FinalPaymentAmt"]." currencyCodeType=".$_SESSION["currencyCodeType"]." payerID=".$_SESSION['payerID']." TRANSACTIONID=".$_SESSION['TRANSACTIONID'], LOG_DEBUG, 0, '_stripe');
     dol_syslog("FULLTAG=".$FULLTAG, LOG_DEBUG, 0, '_stripe');
     dol_syslog("Now call the redirect to paymentok or paymentko", LOG_DEBUG, 0, '_stripe');
-    
+
     if ($error)
     {
         header("Location: ".$urlko);
@@ -319,7 +319,7 @@ if ($action == 'charge')
         header("Location: ".$urlok);
         exit;
     }
-    
+
 }
 
 
@@ -335,6 +335,16 @@ $conf->dol_hide_leftmenu=1;
 
 llxHeader($head, $langs->trans("PaymentForm"), '', '', 0, 0, '', '', '', 'onlinepaymentbody');
 
+// Check link validity
+if (! empty($SOURCE) && in_array($ref, array('member_ref', 'contractline_ref', 'invoice_ref', 'order_ref', '')))
+{
+    $langs->load("errors");
+    dol_print_error_email('BADREFINPAYMENTFORM', $langs->trans("ErrorBadLinkSourceSetButBadValueForRef", $SOURCE, $ref));
+    llxFooter();
+    $db->close();
+    exit;
+}
+
 if (empty($conf->global->STRIPE_LIVE))
 {
     dol_htmloutput_mesg($langs->trans('YouAreCurrentlyInSandboxMode'),'','warning');
@@ -420,7 +430,7 @@ if (! GETPOST("source"))
     $found=true;
     $tag=GETPOST("tag");
     $fulltag=$tag;
-    
+
     // Creditor
     print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
     print '</td><td class="CTableRow'.($var?'1':'2').'"><b>'.$creditor.'</b>';
@@ -485,7 +495,7 @@ if (GETPOST("source") == 'order')
         if (GETPOST("amount",'int')) $amount=GETPOST("amount",'int');
         $amount=price2num($amount);
     }
-    
+
     $fulltag='ORD='.$order->ref.'.CUS='.$order->thirdparty->id;
     //$fulltag.='.NAM='.strtr($order->thirdparty->name,"-"," ");
     if (! empty($TAG)) { $tag=$TAG; $fulltag.='.TAG='.$TAG; }
@@ -600,7 +610,7 @@ if (GETPOST("source") == 'invoice')
     //$fulltag.='.NAM='.strtr($invoice->thirdparty->name,"-"," ");
     if (! empty($TAG)) { $tag=$TAG; $fulltag.='.TAG='.$TAG; }
     $fulltag=dol_string_unaccent($fulltag);
-    
+
     // Creditor
 
     print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Creditor");
@@ -723,7 +733,7 @@ if (GETPOST("source") == 'contractline')
         {
             $product=new Product($db);
             $result=$product->fetch($contractline->fk_product);
-    
+
             // We define price for product (TODO Put this in a method in product class)
             if (! empty($conf->global->PRODUIT_MULTIPRICES))
             {
@@ -737,7 +747,7 @@ if (GETPOST("source") == 'contractline')
                 $pu_ttc = $product->price_ttc;
                 $price_base_type = $product->price_base_type;
             }
-    
+
             $amount=$pu_ttc;
             if (empty($amount))
             {
@@ -749,7 +759,7 @@ if (GETPOST("source") == 'contractline')
         if (GETPOST("amount",'int')) $amount=GETPOST("amount",'int');
         $amount=price2num($amount);
     }
-    
+
     $fulltag='COL='.$contractline->ref.'.CON='.$contract->ref.'.CUS='.$contract->thirdparty->id.'.DAT='.dol_print_date(dol_now(),'%Y%m%d%H%M');
     //$fulltag.='.NAM='.strtr($contract->thirdparty->name,"-"," ");
     if (! empty($TAG)) { $tag=$TAG; $fulltag.='.TAG='.$TAG; }
@@ -904,7 +914,7 @@ if (GETPOST("source") == 'membersubscription')
         if (GETPOST("amount",'int')) $amount=GETPOST("amount",'int');
         $amount=price2num($amount);
     }
-    
+
     $fulltag='MEM='.$member->id.'.DAT='.dol_print_date(dol_now(),'%Y%m%d%H%M');
     if (! empty($TAG)) { $tag=$TAG; $fulltag.='.TAG='.$TAG; }
     $fulltag=dol_string_unaccent($fulltag);
@@ -1059,7 +1069,7 @@ if (preg_match('/^dopayment/',$action))
      data-description="'.$ref.'">
      </script>';
      */
-    
+
     // Personalized checkout
     print '<style>
     /**
@@ -1075,22 +1085,22 @@ if (preg_match('/^dopayment/',$action))
         -webkit-transition: box-shadow 150ms ease;
         transition: box-shadow 150ms ease;
     }
-    
+
     .StripeElement--focus {
         box-shadow: 0 1px 3px 0 #cfd7df;
     }
-    
+
     .StripeElement--invalid {
         border-color: #fa755a;
     }
-    
+
     .StripeElement--webkit-autofill {
         background-color: #fefde5 !important;
     }
     </style>';
-    
+
     print '
-    
+
     <br>
     <form action="'.$_SERVER['REQUEST_URI'].'" method="POST" id="payment-form">';
 
@@ -1106,11 +1116,11 @@ if (preg_match('/^dopayment/',$action))
     print '<input type="hidden" name="entity" value="'.$entity.'" />';
     print '<input type="hidden" name="amount" value="'.$amount.'">'."\n";
     print '<input type="hidden" name="currency" value="'.$currency.'">'."\n";
-    
+
     print '
     <table id="dolpaymenttable" summary="Payment form" class="center">
     <tbody><tr><td class="textpublicpayment">
-                    
+
     <div class="form-row left">
     <label for="card-element">
     Credit or debit card
@@ -1118,7 +1128,7 @@ if (preg_match('/^dopayment/',$action))
     <div id="card-element">
     <!-- a Stripe Element will be inserted here. -->
     </div>
-    
+
     <!-- Used to display form errors -->
     <div id="card-errors" role="alert"></div>
     </div>
@@ -1126,22 +1136,22 @@ if (preg_match('/^dopayment/',$action))
     <button class="button" id="buttontopay">'.$langs->trans("ToPay").'</button>
     <img id="hourglasstopay" class="hidden" src="'.DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/working.gif'.'">
     </td></tr></tbody></table>
-        
+
     </form>
 
-        
+
     <script src="https://js.stripe.com/v2/"></script>
     <script src="https://js.stripe.com/v3/"></script>
-    
+
     <script type="text/javascript" language="javascript">';
     ?>
 
     // Create a Stripe client
     var stripe = Stripe('<?php echo $stripe['publishable_key']; ?>');
-    
+
     // Create an instance of Elements
     var elements = stripe.elements();
-    
+
     // Custom styling can be passed to options when creating an Element.
     // (Note that this demo uses a wider set of styles than the guide below.)
     var style = {
@@ -1160,13 +1170,13 @@ if (preg_match('/^dopayment/',$action))
         iconColor: '#fa755a'
       }
     };
-    
+
     // Create an instance of the card Element
     var card = elements.create('card', {style: style});
-    
+
     // Add an instance of the card Element into the `card-element` <div>
     card.mount('#card-element');
-    
+
     // Handle real-time validation errors from the card Element.
     card.addEventListener('change', function(event) {
       var displayError = document.getElementById('card-errors');
@@ -1176,13 +1186,13 @@ if (preg_match('/^dopayment/',$action))
         displayError.textContent = '';
       }
     });
-    
+
     // Handle form submission
     var form = document.getElementById('payment-form');
     console.log(form);
     form.addEventListener('submit', function(event) {
       event.preventDefault();
-    
+
       stripe.createToken(card).then(function(result) {
         if (result.error) {
           // Inform the user if there was an error
@@ -1194,7 +1204,7 @@ if (preg_match('/^dopayment/',$action))
         }
       });
     });
-    
+
     function stripeTokenHandler(token) {
       // Insert the token ID into the form so it gets submitted to the server
       var form = document.getElementById('payment-form');
@@ -1203,16 +1213,16 @@ if (preg_match('/^dopayment/',$action))
       hiddenInput.setAttribute('name', 'stripeToken');
       hiddenInput.setAttribute('value', token.id);
       form.appendChild(hiddenInput);
-    
+
       // Submit the form
       jQuery('#buttontopay').hide();
       jQuery('#hourglasstopay').show();
       console.log("submit");
       form.submit();
-    }        
-    
+    }
+
     <?php
-    print '</script>';    
+    print '</script>';
 }
 
 
diff --git a/htdocs/societe/admin/societe.php b/htdocs/societe/admin/societe.php
index 63ba12197fddaa32967425566930404b41eaeffe..5c84be25521cc67315e1d9cbe8b882b15dbb218d 100644
--- a/htdocs/societe/admin/societe.php
+++ b/htdocs/societe/admin/societe.php
@@ -42,6 +42,9 @@ if (!$user->admin) accessforbidden();
 /*
  * Actions
  */
+
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
+
 if ($action == 'setcodeclient')
 {
 	if (dolibarr_set_const($db, "SOCIETE_CODECLIENT_ADDON",$value,'chaine',0,'',$conf->entity) > 0)
@@ -101,35 +104,6 @@ if ($action == 'updateoptions')
 	}
 }
 
-// Define constants for submodules that contains parameters (forms with param1, param2, ... and value1, value2, ...)
-if ($action == 'setModuleOptions')
-{
-	$post_size=count($_POST);
-
-	$db->begin();
-
-	for($i=0;$i < $post_size;$i++)
-    {
-    	if (array_key_exists('param'.$i,$_POST))
-    	{
-    		$param=GETPOST("param".$i,'alpha');
-    		$value=GETPOST("value".$i,'alpha');
-    		if ($param) $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity);
-	    	if (! $res > 0) $error++;
-    	}
-    }
-	if (! $error)
-    {
-        $db->commit();
-	    setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
-    }
-    else
-    {
-        $db->rollback();
-	    setEventMessages($langs->trans("Error"), null, 'errors');
-	}
-}
-
 // Activate a document generator module
 if ($action == 'set')
 {
diff --git a/htdocs/supplier_proposal/class/supplier_proposal.class.php b/htdocs/supplier_proposal/class/supplier_proposal.class.php
index 7019933fb9cb2cf7996c847516c8f73d19dcef72..20323136017f27729e0d01d913ba6aa6a71e3efe 100644
--- a/htdocs/supplier_proposal/class/supplier_proposal.class.php
+++ b/htdocs/supplier_proposal/class/supplier_proposal.class.php
@@ -356,11 +356,13 @@ class SupplierProposal extends CommonObject
      *      @param		array		$array_option		extrafields array
 	 * 		@param		string		$ref_fourn			Supplier price reference
 	 * 		@param		int			$fk_unit			Id of the unit to use.
+	 * 		@param		string		$origin				'order', 'supplier_proposal', ...
+	 * 		@param		int			$origin_id			Id of origin line
      *    	@return    	int         	    			>0 if OK, <0 if KO
      *
      *    	@see       	add_product
      */
-	function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $price_base_type='HT', $pu_ttc=0, $info_bits=0, $type=0, $rang=-1, $special_code=0, $fk_parent_line=0, $fk_fournprice=0, $pa_ht=0, $label='',$array_option=0, $ref_fourn='', $fk_unit='')
+    function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $price_base_type='HT', $pu_ttc=0, $info_bits=0, $type=0, $rang=-1, $special_code=0, $fk_parent_line=0, $fk_fournprice=0, $pa_ht=0, $label='',$array_option=0, $ref_fourn='', $fk_unit='', $origin='', $origin_id=0)
     {
     	global $mysoc;
 
@@ -462,7 +464,8 @@ class SupplierProposal extends CommonObject
             $this->line->special_code=$special_code;
             $this->line->fk_parent_line=$fk_parent_line;
             $this->line->fk_unit=$fk_unit;
-
+            $this->line->origin=$origin;
+            $this->line->origin_id=$origin_id;
 			$this->line->ref_fourn = $this->db->escape($ref_fourn);
 
 			// infos marge
@@ -880,7 +883,10 @@ class SupplierProposal extends CommonObject
 							$this->lines[$i]->pa_ht,
 							$this->lines[$i]->label,
 							$this->lines[$i]->array_options,
-							$this->lines[$i]->ref_fourn
+							$this->lines[$i]->ref_fourn,
+							$this->lines[$i]->fk_unit,
+							'supplier_proposal',
+							$this->lines[$i]->rowid
 						);
 
                         if ($result < 0)
diff --git a/htdocs/theme/eldy/style.css.php b/htdocs/theme/eldy/style.css.php
index 33bba8f1404cfe024486bc4692a9cc83bc728c18..3912a9b80fff44d49930b18be5c9a21d1aff12e5 100644
--- a/htdocs/theme/eldy/style.css.php
+++ b/htdocs/theme/eldy/style.css.php
@@ -39,7 +39,7 @@ if (! defined('NOREQUIREAJAX'))   define('NOREQUIREAJAX','1');
 $colorbackhmenu1='80,90,120';      // topmenu
 $colorbackvmenu1='255,255,255';      // vmenu
 $colortopbordertitle1='120,120,120';    // top border of title
-$colorbacktitle1='230,230,230';      // title of tables,list
+$colorbacktitle1='230,230,233';      // title of tables,list
 $colorbacktabcard1='255,255,255';  // card
 $colorbacktabactive='234,234,234';
 $colorbacklineimpair1='255,255,255';    // line impair
@@ -56,7 +56,7 @@ $fontsize='13';
 $fontsizesmaller='12';
 
 if (defined('THEME_ONLY_CONSTANT')) return;
-    
+
 session_cache_limiter(FALSE);
 
 require_once '../../main.inc.php';
@@ -272,8 +272,8 @@ input[type=submit] {
 	margin-left: 5px;
 }
 input, input.flat, form.flat select, select, select.flat, .dataTables_length label select {
-	<?php if (empty($conf->global->THEME_ELDY_SHOW_BORDER_INPUT)) 
-	print "border: none;" 
+	<?php if (empty($conf->global->THEME_ELDY_SHOW_BORDER_INPUT))
+	print "border: none;"
 	?>
 }
 input, input.flat, textarea, textarea.flat, form.flat select, select, select.flat, .dataTables_length label select {
@@ -340,9 +340,9 @@ input.buttongen {
 	vertical-align: middle;
 }
 span.timesheetalreadyrecorded input {
-    /*font-size: smaller;*/
     border: none;
-    /*background:	transparent;*/
+    border-bottom: solid 1px rgba(0,0,0,0.4);
+    margin-right: 1px !important;
 }
 
 select.flat, form.flat select {
@@ -363,8 +363,10 @@ select.flat, form.flat select {
 .opacitytransp {
 	opacity: 0;
 }
-select:invalid { color: gray; }
-	input:disabled {
+select:invalid {
+	color: gray;
+}
+input:disabled {
 	background:#ddd;
 }
 
@@ -712,6 +714,7 @@ div.fiche>form>div.div-table-responsive {
     align-self: flex-start;
 }
 
+
 /* ============================================================================== */
 /* Styles to hide objects                                                         */
 /* ============================================================================== */
@@ -901,7 +904,7 @@ td.showDragHandle {
 #id-right, #id-left {
 	padding-top: 16px;
 	padding-bottom: 16px;
-	
+
 	display: table-cell;			/* DOL_XXX Empeche fonctionnement correct du scroll horizontal sur tableau, avec datatable ou CSS */
 	float: none;
 	vertical-align: top;
@@ -987,7 +990,7 @@ div.fiche {
 
 div.fiche {
 	margin-<?php print $left; ?>: <?php print (GETPOST('optioncss','aZ09') == 'print'?6:($dol_hide_leftmenu?'6':'26')); ?>px;
-	margin-<?php print $right; ?>: <?php print (GETPOST('optioncss','aZ09') == 'print'?8:(empty($conf->dol_optimize_smallscreen)?'16':'6')); ?>px;
+	margin-<?php print $right; ?>: <?php print (GETPOST('optioncss','aZ09') == 'print'?8:(empty($conf->dol_optimize_smallscreen)?'16':'12')); ?>px;
 	<?php if (! empty($conf->dol_hide_leftmenu) && ! empty($conf->dol_hide_topmenu)) print 'margin-top: 4px;'."\n"; ?>
 	<?php if (! empty($conf->dol_hide_leftmenu)) print 'margin-bottom: 12px;'."\n"; ?>
 }
@@ -1529,7 +1532,7 @@ foreach($mainmenuusedarray as $val)
 	display: table;
     position: absolute;
     height: 100%;
-    width: 100%;	
+    width: 100%;
 }
 .login_center {
 	display: table-cell;
@@ -1754,12 +1757,12 @@ div.vmenu, td.vmenu {
 	<?php } ?>
 }
 
-/* Force vmenusearchselectcombo with type=text differently than without because beautify with select2 affect vmenusearchselectcombo differently */ 
+/* Force vmenusearchselectcombo with type=text differently than without because beautify with select2 affect vmenusearchselectcombo differently */
 input.vmenusearchselectcombo[type=text] {
 	width: 180px !important;
 }
 .vmenusearchselectcombo {
-	width: 188px; 
+	width: 188px;
 }
 
 .menu_contenu {
@@ -1926,7 +1929,7 @@ td.ecmroot {
     background-image: -webkit-linear-gradient(bottom, rgba(200,200,200,0.1) 0%, rgba(255,255,255,0.3) 120%) !important;
     background-image: -ms-linear-gradient(bottom, rgba(200,200,200,0.1) 0%, rgba(255,255,255,0.3) 120%) !important;
     background-image: linear-gradient(bottom, rgba(200,200,200,0.1) 0%, rgba(255,255,255,0.3) 120%) !important;
-	
+
     background: #FFF;
     background-repeat: repeat-x !important;
     */
@@ -1939,7 +1942,7 @@ td.ecmroot {
     -webkit-box-shadow: 2px 2px 4px #DDD;
     box-shadow: 2px 2px 4px #DDD;
 	*/
-	
+
     padding: 10px 4px 14px 4px !important;
     min-height: 32px;
 }
@@ -1969,7 +1972,7 @@ div.tabs {
     padding-right: 6px !important;
 	clear:both;
 	height:100%;
-	/* background-image: linear-gradient(to top,#f6f6f6 0,#fff 8px);  */	
+	/* background-image: linear-gradient(to top,#f6f6f6 0,#fff 8px);  */
 }
 div.tabsElem {
 	margin-top: 1px;
@@ -1987,12 +1990,12 @@ div.tabBar {
 	background: rgb(<?php echo $colorbacktabcard1; ?>);
 }
 div.tabBar div.titre {
-	padding-top: 10px;    
+	padding-top: 10px;
 }
 
 div.tabBarWithBottom {
 	padding-bottom: 18px;
-	border-bottom: 1px solid #aaa; 
+	border-bottom: 1px solid #aaa;
 }
 div.tabBar table.tableforservicepart2:last-child {
     border-bottom: 1px solid #aaa;
@@ -2623,7 +2626,7 @@ div.liste_titre_bydiv, .liste_titre div.tagtr, tr.liste_titre, tr.liste_titre_se
 	background: rgb(<?php echo $colorbacktitle1; ?>);
 	font-weight: <?php echo $useboldtitle?'bold':'normal'; ?>;
     border-bottom: 1px solid #ddd;
-	
+
     color: rgb(<?php echo $colortexttitle; ?>);
     font-family: <?php print $fontlist ?>;
     text-align: <?php echo $left; ?>;
@@ -2682,7 +2685,7 @@ input.liste_titre {
 }
 
 .noborder tr.liste_total, .noborder tr.liste_total td, tr.liste_total, form.liste_total {
-	/* background: #F0F0F0; */
+	height: 32px;
 }
 .noborder tr.liste_total td, tr.liste_total td, form.liste_total div {
     color: #552266;
@@ -2734,7 +2737,7 @@ div.tabBar .noborder {
 
 /* Prepare to remove class pair - impair */
 
-.noborder > tbody > tr:nth-child(even):not(.liste_titre), .liste > tbody > tr:nth-child(even):not(.liste_titre) { 
+.noborder > tbody > tr:nth-child(even):not(.liste_titre), .liste > tbody > tr:nth-child(even):not(.liste_titre) {
 	background: linear-gradient(bottom, rgb(<?php echo $colorbacklineimpair1; ?>) 85%, rgb(<?php echo $colorbacklineimpair2; ?>) 100%);
 	background: -o-linear-gradient(bottom, rgb(<?php echo $colorbacklineimpair1; ?>) 85%, rgb(<?php echo $colorbacklineimpair2; ?>) 100%);
 	background: -moz-linear-gradient(bottom, rgb(<?php echo $colorbacklineimpair1; ?>) 85%, rgb(<?php echo $colorbacklineimpair2; ?>) 100%);
@@ -2761,7 +2764,7 @@ div.tabBar .noborder {
 /*
  *  Boxes
  */
- 
+
 .ficheaddleft div.boxstats {
     border: none;
 }
@@ -2775,19 +2778,19 @@ div.tabBar .noborder {
     text-align: center;
     border-radius: 2px;
 }
-.boxstats, .boxstats130, .boxstatscontent {    
+.boxstats, .boxstats130, .boxstatscontent {
 	white-space: nowrap;
 	overflow: hidden;
     text-overflow: ellipsis;
 }
 .boxstats {
     padding: 3px;
-    width: 105px;    
+    width: 105px;
 }
 .boxstats130 {
-    width: 160px; 
+    width: 160px;
     height: 48px;
-    padding: 3px  
+    padding: 3px
 }
 .boxstatscontent {
 	padding: 3px;
@@ -2795,13 +2798,16 @@ div.tabBar .noborder {
 
 @media only screen and (max-width: 767px)
 {
+	.thumbstat {
+		flex: 1 1 110px;
+	}
 	.thumbstat150 {
 		flex: 1 1 110px;
 	}
 	.boxstats, .boxstats130 {
-        width: 90px;    
+        width: 90px;
     }
-    .dashboardlineindicator { 
+    .dashboardlineindicator {
         float: left;
     	padding-left: 5px;
     }
@@ -2833,7 +2839,7 @@ span.dashboardlineko {
 	color: #FFF;
 	/*color: #8c4446 ! important;
 	padding-left: 1px;*/
-	
+
 	font-size: 80%;
 }
 .dashboardlinelatecoin {
@@ -2842,9 +2848,9 @@ span.dashboardlineko {
     text-align: right;
     top: -24px;
     padding: 1px 2px 1px 2px;
-    border-radius: .25em;    
+    border-radius: .25em;
 
-    background-color: #af4705;
+    background-color: #9f4705;
     padding: 0px 5px 0px 5px;
     top: -26px;
 }
@@ -2854,7 +2860,7 @@ span.dashboardlineko {
     margin-right: 2px;
     background-color: #8c4446;
     color: #FFFFFF ! important;
-    border-radius: .25em;    
+    border-radius: .25em;
 	display: inline-block;
 	vertical-align: middle;
 }
@@ -3955,7 +3961,7 @@ div.dataTables_length select {
 	border-top: 1px solid #ccc;
 	border-bottom: solid 1px rgba(0,0,0,.2);
 }
-.select2-container-active .select2-choice, .select2-container-active .select2-choices 
+.select2-container-active .select2-choice, .select2-container-active .select2-choices
 {
 	outline: none;
 	border-top: none;
@@ -4039,7 +4045,7 @@ a span.select2-chosen
 	border-right: none;
 	border-top: none;
 	border-left: none;
-	
+
 }
 
 
@@ -4593,7 +4599,12 @@ div.tabsElem a.tab {
     	z-index: 201;
         background: #FFF;
 	}
-	    
+
+    .login_vertical_align {
+    	padding-left: 20px;
+    	padding-right: 20px;
+    }
+
 	/* Reduce login top right info */
 	.help {
 	<?php if ($disableimages) {  ?>
@@ -4628,7 +4639,7 @@ div.tabsElem a.tab {
         vertical-align: middle;
         background: #FFF;
         height: 42px;
-        
+
     	z-index: 202;
     	min-width: 190px;
     	max-width: 190px;
diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php
index a1851dc4a764659eaf8e92494e47412f1cd59d74..d3f822bcca218e04ca6e6d1aa991bc3fcb6483c5 100644
--- a/htdocs/theme/md/style.css.php
+++ b/htdocs/theme/md/style.css.php
@@ -317,7 +317,7 @@ textarea {
 	border-left:solid 1px rgba(0,0,0,.1);
 	border-right:solid 1px rgba(0,0,0,.1);
 	border-bottom:solid 1px rgba(0,0,0,.2);
-		
+
 	background-color: #FFF;
 	padding:4px;
 	margin-left:1px;
@@ -337,9 +337,9 @@ input.buttongen {
 	vertical-align: middle;
 }
 span.timesheetalreadyrecorded input {
-    /*font-size: smaller;*/
     border: none;
-    /*background:	transparent;*/
+    border-bottom: solid 1px rgba(0,0,0,0.1);
+    margin-right: 1px !important;
 }
 
 select.flat, form.flat select {
@@ -867,10 +867,10 @@ div.fiche>form>div.div-table-responsive {
     	width: 20px;
         object-fit: contain;
     }
-    
+
 	div.statusref {
     	padding-right: 10px;
-   	}    
+   	}
 }
 .linkobject { cursor: pointer; }
 <?php if (GETPOST('optioncss','aZ09') == 'print') { ?>
@@ -1027,7 +1027,7 @@ div.fiche {
 
 div.fiche {
 	margin-<?php print $left; ?>: <?php print (GETPOST('optioncss','aZ09') == 'print'?6:($dol_hide_leftmenu?'4':'20')); ?>px;
-	margin-<?php print $right; ?>: <?php print (GETPOST('optioncss','aZ09') == 'print'?8:(empty($conf->dol_optimize_smallscreen)?'16':'4')); ?>px;
+	margin-<?php print $right; ?>: <?php print (GETPOST('optioncss','aZ09') == 'print'?8:(empty($conf->dol_optimize_smallscreen)?'16':'12')); ?>px;
 	<?php if (! empty($conf->dol_hide_leftmenu) && ! empty($conf->dol_hide_topmenu)) print 'margin-top: 4px;'; ?>
 	margin-bottom: 15px;
 }
@@ -1557,12 +1557,12 @@ foreach($mainmenuusedarray as $val)
 	display: table;
     position: absolute;
     height: 100%;
-    width: 100%;	
+    width: 100%;
 }
 .login_center {
 	display: table-cell;
     vertical-align: middle;
-}	
+}
 .login_vertical_align {
 	padding: 10px;
 	padding-bottom: 80px;
@@ -1992,14 +1992,14 @@ div.tabBar {
     border-top: 1px solid #CCC;
 	width: auto;
 	background: rgb(<?php echo $colorbacktabcard1; ?>);
-	border-bottom: 1px solid #aaa; 
+	border-bottom: 1px solid #aaa;
 }
 div.tabBar div.titre {
-	padding-top: 10px;    
+	padding-top: 10px;
 }
 div.tabBarWithBottom {
 	padding-bottom: 18px;
-	border-bottom: 1px solid #aaa; 
+	border-bottom: 1px solid #aaa;
 }
 div.tabBar table.tableforservicepart2:last-child {
     border-bottom: 1px solid #aaa;
@@ -2720,7 +2720,7 @@ tr.liste_titre th, tr.liste_titre td, th.liste_titre, form.liste_titre div, div.
 {
 	border-bottom: 1px solid #<?php echo ($colorbacktitle1 == '255,255,255'?'BBBBBB':'FDFFFF'); ?>;
 }
-/* TODO Once title line is moved under title search, make border bottom of all th black and force to whit when it's first tr */ 
+/* TODO Once title line is moved under title search, make border bottom of all th black and force to whit when it's first tr */
 tr:first-child th.liste_titre {
     border-bottom: 1px solid #FFF ! important;
 }
@@ -2769,7 +2769,7 @@ input.liste_titre {
 }
 
 .noborder tr.liste_total, .noborder tr.liste_total td, tr.liste_total, form.liste_total {
-	/* background: #F0F0F0; */
+	height: 32px;
 }
 .noborder tr.liste_total td, tr.liste_total td, form.liste_total div {
     /* border-top: 1px solid #f4f4f4; */
@@ -2777,7 +2777,6 @@ input.liste_titre {
     font-weight: normal;
     white-space: nowrap;
     padding: 4px;
-    height: 20px;
 }
 tr.liste_sub_total, tr.liste_sub_total td {
 	border-bottom: 2px solid #aaa;
@@ -2826,7 +2825,7 @@ div .tdtop {
 
 /* Prepare to remove class pair - impair */
 
-.noborder > tbody > tr:nth-child(even):not(.liste_titre), .liste > tbody > tr:nth-child(even):not(.liste_titre) { 
+.noborder > tbody > tr:nth-child(even):not(.liste_titre), .liste > tbody > tr:nth-child(even):not(.liste_titre) {
 	background: linear-gradient(bottom, rgb(<?php echo $colorbacklineimpair1; ?>) 85%, rgb(<?php echo $colorbacklineimpair2; ?>) 100%);
 	background: -o-linear-gradient(bottom, rgb(<?php echo $colorbacklineimpair1; ?>) 85%, rgb(<?php echo $colorbacklineimpair2; ?>) 100%);
 	background: -moz-linear-gradient(bottom, rgb(<?php echo $colorbacklineimpair1; ?>) 85%, rgb(<?php echo $colorbacklineimpair2; ?>) 100%);
@@ -2852,7 +2851,7 @@ div .tdtop {
 /*
  *  Boxes
  */
- 
+
 .ficheaddleft div.boxstats {
     border: none;
 }
@@ -2866,29 +2865,32 @@ div .tdtop {
     text-align: center;
     border-radius: 2px;
 }
-.boxstats, .boxstats130, .boxstatscontent {    
+.boxstats, .boxstats130, .boxstatscontent {
 	white-space: nowrap;
 	overflow: hidden;
     text-overflow: ellipsis;
 }
 .boxstats {
     padding: 3px;
-    width: 105px;    
+    width: 105px;
 }
 .boxstats130 {
-    width: 135px; 
+    width: 135px;
     height: 48px;
-    padding: 3px  
+    padding: 3px
 }
 @media only screen and (max-width: 767px)
 {
+	.thumbstat {
+		flex: 1 1 110px;
+	}
 	.thumbstat150 {
 		flex: 1 1 110px;
 	}
 	.boxstats, .boxstats130 {
-        width: 90px;    
+        width: 90px;
     }
-    .dashboardlineindicator { 
+    .dashboardlineindicator {
         float: left;
     	padding-left: 5px;
     }
@@ -2927,7 +2929,7 @@ span.dashboardlineko {
     padding: 1px 6px 1px 6px;
     background-color: #8c4446;
     color: #FFFFFF ! important;
-    border-radius: .25em;    
+    border-radius: .25em;
 }
 .boxtable {
     margin-bottom: 8px !important;
@@ -4047,7 +4049,7 @@ div.dataTables_length select {
 	border-top: 1px solid #ccc;
 	border-bottom: 1px solid #ccc;
 }
-.select2-container-active .select2-choice, .select2-container-active .select2-choices 
+.select2-container-active .select2-choice, .select2-container-active .select2-choices
 {
 	outline: none;
 	border-top: none;
diff --git a/test/phpunit/CodingSqlTest.php b/test/phpunit/CodingSqlTest.php
index c6123df3e778dc2c5de8a1e25b95c75d978c6f7a..c56f76af246a488a36d158d61efeff54f0070911 100644
--- a/test/phpunit/CodingSqlTest.php
+++ b/test/phpunit/CodingSqlTest.php
@@ -143,16 +143,16 @@ class CodingSqlTest extends PHPUnit_Framework_TestCase
 
         $listofsqldir = array(DOL_DOCUMENT_ROOT.'/install/mysql/tables', DOL_DOCUMENT_ROOT.'/install/mysql/migration');
 
-        foreach ($listofsqldir as $dir) 
+        foreach ($listofsqldir as $dir)
         {
             print 'Process dir '.$dir."\n";
             $filesarray = scandir($dir);
-        
-            foreach($filesarray as $key => $file) 
+
+            foreach($filesarray as $key => $file)
             {
                 if (! preg_match('/\.sql$/',$file))
                     continue;
-                    
+
                 print 'Check sql file '.$file."\n";
                 $filecontent=file_get_contents($dir.'/'.$file);
 
@@ -167,7 +167,7 @@ class CodingSqlTest extends PHPUnit_Framework_TestCase
                 $result=strpos($filecontent,'ON DELETE CASCADE');
                 print __METHOD__." Result for checking we don't have 'ON DELETE CASCADE' = ".$result."\n";
                 $this->assertTrue($result===false, 'Found ON DELETE CASCADE into '.$file.'. Bad.');
-                
+
                 if ($dir == DOL_DOCUMENT_ROOT.'/install/mysql/migration')
                 {
                     // Test for migration files only
@@ -176,16 +176,20 @@ class CodingSqlTest extends PHPUnit_Framework_TestCase
                 else
                 {
                     if (preg_match('/\.key\.sql$/',$file))
-                    {                
-                        // Test for files key files only
-                    
+                    {
+                        // Test for key files only
+
                     }
                     else
                     {
-                        // Test for files non key files only
+                        // Test for non key files only
                         $result=(strpos($filecontent,'KEY ') && strpos($filecontent,'PRIMARY KEY ') == 0);
                         print __METHOD__." Result for checking we don't have ' KEY ' instead of a sql file to create index = ".$result."\n";
                         $this->assertTrue($result===false, 'Found KEY into '.$file.'. Bad.');
+
+                        $result=stripos($filecontent,'ENGINE=innodb');
+                        print __METHOD__." Result for checking we have the ENGINE=innodb string = ".$result."\n";
+                        $this->assertGreaterThan(0, $result, 'The ENGINE=innodb was not found into '.$file.'. Add it or just fix syntax to match case.');
                     }
                 }
             }
diff --git a/test/phpunit/DateLibTest.php b/test/phpunit/DateLibTest.php
index 02d85164d79b26771ef089b7b52995c9298250d0..645993d86593bbb798fc27506819cb208335ff6d 100644
--- a/test/phpunit/DateLibTest.php
+++ b/test/phpunit/DateLibTest.php
@@ -179,32 +179,32 @@ class DateLibTest extends PHPUnit_Framework_TestCase
         $user=$this->savuser;
         $langs=$this->savlangs;
         $db=$this->savdb;
-    
+
         // With same hours - Tuesday/Wednesday jan 2013
         $date1=dol_mktime(0, 0, 0, 1, 1, 2013);
         $date2=dol_mktime(0, 0, 0, 1, 2, 2013);
-    
+
         $result=num_public_holiday($date1,$date2,'FR',1);
         print __METHOD__." result=".$result."\n";
         $this->assertEquals(1,$result,'NumPublicHoliday for Tuesday/Wednesday jan 2013 for FR');   // 1 closed days
-    
+
         $result=num_public_holiday($date1,$date2,'XX',1);
         print __METHOD__." result=".$result."\n";
         $this->assertEquals(0,$result,'NumPublicHoliday for Tuesday/Wednesday jan 2013 for XX');   // no closed days (country unknown)
-        
+
         // With same hours - Friday/Sunday jan 2013
         $date1=dol_mktime(0, 0, 0, 1, 4, 2013);
         $date2=dol_mktime(0, 0, 0, 1, 6, 2013);
-        
+
         $result=num_public_holiday($date1,$date2,'FR',1);
         print __METHOD__." result=".$result."\n";
-        $this->assertEquals(2,$result,'NumPublicHoliday for FR');   // 1 opened day, 2 closed days 
-        
+        $this->assertEquals(2,$result,'NumPublicHoliday for FR');   // 1 opened day, 2 closed days
+
         $result=num_public_holiday($date1,$date2,'XX',1);
         print __METHOD__." result=".$result."\n";
         $this->assertEquals(2,$result,'NumPublicHoliday for XX');   // 1 opened day, 2 closed days (even if country unknown)
     }
-    
+
     /**
      * testNumOpenDay
      *
@@ -217,32 +217,32 @@ class DateLibTest extends PHPUnit_Framework_TestCase
         $user=$this->savuser;
         $langs=$this->savlangs;
         $db=$this->savdb;
-        
+
         // With same hours - Tuesday/Wednesday jan 2013
         $date1=dol_mktime(0, 0, 0, 1, 1, 2013);
         $date2=dol_mktime(0, 0, 0, 1, 2, 2013);
-        
+
         $result=num_open_day($date1,$date2,0,1,0,'FR');
         print __METHOD__." result=".$result."\n";
         $this->assertEquals(1,$result,'NumOpenDay Tuesday/Wednesday jan 2013 for FR');   // 1 opened days
-        
+
         $result=num_open_day($date1,$date2,0,1,0,'XX');
         print __METHOD__." result=".$result."\n";
         $this->assertEquals(2,$result,'NumOpenDay Tuesday/Wednesday jan 2013 for XX');   // 2 opened days (country unknown)
-        
+
         // With same hours - Friday/Sunday jan 2013
         $date1=dol_mktime(0, 0, 0, 1, 4, 2013);
         $date2=dol_mktime(0, 0, 0, 1, 6, 2013);
-        
+
         $result=num_open_day($date1,$date2,0,1,0,'FR');
         print __METHOD__." result=".$result."\n";
         $this->assertEquals(1,$result,'NumOpenDay for FR');   // 1 opened day, 2 closed
-        
+
         $result=num_open_day($date1,$date2,'XX',1);
         print __METHOD__." result=".$result."\n";
         $this->assertEquals(1,$result,'NumOpenDay for XX');   // 1 opened day, 2 closes (even if country unknown)
     }
-    
+
     /**
      * testConvertTime2Seconds
      *
@@ -335,6 +335,11 @@ class DateLibTest extends PHPUnit_Framework_TestCase
     	print __METHOD__." result=".$result."\n";
     	$this->assertEquals('02/01/1970 00:00',$result);
 
+    	// Check %a and %b format for fr_FR
+    	$result=dol_print_date(0,'%a %b %B',true,$outputlangs);
+    	print __METHOD__." result=".$result."\n";
+    	$this->assertEquals('Jeu Jan. Janvier',$result);
+
     	// Check day format for en_US
     	$outputlangs=new Translate('',$conf);
     	$outputlangs->setDefaultLang('en_US');
@@ -345,9 +350,9 @@ class DateLibTest extends PHPUnit_Framework_TestCase
     	$this->assertEquals('01/02/1970',$result);
 
     	// Check %a and %b format for en_US
-    	$result=dol_print_date(0,'%a %b',true,$outputlangs);
+    	$result=dol_print_date(0,'%a %b %B',true,$outputlangs);
     	print __METHOD__." result=".$result."\n";
-    	$this->assertEquals('Thu Jan',$result);
+    	$this->assertEquals('Thu Jan January',$result);
 
     	return $result;
     }