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

This commit is contained in:
Laurent Destailleur 2022-01-28 15:58:15 +01:00
commit a631c94193
12 changed files with 160 additions and 103 deletions

View File

@ -320,12 +320,12 @@ class BlockedLog
$this->error++; $this->error++;
} }
} elseif ($this->action == 'MODULE_SET') { } elseif ($this->action == 'MODULE_SET') {
return '<i class="opacitymedium">System to track events into unalterable logs were enabled</i>'; return '<i class="opacitymedium">'.$langs->trans("BlockedLogEnabled").'</i>';
} elseif ($this->action == 'MODULE_RESET') { } elseif ($this->action == 'MODULE_RESET') {
if ($this->signature == '0000000000') { if ($this->signature == '0000000000') {
return '<i class="opacitymedium">System to track events into unalterable logs were disabled after some recording were done. We saved a special Fingerprint to track the chain as broken.</i>'; return '<i class="opacitymedium">'.$langs->trans("BlockedLogDisabled").'</i>';
} else { } else {
return '<i class="opacitymedium">System to track events into unalterable logs were disabled. This is possible because no record were done yet.</i>'; return '<i class="opacitymedium">'.$langs->trans("BlockedLogDisabledBis").'</i>';
} }
} }

View File

@ -170,7 +170,7 @@ class box_scheduled_jobs extends ModeleBoxes
); );
$this->info_box_contents[$line][] = array( $this->info_box_contents[$line][] = array(
'td' => 'class="center"', 'td' => 'class="center"',
'textnoformat' => ($nbjobsinerror ? '<a href="'.DOL_URL_ROOT.'/cron/list.php?search_lastresult='.urlencode('<>0').'"><div class="badge badge-danger"><i class="fa fa-exclamation-triangle"></i> '.$nbjobsinerror.'</div></a>' : '<div class="center badge-status4">0</div>') 'textnoformat' => ($nbjobsinerror ? '<a href="'.DOL_URL_ROOT.'/cron/list.php?search_lastresult='.urlencode('<>0').'"><div class="badge badge-danger"><i class="fa fa-exclamation-triangle"></i> '.$nbjobsinerror.'</div></a>' : '<a href="'.DOL_URL_ROOT.'/cron/list.php"><div class="center badge-status4">0</div></a>')
); );
} else { } else {
$this->info_box_contents[0][0] = array( $this->info_box_contents[0][0] = array(

View File

@ -210,6 +210,8 @@ class DoliDBMysqli extends DoliDB
{ {
dol_syslog(get_class($this)."::connect host=$host, port=$port, login=$login, passwd=--hidden--, name=$name", LOG_DEBUG); dol_syslog(get_class($this)."::connect host=$host, port=$port, login=$login, passwd=--hidden--, name=$name", LOG_DEBUG);
//mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
// Can also be // Can also be
// mysqli::init(); mysql::options(MYSQLI_INIT_COMMAND, 'SET AUTOCOMMIT = 0'); mysqli::options(MYSQLI_OPT_CONNECT_TIMEOUT, 5); // mysqli::init(); mysql::options(MYSQLI_INIT_COMMAND, 'SET AUTOCOMMIT = 0'); mysqli::options(MYSQLI_OPT_CONNECT_TIMEOUT, 5);
// return mysqli::real_connect($host, $user, $pass, $db, $port); // return mysqli::real_connect($host, $user, $pass, $db, $port);
@ -255,6 +257,8 @@ class DoliDBMysqli extends DoliDB
return false; return false;
} }
/** /**
* Execute a SQL request and return the resultset * Execute a SQL request and return the resultset
* *
@ -288,11 +292,16 @@ class DoliDBMysqli extends DoliDB
} }
} }
if (!$this->database_name) { try {
// Ordre SQL ne necessitant pas de connexion a une base (exemple: CREATE DATABASE) if (!$this->database_name) {
$ret = $this->db->query($query, $result_mode); // Ordre SQL ne necessitant pas de connexion a une base (exemple: CREATE DATABASE)
} else { $ret = $this->db->query($query, $result_mode);
$ret = $this->db->query($query, $result_mode); } else {
$ret = $this->db->query($query, $result_mode);
}
} catch (Exception $e) {
dol_syslog(get_class($this)."::query Exception in query instead of returning an error: ".$e->getMessage(), LOG_ERR);
$ret = false;
} }
if (!preg_match("/^COMMIT/i", $query) && !preg_match("/^ROLLBACK/i", $query)) { if (!preg_match("/^COMMIT/i", $query) && !preg_match("/^ROLLBACK/i", $query)) {

View File

@ -382,7 +382,7 @@ function show_stats_for_company($product, $socid)
} }
$langs->load("propal"); $langs->load("propal");
print '<tr><td>'; print '<tr><td>';
print '<a href="propal.php?id='.$product->id.'">'.img_object('', 'propal', 'class="paddingright"').$langs->trans("Proposals").'</a>'; print '<a href="propal.php?id='.$product->id.'">'.img_object('', 'propal', 'class="pictofixedwidth"').$langs->trans("Proposals").'</a>';
print '</td><td class="right">'; print '</td><td class="right">';
print $product->stats_propale['customers']; print $product->stats_propale['customers'];
print '</td><td class="right">'; print '</td><td class="right">';
@ -401,7 +401,7 @@ function show_stats_for_company($product, $socid)
} }
$langs->load("supplier_proposal"); $langs->load("supplier_proposal");
print '<tr><td>'; print '<tr><td>';
print '<a href="supplier_proposal.php?id='.$product->id.'">'.img_object('', 'supplier_proposal', 'class="paddingright"').$langs->trans("SupplierProposals").'</a>'; print '<a href="supplier_proposal.php?id='.$product->id.'">'.img_object('', 'supplier_proposal', 'class="pictofixedwidth"').$langs->trans("SupplierProposals").'</a>';
print '</td><td class="right">'; print '</td><td class="right">';
print $product->stats_proposal_supplier['suppliers']; print $product->stats_proposal_supplier['suppliers'];
print '</td><td class="right">'; print '</td><td class="right">';
@ -420,7 +420,7 @@ function show_stats_for_company($product, $socid)
} }
$langs->load("orders"); $langs->load("orders");
print '<tr><td>'; print '<tr><td>';
print '<a href="commande.php?id='.$product->id.'">'.img_object('', 'order', 'class="paddingright"').$langs->trans("CustomersOrders").'</a>'; print '<a href="commande.php?id='.$product->id.'">'.img_object('', 'order', 'class="pictofixedwidth"').$langs->trans("CustomersOrders").'</a>';
print '</td><td class="right">'; print '</td><td class="right">';
print $product->stats_commande['customers']; print $product->stats_commande['customers'];
print '</td><td class="right">'; print '</td><td class="right">';
@ -439,7 +439,7 @@ function show_stats_for_company($product, $socid)
} }
$langs->load("orders"); $langs->load("orders");
print '<tr><td>'; print '<tr><td>';
print '<a href="commande_fournisseur.php?id='.$product->id.'">'.img_object('', 'supplier_order', 'class="paddingright"').$langs->trans("SuppliersOrders").'</a>'; print '<a href="commande_fournisseur.php?id='.$product->id.'">'.img_object('', 'supplier_order', 'class="pictofixedwidth"').$langs->trans("SuppliersOrders").'</a>';
print '</td><td class="right">'; print '</td><td class="right">';
print $product->stats_commande_fournisseur['suppliers']; print $product->stats_commande_fournisseur['suppliers'];
print '</td><td class="right">'; print '</td><td class="right">';
@ -458,7 +458,7 @@ function show_stats_for_company($product, $socid)
} }
$langs->load("bills"); $langs->load("bills");
print '<tr><td>'; print '<tr><td>';
print '<a href="facture.php?id='.$product->id.'">'.img_object('', 'bill').' '.$langs->trans("CustomersInvoices").'</a>'; print '<a href="facture.php?id='.$product->id.'">'.img_object('', 'bill', 'class="pictofixedwidth"').$langs->trans("CustomersInvoices").'</a>';
print '</td><td class="right">'; print '</td><td class="right">';
print $product->stats_facture['customers']; print $product->stats_facture['customers'];
print '</td><td class="right">'; print '</td><td class="right">';
@ -477,7 +477,7 @@ function show_stats_for_company($product, $socid)
} }
$langs->load("bills"); $langs->load("bills");
print '<tr><td>'; print '<tr><td>';
print '<a href="facture_fournisseur.php?id='.$product->id.'">'.img_object('', 'supplier_invoice', 'class="paddingright"').$langs->trans("SuppliersInvoices").'</a>'; print '<a href="facture_fournisseur.php?id='.$product->id.'">'.img_object('', 'supplier_invoice', 'class="pictofixedwidth"').$langs->trans("SuppliersInvoices").'</a>';
print '</td><td class="right">'; print '</td><td class="right">';
print $product->stats_facture_fournisseur['suppliers']; print $product->stats_facture_fournisseur['suppliers'];
print '</td><td class="right">'; print '</td><td class="right">';
@ -497,7 +497,7 @@ function show_stats_for_company($product, $socid)
} }
$langs->load("contracts"); $langs->load("contracts");
print '<tr><td>'; print '<tr><td>';
print '<a href="contrat.php?id='.$product->id.'">'.img_object('', 'contract', 'class="paddingright"').$langs->trans("Contracts").'</a>'; print '<a href="contrat.php?id='.$product->id.'">'.img_object('', 'contract', 'class="pictofixedwidth"').$langs->trans("Contracts").'</a>';
print '</td><td class="right">'; print '</td><td class="right">';
print $product->stats_contrat['customers']; print $product->stats_contrat['customers'];
print '</td><td class="right">'; print '</td><td class="right">';
@ -518,7 +518,7 @@ function show_stats_for_company($product, $socid)
$langs->load("mrp"); $langs->load("mrp");
print '<tr><td>'; print '<tr><td>';
print '<a href="bom.php?id='.$product->id.'">'.img_object('', 'bom', 'class="paddingright"').$langs->trans("BOM").'</a>'; print '<a href="bom.php?id='.$product->id.'">'.img_object('', 'bom', 'class="pictofixedwidth"').$langs->trans("BOM").'</a>';
print '</td><td class="right">'; print '</td><td class="right">';
print '</td><td class="right">'; print '</td><td class="right">';
@ -540,7 +540,7 @@ function show_stats_for_company($product, $socid)
} }
$langs->load("mrp"); $langs->load("mrp");
print '<tr><td>'; print '<tr><td>';
print '<a href="mo.php?id='.$product->id.'">'.img_object('', 'mrp', 'class="paddingright"').$langs->trans("MO").'</a>'; print '<a href="mo.php?id='.$product->id.'">'.img_object('', 'mrp', 'class="pictofixedwidth"').$langs->trans("MO").'</a>';
print '</td><td class="right">'; print '</td><td class="right">';
print $form->textwithpicto($product->stats_mo['customers_toconsume'], $langs->trans("ToConsume")); print $form->textwithpicto($product->stats_mo['customers_toconsume'], $langs->trans("ToConsume"));
print $form->textwithpicto($product->stats_mo['customers_consumed'], $langs->trans("QtyAlreadyConsumed")); print $form->textwithpicto($product->stats_mo['customers_consumed'], $langs->trans("QtyAlreadyConsumed"));

View File

@ -239,7 +239,7 @@ class modUser extends DolibarrModules
'u.accountancy_code'=>'Text', 'u.accountancy_code'=>'Text',
'u.address'=>"Text", 'u.zip'=>"Text", 'u.town'=>"Text", 'u.address'=>"Text", 'u.zip'=>"Text", 'u.town'=>"Text",
'u.office_phone'=>'Text', 'u.user_mobile'=>'Text', 'u.office_fax'=>'Text', 'u.office_phone'=>'Text', 'u.user_mobile'=>'Text', 'u.office_fax'=>'Text',
'u.email'=>'Text', 'u.datec'=>"Date", 'u.tms'=>"Date", 'u.admin'=>"Boolean", 'u.statut'=>'Status', 'u.note'=>"Text", 'u.datelastlogin'=>'Date', 'u.email'=>'Text', 'u.datec'=>"Date", 'u.tms'=>"Date", 'u.admin'=>"Boolean", 'u.statut'=>'Status', 'u.note'=>"Text", 'u.signature'=>"Text", 'u.datelastlogin'=>'Date',
'u.fk_user'=>"List:user:login", 'u.fk_user'=>"List:user:login",
'u.birth'=>'Date', 'u.birth'=>'Date',
'u.datepreviouslogin'=>'Date', 'u.fk_soc'=>"List:societe:nom:rowid", 'u.fk_member'=>"List:adherent:firstname", 'u.datepreviouslogin'=>'Date', 'u.fk_soc'=>"List:societe:nom:rowid", 'u.fk_member'=>"List:adherent:firstname",

View File

@ -388,16 +388,17 @@ if ($step == 4 && $action == 'submitFormField') {
$_SESSION["export_filtered_fields"] = array(); $_SESSION["export_filtered_fields"] = array();
foreach ($objexport->array_export_TypeFields[0] as $code => $type) { // $code: s.fieldname $value: Text|Boolean|List:ccc foreach ($objexport->array_export_TypeFields[0] as $code => $type) { // $code: s.fieldname $value: Text|Boolean|List:ccc
$newcode = (string) preg_replace('/\./', '_', $code); $newcode = (string) preg_replace('/\./', '_', $code);
//print 'xxx'.$code."=".$newcode."=".$type."=".$_POST[$newcode]."\n<br>"; //print 'xxx '.$code."=".$newcode."=".$type."=".$_POST[$newcode]."\n<br>";
$check = 'alphanohtml';
$filterqualified = 1; $filterqualified = 1;
if (!GETPOSTISSET($newcode) || GETPOST($newcode, 'restricthtml') == '') { if (!GETPOSTISSET($newcode) || GETPOST($newcode, $check) == '') {
$filterqualified = 0; $filterqualified = 0;
} elseif (preg_match('/^List/', $type) && (is_numeric(GETPOST($newcode, 'restricthtml')) && GETPOST($newcode, 'restricthtml') <= 0)) { } elseif (preg_match('/^List/', $type) && (is_numeric(GETPOST($newcode, $check)) && GETPOST($newcode, $check) <= 0)) {
$filterqualified = 0; $filterqualified = 0;
} }
if ($filterqualified) { if ($filterqualified) {
//print 'Filter on '.$newcode.' type='.$type.' value='.$_POST[$newcode]."\n"; //print 'Filter on '.$newcode.' type='.$type.' value='.$_POST[$newcode]."\n";
$objexport->array_export_FilterValue[0][$code] = GETPOST($newcode, 'restricthtml'); $objexport->array_export_FilterValue[0][$code] = GETPOST($newcode, $check);
} }
} }
$array_filtervalue = (!empty($objexport->array_export_FilterValue[0]) ? $objexport->array_export_FilterValue[0] : ''); $array_filtervalue = (!empty($objexport->array_export_FilterValue[0]) ? $objexport->array_export_FilterValue[0] : '');

View File

@ -622,10 +622,11 @@ if ($id > 0 || !empty($ref)) {
// if ($mesg) print $mesg; // if ($mesg) print $mesg;
print '<br>'; print '<br>';
$disabled = 1; /*$disabled = 1;
if (!empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) { if (!empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) {
$disabled = 0; $disabled = 0;
} }*/
$disabled = 0; // This is used to disable or not the bulk selection of target warehouse. No reason to have it disabled so forced to 0.
// Line of orders // Line of orders
if ($object->statut <= CommandeFournisseur::STATUS_ACCEPTED || $object->statut >= CommandeFournisseur::STATUS_CANCELED) { if ($object->statut <= CommandeFournisseur::STATUS_ACCEPTED || $object->statut >= CommandeFournisseur::STATUS_CANCELED) {

View File

@ -309,8 +309,8 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
$filelist = array(); $filelist = array();
$i = 0; $i = 0;
$ok = 0; $ok = 0;
$from = '^'.$newversionfrom; $from = '^'.preg_quote($newversionfrom, '/');
$to = $newversionto.'\.sql$'; $to = preg_quote($newversionto.'.sql', '/').'$';
// Get files list // Get files list
$filesindir = array(); $filesindir = array();
@ -328,9 +328,9 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
// Define which file to run // Define which file to run
foreach ($filesindir as $file) { foreach ($filesindir as $file) {
if (preg_match('/'.$from.'/i', $file)) { if (preg_match('/'.$from.'\-/i', $file)) {
$filelist[] = $file; $filelist[] = $file;
} elseif (preg_match('/'.$to.'/i', $file)) { // First test may be false if we migrate from x.y.* to x.y.* } elseif (preg_match('/\-'.$to.'/i', $file)) { // First test may be false if we migrate from x.y.* to x.y.*
$filelist[] = $file; $filelist[] = $file;
} }
} }

View File

@ -52,3 +52,6 @@ BlockedLogDisableNotAllowedForCountry=List of countries where usage of this modu
OnlyNonValid=Non-valid OnlyNonValid=Non-valid
TooManyRecordToScanRestrictFilters=Too many records to scan/analyze. Please restrict list with more restrictive filters. TooManyRecordToScanRestrictFilters=Too many records to scan/analyze. Please restrict list with more restrictive filters.
RestrictYearToExport=Restrict month / year to export RestrictYearToExport=Restrict month / year to export
BlockedLogEnabled=System to track events into unalterable logs has been enabled
BlockedLogDisabled=System to track events into unalterable logs has been disabled after some recording were done. We saved a special Fingerprint to track the chain as broken
BlockedLogDisabledBis=System to track events into unalterable logs has been disabled. This is possible because no record were done yet.

View File

@ -1278,22 +1278,30 @@ if (!$action || $action == 'delete' || $action == 'showlog_customer_price' || $a
if (empty($conf->global->PRODUIT_MULTIPRICES) && empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) { if (empty($conf->global->PRODUIT_MULTIPRICES) && empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
if ($user->rights->produit->creer || $user->rights->service->creer) { if ($user->rights->produit->creer || $user->rights->service->creer) {
print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?action=edit_price&token='.newToken().'&id=' . $object->id . '">' . $langs->trans("UpdateDefaultPrice") . '</a></div>'; print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?action=edit_price&token='.newToken().'&id=' . $object->id . '">' . $langs->trans("UpdateDefaultPrice") . '</a></div>';
} else {
print '<div class="inline-block divButAction"><span class="butActionRefused" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">' . $langs->trans("UpdateDefaultPrice") . '</span></div>';
} }
} }
if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) { if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
if ($user->rights->produit->creer || $user->rights->service->creer) { if ($user->rights->produit->creer || $user->rights->service->creer) {
print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?action=add_customer_price&token='.newToken().'token='.newToken().'&id=' . $object->id . '">' . $langs->trans("AddCustomerPrice") . '</a></div>'; print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?action=add_customer_price&token='.newToken().'token='.newToken().'&id=' . $object->id . '">' . $langs->trans("AddCustomerPrice") . '</a></div>';
} else {
print '<div class="inline-block divButAction"><span class="butActionRefused" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">' . $langs->trans("AddCustomerPrice") . '</span></div>';
} }
} }
if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) { if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
if ($user->rights->produit->creer || $user->rights->service->creer) { if ($user->rights->produit->creer || $user->rights->service->creer) {
print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?action=edit_vat&token='.newToken().'&id=' . $object->id . '">' . $langs->trans("UpdateVAT") . '</a></div>'; print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?action=edit_vat&token='.newToken().'&id=' . $object->id . '">' . $langs->trans("UpdateVAT") . '</a></div>';
} else {
print '<div class="inline-block divButAction"><span class="butActionRefused" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">' . $langs->trans("UpdateVAT") . '</span></div>';
} }
if ($user->rights->produit->creer || $user->rights->service->creer) { if ($user->rights->produit->creer || $user->rights->service->creer) {
print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?action=edit_price&token='.newToken().'&id=' . $object->id . '">' . $langs->trans("UpdateLevelPrices") . '</a></div>'; print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?action=edit_price&token='.newToken().'&id=' . $object->id . '">' . $langs->trans("UpdateLevelPrices") . '</a></div>';
} else {
print '<div class="inline-block divButAction"><span class="butActionRefused" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">' . $langs->trans("UpdateLevelPrices") . '</span></div>';
} }
} }
} }

View File

@ -1048,9 +1048,17 @@ if ($action == 'create') {
print "</tr>\n"; print "</tr>\n";
} }
// $objectsrc->lines contains the line of the purchase order
// $dispatchLines is list of lines with dispatching detail (with product, qty and warehouse). One purchase order line may have n of this dispatch lines.
$arrayofpurchaselinealreadyoutput= array();
// $_POST contains fk_commandefourndet_X_Y where Y is num of product line and X is number of splitted line
$indiceAsked = 1; $indiceAsked = 1;
while ($indiceAsked <= $numAsked) { while ($indiceAsked <= $numAsked) { // Loop on $dispatchLines. Warning: $dispatchLines must be sorted by fk_commandefourndet (it is a regroupment key on output)
$product = new Product($db); $product = new Product($db);
// We search the purchase order line that is linked to the dispatchLines
foreach ($objectsrc->lines as $supplierLine) { foreach ($objectsrc->lines as $supplierLine) {
if ($dispatchLines[$indiceAsked]['fk_commandefourndet'] == $supplierLine->id) { if ($dispatchLines[$indiceAsked]['fk_commandefourndet'] == $supplierLine->id) {
$line = $supplierLine; $line = $supplierLine;
@ -1072,7 +1080,6 @@ if ($action == 'create') {
print '<!-- line fk_commandefourndet='.$line->id.' for product='.$line->fk_product.' -->'."\n"; print '<!-- line fk_commandefourndet='.$line->id.' for product='.$line->fk_product.' -->'."\n";
print '<tr class="oddeven">'."\n"; print '<tr class="oddeven">'."\n";
// Product label // Product label
if ($line->fk_product > 0) { // If predefined product if ($line->fk_product > 0) { // If predefined product
$product->fetch($line->fk_product); $product->fetch($line->fk_product);
@ -1081,42 +1088,45 @@ if ($action == 'create') {
print '<td>'; print '<td>';
print '<a name="'.$line->id.'"></a>'; // ancre pour retourner sur la ligne print '<a name="'.$line->id.'"></a>'; // ancre pour retourner sur la ligne
print '<input type="hidden" name="productid'.$indiceAsked.'" value="'.$line->fk_product.'">'; if (! array_key_exists($line->id, $arrayofpurchaselinealreadyoutput)) { // Add test to avoid to show qty twice
print '<input type="hidden" name="productid'.$indiceAsked.'" value="'.$line->fk_product.'">';
// Show product and description // Show product and description
$product_static = $product; $product_static = $product;
$text = $product_static->getNomUrl(1); $text = $product_static->getNomUrl(1);
$text .= ' - '.(!empty($line->label) ? $line->label : $line->product_label); $text .= ' - '.(!empty($line->label) ? $line->label : $line->product_label);
$description = ($conf->global->PRODUIT_DESC_IN_FORM ? '' : dol_htmlentitiesbr($line->desc)); $description = ($conf->global->PRODUIT_DESC_IN_FORM ? '' : dol_htmlentitiesbr($line->desc));
print $form->textwithtooltip($text, $description, 3, '', '', $i); print $form->textwithtooltip($text, $description, 3, '', '', $i);
// Show range // Show range
print_date_range($db->jdate($line->date_start), $db->jdate($line->date_end)); print_date_range($db->jdate($line->date_start), $db->jdate($line->date_end));
// Add description in form // Add description in form
if (!empty($conf->global->PRODUIT_DESC_IN_FORM)) { if (!empty($conf->global->PRODUIT_DESC_IN_FORM)) {
print ($line->desc && $line->desc != $line->product_label) ? '<br>'.dol_htmlentitiesbr($line->desc) : ''; print ($line->desc && $line->desc != $line->product_label) ? '<br>'.dol_htmlentitiesbr($line->desc) : '';
}
} }
print '</td>'; print '</td>';
} else { } else {
print "<td>"; print "<td>";
if ($type == 1) { if (! array_key_exists($line->id, $arrayofpurchaselinealreadyoutput)) { // Add test to avoid to show qty twice
$text = img_object($langs->trans('Service'), 'service'); if ($type == 1) {
} else { $text = img_object($langs->trans('Service'), 'service');
$text = img_object($langs->trans('Product'), 'product'); } else {
} $text = img_object($langs->trans('Product'), 'product');
}
if (!empty($line->label)) { if (!empty($line->label)) {
$text .= ' <strong>'.$line->label.'</strong>'; $text .= ' <strong>'.$line->label.'</strong>';
print $form->textwithtooltip($text, $line->desc, 3, '', '', $i); print $form->textwithtooltip($text, $line->desc, 3, '', '', $i);
} else { } else {
print $text.' '.nl2br($line->desc); print $text.' '.nl2br($line->desc);
} }
// Show range // Show range
print_date_range($db->jdate($line->date_start), $db->jdate($line->date_end)); print_date_range($db->jdate($line->date_start), $db->jdate($line->date_end));
}
print "</td>\n"; print "</td>\n";
} }
@ -1127,8 +1137,11 @@ if ($action == 'create') {
print '<input type="text" class="maxwidth100" name="comment'.$indiceAsked.'" value="'.$defaultcomment.'">'; print '<input type="text" class="maxwidth100" name="comment'.$indiceAsked.'" value="'.$defaultcomment.'">';
print '</td>'; print '</td>';
// Qty // Qty in source purchase order line
print '<td class="center">'.$line->qty; print '<td class="center">';
if (! array_key_exists($line->id, $arrayofpurchaselinealreadyoutput)) { // Add test to avoid to show qty twice
print $line->qty;
}
print '<input type="hidden" name="fk_commandefournisseurdet'.$indiceAsked.'" value="'.$line->id.'">'; print '<input type="hidden" name="fk_commandefournisseurdet'.$indiceAsked.'" value="'.$line->id.'">';
print '<input type="hidden" name="pul'.$indiceAsked.'" value="'.$line->pu_ht.'">'; print '<input type="hidden" name="pul'.$indiceAsked.'" value="'.$line->pu_ht.'">';
print '<input name="qtyasked'.$indiceAsked.'" id="qtyasked'.$indiceAsked.'" type="hidden" value="'.$line->qty.'">'; print '<input name="qtyasked'.$indiceAsked.'" id="qtyasked'.$indiceAsked.'" type="hidden" value="'.$line->qty.'">';
@ -1138,7 +1151,9 @@ if ($action == 'create') {
// Qty already received // Qty already received
print '<td class="center">'; print '<td class="center">';
$quantityDelivered = $objectsrc->receptions[$line->id]; $quantityDelivered = $objectsrc->receptions[$line->id];
print $quantityDelivered; if (! array_key_exists($line->id, $arrayofpurchaselinealreadyoutput)) { // Add test to avoid to show qty twice
print $quantityDelivered;
}
print '<input name="qtydelivered'.$indiceAsked.'" id="qtydelivered'.$indiceAsked.'" type="hidden" value="'.$quantityDelivered.'">'; print '<input name="qtydelivered'.$indiceAsked.'" id="qtydelivered'.$indiceAsked.'" type="hidden" value="'.$quantityDelivered.'">';
print '</td>'; print '</td>';
@ -1214,6 +1229,9 @@ if ($action == 'create') {
} }
} }
} }
$arrayofpurchaselinealreadyoutput[$line->id] = $line->id;
print "</tr>\n"; print "</tr>\n";
$extralabelslines = $extrafields->attributes[$line->table_element]; $extralabelslines = $extrafields->attributes[$line->table_element];
@ -1775,7 +1793,9 @@ if ($action == 'create') {
//var_dump($alreadysent); //var_dump($alreadysent);
} }
// Loop on each product to send/sent $arrayofpurchaselinealreadyoutput = array();
// Loop on each product to send/sent. Warning: $lines must be sorted by ->fk_commandefourndet (it is a regroupment key on output)
for ($i = 0; $i < $num_prod; $i++) { for ($i = 0; $i < $num_prod; $i++) {
print '<!-- origin line id = '.(!empty($lines[$i]->origin_line_id) ? $lines[$i]->origin_line_id : 0).' -->'; // id of order line print '<!-- origin line id = '.(!empty($lines[$i]->origin_line_id) ? $lines[$i]->origin_line_id : 0).' -->'; // id of order line
print '<tr class="oddeven">'; print '<tr class="oddeven">';
@ -1797,32 +1817,35 @@ if ($action == 'create') {
} }
print '<td>'; print '<td>';
if (!array_key_exists($lines[$i]->fk_commandefourndet, $arrayofpurchaselinealreadyoutput)) {
$text = $lines[$i]->product->getNomUrl(1); $text = $lines[$i]->product->getNomUrl(1);
$text .= ' - '.$label; $text .= ' - '.$label;
$description = (!empty($conf->global->PRODUIT_DESC_IN_FORM) ? '' : dol_htmlentitiesbr($lines[$i]->product->description)); $description = (!empty($conf->global->PRODUIT_DESC_IN_FORM) ? '' : dol_htmlentitiesbr($lines[$i]->product->description));
print $form->textwithtooltip($text, $description, 3, '', '', $i); print $form->textwithtooltip($text, $description, 3, '', '', $i);
print_date_range(!empty($lines[$i]->date_start) ? $lines[$i]->date_start : 0, !empty($lines[$i]->date_end) ? $lines[$i]->date_end : 0); print_date_range(!empty($lines[$i]->date_start) ? $lines[$i]->date_start : 0, !empty($lines[$i]->date_end) ? $lines[$i]->date_end : 0);
if (!empty($conf->global->PRODUIT_DESC_IN_FORM)) { if (!empty($conf->global->PRODUIT_DESC_IN_FORM)) {
print (!empty($lines[$i]->product->description) && $lines[$i]->description != $lines[$i]->product->description) ? '<br>'.dol_htmlentitiesbr($lines[$i]->description) : ''; print (!empty($lines[$i]->product->description) && $lines[$i]->description != $lines[$i]->product->description) ? '<br>'.dol_htmlentitiesbr($lines[$i]->description) : '';
}
} }
print "</td>\n"; print "</td>\n";
} else { } else {
print "<td>"; print "<td>";
if ($lines[$i]->product_type == Product::TYPE_SERVICE) { if (!array_key_exists($lines[$i]->fk_commandefourndet, $arrayofpurchaselinealreadyoutput)) {
$text = img_object($langs->trans('Service'), 'service'); if ($lines[$i]->product_type == Product::TYPE_SERVICE) {
} else { $text = img_object($langs->trans('Service'), 'service');
$text = img_object($langs->trans('Product'), 'product'); } else {
} $text = img_object($langs->trans('Product'), 'product');
}
if (!empty($lines[$i]->label)) { if (!empty($lines[$i]->label)) {
$text .= ' <strong>'.$lines[$i]->label.'</strong>'; $text .= ' <strong>'.$lines[$i]->label.'</strong>';
print $form->textwithtooltip($text, $lines[$i]->description, 3, '', '', $i); print $form->textwithtooltip($text, $lines[$i]->description, 3, '', '', $i);
} else { } else {
print $text.' '.nl2br($lines[$i]->description); print $text.' '.nl2br($lines[$i]->description);
} }
print_date_range($lines[$i]->date_start, $lines[$i]->date_end); print_date_range($lines[$i]->date_start, $lines[$i]->date_end);
}
print "</td>\n"; print "</td>\n";
} }
@ -1834,33 +1857,39 @@ if ($action == 'create') {
// Qty ordered // Qty ordered
print '<td class="center">'.$lines[$i]->qty_asked.'</td>'; print '<td class="center">';
if (!array_key_exists($lines[$i]->fk_commandefourndet, $arrayofpurchaselinealreadyoutput)) {
print $lines[$i]->qty_asked;
}
print '</td>';
// Qty in other receptions (with reception and warehouse used) // Qty in other receptions (with reception and warehouse used)
if ($origin && $origin_id > 0) { if ($origin && $origin_id > 0) {
print '<td class="center nowrap">'; print '<td class="center nowrap">';
foreach ($alreadysent as $key => $val) { if (!array_key_exists($lines[$i]->fk_commandefourndet, $arrayofpurchaselinealreadyoutput)) {
if ($lines[$i]->fk_commandefourndet == $key) { foreach ($alreadysent as $key => $val) {
$j = 0; if ($lines[$i]->fk_commandefourndet == $key) {
foreach ($val as $receptionline_id => $receptionline_var) { $j = 0;
if ($receptionline_var['reception_id'] == $lines[$i]->fk_reception) { foreach ($val as $receptionline_id => $receptionline_var) {
continue; // We want to show only "other receptions" if ($receptionline_var['reception_id'] == $lines[$i]->fk_reception) {
} continue; // We want to show only "other receptions"
}
$j++; $j++;
if ($j > 1) { if ($j > 1) {
print '<br>'; print '<br>';
} }
$reception_static->fetch($receptionline_var['reception_id']); $reception_static->fetch($receptionline_var['reception_id']);
print $reception_static->getNomUrl(1); print $reception_static->getNomUrl(1);
print ' - '.$receptionline_var['qty']; print ' - '.$receptionline_var['qty'];
$htmltext = $langs->trans("DateValidation").' : '.(empty($receptionline_var['date_valid']) ? $langs->trans("Draft") : dol_print_date($receptionline_var['date_valid'], 'dayhour')); $htmltext = $langs->trans("DateValidation").' : '.(empty($receptionline_var['date_valid']) ? $langs->trans("Draft") : dol_print_date($receptionline_var['date_valid'], 'dayhour'));
if (!empty($conf->stock->enabled) && $receptionline_var['warehouse'] > 0) { if (!empty($conf->stock->enabled) && $receptionline_var['warehouse'] > 0) {
$warehousestatic->fetch($receptionline_var['warehouse']); $warehousestatic->fetch($receptionline_var['warehouse']);
$htmltext .= '<br>'.$langs->trans("From").' : '.$warehousestatic->getNomUrl(1, '', 0, 1); $htmltext .= '<br>'.$langs->trans("From").' : '.$warehousestatic->getNomUrl(1, '', 0, 1);
}
print ' '.$form->textwithpicto('', $htmltext, 1);
} }
print ' '.$form->textwithpicto('', $htmltext, 1);
} }
} }
} }
@ -1990,6 +2019,8 @@ if ($action == 'create') {
} }
print "</tr>"; print "</tr>";
$arrayofpurchaselinealreadyoutput[$lines[$i]->fk_commandefourndet] = $lines[$i]->fk_commandefourndet;
// Display lines extrafields // Display lines extrafields
$extralabelslines = $extrafields->attributes[$lines[$i]->table_element]; $extralabelslines = $extrafields->attributes[$lines[$i]->table_element];
if (!empty($extralabelslines) && is_array($extralabelslines) && count($extralabelslines) > 0) { if (!empty($extralabelslines) && is_array($extralabelslines) && count($extralabelslines) > 0) {

View File

@ -359,7 +359,7 @@ class SecurityTest extends PHPUnit\Framework\TestCase
$_POST['param8b']='<img src=x onerror=alert(document.location) t='; // this is html obfuscated by non closing tag $_POST['param8b']='<img src=x onerror=alert(document.location) t='; // this is html obfuscated by non closing tag
$_POST['param8c']='< with space after is ok'; $_POST['param8c']='< with space after is ok';
$_POST['param8d']='<abc123 is html to clean'; $_POST['param8d']='<abc123 is html to clean';
$_POST['param8e']='<123abc is not html to clean'; $_POST['param8e']='<123abc is not html to clean'; // other similar case: '<2021-12-12'
$_POST['param8f']='abc<<svg <><<animate onbegin=alert(document.domain) a'; $_POST['param8f']='abc<<svg <><<animate onbegin=alert(document.domain) a';
$_POST["param9"]='is_object($object) ? ($object->id < 10 ? round($object->id / 2, 2) : (2 * $user->id) * (int) substr($mysoc->zip, 1, 2)) : \'objnotdefined\''; $_POST["param9"]='is_object($object) ? ($object->id < 10 ? round($object->id / 2, 2) : (2 * $user->id) * (int) substr($mysoc->zip, 1, 2)) : \'objnotdefined\'';
$_POST["param10"]='is_object($object) ? ($object->id < 10 ? round($object->id / 2, 2) : (2 * $user->id) * (int) substr($mysoc->zip, 1, 2)) : \'<abc>objnotdefined\''; $_POST["param10"]='is_object($object) ? ($object->id < 10 ? round($object->id / 2, 2) : (2 * $user->id) * (int) substr($mysoc->zip, 1, 2)) : \'<abc>objnotdefined\'';
@ -501,6 +501,10 @@ class SecurityTest extends PHPUnit\Framework\TestCase
print __METHOD__." result param7 = ".$result."\n"; print __METHOD__." result param7 = ".$result."\n";
$this->assertEquals('"c:\this is a path~1\aaan &#x;;;;" abcdef', $result); $this->assertEquals('"c:\this is a path~1\aaan &#x;;;;" abcdef', $result);
$result=GETPOST("param8e", 'restricthtml');
print __METHOD__." result param8e = ".$result."\n";
$this->assertEquals('', $result);
$result=GETPOST("param12", 'restricthtml'); $result=GETPOST("param12", 'restricthtml');
print __METHOD__." result=".$result."\n"; print __METHOD__." result=".$result."\n";
$this->assertEquals(trim($_POST["param12"]), $result, 'Test a string with DOCTYPE and restricthtml'); $this->assertEquals(trim($_POST["param12"]), $result, 'Test a string with DOCTYPE and restricthtml');
@ -519,7 +523,7 @@ class SecurityTest extends PHPUnit\Framework\TestCase
$result=GETPOST("param15", 'restricthtml'); // <img onerror<=alert(document.domain)> src=>0xbeefed $result=GETPOST("param15", 'restricthtml'); // <img onerror<=alert(document.domain)> src=>0xbeefed
print __METHOD__." result=".$result."\n"; print __METHOD__." result=".$result."\n";
$this->assertEquals("<img onerror=alert(document.domain) src=>0xbeefed", $result, 'Test 15a'); // The GETPOST return a harmull string $this->assertEquals("<img onerror=alert(document.domain) src=>0xbeefed", $result, 'Test 15'); // The GETPOST return a harmull string
// Test with restricthtml + MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES to test disabling of bad atrributes // Test with restricthtml + MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES to test disabling of bad atrributes
$conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML = 1; $conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML = 1;