Browse Source

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

Conflicts:
	htdocs/commande/class/commande.class.php
	htdocs/core/lib/security.lib.php
	htdocs/modulebuilder/template/myobject_card.php
Laurent Destailleur 6 năm trước cách đây
mục cha
commit
68f6ebd0ff

+ 39 - 23
htdocs/adherents/card.php

@@ -644,19 +644,27 @@ 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";
+
+                    $result=$object->send_an_email($texttosend, $subjecttosend, array(), array(), array(), "", "", 0, -1, '', $moreinheader);
+                    if ($result < 0)
+                    {
+                        $error++;
+                        setEventMessages($object->error, $object->errors, 'errors');
+                    }
+                }
 
-				$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');
-				}
 			}
 		}
 		else
@@ -718,20 +726,28 @@ 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";
+
+                        $result=$object->send_an_email($texttosend, $subjecttosend, array(), array(), array(), "", "", 0, -1, '', $moreinheader);
+                        if ($result < 0)
+                        {
+                            $error++;
+                            setEventMessages($object->error, $object->errors, 'errors');
+                        }
+                    }
+                }
 
-					$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');
-				}
 			}
 			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)
 {

+ 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;

+ 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;
 	}
 
 	/**

+ 10 - 10
htdocs/core/lib/functions.lib.php

@@ -6572,7 +6572,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 +6580,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 +6590,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 +6652,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);
 }

+ 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);
 }

+ 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);
 

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

@@ -73,11 +73,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'));
 
@@ -96,6 +91,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
@@ -219,19 +220,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');
+			}
 		}
 	}
 
@@ -3114,9 +3122,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>';

+ 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

+ 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

+ 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();

+ 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)