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

This commit is contained in:
Laurent Destailleur 2022-09-14 17:26:20 +02:00
commit 35d8320328
15 changed files with 111 additions and 44 deletions

View File

@ -384,15 +384,16 @@ if ($mode == 'feature') {
$text .= '<br><br>';
$text .= '<br><strong>'.$langs->trans("AddDataTables").':</strong> ';
$sqlfiles = dol_dir_list(dol_buildpath($moduledir.'/sql/'), 'files', 0, 'llx.*\.sql', array('\.key\.sql', '\.sql\.back'));
$listofsqlfiles1 = dol_dir_list(DOL_DOCUMENT_ROOT.'/install/mysql/tables/', 'files', 0, 'llx.*-'.$moduledir.'\.sql', array('\.key\.sql', '\.sql\.back'));
$listofsqlfiles2 = dol_dir_list(dol_buildpath($moduledir.'/sql/'), 'files', 0, 'llx.*\.sql', array('\.key\.sql', '\.sql\.back'));
$sqlfiles = array_merge($listofsqlfiles1, $listofsqlfiles2);
if (count($sqlfiles) > 0) {
$text .= $langs->trans("Yes").' (';
$i = 0;
foreach ($sqlfiles as $val) {
$text .= ($i ? ', ' : '').preg_replace('/\.sql$/', '', preg_replace('/llx_/', '', $val['name']));
$text .= ($i ? ', ' : '').preg_replace('/\-'.$moduledir.'$/', '', preg_replace('/\.sql$/', '', preg_replace('/llx_/', '', $val['name'])));
$i++;
}
$text .= ')';
} else {
$text .= $langs->trans("No");
}
@ -415,7 +416,7 @@ if ($mode == 'feature') {
$text .= '<br><strong>'.$langs->trans("AddData").':</strong> ';
$filedata = dol_buildpath($moduledir.'/sql/data.sql');
if (dol_is_file($filedata)) {
$text .= $langs->trans("Yes").' ('.$moduledir.'/sql/data.sql)';
$text .= $langs->trans("Yes").' <span class="opacitymedium">('.$moduledir.'/sql/data.sql)</span>';
} else {
$text .= $langs->trans("No");
}

View File

@ -182,9 +182,18 @@ interface Database
*
* @param string $stringtoencode String to escape
* @return string String escaped
* @deprecated
*/
public function escapeunderscore($stringtoencode);
/**
* Escape a string to insert data into a like
*
* @param string $stringtoencode String to escape
* @return string String escaped
*/
public function escapeforlike($stringtoencode);
/**
* Sanitize a string for SQL forging
*

View File

@ -479,12 +479,24 @@ class DoliDBMysqli extends DoliDB
*
* @param string $stringtoencode String to escape
* @return string String escaped
* @deprecated
*/
public function escapeunderscore($stringtoencode)
{
return str_replace('_', '\_', (string) $stringtoencode);
}
/**
* Escape a string to insert data into a like
*
* @param string $stringtoencode String to escape
* @return string String escaped
*/
public function escapeforlike($stringtoencode)
{
return str_replace(array('_', '\\', '%'), array('\_', '\\\\', '\%'), (string) $stringtoencode);
}
/**
* Return generic error code of last operation.
*

View File

@ -726,10 +726,22 @@ class DoliDBPgsql extends DoliDB
*
* @param string $stringtoencode String to escape
* @return string String escaped
* @deprecated
*/
public function escapeunderscore($stringtoencode)
{
return str_replace('_', '\_', $stringtoencode);
return str_replace('_', '\_', (string) $stringtoencode);
}
/**
* Escape a string to insert data into a like
*
* @param string $stringtoencode String to escape
* @return string String escaped
*/
public function escapeforlike($stringtoencode)
{
return str_replace(array('_', '\\', '%'), array('\_', '\\\\', '\%'), (string) $stringtoencode);
}
/**

View File

@ -654,10 +654,22 @@ class DoliDBSqlite3 extends DoliDB
*
* @param string $stringtoencode String to escape
* @return string String escaped
* @deprecated
*/
public function escapeunderscore($stringtoencode)
{
return str_replace('_', '\_', $stringtoencode);
return str_replace('_', '\_', (string) $stringtoencode);
}
/**
* Escape a string to insert data into a like
*
* @param string $stringtoencode String to escape
* @return string String escaped
*/
public function escapeforlike($stringtoencode)
{
return str_replace(array('_', '\\', '%'), array('\_', '\\\\', '\%'), (string) $stringtoencode);
}
/**

View File

@ -996,11 +996,11 @@ function getPagesFromSearchCriterias($type, $algo, $searchstring, $max = 25, $so
$sql .= " AND (";
$searchalgo = '';
if (preg_match('/meta/', $algo)) {
$searchalgo .= ($searchalgo ? ' OR ' : '')."wp.title LIKE '%".$db->escapeunderscore($db->escape($searchstring))."%' OR wp.description LIKE '%".$db->escapeunderscore($db->escape($searchstring))."%'";
$searchalgo .= ($searchalgo ? ' OR ' : '')."wp.keywords LIKE '".$db->escapeunderscore($db->escape($searchstring)).",%' OR wp.keywords LIKE '% ".$db->escapeunderscore($db->escape($searchstring))."%'"; // TODO Use a better way to scan keywords
$searchalgo .= ($searchalgo ? ' OR ' : '')."wp.title LIKE '%".$db->escapeforlike($db->escape($searchstring))."%' OR wp.description LIKE '%".$db->escapeforlike($db->escape($searchstring))."%'";
$searchalgo .= ($searchalgo ? ' OR ' : '')."wp.keywords LIKE '".$db->escapeforlike($db->escape($searchstring)).",%' OR wp.keywords LIKE '% ".$db->escapeforlike($db->escape($searchstring))."%'"; // TODO Use a better way to scan keywords
}
if (preg_match('/content/', $algo)) {
$searchalgo .= ($searchalgo ? ' OR ' : '')."wp.content LIKE '%".$db->escapeunderscore($db->escape($searchstring))."%'";
$searchalgo .= ($searchalgo ? ' OR ' : '')."wp.content LIKE '%".$db->escapeforlike($db->escape($searchstring))."%'";
}
$sql .= $searchalgo;
if (is_array($otherfilters) && !empty($otherfilters['category'])) {

View File

@ -835,8 +835,8 @@ class ImportCsv extends ModeleImports
$sqlSelect = "SELECT ".$fname." FROM ".$tablename;
$data = array_combine($listfields, $listvalues);
$where = array();
$filters = array();
$where = array(); // filters to forge SQL request
$filters = array(); // filters to forge output error message
foreach ($updatekeys as $key) {
$col = $objimport->array_import_updatekeys[0][$key];
$key = preg_replace('/^.*\./i', '', $key);
@ -846,8 +846,12 @@ class ImportCsv extends ModeleImports
$socialnetwork = $tmp[1];
$jsondata = $data[$key];
$json = json_decode($jsondata);
$where[] = $key." LIKE '%\"".$socialnetwork."\":\"".$this->db->escape($json->$socialnetwork)."\"%'";
$filters[] = $col." LIKE '%\"".$socialnetwork."\":\"".$this->db->escape($json->$socialnetwork)."\"%'";
$stringtosearch = json_encode($socialnetwork).':'.json_encode($json->$socialnetwork);
//var_dump($stringtosearch);
//var_dump($this->db->escape($stringtosearch)); // This provide a value for sql string (but not for a like)
$where[] = $key." LIKE '%".$this->db->escapeforlike($this->db->escape($stringtosearch))."%'";
$filters[] = $col." LIKE '%".$this->db->escapeforlike($this->db->escape($stringtosearch))."%'";
//var_dump($where[1]); // This provide a value for sql string inside a like
} else {
$where[] = $key.' = '.$data[$key];
$filters[] = $col.' = '.$data[$key];

View File

@ -892,8 +892,12 @@ class ImportXlsx extends ModeleImports
$socialnetwork = $tmp[1];
$jsondata = $data[$key];
$json = json_decode($jsondata);
$where[] = $key." LIKE '%\"".$socialnetwork."\":\"".$this->db->escape($json->$socialnetwork)."\"%'";
$filters[] = $col." LIKE '%\"".$socialnetwork."\":\"".$this->db->escape($json->$socialnetwork)."\"%'";
$stringtosearch = json_encode($socialnetwork).':'.json_encode($json->$socialnetwork);
//var_dump($stringtosearch);
//var_dump($this->db->escape($stringtosearch)); // This provide a value for sql string (but not for a like)
$where[] = $key." LIKE '%".$this->db->escapeforlike($this->db->escape($stringtosearch))."%'";
$filters[] = $col." LIKE '%".$this->db->escapeforlike($this->db->escape($stringtosearch))."%'";
//var_dump($where[1]); // This provide a value for sql string inside a like
} else {
$where[] = $key.' = '.$data[$key];
$filters[] = $col.' = '.$data[$key];

View File

@ -272,6 +272,24 @@ class modAccounting extends DolibarrModules
//--------
$r = 0;
// Chart of accounts
$r++;
$this->import_code[$r] = $this->rights_class.'_'.$r;
$this->import_label[$r] = "Chartofaccounts"; // Translation key
$this->import_icon[$r] = $this->picto;
$this->import_entities_array[$r] = array(); // We define here only fields that use another icon that the one defined into import_icon
$this->import_tables_array[$r] = array('aa'=>MAIN_DB_PREFIX.'accounting_account');
$this->import_tables_creator_array[$r] = array('aa'=>'fk_user_author'); // Fields to store import user id
$this->import_fields_array[$r] = array('aa.fk_pcg_version'=>"Chartofaccounts*", 'aa.account_number'=>"AccountAccounting*", 'aa.label'=>"Label*", 'aa.account_parent'=>"Accountparent", "aa.fk_accounting_category"=>"AccountingCategory", "aa.pcg_type"=>"Pcgtype*", 'aa.active'=>'Status*', 'aa.datec'=>"DateCreation");
$this->import_regex_array[$r] = array('aa.fk_pcg_version'=>'pcg_version@'.MAIN_DB_PREFIX.'accounting_system', 'aa.account_number'=>'^.{1,32}$', 'aa.label'=>'^.{1,255}$', 'aa.account_parent'=>'^.{0,32}$', 'aa.fk_accounting_category'=>'rowid@'.MAIN_DB_PREFIX.'c_accounting_category', 'aa.pcg_type'=>'^.{1,20}$', 'aa.active'=>'^0|1$', 'aa.datec'=>'^\d{4}-\d{2}-\d{2}$');
$this->import_convertvalue_array[$r] = array(
'aa.account_number'=>array('rule'=>'accountingaccount'),
'aa.account_parent'=>array('rule'=>'fetchidfromref', 'classfile'=>'/accountancy/class/accountingaccount.class.php', 'class'=>'AccountingAccount', 'method'=>'fetch', 'element'=>'AccountingAccount'),
'aa.fk_accounting_category'=>array('rule'=>'fetchidfromcodeorlabel', 'classfile'=>'/accountancy/class/accountancycategory.class.php', 'class'=>'AccountancyCategory', 'method'=>'fetch', 'dict'=>'DictionaryAccountancyCategory'),
);
$this->import_examplevalues_array[$r] = array('aa.fk_pcg_version'=>"PCG99-ABREGE", 'aa.account_number'=>"707", 'aa.label'=>"Product sales", 'aa.account_parent'=>"ref:7 or id:1407", "aa.fk_accounting_category"=>"", "aa.pcg_type"=>"PROD", 'aa.active'=>'1', 'aa.datec'=>"2017-04-28");
$this->import_updatekeys_array[$r] = array('aa.fk_pcg_version'=>'Chartofaccounts', 'aa.account_number'=>'AccountAccounting');
// General ledger
$r++;
$this->import_code[$r] = $this->rights_class.'_'.$r;
@ -393,23 +411,5 @@ class modAccounting extends DolibarrModules
'b.multicurrency_amount'=>"90 (Necessary if devise is different than EUR)",
'b.multicurrency_code'=>"US (Necessary if devise is different than EUR)",
);
// Chart of accounts
$r++;
$this->import_code[$r] = $this->rights_class.'_'.$r;
$this->import_label[$r] = "Chartofaccounts"; // Translation key
$this->import_icon[$r] = $this->picto;
$this->import_entities_array[$r] = array(); // We define here only fields that use another icon that the one defined into import_icon
$this->import_tables_array[$r] = array('aa'=>MAIN_DB_PREFIX.'accounting_account');
$this->import_tables_creator_array[$r] = array('aa'=>'fk_user_author'); // Fields to store import user id
$this->import_fields_array[$r] = array('aa.fk_pcg_version'=>"Chartofaccounts*", 'aa.account_number'=>"AccountAccounting*", 'aa.label'=>"Label*", 'aa.account_parent'=>"Accountparent", "aa.fk_accounting_category"=>"AccountingCategory", "aa.pcg_type"=>"Pcgtype*", 'aa.active'=>'Status*', 'aa.datec'=>"DateCreation");
$this->import_regex_array[$r] = array('aa.fk_pcg_version'=>'pcg_version@'.MAIN_DB_PREFIX.'accounting_system', 'aa.account_number'=>'^.{1,32}$', 'aa.label'=>'^.{1,255}$', 'aa.account_parent'=>'^.{0,32}$', 'aa.fk_accounting_category'=>'rowid@'.MAIN_DB_PREFIX.'c_accounting_category', 'aa.pcg_type'=>'^.{1,20}$', 'aa.active'=>'^0|1$', 'aa.datec'=>'^\d{4}-\d{2}-\d{2}$');
$this->import_convertvalue_array[$r] = array(
'aa.account_number'=>array('rule'=>'accountingaccount'),
'aa.account_parent'=>array('rule'=>'fetchidfromref', 'classfile'=>'/accountancy/class/accountingaccount.class.php', 'class'=>'AccountingAccount', 'method'=>'fetch', 'element'=>'AccountingAccount'),
'aa.fk_accounting_category'=>array('rule'=>'fetchidfromcodeorlabel', 'classfile'=>'/accountancy/class/accountancycategory.class.php', 'class'=>'AccountancyCategory', 'method'=>'fetch', 'dict'=>'DictionaryAccountancyCategory'),
);
$this->import_examplevalues_array[$r] = array('aa.fk_pcg_version'=>"PCG99-ABREGE", 'aa.account_number'=>"707", 'aa.label'=>"Product sales", 'aa.account_parent'=>"ref:7 or id:1407", "aa.fk_accounting_category"=>"", "aa.pcg_type"=>"PROD", 'aa.active'=>'1', 'aa.datec'=>"2017-04-28");
$this->import_updatekeys_array[$r] = array('aa.fk_pcg_version'=>'Chartofaccounts', 'aa.account_number'=>'AccountAccounting');
}
}

View File

@ -747,7 +747,7 @@ class modSociete extends DolibarrModules
's.fk_departement' => "StateCode",
's.fk_pays' => "CountryCode",
's.birthday' => "DateOfBirth",
's.poste' => "Role",
's.poste' => "PostOrFunction",
's.phone' => "Phone",
's.phone_perso' => "PhonePerso",
's.phone_mobile' => "PhoneMobile",

View File

@ -255,12 +255,24 @@ class TraceableDB extends DoliDB
*
* @param string $stringtoencode String to escape
* @return string String escaped
* @deprecated
*/
public function escapeunderscore($stringtoencode)
{
return $this->db->escapeunderscore($stringtoencode);
}
/**
* Escape a string to insert data into a like
*
* @param string $stringtoencode String to escape
* @return string String escaped
*/
public function escapeforlike($stringtoencode)
{
return str_replace(array('_', '\\', '%'), array('\_', '\\\\', '\%'), (string) $stringtoencode);
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Get last ID after an insert INSERT

View File

@ -235,6 +235,7 @@ if ($action == 'add_import_model') {
$result = $objimport->create($user);
if ($result >= 0) {
setEventMessages($langs->trans("ImportModelSaved", $objimport->model_name), null, 'mesgs');
$import_name = '';
} else {
$langs->load("errors");
if ($objimport->errno == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
@ -1286,7 +1287,7 @@ if ($step == 4 && $datatoimport) {
print '</td></tr>';
// Lines for remark
print '<tr class="liste_titre"><td colspan="2">'.$langs->trans("Remark").'</td></tr>';
print '<tr class="liste_titre"><td colspan="2">'.$langs->trans("Note").'</td></tr>';
print '<tr><td colspan="2"><div id="div-mandatory-target-fields-not-mapped"></div></td></tr>';
print '</table>';
@ -1470,8 +1471,8 @@ if ($step == 4 && $datatoimport) {
print '</tr>';
$nameofimportprofile = str_replace(' ', '-', $langs->trans("ImportProfile").' '.$titleofmodule.' '.dol_print_date(dol_now('gmt'), 'dayxcard'));
if (is_object($objimport) && !empty($objimport->model_name)) {
$nameofimportprofile = $objimport->model_name;
if (GETPOST('import_name')) { // If we have submited a form, we take value used fot the update try
$nameofimportprofile = $import_name;
}
print '<tr class="oddeven">';
@ -1966,9 +1967,9 @@ if ($step == 5 && $datatoimport) {
print '<div class="center">';
print '<span class="opacitymedium">'.$langs->trans("NowClickToRunTheImport", $langs->transnoentitiesnoconv("RunImportFile")).'</span><br>';
if (empty($nboferrors)) {
/*if (empty($nboferrors)) {
print $langs->trans("DataLoadedWithId", $importid).'<br>';
}
}*/
print '</div>';
print '<br>';

View File

@ -559,7 +559,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
// Contract refused / accepted
if ($object->status == $object::STATUS_CONTRACT_PROPOSED) {
if ($permissiontoadd) {
print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=closeas">'.$langs->trans("Accept").' / '.$langs->trans("Decline").'</a>';
print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=closeas&token='.newToken().'">'.$langs->trans("Accept").' / '.$langs->trans("Decline").'</a>';
}
}

View File

@ -426,7 +426,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
// Close as recruited/canceled
if ($object->status == $object::STATUS_VALIDATED) {
if ($usercanclose) {
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=closeas'.(empty($conf->global->MAIN_JUMP_TAG) ? '' : '#close').'"';
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=closeas&token='.newToken().(empty($conf->global->MAIN_JUMP_TAG) ? '' : '#close').'"';
print '>'.$langs->trans('Close').'</a>';
} else {
print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">'.$langs->trans('Close').'</a>';

View File

@ -684,8 +684,8 @@ function Search2(keyCodeForEnter, moreorless) {
console.log("There is only 1 answer with barcode matching the search, so we change the thirdparty "+data[0]['rowid']);
ChangeThirdparty(data[0]['rowid']);
}
else if ('product' == data[0]['object']) {
console.log("There is only 1 answer matching the search, so we add the product in basket, qty="+data[0]['qty']);
else if ($('#search').val() == data[0]['barcode'] && 'product' == data[0]['object']) {
console.log("There is only 1 answer and we found search on a barcode, so we add the product in basket, qty="+data[0]['qty']);
ClickProduct(0, data[0]['qty']);
}
}