Browse Source

Merge branch '5.0' of git@github.com:Dolibarr/dolibarr.git into develop

Conflicts:
	htdocs/core/lib/files.lib.php
Laurent Destailleur 8 years ago
parent
commit
c72e7c1057

+ 3 - 2
README.md

@@ -91,14 +91,15 @@ See the [ChangeLog](https://github.com/Dolibarr/dolibarr/blob/develop/ChangeLog)
 - Standing orders management (European SEPA)
 - Bank accounts management
 - Shared calendar/agenda (with ical and vcal export for third party tools integration)
-- Opportunities and/or project management (following project benefit including invoices, expense reports, time spent, ...)
+- Opportunities and/or project management
 - Projects management
 - Contracts management
 - Stock management
 - Shipping management
 - Interventions management
 - Employee's leave requests management
-- Expense report management
+- Expense reports
+- Timesheets
 - Electronic Document Management (EDM)
 - Foundations members management
 - Mass emailing

+ 9 - 4
htdocs/accountancy/admin/index.php

@@ -1,7 +1,7 @@
 <?php
 /* Copyright (C) 2013-2014 Olivier Geffroy		<jeff@jeffinfo.com>
  * Copyright (C) 2013-2014 Florian Henry		<florian.henry@open-concept.pro>
- * Copyright (C) 2013-2016 Alexandre Spangaro	<aspangaro.dolibarr@gmail.com>
+ * Copyright (C) 2013-2017 Alexandre Spangaro	<aspangaro@zendsi.com>
  * Copyright (C) 2014-2015 Ari Elbaz (elarifr)	<github@accedinfo.com>
  * Copyright (C) 2014      Marcos García        <marcosgdf@gmail.com>
  * Copyright (C) 2014	   Juanjo Menent		<jmenent@2byte.es>
@@ -87,7 +87,8 @@ if ($action == 'update') {
 		setEventMessages($langs->trans("Error"), null, 'errors');
 	}
 
-    foreach ($list as $constname) {
+    foreach ($list as $constname) 
+    {
         $constvalue = GETPOST($constname, 'alpha');
 
         if (! dolibarr_set_const($db, $constname, $constvalue, 'chaine', 0, '', $conf->entity)) {
@@ -278,13 +279,17 @@ foreach ($list as $key)
     $var = ! $var;
 
     print '<tr ' . $bc[$var] . ' class="value">';
+    
+    if (! empty($conf->global->ACCOUNTING_MANAGE_ZERO) && ($key == 'ACCOUNTING_LENGTH_GACCOUNT' || $key == 'ACCOUNTING_LENGTH_AACCOUNT')) continue;
+
     // Param
     $label = $langs->trans($key);
     print '<td>'.$label.'</td>';
     // Value
     print '<td align="right">';
-    print '<input type="text" size="20" id="' . $key . '" name="' . $key . '" value="' . $conf->global->$key . '">';
+    print '<input type="text" class="maxwidth100" id="' . $key . '" name="' . $key . '" value="' . $conf->global->$key . '">';
     print '</td>';
+    
     print '</tr>';
 }
 
@@ -301,7 +306,7 @@ print '<div class="center"><input type="submit" class="button" value="' . $langs
 print '<br>';
 print '<br>';
 
-print $langs->trans("AccountancySetupDoneFromAccountancyMenu", $langs->transnoentitiesnoconv("Home").'-'.$langs->transnoentitiesnoconv("Financial").'-'.$langs->transnoentitiesnoconv("Accountancy"));
+print $langs->trans("AccountancySetupDoneFromAccountancyMenu", $langs->transnoentitiesnoconv("Home").'-'.$langs->transnoentitiesnoconv("MenuFinancial").'-'.$langs->transnoentitiesnoconv("MenuAccountancy"));
 
 print '<br>';
 print '</form>';

+ 1 - 1
htdocs/admin/index.php

@@ -1,7 +1,7 @@
 <?php
 /* Copyright (C) 2001-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  * Copyright (C) 2004-2012 Laurent Destailleur  <eldy@users.sourceforge.net>
- * Copyright (C) 2015       Jean-François Ferry		<jfefe@aternatik.fr>
+ * Copyright (C) 2015      Jean-François Ferry	<jfefe@aternatik.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

+ 14 - 7
htdocs/core/class/commondocgenerator.class.php

@@ -304,11 +304,13 @@ abstract class CommonDocGenerator
 
     	$now=dol_now('gmt');	// gmt
     	$array_other = array(
-   			'current_date'=>dol_print_date($now,'day','tzuser'),
-   			'current_datehour'=>dol_print_date($now,'dayhour','tzuser'),
+    	    // Date in default language
+    	    'current_date'=>dol_print_date($now,'day','tzuser'),
+    	    'current_datehour'=>dol_print_date($now,'dayhour','tzuser'),
    			'current_server_date'=>dol_print_date($now,'day','tzserver'),
    			'current_server_datehour'=>dol_print_date($now,'dayhour','tzserver'),
-   			'current_date_locale'=>dol_print_date($now,'day','tzuser',$outputlangs),
+    	    // Date in requested output language
+    	    'current_date_locale'=>dol_print_date($now,'day','tzuser',$outputlangs),
    			'current_datehour_locale'=>dol_print_date($now,'dayhour','tzuser',$outputlangs),
    			'current_server_date_locale'=>dol_print_date($now,'day','tzserver',$outputlangs),
    			'current_server_datehour_locale'=>dol_print_date($now,'dayhour','tzserver',$outputlangs),
@@ -350,6 +352,7 @@ abstract class CommonDocGenerator
 		$array_key.'_ref_customer'=>$object->ref_client,
 		$array_key.'_ref_supplier'=>(! empty($object->ref_fournisseur)?$object->ref_fournisseur:''),
 		$array_key.'_source_invoice_ref'=>$invoice_source->ref,
+		// Dates
         $array_key.'_hour'=>dol_print_date($object->date,'hour'),
 		$array_key.'_date'=>dol_print_date($object->date,'day'),
 		$array_key.'_date_rfc'=>dol_print_date($object->date,'dayrfc'),
@@ -360,6 +363,7 @@ abstract class CommonDocGenerator
 		$array_key.'_date_validation'=>(! empty($object->date_validation)?dol_print_date($object->date_validation,'dayhour'):''),
 		$array_key.'_date_delivery_planed'=>(! empty($object->date_livraison)?dol_print_date($object->date_livraison,'day'):''),
 		$array_key.'_date_close'=>(! empty($object->date_cloture)?dol_print_date($object->date_cloture,'dayhour'):''),
+
 		$array_key.'_payment_mode_code'=>$object->mode_reglement_code,
 		$array_key.'_payment_mode'=>($outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code)!='PaymentType'.$object->mode_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code):$object->mode_reglement),
 		$array_key.'_payment_term_code'=>$object->cond_reglement_code,
@@ -444,10 +448,13 @@ abstract class CommonDocGenerator
 			'line_price_ht_locale'=>price($line->total_ht, 0, $outputlangs),
 			'line_price_ttc_locale'=>price($line->total_ttc, 0, $outputlangs),
 			'line_price_vat_locale'=>price($line->total_tva, 0, $outputlangs),
-			'line_date_start'=>$line->date_start,
-			'line_date_start_rfc'=>dol_print_date($line->date_start,'dayrfc'),
-			'line_date_end'=>$line->date_end,
-			'line_date_end_rfc'=>dol_print_date($line->date_end,'dayrfc')
+		    // Dates
+			'line_date_start'=>dol_print_date($line->date_start, 'day', 'tzuser'),
+			'line_date_start_locale'=>dol_print_date($line->date_start, 'day', 'tzuser', $outputlangs),
+		    'line_date_start_rfc'=>dol_print_date($line->date_start, 'dayrfc', 'tzuser'),
+		    'line_date_end'=>dol_print_date($line->date_end, 'day', 'tzuser'),
+		    'line_date_end_locale'=>dol_print_date($line->date_end, 'day', 'tzuser', $outputlangs),
+		    'line_date_end_rfc'=>dol_print_date($line->date_end, 'dayrfc', 'tzuser'),
 		);
 
 		// Retrieve extrafields

+ 2 - 2
htdocs/core/class/commonobject.class.php

@@ -1231,7 +1231,7 @@ abstract class CommonObject
      *	@param	int			$id			To force other object id (should not be used)
      *	@param	string		$format		Data format ('text', 'date'). 'text' is used if not defined
      *	@param	string		$id_field	To force rowid field name. 'rowid' is used if not defined
-     *	@param	User|string	$user		Update last update fields also if user object provided
+     *	@param	User|string	$user		Update last update fields also if user object provided. If not provided, current user is used.
      *  @param  string      $trigkey    Trigger key to run (in most cases something like 'XXX_MODIFY')
      *	@return	int						<0 if KO, >0 if OK
      */
@@ -1255,7 +1255,7 @@ abstract class CommonObject
         if ($format == 'text') $sql.= $field." = '".$this->db->escape($value)."'";
         else if ($format == 'int') $sql.= $field." = ".$this->db->escape($value);
         else if ($format == 'date') $sql.= $field." = ".($value ? "'".$this->db->idate($value)."'" : "null");
-        if (is_object($user)) $sql.=", fk_user_modif = ".$user->id;
+        if (empty($user) && is_object($user)) $sql.=", fk_user_modif = ".$user->id;
         $sql.= " WHERE ".$id_field." = ".$id;
 
         dol_syslog(get_class($this)."::".__FUNCTION__."", LOG_DEBUG);

+ 4 - 2
htdocs/core/lib/accounting.lib.php

@@ -116,8 +116,9 @@ function length_accountg($account)
 
 	if ($account < 0 || empty($account)) return '';
 	
+	if (! empty($conf->global->ACCOUNTING_MANAGE_ZERO)) return $account;
+	
 	$g = $conf->global->ACCOUNTING_LENGTH_GACCOUNT;
-
 	if (! empty($g)) {
 		// Clean parameters
 		$i = strlen($account);
@@ -150,8 +151,9 @@ function length_accounta($accounta)
 
 	if ($accounta < 0 || empty($accounta)) return '';
 	
+	if (! empty($conf->global->ACCOUNTING_MANAGE_ZERO)) return $account;
+	
 	$a = $conf->global->ACCOUNTING_LENGTH_AACCOUNT;
-
 	if (! empty($a)) {
 		// Clean parameters
 		$i = strlen($accounta);

+ 108 - 90
htdocs/core/lib/files.lib.php

@@ -772,7 +772,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable
 		}
 
 		// Security:
-		// On interdit fichiers caches, remontees de repertoire ainsi que les pipes dans les noms de fichiers.
+		// We refuse cache files/dirs, upload using .. and pipes into filenames.
 		if (preg_match('/^\./',$src_file) || preg_match('/\.\./',$src_file) || preg_match('/[<>|]/',$src_file))
 		{
 			dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
@@ -845,6 +845,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable
  *  @param	int		$nohook			Disable all hooks
  *  @param	object	$object			Current object in use
  *  @return boolean         		True if no error (file is deleted or if glob is used and there's nothing to delete), False if error
+ *  @see dol_delete_dir
  */
 function dol_delete_file($file,$disableglob=0,$nophperrors=0,$nohook=0,$object=null)
 {
@@ -856,6 +857,14 @@ function dol_delete_file($file,$disableglob=0,$nophperrors=0,$nohook=0,$object=n
 
 	dol_syslog("dol_delete_file file=".$file." disableglob=".$disableglob." nophperrors=".$nophperrors." nohook=".$nohook);
 
+	// Security:
+	// We refuse transversal using .. and pipes into filenames.
+	if (preg_match('/\.\./',$file) || preg_match('/[<>|]/',$file))
+	{
+        dol_syslog("Refused to delete file ".$file, LOG_WARNING);
+	    return False;
+	}
+	
 	if (empty($nohook))
 	{
 		$hookmanager->initHooks(array('fileslib'));
@@ -943,9 +952,18 @@ function dol_delete_file($file,$disableglob=0,$nophperrors=0,$nohook=0,$object=n
  *  @param	string	$dir            Directory to delete
  *  @param  int		$nophperrors    Disable all PHP output errors
  *  @return boolean         		True if success, false if error
+ *  @see dol_delete_file
  */
 function dol_delete_dir($dir,$nophperrors=0)
 {
+	// Security:
+	// We refuse transversal using .. and pipes into filenames.
+	if (preg_match('/\.\./',$dir) || preg_match('/[<>|]/',$dir))
+	{
+        dol_syslog("Refused to delete dir ".$dir, LOG_WARNING);
+	    return False;
+	}
+	
     $dir_osencoded=dol_osencode($dir);
     return ($nophperrors?@rmdir($dir_osencoded):rmdir($dir_osencoded));
 }
@@ -1568,141 +1586,140 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	// find the subdirectory name as the reference
 	if (empty($refname)) $refname=basename(dirname($original_file)."/");
 
+	$relative_original_file = $original_file;
+	
 	// Wrapping for some images
-	if ($modulepart == 'companylogo')
+	if ($modulepart == 'companylogo' && !empty($conf->mycompany->dir_output))
 	{
 		$accessallowed=1;
 		$original_file=$conf->mycompany->dir_output.'/logos/'.$original_file;
 	}
 	// Wrapping for users photos
-	elseif ($modulepart == 'userphoto')
+	elseif ($modulepart == 'userphoto' && !empty($conf->user->dir_output))
 	{
 		$accessallowed=1;
 		$original_file=$conf->user->dir_output.'/'.$original_file;
 	}
 	// Wrapping for members photos
-	elseif ($modulepart == 'memberphoto')
+	elseif ($modulepart == 'memberphoto' && !empty($conf->adherent->dir_output))
 	{
 		$accessallowed=1;
 		$original_file=$conf->adherent->dir_output.'/'.$original_file;
 	}
 	// Wrapping pour les apercu factures
-	elseif ($modulepart == 'apercufacture')
+	elseif ($modulepart == 'apercufacture' && !empty($conf->facture->dir_output))
 	{
 		if ($fuser->rights->facture->lire) $accessallowed=1;
 		$original_file=$conf->facture->dir_output.'/'.$original_file;
 	}
 	// Wrapping pour les apercu propal
-	elseif ($modulepart == 'apercupropal')
+	elseif ($modulepart == 'apercupropal' && !empty($conf->propal->dir_output))
 	{
 		if ($fuser->rights->propale->lire) $accessallowed=1;
 		$original_file=$conf->propal->dir_output.'/'.$original_file;
 	}
 	// Wrapping pour les apercu commande
-	elseif ($modulepart == 'apercucommande')
+	elseif ($modulepart == 'apercucommande' && !empty($conf->commande->dir_output))
 	{
 		if ($fuser->rights->commande->lire) $accessallowed=1;
 		$original_file=$conf->commande->dir_output.'/'.$original_file;
 	}
 	// Wrapping pour les apercu intervention
-	elseif ($modulepart == 'apercufichinter')
+	elseif ($modulepart == 'apercufichinter' && !empty($conf->ficheinter->dir_output))
 	{
 		if ($fuser->rights->ficheinter->lire) $accessallowed=1;
 		$original_file=$conf->ficheinter->dir_output.'/'.$original_file;
 	}
 	// Wrapping pour les images des stats propales
-	elseif ($modulepart == 'propalstats')
+	elseif ($modulepart == 'propalstats' && !empty($conf->propal->dir_temp))
 	{
 		if ($fuser->rights->propale->lire) $accessallowed=1;
 		$original_file=$conf->propal->dir_temp.'/'.$original_file;
 	}
 	// Wrapping pour les images des stats commandes
-	elseif ($modulepart == 'orderstats')
+	elseif ($modulepart == 'orderstats' && !empty($conf->commande->dir_temp))
 	{
 		if ($fuser->rights->commande->lire) $accessallowed=1;
 		$original_file=$conf->commande->dir_temp.'/'.$original_file;
 	}
-	elseif ($modulepart == 'orderstatssupplier')
+	elseif ($modulepart == 'orderstatssupplier' && !empty($conf->fournisseur->dir_output))
 	{
 		if ($fuser->rights->fournisseur->commande->lire) $accessallowed=1;
 		$original_file=$conf->fournisseur->dir_output.'/commande/temp/'.$original_file;
 	}
 	// Wrapping pour les images des stats factures
-	elseif ($modulepart == 'billstats')
+	elseif ($modulepart == 'billstats' && !empty($conf->facture->dir_temp))
 	{
 		if ($fuser->rights->facture->lire) $accessallowed=1;
 		$original_file=$conf->facture->dir_temp.'/'.$original_file;
 	}
-	elseif ($modulepart == 'billstatssupplier')
+	elseif ($modulepart == 'billstatssupplier' && !empty($conf->fournisseur->dir_output))
 	{
 		if ($fuser->rights->fournisseur->facture->lire) $accessallowed=1;
 		$original_file=$conf->fournisseur->dir_output.'/facture/temp/'.$original_file;
 	}
 	// Wrapping pour les images des stats expeditions
-	elseif ($modulepart == 'expeditionstats')
+	elseif ($modulepart == 'expeditionstats' && !empty($conf->expedition->dir_temp))
 	{
 		if ($fuser->rights->expedition->lire) $accessallowed=1;
 		$original_file=$conf->expedition->dir_temp.'/'.$original_file;
 	}
 	// Wrapping pour les images des stats expeditions
-	elseif ($modulepart == 'tripsexpensesstats')
+	elseif ($modulepart == 'tripsexpensesstats' && !empty($conf->deplacement->dir_temp))
 	{
 		if ($fuser->rights->deplacement->lire) $accessallowed=1;
 		$original_file=$conf->deplacement->dir_temp.'/'.$original_file;
 	}
 	// Wrapping pour les images des stats expeditions
-	elseif ($modulepart == 'memberstats')
+	elseif ($modulepart == 'memberstats' && !empty($conf->adherent->dir_temp))
 	{
 		if ($fuser->rights->adherent->lire) $accessallowed=1;
 		$original_file=$conf->adherent->dir_temp.'/'.$original_file;
 	}
 	// Wrapping pour les images des stats produits
-	elseif (preg_match('/^productstats_/i',$modulepart))
+	elseif (preg_match('/^productstats_/i',$modulepart) && !empty($conf->product->dir_temp))
 	{
 		if ($fuser->rights->produit->lire || $fuser->rights->service->lire) $accessallowed=1;
 		$original_file=(!empty($conf->product->multidir_temp[$entity])?$conf->product->multidir_temp[$entity]:$conf->service->multidir_temp[$entity]).'/'.$original_file;
 	}
 	// Wrapping for products or services
-	elseif ($modulepart == 'tax')
+	elseif ($modulepart == 'tax' && !empty($conf->tax->dir_output))
 	{
 		if ($fuser->rights->tax->charges->lire) $accessallowed=1;
 		$original_file=$conf->tax->dir_output.'/'.$original_file;
 	}
 	// Wrapping for products or services
-	elseif ($modulepart == 'actions')
+	elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output))
 	{
 		if ($fuser->rights->agenda->myactions->read) $accessallowed=1;
 		$original_file=$conf->agenda->dir_output.'/'.$original_file;
 	}
 	// Wrapping for categories
-	elseif ($modulepart == 'category')
+	elseif ($modulepart == 'category' && !empty($conf->categorie->dir_output))
 	{
 		if ($fuser->rights->categorie->lire) $accessallowed=1;
 		$original_file=$conf->categorie->multidir_output[$entity].'/'.$original_file;
 	}
 	// Wrapping pour les prelevements
-	elseif ($modulepart == 'prelevement')
+	elseif ($modulepart == 'prelevement' && !empty($conf->prelevement->dir_output))
 	{
-		if ($fuser->rights->prelevement->bons->lire || preg_match('/^specimen/i',$original_file))
-		{
-			$accessallowed=1;
-		}
+		if ($fuser->rights->prelevement->bons->lire || preg_match('/^specimen/i',$original_file)) $accessallowed=1;
 		$original_file=$conf->prelevement->dir_output.'/'.$original_file;
 	}
 	// Wrapping pour les graph energie
-	elseif ($modulepart == 'graph_stock')
+	elseif ($modulepart == 'graph_stock' && !empty($conf->stock->dir_temp))
 	{
 		$accessallowed=1;
 		$original_file=$conf->stock->dir_temp.'/'.$original_file;
 	}
 	// Wrapping pour les graph fournisseurs
-	elseif ($modulepart == 'graph_fourn')
+	elseif ($modulepart == 'graph_fourn' && !empty($conf->fournisseur->dir_temp))
 	{
 		$accessallowed=1;
 		$original_file=$conf->fournisseur->dir_temp.'/'.$original_file;
 	}
 	// Wrapping pour les graph des produits
-	elseif ($modulepart == 'graph_product')
+	elseif ($modulepart == 'graph_product' && !empty($conf->product->dir_temp))
 	{
 		$accessallowed=1;
 		$original_file=$conf->product->multidir_temp[$entity].'/'.$original_file;
@@ -1711,32 +1728,31 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	elseif ($modulepart == 'barcode')
 	{
 		$accessallowed=1;
-		// If viewimage is called for barcode, we try to output an image on the fly,
-		// with not build of file on disk.
+		// If viewimage is called for barcode, we try to output an image on the fly, with no build of file on disk.
 		//$original_file=$conf->barcode->dir_temp.'/'.$original_file;
 		$original_file='';
 	}
 	// Wrapping pour les icones de background des mailings
-	elseif ($modulepart == 'iconmailing')
+	elseif ($modulepart == 'iconmailing' && !empty($conf->mailing->dir_temp))
 	{
 		$accessallowed=1;
 		$original_file=$conf->mailing->dir_temp.'/'.$original_file;
 	}
-	// Wrapping pour les icones de background des mailings
-	elseif ($modulepart == 'scanner_user_temp')
+	// Wrapping pour le scanner
+	elseif ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp))
 	{
 		$accessallowed=1;
 		$original_file=$conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file;
 	}
 	// Wrapping pour les images fckeditor
-	elseif ($modulepart == 'fckeditor')
+	elseif ($modulepart == 'fckeditor' && !empty($conf->fckeditor->dir_output))
 	{
 		$accessallowed=1;
 		$original_file=$conf->fckeditor->dir_output.'/'.$original_file;
 	}
 
 	// Wrapping for third parties
-	else if ($modulepart == 'company' || $modulepart == 'societe')
+	else if (($modulepart == 'company' || $modulepart == 'societe') && !empty($conf->societe->dir_output))
 	{
 		if ($fuser->rights->societe->lire || preg_match('/^specimen/i',$original_file))
 		{
@@ -1747,7 +1763,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping for contact
-	else if ($modulepart == 'contact')
+	else if ($modulepart == 'contact' && !empty($conf->societe->dir_output))
 	{
 		if ($fuser->rights->societe->lire)
 		{
@@ -1757,7 +1773,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping for invoices
-	else if ($modulepart == 'facture' || $modulepart == 'invoice')
+	else if (($modulepart == 'facture' || $modulepart == 'invoice') && !empty($conf->facture->dir_output))
 	{
 		if ($fuser->rights->facture->lire || preg_match('/^specimen/i',$original_file))
 		{
@@ -1766,7 +1782,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 		$original_file=$conf->facture->dir_output.'/'.$original_file;
 		$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
 	}
-	else if ($modulepart == 'massfilesarea_proposals')
+	else if ($modulepart == 'massfilesarea_proposals' && !empty($conf->propal->dir_output))
 	{
 	    if ($fuser->rights->propal->lire || preg_match('/^specimen/i',$original_file))
 	    {
@@ -1791,8 +1807,8 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	    $original_file=$conf->facture->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
 	}
 	
-	// Wrapping pour les fiches intervention
-	else if ($modulepart == 'ficheinter')
+	// Wrapping for interventions
+	else if (($modulepart == 'fichinter' || $modulepart == 'ficheinter') && !empty($conf->ficheinter->dir_output))
 	{
 		if ($fuser->rights->ficheinter->lire || preg_match('/^specimen/i',$original_file))
 		{
@@ -1803,7 +1819,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping pour les deplacements et notes de frais
-	else if ($modulepart == 'deplacement')
+	else if ($modulepart == 'deplacement' && !empty($conf->deplacement->dir_output))
 	{
 		if ($fuser->rights->deplacement->lire || preg_match('/^specimen/i',$original_file))
 		{
@@ -1813,7 +1829,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 		//$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
 	}
 	// Wrapping pour les propales
-	else if ($modulepart == 'propal')
+	else if ($modulepart == 'propal' && !empty($conf->propal->dir_output))
 	{
 		if ($fuser->rights->propale->lire || preg_match('/^specimen/i',$original_file))
 		{
@@ -1825,7 +1841,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping pour les commandes
-	else if ($modulepart == 'commande' || $modulepart == 'order')
+	else if (($modulepart == 'commande' || $modulepart == 'order') && !empty($conf->commande->dir_output))
 	{
 		if ($fuser->rights->commande->lire || preg_match('/^specimen/i',$original_file))
 		{
@@ -1836,7 +1852,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping pour les projets
-	else if ($modulepart == 'project')
+	else if ($modulepart == 'project' && !empty($conf->projet->dir_output))
 	{
 		if ($fuser->rights->projet->lire || preg_match('/^specimen/i',$original_file))
 		{
@@ -1845,7 +1861,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 		$original_file=$conf->projet->dir_output.'/'.$original_file;
 		$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project', 1).")";
 	}
-	else if ($modulepart == 'project_task')
+	else if ($modulepart == 'project_task' && !empty($conf->projet->dir_output))
 	{
 		if ($fuser->rights->projet->lire || preg_match('/^specimen/i',$original_file))
 		{
@@ -1854,19 +1870,9 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 		$original_file=$conf->projet->dir_output.'/'.$original_file;
 		$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project', 1).")";
 	}
-	// Wrapping for interventions
-	else if ($modulepart == 'fichinter')
-	{
-		if ($fuser->rights->ficheinter->lire || preg_match('/^specimen/i',$original_file))
-		{
-			$accessallowed=1;
-		}
-		$original_file=$conf->ficheinter->dir_output.'/'.$original_file;
-		$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
-	}
 
 	// Wrapping pour les commandes fournisseurs
-	else if ($modulepart == 'commande_fournisseur' || $modulepart == 'order_supplier')
+	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))
 		{
@@ -1877,7 +1883,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping pour les factures fournisseurs
-	else if ($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier')
+	else if (($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') && !empty($conf->fournisseur->facture->dir_output))
 	{
 		if ($fuser->rights->fournisseur->facture->lire || preg_match('/^specimen/i',$original_file))
 		{
@@ -1898,7 +1904,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping pour les rapport de paiements
-	else if ($modulepart == 'facture_paiement')
+	else if ($modulepart == 'facture_paiement' && !empty($conf->facture->dir_output))
 	{
 		if ($fuser->rights->facture->lire || preg_match('/^specimen/i',$original_file))
 		{
@@ -1909,7 +1915,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping for accounting exports
-	else if ($modulepart == 'export_compta')
+	else if ($modulepart == 'export_compta' && !empty($conf->accounting->dir_output))
 	{
 		if ($fuser->rights->accounting->bind->write || preg_match('/^specimen/i',$original_file))
 		{
@@ -1919,7 +1925,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping pour les expedition
-	else if ($modulepart == 'expedition')
+	else if ($modulepart == 'expedition' && !empty($conf->expedition->dir_output))
 	{
 		if ($fuser->rights->expedition->lire || preg_match('/^specimen/i',$original_file))
 		{
@@ -1929,7 +1935,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping pour les bons de livraison
-	else if ($modulepart == 'livraison')
+	else if ($modulepart == 'livraison' && !empty($conf->livraison->dir_output))
 	{
 		if ($fuser->rights->expedition->livraison->lire || preg_match('/^specimen/i',$original_file))
 		{
@@ -1939,7 +1945,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping pour les actions
-	else if ($modulepart == 'actions')
+	else if ($modulepart == 'actions' && !empty($conf->agenda->dir_output))
 	{
 		if ($fuser->rights->agenda->myactions->read || preg_match('/^specimen/i',$original_file))
 		{
@@ -1949,7 +1955,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping pour les actions
-	else if ($modulepart == 'actionsreport')
+	else if ($modulepart == 'actionsreport' && !empty($conf->agenda->dir_temp))
 	{
 		if ($fuser->rights->agenda->allactions->read || preg_match('/^specimen/i',$original_file))
 		{
@@ -1970,7 +1976,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping pour les contrats
-	else if ($modulepart == 'contract')
+	else if ($modulepart == 'contract' && !empty($conf->contrat->dir_output))
 	{
 		if ($fuser->rights->contrat->lire || preg_match('/^specimen/i',$original_file))
 		{
@@ -1981,7 +1987,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping pour les dons
-	else if ($modulepart == 'donation')
+	else if ($modulepart == 'donation' && !empty($conf->donation->dir_output))
 	{
 		if ($fuser->rights->don->lire || preg_match('/^specimen/i',$original_file))
 		{
@@ -1991,7 +1997,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping pour les remises de cheques
-	else if ($modulepart == 'remisecheque')
+	else if ($modulepart == 'remisecheque' && !empty($conf->banque->dir_output))
 	{
 		if ($fuser->rights->banque->lire || preg_match('/^specimen/i',$original_file))
 		{
@@ -2002,7 +2008,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping for bank
-	else if ($modulepart == 'bank')
+	else if ($modulepart == 'bank' && !empty($conf->bank->dir_output))
 	{
 		if ($fuser->rights->banque->lire)
 		{
@@ -2012,7 +2018,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping for export module
-	else if ($modulepart == 'export')
+	else if ($modulepart == 'export' && !empty($conf->export->dir_temp))
 	{
 		// Aucun test necessaire car on force le rep de download sur
 		// le rep export qui est propre a l'utilisateur
@@ -2021,21 +2027,21 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping for import module
-	else if ($modulepart == 'import')
+	else if ($modulepart == 'import' && !empty($conf->import->dir_temp))
 	{
 		$accessallowed=1;
 		$original_file=$conf->import->dir_temp.'/'.$original_file;
 	}
 
 	// Wrapping pour l'editeur wysiwyg
-	else if ($modulepart == 'editor')
+	else if ($modulepart == 'editor' && !empty($conf->fckeditor->dir_output))
 	{
 		$accessallowed=1;
 		$original_file=$conf->fckeditor->dir_output.'/'.$original_file;
 	}
 	
 	// Wrapping for miscellaneous medias files
-	elseif ($modulepart == 'medias')
+	elseif ($modulepart == 'medias' && !empty($dolibarr_main_data_root))
 	{
 	    $accessallowed=1;
 	    global $dolibarr_main_data_root;
@@ -2043,25 +2049,21 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 	
 	// Wrapping for backups
-	else if ($modulepart == 'systemtools')
+	else if ($modulepart == 'systemtools' && !empty($conf->admin->dir_output))
 	{
-		if ($fuser->admin)
-		{
-			$accessallowed=1;
-		}
+		if ($fuser->admin) $accessallowed=1;
 		$original_file=$conf->admin->dir_output.'/'.$original_file;
 	}
 
 	// Wrapping for upload file test
-	else if ($modulepart == 'admin_temp')
+	else if ($modulepart == 'admin_temp' && !empty($conf->admin->dir_temp))
 	{
-		if ($fuser->admin)
-			$accessallowed=1;
+		if ($fuser->admin) $accessallowed=1;
 		$original_file=$conf->admin->dir_temp.'/'.$original_file;
 	}
 
 	// Wrapping pour BitTorrent
-	else if ($modulepart == 'bittorrent')
+	else if ($modulepart == 'bittorrent' && !empty($conf->bittorrent->dir_output))
 	{
 		$accessallowed=1;
 		$dir='files';
@@ -2070,7 +2072,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping pour Foundation module
-	else if ($modulepart == 'member')
+	else if ($modulepart == 'member' && !empty($conf->adherent->dir_output))
 	{
 		if ($fuser->rights->adherent->lire || preg_match('/^specimen/i',$original_file))
 		{
@@ -2080,7 +2082,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 	}
 
 	// Wrapping for Scanner
-	else if ($modulepart == 'scanner_user_temp')
+	else if ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp))
 	{
 		$accessallowed=1;
 		$original_file=$conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file;
@@ -2093,20 +2095,38 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
     // 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 ($fuser->admin) $accessallowed=1;    // If user is admin
+
 		// Define $accessallowed
 		if (preg_match('/^([a-z]+)_user_temp$/i',$modulepart,$reg))
 		{
-			if ($fuser->rights->{$reg[1]}->lire || $fuser->rights->{$reg[1]}->read || ($fuser->rights->{$reg[1]}->download)) $accessallowed=1;
+			if (empty($conf->{$reg[1]}->dir_temp))	// modulepart not supported
+			{
+				dol_print_error('','Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
+				exit;
+			}
+		    if ($fuser->rights->{$reg[1]}->lire || $fuser->rights->{$reg[1]}->read || ($fuser->rights->{$reg[1]}->download)) $accessallowed=1;
 			$original_file=$conf->{$reg[1]}->dir_temp.'/'.$fuser->id.'/'.$original_file;
 		}
 		else if (preg_match('/^([a-z]+)_temp$/i',$modulepart,$reg))
 		{
-			if ($fuser->rights->{$reg[1]}->lire || $fuser->rights->{$reg[1]}->read || ($fuser->rights->{$reg[1]}->download)) $accessallowed=1;
+			if (empty($conf->{$reg[1]}->dir_temp))	// modulepart not supported
+			{
+				dol_print_error('','Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
+				exit;
+			}
+		    if ($fuser->rights->{$reg[1]}->lire || $fuser->rights->{$reg[1]}->read || ($fuser->rights->{$reg[1]}->download)) $accessallowed=1;
 			$original_file=$conf->{$reg[1]}->dir_temp.'/'.$original_file;
 		}
 		else if (preg_match('/^([a-z]+)_user$/i',$modulepart,$reg))
 		{
-			if ($fuser->rights->{$reg[1]}->lire || $fuser->rights->{$reg[1]}->read || ($fuser->rights->{$reg[1]}->download)) $accessallowed=1;
+			if (empty($conf->{$reg[1]}->dir_output))	// modulepart not supported
+			{
+				dol_print_error('','Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
+				exit;
+			}
+		    if ($fuser->rights->{$reg[1]}->lire || $fuser->rights->{$reg[1]}->read || ($fuser->rights->{$reg[1]}->download)) $accessallowed=1;
 			$original_file=$conf->{$reg[1]}->dir_output.'/'.$fuser->id.'/'.$original_file;
 		}
 		else
@@ -2130,8 +2150,6 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 				$original_file=$conf->$modulepart->dir_output.'/'.$original_file;
 			}
 		}
-		if (preg_match('/^specimen/i',$original_file))	$accessallowed=1;    // If link to a specimen
-		if ($fuser->admin) $accessallowed=1;    // If user is admin
 
 		// For modules who wants to manage different levels of permissions for documents
 		$subPermCategoryConstName = strtoupper($modulepart).'_SUBPERMCATEGORY_FOR_DOCUMENTS';
@@ -2163,7 +2181,7 @@ function dol_check_secure_access_document($modulepart,$original_file,$entity,$fu
 }
 
 /**
- * Store object in file
+ * Store object in file.
  *
  * @param string $directory Directory of cache
  * @param string $filename Name of filecache
@@ -2179,7 +2197,7 @@ function dol_filecache($directory, $filename, $object)
 }
 
 /**
- * Test if Refresh needed
+ * Test if Refresh needed.
  *
  * @param string $directory Directory of cache
  * @param string $filename Name of filecache
@@ -2195,7 +2213,7 @@ function dol_cache_refresh($directory, $filename, $cachetime)
 }
 
 /**
- * Read object from cachefile
+ * Read object from cachefile.
  *
  * @param string $directory Directory of cache
  * @param string $filename Name of filecache

+ 4 - 1
htdocs/core/login/functions_dolibarr.php

@@ -47,7 +47,7 @@ function check_user_password_dolibarr($usertotest,$passwordtotest,$entitytotest=
 	{
 		dol_syslog("functions_dolibarr::check_user_password_dolibarr usertotest=".$usertotest." passwordtotest=".preg_replace('/./','*',$passwordtotest)." entitytotest=".$entitytotest);
 
-		// If test username/password asked, we define $test=false and $login var if ok, set $_SESSION["dol_loginmesg"] if ko
+		// If test username/password asked, we define $test=false if ko and $login var to login if ok, set also $_SESSION["dol_loginmesg"] if ko
 		$table = MAIN_DB_PREFIX."user";
 		$usernamecol1 = 'login';
 		$usernamecol2 = 'email';
@@ -59,6 +59,9 @@ function check_user_password_dolibarr($usertotest,$passwordtotest,$entitytotest=
 		if (preg_match('/@/',$usertotest)) $sql.=' OR '.$usernamecol2." = '".$db->escape($usertotest)."'";
 		$sql.=') AND '.$entitycol." IN (0," . ($entity ? $entity : 1) . ")";
 		$sql.=' AND statut = 1';
+		// Required to first found the user into entity, then the superadmin.
+		// For the case (TODO and that we must avoid) a user has renamed its login with same value than a user in entity 0. 
+		$sql.=' ORDER BY entity DESC';
 
 		$resql=$db->query($sql);
 		if ($resql)

+ 12 - 5
htdocs/fourn/class/fournisseur.commande.class.php

@@ -2957,7 +2957,8 @@ class CommandeFournisseurLigne extends CommonOrderLine
         $sql.= ' cd.info_bits, cd.total_ht, cd.total_tva, cd.total_ttc,';
         $sql.= ' cd.total_localtax1, cd.total_localtax2,';
         $sql.= ' p.ref as product_ref, p.label as product_libelle, p.description as product_desc,';
-        $sql.= ' cd.date_start, cd.date_end, cd.fk_unit';
+        $sql.= ' cd.date_start, cd.date_end, cd.fk_unit,';
+		$sql.= ' cd.multicurrency_subprice, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc';
         $sql.= ' FROM '.MAIN_DB_PREFIX.'commande_fournisseurdet as cd';
         $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON cd.fk_product = p.rowid';
         $sql.= ' WHERE cd.rowid = '.$rowid;
@@ -2965,6 +2966,7 @@ class CommandeFournisseurLigne extends CommonOrderLine
         if ($result)
         {
             $objp = $this->db->fetch_object($result);
+
             $this->rowid            = $objp->rowid;
             $this->id               = $objp->rowid;
             $this->fk_commande      = $objp->fk_commande;
@@ -2992,10 +2994,15 @@ class CommandeFournisseurLigne extends CommonOrderLine
             $this->product_libelle  = $objp->product_libelle;
             $this->product_desc     = $objp->product_desc;
 
-            $this->date_start       = $this->db->jdate($objp->date_start);
-            $this->date_end         = $this->db->jdate($objp->date_end);
-	        $this->fk_unit          = $objp->fk_unit;
-
+            $this->date_start       		= $this->db->jdate($objp->date_start);
+            $this->date_end         		= $this->db->jdate($objp->date_end);
+	        $this->fk_unit          		= $objp->fk_unit;
+			
+			$this->multicurrency_subprice	= $objp->multicurrency_subprice;
+			$this->multicurrency_total_ht	= $objp->multicurrency_total_ht;
+			$this->multicurrency_total_tva	= $objp->multicurrency_total_tva;
+			$this->multicurrency_total_ttc	= $objp->multicurrency_total_ttc;
+			
             $this->db->free($result);
             return 1;
         }

+ 8 - 1
htdocs/fourn/class/fournisseur.facture.class.php

@@ -2385,8 +2385,9 @@ class SupplierInvoiceLine extends CommonObjectLine
 	{
 		$sql = 'SELECT f.rowid, f.ref as ref_supplier, f.description, f.pu_ht, f.pu_ttc, f.qty, f.remise_percent, f.tva_tx';
 		$sql.= ', f.localtax1_type, f.localtax2_type, f.localtax1_tx, f.localtax2_tx, f.total_localtax1, f.total_localtax2 ';
-		$sql.= ', f.total_ht, f.tva as total_tva, f.total_ttc, f.fk_product, f.product_type, f.info_bits, f.rang, f.special_code, f.fk_parent_line, f.fk_unit';
+		$sql.= ', f.total_ht, f.tva as total_tva, f.total_ttc, f.fk_facture_fourn, f.fk_product, f.product_type, f.info_bits, f.rang, f.special_code, f.fk_parent_line, f.fk_unit';
 		$sql.= ', p.rowid as product_id, p.ref as product_ref, p.label as label, p.description as product_desc';
+		$sql.= ', f.multicurrency_subprice, f.multicurrency_total_ht, f.multicurrency_total_tva, multicurrency_total_ttc';
 		$sql.= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_det as f';
 		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON f.fk_product = p.rowid';
 		$sql.= ' WHERE f.rowid = '.$rowid;
@@ -2407,6 +2408,7 @@ class SupplierInvoiceLine extends CommonObjectLine
 
 		$this->id				= $obj->rowid;
 		$this->rowid				= $obj->rowid;
+		$this->fk_facture_fourn			= $obj->fk_facture_fourn;
 		$this->description		= $obj->description;
 		$this->product_ref		= $obj->product_ref;
 		$this->ref				= $obj->product_ref;
@@ -2439,6 +2441,11 @@ class SupplierInvoiceLine extends CommonObjectLine
 		$this->rang       		= $obj->rang;
 		$this->fk_unit           = $obj->fk_unit;
 
+		$this->multicurrency_subprice	= $obj->multicurrency_subprice;
+		$this->multicurrency_total_ht	= $obj->multicurrency_total_ht;
+		$this->multicurrency_total_tva	= $obj->multicurrency_total_tva;
+		$this->multicurrency_total_ttc	= $obj->multicurrency_total_ttc;
+
 		return 1;
 	}
 

+ 1 - 1
htdocs/fourn/commande/card.php

@@ -1805,7 +1805,7 @@ elseif (! empty($object->id))
 	                $morehtmlref.='<form method="post" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'">';
 	                $morehtmlref.='<input type="hidden" name="action" value="classin">';
 	                $morehtmlref.='<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
-	                $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1);
+	                $morehtmlref.=$formproject->select_projects((empty($conf->global->PROJECT_CAN_ALWAYS_LINK_TO_ALL_SUPPLIERS)?$object->socid:-1), $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1);
 	                $morehtmlref.='<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
 	                $morehtmlref.='</form>';
 	            } else {

+ 2 - 1
htdocs/fourn/facture/card.php

@@ -2053,7 +2053,7 @@ else
     	                $morehtmlref.='<form method="post" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'">';
     	                $morehtmlref.='<input type="hidden" name="action" value="classin">';
     	                $morehtmlref.='<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
-    	                $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1);
+    	                $morehtmlref.=$formproject->select_projects((empty($conf->global->PROJECT_CAN_ALWAYS_LINK_TO_ALL_SUPPLIERS)?$object->socid:-1), $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1);
     	                $morehtmlref.='<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
     	                $morehtmlref.='</form>';
     	            } else {
@@ -2454,6 +2454,7 @@ else
 				print $langs->trans('AlreadyPaid');
 			print ' :</td><td align="right"'.(($totalpaye > 0)?' class="amountalreadypaid"':'').'>' . price($totalpaye) . '</td><td>&nbsp;</td></tr>';
 
+            $resteapayer = $object->total_ttc - $totalpaye;
 			$resteapayeraffiche = $resteapayer;
 			$cssforamountpaymentcomplete = 'amountpaymentcomplete';
 

+ 3 - 3
htdocs/langs/en_US/accountancy.lang

@@ -105,9 +105,9 @@ ACCOUNTING_LIST_SORT_VENTILATION_DONE=Begin the sorting of the page "Binding don
 
 ACCOUNTING_LENGTH_DESCRIPTION=Truncate product & services description in listings after x chars (Best = 50)
 ACCOUNTING_LENGTH_DESCRIPTION_ACCOUNT=Truncate product & services account description form in listings after x chars (Best = 50)
-ACCOUNTING_LENGTH_GACCOUNT=Length of the general accounting accounts
-ACCOUNTING_LENGTH_AACCOUNT=Length of the third party accounting accounts
-ACCOUNTING_MANAGE_ZERO=Manage the zero at the end of an accounting account. Needed by some countries. Disabled by default. If set to on, you must also set the 2 following parameters (or it is ignored)
+ACCOUNTING_LENGTH_GACCOUNT=Length of the general accounting accounts (If you set value to 6 here, the account '706' will appear like '706000' on screen)
+ACCOUNTING_LENGTH_AACCOUNT=Length of the third party accounting accounts (If you set value to 6 here, the account '401' will appear like '401000' on screen)
+ACCOUNTING_MANAGE_ZERO=Allow to manage different number of zero at the end of an accounting account. Needed by some countries (like switzerland). If keep to off (default), you can set the 2 following parameters to ask application to add virtual zero.
 BANK_DISABLE_DIRECT_INPUT=Disable direct recording of transaction in bank account
 
 ACCOUNTING_SELL_JOURNAL=Sell journal

+ 3 - 1
htdocs/product/stock/class/mouvementstock.class.php

@@ -277,7 +277,7 @@ class MouvementStock extends CommonObject
 
 		// Check if stock is enough when qty is < 0
 		// Note that qty should be > 0 with type 0 or 3, < 0 with type 1 or 2.
-		if ($qty < 0 && empty($conf->global->STOCK_ALLOW_NEGATIVE_TRANSFER))
+		if ($movestock && $qty < 0 && empty($conf->global->STOCK_ALLOW_NEGATIVE_TRANSFER))
 		{
     		if (! empty($conf->productbatch->enabled) && $product->hasbatch() && ! $skip_batch)
     		{
@@ -292,6 +292,7 @@ class MouvementStock extends CommonObject
     		    }
     		    if (! $foundforbatch || $qtyisnotenough)
     		    {
+    		        $langs->load("stocks");
         		    $this->error = $langs->trans('qtyToTranferLotIsNotEnough');
         		    $this->errors[] = $langs->trans('qtyToTranferLotIsNotEnough');
         		    $this->db->rollback();
@@ -302,6 +303,7 @@ class MouvementStock extends CommonObject
     		{
     		    if (empty($product->stock_warehouse[$entrepot_id]->real) || $product->stock_warehouse[$entrepot_id]->real < abs($qty))
     		    {
+    		        $langs->load("stocks");
     		        $this->error = $langs->trans('qtyToTranferIsNotEnough');
     		        $this->errors[] = $langs->trans('qtyToTranferIsNotEnough');
     		        $this->db->rollback();