From 156922fc51ff9b273940d191df360ab788f27f16 Mon Sep 17 00:00:00 2001 From: FLIO Date: Tue, 14 Feb 2023 14:09:56 +0100 Subject: [PATCH 001/105] Fix (qodana) Incompatible return type --- htdocs/accountancy/class/bookkeeping.class.php | 2 +- htdocs/commande/class/api_orders.class.php | 2 +- htdocs/commande/class/commande.class.php | 2 +- htdocs/contact/class/contact.class.php | 2 +- htdocs/contrat/class/contrat.class.php | 2 +- htdocs/debugbar/class/DataCollector/DolLogsCollector.php | 2 +- htdocs/debugbar/class/DataCollector/DolRequestDataCollector.php | 2 +- htdocs/expensereport/class/expensereport.class.php | 2 +- htdocs/holiday/class/holiday.class.php | 2 +- htdocs/install/upgrade2.php | 2 +- .../core/modules/mymodule/doc/pdf_standard_myobject.modules.php | 2 +- htdocs/product/class/productbatch.class.php | 2 +- htdocs/product/dynamic_price/class/price_expression.class.php | 2 +- .../product/dynamic_price/class/price_global_variable.class.php | 2 +- htdocs/product/stock/class/productstockentrepot.class.php | 2 +- htdocs/projet/class/api_tasks.class.php | 2 +- .../doc/pdf_standard_recruitmentjobposition.modules.php | 2 +- htdocs/resource/class/html.formresource.class.php | 2 +- htdocs/ticket/class/ticket.class.php | 2 +- htdocs/webservices/server_order.php | 2 +- htdocs/webservices/server_other.php | 2 +- htdocs/webservices/server_project.php | 2 +- htdocs/zapier/class/api_zapier.class.php | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/htdocs/accountancy/class/bookkeeping.class.php b/htdocs/accountancy/class/bookkeeping.class.php index 897f60e8aaa..7e2cdc56543 100644 --- a/htdocs/accountancy/class/bookkeeping.class.php +++ b/htdocs/accountancy/class/bookkeeping.class.php @@ -2088,7 +2088,7 @@ class BookKeeping extends CommonObject * FIXME: This function takes the parent of parent to get the root account ! * * @param string $account Accounting account - * @return array Array with root account information (max 2 upper level) + * @return array|int Array with root account information (max 2 upper level), <0 if KO */ public function getRootAccount($account = null) { diff --git a/htdocs/commande/class/api_orders.class.php b/htdocs/commande/class/api_orders.class.php index 0318cbcd5bf..766637550c2 100644 --- a/htdocs/commande/class/api_orders.class.php +++ b/htdocs/commande/class/api_orders.class.php @@ -713,7 +713,7 @@ class Orders extends DolibarrApi * @throws RestException 404 * @throws RestException 500 System error * - * @return array + * @return object */ public function validate($id, $idwarehouse = 0, $notrigger = 0) { diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index 5b111f67e6c..60cefaf4b52 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -2724,7 +2724,7 @@ class Commande extends CommonOrder * @param int $offset For pagination * @param string $sortfield Sort criteria * @param string $sortorder Sort order - * @return int -1 if KO, array with result if OK + * @return int|array -1 if KO, array with result if OK */ public function liste_array($shortlist = 0, $draft = 0, $excluser = '', $socid = 0, $limit = 0, $offset = 0, $sortfield = 'c.date_commande', $sortorder = 'DESC') { diff --git a/htdocs/contact/class/contact.class.php b/htdocs/contact/class/contact.class.php index b44d22da312..aa86c3f4077 100644 --- a/htdocs/contact/class/contact.class.php +++ b/htdocs/contact/class/contact.class.php @@ -1868,7 +1868,7 @@ class Contact extends CommonObject * Updates all roles (default contact for companies) according to values inside the ->roles array. * This is called by update of contact. * - * @return float|int + * @return void|int * @see fetchRoles() */ public function updateRoles() diff --git a/htdocs/contrat/class/contrat.class.php b/htdocs/contrat/class/contrat.class.php index 97b586a2cde..cfd2dd3b292 100644 --- a/htdocs/contrat/class/contrat.class.php +++ b/htdocs/contrat/class/contrat.class.php @@ -758,7 +758,7 @@ class Contrat extends CommonObject * * @param int $only_services 0=Default, 1=Force only services (depending on setup, we may also have physical products in a contract) * @param int $loadalsotranslation 0=Default, 1=Load also translations of product descriptions - * @return ContratLigne[] Return array of contract lines + * @return array|int Return array of contract lines */ public function fetch_lines($only_services = 0, $loadalsotranslation = 0) { diff --git a/htdocs/debugbar/class/DataCollector/DolLogsCollector.php b/htdocs/debugbar/class/DataCollector/DolLogsCollector.php index 3d3b3b25a0e..0d166a23a6b 100644 --- a/htdocs/debugbar/class/DataCollector/DolLogsCollector.php +++ b/htdocs/debugbar/class/DataCollector/DolLogsCollector.php @@ -138,7 +138,7 @@ class DolLogsCollector extends MessagesCollector * Get logs * * @param string $path Path - * @return array + * @return void */ public function getStorageLogs($path) { diff --git a/htdocs/debugbar/class/DataCollector/DolRequestDataCollector.php b/htdocs/debugbar/class/DataCollector/DolRequestDataCollector.php index 4ddcac9af7c..a74669e5238 100644 --- a/htdocs/debugbar/class/DataCollector/DolRequestDataCollector.php +++ b/htdocs/debugbar/class/DataCollector/DolRequestDataCollector.php @@ -62,7 +62,7 @@ class DolRequestDataCollector extends RequestDataCollector /** * Return widget settings * - * @return void + * @return array */ public function getWidgets() { diff --git a/htdocs/expensereport/class/expensereport.class.php b/htdocs/expensereport/class/expensereport.class.php index a3c726ef521..2d3e20c3a3e 100644 --- a/htdocs/expensereport/class/expensereport.class.php +++ b/htdocs/expensereport/class/expensereport.class.php @@ -2340,7 +2340,7 @@ class ExpenseReport extends CommonObject * Return list of people with permission to validate expense reports. * Search for permission "approve expense report" * - * @return array Array of user ids + * @return array|int Array of user ids, <0 if KO */ public function fetch_users_approver_expensereport() { diff --git a/htdocs/holiday/class/holiday.class.php b/htdocs/holiday/class/holiday.class.php index e3a605a09aa..bcb686ef66a 100644 --- a/htdocs/holiday/class/holiday.class.php +++ b/htdocs/holiday/class/holiday.class.php @@ -1996,7 +1996,7 @@ class Holiday extends CommonObject * Return list of people with permission to validate leave requests. * Search for permission "approve leave requests" * - * @return array Array of user ids + * @return array|int Array of user ids, <0 if ko */ public function fetch_users_approver_holiday() { diff --git a/htdocs/install/upgrade2.php b/htdocs/install/upgrade2.php index 7f76261bcea..f934d24d0fc 100644 --- a/htdocs/install/upgrade2.php +++ b/htdocs/install/upgrade2.php @@ -4222,7 +4222,7 @@ function migrate_delete_old_dir($db, $langs, $conf) * @param Conf $conf Object conf * @param array $listofmodule List of modules, like array('MODULE_KEY_NAME'=>', $reloadmode) * @param int $force 1=Reload module even if not already loaded - * @return int <0 if KO, >0 if OK + * @return int|void <0 if KO, >0 if OK */ function migrate_reload_modules($db, $langs, $conf, $listofmodule = array(), $force = 0) { diff --git a/htdocs/modulebuilder/template/core/modules/mymodule/doc/pdf_standard_myobject.modules.php b/htdocs/modulebuilder/template/core/modules/mymodule/doc/pdf_standard_myobject.modules.php index b78a2a5f4d7..ba93f036c0a 100644 --- a/htdocs/modulebuilder/template/core/modules/mymodule/doc/pdf_standard_myobject.modules.php +++ b/htdocs/modulebuilder/template/core/modules/mymodule/doc/pdf_standard_myobject.modules.php @@ -884,7 +884,7 @@ class pdf_standard_myobject extends ModelePDFMyObject * @param int $showaddress 0=no, 1=yes * @param Translate $outputlangs Object lang for output * @param Translate $outputlangsbis Object lang for output bis - * @return void + * @return float|int */ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null) { diff --git a/htdocs/product/class/productbatch.class.php b/htdocs/product/class/productbatch.class.php index 52a39205b14..750e5d5bd7c 100644 --- a/htdocs/product/class/productbatch.class.php +++ b/htdocs/product/class/productbatch.class.php @@ -431,7 +431,7 @@ class Productbatch extends CommonObject * @param int $fk_product_stock id product_stock for objet * @param int $with_qty 1 = doesn't return line with 0 quantity * @param int $fk_product If set to a product id, get eatby and sellby from table llx_product_lot - * @return array <0 if KO, array of batch + * @return array|int <0 if KO, array of batch */ public static function findAll($dbs, $fk_product_stock, $with_qty = 0, $fk_product = 0) { diff --git a/htdocs/product/dynamic_price/class/price_expression.class.php b/htdocs/product/dynamic_price/class/price_expression.class.php index b9010f60f18..d38851e0eaa 100644 --- a/htdocs/product/dynamic_price/class/price_expression.class.php +++ b/htdocs/product/dynamic_price/class/price_expression.class.php @@ -162,7 +162,7 @@ class PriceExpression /** * List all price expressions * - * @return array Array of price expressions + * @return array|int Array of price expressions, <0 if ko */ public function list_price_expression() { diff --git a/htdocs/product/dynamic_price/class/price_global_variable.class.php b/htdocs/product/dynamic_price/class/price_global_variable.class.php index 336fb024470..99407851174 100644 --- a/htdocs/product/dynamic_price/class/price_global_variable.class.php +++ b/htdocs/product/dynamic_price/class/price_global_variable.class.php @@ -311,7 +311,7 @@ class PriceGlobalVariable /** * List all price global variables * - * @return array Array of price global variables + * @return array|int Array of price global variables, <0 if ko */ public function listGlobalVariables() { diff --git a/htdocs/product/stock/class/productstockentrepot.class.php b/htdocs/product/stock/class/productstockentrepot.class.php index a0310a16359..1151890a4b1 100644 --- a/htdocs/product/stock/class/productstockentrepot.class.php +++ b/htdocs/product/stock/class/productstockentrepot.class.php @@ -242,7 +242,7 @@ class ProductStockEntrepot extends CommonObject * @param array $filter filter array * @param string $filtermode filter mode (AND or OR) * - * @return int <0 if KO, >0 if OK + * @return int|array <0 if KO, array if OK */ public function fetchAll($fk_product = '', $fk_entrepot = '', $sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND') { diff --git a/htdocs/projet/class/api_tasks.class.php b/htdocs/projet/class/api_tasks.class.php index eb7e1579261..cd294aafd4f 100644 --- a/htdocs/projet/class/api_tasks.class.php +++ b/htdocs/projet/class/api_tasks.class.php @@ -272,7 +272,7 @@ class Tasks extends DolibarrApi * * @url GET {id}/roles * - * @return int + * @return array */ public function getRoles($id, $userid = 0) { diff --git a/htdocs/recruitment/core/modules/recruitment/doc/pdf_standard_recruitmentjobposition.modules.php b/htdocs/recruitment/core/modules/recruitment/doc/pdf_standard_recruitmentjobposition.modules.php index 61c2eb3ff20..f98eac047e7 100644 --- a/htdocs/recruitment/core/modules/recruitment/doc/pdf_standard_recruitmentjobposition.modules.php +++ b/htdocs/recruitment/core/modules/recruitment/doc/pdf_standard_recruitmentjobposition.modules.php @@ -803,7 +803,7 @@ class pdf_standard_recruitmentjobposition extends ModelePDFRecruitmentJobPositio * @param int $showaddress 0=no, 1=yes * @param Translate $outputlangs Object lang for output * @param Translate $outputlangsbis Object lang for output bis - * @return void + * @return float|int */ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null) { diff --git a/htdocs/resource/class/html.formresource.class.php b/htdocs/resource/class/html.formresource.class.php index 8b4e32c05d2..5f8c27dab4f 100644 --- a/htdocs/resource/class/html.formresource.class.php +++ b/htdocs/resource/class/html.formresource.class.php @@ -77,7 +77,7 @@ class FormResource * @param int $limit Limit number of answers * @param string $morecss More css * @param bool $multiple add [] in the name of element and add 'multiple' attribut - * @return string HTML string with + * @return string|array HTML string with */ public function select_resource_list($selected = '', $htmlname = 'fk_resource', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $event = array(), $filterkey = '', $outputmode = 0, $limit = 20, $morecss = '', $multiple = false) { diff --git a/htdocs/ticket/class/ticket.class.php b/htdocs/ticket/class/ticket.class.php index bc50c0e31f8..e6688fc7642 100644 --- a/htdocs/ticket/class/ticket.class.php +++ b/htdocs/ticket/class/ticket.class.php @@ -2873,7 +2873,7 @@ class Ticket extends CommonObject * * @param User $user Object user * @param int $mode "opened" for askprice to close, "signed" for proposal to invoice - * @return int <0 if KO, >0 if OK + * @return WorkboardResponse|int <0 if KO, WorkboardResponse if OK */ public function load_board($user, $mode) { diff --git a/htdocs/webservices/server_order.php b/htdocs/webservices/server_order.php index 0f0eb79d10e..bed089abea1 100644 --- a/htdocs/webservices/server_order.php +++ b/htdocs/webservices/server_order.php @@ -654,7 +654,7 @@ function getOrdersForThirdParty($authentication, $idthirdparty) * * @param array $authentication Array of authentication information * @param array $order Order info - * @return int Id of new order + * @return array array of new order */ function createOrder($authentication, $order) { diff --git a/htdocs/webservices/server_other.php b/htdocs/webservices/server_other.php index ae1a480710f..c51ca01639e 100644 --- a/htdocs/webservices/server_other.php +++ b/htdocs/webservices/server_other.php @@ -185,7 +185,7 @@ function getVersions($authentication) * @param string $modulepart Properties of document * @param string $file Relative path * @param string $refname Ref of object to check permission for external users (autodetect if not provided) - * @return void + * @return array */ function getDocument($authentication, $modulepart, $file, $refname = '') { diff --git a/htdocs/webservices/server_project.php b/htdocs/webservices/server_project.php index b64ccc94d59..16aef76c699 100644 --- a/htdocs/webservices/server_project.php +++ b/htdocs/webservices/server_project.php @@ -235,7 +235,7 @@ $server->register( * * @param array $authentication Array of authentication information * @param array $project Project info - * @return int Id of new order + * @return array array of new order */ function createProject($authentication, $project) { diff --git a/htdocs/zapier/class/api_zapier.class.php b/htdocs/zapier/class/api_zapier.class.php index aac72a281f7..62652d9f4b5 100644 --- a/htdocs/zapier/class/api_zapier.class.php +++ b/htdocs/zapier/class/api_zapier.class.php @@ -240,7 +240,7 @@ class Zapier extends DolibarrApi * Create hook object * * @param array $request_data Request datas - * @return int ID of hook + * @return array ID of hook * * @url POST /hook/ */ From e212019ddf353b637ba8298a237a8da1dcbb65fd Mon Sep 17 00:00:00 2001 From: atm-florian Date: Fri, 17 Feb 2023 00:10:00 +0100 Subject: [PATCH 002/105] FIX: SQL error "unknown column p.fk_soc" because ANSI-92 joins take precedence over ANSI-89 joins cf. https://stackoverflow.com/questions/4065985/mysql-unknown-column-in-on-clause --- htdocs/comm/propal/class/propalestats.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/comm/propal/class/propalestats.class.php b/htdocs/comm/propal/class/propalestats.class.php index 52956fa46fd..834ecd2bacb 100644 --- a/htdocs/comm/propal/class/propalestats.class.php +++ b/htdocs/comm/propal/class/propalestats.class.php @@ -248,7 +248,7 @@ class PropaleStats extends Stats global $user; $sql = "SELECT product.ref, COUNT(product.ref) as nb, SUM(tl.".$this->field_line.") as total, AVG(tl.".$this->field_line.") as avg"; - $sql .= " FROM ".$this->from.", ".$this->from_line.", ".MAIN_DB_PREFIX."product as product"; + $sql .= " FROM (".$this->from.", ".$this->from_line.", ".MAIN_DB_PREFIX."product as product)"; if (empty($user->rights->societe->client->voir) && !$user->socid) { $sql .= " INNER JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id); } From c3e42f1961a4d46d0c1b40553727eebcf7be12de Mon Sep 17 00:00:00 2001 From: atm-florian Date: Fri, 17 Feb 2023 16:12:06 +0100 Subject: [PATCH 003/105] Propale stats: replace old-style joins with inner joins --- .../comm/propal/class/propalestats.class.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/htdocs/comm/propal/class/propalestats.class.php b/htdocs/comm/propal/class/propalestats.class.php index 834ecd2bacb..eb699e01c86 100644 --- a/htdocs/comm/propal/class/propalestats.class.php +++ b/htdocs/comm/propal/class/propalestats.class.php @@ -247,17 +247,19 @@ class PropaleStats extends Stats { global $user; - $sql = "SELECT product.ref, COUNT(product.ref) as nb, SUM(tl.".$this->field_line.") as total, AVG(tl.".$this->field_line.") as avg"; - $sql .= " FROM (".$this->from.", ".$this->from_line.", ".MAIN_DB_PREFIX."product as product)"; - if (empty($user->rights->societe->client->voir) && !$user->socid) { - $sql .= " INNER JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id); + $sql = 'SELECT product.ref, COUNT(product.ref) as nb, SUM(tl.' . $this->field_line . ') as total, AVG(tl.' . $this->field_line . ') as avg'; + $sql .= ' FROM ' . $this->from; + $sql .= ' INNER JOIN ' . $this->from_line . ' ON p.rowid = tl.fk_propal'; + $sql .= ' INNER JOIN ' . MAIN_DB_PREFIX . 'product as product ON tl.fk_product = product.rowid'; + if (empty($user->rights->societe->client->voir) && ! $user->socid) { + $sql .= ' INNER JOIN ' . MAIN_DB_PREFIX . 'societe_commerciaux as sc ON p.fk_soc = sc.fk_soc AND sc.fk_user = ' . ((int) $user->id); } $sql .= $this->join; - $sql .= " WHERE ".$this->where; - $sql .= " AND p.rowid = tl.fk_propal AND tl.fk_product = product.rowid"; - $sql .= " AND ".$this->field_date." BETWEEN '".$this->db->idate(dol_get_first_day($year, 1, false))."' AND '".$this->db->idate(dol_get_last_day($year, 12, false))."'"; - $sql .= " GROUP BY product.ref"; + $sql .= ' WHERE ' . $this->where; + $sql .= ' AND ' . $this->field_date . " BETWEEN '" . $this->db->idate(dol_get_first_day($year, 1, false)) . "' AND '" . $this->db->idate(dol_get_last_day($year, 12, false)) . "'"; + $sql .= ' GROUP BY product.ref'; $sql .= $this->db->order('nb', 'DESC'); + //$sql.= $this->db->plimit(20); return $this->_getAllByProduct($sql, $limit); From 45ba2016aa38e2851214320a18fd63fa04bc4206 Mon Sep 17 00:00:00 2001 From: FLIO Date: Wed, 22 Feb 2023 13:29:47 +0100 Subject: [PATCH 004/105] fix (qodana) fix pr --- htdocs/contact/class/contact.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/contact/class/contact.class.php b/htdocs/contact/class/contact.class.php index aa86c3f4077..cc64445fe7c 100644 --- a/htdocs/contact/class/contact.class.php +++ b/htdocs/contact/class/contact.class.php @@ -1868,7 +1868,7 @@ class Contact extends CommonObject * Updates all roles (default contact for companies) according to values inside the ->roles array. * This is called by update of contact. * - * @return void|int + * @return int * @see fetchRoles() */ public function updateRoles() @@ -1878,7 +1878,7 @@ class Contact extends CommonObject $error = 0; if (!isset($this->roles)) { - return; // Avoid to loose roles when property not set + return 0; // Avoid to loose roles when property not set } $this->db->begin(); From b29ebef05fc8394e65196fc5baf8dcb798b7d1cf Mon Sep 17 00:00:00 2001 From: atm-florian Date: Thu, 23 Feb 2023 18:03:00 +0100 Subject: [PATCH 005/105] Propale stats: reworking of the fix to comply with travis rule for SQL string building --- .../comm/propal/class/propalestats.class.php | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/htdocs/comm/propal/class/propalestats.class.php b/htdocs/comm/propal/class/propalestats.class.php index eb699e01c86..fefc8941970 100644 --- a/htdocs/comm/propal/class/propalestats.class.php +++ b/htdocs/comm/propal/class/propalestats.class.php @@ -247,19 +247,18 @@ class PropaleStats extends Stats { global $user; - $sql = 'SELECT product.ref, COUNT(product.ref) as nb, SUM(tl.' . $this->field_line . ') as total, AVG(tl.' . $this->field_line . ') as avg'; - $sql .= ' FROM ' . $this->from; - $sql .= ' INNER JOIN ' . $this->from_line . ' ON p.rowid = tl.fk_propal'; - $sql .= ' INNER JOIN ' . MAIN_DB_PREFIX . 'product as product ON tl.fk_product = product.rowid'; - if (empty($user->rights->societe->client->voir) && ! $user->socid) { - $sql .= ' INNER JOIN ' . MAIN_DB_PREFIX . 'societe_commerciaux as sc ON p.fk_soc = sc.fk_soc AND sc.fk_user = ' . ((int) $user->id); + $sql = "SELECT product.ref, COUNT(product.ref) as nb, SUM(tl.".$this->field_line.") as total, AVG(tl.".$this->field_line.") as avg"; + $sql .= " FROM ".$this->from; + $sql .= " INNER JOIN ".$this->from_line." ON p.rowid = tl.fk_propal"; + $sql .= " INNER JOIN ".MAIN_DB_PREFIX."product as product ON tl.fk_product = product.rowid"; + if (empty($user->rights->societe->client->voir) && !$user->socid) { + $sql .= " INNER JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id); } $sql .= $this->join; - $sql .= ' WHERE ' . $this->where; - $sql .= ' AND ' . $this->field_date . " BETWEEN '" . $this->db->idate(dol_get_first_day($year, 1, false)) . "' AND '" . $this->db->idate(dol_get_last_day($year, 12, false)) . "'"; - $sql .= ' GROUP BY product.ref'; + $sql .= " WHERE ".$this->where; + $sql .= " AND ".$this->field_date." BETWEEN '".$this->db->idate(dol_get_first_day($year, 1, false))."' AND '".$this->db->idate(dol_get_last_day($year, 12, false))."'"; + $sql .= " GROUP BY product.ref"; $sql .= $this->db->order('nb', 'DESC'); - //$sql.= $this->db->plimit(20); return $this->_getAllByProduct($sql, $limit); From fd371cc52b517ea26f50d588cc2c8cf19bc520ce Mon Sep 17 00:00:00 2001 From: Yoan Mollard Date: Fri, 24 Feb 2023 23:31:06 +0100 Subject: [PATCH 006/105] Fix member nature display in new.php --- htdocs/public/members/new.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/public/members/new.php b/htdocs/public/members/new.php index d3a2a556b07..aa8498a85a1 100644 --- a/htdocs/public/members/new.php +++ b/htdocs/public/members/new.php @@ -539,6 +539,8 @@ if (empty($conf->global->MEMBER_NEWFORM_FORCETYPE)) { // Moral/Physic attribute $morphys["phy"] = $langs->trans("Physical"); $morphys["mor"] = $langs->trans("Moral"); +print ''.$langs->trans('MemberNature').' *'."\n"; + if (empty($conf->global->MEMBER_NEWFORM_FORCEMORPHY)) { print ''.$langs->trans('MemberNature').' *'."\n"; print $form->selectarray("morphy", $morphys, GETPOST('morphy'), 1); From 3c883c4b319c1742fa8d4403200081b0119a4f3a Mon Sep 17 00:00:00 2001 From: Alexandre Janniaux Date: Sat, 18 Feb 2023 14:06:58 +0100 Subject: [PATCH 007/105] NEW inc.php: handle parameters from argv This commit adds support for --help and --config to provide a different config file when running upgrade.php from commandline. The argv array is patched afterwards as if the options were never given so that it stays transparent for the code path that are not aware of those arguments. The intention behind is incrementally move the usage of argc/argv to this location and force help/usage from there, in particular for upgrading. The rationale for the --config addition is to be able to provide a different path for conf.php when multiple dolibarr instance are using the same readonly htdocs folder, which is already possible by modifying the `include_path` from PHP for the htdocs/ directory but not for the htdocs/install directory since relative paths are used to fetch the config file. Since the use-case is to upgrade/migrate a Dolibarr instance from CLI, it makes sense to be able to select for which instance (and database parameters) the upgrade should take place. --- htdocs/install/inc.php | 87 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/htdocs/install/inc.php b/htdocs/install/inc.php index 970fd40261b..bf675ae0a36 100644 --- a/htdocs/install/inc.php +++ b/htdocs/install/inc.php @@ -6,6 +6,7 @@ * Copyright (C) 2012 Marcos García * Copyright (C) 2016 Raphaël Doursenaud * Copyright (C) 2021 Charlene Benke + * Copyright (C) 2023 Alexandre Janniaux * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -70,6 +71,92 @@ $conffiletoshow = "htdocs/conf/conf.php"; //$conffile = "/etc/dolibarr/conf.php"; //$conffiletoshow = "/etc/dolibarr/conf.php"; +$short_options = "c:h"; +$long_options = array( + "config:", + "help", +); + +/** + * Print the usage when executing scripts from install/. + * + * Print the help text exposing the available options when executing + * update or install script (ie. from htdocs/install/) from CLI with + * the `php` executable. This function does not `exit` the program and + * the caller should then call `exit` themselves since they should + * determine whether it was an error or not. + * + * @param string $program the script that was originally run + * @param string $header the message to signal to the user + * @return void + */ +function usage($program, $header) +{ + echo $header."\n"; + echo " php ".$program." [options] previous_version new_version [script options]\n"; + echo "\n"; + echo "Script options when using upgrade.php:\n"; + echo "\n"; + echo " dirmodule:\n"; + echo " Specify dirmodule to provide a path for an external module\n"; + echo " so the migration is done using a script from a module.\n"; + echo "\n"; + echo " ignoredbversion:\n"; + echo " Allow to run migration even if database version does\n"; + echo " not match start version of migration.\n"; + echo "\n"; + echo "Script options when using upgrade2.php:\n"; + echo "\n"; + echo " MODULE_NAME1_TO_ENABLE,MODULE_NAME2_TO_ENABLE:\n"; + echo " Specify a list of module-name to enable, joined by comma.\n"; + echo "\n"; + echo "Options:\n"; + echo " -c, --config :\n"; + echo " Provide a different conf.php file to use.\n"; + echo "\n"; + echo " -h, --help:\n"; + echo " Display this help message.\n"; +} + +if (php_sapi_name() === "cli") { + $rest_index = 0; + $opts = getopt($short_options, $long_options, $rest_index); + + foreach ($opts as $opt => $arg) switch ($opt) { + case 'c': + case 'config': + $conffile = $arg; + $conffiletoshow = $arg; + break; + case 'h': + case 'help': + usage($argv[0], "Usage:"); + exit(0); + } + + // In the following test, only dash-prefixed arguments will trigger an + // error, given that scripts options can allow a variable number of + // additional non-prefixed argument and we mostly want to check for + // typo right now. + if ($rest_index < $argc && $argv[$rest_index][0] == "-") { + usage($argv[0], "Unknown option ".$argv[$rest_index]. ", usage:"); + exit(1); + } + + // Currently, scripts using inc.php will require addtional arguments, + // see help above for more details. + if ($rest_index > $argc - 2) { + usage($argv[0], "Missing mandatory arguments, usage:"); + exit(1); + } + + // Tricky argument list hack, should be removed someday. + // Reset argv to remove the argument that were parsed. This is needed + // currently because some install code, like in upgrade.php, are using + // $argv[] directly with fixed index to fetch some arguments. + $argv = array_merge(array($argv[0]), array_slice($argv, $rest_index)); + $argc = count($argv); +} // Load conf file if it is already defined if (!defined('DONOTLOADCONF') && file_exists($conffile) && filesize($conffile) > 8) { // Test on filesize is to ensure that conf file is more that an empty template with just Date: Sun, 26 Feb 2023 22:18:30 +0100 Subject: [PATCH 008/105] Drop the double Must be displayed both in the if and else --- htdocs/public/members/new.php | 1 - 1 file changed, 1 deletion(-) diff --git a/htdocs/public/members/new.php b/htdocs/public/members/new.php index aa8498a85a1..2df2ec45cbc 100644 --- a/htdocs/public/members/new.php +++ b/htdocs/public/members/new.php @@ -542,7 +542,6 @@ $morphys["mor"] = $langs->trans("Moral"); print ''.$langs->trans('MemberNature').' *'."\n"; if (empty($conf->global->MEMBER_NEWFORM_FORCEMORPHY)) { - print ''.$langs->trans('MemberNature').' *'."\n"; print $form->selectarray("morphy", $morphys, GETPOST('morphy'), 1); print ''."\n"; } else { From c2d6e9adcfd62b56877db1490a293ee4745941bf Mon Sep 17 00:00:00 2001 From: David Pareja Rodriguez Date: Wed, 1 Mar 2023 08:33:52 +0100 Subject: [PATCH 009/105] Allow FileUpload to be used when $fk_element and $element are null but enforce a valid upload_dir --- htdocs/core/class/fileupload.class.php | 71 ++++++++++++++++---------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/htdocs/core/class/fileupload.class.php b/htdocs/core/class/fileupload.class.php index 75662d57f94..7eb76032183 100644 --- a/htdocs/core/class/fileupload.class.php +++ b/htdocs/core/class/fileupload.class.php @@ -104,36 +104,40 @@ class FileUpload $dir_output = $conf->$element->dir_output; } - dol_include_once('/'.$pathname.'/class/'.$filename.'.class.php'); + // If pathname and filename are null then we can still upload files + // IF we have specified upload_dir on $this->options + if ($pathname !== null && $filename !== null) { + dol_include_once('/'.$pathname.'/class/'.$filename.'.class.php'); - $classname = ucfirst($filename); + $classname = ucfirst($filename); - if ($element == 'order_supplier') { - $classname = 'CommandeFournisseur'; - } elseif ($element == 'invoice_supplier') { - $classname = 'FactureFournisseur'; - } - - $object = new $classname($db); - - $object->fetch($fk_element); - if (!empty($parentForeignKey)) { - dol_include_once('/'.$parentElement.'/class/'.$parentObject.'.class.php'); - $parent = new $parentClass($db); - $parent->fetch($object->$parentForeignKey); - if (!empty($parent->socid)) { - $parent->fetch_thirdparty(); + if ($element == 'order_supplier') { + $classname = 'CommandeFournisseur'; + } elseif ($element == 'invoice_supplier') { + $classname = 'FactureFournisseur'; } - $object->$parentObject = clone $parent; - } else { - $object->fetch_thirdparty(); - } - $object_ref = dol_sanitizeFileName($object->ref); - if ($element == 'invoice_supplier') { - $object_ref = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier').$object_ref; - } elseif ($element == 'project_task') { - $object_ref = $object->project->ref.'/'.$object_ref; + $object = new $classname($db); + + $object->fetch($fk_element); + if (!empty($parentForeignKey)) { + dol_include_once('/'.$parentElement.'/class/'.$parentObject.'.class.php'); + $parent = new $parentClass($db); + $parent->fetch($object->$parentForeignKey); + if (!empty($parent->socid)) { + $parent->fetch_thirdparty(); + } + $object->$parentObject = clone $parent; + } else { + $object->fetch_thirdparty(); + } + + $object_ref = dol_sanitizeFileName($object->ref); + if ($element == 'invoice_supplier') { + $object_ref = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier').$object_ref; + } elseif ($element == 'project_task') { + $object_ref = $object->project->ref.'/'.$object_ref; + } } $this->options = array( @@ -195,6 +199,21 @@ class FileUpload if ($options) { $this->options = array_replace_recursive($this->options, $options); } + + // At this point we should have a valid upload_dir in options + //if ($pathname === null && $filename === null) { // OR or AND??? + if ($pathname === null || $filename === null) { + if (!key_exists("upload_dir", $this->options)) { + setEventMessage('If $fk_element = null or $element = null you must specify upload_dir on $options', 'errors'); + throw new Exception('If $fk_element = null or $element = null you must specify upload_dir on $options'); + } elseif (is_dir($this->options['upload_dir'])) { + setEventMessage('The directory '$this->options['upload_dir'].' doesn\'t exists', 'errors'); + throw new Exception('The directory '$this->options['upload_dir'].' doesn\'t exists'); + } elseif (is_writable($this->options['upload_dir'])) { + setEventMessage('The directory '$this->options['upload_dir'].' is not writable', 'errors'); + throw new Exception('The directory '$this->options['upload_dir'].' is not writable'); + } + } } /** From 2a706411cf34367902349b68344dfe37f80ba07f Mon Sep 17 00:00:00 2001 From: David Pareja Rodriguez Date: Wed, 1 Mar 2023 08:44:06 +0100 Subject: [PATCH 010/105] fix wrong string concatenation --- htdocs/core/class/fileupload.class.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/core/class/fileupload.class.php b/htdocs/core/class/fileupload.class.php index 7eb76032183..feb35e660d7 100644 --- a/htdocs/core/class/fileupload.class.php +++ b/htdocs/core/class/fileupload.class.php @@ -207,11 +207,11 @@ class FileUpload setEventMessage('If $fk_element = null or $element = null you must specify upload_dir on $options', 'errors'); throw new Exception('If $fk_element = null or $element = null you must specify upload_dir on $options'); } elseif (is_dir($this->options['upload_dir'])) { - setEventMessage('The directory '$this->options['upload_dir'].' doesn\'t exists', 'errors'); - throw new Exception('The directory '$this->options['upload_dir'].' doesn\'t exists'); + setEventMessage('The directory '.$this->options['upload_dir'].' doesn\'t exists', 'errors'); + throw new Exception('The directory '.$this->options['upload_dir'].' doesn\'t exists'); } elseif (is_writable($this->options['upload_dir'])) { - setEventMessage('The directory '$this->options['upload_dir'].' is not writable', 'errors'); - throw new Exception('The directory '$this->options['upload_dir'].' is not writable'); + setEventMessage('The directory '.$this->options['upload_dir'].' is not writable', 'errors'); + throw new Exception('The directory '.$this->options['upload_dir'].' is not writable'); } } } From 0e9451e10081a012e192ad5572ff79fc3fc28595 Mon Sep 17 00:00:00 2001 From: David Pareja Rodriguez Date: Wed, 1 Mar 2023 10:11:55 +0100 Subject: [PATCH 011/105] fix should check the negative --- htdocs/core/class/fileupload.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/class/fileupload.class.php b/htdocs/core/class/fileupload.class.php index feb35e660d7..aff9fd4d412 100644 --- a/htdocs/core/class/fileupload.class.php +++ b/htdocs/core/class/fileupload.class.php @@ -206,10 +206,10 @@ class FileUpload if (!key_exists("upload_dir", $this->options)) { setEventMessage('If $fk_element = null or $element = null you must specify upload_dir on $options', 'errors'); throw new Exception('If $fk_element = null or $element = null you must specify upload_dir on $options'); - } elseif (is_dir($this->options['upload_dir'])) { + } elseif (!is_dir($this->options['upload_dir'])) { setEventMessage('The directory '.$this->options['upload_dir'].' doesn\'t exists', 'errors'); throw new Exception('The directory '.$this->options['upload_dir'].' doesn\'t exists'); - } elseif (is_writable($this->options['upload_dir'])) { + } elseif (!is_writable($this->options['upload_dir'])) { setEventMessage('The directory '.$this->options['upload_dir'].' is not writable', 'errors'); throw new Exception('The directory '.$this->options['upload_dir'].' is not writable'); } From 1c57b755109a29f2dc3353d7b691287c7a090913 Mon Sep 17 00:00:00 2001 From: Marc de Lima Lucio <68746600+marc-dll@users.noreply.github.com> Date: Thu, 2 Mar 2023 15:04:15 +0100 Subject: [PATCH 012/105] FIX: accountancy lettering: better error management --- htdocs/accountancy/journal/bankjournal.php | 6 ++++++ htdocs/accountancy/journal/purchasesjournal.php | 6 ++++++ htdocs/accountancy/journal/sellsjournal.php | 7 +++++++ 3 files changed, 19 insertions(+) diff --git a/htdocs/accountancy/journal/bankjournal.php b/htdocs/accountancy/journal/bankjournal.php index a848f8505d8..85c9551b7ec 100644 --- a/htdocs/accountancy/journal/bankjournal.php +++ b/htdocs/accountancy/journal/bankjournal.php @@ -797,6 +797,12 @@ if (!$error && $action == 'writebookkeeping') { require_once DOL_DOCUMENT_ROOT . '/accountancy/class/lettering.class.php'; $lettering_static = new Lettering($db); $nb_lettering = $lettering_static->bookkeepingLetteringAll(array($bookkeeping->id)); + + if ($nb_lettering < 0) { + $error++; + $errorforline++; + setEventMessages($lettering_static->error, $lettering_static->errors, 'errors'); + } } } } diff --git a/htdocs/accountancy/journal/purchasesjournal.php b/htdocs/accountancy/journal/purchasesjournal.php index c175889357c..5f4182762dc 100644 --- a/htdocs/accountancy/journal/purchasesjournal.php +++ b/htdocs/accountancy/journal/purchasesjournal.php @@ -380,6 +380,12 @@ if ($action == 'writebookkeeping') { require_once DOL_DOCUMENT_ROOT . '/accountancy/class/lettering.class.php'; $lettering_static = new Lettering($db); $nb_lettering = $lettering_static->bookkeepingLettering(array($bookkeeping->id), 'supplier_invoice'); + + if ($nb_lettering < 0) { + $error++; + $errorforline++; + setEventMessages($lettering_static->error, $lettering_static->errors, 'errors'); + } } } } diff --git a/htdocs/accountancy/journal/sellsjournal.php b/htdocs/accountancy/journal/sellsjournal.php index b86f138d232..cb6df055740 100644 --- a/htdocs/accountancy/journal/sellsjournal.php +++ b/htdocs/accountancy/journal/sellsjournal.php @@ -393,6 +393,13 @@ if ($action == 'writebookkeeping') { require_once DOL_DOCUMENT_ROOT . '/accountancy/class/lettering.class.php'; $lettering_static = new Lettering($db); $nb_lettering = $lettering_static->bookkeepingLettering(array($bookkeeping->id), 'customer_invoice'); + + if ($nb_lettering < 0) { + $error++; + $errorforline++; + $errorforinvoice[$key] = 'other'; + setEventMessages($lettering_static->error, $lettering_static->errors, 'errors'); + } } } } From 49afabd440d1db9fc68cc7ea02b285b6b927579e Mon Sep 17 00:00:00 2001 From: Marc de Lima Lucio <68746600+marc-dll@users.noreply.github.com> Date: Thu, 2 Mar 2023 15:16:04 +0100 Subject: [PATCH 013/105] FIX: accountancy lettering: prevent null results when fetching link with payments --- htdocs/accountancy/class/lettering.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/accountancy/class/lettering.class.php b/htdocs/accountancy/class/lettering.class.php index 405a630942e..2f86d6e7e3a 100644 --- a/htdocs/accountancy/class/lettering.class.php +++ b/htdocs/accountancy/class/lettering.class.php @@ -655,7 +655,7 @@ class Lettering extends BookKeeping // Get payment lines $sql = "SELECT DISTINCT pe2.$fk_payment_element, pe2.$fk_element"; $sql .= " FROM " . MAIN_DB_PREFIX . "$payment_element AS pe"; - $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "$payment_element AS pe2 ON pe2.$fk_element = pe.$fk_element"; + $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "$payment_element AS pe2 ON pe2.$fk_element = pe.$fk_element"; $sql .= " WHERE pe.$fk_payment_element IN (" . $this->db->sanitize(implode(',', $payment_ids)) . ")"; dol_syslog(__METHOD__ . " - Get payment lines", LOG_DEBUG); From d3edbbb51bfead001c9095396a2a8418668f17d2 Mon Sep 17 00:00:00 2001 From: Marc de Lima Lucio <68746600+marc-dll@users.noreply.github.com> Date: Thu, 2 Mar 2023 15:56:10 +0100 Subject: [PATCH 014/105] FIX: accountancy lettering: correctly calculated number of lettering operations done --- htdocs/accountancy/class/lettering.class.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/htdocs/accountancy/class/lettering.class.php b/htdocs/accountancy/class/lettering.class.php index 2f86d6e7e3a..48e4eb56647 100644 --- a/htdocs/accountancy/class/lettering.class.php +++ b/htdocs/accountancy/class/lettering.class.php @@ -297,6 +297,7 @@ class Lettering extends BookKeeping // Update request $now = dol_now(); + $affected_rows = 0; if (!$error) { $sql = "UPDATE ".MAIN_DB_PREFIX."accounting_bookkeeping SET"; @@ -309,6 +310,8 @@ class Lettering extends BookKeeping if (!$resql) { $error++; $this->errors[] = "Error ".$this->db->lasterror(); + } else { + $affected_rows = $this->db->affected_rows($resql); } } @@ -320,7 +323,7 @@ class Lettering extends BookKeeping } return -1 * $error; } else { - return 1; + return $affected_rows; } } @@ -355,7 +358,7 @@ class Lettering extends BookKeeping } return -1 * $error; } else { - return 1; + return $this->db->affected_rows($resql); } } @@ -457,7 +460,7 @@ class Lettering extends BookKeeping else $result = $this->updateLettering($bookkeeping_lines); if ($result < 0) { $group_error++; - } else { + } elseif ($result > 0) { $nb_lettering++; } } From be877ffb4b5044995e8e4579224eb1e9b2c0aec0 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Fri, 3 Mar 2023 10:15:11 +0100 Subject: [PATCH 015/105] WIP --- htdocs/core/class/html.form.class.php | 14 ++++++++------ htdocs/projet/tasks/time.php | 7 +++++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 4cb98acbe45..fc9a20fbf8a 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -10027,9 +10027,10 @@ class Form * @param string $projectsListId ''=Automatic filter on project allowed. List of id=Filter on project ids. * @param string $showproject 'all' = Show project info, ''=Hide project info * @param User $usertofilter User object to use for filtering + * @param int $status Invoice status filter (-1 for no filter) * @return int Nbr of project if OK, <0 if KO */ - public function selectInvoice($socid = -1, $selected = '', $htmlname = 'invoiceid', $maxlength = 24, $option_only = 0, $show_empty = '1', $discard_closed = 0, $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500', $projectsListId = '', $showproject = 'all', $usertofilter = null) + public function selectInvoice($socid = -1,$selected = '', $htmlname = 'invoiceid', $maxlength = 24, $option_only = 0, $show_empty = '1', $discard_closed = 0, $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500', $projectsListId = '', $showproject = 'all', $usertofilter = null, $status=0, $events=array()) { global $user, $conf, $langs; @@ -10061,7 +10062,10 @@ class Form $sql .= ' LEFT JOIN '.$this->db->prefix().'societe as s ON s.rowid = p.fk_soc,'; $sql .= ' '.$this->db->prefix().'facture as f'; $sql .= " WHERE p.entity IN (".getEntity('project').")"; - $sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement + $sql .= " AND f.fk_projet = p.rowid "; //Brouillons seulement + if ($status!== -1){ + $sql .= " AND f.fk_statut=".(int)$status; + } //if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")"; //if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)"; //if ($socid > 0) $sql.= " AND (p.fk_soc=".((int) $socid)." OR p.fk_soc IS NULL)"; @@ -10154,13 +10158,11 @@ class Form $out .= ''; } - print $out; + return $out; $this->db->free($resql); - return $num; } else { - dol_print_error($this->db); - return -1; + dol_print_error($this->db->lasterror); } } diff --git a/htdocs/projet/tasks/time.php b/htdocs/projet/tasks/time.php index 85d83031ccd..eea9963bf23 100644 --- a/htdocs/projet/tasks/time.php +++ b/htdocs/projet/tasks/time.php @@ -1468,7 +1468,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser print $langs->trans('InvoiceToUse'); print ''; print ''; - $form->selectInvoice($projectstatic->thirdparty->id, '', 'invoiceid', 24, 0, $langs->trans('NewInvoice'), 1, 0, 0, 'maxwidth500', '', 'all'); + print $form->selectInvoice($projectstatic->thirdparty->id, '', 'invoiceid', 24, 0, $langs->trans('NewInvoice'), 1, 0, 0, 'maxwidth500', '', 'all'); print ''; print ''; /*print ''; @@ -1553,6 +1553,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser $sql .= " u.lastname, u.firstname, u.login, u.photo, u.statut as user_status,"; $sql .= " il.fk_facture as invoice_id, inv.fk_statut,"; $sql .= " p.fk_soc,s.name_alias,"; + $sql .= " t.invoice_line_id"; // Add fields from hooks $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook @@ -2344,7 +2345,9 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser if ($task_time->invoice_id) { $result = $tmpinvoice->fetch($task_time->invoice_id); if ($result > 0) { - print $tmpinvoice->getNomUrl(1); + var_dump($task_time->invoice_line_id); + //print $tmpinvoice->getNomUrl(1); + //print $form->selectInvoiceAndLines($projectstatic->thirdparty->id, $tmpinvoice->id, 'invoiceid', 'invoicelineid', 24, 0, $langs->trans('NewInvoice'), 1, 0, 0, 'maxwidth500', '', 'all',null,-1); } } else { print $langs->trans("No"); From 919d87a49ef1b3471e3207a59a1385d4deeb3f81 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Fri, 3 Mar 2023 10:22:18 +0100 Subject: [PATCH 016/105] fix: remove invoice line id and invoice on time spend when delete line --- htdocs/compta/facture/class/facture.class.php | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index b5332b033ef..2a3f8b4a17f 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -4230,19 +4230,6 @@ class Facture extends CommonInvoice $this->db->begin(); - // Free discount linked to invoice line - $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except'; - $sql .= ' SET fk_facture_line = NULL'; - $sql .= ' WHERE fk_facture_line = '.((int) $rowid); - - dol_syslog(get_class($this)."::deleteline", LOG_DEBUG); - $result = $this->db->query($sql); - if (!$result) { - $this->error = $this->db->error(); - $this->db->rollback(); - return -1; - } - // Memorize previous line for triggers $staticline = clone $line; $line->oldline = $staticline; @@ -6441,13 +6428,38 @@ class FactureLigne extends CommonInvoiceLine return -1; } - $sql = "DELETE FROM ".MAIN_DB_PREFIX."facturedet WHERE rowid = ".((int) $this->rowid); + // Free discount linked to invoice line + $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except'; + $sql .= ' SET fk_facture_line = NULL'; + $sql .= ' WHERE fk_facture_line = '.((int) $this->id); + + dol_syslog(get_class($this)."::deleteline", LOG_DEBUG); + $result = $this->db->query($sql); + if (!$result) { + $this->error = $this->db->error(); + $this->errors[] = $this->error; + $this->db->rollback(); + return -1; + } + + $sql = 'UPDATE '.MAIN_DB_PREFIX.'projet_task_time'; + $sql .= ' SET invoice_id = NULL, invoice_line_id = NULL'; + $sql .= ' WHERE invoice_line_id = '.((int) $this->id); + if (!$this->db->query($sql)) { + $this->error = $this->db->error()." sql=".$sql; + $this->errors[] = $this->error; + $this->db->rollback(); + return -1; + } + + $sql = "DELETE FROM ".MAIN_DB_PREFIX."facturedet WHERE rowid = ".((int) $this->id); if ($this->db->query($sql)) { $this->db->commit(); return 1; } else { $this->error = $this->db->error()." sql=".$sql; + $this->errors[] = $this->error; $this->db->rollback(); return -1; } From b658b9b1d35445415f902bb6cff897c3fa18f268 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Fri, 3 Mar 2023 11:18:19 +0100 Subject: [PATCH 017/105] WIP --- htdocs/core/class/html.form.class.php | 4876 ++++++++++--------- htdocs/core/class/html.formprojet.class.php | 118 + htdocs/projet/tasks/time.php | 8 +- 3 files changed, 2585 insertions(+), 2417 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index fc9a20fbf8a..01e3dc99cce 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -37,15 +37,15 @@ */ /** - * \file htdocs/core/class/html.form.class.php + * \file htdocs/core/class/html.form.class.php * \ingroup core - * \brief File of class with all html predefined components + * \brief File of class with all html predefined components */ /** - * Class to manage generation of HTML components - * Only common components must be here. + * Class to manage generation of HTML components + * Only common components must be here. * * TODO Merge all function load_cache_* and loadCache* (except load_cache_vatrates) into one generic function loadCacheTable */ @@ -81,7 +81,7 @@ class Form /** * Constructor * - * @param DoliDB $db Database handler + * @param DoliDB $db Database handler */ public function __construct($db) { @@ -91,18 +91,18 @@ class Form /** * Output key field for an editable field * - * @param string $text Text of label or key to translate - * @param string $htmlname Name of select field ('edit' prefix will be added) - * @param string $preselected Value to show/edit (not used in this function) - * @param object $object Object (on the page we show) - * @param boolean $perm Permission to allow button to edit parameter. Set it to 0 to have a not edited field. - * @param string $typeofdata Type of data ('string' by default, 'email', 'amount:99', 'numeric:99', 'text' or 'textarea:rows:cols', 'datepicker' ('day' do not work, don't know why), 'dayhour' or 'datehourpicker' 'checkbox:ckeditor:dolibarr_zzz:width:height:savemethod:1:rows:cols', 'select;xxx[:class]'...) - * @param string $moreparam More param to add on a href URL. - * @param int $fieldrequired 1 if we want to show field as mandatory using the "fieldrequired" CSS. - * @param int $notabletag 1=Do not output table tags but output a ':', 2=Do not output table tags and no ':', 3=Do not output table tags but output a ' ' - * @param string $paramid Key of parameter for id ('id', 'socid') - * @param string $help Tooltip help - * @return string HTML edit field + * @param string $text Text of label or key to translate + * @param string $htmlname Name of select field ('edit' prefix will be added) + * @param string $preselected Value to show/edit (not used in this function) + * @param object $object Object (on the page we show) + * @param boolean $perm Permission to allow button to edit parameter. Set it to 0 to have a not edited field. + * @param string $typeofdata Type of data ('string' by default, 'email', 'amount:99', 'numeric:99', 'text' or 'textarea:rows:cols', 'datepicker' ('day' do not work, don't know why), 'dayhour' or 'datehourpicker' 'checkbox:ckeditor:dolibarr_zzz:width:height:savemethod:1:rows:cols', 'select;xxx[:class]'...) + * @param string $moreparam More param to add on a href URL. + * @param int $fieldrequired 1 if we want to show field as mandatory using the "fieldrequired" CSS. + * @param int $notabletag 1=Do not output table tags but output a ':', 2=Do not output table tags and no ':', 3=Do not output table tags but output a ' ' + * @param string $paramid Key of parameter for id ('id', 'socid') + * @param string $help Tooltip help + * @return string HTML edit field */ public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '') { @@ -114,7 +114,7 @@ class Form if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;/', $typeofdata)) { if (!empty($perm)) { $tmp = explode(':', $typeofdata); - $ret .= '
'; + $ret .= '
'; if ($fieldrequired) { $ret .= ''; } @@ -126,7 +126,7 @@ class Form if ($fieldrequired) { $ret .= ''; } - $ret .= '
'."\n"; + $ret .= '
' . "\n"; } else { if ($fieldrequired) { $ret .= ''; @@ -164,8 +164,8 @@ class Form if (empty($notabletag) && $perm) { $ret .= ''; } - if ($htmlname && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { - $ret .= 'id.$moreparam.'">'.img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)).''; + if ($htmlname && GETPOST('action', 'aZ09') != 'edit' . $htmlname && $perm) { + $ret .= '' . img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)) . ''; } if (!empty($notabletag) && $notabletag == 1) { if ($text) { @@ -191,23 +191,23 @@ class Form /** * Output value of a field for an editable field * - * @param string $text Text of label (not used in this function) - * @param string $htmlname Name of select field - * @param string $value Value to show/edit - * @param object $object Object (that we want to show) - * @param boolean $perm Permission to allow button to edit parameter - * @param string $typeofdata Type of data ('string' by default, 'email', 'amount:99', 'numeric:99', 'text' or 'textarea:rows:cols%', 'datepicker' ('day' do not work, don't know why), 'dayhour' or 'datehourpicker', 'ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols', 'select;xkey:xval,ykey:yval,...') - * @param string $editvalue When in edit mode, use this value as $value instead of value (for example, you can provide here a formated price instead of numeric value). Use '' to use same than $value - * @param object $extObject External object ??? - * @param mixed $custommsg String or Array of custom messages : eg array('success' => 'MyMessage', 'error' => 'MyMessage') - * @param string $moreparam More param to add on the form on action href URL parameter - * @param int $notabletag Do no output table tags - * @param string $formatfunc Call a specific function to output field in view mode (For example: 'dol_print_email') - * @param string $paramid Key of parameter for id ('id', 'socid') - * @param string $gm 'auto' or 'tzuser' or 'tzuserrel' or 'tzserver' (when $typeofdata is a date) - * @param array $moreoptions Array with more options. For example array('addnowlink'=>1), array('valuealreadyhtmlescaped'=>1) - * @param string $editaction [=''] use GETPOST default action or set action to edit mode - * @return string HTML edit field + * @param string $text Text of label (not used in this function) + * @param string $htmlname Name of select field + * @param string $value Value to show/edit + * @param object $object Object (that we want to show) + * @param boolean $perm Permission to allow button to edit parameter + * @param string $typeofdata Type of data ('string' by default, 'email', 'amount:99', 'numeric:99', 'text' or 'textarea:rows:cols%', 'datepicker' ('day' do not work, don't know why), 'dayhour' or 'datehourpicker', 'ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols', 'select;xkey:xval,ykey:yval,...') + * @param string $editvalue When in edit mode, use this value as $value instead of value (for example, you can provide here a formated price instead of numeric value). Use '' to use same than $value + * @param object $extObject External object ??? + * @param mixed $custommsg String or Array of custom messages : eg array('success' => 'MyMessage', 'error' => 'MyMessage') + * @param string $moreparam More param to add on the form on action href URL parameter + * @param int $notabletag Do no output table tags + * @param string $formatfunc Call a specific function to output field in view mode (For example: 'dol_print_email') + * @param string $paramid Key of parameter for id ('id', 'socid') + * @param string $gm 'auto' or 'tzuser' or 'tzuserrel' or 'tzserver' (when $typeofdata is a date) + * @param array $moreoptions Array with more options. For example array('addnowlink'=>1), array('valuealreadyhtmlescaped'=>1) + * @param string $editaction [=''] use GETPOST default action or set action to edit mode + * @return string HTML edit field */ public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 1, $formatfunc = '', $paramid = 'id', $gm = 'auto', $moreoptions = array(), $editaction = '') { @@ -230,7 +230,7 @@ class Form } elseif ($reg[1] == 'int') { $typeofdata = 'numeric'; } else { - return 'ErrorBadParameter '.$typeofdata; + return 'ErrorBadParameter ' . $typeofdata; } } @@ -241,13 +241,13 @@ class Form if ($editaction == '') { $editaction = GETPOST('action', 'aZ09'); } - $editmode = ($editaction == 'edit'.$htmlname); + $editmode = ($editaction == 'edit' . $htmlname); if ($editmode) { $ret .= "\n"; - $ret .= '
'; - $ret .= ''; - $ret .= ''; - $ret .= ''; + $ret .= ''; + $ret .= ''; + $ret .= ''; + $ret .= ''; if (empty($notabletag)) { $ret .= ''; } @@ -256,29 +256,29 @@ class Form } if (preg_match('/^(string|safehtmlstring|email)/', $typeofdata)) { $tmp = explode(':', $typeofdata); - $ret .= ''; + $ret .= ''; } elseif (preg_match('/^(integer)/', $typeofdata)) { $tmp = explode(':', $typeofdata); $valuetoshow = price2num($editvalue ? $editvalue : $value, 0); - $ret .= ''; + $ret .= ''; } elseif (preg_match('/^(numeric|amount)/', $typeofdata)) { $tmp = explode(':', $typeofdata); $valuetoshow = price2num($editvalue ? $editvalue : $value); - $ret .= ''; + $ret .= ''; } elseif (preg_match('/^(checkbox)/', $typeofdata)) { $tmp = explode(':', $typeofdata); $ret .= ''; - } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { // if wysiwyg is enabled $typeofdata = 'ckeditor' + } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { // if wysiwyg is enabled $typeofdata = 'ckeditor' $tmp = explode(':', $typeofdata); $cols = (empty($tmp[2]) ? '' : $tmp[2]); $morealt = ''; if (preg_match('/%/', $cols)) { - $morealt = ' style="width: '.$cols.'"'; + $morealt = ' style="width: ' . $cols . '"'; $cols = ''; } $valuetoshow = ($editvalue ? $editvalue : $value); - $ret .= ''; } else { - $resultforextrlang .= ''; + $resultforextrlang .= ''; } } $result .= $resultforextrlang; $result .= ''; - $result .= ''; + $result .= ''; } return $result; @@ -467,15 +467,15 @@ class Form /** * Output edit in place form * - * @param object $object Object - * @param string $value Value to show/edit - * @param string $htmlname DIV ID (field name) - * @param int $condition Condition to edit - * @param string $inputType Type of input ('string', 'numeric', 'datepicker' ('day' do not work, don't know why), 'textarea:rows:cols', 'ckeditor:dolibarr_zzz:width:height:?:1:rows:cols', 'select:loadmethod:savemethod:buttononly') - * @param string $editvalue When in edit mode, use this value as $value instead of value - * @param object $extObject External object - * @param mixed $custommsg String or Array of custom messages : eg array('success' => 'MyMessage', 'error' => 'MyMessage') - * @return string HTML edit in place + * @param object $object Object + * @param string $value Value to show/edit + * @param string $htmlname DIV ID (field name) + * @param int $condition Condition to edit + * @param string $inputType Type of input ('string', 'numeric', 'datepicker' ('day' do not work, don't know why), 'textarea:rows:cols', 'ckeditor:dolibarr_zzz:width:height:?:1:rows:cols', 'select:loadmethod:savemethod:buttononly') + * @param string $editvalue When in edit mode, use this value as $value instead of value + * @param object $extObject External object + * @param mixed $custommsg String or Array of custom messages : eg array('success' => 'MyMessage', 'error' => 'MyMessage') + * @return string HTML edit in place */ protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null) { @@ -495,11 +495,11 @@ class Form if ($condition) { $element = false; $table_element = false; - $fk_element = false; - $loadmethod = false; - $savemethod = false; - $ext_element = false; - $button_only = false; + $fk_element = false; + $loadmethod = false; + $savemethod = false; + $ext_element = false; + $button_only = false; $inputOption = ''; $rows = ''; $cols = ''; @@ -523,7 +523,7 @@ class Form if (!empty($tmp[2])) { $savemethod = $tmp[2]; } - $out .= ''."\n"; + $out .= '' . "\n"; } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) { $tmp = explode(':', $inputType); $inputType = $tmp[0]; @@ -534,7 +534,7 @@ class Form $savemethod = $tmp[2]; } - $out .= ''."\n"; // Use for timestamp format + $out .= '' . "\n"; // Use for timestamp format } elseif (preg_match('/^(select|autocomplete)/', $inputType)) { $tmp = explode(':', $inputType); $inputType = $tmp[0]; @@ -565,40 +565,40 @@ class Form } if (isModEnabled('fckeditor')) { - $out .= ''."\n"; + $out .= '' . "\n"; } else { $inputType = 'textarea'; } } - $out .= ''."\n"; - $out .= ''."\n"; - $out .= ''."\n"; - $out .= ''."\n"; + $out .= '' . "\n"; + $out .= '' . "\n"; + $out .= '' . "\n"; + $out .= '' . "\n"; if (!empty($savemethod)) { - $out .= ''."\n"; + $out .= '' . "\n"; } if (!empty($ext_element)) { - $out .= ''."\n"; + $out .= '' . "\n"; } if (!empty($custommsg)) { if (is_array($custommsg)) { if (!empty($custommsg['success'])) { - $out .= ''."\n"; + $out .= '' . "\n"; } if (!empty($custommsg['error'])) { - $out .= ''."\n"; + $out .= '' . "\n"; } } else { - $out .= ''."\n"; + $out .= '' . "\n"; } } if ($inputType == 'textarea') { - $out .= ''."\n"; - $out .= ''."\n"; + $out .= '' . "\n"; + $out .= '' . "\n"; } - $out .= ''.$value.''."\n"; - $out .= ''.(!empty($editvalue) ? $editvalue : $value).''."\n"; + $out .= '' . $value . '' . "\n"; + $out .= '' . (!empty($editvalue) ? $editvalue : $value) . '' . "\n"; } else { $out = $value; } @@ -607,32 +607,32 @@ class Form } /** - * Show a text and picto with tooltip on text or picto. + * Show a text and picto with tooltip on text or picto. * Can be called by an instancied $form->textwithtooltip or by a static call Form::textwithtooltip * - * @param string $text Text to show - * @param string $htmltext HTML content of tooltip. Must be HTML/UTF8 encoded. - * @param int $tooltipon 1=tooltip on text, 2=tooltip on image, 3=tooltip sur les 2 - * @param int $direction -1=image is before, 0=no image, 1=image is after - * @param string $img Html code for image (use img_xxx() function to get it) - * @param string $extracss Add a CSS style to td tags - * @param int $notabs 0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span - * @param string $incbefore Include code before the text - * @param int $noencodehtmltext Do not encode into html entity the htmltext - * @param string $tooltiptrigger ''=Tooltip on hover, 'abc'=Tooltip on click (abc is a unique key) - * @param int $forcenowrap Force no wrap between text and picto (works with notabs=2 only) - * @return string Code html du tooltip (texte+picto) - * @see textwithpicto() Use thisfunction if you can. + * @param string $text Text to show + * @param string $htmltext HTML content of tooltip. Must be HTML/UTF8 encoded. + * @param int $tooltipon 1=tooltip on text, 2=tooltip on image, 3=tooltip sur les 2 + * @param int $direction -1=image is before, 0=no image, 1=image is after + * @param string $img Html code for image (use img_xxx() function to get it) + * @param string $extracss Add a CSS style to td tags + * @param int $notabs 0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span + * @param string $incbefore Include code before the text + * @param int $noencodehtmltext Do not encode into html entity the htmltext + * @param string $tooltiptrigger ''=Tooltip on hover, 'abc'=Tooltip on click (abc is a unique key) + * @param int $forcenowrap Force no wrap between text and picto (works with notabs=2 only) + * @return string Code html du tooltip (texte+picto) + * @see textwithpicto() Use thisfunction if you can. */ public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0) { if ($incbefore) { - $text = $incbefore.$text; + $text = $incbefore . $text; } if (!$htmltext) { return $text; } - $direction = (int) $direction; // For backward compatibility when $direction was set to '' instead of 0 + $direction = (int)$direction; // For backward compatibility when $direction was set to '' instead of 0 $tag = 'td'; if ($notabs == 2) { @@ -646,11 +646,11 @@ class Form $extrastyle = ''; if ($direction < 0) { - $extracss = ($extracss ? $extracss.' ' : '').($notabs != 3 ? 'inline-block' : ''); + $extracss = ($extracss ? $extracss . ' ' : '') . ($notabs != 3 ? 'inline-block' : ''); $extrastyle = 'padding: 0px; padding-left: 3px;'; } if ($direction > 0) { - $extracss = ($extracss ? $extracss.' ' : '').($notabs != 3 ? 'inline-block' : ''); + $extracss = ($extracss ? $extracss . ' ' : '') . ($notabs != 3 ? 'inline-block' : ''); $extrastyle = 'padding: 0px; padding-right: 3px;'; } @@ -663,53 +663,53 @@ class Form $htmltext = str_replace('"', '"', $htmltext); } else { $classfortooltip = 'classfortooltiponclick'; - $textfordialog .= ''; + $textfordialog .= ''; } if ($tooltipon == 2 || $tooltipon == 3) { - $paramfortooltipimg = ' class="'.$classfortooltip.($notabs != 3 ? ' inline-block' : '').($extracss ? ' '.$extracss : '').'" style="padding: 0px;'.($extrastyle ? ' '.$extrastyle : '').'"'; + $paramfortooltipimg = ' class="' . $classfortooltip . ($notabs != 3 ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '"'; if ($tooltiptrigger == '') { - $paramfortooltipimg .= ' title="'.($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)).'"'; // Attribut to put on img tag to store tooltip + $paramfortooltipimg .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribut to put on img tag to store tooltip } else { - $paramfortooltipimg .= ' dolid="'.$tooltiptrigger.'"'; + $paramfortooltipimg .= ' dolid="' . $tooltiptrigger . '"'; } } else { - $paramfortooltipimg = ($extracss ? ' class="'.$extracss.'"' : '').($extrastyle ? ' style="'.$extrastyle.'"' : ''); // Attribut to put on td text tag + $paramfortooltipimg = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribut to put on td text tag } if ($tooltipon == 1 || $tooltipon == 3) { - $paramfortooltiptd = ' class="'.($tooltipon == 3 ? 'cursorpointer ' : '').$classfortooltip.' inline-block'.($extracss ? ' '.$extracss : '').'" style="padding: 0px;'.($extrastyle ? ' '.$extrastyle : '').'" '; + $paramfortooltiptd = ' class="' . ($tooltipon == 3 ? 'cursorpointer ' : '') . $classfortooltip . ' inline-block' . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '" '; if ($tooltiptrigger == '') { - $paramfortooltiptd .= ' title="'.($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)).'"'; // Attribut to put on td tag to store tooltip + $paramfortooltiptd .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribut to put on td tag to store tooltip } else { - $paramfortooltiptd .= ' dolid="'.$tooltiptrigger.'"'; + $paramfortooltiptd .= ' dolid="' . $tooltiptrigger . '"'; } } else { - $paramfortooltiptd = ($extracss ? ' class="'.$extracss.'"' : '').($extrastyle ? ' style="'.$extrastyle.'"' : ''); // Attribut to put on td text tag + $paramfortooltiptd = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribut to put on td text tag } if (empty($notabs)) { $s .= '
'; } elseif ($notabs == 2) { - $s .= '
'; + $s .= '
'; } // Define value if value is before if ($direction < 0) { - $s .= '<'.$tag.$paramfortooltipimg; + $s .= '<' . $tag . $paramfortooltipimg; if ($tag == 'td') { $s .= ' class="valigntop" width="14"'; } - $s .= '>'.$textfordialog.$img.''; + $s .= '>' . $textfordialog . $img . ''; } // Use another method to help avoid having a space in value in order to use this value with jquery // Define label - if ((string) $text != '') { - $s .= '<'.$tag.$paramfortooltiptd.'>'.$text.''; + if ((string)$text != '') { + $s .= '<' . $tag . $paramfortooltiptd . '>' . $text . ''; } // Define value if value is after if ($direction > 0) { - $s .= '<'.$tag.$paramfortooltipimg; + $s .= '<' . $tag . $paramfortooltipimg; if ($tag == 'td') { $s .= ' class="valignmiddle" width="14"'; } - $s .= '>'.$textfordialog.$img.''; + $s .= '>' . $textfordialog . $img . ''; } if (empty($notabs)) { $s .= '
'; @@ -721,18 +721,18 @@ class Form } /** - * Show a text with a picto and a tooltip on picto + * Show a text with a picto and a tooltip on picto * - * @param string $text Text to show - * @param string $htmltext Content of tooltip - * @param int $direction 1=Icon is after text, -1=Icon is before text, 0=no icon - * @param string $type Type of picto ('info', 'infoclickable', 'help', 'helpclickable', 'warning', 'superadmin', 'mypicto@mymodule', ...) or image filepath or 'none' - * @param string $extracss Add a CSS style to td, div or span tag - * @param int $noencodehtmltext Do not encode into html entity the htmltext - * @param int $notabs 0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span - * @param string $tooltiptrigger ''=Tooltip on hover and hidden on smartphone, 'abconsmartphone'=Tooltip on hover and on click on smartphone, 'abc'=Tooltip on click (abc is a unique key, clickable link is on image or on link if param $type='none' or on both if $type='xxxclickable') - * @param int $forcenowrap Force no wrap between text and picto (works with notabs=2 only) - * @return string HTML code of text, picto, tooltip + * @param string $text Text to show + * @param string $htmltext Content of tooltip + * @param int $direction 1=Icon is after text, -1=Icon is before text, 0=no icon + * @param string $type Type of picto ('info', 'infoclickable', 'help', 'helpclickable', 'warning', 'superadmin', 'mypicto@mymodule', ...) or image filepath or 'none' + * @param string $extracss Add a CSS style to td, div or span tag + * @param int $noencodehtmltext Do not encode into html entity the htmltext + * @param int $notabs 0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span + * @param string $tooltiptrigger ''=Tooltip on hover and hidden on smartphone, 'abconsmartphone'=Tooltip on hover and on click on smartphone, 'abc'=Tooltip on click (abc is a unique key, clickable link is on image or on link if param $type='none' or on both if $type='xxxclickable') + * @param int $forcenowrap Force no wrap between text and picto (works with notabs=2 only) + * @return string HTML code of text, picto, tooltip */ public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = '', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0) { @@ -799,12 +799,12 @@ class Form /** * Generate select HTML to choose massaction * - * @param string $selected Value auto selected when at least one record is selected. Not a preselected value. Use '0' by default. - * @param array $arrayofaction array('code'=>'label', ...). The code is the key stored into the GETPOST('massaction') when submitting action. - * @param int $alwaysvisible 1=select button always visible - * @param string $name Name for massaction - * @param string $cssclass CSS class used to check for select - * @return string|void Select list + * @param string $selected Value auto selected when at least one record is selected. Not a preselected value. Use '0' by default. + * @param array $arrayofaction array('code'=>'label', ...). The code is the key stored into the GETPOST('massaction') when submitting action. + * @param int $alwaysvisible 1=select button always visible + * @param string $name Name for massaction + * @param string $cssclass CSS class used to check for select + * @return string|void Select list */ public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect') { @@ -813,7 +813,7 @@ class Form $disabled = 0; $ret = '
'; - $ret .= ''; // Complete list with data from external modules. THe module can use $_SERVER['PHP_SELF'] to know on which page we are, or use the $parameters['currentcontext'] completed by executeHooks. $parameters = array(); @@ -823,9 +823,9 @@ class Form return; } if (empty($reshook)) { - $ret .= ''; + $ret .= ''; foreach ($arrayofaction as $code => $label) { - $ret .= ''; + $ret .= ''; } } $ret .= $hookmanager->resPrint; @@ -833,17 +833,17 @@ class Form $ret .= ''; if (empty($conf->dol_optimize_smallscreen)) { - $ret .= ajax_combobox('.'.$name.'select'); + $ret .= ajax_combobox('.' . $name . 'select'); } // Warning: if you set submit button to disabled, post using 'Enter' will no more work if there is no another input submit. So we add a hidden button $ret .= ''; // Hidden button BEFORE so it is the one used when we submit with ENTER. - $ret .= 'use_javascript_ajax) ? '' : ' style="display: none"').' class="button smallpaddingimp'.(empty($conf->use_javascript_ajax) ? '' : ' hideobject').' '.$name.' '.$name.'confirmed" value="'.dol_escape_htmltag($langs->trans("Confirm")).'">'; + $ret .= 'use_javascript_ajax) ? '' : ' style="display: none"') . ' class="button smallpaddingimp' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'confirmed" value="' . dol_escape_htmltag($langs->trans("Confirm")) . '">'; $ret .= '
'; if (!empty($conf->use_javascript_ajax)) { $ret .= ' - '; $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter); - $out .= ' '; + $out .= ' '; $out .= '
'; } @@ -2288,32 +2302,33 @@ class Form // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** * Return list of products for customer in Ajax if Ajax activated or go to select_produits_list * - * @param int $selected Preselected products - * @param string $htmlname Name of HTML select field (must be unique in page). - * @param int|string $filtertype Filter on product type (''=nofilter, 0=product, 1=service) - * @param int $limit Limit on number of returned lines - * @param int $price_level Level of price to show - * @param int $status Sell status -1=Return all products, 0=Products not on sell, 1=Products on sell - * @param int $finished 2=all, 1=finished, 0=raw material - * @param string $selected_input_value Value of preselected input text (for use with ajax) - * @param int $hidelabel Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after) - * @param array $ajaxoptions Options for ajax_autocompleter - * @param int $socid Thirdparty Id (to get also price dedicated to this customer) - * @param string $showempty '' to not show empty line. Translation key to show an empty line. '1' show empty line with no text. - * @param int $forcecombo Force to use combo box - * @param string $morecss Add more css on select - * @param int $hidepriceinlabel 1=Hide prices in label - * @param string $warehouseStatus Warehouse status filter to count the quantity in stock. Following comma separated filter options can be used - * 'warehouseopen' = count products from open warehouses, - * 'warehouseclosed' = count products from closed warehouses, - * 'warehouseinternal' = count products from warehouses for internal correct/transfer only - * @param array $selected_combinations Selected combinations. Format: array([attrid] => attrval, [...]) - * @param string $nooutput No print, return the output into a string - * @param int $status_purchase Purchase status -1=Return all products, 0=Products not on purchase, 1=Products on purchase - * @return void|string + * @param int $selected Preselected products + * @param string $htmlname Name of HTML select field (must be unique in page). + * @param int|string $filtertype Filter on product type (''=nofilter, 0=product, 1=service) + * @param int $limit Limit on number of returned lines + * @param int $price_level Level of price to show + * @param int $status Sell status -1=Return all products, 0=Products not on sell, 1=Products on sell + * @param int $finished 2=all, 1=finished, 0=raw material + * @param string $selected_input_value Value of preselected input text (for use with ajax) + * @param int $hidelabel Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after) + * @param array $ajaxoptions Options for ajax_autocompleter + * @param int $socid Thirdparty Id (to get also price dedicated to this customer) + * @param string $showempty '' to not show empty line. Translation key to show an empty line. '1' show empty line with no text. + * @param int $forcecombo Force to use combo box + * @param string $morecss Add more css on select + * @param int $hidepriceinlabel 1=Hide prices in label + * @param string $warehouseStatus Warehouse status filter to count the quantity in stock. Following comma separated filter options can be used + * 'warehouseopen' = count products from open warehouses, + * 'warehouseclosed' = count products from closed warehouses, + * 'warehouseinternal' = count products from warehouses for internal correct/transfer only + * @param array $selected_combinations Selected combinations. Format: array([attrid] => attrval, [...]) + * @param string $nooutput No print, return the output into a string + * @param int $status_purchase Purchase status -1=Return all products, 0=Products not on purchase, 1=Products on purchase + * @return void|string */ public function select_produits($selected = '', $htmlname = 'productid', $filtertype = '', $limit = 0, $price_level = 0, $status = 1, $finished = 2, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $hidepriceinlabel = 0, $warehouseStatus = '', $selected_combinations = null, $nooutput = 0, $status_purchase = -1) { @@ -2340,7 +2355,7 @@ class Form $placeholder = ''; if ($selected && empty($selected_input_value)) { - require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; + require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; $producttmpselect = new Product($this->db); $producttmpselect->fetch($selected); $selected_input_value = $producttmpselect->ref; @@ -2355,17 +2370,17 @@ class Form } } // mode=1 means customers products - $urloption = ($socid > 0 ? 'socid='.$socid.'&' : '').'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=1&status='.$status.'&status_purchase='.$status_purchase.'&finished='.$finished.'&hidepriceinlabel='.$hidepriceinlabel.'&warehousestatus='.$warehouseStatus; - $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions); + $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=1&status=' . $status . '&status_purchase=' . $status_purchase . '&finished=' . $finished . '&hidepriceinlabel=' . $hidepriceinlabel . '&warehousestatus=' . $warehouseStatus; + $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions); if (isModEnabled('variants') && is_array($selected_combinations)) { // Code to automatically insert with javascript the select of attributes under the select of product // when a parent of variant has been selected. $out .= ' - '; } if (empty($hidelabel)) { - $out .= $langs->trans("RefOrLabel").' : '; + $out .= $langs->trans("RefOrLabel") . ' : '; } elseif ($hidelabel > 1) { - $placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"'; + $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"'; if ($hidelabel == 2) { $out .= img_picto($langs->trans("Search"), 'search'); } } - $out .= 'global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />'; + $out .= 'global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '') . ' />'; if ($hidelabel == 3) { $out .= img_picto($langs->trans("Search"), 'search'); } @@ -2471,7 +2486,7 @@ class Form * @param string $morecss Add more css on select * @param string $nooutput No print, return the output into a string * @param int $forcecombo Force to use combo box - * @param array $TProducts Add filter on a defined product + * @param array $TProducts Add filter on a defined product * @return void|string */ public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = []) @@ -2479,29 +2494,29 @@ class Form // phpcs:enable global $conf, $user, $langs, $db; - require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; + require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; $error = 0; $out = ''; if (!$forcecombo) { - include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; + include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php'; $events = array(); $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT")); } - $out .= ''; $sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product'; - $sql.= ' FROM '.MAIN_DB_PREFIX.'bom_bom as b'; - $sql.= ' WHERE b.entity IN ('.getEntity('bom').')'; - if (!empty($status)) $sql.= ' AND status = '. (int) $status; - if (!empty($type)) $sql.= ' AND bomtype = '. (int) $type; - if (!empty($TProducts)) $sql .= ' AND fk_product IN ('.$this->db->sanitize(implode(',', $TProducts)).')'; - if (!empty($limit)) $sql.= ' LIMIT '. (int) $limit; + $sql .= ' FROM ' . MAIN_DB_PREFIX . 'bom_bom as b'; + $sql .= ' WHERE b.entity IN (' . getEntity('bom') . ')'; + if (!empty($status)) $sql .= ' AND status = ' . (int)$status; + if (!empty($type)) $sql .= ' AND bomtype = ' . (int)$type; + if (!empty($TProducts)) $sql .= ' AND fk_product IN (' . $this->db->sanitize(implode(',', $TProducts)) . ')'; + if (!empty($limit)) $sql .= ' LIMIT ' . (int)$limit; $resql = $db->query($sql); if ($resql) { - if ($showempty) { + if ($showempty) { $out .= ''; + $out .= '>' . $obj->ref . ' - ' . $product->label . ' - ' . $obj->label . ''; } } else { $error++; @@ -2525,30 +2540,31 @@ class Form } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** - * Return list of products for a customer. + * Return list of products for a customer. * Called by select_produits. * - * @param int $selected Preselected product - * @param string $htmlname Name of select html - * @param string $filtertype Filter on product type (''=nofilter, 0=product, 1=service) - * @param int $limit Limit on number of returned lines - * @param int $price_level Level of price to show - * @param string $filterkey Filter on product - * @param int $status -1=Return all products, 0=Products not on sell, 1=Products on sell - * @param int $finished Filter on finished field: 2=No filter - * @param int $outputmode 0=HTML select string, 1=Array - * @param int $socid Thirdparty Id (to get also price dedicated to this customer) - * @param string $showempty '' to not show empty line. Translation key to show an empty line. '1' show empty line with no text. - * @param int $forcecombo Force to use combo box - * @param string $morecss Add more css on select - * @param int $hidepriceinlabel 1=Hide prices in label - * @param string $warehouseStatus Warehouse status filter to group/count stock. Following comma separated filter options can be used. - * 'warehouseopen' = count products from open warehouses, - * 'warehouseclosed' = count products from closed warehouses, - * 'warehouseinternal' = count products from warehouses for internal correct/transfer only - * @param int $status_purchase Purchase status -1=Return all products, 0=Products not on purchase, 1=Products on purchase - * @return array|string Array of keys for json + * @param int $selected Preselected product + * @param string $htmlname Name of select html + * @param string $filtertype Filter on product type (''=nofilter, 0=product, 1=service) + * @param int $limit Limit on number of returned lines + * @param int $price_level Level of price to show + * @param string $filterkey Filter on product + * @param int $status -1=Return all products, 0=Products not on sell, 1=Products on sell + * @param int $finished Filter on finished field: 2=No filter + * @param int $outputmode 0=HTML select string, 1=Array + * @param int $socid Thirdparty Id (to get also price dedicated to this customer) + * @param string $showempty '' to not show empty line. Translation key to show an empty line. '1' show empty line with no text. + * @param int $forcecombo Force to use combo box + * @param string $morecss Add more css on select + * @param int $hidepriceinlabel 1=Hide prices in label + * @param string $warehouseStatus Warehouse status filter to group/count stock. Following comma separated filter options can be used. + * 'warehouseopen' = count products from open warehouses, + * 'warehouseclosed' = count products from closed warehouses, + * 'warehouseinternal' = count products from warehouses for internal correct/transfer only + * @param int $status_purchase Purchase status -1=Return all products, 0=Products not on purchase, 1=Products on purchase + * @return array|string Array of keys for json */ public function select_produits_list($selected = '', $htmlname = 'productid', $filtertype = '', $limit = 20, $price_level = 0, $filterkey = '', $status = 1, $finished = 2, $outputmode = 0, $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $hidepriceinlabel = 0, $warehouseStatus = '', $status_purchase = -1) { @@ -2566,7 +2582,7 @@ class Form $warehouseStatusArray = array(); if (!empty($warehouseStatus)) { - require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php'; + require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php'; if (preg_match('/warehouseclosed/', $warehouseStatus)) { $warehouseStatusArray[] = Entrepot::STATUS_CLOSED; } @@ -2580,19 +2596,19 @@ class Form $selectFields = " p.rowid, p.ref, p.label, p.description, p.barcode, p.fk_country, p.fk_product_type, p.price, p.price_ttc, p.price_base_type, p.tva_tx, p.default_vat_code, p.duration, p.fk_price_expression"; if (count($warehouseStatusArray)) { - $selectFieldsGrouped = ", sum(".$this->db->ifsql("e.statut IS NULL", "0", "ps.reel").") as stock"; // e.statut is null if there is no record in stock + $selectFieldsGrouped = ", sum(" . $this->db->ifsql("e.statut IS NULL", "0", "ps.reel") . ") as stock"; // e.statut is null if there is no record in stock } else { - $selectFieldsGrouped = ", ".$this->db->ifsql("p.stock IS NULL", 0, "p.stock")." AS stock"; + $selectFieldsGrouped = ", " . $this->db->ifsql("p.stock IS NULL", 0, "p.stock") . " AS stock"; } $sql = "SELECT "; - $sql .= $selectFields.$selectFieldsGrouped; + $sql .= $selectFields . $selectFieldsGrouped; if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY)) { //Product category - $sql .= ", (SELECT ".$this->db->prefix()."categorie_product.fk_categorie - FROM ".$this->db->prefix()."categorie_product - WHERE ".$this->db->prefix()."categorie_product.fk_product=p.rowid + $sql .= ", (SELECT " . $this->db->prefix() . "categorie_product.fk_categorie + FROM " . $this->db->prefix() . "categorie_product + WHERE " . $this->db->prefix() . "categorie_product.fk_product=p.rowid LIMIT 1 ) AS categorie_product_id "; } @@ -2618,83 +2634,83 @@ class Form } // Price by quantity if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) { - $sql .= ", (SELECT pp.rowid FROM ".$this->db->prefix()."product_price as pp WHERE pp.fk_product = p.rowid"; + $sql .= ", (SELECT pp.rowid FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid"; if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) { - $sql .= " AND price_level = ".((int) $price_level); + $sql .= " AND price_level = " . ((int)$price_level); } $sql .= " ORDER BY date_price"; $sql .= " DESC LIMIT 1) as price_rowid"; - $sql .= ", (SELECT pp.price_by_qty FROM ".$this->db->prefix()."product_price as pp WHERE pp.fk_product = p.rowid"; // price_by_qty is 1 if some prices by qty exists in subtable + $sql .= ", (SELECT pp.price_by_qty FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid"; // price_by_qty is 1 if some prices by qty exists in subtable if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) { - $sql .= " AND price_level = ".((int) $price_level); + $sql .= " AND price_level = " . ((int)$price_level); } $sql .= " ORDER BY date_price"; $sql .= " DESC LIMIT 1) as price_by_qty"; $selectFields .= ", price_rowid, price_by_qty"; } - $sql .= " FROM ".$this->db->prefix()."product as p"; + $sql .= " FROM " . $this->db->prefix() . "product as p"; if (count($warehouseStatusArray)) { - $sql .= " LEFT JOIN ".$this->db->prefix()."product_stock as ps on ps.fk_product = p.rowid"; - $sql .= " LEFT JOIN ".$this->db->prefix()."entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (".getEntity('stock').")"; - $sql .= ' AND e.statut IN ('.$this->db->sanitize($this->db->escape(implode(',', $warehouseStatusArray))).')'; // Return line if product is inside the selected stock. If not, an empty line will be returned so we will count 0. + $sql .= " LEFT JOIN " . $this->db->prefix() . "product_stock as ps on ps.fk_product = p.rowid"; + $sql .= " LEFT JOIN " . $this->db->prefix() . "entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (" . getEntity('stock') . ")"; + $sql .= ' AND e.statut IN (' . $this->db->sanitize($this->db->escape(implode(',', $warehouseStatusArray))) . ')'; // Return line if product is inside the selected stock. If not, an empty line will be returned so we will count 0. } // include search in supplier ref if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) { - $sql .= " LEFT JOIN ".$this->db->prefix()."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product"; + $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product"; } //Price by customer if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) { - $sql .= " LEFT JOIN ".$this->db->prefix()."product_customer_price as pcp ON pcp.fk_soc=".((int) $socid)." AND pcp.fk_product=p.rowid"; + $sql .= " LEFT JOIN " . $this->db->prefix() . "product_customer_price as pcp ON pcp.fk_soc=" . ((int)$socid) . " AND pcp.fk_product=p.rowid"; } // Units if (getDolGlobalInt('PRODUCT_USE_UNITS')) { - $sql .= " LEFT JOIN ".$this->db->prefix()."c_units u ON u.rowid = p.fk_unit"; + $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit"; } // Multilang : we add translation if (getDolGlobalInt('MAIN_MULTILANGS')) { - $sql .= " LEFT JOIN ".$this->db->prefix()."product_lang as pl ON pl.fk_product = p.rowid "; + $sql .= " LEFT JOIN " . $this->db->prefix() . "product_lang as pl ON pl.fk_product = p.rowid "; if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && !empty($socid)) { - require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php'; + require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php'; $soc = new Societe($this->db); $result = $soc->fetch($socid); if ($result > 0 && !empty($soc->default_lang)) { - $sql .= " AND pl.lang = '".$this->db->escape($soc->default_lang)."'"; + $sql .= " AND pl.lang = '" . $this->db->escape($soc->default_lang) . "'"; } else { - $sql .= " AND pl.lang = '".$this->db->escape($langs->getDefaultLang())."'"; + $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'"; } } else { - $sql .= " AND pl.lang = '".$this->db->escape($langs->getDefaultLang())."'"; + $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'"; } } if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) { - $sql .= " LEFT JOIN ".$this->db->prefix()."product_attribute_combination pac ON pac.fk_product_child = p.rowid"; + $sql .= " LEFT JOIN " . $this->db->prefix() . "product_attribute_combination pac ON pac.fk_product_child = p.rowid"; } - $sql .= ' WHERE p.entity IN ('.getEntity('product').')'; + $sql .= ' WHERE p.entity IN (' . getEntity('product') . ')'; if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) { $sql .= " AND pac.rowid IS NULL"; } if ($finished == 0) { - $sql .= " AND p.finished = ".((int) $finished); + $sql .= " AND p.finished = " . ((int)$finished); } elseif ($finished == 1) { - $sql .= " AND p.finished = ".((int) $finished); + $sql .= " AND p.finished = " . ((int)$finished); if ($status >= 0) { - $sql .= " AND p.tosell = ".((int) $status); + $sql .= " AND p.tosell = " . ((int)$status); } } elseif ($status >= 0) { - $sql .= " AND p.tosell = ".((int) $status); + $sql .= " AND p.tosell = " . ((int)$status); } if ($status_purchase >= 0) { - $sql .= " AND p.tobuy = ".((int) $status_purchase); + $sql .= " AND p.tobuy = " . ((int)$status_purchase); } // Filter by product type if (strval($filtertype) != '') { - $sql .= " AND p.fk_product_type = ".((int) $filtertype); + $sql .= " AND p.fk_product_type = " . ((int)$filtertype); } elseif (!isModEnabled('product')) { // when product module is disabled, show services only $sql .= " AND p.fk_product_type = 1"; } elseif (!isModEnabled('service')) { // when service module is disabled, show products only @@ -2718,21 +2734,21 @@ class Form if ($i > 0) { $sql .= " AND "; } - $sql .= "(p.ref LIKE '".$this->db->escape($prefix.$crit)."%' OR p.label LIKE '".$this->db->escape($prefix.$crit)."%'"; + $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'"; if (getDolGlobalInt('MAIN_MULTILANGS')) { - $sql .= " OR pl.label LIKE '".$this->db->escape($prefix.$crit)."%'"; + $sql .= " OR pl.label LIKE '" . $this->db->escape($prefix . $crit) . "%'"; } if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) { - $sql .= " OR pcp.ref_customer LIKE '".$this->db->escape($prefix.$crit)."%'"; + $sql .= " OR pcp.ref_customer LIKE '" . $this->db->escape($prefix . $crit) . "%'"; } if (!empty($conf->global->PRODUCT_AJAX_SEARCH_ON_DESCRIPTION)) { - $sql .= " OR p.description LIKE '".$this->db->escape($prefix.$crit)."%'"; + $sql .= " OR p.description LIKE '" . $this->db->escape($prefix . $crit) . "%'"; if (getDolGlobalInt('MAIN_MULTILANGS')) { - $sql .= " OR pl.description LIKE '".$this->db->escape($prefix.$crit)."%'"; + $sql .= " OR pl.description LIKE '" . $this->db->escape($prefix . $crit) . "%'"; } } if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) { - $sql .= " OR pfp.ref_fourn LIKE '".$this->db->escape($prefix.$crit)."%'"; + $sql .= " OR pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'"; } $sql .= ")"; $i++; @@ -2741,12 +2757,12 @@ class Form $sql .= ")"; } if (isModEnabled('barcode')) { - $sql .= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'"; + $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'"; } $sql .= ')'; } if (count($warehouseStatusArray)) { - $sql .= " GROUP BY ".$selectFields; + $sql .= " GROUP BY " . $selectFields; } //Sort by category @@ -2761,23 +2777,23 @@ class Form $sql .= $this->db->plimit($limit, 0); // Build output string - dol_syslog(get_class($this)."::select_produits_list search products", LOG_DEBUG); + dol_syslog(get_class($this) . "::select_produits_list search products", LOG_DEBUG); $result = $this->db->query($sql); if ($result) { - require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; - require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php'; - require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php'; + require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; + require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php'; + require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php'; $num = $this->db->num_rows($result); $events = null; if (!$forcecombo) { - include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; + include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php'; $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT")); } - $out .= ''; $textifempty = ''; // Do not use textifempty = ' ' or ' ' here, or search on key will search on ' key'. @@ -2794,7 +2810,7 @@ class Form } } if ($showempty) { - $out .= ''; + $out .= ''; } $i = 0; @@ -2805,11 +2821,11 @@ class Form if ((!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) && !empty($objp->price_by_qty) && $objp->price_by_qty == 1) { // Price by quantity will return many prices for the same product $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type"; - $sql .= " FROM ".$this->db->prefix()."product_price_by_qty"; - $sql .= " WHERE fk_product_price = ".((int) $objp->price_rowid); + $sql .= " FROM " . $this->db->prefix() . "product_price_by_qty"; + $sql .= " WHERE fk_product_price = " . ((int)$objp->price_rowid); $sql .= " ORDER BY quantity ASC"; - dol_syslog(get_class($this)."::select_produits_list search prices by qty", LOG_DEBUG); + dol_syslog(get_class($this) . "::select_produits_list search prices by qty", LOG_DEBUG); $result2 = $this->db->query($sql); if ($result2) { $nb_prices = $this->db->num_rows($result2); @@ -2847,7 +2863,7 @@ class Form $price_product = new Product($this->db); $price_product->fetch($objp->rowid, '', '', 1); - require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php'; + require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php'; $priceparser = new PriceParser($this->db); $price_result = $priceparser->parseProduct($price_product); if ($price_result >= 0) { @@ -2891,15 +2907,15 @@ class Form * This define value for &$opt and &$optJson. * This function is called by select_produits_list(). * - * @param object $objp Resultset of fetch - * @param string $opt Option (var used for returned value in string option format) - * @param string $optJson Option (var used for returned value in json format) - * @param int $price_level Price level - * @param string $selected Preselected value - * @param int $hidepriceinlabel Hide price in label - * @param string $filterkey Filter key to highlight - * @param int $novirtualstock Do not load virtual stock, even if slow option STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO is on. - * @return void + * @param object $objp Resultset of fetch + * @param string $opt Option (var used for returned value in string option format) + * @param string $optJson Option (var used for returned value in json format) + * @param int $price_level Price level + * @param string $selected Preselected value + * @param int $hidepriceinlabel Hide price in label + * @param string $filterkey Filter key to highlight + * @param int $novirtualstock Do not load virtual stock, even if slow option STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO is on. + * @return void */ protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0) { @@ -2930,7 +2946,7 @@ class Form $label = $objp->label_translated; } if (!empty($filterkey) && $filterkey != '') { - $label = preg_replace('/('.preg_quote($filterkey, '/').')/i', '$1', $label, 1); + $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '$1', $label, 1); } $outkey = $objp->rowid; @@ -2947,36 +2963,36 @@ class Form $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid; $outtype = $objp->fk_product_type; - $outdurationvalue = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : ''; - $outdurationunit = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, -1) : ''; + $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : ''; + $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : ''; if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) { - require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; + require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php'; } // Units $outvalUnits = ''; if (getDolGlobalInt('PRODUCT_USE_UNITS')) { if (!empty($objp->unit_short)) { - $outvalUnits .= ' - '.$objp->unit_short; + $outvalUnits .= ' - ' . $objp->unit_short; } } if (!empty($conf->global->PRODUCT_SHOW_DIMENSIONS_IN_COMBO)) { if (!empty($objp->weight) && $objp->weight_units !== null) { $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs); - $outvalUnits .= ' - '.$unitToShow; + $outvalUnits .= ' - ' . $unitToShow; } if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) { - $unitToShow = $objp->length.' x '.$objp->width.' x '.$objp->height.' '.measuringUnitString(0, 'size', $objp->length_units); - $outvalUnits .= ' - '.$unitToShow; + $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units); + $outvalUnits .= ' - ' . $unitToShow; } if (!empty($objp->surface) && $objp->surface_units !== null) { $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs); - $outvalUnits .= ' - '.$unitToShow; + $outvalUnits .= ' - ' . $unitToShow; } if (!empty($objp->volume) && $objp->volume_units !== null) { $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs); - $outvalUnits .= ' - '.$unitToShow; + $outvalUnits .= ' - ' . $unitToShow; } } if ($outdurationvalue && $outdurationunit) { @@ -2988,14 +3004,14 @@ class Form 'y' => $langs->trans('Year') ); if (isset($da[$outdurationunit])) { - $outvalUnits .= ' - '.$outdurationvalue.' '.$langs->transnoentities($da[$outdurationunit].($outdurationvalue > 1 ? 's' : '')); + $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : '')); } } - $opt = '\n"; $optJson = array( - 'key'=>$outkey, - 'value'=>$outref, - 'label'=>$outval, - 'label2'=>$outlabel, - 'desc'=>$outdesc, - 'type'=>$outtype, - 'price_ht'=>price2num($outprice_ht), - 'price_ttc'=>price2num($outprice_ttc), - 'price_ht_locale'=>price(price2num($outprice_ht)), - 'price_ttc_locale'=>price(price2num($outprice_ttc)), - 'pricebasetype'=>$outpricebasetype, - 'tva_tx'=>$outtva_tx, - 'default_vat_code'=>$outdefault_vat_code, - 'qty'=>$outqty, - 'discount'=>$outdiscount, - 'duration_value'=>$outdurationvalue, - 'duration_unit'=>$outdurationunit, - 'pbq'=>$outpbq, - 'labeltrans'=>$outlabel_translated, - 'desctrans'=>$outdesc_translated, - 'ref_customer'=>$outrefcust + 'key' => $outkey, + 'value' => $outref, + 'label' => $outval, + 'label2' => $outlabel, + 'desc' => $outdesc, + 'type' => $outtype, + 'price_ht' => price2num($outprice_ht), + 'price_ttc' => price2num($outprice_ttc), + 'price_ht_locale' => price(price2num($outprice_ht)), + 'price_ttc_locale' => price(price2num($outprice_ttc)), + 'pricebasetype' => $outpricebasetype, + 'tva_tx' => $outtva_tx, + 'default_vat_code' => $outdefault_vat_code, + 'qty' => $outqty, + 'discount' => $outdiscount, + 'duration_value' => $outdurationvalue, + 'duration_unit' => $outdurationunit, + 'pbq' => $outpbq, + 'labeltrans' => $outlabel_translated, + 'desctrans' => $outdesc_translated, + 'ref_customer' => $outrefcust ); } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** - * Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs_list) + * Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs_list) * - * @param int $socid Id third party - * @param string $selected Preselected product - * @param string $htmlname Name of HTML Select - * @param string $filtertype Filter on product type (''=nofilter, 0=product, 1=service) - * @param string $filtre For a SQL filter - * @param array $ajaxoptions Options for ajax_autocompleter - * @param int $hidelabel Hide label (0=no, 1=yes) - * @param int $alsoproductwithnosupplierprice 1=Add also product without supplier prices - * @param string $morecss More CSS - * @param string $placeholder Placeholder - * @return void + * @param int $socid Id third party + * @param string $selected Preselected product + * @param string $htmlname Name of HTML Select + * @param string $filtertype Filter on product type (''=nofilter, 0=product, 1=service) + * @param string $filtre For a SQL filter + * @param array $ajaxoptions Options for ajax_autocompleter + * @param int $hidelabel Hide label (0=no, 1=yes) + * @param int $alsoproductwithnosupplierprice 1=Add also product without supplier prices + * @param string $morecss More CSS + * @param string $placeholder Placeholder + * @return void */ public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '') { @@ -3244,7 +3261,7 @@ class Form $selected_input_value = ''; if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) { if ($selected > 0) { - require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; + require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; $producttmpselect = new Product($this->db); $producttmpselect->fetch($selected); $selected_input_value = $producttmpselect->ref; @@ -3252,33 +3269,34 @@ class Form } // mode=2 means suppliers products - $urloption = ($socid > 0 ? 'socid='.$socid.'&' : '').'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=2&status='.$status.'&finished='.$finished.'&alsoproductwithnosupplierprice='.$alsoproductwithnosupplierprice; - print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions); + $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=2&status=' . $status . '&finished=' . $finished . '&alsoproductwithnosupplierprice=' . $alsoproductwithnosupplierprice; + print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions); - print ($hidelabel ? '' : $langs->trans("RefOrLabel").' : ').''; + print ($hidelabel ? '' : $langs->trans("RefOrLabel") . ' : ') . ''; } else { print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder); } } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** - * Return list of suppliers products + * Return list of suppliers products * - * @param int $socid Id of supplier thirdparty (0 = no filter) - * @param int $selected Product price pre-selected (must be 'id' in product_fournisseur_price or 'idprod_IDPROD') - * @param string $htmlname Name of HTML select - * @param string $filtertype Filter on product type (''=nofilter, 0=product, 1=service) - * @param string $filtre Generic filter. Data must not come from user input. - * @param string $filterkey Filter of produdts - * @param int $statut -1=Return all products, 0=Products not on buy, 1=Products on buy - * @param int $outputmode 0=HTML select string, 1=Array - * @param int $limit Limit of line number - * @param int $alsoproductwithnosupplierprice 1=Add also product without supplier prices - * @param string $morecss Add more CSS - * @param int $showstockinlist Show stock information (slower). - * @param string $placeholder Placeholder - * @return array|string Array of keys for json or HTML component + * @param int $socid Id of supplier thirdparty (0 = no filter) + * @param int $selected Product price pre-selected (must be 'id' in product_fournisseur_price or 'idprod_IDPROD') + * @param string $htmlname Name of HTML select + * @param string $filtertype Filter on product type (''=nofilter, 0=product, 1=service) + * @param string $filtre Generic filter. Data must not come from user input. + * @param string $filterkey Filter of produdts + * @param int $statut -1=Return all products, 0=Products not on buy, 1=Products on buy + * @param int $outputmode 0=HTML select string, 1=Array + * @param int $limit Limit of line number + * @param int $alsoproductwithnosupplierprice 1=Add also product without supplier prices + * @param string $morecss Add more CSS + * @param int $showstockinlist Show stock information (slower). + * @param string $placeholder Placeholder + * @return array|string Array of keys for json or HTML component */ public function select_produits_fournisseurs_list($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $filterkey = '', $statut = -1, $outputmode = 0, $limit = 100, $alsoproductwithnosupplierprice = 0, $morecss = '', $showstockinlist = 0, $placeholder = '') { @@ -3314,25 +3332,25 @@ class Form if (isModEnabled('barcode')) { $sql .= ", pfp.barcode"; } - $sql .= " FROM ".$this->db->prefix()."product as p"; - $sql .= " LEFT JOIN ".$this->db->prefix()."product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (".getEntity('product').") )"; + $sql .= " FROM " . $this->db->prefix() . "product as p"; + $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (" . getEntity('product') . ") )"; if ($socid > 0) { - $sql .= " AND pfp.fk_soc = ".((int) $socid); + $sql .= " AND pfp.fk_soc = " . ((int)$socid); } - $sql .= " LEFT JOIN ".$this->db->prefix()."societe as s ON pfp.fk_soc = s.rowid"; + $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid"; // Units if (getDolGlobalInt('PRODUCT_USE_UNITS')) { - $sql .= " LEFT JOIN ".$this->db->prefix()."c_units u ON u.rowid = p.fk_unit"; + $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit"; } - $sql .= " WHERE p.entity IN (".getEntity('product').")"; + $sql .= " WHERE p.entity IN (" . getEntity('product') . ")"; if ($statut != -1) { - $sql .= " AND p.tobuy = ".((int) $statut); + $sql .= " AND p.tobuy = " . ((int)$statut); } if (strval($filtertype) != '') { - $sql .= " AND p.fk_product_type = ".((int) $filtertype); + $sql .= " AND p.fk_product_type = " . ((int)$filtertype); } if (!empty($filtre)) { - $sql .= " ".$filtre; + $sql .= " " . $filtre; } // Add where from hooks $parameters = array(); @@ -3352,9 +3370,9 @@ class Form if ($i > 0) { $sql .= " AND "; } - $sql .= "(pfp.ref_fourn LIKE '".$this->db->escape($prefix.$crit)."%' OR p.ref LIKE '".$this->db->escape($prefix.$crit)."%' OR p.label LIKE '".$this->db->escape($prefix.$crit)."%'"; + $sql .= "(pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'"; if (!empty($conf->global->PRODUIT_FOURN_TEXTS)) { - $sql .= " OR pfp.desc_fourn LIKE '".$this->db->escape($prefix.$crit)."%'"; + $sql .= " OR pfp.desc_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'"; } $sql .= ")"; $i++; @@ -3363,8 +3381,8 @@ class Form $sql .= ")"; } if (isModEnabled('barcode')) { - $sql .= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'"; - $sql .= " OR pfp.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'"; + $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'"; + $sql .= " OR pfp.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'"; } $sql .= ')'; } @@ -3373,20 +3391,20 @@ class Form // Build output string - dol_syslog(get_class($this)."::select_produits_fournisseurs_list", LOG_DEBUG); + dol_syslog(get_class($this) . "::select_produits_fournisseurs_list", LOG_DEBUG); $result = $this->db->query($sql); if ($result) { - require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php'; - require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php'; + require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php'; + require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php'; $num = $this->db->num_rows($result); //$out.=''; + $out .= ''; + $form = ''; + print ''; + print ''; + print ''; + $out .= ''; + $out .= ''; if ($user->admin && empty($noinfoadmin)) { - $out.= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); + $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); } - $out.= ajax_combobox($htmlname); + $out .= ajax_combobox($htmlname); if ($deposit_percent >= 0) { - $out .= '