Просмотр исходного кода

Merge remote-tracking branch 'upstream/develop' into fieldlabel

Frédéric FRANCE 6 лет назад
Родитель
Сommit
da3ee9ad9a
67 измененных файлов с 1340 добавлено и 985 удалено
  1. 1 0
      build/rpm/dolibarr_fedora.spec
  2. 1 0
      build/rpm/dolibarr_generic.spec
  3. 1 0
      build/rpm/dolibarr_mandriva.spec
  4. 1 0
      build/rpm/dolibarr_opensuse.spec
  5. 35 21
      htdocs/adherents/card.php
  6. 3 2
      htdocs/adherents/subscription/list.php
  7. 1 0
      htdocs/admin/holiday.php
  8. 1 1
      htdocs/admin/modules.php
  9. 0 1
      htdocs/cache.manifest
  10. 13 9
      htdocs/commande/class/commande.class.php
  11. 20 16
      htdocs/compta/facture/card.php
  12. 3 3
      htdocs/compta/facture/class/facture.class.php
  13. 42 41
      htdocs/contrat/class/api_contracts.class.php
  14. 3 3
      htdocs/core/actions_addupdatedelete.inc.php
  15. 34 7
      htdocs/core/actions_massactions.inc.php
  16. 4 3
      htdocs/core/boxes/box_graph_product_distribution.php
  17. 9 1
      htdocs/core/class/CMailFile.class.php
  18. 3 2
      htdocs/core/class/commoninvoice.class.php
  19. 1 1
      htdocs/core/class/commonobject.class.php
  20. 28 14
      htdocs/core/class/conf.class.php
  21. 20 19
      htdocs/core/class/html.form.class.php
  22. 4 6
      htdocs/core/class/html.formfile.class.php
  23. 15 1
      htdocs/core/class/html.formmail.class.php
  24. 4 2
      htdocs/core/lib/admin.lib.php
  25. 17 14
      htdocs/core/lib/functions.lib.php
  26. 239 238
      htdocs/core/lib/security.lib.php
  27. 1 1
      htdocs/core/modules/DolibarrModules.class.php
  28. 1 1
      htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php
  29. 12 5
      htdocs/core/modules/contract/doc/doc_generic_contract_odt.modules.php
  30. 20 9
      htdocs/core/modules/expedition/doc/doc_generic_shipment_odt.modules.php
  31. 1 1
      htdocs/core/modules/expensereport/doc/pdf_standard.modules.php
  32. 18 9
      htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php
  33. 0 37
      htdocs/core/modules/livraison/doc/pdf_typhon.modules.php
  34. 2 2
      htdocs/core/modules/modDav.class.php
  35. 323 0
      htdocs/core/modules/modEmailCollector.class.php
  36. 14 14
      htdocs/core/modules/modSyslog.class.php
  37. 1 1
      htdocs/core/modules/modTakePos.class.php
  38. 23 14
      htdocs/core/modules/product/doc/doc_generic_product_odt.modules.php
  39. 140 126
      htdocs/core/modules/project/doc/doc_generic_project_odt.modules.php
  40. 25 20
      htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php
  41. 14 5
      htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php
  42. 12 3
      htdocs/core/modules/societe/doc/doc_generic_odt.modules.php
  43. 13 4
      htdocs/core/modules/stock/doc/doc_generic_stock_odt.modules.php
  44. 18 9
      htdocs/core/modules/supplier_proposal/doc/doc_generic_supplier_proposal_odt.modules.php
  45. 14 8
      htdocs/core/modules/user/doc/doc_generic_user_odt.modules.php
  46. 28 21
      htdocs/core/modules/usergroup/doc/doc_generic_usergroup_odt.modules.php
  47. 1 1
      htdocs/core/tpl/ajax/objectlinked_lineimport.tpl.php
  48. 6 5
      htdocs/core/tpl/massactions_pre.tpl.php
  49. 1 0
      htdocs/emailcollector/index.html
  50. 4 4
      htdocs/expensereport/class/expensereport.class.php
  51. 4 4
      htdocs/fichinter/class/fichinter.class.php
  52. 5 2
      htdocs/fourn/class/fournisseur.commande.class.php
  53. 15 8
      htdocs/fourn/class/fournisseur.facture.class.php
  54. 4 6
      htdocs/fourn/class/paiementfourn.class.php
  55. 27 16
      htdocs/fourn/facture/card.php
  56. 44 44
      htdocs/install/upgrade2.php
  57. 1 0
      htdocs/langs/en_US/errors.lang
  58. 1 0
      htdocs/langs/en_US/main.lang
  59. 3 3
      htdocs/loan/card.php
  60. 1 1
      htdocs/modulebuilder/template/core/modules/modMyModule.class.php
  61. 2 1
      htdocs/modulebuilder/template/myobject_card.php
  62. 25 20
      htdocs/product/stock/replenish.php
  63. 4 4
      htdocs/projet/class/project.class.php
  64. 3 3
      htdocs/projet/element.php
  65. 4 3
      htdocs/projet/tasks.php
  66. 2 2
      htdocs/resource/element_resource.php
  67. 0 163
      htdocs/support/online.php

+ 1 - 0
build/rpm/dolibarr_fedora.spec

@@ -181,6 +181,7 @@ done >>%{name}.lang
 %_datadir/dolibarr/htdocs/dav
 %_datadir/dolibarr/htdocs/don
 %_datadir/dolibarr/htdocs/ecm
+%_datadir/dolibarr/htdocs/emailcollector
 %_datadir/dolibarr/htdocs/expedition
 %_datadir/dolibarr/htdocs/expensereport
 %_datadir/dolibarr/htdocs/exports

+ 1 - 0
build/rpm/dolibarr_generic.spec

@@ -261,6 +261,7 @@ done >>%{name}.lang
 %_datadir/dolibarr/htdocs/dav
 %_datadir/dolibarr/htdocs/don
 %_datadir/dolibarr/htdocs/ecm
+%_datadir/dolibarr/htdocs/emailcollector
 %_datadir/dolibarr/htdocs/expedition
 %_datadir/dolibarr/htdocs/expensereport
 %_datadir/dolibarr/htdocs/exports

+ 1 - 0
build/rpm/dolibarr_mandriva.spec

@@ -178,6 +178,7 @@ done >>%{name}.lang
 %_datadir/dolibarr/htdocs/dav
 %_datadir/dolibarr/htdocs/don
 %_datadir/dolibarr/htdocs/ecm
+%_datadir/dolibarr/htdocs/emailcollector
 %_datadir/dolibarr/htdocs/expedition
 %_datadir/dolibarr/htdocs/expensereport
 %_datadir/dolibarr/htdocs/exports

+ 1 - 0
build/rpm/dolibarr_opensuse.spec

@@ -189,6 +189,7 @@ done >>%{name}.lang
 %_datadir/dolibarr/htdocs/dav
 %_datadir/dolibarr/htdocs/don
 %_datadir/dolibarr/htdocs/ecm
+%_datadir/dolibarr/htdocs/emailcollector
 %_datadir/dolibarr/htdocs/expedition
 %_datadir/dolibarr/htdocs/expensereport
 %_datadir/dolibarr/htdocs/exports

+ 35 - 21
htdocs/adherents/card.php

@@ -644,18 +644,25 @@ if (empty($reshook))
 					$msg     = $arraydefaultmessage->content;
 				}
 
-				$substitutionarray=getCommonSubstitutionArray($outputlangs, 0, null, $object);
-				complete_substitutions_array($substitutionarray, $outputlangs, $object);
-				$subjecttosend = make_substitutions($subject, $substitutionarray, $outputlangs);
-				$texttosend = make_substitutions(dol_concatdesc($msg, $adht->getMailOnValid()), $substitutionarray, $outputlangs);
+				if (empty($labeltouse) || (int) $labeltouse === -1) {
+					//fallback on the old configuration.
+					setEventMessages('WarningMandatorySetupNotComplete', [], 'errors');
+					$error++;
+				}
+				else {
+					$substitutionarray=getCommonSubstitutionArray($outputlangs, 0, null, $object);
+					complete_substitutions_array($substitutionarray, $outputlangs, $object);
+					$subjecttosend = make_substitutions($subject, $substitutionarray, $outputlangs);
+					$texttosend = make_substitutions(dol_concatdesc($msg, $adht->getMailOnValid()), $substitutionarray, $outputlangs);
 
-				$moreinheader='X-Dolibarr-Info: send_an_email by adherents/card.php'."\r\n";
+					$moreinheader='X-Dolibarr-Info: send_an_email by adherents/card.php'."\r\n";
 
-				$result=$object->send_an_email($texttosend, $subjecttosend, array(), array(), array(), "", "", 0, -1, '', $moreinheader);
-				if ($result < 0)
-				{
-					$error++;
-					setEventMessages($object->error, $object->errors, 'errors');
+					$result=$object->send_an_email($texttosend, $subjecttosend, array(), array(), array(), "", "", 0, -1, '', $moreinheader);
+					if ($result < 0)
+					{
+						$error++;
+						setEventMessages($object->error, $object->errors, 'errors');
+					}
 				}
 			}
 		}
@@ -718,19 +725,26 @@ if (empty($reshook))
 						$msg     = $arraydefaultmessage->content;
 					}
 
-					$substitutionarray=getCommonSubstitutionArray($outputlangs, 0, null, $object);
-					complete_substitutions_array($substitutionarray, $outputlangs, $object);
-					$subjecttosend = make_substitutions($subject, $substitutionarray, $outputlangs);
-					$texttosend = make_substitutions(dol_concatdesc($msg, $adht->getMailOnResiliate()), $substitutionarray, $outputlangs);
+					if (empty($labeltouse) || (int) $labeltouse === -1) {
+						//fallback on the old configuration.
+						setEventMessages('WarningMandatorySetupNotComplete', [], 'errors');
+						$error++;
+					}
+					else {
+						$substitutionarray=getCommonSubstitutionArray($outputlangs, 0, null, $object);
+						complete_substitutions_array($substitutionarray, $outputlangs, $object);
+						$subjecttosend = make_substitutions($subject, $substitutionarray, $outputlangs);
+						$texttosend = make_substitutions(dol_concatdesc($msg, $adht->getMailOnResiliate()), $substitutionarray, $outputlangs);
 
-					$moreinheader='X-Dolibarr-Info: send_an_email by adherents/card.php'."\r\n";
+						$moreinheader='X-Dolibarr-Info: send_an_email by adherents/card.php'."\r\n";
 
-					$result=$object->send_an_email($texttosend, $subjecttosend, array(), array(), array(), "", "", 0, -1, '', $moreinheader);
-				}
-				if ($result < 0)
-				{
-					$error++;
-					setEventMessages($object->error, $object->errors, 'errors');
+						$result=$object->send_an_email($texttosend, $subjecttosend, array(), array(), array(), "", "", 0, -1, '', $moreinheader);
+						if ($result < 0)
+						{
+							$error++;
+							setEventMessages($object->error, $object->errors, 'errors');
+						}
+					}
 				}
 			}
 			else

+ 3 - 2
htdocs/adherents/subscription/list.php

@@ -40,7 +40,7 @@ $search_account=GETPOST('search_account','int');
 $search_amount=GETPOST('search_amount','alpha');
 $optioncss = GETPOST('optioncss','alpha');
 
-$date_select=isset($_GET["date_select"])?$_GET["date_select"]:$_POST["date_select"];
+$date_select=GETPOST("date_select",'alpha');
 
 $limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit;
 $sortfield = GETPOST("sortfield",'alpha');
@@ -126,7 +126,8 @@ $sql.= " WHERE d.rowid = c.fk_adherent";
 $sql.= " AND d.entity IN (".getEntity('adherent').")";
 if (isset($date_select) && $date_select != '')
 {
-    $sql.= " AND c.dateadh LIKE '".$date_select."%'";
+    $sql.= " AND c.dateadh >= '".$date_select."-01-01 00:00:00'";
+    $sql.= " AND c.dateadh < '".($date_select+1)."-01-01 00:00:00'";
 }
 if ($search_ref)
 {

+ 1 - 0
htdocs/admin/holiday.php

@@ -2,6 +2,7 @@
 /* Copyright (C) 2011-2013      Juanjo Menent	    <jmenent@2byte.es>
  * Copyright (C) 2011-2018      Philippe Grand	    <philippe.grand@atoo-net.com>
  * Copyright (C) 2018		    Charlene Benke		<charlie@patas-monkey.com>
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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

+ 1 - 1
htdocs/admin/modules.php

@@ -805,7 +805,7 @@ if ($mode == 'common')
 	        	        {
         	        	    foreach ($arrayofwarningsextbycountry as $keycountry => $cursorwarningmessage)
         	        	    {
-        	        	        if ($keycountry == 'always' || $keycountry == $mysoc->country_code)
+        	        	    	if (preg_match('/^always/', $keycountry) || ($mysoc->country_code && preg_match('/^'.$mysoc->country_code.'/', $keycountry)))
         	        	        {
         	        	            $warningmessage .= ($warningmessage?"\n":"").$langs->trans($cursorwarningmessage, $objMod->getName(), $mysoc->country_code, $modules[$keymodule]->getName());
         	        	            $warningmessage .= ($warningmessage?"\n":"").($warningmessage?"\n":"").$langs->trans("Module").' : '.$objMod->getName();

+ 0 - 1
htdocs/cache.manifest

@@ -11,7 +11,6 @@ CACHE:
 theme/dolibarr_logo.png
 support/
 support/index.php
-support/online.php
 
 support/default.css
 support/helpcenter.png

+ 13 - 9
htdocs/commande/class/commande.class.php

@@ -108,8 +108,11 @@ class Commande extends CommonOrder
 	 */
 	public $billed;		// billed or not
 
-	public $brouillon;
-	public $cond_reglement_code;
+    /**
+     * @var int Draft Status of the order
+     */
+    public $brouillon;
+    public $cond_reglement_code;
 
 	/**
      * @var int ID
@@ -155,7 +158,7 @@ class Commande extends CommonOrder
 	public $demand_reason_id;   // Source reason. Why we receive order (after a phone campaign, ...)
 	public $demand_reason_code;
 	public $date;				// Date commande
-  
+
 	/**
 	 * @deprecated
 	 * @see date
@@ -274,11 +277,11 @@ class Commande extends CommonOrder
 				$mybool|=@include_once $dir.$file;
 			}
 
-			if (! $mybool)
-			{
-				dol_print_error('',"Failed to include file ".$file);
-				return '';
-			}
+            if ($mybool === false)
+            {
+                dol_print_error('',"Failed to include file ".$file);
+                return '';
+            }
 
 			$obj = new $classname();
 			$numref = $obj->getNextValue($soc,$this);
@@ -448,6 +451,7 @@ class Commande extends CommonOrder
 		{
 			$this->ref = $num;
 			$this->statut = self::STATUS_VALIDATED;
+            $this->brouillon = 0;
 		}
 
 		if (! $error)
@@ -3774,7 +3778,7 @@ class Commande extends CommonOrder
 	 *  @param      int			$hidedetails    Hide details of lines
 	 *  @param      int			$hidedesc       Hide description
 	 *  @param      int			$hideref        Hide ref
-	 *  @param   null|array  $moreparams     Array to provide more information
+	 *  @param      null|array  $moreparams     Array to provide more information
 	 *  @return     int         				0 if KO, 1 if OK
 	 */
 	public function generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)

+ 20 - 16
htdocs/compta/facture/card.php

@@ -93,11 +93,6 @@ $hidedetails = (GETPOST('hidedetails', 'int') ? GETPOST('hidedetails', 'int') :
 $hidedesc = (GETPOST('hidedesc', 'int') ? GETPOST('hidedesc', 'int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DESC) ? 1 : 0));
 $hideref = (GETPOST('hideref', 'int') ? GETPOST('hideref', 'int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_REF) ? 1 : 0));
 
-// Security check
-$fieldid = (! empty($ref) ? 'facnumber' : 'rowid');
-if ($user->societe_id) $socid = $user->societe_id;
-$result = restrictedArea($user, 'facture', $id, '', '', 'fk_soc', $fieldid);
-
 // Nombre de ligne pour choix de produit/service predefinis
 $NBLINES = 4;
 
@@ -118,6 +113,12 @@ $permissionnote = $user->rights->facture->creer; // Used by the include of actio
 $permissiondellink=$user->rights->facture->creer;	// Used by the include of actions_dellink.inc.php
 $permissiontoedit = $user->rights->facture->creer; // Used by the include of actions_lineupdonw.inc.php
 
+// Security check
+$fieldid = (! empty($ref) ? 'facnumber' : 'rowid');
+if ($user->societe_id) $socid = $user->societe_id;
+$isdraft = (($object->statut == Facture::STATUS_DRAFT) ? 1 : 0);
+$result = restrictedArea($user, 'facture', $id, '', '', 'fk_soc', $fieldid, $isdraft);
+
 
 /*
  * Actions
@@ -178,7 +179,7 @@ if (empty($reshook))
 	}
 
 	// Delete invoice
-	else if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->facture->supprimer) {
+	else if ($action == 'confirm_delete' && $confirm == 'yes') {
 		$result = $object->fetch($id);
 		$object->fetch_thirdparty();
 
@@ -191,7 +192,10 @@ if (empty($reshook))
 			$qualified_for_stock_change = $object->hasProductsOrServices(1);
 		}
 
-		if ($object->is_erasable())
+		$isErasable=$object->is_erasable();
+
+		if (($user->rights->facture->supprimer && $isErasable > 0)
+			|| ($user->rights->facture->creer && $isErasable == 1))
 		{
 			$result = $object->delete($user, 0, $idwarehouse);
 			if ($result > 0) {
@@ -2981,8 +2985,8 @@ if ($action == 'create')
 		print $desc;
 		print '</div></div>';
 	}
-	
-	
+
+
 	if (empty($origin))
 	{
 		if ($socid > 0)
@@ -3057,7 +3061,7 @@ if ($action == 'create')
 
 	print '</div>';
 
-	
+
 	if(!empty($conf->global->INVOICE_USE_DEFAULT_DOCUMENT)) // Hidden conf
 	{
     	// Add auto select default document model
@@ -3069,7 +3073,7 @@ if ($action == 'create')
     	    $curent = !empty($conf->global->{$thisTypeConfName})?$conf->global->{$thisTypeConfName}:$conf->global->FACTURE_ADDON_PDF;
     	    $jsListType.=(!empty($jsListType)?',':'').'"'.$type.'":"'.$curent.'"';
     	}
-    	
+
     	print '<script type="text/javascript" language="javascript">
         		$(document).ready(function() {
                     var listType = {'.$jsListType.'};
@@ -3089,9 +3093,9 @@ if ($action == 'create')
         		});
         		</script>';
 	}
-	
-	
-	
+
+
+
 	print '</td></tr>';
 
 	if ($socid > 0)
@@ -4847,9 +4851,9 @@ else if ($id > 0 || ! empty($ref))
 			}
 
 			// Delete
-			if ($user->rights->facture->supprimer)
+			$isErasable = $object->is_erasable();
+			if ($user->rights->facture->supprimer || ($user->rights->facture->creer && $isErasable == 1))	// isErasable = 1 means draft with temporary ref (draft can always be deleted with no need of permissions)
 			{
-				$isErasable = $object->is_erasable();
 				//var_dump($isErasable);
 				if ($isErasable == -4) {
 					print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="' . $langs->trans("DisabledBecausePayments") . '">' . $langs->trans('Delete') . '</a></div>';

+ 3 - 3
htdocs/compta/facture/class/facture.class.php

@@ -251,7 +251,7 @@ class Facture extends CommonInvoice
 	 * If paid partially, $this->close_code can be:
 	 * - CLOSECODE_DISCOUNTVAT
 	 * - CLOSECODE_BADDEBT
-	 * If paid completelly, this->close_code will be null
+	 * If paid completely, this->close_code will be null
 	 */
 	const STATUS_CLOSED = 2;
 
@@ -2442,7 +2442,7 @@ class Facture extends CommonInvoice
 				}
 			}
 
-			// Set new ref and define current statut
+			// Set new ref and define current status
 			if (! $error)
 			{
 				$this->ref = $num;
@@ -4950,7 +4950,7 @@ class FactureLigne extends CommonInvoiceLine
 		if (is_null($this->fk_prev_id) || empty($this->fk_prev_id) || $this->fk_prev_id == "") {
 			return 0;
 		} else {
-		    // If invoice is a not a situation invoice, this->fk_prev_id is used for something else
+		    // If invoice is not a situation invoice, this->fk_prev_id is used for something else
             $tmpinvoice=new Facture($this->db);
             $tmpinvoice->fetch($invoiceid);
             if ($tmpinvoice->type != Facture::TYPE_SITUATION) return 0;

+ 42 - 41
htdocs/contrat/class/api_contracts.class.php

@@ -1,6 +1,7 @@
 <?php
 /* Copyright (C) 2015   Jean-François Ferry     <jfefe@aternatik.fr>
  * Copyright (C) 2016	Laurent Destailleur		<eldy@users.sourceforge.net>
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -215,28 +216,28 @@ class Contracts extends DolibarrApi
      *
      * @url	GET {id}/lines
      *
-     * @return int
+     * @return array
      */
     function getLines($id)
     {
-      if(! DolibarrApiAccess::$user->rights->contrat->lire) {
-		  	throw new RestException(401);
-		  }
+        if(! DolibarrApiAccess::$user->rights->contrat->lire) {
+            throw new RestException(401);
+		}
 
-      $result = $this->contract->fetch($id);
-      if( ! $result ) {
-         throw new RestException(404, 'Contract not found');
-      }
-
-		  if( ! DolibarrApi::_checkAccessToResource('contrat',$this->contract->id)) {
-			  throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
-      }
-      $this->contract->getLinesArray();
-      $result = array();
-      foreach ($this->contract->lines as $line) {
-        array_push($result,$this->_cleanObjectDatas($line));
-      }
-      return $result;
+        $result = $this->contract->fetch($id);
+        if( ! $result ) {
+            throw new RestException(404, 'Contract not found');
+        }
+
+		if( ! DolibarrApi::_checkAccessToResource('contrat',$this->contract->id)) {
+		    throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
+        }
+        $this->contract->getLinesArray();
+        $result = array();
+        foreach ($this->contract->lines as $line) {
+            array_push($result, $this->_cleanObjectDatas($line));
+        }
+        return $result;
     }
 
     /**
@@ -247,7 +248,7 @@ class Contracts extends DolibarrApi
      *
      * @url	POST {id}/lines
      *
-     * @return int
+     * @return int|bool
      */
     function postLine($id, $request_data = null)
     {
@@ -300,7 +301,7 @@ class Contracts extends DolibarrApi
      *
      * @url	PUT {id}/lines/{lineid}
      *
-     * @return object
+     * @return array|bool
      */
     function putLine($id, $lineid, $request_data = null)
     {
@@ -360,7 +361,7 @@ class Contracts extends DolibarrApi
      *
      * @url	PUT {id}/lines/{lineid}/activate
      *
-     * @return object
+     * @return array|bool
      */
     function activateLine($id, $lineid, $datestart, $dateend = null, $comment = null)
     {
@@ -369,7 +370,7 @@ class Contracts extends DolibarrApi
     	}
 
     	$result = $this->contract->fetch($id);
-    	if( ! $result ) {
+    	if (! $result) {
     		throw new RestException(404, 'Contrat not found');
     	}
 
@@ -398,16 +399,16 @@ class Contracts extends DolibarrApi
      *
      * @url	PUT {id}/lines/{lineid}/unactivate
      *
-     * @return object
+     * @return array|bool
      */
     function unactivateLine($id, $lineid, $datestart, $comment = null)
     {
-    	if(! DolibarrApiAccess::$user->rights->contrat->creer) {
+    	if (! DolibarrApiAccess::$user->rights->contrat->creer) {
     		throw new RestException(401);
     	}
 
     	$result = $this->contract->fetch($id);
-    	if( ! $result ) {
+    	if (! $result) {
     		throw new RestException(404, 'Contrat not found');
     	}
 
@@ -443,16 +444,16 @@ class Contracts extends DolibarrApi
      */
     function deleteLine($id, $lineid)
     {
-        if(! DolibarrApiAccess::$user->rights->contrat->creer) {
+        if (! DolibarrApiAccess::$user->rights->contrat->creer) {
 			throw new RestException(401);
 		}
 
         $result = $this->contract->fetch($id);
-        if( ! $result ) {
+        if (! $result) {
             throw new RestException(404, 'Contrat not found');
         }
 
-		if( ! DolibarrApi::_checkAccessToResource('contrat',$this->contract->id)) {
+		if (! DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) {
 			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
         }
 
@@ -478,16 +479,16 @@ class Contracts extends DolibarrApi
      */
     function put($id, $request_data = null)
     {
-        if(! DolibarrApiAccess::$user->rights->contrat->creer) {
+        if (! DolibarrApiAccess::$user->rights->contrat->creer) {
 			throw new RestException(401);
 		}
 
         $result = $this->contract->fetch($id);
-        if( ! $result ) {
+        if (! $result) {
             throw new RestException(404, 'Contrat not found');
         }
 
-		if( ! DolibarrApi::_checkAccessToResource('contrat',$this->contract->id)) {
+		if (! DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) {
 			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
 		}
         foreach($request_data as $field => $value) {
@@ -514,19 +515,19 @@ class Contracts extends DolibarrApi
      */
     function delete($id)
     {
-        if(! DolibarrApiAccess::$user->rights->contrat->supprimer) {
+        if (! DolibarrApiAccess::$user->rights->contrat->supprimer) {
 			throw new RestException(401);
 		}
         $result = $this->contract->fetch($id);
-        if( ! $result ) {
+        if (! $result) {
             throw new RestException(404, 'Contract not found');
         }
 
-		if( ! DolibarrApi::_checkAccessToResource('contrat',$this->contract->id)) {
+		if (! DolibarrApi::_checkAccessToResource('contrat',$this->contract->id)) {
 			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
 		}
 
-        if( ! $this->contract->delete(DolibarrApiAccess::$user)) {
+        if (! $this->contract->delete(DolibarrApiAccess::$user)) {
             throw new RestException(500, 'Error when delete contract : '.$this->contract->error);
         }
 
@@ -556,15 +557,15 @@ class Contracts extends DolibarrApi
      */
     function validate($id, $notrigger=0)
     {
-        if(! DolibarrApiAccess::$user->rights->contrat->creer) {
+        if (! DolibarrApiAccess::$user->rights->contrat->creer) {
 			throw new RestException(401);
 		}
         $result = $this->contract->fetch($id);
-        if( ! $result ) {
+        if (! $result) {
             throw new RestException(404, 'Contract not found');
         }
 
-		if( ! DolibarrApi::_checkAccessToResource('contrat',$this->contract->id)) {
+		if (! DolibarrApi::_checkAccessToResource('contrat',$this->contract->id)) {
 			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
 		}
 
@@ -602,15 +603,15 @@ class Contracts extends DolibarrApi
      */
     function close($id, $notrigger=0)
     {
-    	if(! DolibarrApiAccess::$user->rights->contrat->creer) {
+    	if (! DolibarrApiAccess::$user->rights->contrat->creer) {
     		throw new RestException(401);
     	}
     	$result = $this->contract->fetch($id);
-    	if( ! $result ) {
+    	if (! $result) {
     		throw new RestException(404, 'Contract not found');
     	}
 
-    	if( ! DolibarrApi::_checkAccessToResource('contrat',$this->contract->id)) {
+    	if (! DolibarrApi::_checkAccessToResource('contrat',$this->contract->id)) {
     		throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
     	}
 

+ 3 - 3
htdocs/core/actions_addupdatedelete.inc.php

@@ -72,7 +72,7 @@ if ($action == 'add' && ! empty($permissiontoadd))
 
 	if (! $error)
 	{
-		$result=$object->createCommon($user);
+		$result=$object->create($user);
 		if ($result > 0)
 		{
 			// Creation OK
@@ -127,7 +127,7 @@ if ($action == 'update' && ! empty($permissiontoadd))
 
 	if (! $error)
 	{
-		$result=$object->updateCommon($user);
+		$result=$object->update($user);
 		if ($result > 0)
 		{
 			$action='view';
@@ -169,7 +169,7 @@ if ($action == "update_extras" && ! empty($permissiontoadd))
 // Action to delete
 if ($action == 'confirm_delete' && ! empty($permissiontodelete))
 {
-	$result=$object->deleteCommon($user);
+	$result=$object->delete($user);
 	if ($result > 0)
 	{
 		// Delete OK

+ 34 - 7
htdocs/core/actions_massactions.inc.php

@@ -74,6 +74,7 @@ if (! $error && $massaction == 'confirm_presend')
 	{
 		$thirdparty=new Societe($db);
 		if ($objecttmp->element == 'expensereport') $thirdparty=new User($db);
+		if ($objecttmp->element == 'holiday')       $thirdparty=new User($db);
 
 		$objecttmp=new $objectclass($db);
 		foreach($toselect as $toselectid)
@@ -83,9 +84,10 @@ if (! $error && $massaction == 'confirm_presend')
 			if ($result > 0)
 			{
 				$listofobjectid[$toselectid]=$toselectid;
-				$thirdpartyid=$objecttmp->fk_soc?$objecttmp->fk_soc:$objecttmp->socid;
-				if ($objecttmp->element == 'societe') $thirdpartyid=$objecttmp->id;
+				$thirdpartyid=($objecttmp->fk_soc?$objecttmp->fk_soc:$objecttmp->socid);
+				if ($objecttmp->element == 'societe')       $thirdpartyid=$objecttmp->id;
 				if ($objecttmp->element == 'expensereport') $thirdpartyid=$objecttmp->fk_user_author;
+				if ($objecttmp->element == 'holiday')       $thirdpartyid=$objecttmp->fk_user;
 				$listofobjectthirdparties[$thirdpartyid]=$thirdpartyid;
 				$listofobjectref[$thirdpartyid][$toselectid]=$objecttmp;
 			}
@@ -93,7 +95,7 @@ if (! $error && $massaction == 'confirm_presend')
 	}
 
 	// Check mandatory parameters
-	if (empty($user->email))
+	if (GETPOST('fromtype','alpha') === 'user' && empty($user->email))
 	{
 		$error++;
 		setEventMessages($langs->trans("NoSenderEmailDefined"), null, 'warnings');
@@ -326,19 +328,23 @@ if (! $error && $massaction == 'confirm_presend')
 				$message = GETPOST('message','none');
 
 				$sendtobcc = GETPOST('sendtoccc');
-				if ($objectclass == 'Propale') 				$sendtobcc .= (empty($conf->global->MAIN_MAIL_AUTOCOPY_PROPOSAL_TO) ? '' : (($sendtobcc?", ":"").$conf->global->MAIN_MAIL_AUTOCOPY_PROPOSAL_TO));
+				if ($objectclass == 'Propal') 				$sendtobcc .= (empty($conf->global->MAIN_MAIL_AUTOCOPY_PROPOSAL_TO) ? '' : (($sendtobcc?", ":"").$conf->global->MAIN_MAIL_AUTOCOPY_PROPOSAL_TO));
 				if ($objectclass == 'Commande') 			$sendtobcc .= (empty($conf->global->MAIN_MAIL_AUTOCOPY_ORDER_TO) ? '' : (($sendtobcc?", ":"").$conf->global->MAIN_MAIL_AUTOCOPY_ORDER_TO));
 				if ($objectclass == 'Facture') 				$sendtobcc .= (empty($conf->global->MAIN_MAIL_AUTOCOPY_INVOICE_TO) ? '' : (($sendtobcc?", ":"").$conf->global->MAIN_MAIL_AUTOCOPY_INVOICE_TO));
 				if ($objectclass == 'Supplier_Proposal') 	$sendtobcc .= (empty($conf->global->MAIN_MAIL_AUTOCOPY_SUPPLIER_PROPOSAL_TO) ? '' : (($sendtobcc?", ":"").$conf->global->MAIN_MAIL_AUTOCOPY_SUPPLIER_PROPOSAL_TO));
 				if ($objectclass == 'CommandeFournisseur')	$sendtobcc .= (empty($conf->global->MAIN_MAIL_AUTOCOPY_SUPPLIER_ORDER_TO) ? '' : (($sendtobcc?", ":"").$conf->global->MAIN_MAIL_AUTOCOPY_SUPPLIER_ORDER_TO));
 				if ($objectclass == 'FactureFournisseur')	$sendtobcc .= (empty($conf->global->MAIN_MAIL_AUTOCOPY_SUPPLIER_INVOICE_TO) ? '' : (($sendtobcc?", ":"").$conf->global->MAIN_MAIL_AUTOCOPY_SUPPLIER_INVOICE_TO));
 
-				// $listofqualifiedobj is array with key = object id of qualified objects for the current thirdparty
+				// $listofqualifiedobj is array with key = object id and value is instance of qualified objects, for the current thirdparty (but thirdparty property is not loaded yet)
 				$oneemailperrecipient=(GETPOST('oneemailperrecipient')=='on'?1:0);
 				$looparray=array();
 				if (! $oneemailperrecipient)
 				{
 					$looparray = $listofqualifiedobj;
+					foreach ($looparray as $key => $objecttmp)
+					{
+						$looparray[$key]->thirdparty = $thirdparty;
+					}
 				}
 				else
 				{
@@ -348,7 +354,7 @@ if (! $error && $massaction == 'confirm_presend')
 				}
 				//var_dump($looparray);exit;
 
-				foreach ($looparray as $objecttmp)		// $objecttmp is a real object or an empty if we choose to send one email per thirdparty instead of per record
+				foreach ($looparray as $objecttmp)		// $objecttmp is a real object or an empty object if we choose to send one email per thirdparty instead of one per record
 				{
 					// Make substitution in email content
 					$substitutionarray=getCommonSubstitutionArray($langs, 0, null, $objecttmp);
@@ -375,11 +381,32 @@ if (! $error && $massaction == 'confirm_presend')
 					$filename = $attachedfiles['names'];
 					$mimetype = $attachedfiles['mimes'];
 
+					// Define the trackid when emails sent from the mass action
+					if ($oneemailperrecipient)
+					{
+						$trackid='thi'.$thirdparty->id;
+						if ($objecttmp->element == 'expensereport') $trackid='use'.$thirdparty->id;
+						if ($objecttmp->element == 'holiday') $trackid='use'.$thirdparty->id;
+					}
+					else
+					{
+						$trackid=strtolower(get_class($objecttmp));
+						if (get_class($objecttmp)=='Contrat')  $trackid='con';
+						if (get_class($objecttmp)=='Propal')   $trackid='pro';
+						if (get_class($objecttmp)=='Commande') $trackid='ord';
+						if (get_class($objecttmp)=='Facture')  $trackid='inv';
+						if (get_class($objecttmp)=='Supplier_Proposal')   $trackid='spr';
+						if (get_class($objecttmp)=='CommandeFournisseur') $trackid='sor';
+						if (get_class($objecttmp)=='FactureFournisseur')  $trackid='sin';
+
+						$trackid.=$objecttmp->id;
+					}
 					//var_dump($filepath);
+					//var_dump($trackid);exit;
 
 					// Send mail (substitutionarray must be done just before this)
 					require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
-					$mailfile = new CMailFile($subject,$sendto,$from,$message,$filepath,$mimetype,$filename,$sendtocc,$sendtobcc,$deliveryreceipt,-1);
+					$mailfile = new CMailFile($subject,$sendto,$from,$message,$filepath,$mimetype,$filename,$sendtocc,$sendtobcc,$deliveryreceipt,-1,'','',$trackid);
 					if ($mailfile->error)
 					{
 						$resaction.='<div class="error">'.$mailfile->error.'</div>';

+ 4 - 3
htdocs/core/boxes/box_graph_product_distribution.php

@@ -1,5 +1,6 @@
 <?php
 /* Copyright (C) 2013-2015 Laurent Destailleur  <eldy@users.sourceforge.net>
+ * Copyright (C) 2018       Frédéric France     <frederic.france@netlogic.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
@@ -139,10 +140,10 @@ class box_graph_product_distribution extends ModeleBoxes
 
 		if (! empty($conf->facture->enabled) && ! empty($user->rights->facture->lire))
 		{
-
 			// Build graphic number of object. $data = array(array('Lib',val1,val2,val3),...)
 			if ($showinvoicenb)
 			{
+                $langs->load("bills");
 				include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facturestats.class.php';
 
 				$showpointvalue = 1; $nocolor = 0;
@@ -202,6 +203,7 @@ class box_graph_product_distribution extends ModeleBoxes
 			// Build graphic number of object. $data = array(array('Lib',val1,val2,val3),...)
 			if ($showpropalnb)
 			{
+                $langs->load("propal");
 				include_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propalestats.class.php';
 
 				$showpointvalue = 1; $nocolor = 0;
@@ -258,11 +260,10 @@ class box_graph_product_distribution extends ModeleBoxes
 
 		if (! empty($conf->commande->enabled) && ! empty($user->rights->commande->lire))
 		{
-			$langs->load("orders");
-
 			// Build graphic number of object. $data = array(array('Lib',val1,val2,val3),...)
 			if ($showordernb)
 			{
+			    $langs->load("orders");
 				include_once DOL_DOCUMENT_ROOT.'/commande/class/commandestats.class.php';
 
 				$showpointvalue = 1; $nocolor = 0;

+ 9 - 1
htdocs/core/class/CMailFile.class.php

@@ -735,7 +735,11 @@ class CMailFile
 					if (! empty($conf->global->MAIN_MAIL_DEBUG)) $this->dump_mail();
 
 					$result=$this->smtps->getErrors();
-					if (empty($this->error) && empty($result)) $res=true;
+					if (empty($this->error) && empty($result))
+					{
+						dol_syslog("CMailFile::sendfile: mail end success", LOG_DEBUG);
+						$res=true;
+					}
 					else
 					{
 						if (empty($this->error)) $this->error=$result;
@@ -798,6 +802,10 @@ class CMailFile
 					dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
 					$res=false;
 				}
+				else
+				{
+					dol_syslog("CMailFile::sendfile: mail end success", LOG_DEBUG);
+				}
 			}
 			else
 			{

+ 3 - 2
htdocs/core/class/commoninvoice.class.php

@@ -329,12 +329,13 @@ abstract class CommonInvoice extends CommonObject
 	/**
 	 *  Return if an invoice can be deleted
 	 *	Rule is:
-	 *  If invoice is draft and has a temporary ref -> yes
+	 *  If invoice is draft and has a temporary ref -> yes (1)
 	 *  If hidden option INVOICE_CAN_NEVER_BE_REMOVED is on -> no (0)
 	 *  If invoice is dispatched in bookkeeping -> no (-1)
 	 *  If invoice has a definitive ref, is not last and INVOICE_CAN_ALWAYS_BE_REMOVED off -> no (-2)
 	 *  If invoice not last in a cycle -> no (-3)
 	 *  If there is payment -> no (-4)
+	 *  Otherwise -> yes (2)
 	 *
 	 *  @return    int         <=0 if no, >0 if yes
 	 */
@@ -383,7 +384,7 @@ abstract class CommonInvoice extends CommonObject
 		// Test if there is at least one payment. If yes, refuse to delete.
 		if (empty($conf->global->INVOICE_CAN_ALWAYS_BE_REMOVED) && $this->getSommePaiement() > 0) return -4;
 
-		return 1;
+		return 2;
 	}
 
 	/**

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

@@ -1824,7 +1824,7 @@ abstract class CommonObject
 				$this->multicurrency_code = $code;
 
 				list($fk_multicurrency, $rate) = MultiCurrency::getIdAndTxFromCode($this->db, $code);
-				if ($rate) $this->setMulticurrencyRate($rate);
+				if ($rate) $this->setMulticurrencyRate($rate,2);
 
 				return 1;
 			}

+ 28 - 14
htdocs/core/class/conf.class.php

@@ -348,32 +348,46 @@ class Conf
 		if (! empty($this->fournisseur))
 		{
 			$this->fournisseur->commande=new stdClass();
-			$this->fournisseur->commande->dir_output=$rootfordata."/fournisseur/commande";
-			$this->fournisseur->commande->dir_temp  =$rootfordata."/fournisseur/commande/temp";
+			$this->fournisseur->commande->multidir_output=array($this->entity => $rootfordata."/fournisseur/commande");
+			$this->fournisseur->commande->multidir_temp  =array($this->entity => $rootfordata."/fournisseur/commande/temp");
+			$this->fournisseur->commande->dir_output=$rootfordata."/fournisseur/commande";		// For backward compatibility
+			$this->fournisseur->commande->dir_temp  =$rootfordata."/fournisseur/commande/temp";	// For backward compatibility
 			$this->fournisseur->facture=new stdClass();
-			$this->fournisseur->facture->dir_output =$rootfordata."/fournisseur/facture";
-			$this->fournisseur->facture->dir_temp   =$rootfordata."/fournisseur/facture/temp";
+			$this->fournisseur->facture->multidir_output=array($this->entity => $rootfordata."/fournisseur/facture");
+			$this->fournisseur->facture->multidir_temp  =array($this->entity => $rootfordata."/fournisseur/facture/temp");
+			$this->fournisseur->facture->dir_output =$rootfordata."/fournisseur/facture";		// For backward compatibility
+			$this->fournisseur->facture->dir_temp   =$rootfordata."/fournisseur/facture/temp";	// For backward compatibility
 			$this->supplierproposal=new stdClass();
-			$this->supplierproposal->dir_output=$rootfordata."/supplier_proposal";
-			$this->supplierproposal->dir_temp=$rootfordata."/supplier_proposal/temp";
+			$this->supplierproposal->multidir_output=array($this->entity => $rootfordata."/supplier_proposal");
+			$this->supplierproposal->multidir_temp  =array($this->entity => $rootfordata."/supplier_proposal/temp");
+			$this->supplierproposal->dir_output=$rootfordata."/supplier_proposal";				// For backward compatibility
+			$this->supplierproposal->dir_temp=$rootfordata."/supplier_proposal/temp";			// For backward compatibility
 			$this->fournisseur->payment=new stdClass();
-			$this->fournisseur->payment->dir_output =$rootfordata."/fournisseur/payment";
-			$this->fournisseur->payment->dir_temp   =$rootfordata."/fournisseur/payment/temp";
+			$this->fournisseur->payment->multidir_output=array($this->entity => $rootfordata."/fournisseur/payment");
+			$this->fournisseur->payment->multidir_temp  =array($this->entity => $rootfordata."/fournisseur/payment/temp");
+			$this->fournisseur->payment->dir_output =$rootfordata."/fournisseur/payment";		// For backward compatibility
+			$this->fournisseur->payment->dir_temp   =$rootfordata."/fournisseur/payment/temp";	// For backward compatibility
 
 			// To prepare split of module fournisseur into fournisseur + supplier_order + supplier_invoice
 			if (! empty($this->fournisseur->enabled) && empty($this->global->MAIN_USE_NEW_SUPPLIERMOD))  // By default, if module supplier is on, we set new properties
 			{
     			$this->supplier_order=new stdClass();
     			$this->supplier_order->enabled=1;
-    			$this->supplier_order->dir_output=$rootfordata."/fournisseur/commande";
-    			$this->supplier_order->dir_temp=$rootfordata."/fournisseur/commande/temp";
+    			$this->supplier_order->multidir_output=array($this->entity => $rootfordata."/fournisseur/commande");
+    			$this->supplier_order->multidir_temp  =array($this->entity => $rootfordata."/fournisseur/commande/temp");
+    			$this->supplier_order->dir_output=$rootfordata."/fournisseur/commande";			// For backward compatibility
+    			$this->supplier_order->dir_temp=$rootfordata."/fournisseur/commande/temp";		// For backward compatibility
     			$this->supplier_invoice=new stdClass();
     			$this->supplier_invoice->enabled=1;
-    			$this->supplier_invoice->dir_output=$rootfordata."/fournisseur/facture";
-    			$this->supplier_invoice->dir_temp=$rootfordata."/fournisseur/facture/temp";
+    			$this->supplier_invoice->multidir_output=array($this->entity => $rootfordata."/fournisseur/facture");
+    			$this->supplier_invoice->multidir_temp  =array($this->entity => $rootfordata."/fournisseur/facture/temp");
+    			$this->supplier_invoice->dir_output=$rootfordata."/fournisseur/facture";		// For backward compatibility
+    			$this->supplier_invoice->dir_temp=$rootfordata."/fournisseur/facture/temp";		// For backward compatibility
     			$this->supplierproposal=new stdClass();
-    			$this->supplierproposal->dir_output=$rootfordata."/supplier_proposal";
-    			$this->supplierproposal->dir_temp=$rootfordata."/supplier_proposal/temp";
+    			$this->supplierproposal->multidir_output=array($this->entity => $rootfordata."/supplier_proposal");
+    			$this->supplierproposal->multidir_temp  =array($this->entity => $rootfordata."/supplier_proposal/temp");
+    			$this->supplierproposal->dir_output=$rootfordata."/supplier_proposal";			// For backward compatibility
+    			$this->supplierproposal->dir_temp=$rootfordata."/supplier_proposal/temp";		// For backward compatibility
 			}
 		}
 

+ 20 - 19
htdocs/core/class/html.form.class.php

@@ -2071,7 +2071,7 @@ class Form
 			$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_stock as ps on ps.fk_product = p.rowid";
 			$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e on ps.fk_entrepot = e.rowid";
 		}
-		
+
 		// include search in supplier ref
 		if(!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF))
 		{
@@ -3283,17 +3283,17 @@ class Form
 			if ($empty && empty($arraytypes['code'])) continue;
 
 			if ($format == 0) print '<option value="'.$id.'"';
-			if ($format == 1) print '<option value="'.$arraytypes['code'].'"';
-			if ($format == 2) print '<option value="'.$arraytypes['code'].'"';
-			if ($format == 3) print '<option value="'.$id.'"';
+			elseif ($format == 1) print '<option value="'.$arraytypes['code'].'"';
+			elseif ($format == 2) print '<option value="'.$arraytypes['code'].'"';
+			elseif ($format == 3) print '<option value="'.$id.'"';
 			// Si selected est text, on compare avec code, sinon avec id
 			if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) print ' selected';
 			elseif ($selected == $id) print ' selected';
 			print '>';
 			if ($format == 0) $value=($maxlength?dol_trunc($arraytypes['label'],$maxlength):$arraytypes['label']);
-			if ($format == 1) $value=$arraytypes['code'];
-			if ($format == 2) $value=($maxlength?dol_trunc($arraytypes['label'],$maxlength):$arraytypes['label']);
-			if ($format == 3) $value=$arraytypes['code'];
+			elseif ($format == 1) $value=$arraytypes['code'];
+			elseif ($format == 2) $value=($maxlength?dol_trunc($arraytypes['label'],$maxlength):$arraytypes['label']);
+			elseif ($format == 3) $value=$arraytypes['code'];
 			print $value?$value:'&nbsp;';
 			print '</option>';
 		}
@@ -3508,7 +3508,7 @@ class Form
 			    {
 			        $unitLabel = $langs->trans('unit'.$res->code)!=$res->label?$langs->trans('unit'.$res->code):$res->label;
 			    }
-			    
+
 				if ($selected == $res->rowid)
 				{
 				    $return.='<option value="'.$res->rowid.'" selected>'.$unitLabel.'</option>';
@@ -3806,18 +3806,18 @@ class Form
 					{
 						$more.='<tr><td'.(empty($input['tdclass'])?'':(' class="'.$input['tdclass'].'"')).'>'.$input['label'].'</td><td align="left"><input type="text" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'"'.$size.' value="'.$input['value'].'"'.$moreattr.' /></td></tr>'."\n";
 					}
-					else if ($input['type'] == 'password')
+					elseif ($input['type'] == 'password')
 					{
 						$more.='<tr><td'.(empty($input['tdclass'])?'':(' class="'.$input['tdclass'].'"')).'>'.$input['label'].'</td><td align="left"><input type="password" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'"'.$size.' value="'.$input['value'].'"'.$moreattr.' /></td></tr>'."\n";
 					}
-					else if ($input['type'] == 'select')
+					elseif ($input['type'] == 'select')
 					{
 						$more.='<tr><td'.(empty($input['tdclass'])?'':(' class="'.$input['tdclass'].'"')).'>';
 						if (! empty($input['label'])) $more.=$input['label'].'</td><td class="tdtop" align="left">';
 						$more.=$this->selectarray($input['name'],$input['values'],$input['default'],1,0,0,$moreattr,0,0,0,'',$morecss);
 						$more.='</td></tr>'."\n";
 					}
-					else if ($input['type'] == 'checkbox')
+					elseif ($input['type'] == 'checkbox')
 					{
 						$more.='<tr>';
 						$more.='<td'.(empty($input['tdclass'])?'':(' class="'.$input['tdclass'].'"')).'>'.$input['label'].' </td><td align="left">';
@@ -3828,7 +3828,7 @@ class Form
 						$more.=' /></td>';
 						$more.='</tr>'."\n";
 					}
-					else if ($input['type'] == 'radio')
+					elseif ($input['type'] == 'radio')
 					{
 						$i=0;
 						foreach($input['values'] as $selkey => $selval)
@@ -3844,7 +3844,7 @@ class Form
 							$i++;
 						}
 					}
-					else if ($input['type'] == 'date')
+					elseif ($input['type'] == 'date')
 					{
 						$more.='<tr><td'.(empty($input['tdclass'])?'':(' class="'.$input['tdclass'].'"')).'>'.$input['label'].'</td>';
 						$more.='<td align="left">';
@@ -3856,7 +3856,7 @@ class Form
 						$formquestion[] = array('name'=>$input['name'].'hour');
 						$formquestion[] = array('name'=>$input['name'].'min');
 					}
-					else if ($input['type'] == 'other')
+					elseif ($input['type'] == 'other')
 					{
 						$more.='<tr><td'.(empty($input['tdclass'])?'':(' class="'.$input['tdclass'].'"')).'>';
 						if (! empty($input['label'])) $more.=$input['label'].'</td><td align="left">';
@@ -3864,7 +3864,7 @@ class Form
 						$more.='</td></tr>'."\n";
 					}
 
-					else if ($input['type'] == 'onecolumn')
+					elseif ($input['type'] == 'onecolumn')
 					{
 						$more.='<tr><td colspan="2" align="left">';
 						$more.=$input['value'];
@@ -4589,6 +4589,7 @@ class Form
 	 *
 	 *    @param	string	$selected    preselected currency code
 	 *    @param    string	$htmlname    name of HTML select list
+     *    @deprecated
 	 *    @return	void
 	 */
 	function select_currency($selected='',$htmlname='currency_id')
@@ -4976,7 +4977,7 @@ class Form
 	 *  @param  int			$fullday        When a checkbox with this html name is on, hour and day are set with 00:00 or 23:59
 	 *  @param	string		$addplusone		Add a link "+1 hour". Value must be name of another select_date field.
 	 *  @param  datetime    $adddateof      Add a link "Date of invoice" using the following date.
-	 *  @return	string|null					Nothing or string if nooutput is 1
+	 *  @return	string|void					Nothing or string if nooutput is 1
      *  @deprecated
 	 *  @see    form_date, select_month, select_year, select_dayofweek
 	 */
@@ -5374,7 +5375,7 @@ class Form
 	 *						            if 'textselect' input hour is in text and input min is a combo
 	 *  @param	integer	$minunderhours	If 1, show minutes selection under the hours
 	 * 	@param	int	$nooutput		    Do not output html string but return it
-	 *  @return	string|null
+	 *  @return	string|void
 	 */
 	function select_duration($prefix, $iSecond='', $disabled=0, $typehour='select', $minunderhours=0, $nooutput=0)
 	{
@@ -7144,7 +7145,7 @@ class Form
 	}
 
 	/**
-	 * Return HTML to show the select categories of expense category
+	 * Return HTML to show the select of expense categories
 	 *
 	 * @param	string	$selected              preselected category
 	 * @param	string	$htmlname              name of HTML select list
@@ -7160,7 +7161,7 @@ class Form
 		global $db, $conf, $langs, $user;
 
 		$sql = 'SELECT rowid, label FROM '.MAIN_DB_PREFIX.'c_exp_tax_cat WHERE active = 1';
-		$sql.= ' AND entity IN (0,'.getEntity('').')';
+		$sql.= ' AND entity IN (0,'.getEntity('exp_tax_cat').')';
 		if (!empty($excludeid)) $sql.= ' AND rowid NOT IN ('.implode(',', $excludeid).')';
 		$sql.= ' ORDER BY label';
 

+ 4 - 6
htdocs/core/class/html.formfile.class.php

@@ -884,15 +884,13 @@ class FormFile
 		$out='';
 		$this->infofiles=array('nboffiles'=>0,'extensions'=>array(),'files'=>array());
 
+		$entity = 1; // Without multicompany
+
 		// Get object entity
-		if (empty($conf->multicompany->enabled))
-		{
-			$entity = $conf->entity;
-		}
-		else
+		if (! empty($conf->multicompany->enabled))
 		{
 			preg_match('/\/([0-9]+)\/[^\/]+\/'.preg_quote($modulesubdir,'/').'$/', $filedir, $regs);
-			$entity = ((! empty($regs[1]) && $regs[1] > 1) ? $regs[1] : $conf->entity);
+			$entity = ((! empty($regs[1]) && $regs[1] > 1) ? $regs[1] : 1); // If entity id not found in $filedir this is entity 1 by default
 		}
 
 		// Get list of files starting with name of ref (but not followed by "-" to discard uploaded files and get only generated files)

+ 15 - 1
htdocs/core/class/html.formmail.class.php

@@ -880,6 +880,20 @@ class FormMail extends Form
 				$out.= '<td>'.$langs->trans("MailFile").'</td>';
 
 				$out.= '<td>';
+
+				if ($this->withmaindocfile)	// withmaindocfile is set to 1 or -1 to show the checkbox (-1 = checked or 1 = not checked)
+				{
+					if (GETPOSTISSET('sendmail'))
+					{
+						$this->withmaindocfile = (GETPOST('addmaindocfile', 'alpha') ? -1 : 1);
+					}
+					// If a template was selected, we use setup of template to define if join file checkbox is selected or not.
+					elseif (is_object($arraydefaultmessage) && $arraydefaultmessage->id > 0)
+					{
+						$this->withmaindocfile = ($arraydefaultmessage->joinfiles ? -1 : 1);
+					}
+				}
+
 				if (! empty($this->withmaindocfile))
 				{
 					if ($this->withmaindocfile == 1)
@@ -888,7 +902,7 @@ class FormMail extends Form
 					}
 					if ($this->withmaindocfile == -1)
 					{
-						$out.='<input type="checkbox" name="addmaindocfile" checked="checked" />';
+						$out.='<input type="checkbox" name="addmaindocfile" value="1" checked="checked" />';
 					}
 					$out.=' '.$langs->trans("JoinMainDoc").'.<br>';
 				}

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

@@ -932,10 +932,11 @@ function activateModule($value,$withdeps=1)
             if (isset($objMod->depends) && is_array($objMod->depends) && ! empty($objMod->depends))
             {
                 // Activation of modules this module depends on
-                // this->depends may be array('modModule1', 'mmodModule2') or array('always'=>"modModule1", 'FR'=>'modModule2')
+                // this->depends may be array('modModule1', 'mmodModule2') or array('always1'=>"modModule1", 'FR'=>'modModule2')
                 foreach ($objMod->depends as $key => $modulestring)
                 {
-                    if ((! is_numeric($key)) && $key != 'always' && $key != $mysoc->country_code)
+                	//var_dump((! is_numeric($key)) && ! preg_match('/^always/', $key) && $mysoc->country_code && ! preg_match('/^'.$mysoc->country_code.'/', $key));exit;
+                	if ((! is_numeric($key)) && ! preg_match('/^always/', $key) && $mysoc->country_code && ! preg_match('/^'.$mysoc->country_code.'/', $key))
                     {
                         dol_syslog("We are not concerned by dependency with key=".$key." because our country is ".$mysoc->country_code);
                         continue;
@@ -943,6 +944,7 @@ function activateModule($value,$withdeps=1)
                 	$activate = false;
                 	foreach ($modulesdir as $dir)
                 	{
+                		var_dump($modulestring);
                 		if (file_exists($dir.$modulestring.".class.php"))
                 		{
                 			$resarray = activateModule($modulestring);

+ 17 - 14
htdocs/core/lib/functions.lib.php

@@ -115,16 +115,16 @@ function getDoliDBInstance($type, $host, $user, $pass, $name, $port)
  *									'c_paiement', 'c_payment_term', ...
  * 	@param	int		$shared			0=Return id of current entity only,
  * 									1=Return id of current entity + shared entities (default)
- *  @param	int		$forceentity	Entity id
+ *  @param	object	$currentobject	Current object if needed
  * 	@return	mixed				Entity id(s) to use
  */
-function getEntity($element, $shared=1, $forceentity=null)
+function getEntity($element, $shared=1, $currentobject=null)
 {
 	global $conf, $mc;
 
 	if (is_object($mc))
 	{
-		return $mc->getEntity($element, $shared, $forceentity);
+		return $mc->getEntity($element, $shared, $currentobject);
 	}
 	else
 	{
@@ -3237,6 +3237,9 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $
 			elseif ($pictowithoutext == 'playdisabled') {
 				$fakey = 'fa-play';
 				$facolor = '#ccc';
+			} elseif ($pictowithoutext == 'play') {
+				$fakey = 'fa-play';
+				$facolor = '#444';
 			}
 			else {
 				$fakey = 'fa-'.$pictowithoutext;
@@ -6572,7 +6575,7 @@ function get_htmloutput_mesg($mesgstring='',$mesgarray='', $style='ok', $keepemb
 /**
  *  Get formated error messages to output (Used to show messages on html output).
  *
- *  @param	string	$mesgstring         Error message
+ *  @param  string	$mesgstring         Error message
  *  @param  array	$mesgarray          Error messages array
  *  @param  int		$keepembedded       Set to 1 in error message must be kept embedded into its html place (this disable jnotify)
  *  @return string                		Return html output
@@ -6580,7 +6583,7 @@ function get_htmloutput_mesg($mesgstring='',$mesgarray='', $style='ok', $keepemb
  *  @see    dol_print_error
  *  @see    dol_htmloutput_mesg
  */
-function get_htmloutput_errors($mesgstring='', $mesgarray='', $keepembedded=0)
+function get_htmloutput_errors($mesgstring='', $mesgarray=array(), $keepembedded=0)
 {
 	return get_htmloutput_mesg($mesgstring, $mesgarray,'error',$keepembedded);
 }
@@ -6590,15 +6593,15 @@ function get_htmloutput_errors($mesgstring='', $mesgarray='', $keepembedded=0)
  *
  *	@param	string		$mesgstring		Message string or message key
  *	@param	string[]	$mesgarray      Array of message strings or message keys
- *  @param  string      $style          Which style to use ('ok', 'warning', 'error')
- *  @param  int         $keepembedded   Set to 1 if message must be kept embedded into its html place (this disable jnotify)
- *  @return	void
+ *	@param  string      $style          Which style to use ('ok', 'warning', 'error')
+ *	@param  int         $keepembedded   Set to 1 if message must be kept embedded into its html place (this disable jnotify)
+ *	@return	void
  *
- *  @see    dol_print_error
- *  @see    dol_htmloutput_errors
- *  @see    setEventMessages
+ *	@see    dol_print_error
+ *	@see    dol_htmloutput_errors
+ *	@see    setEventMessages
  */
-function dol_htmloutput_mesg($mesgstring='',$mesgarray='', $style='ok', $keepembedded=0)
+function dol_htmloutput_mesg($mesgstring = '',$mesgarray = array(), $style = 'ok', $keepembedded=0)
 {
 	if (empty($mesgstring) && (! is_array($mesgarray) || count($mesgarray) == 0)) return;
 
@@ -6652,7 +6655,7 @@ function dol_htmloutput_mesg($mesgstring='',$mesgarray='', $style='ok', $keepemb
  *  @see    dol_print_error
  *  @see    dol_htmloutput_mesg
  */
-function dol_htmloutput_errors($mesgstring='', $mesgarray='', $keepembedded=0)
+function dol_htmloutput_errors($mesgstring='', $mesgarray=array(), $keepembedded=0)
 {
 	dol_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
 }
@@ -7682,7 +7685,7 @@ function getDictvalue($tablename, $field, $id, $checkentity=false, $rowidfield='
 	{
 		$dictvalues[$tablename] = array();
 		$sql = 'SELECT * FROM '.$tablename.' WHERE 1';
-		if ($checkentity) $sql.= ' AND entity IN (0,'.getEntity('').')';
+		if ($checkentity) $sql.= ' AND entity IN (0,'.getEntity($tablename).')';
 
 		$resql = $db->query($sql);
 		if ($resql)

+ 239 - 238
htdocs/core/lib/security.lib.php

@@ -39,7 +39,7 @@ function dol_encode($chain, $key='1')
 	if (is_numeric($key) && $key == '1')	// rule 1 is offset of 17 for char
 	{
 		$output_tab=array();
-	    $strlength=dol_strlen($chain);
+		$strlength=dol_strlen($chain);
 		for ($i=0; $i < $strlength; $i++)
 		{
 			$output_tab[$i] = chr(ord(substr($chain,$i,1))+17);
@@ -174,18 +174,19 @@ function dol_verifyHash($chain, $hash, $type='0')
  *	@param  string	$feature2		Feature to check, second level of permission (optional). Can be a 'or' check with 'level1|level2'.
  *  @param  string	$dbt_keyfield   Field name for socid foreign key if not fk_soc. Not used if objectid is null (optional)
  *  @param  string	$dbt_select     Field name for select if not rowid. Not used if objectid is null (optional)
+ *  @param	int		$isdraft		1=The object with id=$objectid is a draft
  * 	@return	int						Always 1, die process if not allowed
  *  @see dol_check_secure_access_document
  */
-function restrictedArea($user, $features, $objectid=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid')
+function restrictedArea($user, $features, $objectid=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0)
 {
 	global $db, $conf;
 	global $hookmanager;
 
-    //dol_syslog("functions.lib:restrictedArea $feature, $objectid, $dbtablename,$feature2,$dbt_socfield,$dbt_select");
-    //print "user_id=".$user->id.", features=".$features.", feature2=".$feature2.", objectid=".$objectid;
-    //print ", dbtablename=".$dbtablename.", dbt_socfield=".$dbt_keyfield.", dbt_select=".$dbt_select;
-    //print ", perm: ".$features."->".$feature2."=".($user->rights->$features->$feature2->lire)."<br>";
+	//dol_syslog("functions.lib:restrictedArea $feature, $objectid, $dbtablename,$feature2,$dbt_socfield,$dbt_select");
+	//print "user_id=".$user->id.", features=".$features.", feature2=".$feature2.", objectid=".$objectid;
+	//print ", dbtablename=".$dbtablename.", dbt_socfield=".$dbt_keyfield.", dbt_select=".$dbt_select;
+	//print ", perm: ".$features."->".$feature2."=".($user->rights->$features->$feature2->lire)."<br>";
 
 	// Get more permissions checks from hooks
 	$parameters=array('features'=>$features, 'objectid'=>$objectid, 'idtype'=>$dbt_select);
@@ -196,225 +197,225 @@ function restrictedArea($user, $features, $objectid=0, $tableandshare='', $featu
 	if ($dbt_select != 'rowid' && $dbt_select != 'id') $objectid = "'".$objectid."'";
 
 	// Features/modules to check
-    $featuresarray = array($features);
-    if (preg_match('/&/', $features)) $featuresarray = explode("&", $features);
-    else if (preg_match('/\|/', $features)) $featuresarray = explode("|", $features);
+	$featuresarray = array($features);
+	if (preg_match('/&/', $features)) $featuresarray = explode("&", $features);
+	else if (preg_match('/\|/', $features)) $featuresarray = explode("|", $features);
 
-    // More subfeatures to check
-    if (! empty($feature2)) $feature2 = explode("|", $feature2);
+	// More subfeatures to check
+	if (! empty($feature2)) $feature2 = explode("|", $feature2);
 
-    // More parameters
-    $params = explode('&', $tableandshare);
-    $dbtablename=(! empty($params[0]) ? $params[0] : '');
-    $sharedelement=(! empty($params[1]) ? $params[1] : $dbtablename);
+	// More parameters
+	$params = explode('&', $tableandshare);
+	$dbtablename=(! empty($params[0]) ? $params[0] : '');
+	$sharedelement=(! empty($params[1]) ? $params[1] : $dbtablename);
 
 	$listofmodules=explode(',',$conf->global->MAIN_MODULES_FOR_EXTERNAL);
 
 	// Check read permission from module
-    $readok=1; $nbko=0;
-    foreach ($featuresarray as $feature)	// first we check nb of test ko
-    {
-        $featureforlistofmodule=$feature;
-        if ($featureforlistofmodule == 'produit') $featureforlistofmodule='product';
-        if (! empty($user->societe_id) && ! empty($conf->global->MAIN_MODULES_FOR_EXTERNAL) && ! in_array($featureforlistofmodule,$listofmodules))	// If limits on modules for external users, module must be into list of modules for external users
-    	{
-    		$readok=0; $nbko++;
-    		continue;
-    	}
-
-        if ($feature == 'societe')
-        {
-            if (! $user->rights->societe->lire && ! $user->rights->fournisseur->lire) { $readok=0; $nbko++; }
-        }
-        else if ($feature == 'contact')
-        {
-            if (! $user->rights->societe->contact->lire) { $readok=0; $nbko++; }
-        }
-        else if ($feature == 'produit|service')
-        {
-            if (! $user->rights->produit->lire && ! $user->rights->service->lire) { $readok=0; $nbko++; }
-        }
-        else if ($feature == 'prelevement')
-        {
-            if (! $user->rights->prelevement->bons->lire) { $readok=0; $nbko++; }
-        }
-        else if ($feature == 'cheque')
-        {
-            if (! $user->rights->banque->cheque) { $readok=0; $nbko++; }
-        }
-        else if ($feature == 'projet')
-        {
-            if (! $user->rights->projet->lire && ! $user->rights->projet->all->lire) { $readok=0; $nbko++; }
-        }
-        else if (! empty($feature2))	// This should be used for future changes
-        {
-        	$tmpreadok=1;
-        	foreach($feature2 as $subfeature)
-        	{
-        		if (! empty($subfeature) && empty($user->rights->$feature->$subfeature->lire) && empty($user->rights->$feature->$subfeature->read)) { $tmpreadok=0; }
-        		else if (empty($subfeature) && empty($user->rights->$feature->lire) && empty($user->rights->$feature->read)) { $tmpreadok=0; }
-        		else { $tmpreadok=1; break; } // Break is to bypass second test if the first is ok
-        	}
-        	if (! $tmpreadok)	// We found a test on feature that is ko
-        	{
-        		$readok=0;	// All tests are ko (we manage here the and, the or will be managed later using $nbko).
-        		$nbko++;
-        	}
-        }
-        else if (! empty($feature) && ($feature!='user' && $feature!='usergroup'))		// This is for old permissions
-        {
-            if (empty($user->rights->$feature->lire)
-            && empty($user->rights->$feature->read)
-            && empty($user->rights->$feature->run)) { $readok=0; $nbko++; }
-        }
-    }
+	$readok=1; $nbko=0;
+	foreach ($featuresarray as $feature)	// first we check nb of test ko
+	{
+		$featureforlistofmodule=$feature;
+		if ($featureforlistofmodule == 'produit') $featureforlistofmodule='product';
+		if (! empty($user->societe_id) && ! empty($conf->global->MAIN_MODULES_FOR_EXTERNAL) && ! in_array($featureforlistofmodule,$listofmodules))	// If limits on modules for external users, module must be into list of modules for external users
+		{
+			$readok=0; $nbko++;
+			continue;
+		}
 
-    // If a or and at least one ok
-    if (preg_match('/\|/', $features) && $nbko < count($featuresarray)) $readok=1;
+		if ($feature == 'societe')
+		{
+			if (! $user->rights->societe->lire && ! $user->rights->fournisseur->lire) { $readok=0; $nbko++; }
+		}
+		else if ($feature == 'contact')
+		{
+			if (! $user->rights->societe->contact->lire) { $readok=0; $nbko++; }
+		}
+		else if ($feature == 'produit|service')
+		{
+			if (! $user->rights->produit->lire && ! $user->rights->service->lire) { $readok=0; $nbko++; }
+		}
+		else if ($feature == 'prelevement')
+		{
+			if (! $user->rights->prelevement->bons->lire) { $readok=0; $nbko++; }
+		}
+		else if ($feature == 'cheque')
+		{
+			if (! $user->rights->banque->cheque) { $readok=0; $nbko++; }
+		}
+		else if ($feature == 'projet')
+		{
+			if (! $user->rights->projet->lire && ! $user->rights->projet->all->lire) { $readok=0; $nbko++; }
+		}
+		else if (! empty($feature2))	// This should be used for future changes
+		{
+			$tmpreadok=1;
+			foreach($feature2 as $subfeature)
+			{
+				if (! empty($subfeature) && empty($user->rights->$feature->$subfeature->lire) && empty($user->rights->$feature->$subfeature->read)) { $tmpreadok=0; }
+				else if (empty($subfeature) && empty($user->rights->$feature->lire) && empty($user->rights->$feature->read)) { $tmpreadok=0; }
+				else { $tmpreadok=1; break; } // Break is to bypass second test if the first is ok
+			}
+			if (! $tmpreadok)	// We found a test on feature that is ko
+			{
+				$readok=0;	// All tests are ko (we manage here the and, the or will be managed later using $nbko).
+				$nbko++;
+			}
+		}
+		else if (! empty($feature) && ($feature!='user' && $feature!='usergroup'))		// This is for old permissions
+		{
+			if (empty($user->rights->$feature->lire)
+				&& empty($user->rights->$feature->read)
+				&& empty($user->rights->$feature->run)) { $readok=0; $nbko++; }
+		}
+	}
 
-    if (! $readok) accessforbidden();
-    //print "Read access is ok";
+	// If a or and at least one ok
+	if (preg_match('/\|/', $features) && $nbko < count($featuresarray)) $readok=1;
 
-    // Check write permission from module
-    $createok=1; $nbko=0;
-    if (GETPOST('action','aZ09')  == 'create')
-    {
-        foreach ($featuresarray as $feature)
-        {
-            if ($feature == 'contact')
-            {
-                if (! $user->rights->societe->contact->creer) { $createok=0; $nbko++; }
-            }
-            else if ($feature == 'produit|service')
-            {
-                if (! $user->rights->produit->creer && ! $user->rights->service->creer) { $createok=0; $nbko++; }
-            }
-            else if ($feature == 'prelevement')
-            {
-                if (! $user->rights->prelevement->bons->creer) { $createok=0; $nbko++; }
-            }
-            else if ($feature == 'commande_fournisseur')
-            {
-                if (! $user->rights->fournisseur->commande->creer) { $createok=0; $nbko++; }
-            }
-            else if ($feature == 'banque')
-            {
-                if (! $user->rights->banque->modifier) { $createok=0; $nbko++; }
-            }
-            else if ($feature == 'cheque')
-            {
-                if (! $user->rights->banque->cheque) { $createok=0; $nbko++; }
-            }
-            else if (! empty($feature2))	// This should be used
-            {
-            	foreach($feature2 as $subfeature)
-            	{
-                        if (empty($user->rights->$feature->$subfeature->creer)
-                        && empty($user->rights->$feature->$subfeature->write)
-                        && empty($user->rights->$feature->$subfeature->create)) { $createok=0; $nbko++; }
-            		else { $createok=1; break; } // Break to bypass second test if the first is ok
-            	}
-            }
-            else if (! empty($feature))		// This is for old permissions ('creer' or 'write')
-            {
-                //print '<br>feature='.$feature.' creer='.$user->rights->$feature->creer.' write='.$user->rights->$feature->write;
-                if (empty($user->rights->$feature->creer)
-                && empty($user->rights->$feature->write)
-                && empty($user->rights->$feature->create)) { $createok=0; $nbko++; }
-            }
-        }
-
-	    // If a or and at least one ok
-	    if (preg_match('/\|/', $features) && $nbko < count($featuresarray)) $createok=1;
-
-        if (! $createok) accessforbidden();
-        //print "Write access is ok";
-    }
+	if (! $readok) accessforbidden();
+	//print "Read access is ok";
 
-    // Check create user permission
-    $createuserok=1;
-    if (GETPOST('action','aZ09') == 'confirm_create_user' && GETPOST("confirm",'aZ09') == 'yes')
-    {
-        if (! $user->rights->user->user->creer) $createuserok=0;
+	// Check write permission from module (we need to know write permission to create but also to delete drafts record)
+	$createok=1; $nbko=0;
+	if (GETPOST('action','aZ09')  == 'create' || ((GETPOST("action","aZ09")  == 'confirm_delete' && GETPOST("confirm","aZ09") == 'yes') || GETPOST("action","aZ09")  == 'delete'))
+	{
+		foreach ($featuresarray as $feature)
+		{
+			if ($feature == 'contact')
+			{
+				if (! $user->rights->societe->contact->creer) { $createok=0; $nbko++; }
+			}
+			else if ($feature == 'produit|service')
+			{
+				if (! $user->rights->produit->creer && ! $user->rights->service->creer) { $createok=0; $nbko++; }
+			}
+			else if ($feature == 'prelevement')
+			{
+				if (! $user->rights->prelevement->bons->creer) { $createok=0; $nbko++; }
+			}
+			else if ($feature == 'commande_fournisseur')
+			{
+				if (! $user->rights->fournisseur->commande->creer) { $createok=0; $nbko++; }
+			}
+			else if ($feature == 'banque')
+			{
+				if (! $user->rights->banque->modifier) { $createok=0; $nbko++; }
+			}
+			else if ($feature == 'cheque')
+			{
+				if (! $user->rights->banque->cheque) { $createok=0; $nbko++; }
+			}
+			else if (! empty($feature2))	// This should be used
+			{
+				foreach($feature2 as $subfeature)
+				{
+					if (empty($user->rights->$feature->$subfeature->creer)
+						&& empty($user->rights->$feature->$subfeature->write)
+						&& empty($user->rights->$feature->$subfeature->create)) { $createok=0; $nbko++; }
+						else { $createok=1; break; } // Break to bypass second test if the first is ok
+				}
+			}
+			else if (! empty($feature))		// This is for old permissions ('creer' or 'write')
+			{
+				//print '<br>feature='.$feature.' creer='.$user->rights->$feature->creer.' write='.$user->rights->$feature->write;
+				if (empty($user->rights->$feature->creer)
+					&& empty($user->rights->$feature->write)
+					&& empty($user->rights->$feature->create)) { $createok=0; $nbko++; }
+			}
+		}
 
-        if (! $createuserok) accessforbidden();
-        //print "Create user access is ok";
-    }
+		// If a or and at least one ok
+		if (preg_match('/\|/', $features) && $nbko < count($featuresarray)) $createok=1;
 
-    // Check delete permission from module
-    $deleteok=1; $nbko=0;
-    if ((GETPOST("action","aZ09")  == 'confirm_delete' && GETPOST("confirm","aZ09") == 'yes') || GETPOST("action","aZ09")  == 'delete')
-    {
-        foreach ($featuresarray as $feature)
-        {
-            if ($feature == 'contact')
-            {
-                if (! $user->rights->societe->contact->supprimer) $deleteok=0;
-            }
-            else if ($feature == 'produit|service')
-            {
-                if (! $user->rights->produit->supprimer && ! $user->rights->service->supprimer) $deleteok=0;
-            }
-            else if ($feature == 'commande_fournisseur')
-            {
-                if (! $user->rights->fournisseur->commande->supprimer) $deleteok=0;
-            }
-            else if ($feature == 'banque')
-            {
-                if (! $user->rights->banque->modifier) $deleteok=0;
-            }
-            else if ($feature == 'cheque')
-            {
-                if (! $user->rights->banque->cheque) $deleteok=0;
-            }
-            else if ($feature == 'ecm')
-            {
-                if (! $user->rights->ecm->upload) $deleteok=0;
-            }
-            else if ($feature == 'ftp')
-            {
-                if (! $user->rights->ftp->write) $deleteok=0;
-            }else if ($feature == 'salaries')
-            {
-                if (! $user->rights->salaries->delete) $deleteok=0;
-            }
-            else if ($feature == 'salaries')
-            {
-                if (! $user->rights->salaries->delete) $deleteok=0;
-            }
-            else if (! empty($feature2))	// This should be used for future changes
-            {
-            	foreach($feature2 as $subfeature)
-            	{
-            		if (empty($user->rights->$feature->$subfeature->supprimer) && empty($user->rights->$feature->$subfeature->delete)) $deleteok=0;
-            		else { $deleteok=1; break; } // For bypass the second test if the first is ok
-            	}
-            }
-            else if (! empty($feature))		// This is for old permissions
-            {
-                //print '<br>feature='.$feature.' creer='.$user->rights->$feature->supprimer.' write='.$user->rights->$feature->delete;
-                if (empty($user->rights->$feature->supprimer)
-                && empty($user->rights->$feature->delete)
-                && empty($user->rights->$feature->run)) $deleteok=0;
-            }
-        }
-
-	    // If a or and at least one ok
-	    if (preg_match('/\|/', $features) && $nbko < count($featuresarray)) $deleteok=1;
-
-        if (! $deleteok) accessforbidden();
-        //print "Delete access is ok";
-    }
+		if (GETPOST('action','aZ09') == 'create' && ! $createok) accessforbidden();
+		//print "Write access is ok";
+	}
 
-    // If we have a particular object to check permissions on, we check this object
-    // is linked to a company allowed to $user.
-    if (! empty($objectid) && $objectid > 0)
-    {
-        $ok = checkUserAccessToObject($user, $featuresarray, $objectid, $tableandshare, $feature2, $dbt_keyfield, $dbt_select);
-        return $ok ? 1 : accessforbidden();
-    }
+	// Check create user permission
+	$createuserok=1;
+	if (GETPOST('action','aZ09') == 'confirm_create_user' && GETPOST("confirm",'aZ09') == 'yes')
+	{
+		if (! $user->rights->user->user->creer) $createuserok=0;
+
+		if (! $createuserok) accessforbidden();
+		//print "Create user access is ok";
+	}
+
+	// Check delete permission from module
+	$deleteok=1; $nbko=0;
+	if ((GETPOST("action","aZ09")  == 'confirm_delete' && GETPOST("confirm","aZ09") == 'yes') || GETPOST("action","aZ09")  == 'delete')
+	{
+		foreach ($featuresarray as $feature)
+		{
+			if ($feature == 'contact')
+			{
+				if (! $user->rights->societe->contact->supprimer) $deleteok=0;
+			}
+			else if ($feature == 'produit|service')
+			{
+				if (! $user->rights->produit->supprimer && ! $user->rights->service->supprimer) $deleteok=0;
+			}
+			else if ($feature == 'commande_fournisseur')
+			{
+				if (! $user->rights->fournisseur->commande->supprimer) $deleteok=0;
+			}
+			else if ($feature == 'banque')
+			{
+				if (! $user->rights->banque->modifier) $deleteok=0;
+			}
+			else if ($feature == 'cheque')
+			{
+				if (! $user->rights->banque->cheque) $deleteok=0;
+			}
+			else if ($feature == 'ecm')
+			{
+				if (! $user->rights->ecm->upload) $deleteok=0;
+			}
+			else if ($feature == 'ftp')
+			{
+				if (! $user->rights->ftp->write) $deleteok=0;
+			}else if ($feature == 'salaries')
+			{
+				if (! $user->rights->salaries->delete) $deleteok=0;
+			}
+			else if ($feature == 'salaries')
+			{
+				if (! $user->rights->salaries->delete) $deleteok=0;
+			}
+			else if (! empty($feature2))	// This should be used for permissions on 2 levels
+			{
+				foreach($feature2 as $subfeature)
+				{
+					if (empty($user->rights->$feature->$subfeature->supprimer) && empty($user->rights->$feature->$subfeature->delete)) $deleteok=0;
+					else { $deleteok=1; break; } // For bypass the second test if the first is ok
+				}
+			}
+			else if (! empty($feature))		// This is used for permissions on 1 level
+			{
+				//print '<br>feature='.$feature.' creer='.$user->rights->$feature->supprimer.' write='.$user->rights->$feature->delete;
+				if (empty($user->rights->$feature->supprimer)
+					&& empty($user->rights->$feature->delete)
+					&& empty($user->rights->$feature->run)) $deleteok=0;
+			}
+		}
 
-    return 1;
+		// If a or and at least one ok
+		if (preg_match('/\|/', $features) && $nbko < count($featuresarray)) $deleteok=1;
+
+		if (! $deleteok && ! ($isdraft && $createok)) accessforbidden();
+		//print "Delete access is ok";
+	}
+
+	// If we have a particular object to check permissions on, we check this object
+	// is linked to a company allowed to $user.
+	if (! empty($objectid) && $objectid > 0)
+	{
+		$ok = checkUserAccessToObject($user, $featuresarray, $objectid, $tableandshare, $feature2, $dbt_keyfield, $dbt_select);
+		return $ok ? 1 : accessforbidden();
+	}
+
+	return 1;
 }
 
 /**
@@ -576,8 +577,8 @@ function checkUserAccessToObject($user, $featuresarray, $objectid=0, $tableandsh
 		{
 			if (! empty($conf->projet->enabled) && empty($user->rights->projet->all->lire))
 			{
-			    $task = new Task($db);
-			    $task->fetch($objectid);
+				$task = new Task($db);
+				$task->fetch($objectid);
 
 				include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
 				$projectstatic=new Project($db);
@@ -665,30 +666,30 @@ function accessforbidden($message='',$printheader=1,$printfooter=1,$showonlymess
         $langs->setDefaultLang();
     }
 
-    $langs->load("errors");
+	$langs->load("errors");
 
-    if ($printheader)
-    {
-        if (function_exists("llxHeader")) llxHeader('');
-        else if (function_exists("llxHeaderVierge")) llxHeaderVierge('');
-    }
-    print '<div class="error">';
-    if (! $message) print $langs->trans("ErrorForbidden");
-    else print $message;
-    print '</div>';
-    print '<br>';
-    if (empty($showonlymessage))
-    {
-        if ($user->login)
-        {
-            print $langs->trans("CurrentLogin").': <font class="error">'.$user->login.'</font><br>';
-            print $langs->trans("ErrorForbidden2",$langs->trans("Home"),$langs->trans("Users"));
-        }
-        else
-        {
-            print $langs->trans("ErrorForbidden3");
-        }
-    }
-    if ($printfooter && function_exists("llxFooter")) llxFooter();
-    exit(0);
+	if ($printheader)
+	{
+		if (function_exists("llxHeader")) llxHeader('');
+		else if (function_exists("llxHeaderVierge")) llxHeaderVierge('');
+	}
+	print '<div class="error">';
+	if (! $message) print $langs->trans("ErrorForbidden");
+	else print $message;
+	print '</div>';
+	print '<br>';
+	if (empty($showonlymessage))
+	{
+		if ($user->login)
+		{
+			print $langs->trans("CurrentLogin").': <font class="error">'.$user->login.'</font><br>';
+			print $langs->trans("ErrorForbidden2",$langs->trans("Home"),$langs->trans("Users"));
+		}
+		else
+		{
+			print $langs->trans("ErrorForbidden3");
+		}
+	}
+	if ($printfooter && function_exists("llxFooter")) llxFooter();
+	exit(0);
 }

+ 1 - 1
htdocs/core/modules/DolibarrModules.class.php

@@ -300,7 +300,7 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it
 	/**
 	 * @var string[] List of module class names that must be enabled if this module is enabled.
 	 *
-	 * e.g.: array('modAnotherModule', 'modYetAnotherModule')
+	 * e.g.: array('modAnotherModule', 'FR'=>'modYetAnotherModule')
 	 */
 	public $depends;
 

+ 1 - 1
htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php

@@ -488,7 +488,7 @@ class doc_generic_order_odt extends ModelePDFCommandes
 				else {
 					try {
 					$odfHandler->saveToDisk($file);
-					}catch (Exception $e){
+					} catch (Exception $e) {
                         $this->error=$e->getMessage();
                         dol_syslog($e->getMessage(), LOG_INFO);
 						return -1;

+ 12 - 5
htdocs/core/modules/contract/doc/doc_generic_contract_odt.modules.php

@@ -2,7 +2,8 @@
 /* Copyright (C) 2010-2012 	Laurent Destailleur <eldy@users.sourceforge.net>
  * Copyright (C) 2012		Juanjo Menent		<jmenent@2byte.es>
  * Copyright (C) 2018		Ferran Marcet		<fmarcet@2byte.es>
-*
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -354,6 +355,7 @@ class doc_generic_contract_odt extends ModelePDFContract
 				catch(Exception $e)
 				{
 					$this->error=$e->getMessage();
+					dol_syslog($e->getMessage(), LOG_INFO);
 					return -1;
 				}
 				// After construction $odfHandler->contentXml contains content and
@@ -367,8 +369,9 @@ class doc_generic_contract_odt extends ModelePDFContract
 				try {
 					$odfHandler->setVars('free_text', $newfreetext, true, 'UTF-8');
 				}
-				catch(OdfException $e)
+				catch (OdfException $e)
 				{
+					dol_syslog($e->getMessage(), LOG_INFO);
 				}
 
 				foreach($tmparray as $key=>$value)
@@ -384,8 +387,9 @@ class doc_generic_contract_odt extends ModelePDFContract
 							$odfHandler->setVars($key, $value, true, 'UTF-8');
 						}
 					}
-					catch(OdfException $e)
+					catch (OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 
@@ -419,9 +423,11 @@ class doc_generic_contract_odt extends ModelePDFContract
 								}
 								catch(OdfException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 								catch(SegmentException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 							}
 							$listlines->merge();
@@ -445,6 +451,7 @@ class doc_generic_contract_odt extends ModelePDFContract
 					}
 					catch(OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 
@@ -456,7 +463,7 @@ class doc_generic_contract_odt extends ModelePDFContract
 				if (!empty($conf->global->MAIN_ODT_AS_PDF)) {
 					try {
 						$odfHandler->exportAsAttachedPDF($file);
-					}catch (Exception $e){
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
 						return -1;
 					}
@@ -464,7 +471,7 @@ class doc_generic_contract_odt extends ModelePDFContract
 				else {
 					try {
 					$odfHandler->saveToDisk($file);
-					}catch (Exception $e){
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
 						return -1;
 					}

+ 20 - 9
htdocs/core/modules/expedition/doc/doc_generic_shipment_odt.modules.php

@@ -4,8 +4,8 @@
  * Copyright (C) 2014		Marcos García		<marcosgdf@gmail.com>
  * Copyright (C) 2016		Charlie Benke		<charlie@patas-monkey.com>
  * Copyright (C) 2018       Philippe Grand      <philippe.grand@atoo-net.com>
-
-*
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -347,6 +347,7 @@ class doc_generic_shipment_odt extends ModelePdfExpedition
 				catch(Exception $e)
 				{
 					$this->error=$e->getMessage();
+					dol_syslog($e->getMessage(), LOG_INFO);
 					return -1;
 				}
 				// After construction $odfHandler->contentXml contains content and
@@ -362,6 +363,7 @@ class doc_generic_shipment_odt extends ModelePdfExpedition
 				}
 				catch(OdfException $e)
 				{
+					dol_syslog($e->getMessage(), LOG_INFO);
 				}
 
 				// Make substitutions into odt of user info
@@ -381,8 +383,9 @@ class doc_generic_shipment_odt extends ModelePdfExpedition
 							$odfHandler->setVars($key, $value, true, 'UTF-8');
 						}
 					}
-					catch(OdfException $e)
+					catch (OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 				// Make substitutions into odt of mysoc
@@ -402,8 +405,9 @@ class doc_generic_shipment_odt extends ModelePdfExpedition
 							$odfHandler->setVars($key, $value, true, 'UTF-8');
 						}
 					}
-					catch(OdfException $e)
+					catch (OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 				// Make substitutions into odt of thirdparty
@@ -421,8 +425,9 @@ class doc_generic_shipment_odt extends ModelePdfExpedition
 							$odfHandler->setVars($key, $value, true, 'UTF-8');
 						}
 					}
-					catch(OdfException $e)
+					catch (OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 				// Replace tags of object + external modules
@@ -446,6 +451,7 @@ class doc_generic_shipment_odt extends ModelePdfExpedition
 					}
 					catch(OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 				// Replace tags of lines
@@ -478,9 +484,11 @@ class doc_generic_shipment_odt extends ModelePdfExpedition
 								}
 								catch(OdfException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 								catch(SegmentException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 							}
 							$listlines->merge();
@@ -488,7 +496,7 @@ class doc_generic_shipment_odt extends ModelePdfExpedition
 						$odfHandler->mergeSegment($listlines);
 					}
 				}
-				catch(OdfException $e)
+				catch (OdfException $e)
 				{
 					$this->error=$e->getMessage();
 					dol_syslog($this->error, LOG_WARNING);
@@ -502,8 +510,9 @@ class doc_generic_shipment_odt extends ModelePdfExpedition
 					try {
 						$odfHandler->setVars($key, $value, true, 'UTF-8');
 					}
-					catch(OdfException $e)
+					catch (OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 
@@ -515,16 +524,18 @@ class doc_generic_shipment_odt extends ModelePdfExpedition
 				if (!empty($conf->global->MAIN_ODT_AS_PDF)) {
 					try {
 						$odfHandler->exportAsAttachedPDF($file);
-					}catch (Exception $e){
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
+                        dol_syslog($e->getMessage(), LOG_INFO);
 						return -1;
 					}
 				}
 				else {
 					try {
 					$odfHandler->saveToDisk($file);
-					}catch (Exception $e){
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
+                        dol_syslog($e->getMessage(), LOG_INFO);
 						return -1;
 					}
 				}

+ 1 - 1
htdocs/core/modules/expensereport/doc/pdf_standard.modules.php

@@ -278,7 +278,7 @@ class pdf_standard extends ModeleExpenseReport
 				$pagenb=0;
 				$pdf->SetDrawColor(128,128,128);
 
-				$pdf->SetTitle($outputlangs->convToOutputCharset($object->ref_number));
+				$pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
 				$pdf->SetSubject($outputlangs->transnoentities("Trips"));
 				$pdf->SetCreator("Dolibarr ".DOL_VERSION);
 				$pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs)));

+ 18 - 9
htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php

@@ -1,9 +1,10 @@
 <?php
 /* Copyright (C) 2010-2012	Laurent Destailleur	<ely@users.sourceforge.net>
-* Copyright (C) 2012		Regis Houssin		<regis.houssin@capnetworks.com>
-* Copyright (C) 2014		Marcos García		<marcosgdf@gmail.com>
-* Copyright (C) 2016		Charlie Benke		<charlie@patas-monkey.com>
-*
+ * Copyright (C) 2012		Regis Houssin		<regis.houssin@capnetworks.com>
+ * Copyright (C) 2014		Marcos García		<marcosgdf@gmail.com>
+ * Copyright (C) 2016		Charlie Benke		<charlie@patas-monkey.com>
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -355,9 +356,10 @@ class doc_generic_invoice_odt extends ModelePDFFactures
 						)
 					);
 				}
-				catch(Exception $e)
+				catch (Exception $e)
 				{
 					$this->error=$e->getMessage();
+					dol_syslog($e->getMessage(), LOG_INFO);
 					return -1;
 				}
 				// After construction $odfHandler->contentXml contains content and
@@ -371,8 +373,9 @@ class doc_generic_invoice_odt extends ModelePDFFactures
 				try {
 					$odfHandler->setVars('free_text', $newfreetext, true, 'UTF-8');
 				}
-				catch(OdfException $e)
+				catch (OdfException $e)
 				{
+					dol_syslog($e->getMessage(), LOG_INFO);
 				}
 
 				// Define substitution array
@@ -410,8 +413,9 @@ class doc_generic_invoice_odt extends ModelePDFFactures
 							$odfHandler->setVars($key, $value, true, 'UTF-8');
 						}
 					}
-					catch(OdfException $e)
+					catch (OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 				// Replace tags of lines
@@ -444,9 +448,11 @@ class doc_generic_invoice_odt extends ModelePDFFactures
 								}
 								catch(OdfException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 								catch(SegmentException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 							}
 							$listlines->merge();
@@ -470,6 +476,7 @@ class doc_generic_invoice_odt extends ModelePDFFactures
 					}
 					catch(OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 
@@ -483,14 +490,16 @@ class doc_generic_invoice_odt extends ModelePDFFactures
 						$odfHandler->exportAsAttachedPDF($file);
 					}catch (Exception $e){
 						$this->error=$e->getMessage();
+                        dol_syslog($e->getMessage(), LOG_INFO);
 						return -1;
 					}
 				}
 				else {
 					try {
-					$odfHandler->saveToDisk($file);
-					}catch (Exception $e){
+						$odfHandler->saveToDisk($file);
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
+                        dol_syslog($e->getMessage(), LOG_INFO);
 						return -1;
 					}
 				}

+ 0 - 37
htdocs/core/modules/livraison/doc/pdf_typhon.modules.php

@@ -808,43 +808,6 @@ class pdf_typhon extends ModelePDFDeliveryOrder
 
 		$posy+=2;
 
-		// Add list of linked orders on shipment
-		// Currently not supported by pdf_writeLinkedObjects, link for delivery to order is done through shipment)
-		if ($object->origin == 'expedition' || $object->origin == 'shipping')
-		{
-			$Yoff=$posy-5;
-
-			include_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
-			$shipment = new Expedition($this->db);
-			$shipment->fetch($object->origin_id);
-
-		    $origin 	= $shipment->origin;
-			$origin_id 	= $shipment->origin_id;
-
-			if ($conf->$origin->enabled)
-			{
-				$outputlangs->load('orders');
-
-				$classname = ucfirst($origin);
-				$linkedobject = new $classname($this->db);
-				$result=$linkedobject->fetch($origin_id);
-				if ($result >= 0)
-				{
-					$pdf->SetFont('','', $default_font_size - 2);
-					$text=$linkedobject->ref;
-					if ($linkedobject->ref_client) $text.=' ('.$linkedobject->ref_client.')';
-					$Yoff = $Yoff+8;
-					$pdf->SetXY($this->page_largeur - $this->marge_droite - 100,$Yoff);
-					$pdf->MultiCell(100, 2, $outputlangs->transnoentities("RefOrder") ." : ".$outputlangs->transnoentities($text), 0, 'R');
-					$Yoff = $Yoff+3;
-					$pdf->SetXY($this->page_largeur - $this->marge_droite - 60,$Yoff);
-					$pdf->MultiCell(60, 2, $outputlangs->transnoentities("OrderDate")." : ".dol_print_date($linkedobject->date,"day",false,$outputlangs,true), 0, 'R');
-				}
-			}
-
-			$posy=$Yoff;
-		}
-
 		// Show list of linked objects
 		$posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, 100, 3, 'R', $default_font_size);
 

+ 2 - 2
htdocs/core/modules/modDav.class.php

@@ -44,7 +44,7 @@ class modDav extends DolibarrModules
 
 		// Id for module (must be unique).
 		// Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id).
-		$this->numero = 50310;		// TODO Go on page https://wiki.dolibarr.org/index.php/List_of_modules_id to reserve id number for your module
+		$this->numero = 50310;
 		// Key text used to identify module (for permissions, menus, etc...)
 		$this->rights_class = 'dav';
 
@@ -104,7 +104,7 @@ class modDav extends DolibarrModules
 		//                             1=>array('DAV_MYNEWCONST2','chaine','myvalue','This is another constant to add',0, 'current', 1)
 		// );
 		$this->const = array(
-			1=>array('DAV_MYCONSTANT', 'chaine', 'avalue', 'This is a constant to add', 1, 'allentities', 1)
+			//1=>array('DAV_MYCONSTANT', 'chaine', 'avalue', 'This is a constant to add', 1, 'allentities', 1)
 		);
 
 

+ 323 - 0
htdocs/core/modules/modEmailCollector.class.php

@@ -0,0 +1,323 @@
+<?php
+/* Copyright (C) 2004-2018 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/>.
+ */
+
+/**
+ * 	\defgroup   dav     Module dav
+ *  \brief      dav module descriptor.
+ *
+ *  \file       htdocs/dav/core/modules/modDav.class.php
+ *  \ingroup    dav
+ *  \brief      Description and activation file for module dav
+ */
+include_once DOL_DOCUMENT_ROOT .'/core/modules/DolibarrModules.class.php';
+
+
+/**
+ *  Description and activation class for module dav
+ */
+class modEmailCollector extends DolibarrModules
+{
+	/**
+	 * Constructor. Define names, constants, directories, boxes, permissions
+	 *
+	 * @param DoliDB $db Database handler
+	 */
+	public function __construct($db)
+	{
+        global $langs,$conf;
+
+        $this->db = $db;
+
+		// Id for module (must be unique).
+		// Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id).
+		$this->numero = 50320;
+		// Key text used to identify module (for permissions, menus, etc...)
+		$this->rights_class = 'dav';
+
+		// Family can be 'base' (core modules),'crm','financial','hr','projects','products','ecm','technic' (transverse modules),'interface' (link with external tools),'other','...'
+		// It is used to group modules by family in module setup page
+		$this->family = "interface";
+		// Module position in the family on 2 digits ('01', '10', '20', ...)
+		$this->module_position = '75';
+		// Gives the possibility to the module, to provide his own family info and position of this family (Overwrite $this->family and $this->module_position. Avoid this)
+		//$this->familyinfo = array('myownfamily' => array('position' => '01', 'label' => $langs->trans("MyOwnFamily")));
+
+		// Module label (no space allowed), used if translation string 'ModuledavName' not found (MyModue is name of module).
+		$this->name = preg_replace('/^mod/i','',get_class($this));
+		// Module description, used if translation string 'ModuledavDesc' not found (MyModue is name of module).
+		$this->description = "EmailCollectorDescription";
+		// Used only if file README.md and README-LL.md not found.
+		$this->descriptionlong = "EmailCollectorDescription";
+
+		// Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z'
+		$this->version = 'development';
+		// Key used in llx_const table to save module status enabled/disabled (where DAV is value of property name of module in uppercase)
+		$this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
+		// Name of image file used for this module.
+		// If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue'
+		// If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module'
+		$this->picto='generic';
+
+		// Defined all module parts (triggers, login, substitutions, menus, css, etc...)
+		// for default path (eg: /dav/core/xxxxx) (0=disable, 1=enable)
+		// for specific path of parts (eg: /dav/core/modules/barcode)
+		// for specific css file (eg: /dav/css/dav.css.php)
+		$this->module_parts = array();
+
+		// Data directories to create when module is enabled.
+		// Example: this->dirs = array("/dav/temp","/dav/subdir");
+		$this->dirs = array();
+
+		// Config pages. Put here list of php page, stored into dav/admin directory, to use to setup module.
+		$this->config_page_url = array("emailcollector.php");
+
+		// Dependencies
+		$this->hidden = false;			// A condition to hide module
+		$this->depends = array();		// List of module class names as string that must be enabled if this module is enabled
+		$this->requiredby = array();	// List of module ids to disable if this one is disabled
+		$this->conflictwith = array();	// List of module class names as string this module is in conflict with
+		$this->langfiles = array("admin");
+		$this->phpmin = array(5,4);					// Minimum version of PHP required by module
+		$this->need_dolibarr_version = array(7,0);	// Minimum version of Dolibarr required by module
+		$this->warnings_activation = array();                     // Warning to show when we activate module. array('always'='text') or array('FR'='textfr','ES'='textes'...)
+		$this->warnings_activation_ext = array();                 // Warning to show when we activate an external module. array('always'='text') or array('FR'='textfr','ES'='textes'...)
+		//$this->automatic_activation = array('FR'=>'davWasAutomaticallyActivatedBecauseOfYourCountryChoice');
+		//$this->always_enabled = true;								// If true, can't be disabled
+
+		// Constants
+		// List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive)
+		// Example: $this->const=array(0=>array('DAV_MYNEWCONST1','chaine','myvalue','This is a constant to add',1),
+		//                             1=>array('DAV_MYNEWCONST2','chaine','myvalue','This is another constant to add',0, 'current', 1)
+		// );
+		$this->const = array(
+			//1=>array('DAV_MYCONSTANT', 'chaine', 'avalue', 'This is a constant to add', 1, 'allentities', 1)
+		);
+
+
+		if (! isset($conf->dav) || ! isset($conf->dav->enabled))
+		{
+			$conf->dav=new stdClass();
+			$conf->dav->enabled=0;
+		}
+
+
+		// Array to add new pages in new tabs
+        $this->tabs = array();
+		// Example:
+		// $this->tabs[] = array('data'=>'objecttype:+tabname1:Title1:mylangfile@dav:$user->rights->dav->read:/dav/mynewtab1.php?id=__ID__');  					// To add a new tab identified by code tabname1
+        // $this->tabs[] = array('data'=>'objecttype:+tabname2:SUBSTITUTION_Title2:mylangfile@dav:$user->rights->othermodule->read:/dav/mynewtab2.php?id=__ID__',  	// To add another new tab identified by code tabname2. Label will be result of calling all substitution functions on 'Title2' key.
+        // $this->tabs[] = array('data'=>'objecttype:-tabname:NU:conditiontoremove');                                                     										// To remove an existing tab identified by code tabname
+        //
+        // Where objecttype can be
+		// 'categories_x'	  to add a tab in category view (replace 'x' by type of category (0=product, 1=supplier, 2=customer, 3=member)
+		// 'contact'          to add a tab in contact view
+		// 'contract'         to add a tab in contract view
+		// 'group'            to add a tab in group view
+		// 'intervention'     to add a tab in intervention view
+		// 'invoice'          to add a tab in customer invoice view
+		// 'invoice_supplier' to add a tab in supplier invoice view
+		// 'member'           to add a tab in fundation member view
+		// 'opensurveypoll'	  to add a tab in opensurvey poll view
+		// 'order'            to add a tab in customer order view
+		// 'order_supplier'   to add a tab in supplier order view
+		// 'payment'		  to add a tab in payment view
+		// 'payment_supplier' to add a tab in supplier payment view
+		// 'product'          to add a tab in product view
+		// 'propal'           to add a tab in propal view
+		// 'project'          to add a tab in project view
+		// 'stock'            to add a tab in stock view
+		// 'thirdparty'       to add a tab in third party view
+		// 'user'             to add a tab in user view
+
+
+        // Dictionaries
+		$this->dictionaries=array();
+        /* Example:
+        $this->dictionaries=array(
+            'langs'=>'mylangfile@dav',
+            'tabname'=>array(MAIN_DB_PREFIX."table1",MAIN_DB_PREFIX."table2",MAIN_DB_PREFIX."table3"),		// List of tables we want to see into dictonnary editor
+            'tablib'=>array("Table1","Table2","Table3"),													// Label of tables
+            'tabsql'=>array('SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table1 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table2 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table3 as f'),	// Request to select fields
+            'tabsqlsort'=>array("label ASC","label ASC","label ASC"),																					// Sort order
+            'tabfield'=>array("code,label","code,label","code,label"),																					// List of fields (result of select to show dictionary)
+            'tabfieldvalue'=>array("code,label","code,label","code,label"),																				// List of fields (list of fields to edit a record)
+            'tabfieldinsert'=>array("code,label","code,label","code,label"),																			// List of fields (list of fields for insert)
+            'tabrowid'=>array("rowid","rowid","rowid"),																									// Name of columns with primary key (try to always name it 'rowid')
+            'tabcond'=>array($conf->dav->enabled,$conf->dav->enabled,$conf->dav->enabled)												// Condition to show each dictionary
+        );
+        */
+
+
+        // Boxes/Widgets
+		// Add here list of php file(s) stored in dav/core/boxes that contains class to show a widget.
+        $this->boxes = array(
+        	//0=>array('file'=>'davwidget1.php@dav','note'=>'Widget provided by dav','enabledbydefaulton'=>'Home'),
+        	//1=>array('file'=>'davwidget2.php@dav','note'=>'Widget provided by dav'),
+        	//2=>array('file'=>'davwidget3.php@dav','note'=>'Widget provided by dav')
+        );
+
+
+		// Cronjobs (List of cron jobs entries to add when module is enabled)
+		// unit_frequency must be 60 for minute, 3600 for hour, 86400 for day, 604800 for week
+		//$this->cronjobs = array(
+			//0=>array('label'=>'MyJob label', 'jobtype'=>'method', 'class'=>'/dav/class/myobject.class.php', 'objectname'=>'MyObject', 'method'=>'doScheduledJob', 'parameters'=>'', 'comment'=>'Comment', 'frequency'=>2, 'unitfrequency'=>3600, 'status'=>0, 'test'=>true)
+		//);
+		// Example: $this->cronjobs=array(0=>array('label'=>'My label', 'jobtype'=>'method', 'class'=>'/dir/class/file.class.php', 'objectname'=>'MyClass', 'method'=>'myMethod', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>2, 'unitfrequency'=>3600, 'status'=>0, 'test'=>true),
+		//                                1=>array('label'=>'My label', 'jobtype'=>'command', 'command'=>'', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>1, 'unitfrequency'=>3600*24, 'status'=>0, 'test'=>true)
+		// );
+
+
+		// Permissions
+		$this->rights = array();		// Permission array used by this module
+
+		/*
+		$r=0;
+		$this->rights[$r][0] = $this->numero + $r;	// Permission id (must not be already used)
+		$this->rights[$r][1] = 'Read myobject of dav';	// Permission label
+		$this->rights[$r][3] = 1; 					// Permission by default for new user (0/1)
+		$this->rights[$r][4] = 'read';				// In php code, permission will be checked by test if ($user->rights->dav->level1->level2)
+		$this->rights[$r][5] = '';				    // In php code, permission will be checked by test if ($user->rights->dav->level1->level2)
+
+		$r++;
+		$this->rights[$r][0] = $this->numero + $r;	// Permission id (must not be already used)
+		$this->rights[$r][1] = 'Create/Update myobject of dav';	// Permission label
+		$this->rights[$r][3] = 1; 					// Permission by default for new user (0/1)
+		$this->rights[$r][4] = 'write';				// In php code, permission will be checked by test if ($user->rights->dav->level1->level2)
+		$this->rights[$r][5] = '';				    // In php code, permission will be checked by test if ($user->rights->dav->level1->level2)
+
+		$r++;
+		$this->rights[$r][0] = $this->numero + $r;	// Permission id (must not be already used)
+		$this->rights[$r][1] = 'Delete myobject of dav';	// Permission label
+		$this->rights[$r][3] = 1; 					// Permission by default for new user (0/1)
+		$this->rights[$r][4] = 'delete';				// In php code, permission will be checked by test if ($user->rights->dav->level1->level2)
+		$this->rights[$r][5] = '';				    // In php code, permission will be checked by test if ($user->rights->dav->level1->level2)
+		*/
+
+		// Main menu entries
+		$this->menu = array();			// List of menus to add
+		$r=0;
+
+		// Add here entries to declare new menus
+
+		/* BEGIN MODULEBUILDER TOPMENU */
+		/*$this->menu[$r++]=array('fk_menu'=>'',			                // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
+								'type'=>'top',			                // This is a Top menu entry
+								'titre'=>'dav',
+								'mainmenu'=>'dav',
+								'leftmenu'=>'',
+								'url'=>'/dav/davindex.php',
+								'langs'=>'dav@dav',	        // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
+								'position'=>1000+$r,
+								'enabled'=>'$conf->dav->enabled',	// Define condition to show or hide menu entry. Use '$conf->dav->enabled' if entry must be visible if module is enabled.
+								'perms'=>'1',			                // Use 'perms'=>'$user->rights->dav->level1->level2' if you want your menu with a permission rules
+								'target'=>'',
+								'user'=>2);				                // 0=Menu for internal users, 1=external users, 2=both
+		*/
+		/* END MODULEBUILDER TOPMENU */
+
+		/* BEGIN MODULEBUILDER LEFTMENU MYOBJECT
+		$this->menu[$r++]=array(	'fk_menu'=>'fk_mainmenu=dav',	    // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
+								'type'=>'left',			                // This is a Left menu entry
+								'titre'=>'List MyObject',
+								'mainmenu'=>'dav',
+								'leftmenu'=>'dav_myobject_list',
+								'url'=>'/dav/myobject_list.php',
+								'langs'=>'dav@dav',	        // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
+								'position'=>1000+$r,
+								'enabled'=>'$conf->dav->enabled',  // Define condition to show or hide menu entry. Use '$conf->dav->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected.
+								'perms'=>'1',			                // Use 'perms'=>'$user->rights->dav->level1->level2' if you want your menu with a permission rules
+								'target'=>'',
+								'user'=>2);				                // 0=Menu for internal users, 1=external users, 2=both
+		$this->menu[$r++]=array(	'fk_menu'=>'fk_mainmenu=dav,fk_leftmenu=dav',	    // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
+								'type'=>'left',			                // This is a Left menu entry
+								'titre'=>'New MyObject',
+								'mainmenu'=>'dav',
+								'leftmenu'=>'dav_myobject_new',
+								'url'=>'/dav/myobject_page.php?action=create',
+								'langs'=>'dav@dav',	        // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
+								'position'=>1000+$r,
+								'enabled'=>'$conf->dav->enabled',  // Define condition to show or hide menu entry. Use '$conf->dav->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected.
+								'perms'=>'1',			                // Use 'perms'=>'$user->rights->dav->level1->level2' if you want your menu with a permission rules
+								'target'=>'',
+								'user'=>2);				                // 0=Menu for internal users, 1=external users, 2=both
+		END MODULEBUILDER LEFTMENU MYOBJECT */
+
+
+		// Exports
+		$r=1;
+
+		/* BEGIN MODULEBUILDER EXPORT MYOBJECT */
+		/*
+		$langs->load("dav@dav");
+		$this->export_code[$r]=$this->rights_class.'_'.$r;
+		$this->export_label[$r]='MyObjectLines';	// Translation key (used only if key ExportDataset_xxx_z not found)
+		$this->export_icon[$r]='myobject@dav';
+		$keyforclass = 'MyObject'; $keyforclassfile='/mymobule/class/myobject.class.php'; $keyforelement='myobject';
+		include DOL_DOCUMENT_ROOT.'/core/commonfieldsinexport.inc.php';
+		$keyforselect='myobject'; $keyforaliasextra='extra'; $keyforelement='myobject';
+		include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php';
+		//$this->export_dependencies_array[$r]=array('mysubobject'=>'ts.rowid', 't.myfield'=>array('t.myfield2','t.myfield3')); // To force to activate one or several fields if we select some fields that need same (like to select a unique key if we ask a field of a child to avoid the DISTINCT to discard them, or for computed field than need several other fields)
+		$this->export_sql_start[$r]='SELECT DISTINCT ';
+		$this->export_sql_end[$r]  =' FROM '.MAIN_DB_PREFIX.'myobject as t';
+		$this->export_sql_end[$r] .=' WHERE 1 = 1';
+		$this->export_sql_end[$r] .=' AND t.entity IN ('.getEntity('myobject').')';
+		$r++; */
+		/* END MODULEBUILDER EXPORT MYOBJECT */
+	}
+
+	/**
+	 *	Function called when module is enabled.
+	 *	The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database.
+	 *	It also creates data directories
+	 *
+     *	@param      string	$options    Options when enabling module ('', 'noboxes')
+	 *	@return     int             	1 if OK, 0 if KO
+	 */
+	public function init($options='')
+	{
+		//$this->_load_tables('/dav/sql/');
+
+		// Create extrafields
+		include_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
+		$extrafields = new ExtraFields($this->db);
+
+		//$result1=$extrafields->addExtraField('myattr1', "New Attr 1 label", 'boolean', 1,  3, 'thirdparty',   0, 0, '', '', 1, '', 0, 0, '', '', 'dav@dav', '$conf->dav->enabled');
+		//$result2=$extrafields->addExtraField('myattr2', "New Attr 2 label", 'varchar', 1, 10, 'project',      0, 0, '', '', 1, '', 0, 0, '', '', 'dav@dav', '$conf->dav->enabled');
+		//$result3=$extrafields->addExtraField('myattr3', "New Attr 3 label", 'varchar', 1, 10, 'bank_account', 0, 0, '', '', 1, '', 0, 0, '', '', 'dav@dav', '$conf->dav->enabled');
+		//$result4=$extrafields->addExtraField('myattr4', "New Attr 4 label", 'select',  1,  3, 'thirdparty',   0, 1, '', array('options'=>array('code1'=>'Val1','code2'=>'Val2','code3'=>'Val3')), 1 '', 0, 0, '', '', 'dav@dav', '$conf->dav->enabled');
+		//$result5=$extrafields->addExtraField('myattr5', "New Attr 5 label", 'text',    1, 10, 'user',         0, 0, '', '', 1, '', 0, 0, '', '', 'dav@dav', '$conf->dav->enabled');
+
+		$sql = array();
+
+		return $this->_init($sql, $options);
+	}
+
+	/**
+	 *	Function called when module is disabled.
+	 *	Remove from database constants, boxes and permissions from Dolibarr database.
+	 *	Data directories are not deleted
+	 *
+	 *	@param      string	$options    Options when enabling module ('', 'noboxes')
+	 *	@return     int             	1 if OK, 0 if KO
+	 */
+	public function remove($options = '')
+	{
+		$sql = array();
+
+		return $this->_remove($sql, $options);
+	}
+}

+ 14 - 14
htdocs/core/modules/modSyslog.class.php

@@ -85,20 +85,20 @@ class modSyslog extends DolibarrModules
 
 		// Cronjobs
 		$this->cronjobs = array(
-		    0 => array(
-                'label' => 'CompressSyslogs',
-                'jobtype' => 'method',
-                'class' => 'core/class/utils.class.php',
-                'objectname' => 'Utils',
-                'method' => 'compressSyslogs',
-                'parameters' => '',
-                'comment' => 'Compress and archive log files. Warning: batch must be run with same account than your web server to avoid to get log files with different owner than required by web server. Another solution is to set web server Operating System group as the group of directory documents and set GROUP permission "rws" on this directory so log files will always have the group and permissions of the web server Operating System group',
-                'frequency' => 1,
-                'unitfrequency' => 3600 * 24,
-                'priority' => 50,
-                'status' => 0,
-                'test' => true,
-            ),
+			0 => array(
+				'label' => 'CompressSyslogs',
+				'jobtype' => 'method',
+				'class' => 'core/class/utils.class.php',
+				'objectname' => 'Utils',
+				'method' => 'compressSyslogs',
+				'parameters' => '',
+				'comment' => 'Compress and archive log files. Warning: batch must be run with same account than your web server to avoid to get log files with different owner than required by web server. Another solution is to set web server Operating System group as the group of directory documents and set GROUP permission "rws" on this directory so log files will always have the group and permissions of the web server Operating System group',
+				'frequency' => 1,
+				'unitfrequency' => 3600 * 24,
+				'priority' => 50,
+				'status' => 0,
+				'test' => true
+			)
 		);
 	}
 }

+ 1 - 1
htdocs/core/modules/modTakePos.class.php

@@ -98,7 +98,7 @@ class modTakePos extends DolibarrModules
 
 		// Dependencies
 		$this->hidden = false;			// A condition to hide module
-		$this->depends = array('always'=>"modBanque", 'always'=>"modFacture", 'always'=>"modProduct", 'always'=>'modCategorie', 'FR'=>'modBlockedLog');			// List of module class names as string that must be enabled if this module is enabled
+		$this->depends = array('always1'=>"modBanque", 'always2'=>"modFacture", 'always3'=>"modProduct", 'always4'=>'modCategorie', 'FR1'=>'modBlockedLog');			// List of module class names as string that must be enabled if this module is enabled
 		$this->requiredby = array();	// List of module ids to disable if this one is disabled
 		$this->conflictwith = array();	// List of module class names as string this module is in conflict with
 		$this->langfiles = array("cashdesk");

+ 23 - 14
htdocs/core/modules/product/doc/doc_generic_product_odt.modules.php

@@ -1,7 +1,8 @@
 <?php
 /* Copyright (C) 2010-2012 	Laurent Destailleur <eldy@products.sourceforge.net>
  * Copyright (C) 2012		Juanjo Menent		<jmenent@2byte.es>
-*
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -358,16 +359,17 @@ class doc_generic_product_odt extends ModelePDFProduct
 					$odfHandler = new odf(
 						$srctemplatepath,
 						array(
-						'PATH_TO_TMP'	  => $conf->produit->dir_temp,
-						'ZIP_PROXY'		  => 'PclZipProxy',	// PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy.
-						'DELIMITER_LEFT'  => '{',
-						'DELIMITER_RIGHT' => '}'
+							'PATH_TO_TMP'	  => $conf->produit->dir_temp,
+							'ZIP_PROXY'		  => 'PclZipProxy',	// PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy.
+							'DELIMITER_LEFT'  => '{',
+							'DELIMITER_RIGHT' => '}'
 						)
 					);
 				}
-				catch(Exception $e)
+				catch (Exception $e)
 				{
 					$this->error=$e->getMessage();
+					dol_syslog($e->getMessage(), LOG_INFO);
 					return -1;
 				}
 				// After construction $odfHandler->contentXml contains content and
@@ -382,8 +384,9 @@ class doc_generic_product_odt extends ModelePDFProduct
 				try {
 					$odfHandler->setVars('free_text', $newfreetext, true, 'UTF-8');
 				}
-				catch(OdfException $e)
+				catch (OdfException $e)
 				{
+					dol_syslog($e->getMessage(), LOG_INFO);
 				}
 
 				// Define substitution array
@@ -418,8 +421,9 @@ class doc_generic_product_odt extends ModelePDFProduct
 							$odfHandler->setVars($key, $value, true, 'UTF-8');
 						}
 					}
-					catch(OdfException $e)
+					catch (OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 				// Replace tags of lines
@@ -440,11 +444,13 @@ class doc_generic_product_odt extends ModelePDFProduct
 								{
 									$listlines->setVars($key, $val, true, 'UTF-8');
 								}
-								catch(OdfException $e)
+								catch (OdfException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
-								catch(SegmentException $e)
+								catch (SegmentException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 							}
 							$listlines->merge();
@@ -452,7 +458,7 @@ class doc_generic_product_odt extends ModelePDFProduct
 					}
 					$odfHandler->mergeSegment($listlines);
 				}
-				catch(OdfException $e)
+				catch (OdfException $e)
 				{
 					$this->error=$e->getMessage();
 					dol_syslog($this->error, LOG_WARNING);
@@ -468,6 +474,7 @@ class doc_generic_product_odt extends ModelePDFProduct
 					}
 					catch(OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 
@@ -479,16 +486,18 @@ class doc_generic_product_odt extends ModelePDFProduct
 				if (!empty($conf->global->MAIN_ODT_AS_PDF)) {
 					try {
 						$odfHandler->exportAsAttachedPDF($file);
-					}catch (Exception $e){
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
+                        dol_syslog($e->getMessage(), LOG_INFO);
 						return -1;
 					}
 				}
 				else {
 					try {
-					$odfHandler->saveToDisk($file);
-					}catch (Exception $e){
+						$odfHandler->saveToDisk($file);
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
+                        dol_syslog($e->getMessage(), LOG_INFO);
 						return -1;
 					}
 				}

+ 140 - 126
htdocs/core/modules/project/doc/doc_generic_project_odt.modules.php

@@ -3,6 +3,7 @@
  * Copyright (C) 2012		Juanjo Menent		<jmenent@2byte.es>
  * Copyright (C) 2013		Florian Henry		<florian.henry@ope-concept.pro>
  * Copyright (C) 2016		Charlie Benke		<charlie@patas-monkey.com>
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -596,10 +597,9 @@ class doc_generic_project_odt extends ModelePDFProjects
 						'DELIMITER_RIGHT' => '}'
 						)
 					);
-				}
-				catch(Exception $e)
-				{
+				} catch (Exception $e) {
 					$this->error=$e->getMessage();
+					dol_syslog($e->getMessage(), LOG_INFO);
 					return -1;
 				}
 				// After construction $odfHandler->contentXml contains content and
@@ -641,8 +641,9 @@ class doc_generic_project_odt extends ModelePDFProjects
 							$odfHandler->setVars($key, $value, true, 'UTF-8');
 						}
 					}
-					catch(OdfException $e)
+					catch (OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 
@@ -672,9 +673,11 @@ class doc_generic_project_odt extends ModelePDFProjects
 							}
 							catch(OdfException $e)
 							{
+								dol_syslog($e->getMessage(), LOG_INFO);
 							}
 							catch(SegmentException $e)
 							{
+								dol_syslog($e->getMessage(), LOG_INFO);
 							}
 						}
 
@@ -721,9 +724,11 @@ class doc_generic_project_odt extends ModelePDFProjects
 									}
 									catch(OdfException $e)
 									{
+										dol_syslog($e->getMessage(), LOG_INFO);
 									}
 									catch(SegmentException $e)
 									{
+										dol_syslog($e->getMessage(), LOG_INFO);
 									}
 								}
 								$listlinestaskres->merge();
@@ -768,9 +773,11 @@ class doc_generic_project_odt extends ModelePDFProjects
 									}
 									catch(OdfException $e)
 									{
+										dol_syslog($e->getMessage(), LOG_INFO);
 									}
 									catch(SegmentException $e)
 									{
+										dol_syslog($e->getMessage(), LOG_INFO);
 									}
 								}
 								$listlinestasktime->merge();
@@ -806,9 +813,11 @@ class doc_generic_project_odt extends ModelePDFProjects
 									}
 									catch(OdfException $e)
 									{
+										dol_syslog($e->getMessage(), LOG_INFO);
 									}
 									catch(SegmentException $e)
 									{
+										dol_syslog($e->getMessage(), LOG_INFO);
 									}
 								}
 								$listlinestasktime->merge();
@@ -835,11 +844,13 @@ class doc_generic_project_odt extends ModelePDFProjects
 								{
 									$listtasksfiles->setVars($key, $val, true, 'UTF-8');
 								}
-								catch(OdfException $e)
+								catch (OdfException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
-								catch(SegmentException $e)
+								catch (SegmentException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 							}
 							$listtasksfiles->merge();
@@ -881,9 +892,11 @@ class doc_generic_project_odt extends ModelePDFProjects
 							}
 							catch(OdfException $e)
 							{
+								dol_syslog($e->getMessage(), LOG_INFO);
 							}
 							catch(SegmentException $e)
 							{
+								dol_syslog($e->getMessage(), LOG_INFO);
 							}
 						}
 						$listlines->merge();
@@ -938,9 +951,11 @@ class doc_generic_project_odt extends ModelePDFProjects
 								}
 								catch(OdfException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 								catch(SegmentException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 							}
 							$listlines->merge();
@@ -958,113 +973,113 @@ class doc_generic_project_odt extends ModelePDFProjects
 				//List of referent
 
 				$listofreferent = array(
-						'propal' => array(
-								'title' => "ListProposalsAssociatedProject",
-								'class' => 'Propal',
-								'table' => 'propal',
-								'test' => $conf->propal->enabled && $user->rights->propale->lire
-						),
-						'order' => array(
-								'title' => "ListOrdersAssociatedProject",
-								'class' => 'Commande',
-								'table' => 'commande',
-								'test' => $conf->commande->enabled && $user->rights->commande->lire
-						),
-						'invoice' => array(
-								'title' => "ListInvoicesAssociatedProject",
-								'class' => 'Facture',
-								'table' => 'facture',
-								'test' => $conf->facture->enabled && $user->rights->facture->lire
-						),
-						'invoice_predefined' => array(
-								'title' => "ListPredefinedInvoicesAssociatedProject",
-								'class' => 'FactureRec',
-								'table' => 'facture_rec',
-								'test' => $conf->facture->enabled && $user->rights->facture->lire
-						),
-						'proposal_supplier' => array(
-								'title' => "ListSupplierProposalsAssociatedProject",
-								'class' => 'SupplierProposal',
-								'table' => 'supplier_proposal',
-								'test' => $conf->supplier_proposal->enabled && $user->rights->supplier_proposal->lire
-						),
-						'order_supplier' => array(
-								'title' => "ListSupplierOrdersAssociatedProject",
-								'table' => 'commande_fournisseur',
-								'class' => 'CommandeFournisseur',
-								'test' => $conf->fournisseur->enabled && $user->rights->fournisseur->commande->lire
-						),
-						'invoice_supplier' => array(
-								'title' => "ListSupplierInvoicesAssociatedProject",
-								'table' => 'facture_fourn',
-								'class' => 'FactureFournisseur',
-								'test' => $conf->fournisseur->enabled && $user->rights->fournisseur->facture->lire
-						),
-						'contract' => array(
-								'title' => "ListContractAssociatedProject",
-								'class' => 'Contrat',
-								'table' => 'contrat',
-								'test' => $conf->contrat->enabled && $user->rights->contrat->lire
-						),
-						'intervention' => array(
-								'title' => "ListFichinterAssociatedProject",
-								'class' => 'Fichinter',
-								'table' => 'fichinter',
-								'disableamount' => 1,
-								'test' => $conf->ficheinter->enabled && $user->rights->ficheinter->lire
-						),
-						'shipping' => array(
-								'title' => "ListShippingAssociatedProject",
-								'class' => 'Expedition',
-								'table' => 'expedition',
-								'disableamount' => 1,
-								'test' => $conf->expedition->enabled && $user->rights->expedition->lire
-						),
-						'trip' => array(
-								'title' => "ListTripAssociatedProject",
-								'class' => 'Deplacement',
-								'table' => 'deplacement',
-								'disableamount' => 1,
-								'test' => $conf->deplacement->enabled && $user->rights->deplacement->lire
-						),
-						'expensereport' => array(
-								'title' => "ListExpenseReportsAssociatedProject",
-								'class' => 'ExpenseReportLine',
-								'table' => 'expensereport_det',
-								'test' => $conf->expensereport->enabled && $user->rights->expensereport->lire
-						),
-						'donation' => array(
-								'title' => "ListDonationsAssociatedProject",
-								'class' => 'Don',
-								'table' => 'don',
-								'test' => $conf->don->enabled && $user->rights->don->lire
-						),
-						'loan' => array(
-								'title' => "ListLoanAssociatedProject",
-								'class' => 'Loan',
-								'table' => 'loan',
-								'test' => $conf->loan->enabled && $user->rights->loan->read
-						),
-						'chargesociales' => array(
-								'title' => "ListSocialContributionAssociatedProject",
-								'class' => 'ChargeSociales',
-								'table' => 'chargesociales',
-								'urlnew' => DOL_URL_ROOT . '/compta/sociales/card.php?action=create&projectid=' . $id,
-								'test' => $conf->tax->enabled && $user->rights->tax->charges->lire
-						),
-						'stock_mouvement' => array(
-								'title' => "ListMouvementStockProject",
-								'class' => 'MouvementStock',
-								'table' => 'stock_mouvement',
-								'test' => ($conf->stock->enabled && $user->rights->stock->mouvement->lire && ! empty($conf->global->STOCK_MOVEMENT_INTO_PROJECT_OVERVIEW))
-						),
-						'agenda' => array(
-								'title' => "ListActionsAssociatedProject",
-								'class' => 'ActionComm',
-								'table' => 'actioncomm',
-								'disableamount' => 1,
-								'test' => $conf->agenda->enabled && $user->rights->agenda->allactions->lire
-						)
+					'propal' => array(
+						'title' => "ListProposalsAssociatedProject",
+						'class' => 'Propal',
+						'table' => 'propal',
+						'test' => $conf->propal->enabled && $user->rights->propale->lire
+					),
+					'order' => array(
+						'title' => "ListOrdersAssociatedProject",
+						'class' => 'Commande',
+						'table' => 'commande',
+						'test' => $conf->commande->enabled && $user->rights->commande->lire
+					),
+					'invoice' => array(
+						'title' => "ListInvoicesAssociatedProject",
+						'class' => 'Facture',
+						'table' => 'facture',
+						'test' => $conf->facture->enabled && $user->rights->facture->lire
+					),
+					'invoice_predefined' => array(
+						'title' => "ListPredefinedInvoicesAssociatedProject",
+						'class' => 'FactureRec',
+						'table' => 'facture_rec',
+						'test' => $conf->facture->enabled && $user->rights->facture->lire
+					),
+					'proposal_supplier' => array(
+						'title' => "ListSupplierProposalsAssociatedProject",
+						'class' => 'SupplierProposal',
+						'table' => 'supplier_proposal',
+						'test' => $conf->supplier_proposal->enabled && $user->rights->supplier_proposal->lire
+					),
+					'order_supplier' => array(
+						'title' => "ListSupplierOrdersAssociatedProject",
+						'table' => 'commande_fournisseur',
+						'class' => 'CommandeFournisseur',
+						'test' => $conf->fournisseur->enabled && $user->rights->fournisseur->commande->lire
+					),
+					'invoice_supplier' => array(
+						'title' => "ListSupplierInvoicesAssociatedProject",
+						'table' => 'facture_fourn',
+						'class' => 'FactureFournisseur',
+						'test' => $conf->fournisseur->enabled && $user->rights->fournisseur->facture->lire
+					),
+					'contract' => array(
+						'title' => "ListContractAssociatedProject",
+						'class' => 'Contrat',
+						'table' => 'contrat',
+						'test' => $conf->contrat->enabled && $user->rights->contrat->lire
+					),
+					'intervention' => array(
+						'title' => "ListFichinterAssociatedProject",
+						'class' => 'Fichinter',
+						'table' => 'fichinter',
+						'disableamount' => 1,
+						'test' => $conf->ficheinter->enabled && $user->rights->ficheinter->lire
+					),
+					'shipping' => array(
+						'title' => "ListShippingAssociatedProject",
+						'class' => 'Expedition',
+						'table' => 'expedition',
+						'disableamount' => 1,
+						'test' => $conf->expedition->enabled && $user->rights->expedition->lire
+					),
+					'trip' => array(
+						'title' => "ListTripAssociatedProject",
+						'class' => 'Deplacement',
+						'table' => 'deplacement',
+						'disableamount' => 1,
+						'test' => $conf->deplacement->enabled && $user->rights->deplacement->lire
+					),
+					'expensereport' => array(
+						'title' => "ListExpenseReportsAssociatedProject",
+						'class' => 'ExpenseReportLine',
+						'table' => 'expensereport_det',
+						'test' => $conf->expensereport->enabled && $user->rights->expensereport->lire
+					),
+					'donation' => array(
+						'title' => "ListDonationsAssociatedProject",
+						'class' => 'Don',
+						'table' => 'don',
+						'test' => $conf->don->enabled && $user->rights->don->lire
+					),
+					'loan' => array(
+						'title' => "ListLoanAssociatedProject",
+						'class' => 'Loan',
+						'table' => 'loan',
+						'test' => $conf->loan->enabled && $user->rights->loan->read
+					),
+					'chargesociales' => array(
+						'title' => "ListSocialContributionAssociatedProject",
+						'class' => 'ChargeSociales',
+						'table' => 'chargesociales',
+						'urlnew' => DOL_URL_ROOT . '/compta/sociales/card.php?action=create&projectid=' . $id,
+						'test' => $conf->tax->enabled && $user->rights->tax->charges->lire
+					),
+					'stock_mouvement' => array(
+						'title' => "ListMouvementStockProject",
+						'class' => 'MouvementStock',
+						'table' => 'stock_mouvement',
+						'test' => ($conf->stock->enabled && $user->rights->stock->mouvement->lire && ! empty($conf->global->STOCK_MOVEMENT_INTO_PROJECT_OVERVIEW))
+					),
+					'agenda' => array(
+						'title' => "ListActionsAssociatedProject",
+						'class' => 'ActionComm',
+						'table' => 'actioncomm',
+						'disableamount' => 1,
+						'test' => $conf->agenda->enabled && $user->rights->agenda->allactions->lire
+					),
 				);
 
 				//Insert reference
@@ -1116,11 +1131,11 @@ class doc_generic_project_odt extends ModelePDFProjects
 										if (!empty($element->total_ht)) {
 											$ref_array['amountht']=$element->total_ht;
 											$ref_array['amountttc']=$element->total_ttc;
-										}else {
+										} else {
 											$ref_array['amountht']=0;
 											$ref_array['amountttc']=0;
 										}
-									}else {
+									} else {
 										$ref_array['amountht']='';
 										$ref_array['amountttc']='';
 									}
@@ -1137,9 +1152,11 @@ class doc_generic_project_odt extends ModelePDFProjects
 										}
 										catch(OdfException $e)
 										{
+											dol_syslog($e->getMessage(), LOG_INFO);
 										}
 										catch(SegmentException $e)
 										{
+											dol_syslog($e->getMessage(), LOG_INFO);
 										}
 									}
 									$listlines->merge();
@@ -1148,9 +1165,7 @@ class doc_generic_project_odt extends ModelePDFProjects
 						}
 						$odfHandler->mergeSegment($listlines);
 					}
-				}
-				catch(OdfException $e)
-				{
+				} catch(OdfException $e) {
 					$this->error=$e->getMessage();
 					dol_syslog($this->error, LOG_WARNING);
 					return -1;
@@ -1162,9 +1177,8 @@ class doc_generic_project_odt extends ModelePDFProjects
 				{
 					try {
 						$odfHandler->setVars($key, $value, true, 'UTF-8');
-					}
-					catch(OdfException $e)
-					{
+					} catch (OdfException $e) {
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 
@@ -1177,16 +1191,16 @@ class doc_generic_project_odt extends ModelePDFProjects
 				if (!empty($conf->global->MAIN_ODT_AS_PDF)) {
 					try {
 						$odfHandler->exportAsAttachedPDF($file);
-					}catch (Exception $e){
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
 						return -1;
 					}
-				}
-				else {
+				} else {
 					try {
-					$odfHandler->saveToDisk($file);
-					}catch (Exception $e){
+						$odfHandler->saveToDisk($file);
+					} catch (Exception $e){
 						$this->error=$e->getMessage();
+                        dol_syslog($e->getMessage(), LOG_INFO);
 						return -1;
 					}
 				}

+ 25 - 20
htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php

@@ -3,6 +3,7 @@
  * Copyright (C) 2012		Juanjo Menent		<jmenent@2byte.es>
  * Copyright (C) 2013		Florian Henry		<florian.henry@ope-concept.pro>
  * Copyright (C) 2016		Charlie Benke		<charlie@patas-monkey.com>
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -560,9 +561,8 @@ class doc_generic_task_odt extends ModelePDFTask
 						{
 							$odfHandler->setVars($key, $value, true, 'UTF-8');
 						}
-					}
-					catch(OdfException $e)
-					{
+					} catch (OdfException $e) {
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 
@@ -577,15 +577,12 @@ class doc_generic_task_odt extends ModelePDFTask
 					complete_substitutions_array($tmparray, $outputlangs, $object);
 					foreach($tmparray as $key => $val)
 					{
-						try
-						{
+						try {
 							$odfHandler->setVars($key, $val, true, 'UTF-8');
-						}
-						catch(OdfException $e)
-						{
-						}
-						catch(SegmentException $e)
-						{
+						} catch (OdfException $e) {
+							dol_syslog($e->getMessage(), LOG_INFO);
+						} catch(SegmentException $e) {
+							dol_syslog($e->getMessage(), LOG_INFO);
 						}
 					}
 
@@ -623,15 +620,13 @@ class doc_generic_task_odt extends ModelePDFTask
 
 							foreach($tmparray as $key => $val)
 							{
-								try
-								{
+								try {
 									$listlinestaskres->setVars($key, $val, true, 'UTF-8');
+								} catch (OdfException $e) {
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
-								catch(OdfException $e)
-								{
-								}
-								catch(SegmentException $e)
-								{
+								catch (SegmentException $e) {
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 							}
 							$listlinestaskres->merge();
@@ -677,9 +672,11 @@ class doc_generic_task_odt extends ModelePDFTask
 								}
 								catch(OdfException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 								catch(SegmentException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 							}
 							$listlinestasktime->merge();
@@ -710,9 +707,11 @@ class doc_generic_task_odt extends ModelePDFTask
 							}
 							catch(OdfException $e)
 							{
+								dol_syslog($e->getMessage(), LOG_INFO);
 							}
 							catch(SegmentException $e)
 							{
+								dol_syslog($e->getMessage(), LOG_INFO);
 							}
 						}
 						$listtasksfiles->merge();
@@ -752,9 +751,11 @@ class doc_generic_task_odt extends ModelePDFTask
 							}
 							catch(OdfException $e)
 							{
+								dol_syslog($e->getMessage(), LOG_INFO);
 							}
 							catch(SegmentException $e)
 							{
+								dol_syslog($e->getMessage(), LOG_INFO);
 							}
 						}
 						$listlines->merge();
@@ -810,9 +811,11 @@ class doc_generic_task_odt extends ModelePDFTask
 								}
 								catch(OdfException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 								catch(SegmentException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 							}
 							$listlines->merge();
@@ -837,16 +840,18 @@ class doc_generic_task_odt extends ModelePDFTask
 				if (!empty($conf->global->MAIN_ODT_AS_PDF)) {
 					try {
 						$odfHandler->exportAsAttachedPDF($file);
-					}catch (Exception $e){
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
+                        dol_syslog($e->getMessage(), LOG_INFO);
 						return -1;
 					}
 				}
 				else {
 					try {
 						$odfHandler->saveToDisk($file);
-					}catch (Exception $e){
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
+                        dol_syslog($e->getMessage(), LOG_INFO);
 						return -1;
 					}
 				}

+ 14 - 5
htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php

@@ -2,7 +2,8 @@
 /* Copyright (C) 2010-2012 	Laurent Destailleur <eldy@users.sourceforge.net>
  * Copyright (C) 2012		Juanjo Menent		<jmenent@2byte.es>
  * Copyright (C) 2016		Charlie Benke		<charlie@patas-monkey.com>
-*
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -381,6 +382,7 @@ class doc_generic_proposal_odt extends ModelePDFPropales
 				catch(Exception $e)
 				{
 					$this->error=$e->getMessage();
+					dol_syslog($e->getMessage(), LOG_INFO);
 					return -1;
 				}
 				// After construction $odfHandler->contentXml contains content and
@@ -395,8 +397,9 @@ class doc_generic_proposal_odt extends ModelePDFPropales
 				try {
 					$odfHandler->setVars('free_text', $newfreetext, true, 'UTF-8');
 				}
-				catch(OdfException $e)
+				catch (OdfException $e)
 				{
+					dol_syslog($e->getMessage(), LOG_INFO);
 				}
 
 				// Define substitution array
@@ -433,6 +436,7 @@ class doc_generic_proposal_odt extends ModelePDFPropales
 					}
 					catch(OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 				// Replace tags of lines
@@ -465,9 +469,11 @@ class doc_generic_proposal_odt extends ModelePDFPropales
 								}
 								catch(OdfException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 								catch(SegmentException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 							}
 							$listlines->merge();
@@ -489,8 +495,9 @@ class doc_generic_proposal_odt extends ModelePDFPropales
 					try {
 						$odfHandler->setVars($key, $value, true, 'UTF-8');
 					}
-					catch(OdfException $e)
+					catch (OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 
@@ -502,16 +509,18 @@ class doc_generic_proposal_odt extends ModelePDFPropales
 				if (!empty($conf->global->MAIN_ODT_AS_PDF)) {
 					try {
 						$odfHandler->exportAsAttachedPDF($file);
-					}catch (Exception $e){
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
+                        dol_syslog($e->getMessage(), LOG_INFO);
 						return -1;
 					}
 				}
 				else {
 					try {
 					$odfHandler->saveToDisk($file);
-					}catch (Exception $e){
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
+                        dol_syslog($e->getMessage(), LOG_INFO);
 						return -1;
 					}
 				}

+ 12 - 3
htdocs/core/modules/societe/doc/doc_generic_odt.modules.php

@@ -1,6 +1,8 @@
 <?php
 /* Copyright (C) 2010-2011 Laurent Destailleur <ely@users.sourceforge.net>
  * Copyright (C) 2016		Charlie Benke		<charlie@patas-monkey.com>
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -276,6 +278,7 @@ class doc_generic_odt extends ModeleThirdPartyDoc
 				catch(Exception $e)
 				{
 					$this->error=$e->getMessage();
+					dol_syslog($e->getMessage(), LOG_INFO);
 					return -1;
 				}
 				//print $odfHandler->__toString()."\n";
@@ -323,9 +326,11 @@ class doc_generic_odt extends ModeleThirdPartyDoc
                 				}
                 				catch(OdfException $e)
                 				{
+									dol_syslog($e->getMessage(), LOG_INFO);
                 				}
                 				catch(SegmentException $e)
                 				{
+									dol_syslog($e->getMessage(), LOG_INFO);
                 				}
                 			}
                 			$listlines->merge();
@@ -367,9 +372,10 @@ class doc_generic_odt extends ModeleThirdPartyDoc
 							$odfHandler->setVars($key, $value, true, 'UTF-8');
 						}
 					}
-					catch(OdfException $e)
+					catch (OdfException $e)
 					{
 						// setVars failed, probably because key not found
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 
@@ -380,8 +386,9 @@ class doc_generic_odt extends ModeleThirdPartyDoc
 					try {
 						$odfHandler->setVars($key, $value, true, 'UTF-8');
 					}
-					catch(OdfException $e)
+					catch (OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 
@@ -393,8 +400,9 @@ class doc_generic_odt extends ModeleThirdPartyDoc
 				if (!empty($conf->global->MAIN_ODT_AS_PDF)) {
 					try {
 						$odfHandler->exportAsAttachedPDF($file);
-					}catch (Exception $e){
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
+                        dol_syslog($e->getMessage(), LOG_INFO);
 						return -1;
 					}
 				}
@@ -413,6 +421,7 @@ class doc_generic_odt extends ModeleThirdPartyDoc
 					   $odfHandler->saveToDisk($file);
 					}catch (Exception $e){
 						$this->error=$e->getMessage();
+                        dol_syslog($e->getMessage(), LOG_INFO);
 						return -1;
 					}
 				}

+ 13 - 4
htdocs/core/modules/stock/doc/doc_generic_stock_odt.modules.php

@@ -1,6 +1,7 @@
 <?php
 /* Copyright (C) 2010-2012 	Laurent Destailleur <eldy@stocks.sourceforge.net>
  * Copyright (C) 2012		Juanjo Menent		<jmenent@2byte.es>
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -368,6 +369,7 @@ class doc_generic_stock_odt extends ModelePDFStock
 				catch(Exception $e)
 				{
 					$this->error=$e->getMessage();
+					dol_syslog($e->getMessage(), LOG_INFO);
 					return -1;
 				}
 				// After construction $odfHandler->contentXml contains content and
@@ -382,8 +384,9 @@ class doc_generic_stock_odt extends ModelePDFStock
 				try {
 					$odfHandler->setVars('free_text', $newfreetext, true, 'UTF-8');
 				}
-				catch(OdfException $e)
+				catch (OdfException $e)
 				{
+					dol_syslog($e->getMessage(), LOG_INFO);
 				}
 
 				// Define substitution array
@@ -418,8 +421,9 @@ class doc_generic_stock_odt extends ModelePDFStock
 							$odfHandler->setVars($key, $value, true, 'UTF-8');
 						}
 					}
-					catch(OdfException $e)
+					catch (OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 				// Replace tags of lines
@@ -442,9 +446,11 @@ class doc_generic_stock_odt extends ModelePDFStock
 								}
 								catch(OdfException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 								catch(SegmentException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 							}
 							$listlines->merge();
@@ -468,6 +474,7 @@ class doc_generic_stock_odt extends ModelePDFStock
 					}
 					catch(OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 
@@ -479,16 +486,18 @@ class doc_generic_stock_odt extends ModelePDFStock
 				if (!empty($conf->global->MAIN_ODT_AS_PDF)) {
 					try {
 						$odfHandler->exportAsAttachedPDF($file);
-					}catch (Exception $e){
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
+                        dol_syslog($e->getMessage(), LOG_INFO);
 						return -1;
 					}
 				}
 				else {
 					try {
 					$odfHandler->saveToDisk($file);
-					}catch (Exception $e){
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
+                        dol_syslog($e->getMessage(), LOG_INFO);
 						return -1;
 					}
 				}

+ 18 - 9
htdocs/core/modules/supplier_proposal/doc/doc_generic_supplier_proposal_odt.modules.php

@@ -2,6 +2,7 @@
 /* Copyright (C) 2010-2012 	Laurent Destailleur <eldy@users.sourceforge.net>
  * Copyright (C) 2012		Juanjo Menent		<jmenent@2byte.es>
  * Copyright (C) 2016		Charlie Benke		<charlie@patas-monkey.com>
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -367,16 +368,17 @@ class doc_generic_supplier_proposal_odt extends ModelePDFSupplierProposal
 					$odfHandler = new odf(
 						$srctemplatepath,
 						array(
-						'PATH_TO_TMP'	  => $conf->supplier_proposal->dir_temp,
-						'ZIP_PROXY'		  => 'PclZipProxy',	// PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy.
-						'DELIMITER_LEFT'  => '{',
-						'DELIMITER_RIGHT' => '}'
+							'PATH_TO_TMP'	  => $conf->supplier_proposal->dir_temp,
+							'ZIP_PROXY'		  => 'PclZipProxy',	// PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy.
+							'DELIMITER_LEFT'  => '{',
+							'DELIMITER_RIGHT' => '}'
 						)
 					);
 				}
-				catch(Exception $e)
+				catch (Exception $e)
 				{
 					$this->error=$e->getMessage();
+					dol_syslog($e->getMessage(), LOG_INFO);
 					return -1;
 				}
 				// After construction $odfHandler->contentXml contains content and
@@ -390,8 +392,9 @@ class doc_generic_supplier_proposal_odt extends ModelePDFSupplierProposal
 				try {
 					$odfHandler->setVars('free_text', $newfreetext, true, 'UTF-8');
 				}
-				catch(OdfException $e)
+				catch (OdfException $e)
 				{
+					dol_syslog($e->getMessage(), LOG_INFO);
 				}
 
 				// Define substitution array
@@ -424,6 +427,7 @@ class doc_generic_supplier_proposal_odt extends ModelePDFSupplierProposal
 					}
 					catch(OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 				// Replace tags of lines
@@ -456,9 +460,11 @@ class doc_generic_supplier_proposal_odt extends ModelePDFSupplierProposal
 								}
 								catch(OdfException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 								catch(SegmentException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_INFO);
 								}
 							}
 							$listlines->merge();
@@ -482,6 +488,7 @@ class doc_generic_supplier_proposal_odt extends ModelePDFSupplierProposal
 					}
 					catch(OdfException $e)
 					{
+                        dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
 
@@ -493,16 +500,18 @@ class doc_generic_supplier_proposal_odt extends ModelePDFSupplierProposal
 				if (!empty($conf->global->MAIN_ODT_AS_PDF)) {
 					try {
 						$odfHandler->exportAsAttachedPDF($file);
-					}catch (Exception $e){
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
+                        dol_syslog($e->getMessage(), LOG_INFO);
 						return -1;
 					}
 				}
 				else {
 					try {
-					$odfHandler->saveToDisk($file);
-					}catch (Exception $e){
+						$odfHandler->saveToDisk($file);
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
+                        dol_syslog($e->getMessage(), LOG_INFO);
 						return -1;
 					}
 				}

+ 14 - 8
htdocs/core/modules/user/doc/doc_generic_user_odt.modules.php

@@ -1,6 +1,7 @@
 <?php
 /* Copyright (C) 2010-2012 	Laurent Destailleur <eldy@users.sourceforge.net>
  * Copyright (C) 2012		Juanjo Menent		<jmenent@2byte.es>
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -333,16 +334,17 @@ class doc_generic_user_odt extends ModelePDFUser
 					$odfHandler = new odf(
 						$srctemplatepath,
 						array(
-						'PATH_TO_TMP'	  => $conf->user->dir_temp,
-						'ZIP_PROXY'		  => 'PclZipProxy',	// PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy.
-						'DELIMITER_LEFT'  => '{',
-						'DELIMITER_RIGHT' => '}'
+							'PATH_TO_TMP'	  => $conf->user->dir_temp,
+							'ZIP_PROXY'		  => 'PclZipProxy',	// PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy.
+							'DELIMITER_LEFT'  => '{',
+							'DELIMITER_RIGHT' => '}'
 						)
 					);
 				}
 				catch(Exception $e)
 				{
 					$this->error=$e->getMessage();
+					dol_syslog($e->getMessage(), LOG_WARNING);
 					return -1;
 				}
 
@@ -377,6 +379,7 @@ class doc_generic_user_odt extends ModelePDFUser
 					}
 					catch(OdfException $e)
 					{
+						dol_syslog($e->getMessage(), LOG_WARNING);
 					}
 				}
 
@@ -387,8 +390,9 @@ class doc_generic_user_odt extends ModelePDFUser
 					try {
 						$odfHandler->setVars($key, $value, true, 'UTF-8');
 					}
-					catch(OdfException $e)
+					catch (OdfException $e)
 					{
+						dol_syslog($e->getMessage(), LOG_WARNING);
 					}
 				}
 
@@ -400,16 +404,18 @@ class doc_generic_user_odt extends ModelePDFUser
 				if (!empty($conf->global->MAIN_ODT_AS_PDF)) {
 					try {
 						$odfHandler->exportAsAttachedPDF($file);
-					}catch (Exception $e){
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
+						dol_syslog($e->getMessage(), LOG_WARNING);
 						return -1;
 					}
 				}
 				else {
 					try {
-					$odfHandler->saveToDisk($file);
-					}catch (Exception $e){
+						$odfHandler->saveToDisk($file);
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
+						dol_syslog($e->getMessage(), LOG_WARNING);
 						return -1;
 					}
 				}

+ 28 - 21
htdocs/core/modules/usergroup/doc/doc_generic_usergroup_odt.modules.php

@@ -1,6 +1,7 @@
 <?php
 /* Copyright (C) 2010-2012 	Laurent Destailleur <eldy@users.sourceforge.net>
  * Copyright (C) 2012		Juanjo Menent		<jmenent@2byte.es>
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -355,16 +356,15 @@ class doc_generic_usergroup_odt extends ModelePDFUserGroup
 					$odfHandler = new odf(
 						$srctemplatepath,
 						array(
-						'PATH_TO_TMP'	  => $conf->user->dir_temp,
-						'ZIP_PROXY'		  => 'PclZipProxy',	// PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy.
-						'DELIMITER_LEFT'  => '{',
-						'DELIMITER_RIGHT' => '}'
+							'PATH_TO_TMP'	  => $conf->user->dir_temp,
+							'ZIP_PROXY'		  => 'PclZipProxy',	// PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy.
+							'DELIMITER_LEFT'  => '{',
+							'DELIMITER_RIGHT' => '}'
 						)
 					);
-				}
-				catch(Exception $e)
-				{
+				} catch (Exception $e) {
 					$this->error=$e->getMessage();
+					dol_syslog($e->getMessage(), LOG_WARNING);
 					return -1;
 				}
 				// After construction $odfHandler->contentXml contains content and
@@ -378,8 +378,9 @@ class doc_generic_usergroup_odt extends ModelePDFUserGroup
 				try {
 					$odfHandler->setVars('free_text', $newfreetext, true, 'UTF-8');
 				}
-				catch(OdfException $e)
+				catch (OdfException $e)
 				{
+					dol_syslog($e->getMessage(), LOG_WARNING);
 				}
 
 				// Make substitutions into odt
@@ -414,8 +415,9 @@ class doc_generic_usergroup_odt extends ModelePDFUserGroup
 							$odfHandler->setVars($key, $value, true, 'UTF-8');
 						}
 					}
-					catch(OdfException $e)
+					catch (OdfException $e)
 					{
+						dol_syslog($e->getMessage(), LOG_WARNING);
 					}
 				}
 				// Replace tags of lines
@@ -425,7 +427,7 @@ class doc_generic_usergroup_odt extends ModelePDFUserGroup
 					try {
 						$listlines = $odfHandler->setSegment('lines');
 					}
-					catch(OdfException $e)
+					catch (OdfException $e)
 					{
 						// We may arrive here if tags for lines not present into template
 						$foundtagforlines = 0;
@@ -446,15 +448,17 @@ class doc_generic_usergroup_odt extends ModelePDFUserGroup
 							{
 								try
 								{
-									if(!is_array($val)) {
+									if (!is_array($val)) {
 										$listlines->setVars($key, $val, true, 'UTF-8');
 									}
 								}
-								catch(OdfException $e)
+								catch (OdfException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_WARNING);
 								}
-								catch(SegmentException $e)
+								catch (SegmentException $e)
 								{
+									dol_syslog($e->getMessage(), LOG_WARNING);
 								}
 							}
 							$listlines->merge();
@@ -471,39 +475,42 @@ class doc_generic_usergroup_odt extends ModelePDFUserGroup
 
 				// Replace labels translated
 				$tmparray=$outputlangs->get_translations_for_substitutions();
-				foreach($tmparray as $key=>$value)
+				foreach($tmparray as $key => $value)
 				{
 					try {
 						$odfHandler->setVars($key, $value, true, 'UTF-8');
 					}
-					catch(OdfException $e)
+					catch (OdfException $e)
 					{
+						dol_syslog($e->getMessage(), LOG_WARNING);
 					}
 				}
 
 				// Call the beforeODTSave hook
-				$parameters=array('odfHandler'=>&$odfHandler,'file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs);
-				$reshook=$hookmanager->executeHooks('beforeODTSave',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
+				$parameters=array('odfHandler'=>&$odfHandler, 'file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
+				$reshook=$hookmanager->executeHooks('beforeODTSave', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
 
 				// Write new file
 				if (!empty($conf->global->MAIN_ODT_AS_PDF)) {
 					try {
 						$odfHandler->exportAsAttachedPDF($file);
-					}catch (Exception $e){
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
+						dol_syslog($e->getMessage(), LOG_WARNING);
 						return -1;
 					}
 				}
 				else {
 					try {
-					$odfHandler->saveToDisk($file);
-					}catch (Exception $e){
+						$odfHandler->saveToDisk($file);
+					} catch (Exception $e) {
 						$this->error=$e->getMessage();
+						dol_syslog($e->getMessage(), LOG_WARNING);
 						return -1;
 					}
 				}
 
-				$reshook=$hookmanager->executeHooks('afterODTCreation',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
+				$reshook=$hookmanager->executeHooks('afterODTCreation', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
 
 				if (! empty($conf->global->MAIN_UMASK))
 					@chmod($file, octdec($conf->global->MAIN_UMASK));

+ 1 - 1
htdocs/core/tpl/ajax/objectlinked_lineimport.tpl.php

@@ -68,7 +68,7 @@ $(document).ready(function(){
 	            modal: true,
 	            height: windowHeight,
 	            width: windowWidth,
-	            title: "<?php echo $langs->trans('LinesToImport'); ?>",
+	            title: "<?php echo $langs->transnoentities('LinesToImport'); ?>",
 	            buttons: {
 	                    "<?php echo $langs->trans('Import'); ?>": function() {
 	                      	$( this ).dialog( "close" );

+ 6 - 5
htdocs/core/tpl/massactions_pre.tpl.php

@@ -41,11 +41,12 @@ if ($massaction == 'presend')
 {
 	$langs->load("mails");
 
+	$listofselectedid = array();
+	$listofselectedthirdparties = array();
+	$listofselectedref = array();
+	
 	if (! GETPOST('cancel', 'alpha'))
 	{
-		$listofselectedid = array();
-		$listofselectedthirdparties = array();
-		$listofselectedref = array();
 		foreach ($arrayofselected as $toselectid)
 		{
 			$result = $objecttmp->fetch($toselectid);
@@ -110,8 +111,8 @@ if ($massaction == 'presend')
 	} else {
 		$formmail->withtoreadonly = 1;
 	}
-
-	$formmail->withoptiononeemailperrecipient = empty($liste)?0:((GETPOST('oneemailperrecipient')=='on')?1:-1);
+	
+	$formmail->withoptiononeemailperrecipient = (count($listofselectedref) == 1 || empty($liste))? 0 : ((GETPOST('oneemailperrecipient')=='on')?1:-1);
 	$formmail->withto = empty($liste)?(GETPOST('sendto','alpha')?GETPOST('sendto','alpha'):array()):$liste;
 	$formmail->withtofree = empty($liste)?1:0;
 	$formmail->withtocc = 1;

+ 1 - 0
htdocs/emailcollector/index.html

@@ -0,0 +1 @@
+

+ 4 - 4
htdocs/expensereport/class/expensereport.class.php

@@ -4,6 +4,7 @@
  * Copyright (C) 2015 Alexandre Spangaro  <aspangaro@zendsi.com>
  * Copyright (C) 2016 Ferran Marcet       <fmarcet@2byte.es>
  * Copyright (C) 2018 Nicolas ZABOURI     <info@inovea-conseil.com>
+ * Copyright (c) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -1512,7 +1513,7 @@ class ExpenseReport extends CommonObject
 			$classname = $conf->global->EXPENSEREPORT_ADDON;
 
 			// Include file with class
-			$dirmodels=array_merge(array('/'),(array) $conf->modules_parts['models']);
+			$dirmodels=array_merge(array('/'), (array) $conf->modules_parts['models']);
 			foreach ($dirmodels as $reldir)
 			{
                 $dir = dol_buildpath($reldir."core/modules/expensereport/");
@@ -1521,9 +1522,8 @@ class ExpenseReport extends CommonObject
                 $mybool|=@include_once $dir.$file;
             }
 
-            if (! $mybool)
-            {
-                dol_print_error('',"Failed to include file ".$file);
+            if ($mybool === false) {
+                dol_print_error('', "Failed to include file ".$file);
                 return '';
             }
 

+ 4 - 4
htdocs/fichinter/class/fichinter.class.php

@@ -6,6 +6,7 @@
  * Copyright (C) 2015      Marcos García        <marcosgdf@gmail.com>
  * Copyright (C) 2015      Charlie Benke        <charlie@patas-monkey.com>
  * Copyright (C) 2018      Nicolas ZABOURI	<info@inovea-conseil.com>
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -805,15 +806,14 @@ class Fichinter extends CommonObject
 				$mybool|=@include_once $dir.$file;
 			}
 
-			if (! $mybool)
-			{
-				dol_print_error('',"Failed to include file ".$file);
+			if ($mybool === false) {
+				dol_print_error('', "Failed to include file ".$file);
 				return '';
 			}
 
 			$obj = new $classname();
 			$numref = "";
-			$numref = $obj->getNextValue($soc,$this);
+			$numref = $obj->getNextValue($soc, $this);
 
 			if ( $numref != "")
 			{

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

@@ -9,6 +9,7 @@
  * Copyright (C) 2013       Florian Henry		  	<florian.henry@open-concept.pro>
  * Copyright (C) 2013       Cédric Salvador         <csalvador@gpcsolutions.fr>
  * Copyright (C) 2018       Nicolas ZABOURI			<info@inovea-conseil.com>
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -800,8 +801,7 @@ class CommandeFournisseur extends CommonOrder
                 $mybool|=@include_once $dir.$file;
             }
 
-            if (! $mybool)
-            {
+            if ($mybool === false) {
                 dol_print_error('',"Failed to include file ".$file);
                 return '';
             }
@@ -1289,6 +1289,9 @@ class CommandeFournisseur extends CommonOrder
 	            // insert products details into database
 	            for ($i=0;$i<$num;$i++)
 	            {
+	                
+	                $this->special_code = $this->lines[$i]->special_code; // TODO : remove this in 9.0 and add special_code param to addline()
+	                
 	                $result = $this->addline(              // This include test on qty if option SUPPLIER_ORDER_WITH_NOPRICEDEFINED is not set
 	                    $this->lines[$i]->desc,
 	                    $this->lines[$i]->subprice,

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

@@ -12,6 +12,7 @@
  * Copyright (C) 2015		Ferran Marcet			<fmarcet@2byte.es>
  * Copyright (C) 2016		Alexandre Spangaro		<aspangaro@zendsi.com>
  * Copyright (C) 2018       Nicolas ZABOURI			<info@inovea-conseil.com>
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -401,8 +402,8 @@ class FactureFournisseur extends CommonInvoice
                 dol_syslog("There is ".count($this->lines)." lines that are invoice lines objects");
                 foreach ($this->lines as $i => $val)
                 {
-                    $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_det (fk_facture_fourn)';
-                    $sql .= ' VALUES ('.$this->id.')';
+                    $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_det (fk_facture_fourn, special_code)';
+                    $sql .= ' VALUES ('.$this->id.','.intval($this->lines[$i]->special_code).')';
 
                     $resql_insert=$this->db->query($sql);
                     if ($resql_insert)
@@ -420,7 +421,14 @@ class FactureFournisseur extends CommonInvoice
                             $this->lines[$i]->fk_product,
                             'HT',
                             (! empty($this->lines[$i]->info_bits)?$this->lines[$i]->info_bits:''),
-                            $this->lines[$i]->product_type
+                            $this->lines[$i]->product_type,
+                            $this->lines[$i]->remise_percent,
+                            false,
+                            $this->lines[$i]->date_start,
+                            $this->lines[$i]->date_end,
+                            $this->lines[$i]->array_options,
+                            $this->lines[$i]->fk_unit,
+                            $this->lines[$i]->pu_ht_devise
                         );
                     }
                     else
@@ -442,8 +450,8 @@ class FactureFournisseur extends CommonInvoice
 				    //if (! is_object($line)) $line=json_decode(json_encode($line), false);  // convert recursively array into object.
                 	if (! is_object($line)) $line = (object) $line;
 
-                	$sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_det (fk_facture_fourn)';
-			        $sql .= ' VALUES ('.$this->id.')';
+                	$sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_det (fk_facture_fourn, special_code)';
+			        $sql .= ' VALUES ('.$this->id.','.intval($this->lines[$i]->special_code).')';
 
 			        $resql_insert=$this->db->query($sql);
 			        if ($resql_insert)
@@ -2280,9 +2288,8 @@ class FactureFournisseur extends CommonInvoice
             $mybool|=@include_once $dir.$file;
         }
 
-        if (! $mybool)
-        {
-        	dol_print_error('',"Failed to include file ".$file);
+        if ($mybool === false) {
+        	dol_print_error('', "Failed to include file ".$file);
         	return '';
         }
 

+ 4 - 6
htdocs/fourn/class/paiementfourn.class.php

@@ -6,6 +6,7 @@
  * Copyright (C) 2010-2011 Juanjo Menent          <jmenent@2byte.es>
  * Copyright (C) 2014      Marcos García          <marcosgdf@gmail.com>
  * Copyright (C) 2018      Nicolas ZABOURI	  <info@inovea-conseil.com>
+ * Copyright (C) 2018       Frédéric France         <frederic.francenetlogic.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
@@ -654,14 +655,12 @@ class PaiementFourn extends Paiement
 			}
 
 			// For compatibility
-			if (! $mybool)
-			{
+			if ($mybool === false) {
 				$file = $conf->global->SUPPLIER_PAYMENT_ADDON.".php";
 				$classname = "mod_supplier_payment_".$conf->global->SUPPLIER_PAYMENT_ADDON;
 				$classname = preg_replace('/\-.*$/','',$classname);
 				// Include file with class
-				foreach ($conf->file->dol_document_root as $dirroot)
-				{
+				foreach ($conf->file->dol_document_root as $dirroot) {
 					$dir = $dirroot."/core/modules/supplier_payment/";
 
 					// Load file with numbering class (if found)
@@ -671,8 +670,7 @@ class PaiementFourn extends Paiement
 				}
 			}
 
-			if (! $mybool)
-			{
+			if ($mybool === false) {
 				dol_print_error('',"Failed to include file ".$file);
 				return '';
 			}

+ 27 - 16
htdocs/fourn/facture/card.php

@@ -74,11 +74,6 @@ $hidedetails = (GETPOST('hidedetails','int') ? GETPOST('hidedetails','int') : (!
 $hidedesc 	 = (GETPOST('hidedesc','int') ? GETPOST('hidedesc','int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DESC) ?  1 : 0));
 $hideref 	 = (GETPOST('hideref','int') ? GETPOST('hideref','int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_REF) ? 1 : 0));
 
-// Security check
-$socid='';
-if (! empty($user->societe_id)) $socid=$user->societe_id;
-$result = restrictedArea($user, 'fournisseur', $id, 'facture_fourn', 'facture');
-
 // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
 $hookmanager->initHooks(array('invoicesuppliercard','globalcard'));
 
@@ -97,6 +92,12 @@ if ($id > 0 || ! empty($ref))
 	if ($ret < 0) dol_print_error($db,$object->error);
 }
 
+// Security check
+$socid='';
+if (! empty($user->societe_id)) $socid=$user->societe_id;
+$isdraft = (($object->statut == FactureFournisseur::STATUS_DRAFT) ? 1 : 0);
+$result = restrictedArea($user, 'fournisseur', $id, 'facture_fourn', 'facture', 'fk_soc', 'rowid', $isdraft);
+
 $permissionnote=$user->rights->fournisseur->facture->creer;	// Used by the include of actions_setnotes.inc.php
 $permissiondellink=$user->rights->fournisseur->facture->creer;	// Used by the include of actions_dellink.inc.php
 $permissionedit=$user->rights->fournisseur->facture->creer; // Used by the include of actions_lineupdown.inc.php
@@ -220,19 +221,26 @@ if (empty($reshook))
 		}
 	}
 
-	elseif ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->fournisseur->facture->supprimer)
+	elseif ($action == 'confirm_delete' && $confirm == 'yes')
 	{
 		$object->fetch($id);
 		$object->fetch_thirdparty();
-		$result=$object->delete($user);
-		if ($result > 0)
-		{
-			header('Location: list.php?restore_lastsearch_values=1');
-			exit;
-		}
-		else
+
+		$isErasable=$object->is_erasable();
+
+		if (($user->rights->fournisseur->facture->supprimer && $isErasable > 0)
+			|| ($user->rights->fournisseur->facture->creer && $isErasable == 1))
 		{
-			setEventMessages($object->error, $object->errors, 'errors');
+			$result=$object->delete($user);
+			if ($result > 0)
+			{
+				header('Location: list.php?restore_lastsearch_values=1');
+				exit;
+			}
+			else
+			{
+				setEventMessages($object->error, $object->errors, 'errors');
+			}
 		}
 	}
 
@@ -895,6 +903,9 @@ if (empty($reshook))
 								if ($lines[$i]->date_fin_reel) $date_end=$lines[$i]->date_fin_reel;
 								if ($lines[$i]->date_end) $date_end=$lines[$i]->date_end;
 
+								// FIXME Missing special_code  into addline and updateline methods
+								$object->special_code = $lines[$i]->special_code;
+								
 								// FIXME Missing $lines[$i]->ref_supplier and $lines[$i]->label into addline and updateline methods. They are filled when coming from order for example.
 								$result = $object->addline(
 									$desc,
@@ -3115,9 +3126,9 @@ else
 				}
 
 	            // Delete
-	            if ($action != 'confirm_edit' && $user->rights->fournisseur->facture->supprimer)
+				$isErasable=$object->is_erasable();
+				if ($action != 'confirm_edit' && ($user->rights->fournisseur->facture->supprimer || ($user->rights->fournisseur->facture->creer && $isErasable == 1)))	// isErasable = 1 means draft with temporary ref (draft can always be deleted with no need of permissions)
 	            {
-	            	$isErasable=$object->is_erasable();
 	            	//var_dump($isErasable);
 	            	if ($isErasable == -4) {
 	            		print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="' . $langs->trans("DisabledBecausePayments") . '">' . $langs->trans('Delete') . '</a></div>';

+ 44 - 44
htdocs/install/upgrade2.php

@@ -4425,50 +4425,50 @@ function migrate_rename_directories($db,$langs,$conf,$oldname,$newname)
  */
 function migrate_delete_old_files($db,$langs,$conf)
 {
-    $result=true;
-
-    dolibarr_install_syslog("upgrade2::migrate_delete_old_files");
-
-    // List of files to delete
-    $filetodeletearray=array(
-    DOL_DOCUMENT_ROOT.'/core/triggers/interface_demo.class.php',
-    DOL_DOCUMENT_ROOT.'/core/menus/barre_left/default.php',
-    DOL_DOCUMENT_ROOT.'/core/menus/barre_top/default.php',
-    DOL_DOCUMENT_ROOT.'/core/modules/modComptabiliteExpert.class.php',
-    DOL_DOCUMENT_ROOT.'/core/modules/modCommercial.class.php',
-    DOL_DOCUMENT_ROOT.'/core/modules/modProduit.class.php',
-    DOL_DOCUMENT_ROOT.'/core/modules/modSkype.class.php',
-    DOL_DOCUMENT_ROOT.'/phenix/inc/triggers/interface_modPhenix_Phenixsynchro.class.php',
-    DOL_DOCUMENT_ROOT.'/webcalendar/inc/triggers/interface_modWebcalendar_webcalsynchro.class.php',
-    DOL_DOCUMENT_ROOT.'/core/triggers/interface_modWebcalendar_Webcalsynchro.class.php',
-    DOL_DOCUMENT_ROOT.'/core/triggers/interface_modCommande_Ecotax.class.php',
-    DOL_DOCUMENT_ROOT.'/core/triggers/interface_modCommande_fraisport.class.php',
-    DOL_DOCUMENT_ROOT.'/core/triggers/interface_modPropale_PropalWorkflow.class.php',
-    DOL_DOCUMENT_ROOT.'/core/menus/smartphone/iphone.lib.php',
-    DOL_DOCUMENT_ROOT.'/core/menus/smartphone/iphone_backoffice.php',
-    DOL_DOCUMENT_ROOT.'/core/menus/smartphone/iphone_frontoffice.php',
-    DOL_DOCUMENT_ROOT.'/core/menus/standard/auguria_backoffice.php',
-    DOL_DOCUMENT_ROOT.'/core/menus/standard/auguria_frontoffice.php',
-    DOL_DOCUMENT_ROOT.'/core/menus/standard/eldy_backoffice.php',
-    DOL_DOCUMENT_ROOT.'/core/menus/standard/eldy_frontoffice.php',
-    DOL_DOCUMENT_ROOT.'/core/modules/mailings/contacts2.modules.php',
-    DOL_DOCUMENT_ROOT.'/core/modules/mailings/contacts3.modules.php',
-    DOL_DOCUMENT_ROOT.'/core/modules/mailings/contacts4.modules.php',
-    DOL_DOCUMENT_ROOT.'/core/modules/mailings/framboise.modules.php',
-    DOL_DOCUMENT_ROOT.'/core/modules/mailings/dolibarr_services_expired.modules.php',
-    DOL_DOCUMENT_ROOT.'/core/modules/mailings/peche.modules.php',
-    DOL_DOCUMENT_ROOT.'/core/modules/mailings/poire.modules.php',
-    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.'/product/class/api_product.class.php',
-    DOL_DOCUMENT_ROOT.'/societe/class/api_contact.class.php',
-    DOL_DOCUMENT_ROOT.'/societe/class/api_thirdparty.class.php'
-
+	$result=true;
+
+	dolibarr_install_syslog("upgrade2::migrate_delete_old_files");
+
+	// List of files to delete
+	$filetodeletearray=array(
+		DOL_DOCUMENT_ROOT.'/core/triggers/interface_demo.class.php',
+		DOL_DOCUMENT_ROOT.'/core/menus/barre_left/default.php',
+		DOL_DOCUMENT_ROOT.'/core/menus/barre_top/default.php',
+		DOL_DOCUMENT_ROOT.'/core/modules/modComptabiliteExpert.class.php',
+		DOL_DOCUMENT_ROOT.'/core/modules/modCommercial.class.php',
+		DOL_DOCUMENT_ROOT.'/core/modules/modProduit.class.php',
+		DOL_DOCUMENT_ROOT.'/core/modules/modSkype.class.php',
+		DOL_DOCUMENT_ROOT.'/phenix/inc/triggers/interface_modPhenix_Phenixsynchro.class.php',
+		DOL_DOCUMENT_ROOT.'/webcalendar/inc/triggers/interface_modWebcalendar_webcalsynchro.class.php',
+		DOL_DOCUMENT_ROOT.'/core/triggers/interface_modWebcalendar_Webcalsynchro.class.php',
+		DOL_DOCUMENT_ROOT.'/core/triggers/interface_modCommande_Ecotax.class.php',
+		DOL_DOCUMENT_ROOT.'/core/triggers/interface_modCommande_fraisport.class.php',
+		DOL_DOCUMENT_ROOT.'/core/triggers/interface_modPropale_PropalWorkflow.class.php',
+		DOL_DOCUMENT_ROOT.'/core/menus/smartphone/iphone.lib.php',
+		DOL_DOCUMENT_ROOT.'/core/menus/smartphone/iphone_backoffice.php',
+		DOL_DOCUMENT_ROOT.'/core/menus/smartphone/iphone_frontoffice.php',
+		DOL_DOCUMENT_ROOT.'/core/menus/standard/auguria_backoffice.php',
+		DOL_DOCUMENT_ROOT.'/core/menus/standard/auguria_frontoffice.php',
+		DOL_DOCUMENT_ROOT.'/core/menus/standard/eldy_backoffice.php',
+		DOL_DOCUMENT_ROOT.'/core/menus/standard/eldy_frontoffice.php',
+		DOL_DOCUMENT_ROOT.'/core/modules/mailings/contacts2.modules.php',
+		DOL_DOCUMENT_ROOT.'/core/modules/mailings/contacts3.modules.php',
+		DOL_DOCUMENT_ROOT.'/core/modules/mailings/contacts4.modules.php',
+		DOL_DOCUMENT_ROOT.'/core/modules/mailings/framboise.modules.php',
+		DOL_DOCUMENT_ROOT.'/core/modules/mailings/dolibarr_services_expired.modules.php',
+		DOL_DOCUMENT_ROOT.'/core/modules/mailings/peche.modules.php',
+		DOL_DOCUMENT_ROOT.'/core/modules/mailings/poire.modules.php',
+		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.'/product/class/api_product.class.php',
+		DOL_DOCUMENT_ROOT.'/societe/class/api_contact.class.php',
+		DOL_DOCUMENT_ROOT.'/societe/class/api_thirdparty.class.php',
+		DOL_DOCUMENT_ROOT.'/support/online.php'
     );
 
     foreach ($filetodeletearray as $filetodelete)

+ 1 - 0
htdocs/langs/en_US/errors.lang

@@ -89,6 +89,7 @@ ErrorFileIsInfectedWithAVirus=The antivirus program was not able to validate the
 ErrorSpecialCharNotAllowedForField=Special characters are not allowed for field "%s"
 ErrorNumRefModel=A reference exists into database (%s) and is not compatible with this numbering rule. Remove record or renamed reference to activate this module.
 ErrorQtyTooLowForThisSupplier=Quantity too low for this vendor or no price defined on this product for this supplier
+ErrorOrdersNotCreatedQtyTooLow=Some orders haven't been created beacuse of too low quantity
 ErrorModuleSetupNotComplete=Setup of module looks to be uncomplete. Go on Home - Setup - Modules to complete.
 ErrorBadMask=Error on mask
 ErrorBadMaskFailedToLocatePosOfSequence=Error, mask without sequence number

+ 1 - 0
htdocs/langs/en_US/main.lang

@@ -750,6 +750,7 @@ LinkToIntervention=Link to intervention
 CreateDraft=Create draft
 SetToDraft=Back to draft
 ClickToEdit=Click to edit
+ClickToRefresh=Click to refresh
 EditWithEditor=Edit with CKEditor
 EditWithTextEditor=Edit with Text editor
 EditHTMLSource=Edit HTML Source

+ 3 - 3
htdocs/loan/card.php

@@ -340,19 +340,19 @@ if ($action == 'create')
 		// Accountancy_account_capital
 		print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans("LoanAccountancyCapitalCode").'</td>';
 		print '<td>';
-		print $formaccounting->select_account($object->accountancy_account_capital, 'accountancy_account_capital', 1, '', 0, 1);
+		print $formaccounting->select_account(GETPOST('accountancy_account_capital')?GETPOST('accountancy_account_capital'):$conf->global->LOAN_ACCOUNTING_ACCOUNT_CAPITAL, 'accountancy_account_capital', 1, '', 1, 1);
 		print '</td></tr>';
 
 		// Accountancy_account_insurance
 		print '<tr><td class="fieldrequired">'.$langs->trans("LoanAccountancyInsuranceCode").'</td>';
 		print '<td>';
-		print $formaccounting->select_account($object->accountancy_account_insurance, 'accountancy_account_insurance', 1, '', 0, 1);
+		print $formaccounting->select_account(GETPOST('accountancy_account_insurance')?GETPOST('accountancy_account_insurance'):$conf->global->LOAN_ACCOUNTING_ACCOUNT_INSURANCE, 'accountancy_account_insurance', 1, '', 1, 1);
 		print '</td></tr>';
 
 		// Accountancy_account_interest
 		print '<tr><td class="fieldrequired">'.$langs->trans("LoanAccountancyInterestCode").'</td>';
 		print '<td>';
-		print $formaccounting->select_account($object->accountancy_account_interest, 'accountancy_account_interest', 1, '', 0, 1);
+		print $formaccounting->select_account(GETPOST('accountancy_account_interest')?GETPOST('accountancy_account_interest'):$conf->global->LOAN_ACCOUNTING_ACCOUNT_INTEREST, 'accountancy_account_interest', 1, '', 1, 1);
 		print '</td></tr>';
 	}
 	else // For external software

+ 1 - 1
htdocs/modulebuilder/template/core/modules/modMyModule.class.php

@@ -108,7 +108,7 @@ class modMyModule extends DolibarrModules
 
 		// Dependencies
 		$this->hidden = false;			// A condition to hide module
-		$this->depends = array();		// List of module class names as string that must be enabled if this module is enabled
+		$this->depends = array();		// List of module class names as string that must be enabled if this module is enabled. array('always1'=>'modModule1','always2'=>'modModule2', 'FR1'=>'modModuleFR'...)
 		$this->requiredby = array();	// List of module class names to disable if this one is disabled
 		$this->conflictwith = array();	// List of module class names as string this module is in conflict with
 		$this->langfiles = array("mymodule@mymodule");

+ 2 - 1
htdocs/modulebuilder/template/myobject_card.php

@@ -99,7 +99,8 @@ include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php';  // Must be inclu
 // Security check - Protection if external user
 //if ($user->societe_id > 0) access_forbidden();
 //if ($user->societe_id > 0) $socid = $user->societe_id;
-//$result = restrictedArea($user, 'mymodule', $object->id);
+//$isdraft = (($object->statut == MyObject::STATUS_DRAFT) ? 1 : 0);
+//$result = restrictedArea($user, 'mymodule', $object->id, '', '', 'fk_soc', 'rowid', $isdraft);
 
 
 /*

+ 25 - 20
htdocs/product/stock/replenish.php

@@ -112,12 +112,15 @@ if ($action == 'order' && isset($_POST['valid']))
 {
     $linecount = GETPOST('linecount', 'int');
     $box = 0;
+	$errorQty = 0;
     unset($_POST['linecount']);
     if ($linecount > 0)
     {
     	$db->begin();
 
         $suppliers = array();
+		require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.product.class.php';
+		$productsupplier = new ProductFournisseur($db);
         for ($i = 0; $i < $linecount; $i++)
         {
             if (GETPOST('choose' . $i, 'alpha') === 'on' && GETPOST('fourn' . $i, 'int') > 0)
@@ -127,13 +130,9 @@ if ($action == 'order' && isset($_POST['valid']))
                 $supplierpriceid = GETPOST('fourn'.$i, 'int');
                 //get all the parameters needed to create a line
                 $qty = GETPOST('tobuy'.$i, 'int');
-                //$desc = GETPOST('desc'.$i, 'alpha');
-                $sql = 'SELECT fk_product, fk_soc, ref_fourn';
-                $sql .= ', tva_tx, unitprice, remise_percent FROM ';
-                $sql .= MAIN_DB_PREFIX . 'product_fournisseur_price';
-                $sql .= ' WHERE rowid = ' . $supplierpriceid;
-                $resql = $db->query($sql);
-                if ($resql && $db->num_rows($resql) > 0)
+				$idprod=$productsupplier->get_buyprice($supplierpriceid, $qty);
+				$res=$productsupplier->fetch($idprod);
+                if ($res && $idprod > 0)
                 {
                 	if ($qty)
                 	{
@@ -141,33 +140,37 @@ if ($action == 'order' && isset($_POST['valid']))
 	                    $obj = $db->fetch_object($resql);
 	                    $line = new CommandeFournisseurLigne($db);
 	                    $line->qty = $qty;
-	                    $line->fk_product = $obj->fk_product;
+	                    $line->fk_product = $idprod;
 
-	                    $product = new Product($db);
-	                    $product->fetch($obj->fk_product);
+	                    //$product = new Product($db);
+	                    //$product->fetch($obj->fk_product);
 	                    if (! empty($conf->global->MAIN_MULTILANGS))
 	                    {
-	                        $product->getMultiLangs();
+	                        $productsupplier->getMultiLangs();
 	                    }
-	                    $line->desc = $product->description;
+	                    $line->desc = $productsupplier->description;
                         if (! empty($conf->global->MAIN_MULTILANGS))
                         {
                             // TODO Get desc in language of thirdparty
                         }
 
-	                    $line->tva_tx = $obj->tva_tx;
-	                    $line->subprice = $obj->unitprice;
-	                    $line->total_ht = $obj->unitprice * $qty;
+	                    $line->tva_tx = $productsupplier->vatrate_supplier;
+	                    $line->subprice = $productsupplier->fourn_pu;
+	                    $line->total_ht = $productsupplier->fourn_pu * $qty;
 	                    $tva = $line->tva_tx / 100;
 	                    $line->total_tva = $line->total_ht * $tva;
 	                    $line->total_ttc = $line->total_ht + $line->total_tva;
-						$line->remise_percent = $obj->remise_percent;
-	                    $line->ref_fourn = $obj->ref_fourn;
-						$line->type = $product->type;
-						$line->fk_unit = $product->fk_unit;
-	                    $suppliers[$obj->fk_soc]['lines'][] = $line;
+						$line->remise_percent = $productsupplier->remise_percent;
+	                    $line->ref_fourn = $productsupplier->ref_supplier;
+						$line->type = $productsupplier->type;
+						$line->fk_unit = $productsupplier->fk_unit;
+	                    $suppliers[$productsupplier->fourn_socid]['lines'][] = $line;
                 	}
                 }
+				elseif ($idprod == -1)
+				{
+					$errorQty++;
+				}
                 else
 				{
                     $error=$db->lasterror();
@@ -248,6 +251,8 @@ if ($action == 'order' && isset($_POST['valid']))
             }
         }
 
+		if($errorQty) setEventMessages($langs->trans('ErrorOrdersNotCreatedQtyTooLow'), null, 'warnings');
+
         if (! $fail && $id)
         {
         	$db->commit();

+ 4 - 4
htdocs/projet/class/project.class.php

@@ -565,11 +565,11 @@ class Project extends CommonObject
 
 		if ($type == 'agenda')
         {
-        	$sql = "SELECT id as rowid FROM " . MAIN_DB_PREFIX . "actioncomm WHERE fk_project IN (". $ids .")";
+        	$sql = "SELECT id as rowid FROM " . MAIN_DB_PREFIX . "actioncomm WHERE fk_project IN (". $ids .") AND entity IN (".getEntity('agenda').")";
         }
         elseif ($type == 'expensereport')
 		{
-            $sql = "SELECT ed.rowid FROM " . MAIN_DB_PREFIX . "expensereport as e, " . MAIN_DB_PREFIX . "expensereport_det as ed WHERE e.rowid = ed.fk_expensereport AND ed.fk_projet IN (". $ids .")";
+            $sql = "SELECT ed.rowid FROM " . MAIN_DB_PREFIX . "expensereport as e, " . MAIN_DB_PREFIX . "expensereport_det as ed WHERE e.rowid = ed.fk_expensereport AND e.entity IN (".getEntity('expensereport').") AND ed.fk_projet IN (". $ids .")";
 		}
         elseif ($type == 'project_task')
 		{
@@ -581,11 +581,11 @@ class Project extends CommonObject
 		}
 		elseif ($type == 'stock_mouvement')
 		{
-			$sql = 'SELECT ms.rowid, ms.fk_user_author as fk_user FROM ' . MAIN_DB_PREFIX . "stock_mouvement as ms WHERE ms.origintype = 'project' AND ms.fk_origin  IN (". $ids .") AND ms.type_mouvement = 1";
+			$sql = 'SELECT ms.rowid, ms.fk_user_author as fk_user FROM ' . MAIN_DB_PREFIX . "stock_mouvement as ms, " . MAIN_DB_PREFIX . "entrepot as e WHERE e.rowid = ms.fk_entrepot AND e.entity IN (".getEntity('stock').") AND ms.origintype = 'project' AND ms.fk_origin IN (". $ids .") AND ms.type_mouvement = 1";
 		}
         else
 		{
-            $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . $tablename." WHERE ".$projectkey." IN (". $ids .")";
+            $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . $tablename." WHERE ".$projectkey." IN (". $ids .") AND entity IN (".getEntity($type).")";
 		}
 
 		if ($dates > 0)

+ 3 - 3
htdocs/projet/element.php

@@ -905,16 +905,16 @@ foreach ($listofreferent as $key => $value)
 
 					$element_doc = $element->element;
 					$filename=dol_sanitizeFileName($element->ref);
-					$filedir=$conf->{$element_doc}->dir_output . '/' . dol_sanitizeFileName($element->ref);
+					$filedir=$conf->{$element_doc}->multidir_output[$element->entity] . '/' . dol_sanitizeFileName($element->ref);
 
 					if ($element_doc === 'order_supplier') {
 						$element_doc='commande_fournisseur';
-						$filedir = $conf->fournisseur->commande->dir_output.'/'.dol_sanitizeFileName($element->ref);
+						$filedir = $conf->fournisseur->commande->multidir_output[$element->entity].'/'.dol_sanitizeFileName($element->ref);
 					}
 					else if ($element_doc === 'invoice_supplier') {
 						$element_doc='facture_fournisseur';
 						$filename = get_exdir($element->id,2,0,0,$element,'product').dol_sanitizeFileName($element->ref);
-						$filedir = $conf->fournisseur->facture->dir_output.'/'.get_exdir($element->id,2,0,0,$element,'invoice_supplier').dol_sanitizeFileName($element->ref);
+						$filedir = $conf->fournisseur->facture->multidir_output[$element->entity].'/'.get_exdir($element->id,2,0,0,$element,'invoice_supplier').dol_sanitizeFileName($element->ref);
 					}
 
 					print '<div class="inline-block valignmiddle">'.$formfile->getDocumentsLink($element_doc, $filename, $filedir).'</div>';

+ 4 - 3
htdocs/projet/tasks.php

@@ -499,7 +499,7 @@ if ($action == 'create' && $user->rights->projet->creer && (empty($object->third
 
 	// Planned workload
 	print '<tr><td>'.$langs->trans("PlannedWorkload").'</td><td>';
-	print $form->select_duration('planned_workload', $planned_workload?$planned_workload : $object->planned_workload,0,'text');
+	print $form->select_duration('planned_workload', $planned_workload?$planned_workload : 0, 0, 'text');
 	print '</td></tr>';
 
 	// Progress
@@ -515,11 +515,12 @@ if ($action == 'create' && $user->rights->projet->creer && (empty($object->third
 
 	// Other options
 	$parameters=array();
-	$reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook
+	$reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$taskstatic,$action); // Note that $action and $object may have been modified by hook
     print $hookmanager->resPrint;
+
     if (empty($reshook) && ! empty($extrafields_task->attribute_label))
 	{
-		print $object->showOptionals($extrafields_task,'edit');
+		print $taskstatic->showOptionals($extrafields_task,'edit');		// Do not use $object here that is object of project
 	}
 
 	print '</table>';

+ 2 - 2
htdocs/resource/element_resource.php

@@ -1,5 +1,5 @@
 <?php
-/* Copyright (C) 2013		Jean-François Ferry	<jfefe@aternatik.fr>
+/* Copyright (C) 2013-2018	Jean-François Ferry	<hello+jf@librethic.io>
  * Copyright (C) 2016		Gilles Poirier 		<glgpoirier@gmail.com>
  *
  * This program is free software: you can redistribute it and/or modify
@@ -90,7 +90,7 @@ if ($action == 'add_element_resource' && ! $cancel)
 	else
 	{
 		$objstat = fetchObjectByElement($element_id, $element);
-
+		$objstat->element = $element; // For externals module, we need to keep @xx
 		$res = $objstat->add_element_resource($resource_id, $resource_type, $busy, $mandatory);
 	}
 	if (! $error && $res > 0)

+ 0 - 163
htdocs/support/online.php

@@ -1,163 +0,0 @@
-<?php
-/* Copyright (C) 2008-2010 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/>.
- */
-
-/**
- *       \file      htdocs/support/online.php
- *       \ingroup   install
- *       \brief     Provide an Online Help support
- */
-
-error_reporting(0);
-
-include_once 'inc.php';
-$uri=preg_replace('/^http(s?):\/\//i','',$dolibarr_main_url_root);
-$pos = strstr($uri, '/');      // $pos contient alors url sans nom domaine
-if ($pos == '/') $pos = '';     // si $pos vaut /, on le met a ''
-define('DOL_URL_ROOT', $pos);	// URL racine relative
-
-
-$langs->loadLangs(array("other", "help"));
-
-/*
- * View
- */
-
-pHeader($langs->trans("DolibarrHelpCenter"),$_SERVER["PHP_SELF"]);
-
-$urlsparkengels='http://www.spark-angels.com';
-$titlesparkangels='Spark-Angels';
-
-//print '<br>';
-
-print $langs->trans("ToGetHelpGoOnSparkAngels1",$titlesparkangels).'<br>';
-
-print '<br><br>';
-
-
-// List of predefined coaches
-// We list here the 4 most active coaches on Dolibarr projects (according to number of commits
-// found in page http://www.nltechno.com/stats/dolibarr/cvschangelogbuilder_dolibarr.html
-$limit=4;
-$arrayofwidgets=array(
-// Widget for Laurent Destailleur
-array('name'=>'Laurent Destailleur',	// id user 4702
-		'sort'=>1,
-		'logo'=>'logoUrl='.urlencode('http://www.nltechno.com/images/logo_nltechno_long.jpg'), // Put your own logo
-		'id'=>'4256,4255',	// Put of list of sparkangels widget id (for each language)
-		'lang'=>'fr,en'),	// Put list of language code of widgets (always english at end)
-// Widget for Auguria
-array('name'=>'Auguria',
-		'sort'=>2,
-		//'logo'=>'logoUrl='.urlencode('http://www.cap-networks.com/images/logo_small.jpg'),
-		'id'=>'7196',
-		'lang'=>'fr'),
-//Widget for Open-Concept
-array('name'=>'Open-Concept.pro',
-		'sort'=>2,
-		'logo'=>'logoUrl='.urlencode('http://www.open-concept.pro/CMS/images/Logo/logosimplecomplet.png'),
-		'id'=>'9340',
-		'lang'=>'fr')
-);
-$arrayofwidgets=dol_sort_array($arrayofwidgets,'sort','asc',0,0);
-
-$found=0;
-print '* '.$langs->trans("LinkToGoldMember",$langs->defaultlang).'<br><br>';
-print '<table summary="listofgoldcoaches"><tr>';
-foreach ($arrayofwidgets as $arraywidget)	// Loop on each user
-{
-	if ($found >= $limit) break;
-	$listofwidgets=explode(',',$arraywidget['id']);
-	$listoflangs=explode(',',$arraywidget['lang']);
-	$pos=0;
-	foreach($listoflangs as $langcode)		// Loop on each lang of user
-	{
-		$pos++;
-		if (preg_match('/'.$langcode.'/i',$langs->defaultlang) || $langcode == 'en')	// If lang qualified
-		{
-			print '<td align="center">';
-			print $arraywidget['name'].'<br>';
-			print $langs->trans("PossibleLanguages").': ';
-			// All languages of user are shown
-			foreach ($listoflangs as $langcode2)
-			{
-				if (empty($widgetid)) $widgetid=$listoflangs[$pos-1];
-				if (! preg_match('/'.$langcode.'/i',$langs->defaultlang) && $langcode2 != 'en') continue;	// Show only english
-				print $langcode2.' ';
-			}
-			print '<br>';
-
-			// Only first language found is used for widget
-			$widgetid=$listofwidgets[$pos-1];
-
-			// Widget V3
-			print '<iframe src="http://www.spark-angels.com/static/widget/template-pro3/widgetpro3-iframe.html?widgetId='.$widgetid.'&lgCode='.$langcode.'&'.(isset($arraywidget['logo'])?$arraywidget['logo']:'').'" width="172" height="123" frameborder="0" scrolling="no" marginheight="0" > </iframe>';
-
-			print '</td>';
-			$found++;
-			break;
-		}
-	}
-}
-if (! $found) print '<td>'.$langs->trans("SorryNoHelpForYourLanguage").'</td>';
-print '</tr></table>';
-
-print '<br><br>';
-
-// List of coaches
-$sparkangellangcode=substr($langs->defaultlang,0,2);
-if (! in_array($sparkangellangcode,array('fr','en','sp'))) $sparkangellangcode='en';
-print '<table class="noborder" summary="ListOfSupport"><tr valign="middle"><td>';
-print '* '.$langs->trans("ToGetHelpGoOnSparkAngels3",$urlsparkengels);
-print '<div id="sparkom_bsaHelpersSearch">'."\n";
-print '<form target="_blank" id="frJSkw" action="http://www.spark-angels.com/rss/action/resultsearch.html" name="fResult" method="get">'."\n";
-print '   <input type="hidden" value="" title="Rechercher" maxlength="1024" name="kws" id="kws"/> <!-- mots clés pour la recherche dont la ou les compétences matchent avec ces mots -->'."\n";
-print '   <input id="dhids" name="dhids" type="hidden" value=""><!-- identifiant SHSAPI communiqué par SparkAngels. -->'."\n";
-print '   <input id="lgSearch" name="lgS" type="hidden" value=""><!-- code langue, les accompagnateurs proposés suite à cette recherche prétendent pouvoir fournir de l assistance dans au moins cette langue-->'."\n";
-print '   <input id="myLv" name="myLv" type="hidden" value=""><!-- niveau de l internaute dans le domaine de sa recherche.-->'."\n";
-print '   <input id="catSrv" name="catSrv" type="hidden" value=""><!-- type de catégorie de service demandée.-->'."\n";
-print '   <input type="submit" value="'.$langs->trans("Search").'" onclick="getSAParams();">'."\n";
-print '<script type="text/javascript">'."\n";
-print '<!--'."\n";
-print '   function getSAParams(){'."\n";
-print '       document.getElementById(\'dhids\').value= "4702";'."\n";
-print '       document.getElementById(\'kws\').value= "dolibarr";'."\n";
-print '       document.getElementById(\'lgSearch\').value= "'.$sparkangellangcode.'";'."\n";
-print '       document.getElementById(\'myLv\').value= "0";'."\n";
-print '       document.getElementById(\'catSrv\').value= "1";'."\n";
-print '   }'."\n";
-print '-->'."\n";
-print '</script>'."\n";
-print '</form>'."\n";
-print '</div>'."\n";
-
-print '</td><td>';
-//print '<a href="'.$urlsparkengels.'" target="_blank">';
-//print '<img border="0" src="sparkangels.png" alt="SparkAngels web site" title="SparkAngels web site">';
-//print $titlesparkangels;
-//print '</a>';
-print '</td></tr></table>';
-//print $langs->trans("ToGetHelpGoOnSparkAngels2",$titlesparkangels).'<br>';
-
-
-// Otherwise, go back to help center home
-print '<br><br>';
-print '* '.$langs->trans("BackToHelpCenter",'index.php');
-print '<br><br>';
-
-
-
-pFooter();