From e915552ae18882a1c39d9a3252ba77e9d9c688f3 Mon Sep 17 00:00:00 2001 From: ATM john Date: Sat, 18 Apr 2020 11:39:33 +0200 Subject: [PATCH 001/120] New class tool for converting units --- htdocs/core/class/unitsTools.class.php | 119 +++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 htdocs/core/class/unitsTools.class.php diff --git a/htdocs/core/class/unitsTools.class.php b/htdocs/core/class/unitsTools.class.php new file mode 100644 index 00000000000..79ffdb82338 --- /dev/null +++ b/htdocs/core/class/unitsTools.class.php @@ -0,0 +1,119 @@ +unit_type == 'time'){ + return doubleval($unit->scale); + } + + return pow($base, doubleval($unit->scale)); + } + + return 0; + } + + /** + * return first result from query + * @param string $sql the sql query string + * @return bool| var + */ + static public function dbGetvalue($sql) + { + global $db; + $sql .= ' LIMIT 1;'; + + $res = $db->query($sql); + if ($res) + { + $Tresult = $db->fetch_row($res); + return $Tresult[0]; + } + + return false; + } + + /** + * return first result from query + * @param string $sql the sql query string + * @return bool| var + */ + static public function dbGetRow($sql) + { + global $db; + $sql .= ' LIMIT 1;'; + + $res = $db->query($sql); + if ($res) + { + return $db->fetch_object($res); + } + + return false; + } +} From 09591d75f6bfd848363cddd4a4dbf0888bf5ddb9 Mon Sep 17 00:00:00 2001 From: ATM john Date: Sat, 18 Apr 2020 13:20:08 +0200 Subject: [PATCH 002/120] Sql write less do more... --- htdocs/core/class/unitsTools.class.php | 42 ++------------------------ htdocs/core/db/DoliDB.class.php | 38 +++++++++++++++++++++++ 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/htdocs/core/class/unitsTools.class.php b/htdocs/core/class/unitsTools.class.php index 79ffdb82338..a5bc839da0c 100644 --- a/htdocs/core/class/unitsTools.class.php +++ b/htdocs/core/class/unitsTools.class.php @@ -63,9 +63,10 @@ class UnitsTools */ static public function scaleOfUnitPow($id) { + global $db; $base = 10; // TODO : add base col into unit dictionary table - $unit = self::dbGetRow('SELECT scale, unit_type from '.MAIN_DB_PREFIX.'c_units WHERE rowid = '.intval($id)); + $unit = $db->getRow('SELECT scale, unit_type from '.MAIN_DB_PREFIX.'c_units WHERE rowid = '.intval($id)); if($unit){ // TODO : if base exist in unit dictionary table remove this convertion exception and update convertion infos in database exemple time hour currently scale 3600 will become scale 2 base 60 if($unit->unit_type == 'time'){ @@ -77,43 +78,4 @@ class UnitsTools return 0; } - - /** - * return first result from query - * @param string $sql the sql query string - * @return bool| var - */ - static public function dbGetvalue($sql) - { - global $db; - $sql .= ' LIMIT 1;'; - - $res = $db->query($sql); - if ($res) - { - $Tresult = $db->fetch_row($res); - return $Tresult[0]; - } - - return false; - } - - /** - * return first result from query - * @param string $sql the sql query string - * @return bool| var - */ - static public function dbGetRow($sql) - { - global $db; - $sql .= ' LIMIT 1;'; - - $res = $db->query($sql); - if ($res) - { - return $db->fetch_object($res); - } - - return false; - } } diff --git a/htdocs/core/db/DoliDB.class.php b/htdocs/core/db/DoliDB.class.php index 96e76097877..c38db8f9c99 100644 --- a/htdocs/core/db/DoliDB.class.php +++ b/htdocs/core/db/DoliDB.class.php @@ -297,4 +297,42 @@ abstract class DoliDB implements Database { return $this->lastqueryerror; } + + + /** + * return first result value from query + * @param string $sql the sql query string + * @return bool| var + */ + public function getvalue($sql) + { + $sql .= ' LIMIT 1;'; + + $res = $this->query($sql); + if ($res) + { + $Tresult = $this->fetch_row($res); + return $Tresult[0]; + } + + return false; + } + + /** + * return first result from query as object + * @param string $sql the sql query string + * @return bool| var + */ + public function getRow($sql) + { + $sql .= ' LIMIT 1;'; + + $res = $this->query($sql); + if ($res) + { + return $this->fetch_object($res); + } + + return false; + } } From 395446a924f6a5ed7d3f3851f6906b40dfe35180 Mon Sep 17 00:00:00 2001 From: ATM john Date: Sat, 18 Apr 2020 13:44:13 +0200 Subject: [PATCH 003/120] Add getRows method and comments --- htdocs/core/db/DoliDB.class.php | 36 +++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/htdocs/core/db/DoliDB.class.php b/htdocs/core/db/DoliDB.class.php index c38db8f9c99..e3e0491b298 100644 --- a/htdocs/core/db/DoliDB.class.php +++ b/htdocs/core/db/DoliDB.class.php @@ -300,11 +300,13 @@ abstract class DoliDB implements Database /** - * return first result value from query + * Return first result value from query + * Note : This method executes a given SQL query and retrieves the first value of the first row of results. It should only be used with SELECT queries. + * Dont add LIMIT to your query, it will be added by this method * @param string $sql the sql query string * @return bool| var */ - public function getvalue($sql) + public function getValue($sql) { $sql .= ' LIMIT 1;'; @@ -319,9 +321,11 @@ abstract class DoliDB implements Database } /** - * return first result from query as object + * Return first result from query as object + * Note : This method executes a given SQL query and retrieves the first row of results as an object. It should only be used with SELECT queries + * Dont add LIMIT to your query, it will be added by this method * @param string $sql the sql query string - * @return bool| var + * @return bool| object */ public function getRow($sql) { @@ -335,4 +339,28 @@ abstract class DoliDB implements Database return false; } + + /** + * return all results from query as an array of objects + * Note : This method executes a given SQL query and retrieves all row of results as an array of objects. It should only be used with SELECT queries + * be carefull with this method use it only with some limit of results to avoid performences loss + * @param string $sql the sql query string + * @return bool| array + */ + public function getRows($sql) + { + $res = $this->query($sql); + if ($res) + { + $results = array(); + if($this->num_rows($res) > 0){ + while ($obj = $this->fetch_object($res)){ + $results[] = $obj; + } + } + return $results; + } + + return false; + } } From f2435f6247adb16374ff732dd8797e81a335c720 Mon Sep 17 00:00:00 2001 From: ATM john Date: Sat, 18 Apr 2020 16:08:26 +0200 Subject: [PATCH 004/120] Move methods to cunits class --- htdocs/core/class/cunits.class.php | 73 +++++++++++++++++++++++ htdocs/core/class/unitsTools.class.php | 81 -------------------------- 2 files changed, 73 insertions(+), 81 deletions(-) delete mode 100644 htdocs/core/class/unitsTools.class.php diff --git a/htdocs/core/class/cunits.class.php b/htdocs/core/class/cunits.class.php index 65baf0056e9..6de3af70416 100644 --- a/htdocs/core/class/cunits.class.php +++ b/htdocs/core/class/cunits.class.php @@ -386,4 +386,77 @@ class CUnits // extends CommonObject return 1; } } + + + /** + * Get unit from code + * @param string $code code of unit + * @param string $mode 0= id , short_label=Use short label as value, code=use code + * @return int <0 if KO, Id of code if OK + */ + public function getUnitFromCode($code, $mode = 'code') + { + + if($mode == 'short_label'){ + return dol_getIdFromCode($this->db, $code, 'c_units', 'short_label', 'rowid'); + } + elseif($mode == 'code'){ + return dol_getIdFromCode($this->db, $code, 'c_units', 'code', 'rowid'); + } + + return $code; + } + + /** + * Unit converter + * @param double $value value to convert + * @param int $fk_unit current unit id of value + * @param int $fk_new_unit the id of unit to convert in + * @return double + */ + public function unitConverter($value, $fk_unit, $fk_new_unit = 0) + { + $value = doubleval(price2num($value)); + $fk_unit = intval($fk_unit); + + // Calcul en unité de base + $scaleUnitPow = $this->scaleOfUnitPow($fk_unit); + + // convert to standard unit + $value = $value * $scaleUnitPow; + if($fk_new_unit !=0 ){ + // Calcul en unité de base + $scaleUnitPow = $this->scaleOfUnitPow($fk_new_unit); + if(!empty($scaleUnitPow)) + { + // convert to new unit + $value = $value / $scaleUnitPow; + } + } + return round($value, 2); + } + + + + /** + * get scale of unit factor + * @param $id int id of unit in dictionary + * @return float|int + */ + public function scaleOfUnitPow($id) + { + $base = 10; + // TODO : add base col into unit dictionary table + $unit = $this->db->getRow('SELECT scale, unit_type from '.MAIN_DB_PREFIX.'c_units WHERE rowid = '.intval($id)); + if($unit){ + // TODO : if base exist in unit dictionary table remove this convertion exception and update convertion infos in database exemple time hour currently scale 3600 will become scale 2 base 60 + if($unit->unit_type == 'time'){ + return doubleval($unit->scale); + } + + return pow($base, doubleval($unit->scale)); + } + + return 0; + } } diff --git a/htdocs/core/class/unitsTools.class.php b/htdocs/core/class/unitsTools.class.php deleted file mode 100644 index a5bc839da0c..00000000000 --- a/htdocs/core/class/unitsTools.class.php +++ /dev/null @@ -1,81 +0,0 @@ -getRow('SELECT scale, unit_type from '.MAIN_DB_PREFIX.'c_units WHERE rowid = '.intval($id)); - if($unit){ - // TODO : if base exist in unit dictionary table remove this convertion exception and update convertion infos in database exemple time hour currently scale 3600 will become scale 2 base 60 - if($unit->unit_type == 'time'){ - return doubleval($unit->scale); - } - - return pow($base, doubleval($unit->scale)); - } - - return 0; - } -} From e230a3a264ce7e81b0ea61111ebc72161f406a82 Mon Sep 17 00:00:00 2001 From: ATM john Date: Sat, 18 Apr 2020 16:24:12 +0200 Subject: [PATCH 005/120] add num row test --- htdocs/core/db/DoliDB.class.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/htdocs/core/db/DoliDB.class.php b/htdocs/core/db/DoliDB.class.php index e3e0491b298..3bb5e025c34 100644 --- a/htdocs/core/db/DoliDB.class.php +++ b/htdocs/core/db/DoliDB.class.php @@ -313,8 +313,10 @@ abstract class DoliDB implements Database $res = $this->query($sql); if ($res) { - $Tresult = $this->fetch_row($res); - return $Tresult[0]; + if($this->num_rows($res) > 0) { + $Tresult = $this->fetch_row($res); + return reset($Tresult); + } } return false; From 3f5270cf3906cc13156addc507fe688dc5451007 Mon Sep 17 00:00:00 2001 From: ATM john Date: Wed, 22 Apr 2020 23:12:15 +0200 Subject: [PATCH 006/120] Remove getValue Method : usage of fetch_row is deprecated --- htdocs/core/db/DoliDB.class.php | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/htdocs/core/db/DoliDB.class.php b/htdocs/core/db/DoliDB.class.php index 3bb5e025c34..2818eff65e2 100644 --- a/htdocs/core/db/DoliDB.class.php +++ b/htdocs/core/db/DoliDB.class.php @@ -298,30 +298,6 @@ abstract class DoliDB implements Database return $this->lastqueryerror; } - - /** - * Return first result value from query - * Note : This method executes a given SQL query and retrieves the first value of the first row of results. It should only be used with SELECT queries. - * Dont add LIMIT to your query, it will be added by this method - * @param string $sql the sql query string - * @return bool| var - */ - public function getValue($sql) - { - $sql .= ' LIMIT 1;'; - - $res = $this->query($sql); - if ($res) - { - if($this->num_rows($res) > 0) { - $Tresult = $this->fetch_row($res); - return reset($Tresult); - } - } - - return false; - } - /** * Return first result from query as object * Note : This method executes a given SQL query and retrieves the first row of results as an object. It should only be used with SELECT queries From 1aafd4667b70148265d79ef44731e659c9b1cc3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Fri, 24 Apr 2020 11:57:23 +0200 Subject: [PATCH 007/120] fix countable php7 warning --- htdocs/core/lib/sendings.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/sendings.lib.php b/htdocs/core/lib/sendings.lib.php index 6dc78611c26..96a51815b09 100644 --- a/htdocs/core/lib/sendings.lib.php +++ b/htdocs/core/lib/sendings.lib.php @@ -388,7 +388,7 @@ function show_list_sending_receive($origin,$origin_id,$filter='') //var_dump($expedition->linkedObjects); $receiving=''; - if (count($expedition->linkedObjects['delivery']) > 0) $receiving=reset($expedition->linkedObjects['delivery']); // Take first link + if (!empty($expedition->linkedObjects['delivery'])) $receiving=reset($expedition->linkedObjects['delivery']); // Take first link if (! empty($receiving)) { From ac872b6d3dc618b23b456fd7dccb9e9c1535e103 Mon Sep 17 00:00:00 2001 From: Anthony Berton <34568357+bb2a@users.noreply.github.com> Date: Fri, 24 Apr 2020 23:36:37 +0200 Subject: [PATCH 008/120] Update global.inc.php --- htdocs/theme/eldy/global.inc.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index e495a3bb4bc..7b8e1373df9 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -3360,6 +3360,7 @@ tr.liste_titre th, th.liste_titre, tr.liste_titre td, td.liste_titre, form.liste } tr.liste_titre th a, th.liste_titre a, tr.liste_titre td a, td.liste_titre a, form.liste_titre div a, div.liste_titre a { text-shadow: none !important; + color: unset; } tr.liste_titre_topborder td { border-top-width: px; From a040cd030569f06a84ea57aaeef31350dd5cbf44 Mon Sep 17 00:00:00 2001 From: Marc Guenneugues Date: Sat, 25 Apr 2020 15:19:47 +0200 Subject: [PATCH 009/120] Properly assign ->id in expensereport fetch_lines --- htdocs/expensereport/class/expensereport.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/expensereport/class/expensereport.class.php b/htdocs/expensereport/class/expensereport.class.php index ab54a4f3915..048bdb5d493 100644 --- a/htdocs/expensereport/class/expensereport.class.php +++ b/htdocs/expensereport/class/expensereport.class.php @@ -1049,7 +1049,7 @@ class ExpenseReport extends CommonObject $deplig = new ExpenseReportLine($this->db); $deplig->rowid = $objp->rowid; - $deplig->id = $objp->id; + $deplig->id = $objp->rowid; $deplig->comments = $objp->comments; $deplig->qty = $objp->qty; $deplig->value_unit = $objp->value_unit; From b90a6024f57097830be749a5eee755cc45b603af Mon Sep 17 00:00:00 2001 From: Ferran Marcet Date: Mon, 27 Apr 2020 10:15:47 +0200 Subject: [PATCH 010/120] FIX: Wrong Sql on getListOfTowns api method --- htdocs/api/class/api_setup.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/api/class/api_setup.class.php b/htdocs/api/class/api_setup.class.php index 5174aae7221..1e1ab2f8307 100644 --- a/htdocs/api/class/api_setup.class.php +++ b/htdocs/api/class/api_setup.class.php @@ -603,7 +603,7 @@ class Setup extends DolibarrApi $sql = "SELECT rowid AS id, zip, town, fk_county, fk_pays AS fk_country"; $sql.= " FROM ".MAIN_DB_PREFIX."c_ziptown as t"; - $sql.= " AND t.active = ".$active; + $sql.= " WHERE t.active = ".$active; if ($zipcode) $sql.=" AND t.zip LIKE '%" . $this->db->escape($zipcode) . "%'"; if ($town) $sql.=" AND t.town LIKE '%" . $this->db->escape($town) . "%'"; // Add sql filters From 7f56c4a785b93f460f43a049257617faa0102d36 Mon Sep 17 00:00:00 2001 From: gauthier Date: Mon, 27 Apr 2020 11:18:53 +0200 Subject: [PATCH 011/120] FIX : Another "Access to undeclared static property: Contact::$table_element" && "Societe::$table_element" --- htdocs/comm/mailing/class/advtargetemailing.class.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/htdocs/comm/mailing/class/advtargetemailing.class.php b/htdocs/comm/mailing/class/advtargetemailing.class.php index da1775955b7..6987a27dacd 100644 --- a/htdocs/comm/mailing/class/advtargetemailing.class.php +++ b/htdocs/comm/mailing/class/advtargetemailing.class.php @@ -615,7 +615,8 @@ class AdvanceTargetingMailing extends CommonObject //Standard Extrafield feature if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) { - $elementtype = Societe::$table_element; + $socstatic = new Societe($this->db); + $elementtype = $socstatic->table_element; $extrafields->fetch_name_optionals_label($elementtype); @@ -752,7 +753,8 @@ class AdvanceTargetingMailing extends CommonObject //Standard Extrafield feature if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) { - $elementtype = Contact::$table_element; + $contactstatic = new Contact($this->db); + $elementtype = $contactstatic->table_element; // fetch optionals attributes and labels dol_include_once('/core/class/extrafields.class.php'); @@ -854,7 +856,8 @@ class AdvanceTargetingMailing extends CommonObject //Standard Extrafield feature if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) { - $elementtype = Societe::$table_element; + $socstatic = new Societe($this->db); + $elementtype = $socstatic->table_element; // fetch optionals attributes and labels dol_include_once('/core/class/extrafields.class.php'); From ed632877971d1de2d5f1b8790d17b4a2b9e34d6f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 27 Apr 2020 14:02:18 +0200 Subject: [PATCH 012/120] Fix font --- htdocs/langs/es_AR/main.lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/langs/es_AR/main.lang b/htdocs/langs/es_AR/main.lang index 1451ea1c508..a48f7399746 100644 --- a/htdocs/langs/es_AR/main.lang +++ b/htdocs/langs/es_AR/main.lang @@ -1,6 +1,6 @@ # Dolibarr language file - Source file is en_US - main DIRECTION=ltr -FONTFORPDF=helvética +FONTFORPDF=helvetica FONTSIZEFORPDF=10 SeparatorDecimal=. SeparatorThousand=, From ed045b26736523cbbf82fc1f8c13081f671192f7 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 27 Apr 2020 14:38:45 +0200 Subject: [PATCH 013/120] FIX #13749 --- htdocs/api/class/api.class.php | 9 +++++++++ htdocs/product/class/api_products.class.php | 18 +++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/htdocs/api/class/api.class.php b/htdocs/api/class/api.class.php index 26f83f36fd6..46431cdb510 100644 --- a/htdocs/api/class/api.class.php +++ b/htdocs/api/class/api.class.php @@ -137,6 +137,15 @@ class DolibarrApi unset($object->labelStatus); unset($object->labelStatusShort); + unset($object->stats_propale); + unset($object->stats_commande); + unset($object->stats_contrat); + unset($object->stats_facture); + unset($object->stats_commande_fournisseur); + unset($object->stats_reception); + unset($object->stats_mrptoconsume); + unset($object->stats_mrptoproduce); + unset($object->element); unset($object->fk_element); unset($object->table_element); diff --git a/htdocs/product/class/api_products.class.php b/htdocs/product/class/api_products.class.php index 0cf6b344abf..b1fee0177d6 100644 --- a/htdocs/product/class/api_products.class.php +++ b/htdocs/product/class/api_products.class.php @@ -669,8 +669,6 @@ class Products extends DolibarrApi } /** - * List purchase prices - * * Get a list of all purchase prices of products * * @param string $sortfield Sort field @@ -702,11 +700,11 @@ class Products extends DolibarrApi if ($supplier > 0) { $sql .= " AND s.fk_soc = ".$db->escape($supplier); } - $sql .= " AND s.fk_product = t.rowid "; + $sql .= " AND s.fk_product = t.rowid"; // Select products of given category if ($category > 0) { $sql .= " AND c.fk_categorie = ".$db->escape($category); - $sql .= " AND c.fk_product = t.rowid "; + $sql .= " AND c.fk_product = t.rowid"; } if ($mode == 1) { // Show only products @@ -739,10 +737,15 @@ class Products extends DolibarrApi while ($i < $min) { $obj = $db->fetch_object($result); - $product_static = new Product($db); - if ($product_static->fetch($obj->rowid)) { - $obj_ret[] = $this->_cleanObjectDatas($product_static); + + $product_fourn = new ProductFournisseur($this->db); + $product_fourn_list = $product_fourn->list_product_fournisseur_price($obj->rowid, '', '', 0, 0); + foreach($product_fourn_list as $tmpobj) { + $this->_cleanObjectDatas($tmpobj); } + //var_dump($product_fourn_list->db);exit; + $obj_ret[$obj->rowid] = $product_fourn_list; + $i++; } } @@ -1527,6 +1530,7 @@ class Products extends DolibarrApi unset($object->prices_by_qty_id); unset($object->libelle); unset($object->product_id_already_linked); + unset($object->reputations); unset($object->name); unset($object->firstname); From 635b9bb0fee53252f5cd5442045032614a8086ab Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 27 Apr 2020 15:27:03 +0200 Subject: [PATCH 014/120] FIX #13641 --- htdocs/core/tpl/extrafields_list_search_sql.tpl.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/core/tpl/extrafields_list_search_sql.tpl.php b/htdocs/core/tpl/extrafields_list_search_sql.tpl.php index 3a0bcf6375c..6b08baddb72 100644 --- a/htdocs/core/tpl/extrafields_list_search_sql.tpl.php +++ b/htdocs/core/tpl/extrafields_list_search_sql.tpl.php @@ -33,12 +33,12 @@ if (! empty($extrafieldsobjectkey) && ! empty($search_array_options) && is_array $sql.= ")"; } } - elseif ($crit != '' && (! in_array($typ, array('select','sellist')) || $crit != '0') && (! in_array($typ, array('link')) || $crit != '-1')) + elseif ($crit != '' && (! in_array($typ, array('select', 'sellist')) || $crit != '0') && (! in_array($typ, array('link')) || $crit != '-1')) { $mode_search=0; - if (in_array($typ, array('int','double','real'))) $mode_search=1; // Search on a numeric - if (in_array($typ, array('sellist','link')) && $crit != '0' && $crit != '-1') $mode_search=2; // Search on a foreign key int - if (in_array($typ, array('chkbxlst','checkbox'))) $mode_search=4; // Search on a multiselect field with sql type = text + if (in_array($typ, array('int', 'double', 'real', 'price'))) $mode_search=1; // Search on a numeric + if (in_array($typ, array('sellist', 'link')) && $crit != '0' && $crit != '-1') $mode_search=2; // Search on a foreign key int + if (in_array($typ, array('chkbxlst', 'checkbox'))) $mode_search=4; // Search on a multiselect field with sql type = text if (is_array($crit)) $crit = implode(' ', $crit); // natural_search() expects a string elseif ($typ === 'select' and is_string($crit) and strpos($crit, ' ') === false) { $sql .= ' AND (' . $extrafieldsobjectprefix.$tmpkey . ' = "' . $db->escape($crit) . '")'; From fe6fb12d189825fdec451cb9dfe4ca69be0f7d13 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 27 Apr 2020 17:13:23 +0200 Subject: [PATCH 015/120] Fix missing link --- htdocs/core/class/notify.class.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/htdocs/core/class/notify.class.php b/htdocs/core/class/notify.class.php index 7a3508c7d2f..c0258bdec90 100644 --- a/htdocs/core/class/notify.class.php +++ b/htdocs/core/class/notify.class.php @@ -314,6 +314,7 @@ class Notify global $user, $conf, $langs, $mysoc; global $hookmanager; global $dolibarr_main_url_root; + global $action; if (!in_array($notifcode, $this->arrayofnotifsupported)) return 0; @@ -526,6 +527,8 @@ class Notify if ($link) $message .= "\n".$urlwithroot.$link; $parameters = array('notifcode'=>$notifcode, 'sendto'=>$sendto, 'replyto'=>$replyto, 'file'=>$filename_list, 'mimefile'=>$mimetype_list, 'filename'=>$mimefilename_list); + if (!isset($action)) $action = ''; + $reshook = $hookmanager->executeHooks('formatNotificationMessage', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks if (empty($reshook)) { @@ -700,21 +703,25 @@ class Notify $mesg = $langs->transnoentitiesnoconv("EMailTextExpeditionValidated", $newref); break; case 'EXPENSE_REPORT_VALIDATE': + $link = ''.$newref.''; $dir_output = $conf->expensereport->dir_output; $object_type = 'expensereport'; $mesg = $langs->transnoentitiesnoconv("EMailTextExpenseReportValidated", $newref); break; case 'EXPENSE_REPORT_APPROVE': + $link = ''.$newref.''; $dir_output = $conf->expensereport->dir_output; $object_type = 'expensereport'; $mesg = $langs->transnoentitiesnoconv("EMailTextExpenseReportApproved", $newref); break; case 'HOLIDAY_VALIDATE': + $link = ''.$newref.''; $dir_output = $conf->holiday->dir_output; $object_type = 'holiday'; $mesg = $langs->transnoentitiesnoconv("EMailTextHolidayValidated", $newref); break; case 'HOLIDAY_APPROVE': + $link = ''.$newref.''; $dir_output = $conf->holiday->dir_output; $object_type = 'holiday'; $mesg = $langs->transnoentitiesnoconv("EMailTextHolidayApproved", $newref); From 31583c9b6380d0ccf3a03eba6244f847d3bc4ae6 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Tue, 28 Apr 2020 04:45:06 +0200 Subject: [PATCH 016/120] NEW: Accountancy add column thirdparty on binding page --- htdocs/accountancy/supplier/lines.php | 31 ++++++++++++++++++++++++--- htdocs/accountancy/supplier/list.php | 30 +++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/htdocs/accountancy/supplier/lines.php b/htdocs/accountancy/supplier/lines.php index 8d3f3937823..e81da78bf55 100644 --- a/htdocs/accountancy/supplier/lines.php +++ b/htdocs/accountancy/supplier/lines.php @@ -1,6 +1,6 @@ - * Copyright (C) 2013-2017 Alexandre Spangaro + * Copyright (C) 2013-2020 Alexandre Spangaro * Copyright (C) 2014-2015 Ari Elbaz (elarifr) * Copyright (C) 2013-2016 Florian Henry * Copyright (C) 2014 Juanjo Menent @@ -27,12 +27,13 @@ require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php'; require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php'; require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; @@ -44,6 +45,7 @@ $optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' $account_parent = GETPOST('account_parent'); $changeaccount = GETPOST('changeaccount'); // Search Getpost +$search_societe = GETPOST('search_societe', 'alpha'); $search_lineid = GETPOST('search_lineid', 'int'); $search_ref = GETPOST('search_ref', 'alpha'); $search_invoice = GETPOST('search_invoice', 'alpha'); @@ -91,6 +93,7 @@ $formaccounting = new FormAccounting($db); // Purge search criteria if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // All tests are required to be compatible with all browsers { + $search_societe = ''; $search_lineid = ''; $search_ref = ''; $search_invoice = ''; @@ -177,7 +180,7 @@ $sql .= " l.rowid, l.fk_product, l.product_type as line_type, l.description, l.t $sql .= " aa.label, aa.account_number, "; $sql .= " p.rowid as product_id, p.fk_product_type as product_type, p.ref as product_ref, p.label as product_label, p.fk_product_type as type,"; $sql .= " co.code as country_code, co.label as country,"; -$sql .= " s.tva_intra"; +$sql .= " s.rowid as socid, s.nom as name, s.tva_intra, s.email, s.town, s.zip, s.fk_pays, s.client, s.fournisseur, s.code_client, s.code_fournisseur, s.code_compta as code_compta_client, s.code_compta_fournisseur"; $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; @@ -188,6 +191,10 @@ $sql .= " INNER JOIN ".MAIN_DB_PREFIX."facture_fourn as f ON f.rowid = l.fk_fact $sql .= " INNER JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = f.fk_soc"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_country as co ON co.rowid = s.fk_pays "; $sql .= " WHERE f.rowid = l.fk_facture_fourn and f.fk_statut >= 1 AND l.fk_code_ventilation <> 0 "; +// Add search filter like +if ($search_societe) { + $sql .= natural_search('s.nom', $search_societe); +} if ($search_lineid) { $sql .= natural_search("l.rowid", $search_lineid, 1); } @@ -264,6 +271,7 @@ if ($result) { $param = ''; if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage); if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit); + if ($search_societe) $param .= "&search_societe=" . urlencode($search_societe); if ($search_invoice) $param .= "&search_invoice=".urlencode($search_invoice); if ($search_ref) $param .= "&search_ref=".urlencode($search_ref); if ($search_label) $param .= "&search_label=".urlencode($search_label); @@ -300,6 +308,7 @@ if ($result) { // We add search filter print ''; + print ''; print ''; print ''; print ''; @@ -325,6 +334,7 @@ if ($result) { print "\n"; print ''; + print_liste_field_titre("ThirdParty", $_SERVER["PHP_SELF"], "s.nom", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("LineId", $_SERVER["PHP_SELF"], "l.rowid", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("Invoice", $_SERVER["PHP_SELF"], "f.ref", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("InvoiceLabel", $_SERVER["PHP_SELF"], "f.libelle", "", $param, '', $sortfield, $sortorder); @@ -341,6 +351,7 @@ if ($result) { print_liste_field_titre($checkpicto, '', '', '', '', '', '', '', 'center '); print "\n"; + $thirdpartystatic = new Societe($db); $facturefournisseur_static = new FactureFournisseur($db); $product_static = new ProductFournisseur($db); @@ -352,6 +363,17 @@ if ($result) { $facturefournisseur_static->ref = $objp->ref; $facturefournisseur_static->id = $objp->facid; + $thirdpartystatic->id = $objp->socid; + $thirdpartystatic->name = $objp->name; + $thirdpartystatic->client = $objp->client; + $thirdpartystatic->fournisseur = $objp->fournisseur; + $thirdpartystatic->code_client = $objp->code_client; + $thirdpartystatic->code_compta_client = $objp->code_compta_client; + $thirdpartystatic->code_fournisseur = $objp->code_fournisseur; + $thirdpartystatic->code_compta_fournisseur = $objp->code_compta_fournisseur; + $thirdpartystatic->email = $objp->email; + $thirdpartystatic->country_code = $objp->country_code; + $product_static->ref = $objp->product_ref; $product_static->id = $objp->product_id; $product_static->label = $objp->product_label; @@ -359,6 +381,9 @@ if ($result) { print ''; + // Thirdparty + print '' . $thirdpartystatic->getNomUrl(1, 'supplier') . ''; + // Line id print ''.$objp->rowid.''; diff --git a/htdocs/accountancy/supplier/list.php b/htdocs/accountancy/supplier/list.php index ce354c789f3..9788de4bb5f 100644 --- a/htdocs/accountancy/supplier/list.php +++ b/htdocs/accountancy/supplier/list.php @@ -27,12 +27,13 @@ */ require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php'; require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php'; require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; @@ -49,6 +50,7 @@ $toselect = GETPOST('toselect', 'array'); $mesCasesCochees = GETPOST('toselect', 'array'); // Search Getpost +$search_societe = GETPOST('search_societe', 'alpha'); $search_lineid = GETPOST('search_lineid', 'int'); $search_invoice = GETPOST('search_invoice', 'alpha'); $search_ref = GETPOST('search_ref', 'alpha'); @@ -116,6 +118,7 @@ if (empty($reshook)) // Purge search criteria if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // All test are required to be compatible with all browsers { + $search_societe=''; $search_lineid = ''; $search_ref = ''; $search_invoice = ''; @@ -216,7 +219,7 @@ $sql .= " p.accountancy_code_buy as code_buy, p.accountancy_code_buy_intra as co $sql .= " p.tosell as status, p.tobuy as status_buy,"; $sql .= " aa.rowid as aarowid, aa2.rowid as aarowid_intra, aa3.rowid as aarowid_export,"; $sql .= " co.code as country_code, co.label as country_label,"; -$sql .= " s.tva_intra"; +$sql .= " s.rowid as socid, s.nom as name, s.tva_intra, s.email, s.town, s.zip, s.fk_pays, s.client, s.fournisseur, s.code_client, s.code_fournisseur, s.code_compta as code_compta_client, s.code_compta_fournisseur"; $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; @@ -231,6 +234,9 @@ $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as aa3 ON p.accountancy $sql .= " WHERE f.fk_statut > 0 AND l.fk_code_ventilation <= 0"; $sql .= " AND l.product_type <= 2"; // Add search filter like +if ($search_societe) { + $sql .= natural_search('s.nom', $search_societe); +} if ($search_lineid) { $sql .= natural_search("l.rowid", $search_lineid, 1); } @@ -314,6 +320,7 @@ if ($result) { $param = ''; if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage); if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit); + if ($search_societe) $param.='&search_societe='.urlencode($search_societe); if ($search_lineid) $param .= '&search_lineid='.urlencode($search_lineid); if ($search_day) $param .= '&search_day='.urlencode($search_day); if ($search_month) $param .= '&search_month='.urlencode($search_month); @@ -364,6 +371,7 @@ if ($result) { // We add search filter print ''; + print ''; print ''; print ''; print ''; @@ -390,6 +398,7 @@ if ($result) { print "\n"; print ''; + print_liste_field_titre("ThirdParty", $_SERVER["PHP_SELF"], "s.nom", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("LineId", $_SERVER["PHP_SELF"], "l.rowid", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("Invoice", $_SERVER["PHP_SELF"], "f.ref", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("InvoiceLabel", $_SERVER["PHP_SELF"], "f.libelle", "", $param, '', $sortfield, $sortorder); @@ -408,6 +417,7 @@ if ($result) { print_liste_field_titre($checkpicto, '', '', '', '', '', '', '', 'center '); print "\n"; + $thirdpartystatic=new Societe($db); $facturefourn_static = new FactureFournisseur($db); $product_static = new Product($db); @@ -424,6 +434,17 @@ if ($result) { $objp->code_buy_l = ''; $objp->code_buy_p = ''; + $thirdpartystatic->id = $objp->socid; + $thirdpartystatic->name = $objp->name; + $thirdpartystatic->client = $objp->client; + $thirdpartystatic->fournisseur = $objp->fournisseur; + $thirdpartystatic->code_client = $objp->code_client; + $thirdpartystatic->code_compta_client = $objp->code_compta_client; + $thirdpartystatic->code_fournisseur = $objp->code_fournisseur; + $thirdpartystatic->code_compta_fournisseur = $objp->code_compta_fournisseur; + $thirdpartystatic->email = $objp->email; + $thirdpartystatic->country_code = $objp->country_code; + $product_static->ref = $objp->product_ref; $product_static->id = $objp->product_id; $product_static->type = $objp->type; @@ -506,6 +527,9 @@ if ($result) { print ''; + // Thirdparty + print '' . $thirdpartystatic->getNomUrl(1, 'supplier') . ''; + // Line id print ''.$objp->rowid.''; From 1f6c959b723e04db550b215f9e05d41f2fdafae9 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Tue, 28 Apr 2020 04:55:54 +0200 Subject: [PATCH 017/120] NEW: Accountancy add column thirdparty on binding page --- htdocs/accountancy/customer/lines.php | 33 ++++++++++++++++++++++---- htdocs/accountancy/customer/list.php | 34 +++++++++++++++++++++++---- htdocs/accountancy/supplier/lines.php | 2 +- htdocs/accountancy/supplier/list.php | 2 +- 4 files changed, 60 insertions(+), 11 deletions(-) diff --git a/htdocs/accountancy/customer/lines.php b/htdocs/accountancy/customer/lines.php index 7e51160195b..94835b429c8 100644 --- a/htdocs/accountancy/customer/lines.php +++ b/htdocs/accountancy/customer/lines.php @@ -1,6 +1,6 @@ - * Copyright (C) 2013-2016 Alexandre Spangaro + * Copyright (C) 2013-2020 Alexandre Spangaro * Copyright (C) 2014-2015 Ari Elbaz (elarifr) * Copyright (C) 2014-2016 Florian Henry * Copyright (C) 2014 Juanjo Menent @@ -27,10 +27,11 @@ require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; @@ -42,6 +43,7 @@ $optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' $account_parent = GETPOST('account_parent'); $changeaccount = GETPOST('changeaccount'); // Search Getpost +$search_societe = GETPOST('search_societe', 'alpha'); $search_lineid = GETPOST('search_lineid', 'int'); $search_ref = GETPOST('search_ref', 'alpha'); $search_invoice = GETPOST('search_invoice', 'alpha'); @@ -89,6 +91,7 @@ $formaccounting = new FormAccounting($db); // Purge search criteria if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // All tests are required to be compatible with all browsers { + $search_societe=''; $search_lineid = ''; $search_ref = ''; $search_invoice = ''; @@ -175,7 +178,7 @@ $sql .= " s.rowid as socid, s.nom as name, s.code_compta, s.code_client,"; $sql .= " p.rowid as product_id, p.fk_product_type as product_type, p.ref as product_ref, p.label as product_label, p.accountancy_code_sell, aa.rowid as fk_compte, aa.account_number, aa.label as label_compte,"; $sql .= " fd.situation_percent,"; $sql .= " co.code as country_code, co.label as country,"; -$sql .= " s.tva_intra"; +$sql .= " s.rowid as socid, s.nom as name, s.tva_intra, s.email, s.town, s.zip, s.fk_pays, s.client, s.fournisseur, s.code_client, s.code_fournisseur, s.code_compta as code_compta_client, s.code_compta_fournisseur"; $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; @@ -193,6 +196,10 @@ if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { } else { $sql .= " AND f.type IN (".Facture::TYPE_STANDARD.",".Facture::TYPE_STANDARD.",".Facture::TYPE_CREDIT_NOTE.",".Facture::TYPE_DEPOSIT.",".Facture::TYPE_SITUATION.")"; } +// Add search filter like +if ($search_societe) { + $sql .= natural_search('s.nom', $search_societe); +} if ($search_lineid) { $sql .= natural_search("fd.rowid", $search_lineid, 1); } @@ -262,6 +269,7 @@ if ($result) { $param = ''; if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage); if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit); + if ($search_societe) $param .= "&search_societe=".urlencode($search_societe); if ($search_invoice) $param .= "&search_invoice=".urlencode($search_invoice); if ($search_ref) $param .= "&search_ref=".urlencode($search_ref); if ($search_label) $param .= "&search_label=".urlencode($search_label); @@ -296,7 +304,8 @@ if ($result) { print ''."\n"; print ''; - print ''; + print ''; + print ''; print ''; print '\n"; print ''; + print_liste_field_titre("ThirdParty", $_SERVER["PHP_SELF"], "s.nom", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("LineId", $_SERVER["PHP_SELF"], "fd.rowid", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("Invoice", $_SERVER["PHP_SELF"], "f.ref", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("Date", $_SERVER["PHP_SELF"], "f.datef, f.ref, fd.rowid", "", $param, '', $sortfield, $sortorder, 'center '); @@ -337,6 +347,7 @@ if ($result) { print_liste_field_titre($clickpicto, '', '', '', '', '', '', '', 'center '); print "\n"; + $thirdpartystatic=new Societe($db); $facture_static = new Facture($db); $product_static = new Product($db); @@ -347,6 +358,17 @@ if ($result) { $facture_static->id = $objp->facid; $facture_static->type = $objp->ftype; + $thirdpartystatic->id = $objp->socid; + $thirdpartystatic->name = $objp->name; + $thirdpartystatic->client = $objp->client; + $thirdpartystatic->fournisseur = $objp->fournisseur; + $thirdpartystatic->code_client = $objp->code_client; + $thirdpartystatic->code_compta_client = $objp->code_compta_client; + $thirdpartystatic->code_fournisseur = $objp->code_fournisseur; + $thirdpartystatic->code_compta_fournisseur = $objp->code_compta_fournisseur; + $thirdpartystatic->email = $objp->email; + $thirdpartystatic->country_code = $objp->country_code; + $product_static->ref = $objp->product_ref; $product_static->id = $objp->product_id; $product_static->label = $objp->product_label; @@ -354,6 +376,9 @@ if ($result) { print ''; + // Thirdparty + print ''; + // Line id print ''; diff --git a/htdocs/accountancy/customer/list.php b/htdocs/accountancy/customer/list.php index 8d09587ca5a..a623628a3d4 100644 --- a/htdocs/accountancy/customer/list.php +++ b/htdocs/accountancy/customer/list.php @@ -1,6 +1,6 @@ - * Copyright (C) 2013-2019 Alexandre Spangaro + * Copyright (C) 2013-2020 Alexandre Spangaro * Copyright (C) 2014-2015 Ari Elbaz (elarifr) * Copyright (C) 2013-2014 Florian Henry * Copyright (C) 2014 Juanjo Menent @@ -27,12 +27,13 @@ */ require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php'; require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; @@ -49,6 +50,7 @@ $toselect = GETPOST('toselect', 'array'); $mesCasesCochees = GETPOST('toselect', 'array'); // Search Getpost +$search_societe = GETPOST('search_societe', 'alpha'); $search_lineid = GETPOST('search_lineid', 'int'); $search_ref = GETPOST('search_ref', 'alpha'); $search_invoice = GETPOST('search_invoice', 'alpha'); @@ -112,6 +114,7 @@ if (empty($reshook)) // Purge search criteria if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // All test are required to be compatible with all browsers { + $search_societe=''; $search_lineid = ''; $search_ref = ''; $search_invoice = ''; @@ -212,7 +215,7 @@ $sql .= " p.accountancy_code_buy as code_buy, p.accountancy_code_buy_intra as co $sql .= " p.tosell as status, p.tobuy as status_buy,"; $sql .= " aa.rowid as aarowid, aa2.rowid as aarowid_intra, aa3.rowid as aarowid_export,"; $sql .= " co.code as country_code, co.label as country_label,"; -$sql .= " s.tva_intra"; +$sql .= " s.rowid as socid, s.nom as name, s.tva_intra, s.email, s.town, s.zip, s.fk_pays, s.client, s.fournisseur, s.code_client, s.code_fournisseur, s.code_compta as code_compta_client, s.code_compta_fournisseur"; $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; @@ -227,6 +230,9 @@ $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as aa3 ON p.accountancy $sql .= " WHERE f.fk_statut > 0 AND l.fk_code_ventilation <= 0"; $sql .= " AND l.product_type <= 2"; // Add search filter like +if ($search_societe) { + $sql .= natural_search('s.nom', $search_societe); +} if ($search_lineid) { $sql .= natural_search("l.rowid", $search_lineid, 1); } @@ -314,6 +320,7 @@ if ($result) { $param = ''; if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage); if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit); + if ($search_societe) $param .= '&search_societe='.urlencode($search_societe); if ($search_lineid) $param .= '&search_lineid='.urlencode($search_lineid); if ($search_day) $param .= '&search_day='.urlencode($search_day); if ($search_month) $param .= '&search_month='.urlencode($search_month); @@ -363,7 +370,8 @@ if ($result) { // We add search filter print ''; - print ''; + print ''; + print ''; print ''; print ''; print ''; + print_liste_field_titre("ThirdParty", $_SERVER["PHP_SELF"], "s.nom", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("LineId", $_SERVER["PHP_SELF"], "l.rowid", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("Invoice", $_SERVER["PHP_SELF"], "f.ref", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("Date", $_SERVER["PHP_SELF"], "f.datef, f.ref, l.rowid", "", $param, '', $sortfield, $sortorder, 'center '); @@ -408,6 +417,7 @@ if ($result) { print_liste_field_titre($checkpicto, '', '', '', '', '', '', '', 'center '); print "\n"; + $thirdpartystatic = new Societe($db); $facture_static = new Facture($db); $product_static = new Product($db); @@ -421,6 +431,17 @@ if ($result) { $objp->code_sell_l = ''; $objp->code_sell_p = ''; + $thirdpartystatic->id = $objp->socid; + $thirdpartystatic->name = $objp->name; + $thirdpartystatic->client = $objp->client; + $thirdpartystatic->fournisseur = $objp->fournisseur; + $thirdpartystatic->code_client = $objp->code_client; + $thirdpartystatic->code_compta_client = $objp->code_compta_client; + $thirdpartystatic->code_fournisseur = $objp->code_fournisseur; + $thirdpartystatic->code_compta_fournisseur = $objp->code_compta_fournisseur; + $thirdpartystatic->email = $objp->email; + $thirdpartystatic->country_code = $objp->country_code; + $product_static->ref = $objp->product_ref; $product_static->id = $objp->product_id; $product_static->type = $objp->type; @@ -525,6 +546,9 @@ if ($result) { print ''; + // Thirdparty + print ''; + // Line id print ''; diff --git a/htdocs/accountancy/supplier/lines.php b/htdocs/accountancy/supplier/lines.php index cd553849414..2e4059bcaba 100644 --- a/htdocs/accountancy/supplier/lines.php +++ b/htdocs/accountancy/supplier/lines.php @@ -309,7 +309,7 @@ if ($result) { // We add search filter print ''; print ''; - print ''; + print ''; print ''; print ''; print ''; print ''; - print ''; + print ''; print ''; print ''; print ''; + // ThirdParty Type + print ''; + // Category + print ''; // User print ''; +// ThirdParty Type +print ''; +// Category +if ($mode == 'customer') +{ + $cat_type = Categorie::TYPE_CUSTOMER; + $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Customer")); +} +if ($mode == 'supplier') +{ + $cat_type = Categorie::TYPE_SUPPLIER; + $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Customer")); +} +print ''; // User print ''; +// ThirdParty Type +print ''; +// Category +print ''; // User print ''; print ''; // Category -print ''; // User From 790cffb7ae4e0b461b226044023fa360fea17809 Mon Sep 17 00:00:00 2001 From: "DEMAREST Maxime (Indelog)" Date: Wed, 29 Apr 2020 15:24:13 +0200 Subject: [PATCH 027/120] Correct select label for categories in stats pages --- htdocs/comm/propal/stats/index.php | 2 +- htdocs/commande/stats/index.php | 2 +- htdocs/compta/facture/stats/index.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/comm/propal/stats/index.php b/htdocs/comm/propal/stats/index.php index 78fbf725929..add31f13f08 100644 --- a/htdocs/comm/propal/stats/index.php +++ b/htdocs/comm/propal/stats/index.php @@ -89,7 +89,7 @@ if ($mode == 'supplier') $title = $langs->trans("ProposalsStatisticsSuppliers").' ('.$langs->trans("SentToSuppliers").")"; $dir = $conf->supplier_proposal->dir_temp; $cat_type = Categorie::TYPE_SUPPLIER; - $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Customer")); + $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Supplier")); } llxHeader('', $title); diff --git a/htdocs/commande/stats/index.php b/htdocs/commande/stats/index.php index d009621dc82..4e7ed481882 100644 --- a/htdocs/commande/stats/index.php +++ b/htdocs/commande/stats/index.php @@ -289,7 +289,7 @@ if ($mode == 'customer') if ($mode == 'supplier') { $cat_type = Categorie::TYPE_SUPPLIER; - $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Customer")); + $cat_label = $langs->trans("Supplier").' '.lcfirst($langs->trans("Customer")); } print ''; print ''."\n"; @@ -2287,6 +2292,7 @@ else print ''; From 6d79eed8c1776cd48d47ff4675b46634ca089c88 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 29 Apr 2020 20:36:14 +0200 Subject: [PATCH 030/120] Fix colspan alignement --- htdocs/societe/card.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/societe/card.php b/htdocs/societe/card.php index 8800bd887a1..b5400db04b3 100644 --- a/htdocs/societe/card.php +++ b/htdocs/societe/card.php @@ -1354,10 +1354,10 @@ else // Phone / Fax print ''; - print ''; + print 'browser->layout == 'phone' ? ' colspan="3"': '').'>'.img_picto('', 'object_phoning').' '; if ($conf->browser->layout == 'phone') print ''; print ''; - print ''; + print 'browser->layout == 'phone' ? ' colspan="3"': '').'>'.img_picto('', 'object_phoning_fax').' '; // Email / Web print ''; @@ -1501,13 +1501,13 @@ else } // Type - Size - print ''; if ($conf->browser->layout == 'phone') print ''; - print ''; From 4dbd16077e4de7228e436573904ced5f8f9bcfa6 Mon Sep 17 00:00:00 2001 From: "jove@bisquerra.com" Date: Thu, 30 Apr 2020 01:10:12 +0200 Subject: [PATCH 031/120] Finish send receipt by email from TakePOS --- htdocs/takepos/admin/setup.php | 2 +- htdocs/takepos/invoice.php | 4 +- htdocs/takepos/receipt.php | 2 +- htdocs/takepos/send.php | 141 +++++++++++---------------------- 4 files changed, 50 insertions(+), 99 deletions(-) diff --git a/htdocs/takepos/admin/setup.php b/htdocs/takepos/admin/setup.php index bf5c4671b13..3e12fdce5c9 100644 --- a/htdocs/takepos/admin/setup.php +++ b/htdocs/takepos/admin/setup.php @@ -362,7 +362,7 @@ if (is_array($formmail->lines_model)) { if (!empty($arrayofmessagename[$modelmail->label])) { $moreonlabel = ' ('.$langs->trans("SeveralLangugeVariatFound").')'; } - $arrayofmessagename[$modelmail->label] = $langs->trans(preg_replace('/\(|\)/', '', $modelmail->label)).$moreonlabel; + $arrayofmessagename[$modelmail->id] = $langs->trans(preg_replace('/\(|\)/', '', $modelmail->topic)).$moreonlabel; } } //var_dump($arraydefaultmessage); diff --git a/htdocs/takepos/invoice.php b/htdocs/takepos/invoice.php index adbf403491e..fa5ca2f83be 100644 --- a/htdocs/takepos/invoice.php +++ b/htdocs/takepos/invoice.php @@ -597,7 +597,7 @@ if ($action == "valid" || $action == "history") } else { $sectionwithinvoicelink .= ' '; } - if ($conf->global->MAIN_FEATURES_LEVEL >= 2) + if ($conf->global->TAKEPOS_EMAIL_TEMPLATE_INVOICE > 0) { $sectionwithinvoicelink .= ' '; } @@ -690,7 +690,7 @@ if ($action == "search") { function SendTicket(id) { console.log("Open box to select the Print/Send form"); - $.colorbox({href:"send.php?facid="+id, width:"90%", height:"50%", transition:"none", iframe:"true", title:"trans("SendTicket"); ?>"}); + $.colorbox({href:"send.php?facid="+id, width:"70%", height:"30%", transition:"none", iframe:"true", title:"trans("SendTicket"); ?>"}); } function Print(id){ diff --git a/htdocs/takepos/receipt.php b/htdocs/takepos/receipt.php index c025f504d73..90b3a5c1fee 100644 --- a/htdocs/takepos/receipt.php +++ b/htdocs/takepos/receipt.php @@ -25,7 +25,7 @@ * \brief Page to show a receipt. */ -require '../main.inc.php'; // Load $user and permissions +if (!isset($action)) require '../main.inc.php'; // If this file is called from send.php avoid load again include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; $langs->loadLangs(array("main", "cashdesk", "companies")); diff --git a/htdocs/takepos/send.php b/htdocs/takepos/send.php index 5774c9bbaf1..720cd4e271c 100644 --- a/htdocs/takepos/send.php +++ b/htdocs/takepos/send.php @@ -1,5 +1,6 @@ +/* Copyright (C) 2019 Thibault FOUCART + * Copyright (C) 2020 Andreu Bisquerra Gaya * * 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 @@ -35,123 +36,73 @@ require '../main.inc.php'; // Load $user and permissions require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; -$invoiceid = GETPOST('facid', 'int'); +$facid = GETPOST('facid', 'int'); +$action = GETPOST('action', 'alpha'); +$email = GETPOST('email', 'alpha'); if (empty($user->rights->takepos->run)) { accessforbidden(); } - -/* - * View - */ - -$invoice = new Facture($db); -if ($invoiceid > 0) -{ - $invoice->fetch($invoiceid); -} -else -{ - $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."facture where ref='(PROV-POS".$_SESSION["takeposterminal"]."-".$place.")'"; - $resql = $db->query($sql); - $obj = $db->fetch_object($resql); - if ($obj) - { - $invoiceid = $obj->rowid; - } - if (!$invoiceid) - { - $invoiceid = 0; // Invoice does not exist yet - } - else - { - $invoice->fetch($invoiceid); - } -} - $langs->loadLangs(array("main", "bills", "cashdesk")); +$invoice = new Facture($db); +$invoice->fetch($facid); +$customer = new Societe($db); +$customer->fetch($invoice->socid); + +if ($action=="send") +{ + include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php'; + include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; + $formmail = new FormMail($db); + $outputlangs = new Translate('', $conf); + $model_id = $conf->global->TAKEPOS_EMAIL_TEMPLATE_INVOICE; + $arraydefaultmessage = $formmail->getEMailTemplate($db, 'facture_send', $user, $outputlangs, $model_id); + $subject = $arraydefaultmessage->topic; + ob_start(); // turn on output receipt + include('receipt.php'); + $receipt = ob_get_contents(); // get the contents of the output buffer + ob_end_clean(); + $msg="".$arraydefaultmessage->content."
".$receipt.""; + $sendto=$email; + $from=$mysoc->email; + $mail = new CMailFile($subject, $sendto, $from, $msg, array(), array(), array(), '', '', 0, 1); + if ($mail->error || $mail->errors) { + setEventMessages($mail->error, $mail->errors, 'errors'); + } else { + $result = $mail->sendfile(); + } + exit; +} +$arrayofcss = array('/takepos/css/pos.css.php'); +$arrayofjs = array(); +top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss); ?> -
-
+
+

- +
From 281a97404a84c740fa4b7906ecc3126ca055f22d Mon Sep 17 00:00:00 2001 From: andreubisquerra Date: Thu, 30 Apr 2020 01:27:55 +0200 Subject: [PATCH 032/120] Fix travis --- htdocs/takepos/send.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/takepos/send.php b/htdocs/takepos/send.php index 720cd4e271c..3f59d4069b5 100644 --- a/htdocs/takepos/send.php +++ b/htdocs/takepos/send.php @@ -61,9 +61,9 @@ if ($action=="send") $arraydefaultmessage = $formmail->getEMailTemplate($db, 'facture_send', $user, $outputlangs, $model_id); $subject = $arraydefaultmessage->topic; ob_start(); // turn on output receipt - include('receipt.php'); + include 'receipt.php'; $receipt = ob_get_contents(); // get the contents of the output buffer - ob_end_clean(); + ob_end_clean(); $msg="".$arraydefaultmessage->content."
".$receipt.""; $sendto=$email; $from=$mysoc->email; From 82ace4b4ef6f8fd63ec4f6d73df641fb7362c129 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 3 Sep 2019 22:39:24 +0200 Subject: [PATCH 033/120] FIX Several pb in export of documents FIX Must escape shell FIX Must exclude logs and some dirs for compressed backup FIX gzip and bzip2 must use option -f --- htdocs/admin/tools/dolibarr_export.php | 74 ++-- htdocs/admin/tools/export_files.php | 49 +- htdocs/core/class/utils.class.php | 178 +++++--- htdocs/core/lib/files.lib.php | 591 +++++++++++++++---------- 4 files changed, 520 insertions(+), 372 deletions(-) diff --git a/htdocs/admin/tools/dolibarr_export.php b/htdocs/admin/tools/dolibarr_export.php index d04840e2d71..0bef19dde56 100644 --- a/htdocs/admin/tools/dolibarr_export.php +++ b/htdocs/admin/tools/dolibarr_export.php @@ -29,15 +29,15 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; $langs->load("admin"); -$action=GETPOST('action','alpha'); +$action=GETPOST('action', 'alpha'); -$sortfield = GETPOST('sortfield','alpha'); -$sortorder = GETPOST('sortorder','alpha'); -$page = GETPOST('page','int'); +$sortfield = GETPOST('sortfield', 'alpha'); +$sortorder = GETPOST('sortorder', 'alpha'); +$page = GETPOST('page', 'int'); if (! $sortorder) $sortorder="DESC"; if (! $sortfield) $sortfield="date"; if (empty($page) || $page == -1) { $page = 0; } -$limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit; +$limit = GETPOST('limit', 'int')?GETPOST('limit', 'int'):$conf->liste_limit; $offset = $limit * $page; if (! $user->admin) @@ -50,10 +50,20 @@ if (! $user->admin) if ($action == 'delete') { - $file=$conf->admin->dir_output.'/backup/'.basename(GETPOST('urlfile', 'alpha')); - $ret=dol_delete_file($file, 1); - if ($ret) setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs'); - else setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors'); + if (preg_match('/^backup\//', GETPOST('urlfile', 'alpha'))) + { + $file=$conf->admin->dir_output.'/backup/'.basename(GETPOST('urlfile', 'alpha')); + $ret=dol_delete_file($file, 1); + if ($ret) setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs'); + else setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors'); + } + else + { + $file=$conf->admin->dir_output.'/documents/'.basename(GETPOST('urlfile', 'alpha')); + $ret=dol_delete_file($file, 1); + if ($ret) setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs'); + else setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors'); + } $action=''; } @@ -70,7 +80,7 @@ $type=$db->type; //var_dump($db); $help_url='EN:Backups|FR:Sauvegardes|ES:Copias_de_seguridad'; -llxHeader('','',$help_url); +llxHeader('', '', $help_url); ?> trans("Backup"),'','title_setup'); +print load_fiche_titre($langs->trans("Backup"), '', 'title_setup'); //print_barre_liste($langs->trans("Backup"), '', '', '', '', '', $langs->trans("BackupDesc",DOL_DATA_ROOT), 0, 0, 'title_setup'); -print '
'; -print $langs->trans("BackupDesc",DOL_DATA_ROOT); +print '
'; +print $langs->trans("BackupDesc", DOL_DATA_ROOT); print '
'; print '
'; @@ -128,7 +138,7 @@ print '
';
1 trans("BackupDesc3",$dolibarr_main_db_name).'
'; +print $langs->trans("BackupDesc3", $dolibarr_main_db_name).'
'; //print $langs->trans("BackupDescY").'
'; print '
'; ?> @@ -166,7 +176,7 @@ print '
'; if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) { @@ -322,6 +331,7 @@ if ($result) { print "
' . $thirdpartystatic->getNomUrl(1, 'customer') . ''.$objp->rowid.'
'; if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) { @@ -391,6 +399,7 @@ if ($result) { print '
' . $thirdpartystatic->getNomUrl(1, 'customer') . ''.$objp->rowid.'
'; diff --git a/htdocs/accountancy/supplier/list.php b/htdocs/accountancy/supplier/list.php index 4996faa9260..f9bac6682a8 100644 --- a/htdocs/accountancy/supplier/list.php +++ b/htdocs/accountancy/supplier/list.php @@ -372,7 +372,7 @@ if ($result) { // We add search filter print '
'; From 91523b4b6425b201f2c8c4e1580b49d9364e8334 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 28 Apr 2020 14:22:13 +0200 Subject: [PATCH 018/120] FIX Can switch from double to price type for extrafields Conflicts: htdocs/core/tpl/admin_extrafields_edit.tpl.php --- htdocs/core/tpl/admin_extrafields_edit.tpl.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/htdocs/core/tpl/admin_extrafields_edit.tpl.php b/htdocs/core/tpl/admin_extrafields_edit.tpl.php index 4063111a6fb..b9035f546dd 100644 --- a/htdocs/core/tpl/admin_extrafields_edit.tpl.php +++ b/htdocs/core/tpl/admin_extrafields_edit.tpl.php @@ -193,14 +193,17 @@ elseif (($type== 'sellist') || ($type == 'chkbxlst') || ($type == 'link') || ($t // Define list of possible type transition $typewecanchangeinto=array( 'varchar'=>array('varchar', 'phone', 'mail', 'url', 'select', 'password', 'text', 'html'), - 'text'=>array('text','html'), - 'html'=>array('text','html'), + 'double'=>array('double', 'price'), + 'price'=>array('double', 'price'), + 'text'=>array('text', 'html'), + 'html'=>array('text', 'html'), 'password'=>array('password', 'varchar'), 'mail'=>array('varchar', 'phone', 'mail', 'url', 'select'), 'url'=>array('varchar', 'phone', 'mail', 'url', 'select'), 'phone'=>array('varchar', 'phone', 'mail', 'url', 'select'), 'select'=>array('varchar', 'phone', 'mail', 'url', 'select') ); + if (in_array($type, array_keys($typewecanchangeinto))) { $newarray=array(); From a8740352af918429cdd766aaf8ca106a0daeec72 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 28 Apr 2020 14:22:52 +0200 Subject: [PATCH 019/120] FIX Extrafields of type price must be '' and not '0' if not defined --- htdocs/core/class/extrafields.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index 0938da39dcd..ac388b1ef83 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -1681,7 +1681,8 @@ class ExtraFields } elseif ($type == 'price') { - $value = price($value, 0, $langs, 0, 0, -1, $conf->currency); + //$value = price($value, 0, $langs, 0, 0, -1, $conf->currency); + if ($value || $value == '0') $value = price($value, 0, $langs, 0, 0, -1); } elseif ($type == 'select') { From c22e13b138d28bbb902881c6cdd061ca555b8b60 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 28 Apr 2020 14:25:07 +0200 Subject: [PATCH 020/120] FIX Avoid infinite loop when a fetch is inside a compute field. --- htdocs/core/class/commonobject.class.php | 26 ++++++++++++++++++++++-- htdocs/core/class/conf.class.php | 2 ++ htdocs/langs/en_US/admin.lang | 2 +- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index f7202040fe5..10e04896314 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -5012,6 +5012,25 @@ abstract class CommonObject /* Functions for extrafields */ + /** + * Function to make a fetch but set environment to avoid to load computed values before. + * + * @param int $id ID of object + * @return int >0 if OK, 0 if not found, <0 if KO + */ + public function fetchNoCompute($id) + { + global $conf; + + $savDisableCompute = $conf->disable_compute; + $conf->disable_compute = 1; + + $ret = $this->fetch($id); + + $conf->disable_compute = $savDisableCompute; + + return $ret; + } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** @@ -5025,7 +5044,7 @@ abstract class CommonObject public function fetch_optionals($rowid = null, $optionsArray = null) { // phpcs:enable - global $extrafields; + global $conf, $extrafields; if (empty($rowid)) $rowid = $this->id; @@ -5109,7 +5128,10 @@ abstract class CommonObject foreach ($tab as $key => $value) { if (!empty($extrafields) && !empty($extrafields->attributes[$this->table_element]['computed'][$key])) { - $this->array_options["options_".$key] = dol_eval($extrafields->attributes[$this->table_element]['computed'][$key], 1, 0); + //var_dump($conf->disable_compute); + if (empty($conf->disable_compute)) { + $this->array_options["options_".$key] = dol_eval($extrafields->attributes[$this->table_element]['computed'][$key], 1, 0); + } } } } diff --git a/htdocs/core/class/conf.class.php b/htdocs/core/class/conf.class.php index 4136cef1be5..00556f40480 100644 --- a/htdocs/core/class/conf.class.php +++ b/htdocs/core/class/conf.class.php @@ -48,6 +48,8 @@ class Conf //! To store if javascript/ajax is enabked public $use_javascript_ajax; + //! To store if javascript/ajax is enabked + public $disable_compute; //! Used to store current currency (ISO code like 'USD', 'EUR', ...) public $currency; //! Used to store current css (from theme) diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index e2c03545124..00e6279349b 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -427,7 +427,7 @@ ExtrafieldCheckBox=Checkboxes ExtrafieldCheckBoxFromList=Checkboxes from table ExtrafieldLink=Link to an object ComputedFormula=Computed field -ComputedFormulaDesc=You can enter here a formula using other properties of object or any PHP coding to get a dynamic computed value. You can use any PHP compatible formulas including the "?" condition operator, and following global object: $db, $conf, $langs, $mysoc, $user, $object.
WARNING: Only some properties of $object may be available. If you need a properties not loaded, just fetch yourself the object into your formula like in the second example.
Using a computed field means you can't enter yourself any value from interface. Also, if there is a syntax error, the formula may return nothing.

Example of formula:
$object->id < 10 ? round($object->id / 2, 2): ($object->id + 2 * $user->id) * (int) substr($mysoc->zip, 1, 2)

Example to reload object
(($reloadedobj = new Societe($db)) && ($reloadedobj->fetch($obj->id ? $obj->id: ($obj->rowid ? $obj->rowid: $object->id)) > 0)) ? $reloadedobj->array_options['options_extrafieldkey'] * $reloadedobj->capital / 5: '-1'

Other example of formula to force load of object and its parent object:
(($reloadedobj = new Task($db)) && ($reloadedobj->fetch($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetch($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref: 'Parent project not found' +ComputedFormulaDesc=You can enter here a formula using other properties of object or any PHP coding to get a dynamic computed value. You can use any PHP compatible formulas including the "?" condition operator, and following global object: $db, $conf, $langs, $mysoc, $user, $object.
WARNING: Only some properties of $object may be available. If you need a properties not loaded, just fetch yourself the object into your formula like in the second example.
Using a computed field means you can't enter yourself any value from interface. Also, if there is a syntax error, the formula may return nothing.

Example of formula:
$object->id < 10 ? round($object->id / 2, 2): ($object->id + 2 * $user->id) * (int) substr($mysoc->zip, 1, 2)

Example to reload object
(($reloadedobj = new Societe($db)) && ($reloadedobj->fetchNoCompute($obj->id ? $obj->id: ($obj->rowid ? $obj->rowid: $object->id)) > 0)) ? $reloadedobj->array_options['options_extrafieldkey'] * $reloadedobj->capital / 5: '-1'

Other example of formula to force load of object and its parent object:
(($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref: 'Parent project not found' Computedpersistent=Store computed field ComputedpersistentDesc=Computed extra fields will be stored in the database, however, the value will only be recalculated when the object of this field is changed. If the computed field depends on other objects or global data this value might be wrong!! ExtrafieldParamHelpPassword=Leaving this field blank means this value will be stored without encryption (field must be only hidden with star on screen).
Set 'auto' to use the default encryption rule to save password into database (then value read will be the hash only, no way to retrieve original value) From a0c013d87bfc61db04b84ae33990d6b14112724e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 27 Apr 2020 17:13:23 +0200 Subject: [PATCH 021/120] Fix missing link Conflicts: htdocs/core/class/notify.class.php --- htdocs/core/class/notify.class.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/htdocs/core/class/notify.class.php b/htdocs/core/class/notify.class.php index 59d523b6b44..99910e82ecc 100644 --- a/htdocs/core/class/notify.class.php +++ b/htdocs/core/class/notify.class.php @@ -314,6 +314,7 @@ class Notify global $user,$conf,$langs,$mysoc; global $hookmanager; global $dolibarr_main_url_root; + global $action; if (! in_array($notifcode, $this->arrayofnotifsupported)) return 0; @@ -524,8 +525,10 @@ class Notify $message.= $mesg; if ($link) $message.= "\n" . $urlwithroot . $link; - $parameters=array('notifcode'=>$notifcode, 'sendto'=>$sendto, 'replyto'=>$replyto, 'file'=>$filename_list, 'mimefile'=>$mimetype_list, 'filename'=>$mimefilename_list); - $reshook=$hookmanager->executeHooks('formatNotificationMessage', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks + $parameters = array('notifcode'=>$notifcode, 'sendto'=>$sendto, 'replyto'=>$replyto, 'file'=>$filename_list, 'mimefile'=>$mimetype_list, 'filename'=>$mimefilename_list); + if (!isset($action)) $action = ''; + + $reshook = $hookmanager->executeHooks('formatNotificationMessage', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks if (empty($reshook)) { if (! empty($hookmanager->resArray['subject'])) $subject.=$hookmanager->resArray['subject']; @@ -694,21 +697,25 @@ class Notify $mesg = $langs->transnoentitiesnoconv("EMailTextExpeditionValidated", $newref); break; case 'EXPENSE_REPORT_VALIDATE': + $link = ''.$newref.''; $dir_output = $conf->expensereport->dir_output; $object_type = 'expensereport'; $mesg = $langs->transnoentitiesnoconv("EMailTextExpenseReportValidated", $newref); break; case 'EXPENSE_REPORT_APPROVE': + $link = ''.$newref.''; $dir_output = $conf->expensereport->dir_output; $object_type = 'expensereport'; $mesg = $langs->transnoentitiesnoconv("EMailTextExpenseReportApproved", $newref); break; case 'HOLIDAY_VALIDATE': + $link = ''.$newref.''; $dir_output = $conf->holiday->dir_output; $object_type = 'holiday'; $mesg = $langs->transnoentitiesnoconv("EMailTextHolidayValidated", $newref); break; case 'HOLIDAY_APPROVE': + $link = ''.$newref.''; $dir_output = $conf->holiday->dir_output; $object_type = 'holiday'; $mesg = $langs->transnoentitiesnoconv("EMailTextHolidayApproved", $newref); From 40f1bed8d0dfaaabb4712f445f1fc9561d84111d Mon Sep 17 00:00:00 2001 From: "DEMAREST Maxime (Indelog)" Date: Wed, 29 Apr 2020 09:15:27 +0200 Subject: [PATCH 022/120] Add possibility to filter stats by ThirdParty type and categorie --- .../comm/propal/class/propalestats.class.php | 24 +++++++++++++- htdocs/comm/propal/stats/index.php | 33 ++++++++++++++++--- htdocs/commande/class/commandestats.class.php | 24 +++++++++++++- htdocs/commande/stats/index.php | 30 ++++++++++++++++- .../facture/class/facturestats.class.php | 26 ++++++++++++++- htdocs/compta/facture/stats/index.php | 32 ++++++++++++++++-- 6 files changed, 159 insertions(+), 10 deletions(-) diff --git a/htdocs/comm/propal/class/propalestats.class.php b/htdocs/comm/propal/class/propalestats.class.php index d5c48006430..655ccda2a80 100644 --- a/htdocs/comm/propal/class/propalestats.class.php +++ b/htdocs/comm/propal/class/propalestats.class.php @@ -3,6 +3,7 @@ * Copyright (c) 2005-2013 Laurent Destailleur * Copyright (C) 2005-2009 Regis Houssin * Copyright (c) 2011 Juanjo Menent + * Copyright (C) 2020 Maxime DEMAREST * * 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 @@ -46,6 +47,7 @@ class PropaleStats extends Stats public $from; public $field; public $where; + public $join; /** @@ -56,13 +58,14 @@ class PropaleStats extends Stats * @param int $userid Id user for filter (creation user) * @param string $mode Option ('customer', 'supplier') */ - public function __construct($db, $socid = 0, $userid = 0, $mode = 'customer') + public function __construct($db, $socid = 0, $userid = 0, $mode = 'customer', $typentid = 0, $categid = 0) { global $user, $conf; $this->db = $db; $this->socid = ($socid > 0 ? $socid : 0); $this->userid = $userid; + $this->join = ''; if ($mode == 'customer') { @@ -96,6 +99,19 @@ class PropaleStats extends Stats $this->where .= " AND p.fk_soc = ".$this->socid; } if ($this->userid > 0) $this->where .= ' AND fk_user_author = '.$this->userid; + + if ($typentid) + { + $this->join .= ' LEFT JOIN '.MAIN_DB_PREFIX.'societe as s ON s.rowid = p.fk_soc'; + $this->where .= ' AND s.fk_typent = '.$typentid; + } + + if ($categid) + { + $this->join .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie_societe as cs ON cs.fk_soc = p.fk_soc'; + $this->join .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie as c ON c.rowid = cs.fk_categorie'; + $this->where .= ' AND c.rowid = '.$categid; + } } @@ -113,6 +129,7 @@ class PropaleStats extends Stats $sql = "SELECT date_format(".$this->field_date.",'%m') as dm, COUNT(*) as nb"; $sql .= " FROM ".$this->from; if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= $this->join; $sql .= " WHERE ".$this->field_date." BETWEEN '".$this->db->idate(dol_get_first_day($year))."' AND '".$this->db->idate(dol_get_last_day($year))."'"; $sql .= " AND ".$this->where; $sql .= " GROUP BY dm"; @@ -135,6 +152,7 @@ class PropaleStats extends Stats $sql = "SELECT date_format(".$this->field_date.",'%Y') as dm, COUNT(*) as nb, SUM(c.".$this->field.")"; $sql .= " FROM ".$this->from; if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= $this->join; $sql .= " WHERE ".$this->where; $sql .= " GROUP BY dm"; $sql .= $this->db->order('dm', 'DESC'); @@ -156,6 +174,7 @@ class PropaleStats extends Stats $sql = "SELECT date_format(".$this->field_date.",'%m') as dm, SUM(p.".$this->field.")"; $sql .= " FROM ".$this->from; if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= $this->join; $sql .= " WHERE ".$this->field_date." BETWEEN '".$this->db->idate(dol_get_first_day($year))."' AND '".$this->db->idate(dol_get_last_day($year))."'"; $sql .= " AND ".$this->where; $sql .= " GROUP BY dm"; @@ -178,6 +197,7 @@ class PropaleStats extends Stats $sql = "SELECT date_format(".$this->field_date.",'%m') as dm, AVG(p.".$this->field.")"; $sql .= " FROM ".$this->from; if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= $this->join; $sql .= " WHERE ".$this->field_date." BETWEEN '".$this->db->idate(dol_get_first_day($year))."' AND '".$this->db->idate(dol_get_last_day($year))."'"; $sql .= " AND ".$this->where; $sql .= " GROUP BY dm"; @@ -198,6 +218,7 @@ class PropaleStats extends Stats $sql = "SELECT date_format(".$this->field_date.",'%Y') as year, COUNT(*) as nb, SUM(".$this->field.") as total, AVG(".$this->field.") as avg"; $sql .= " FROM ".$this->from; if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= $this->join; $sql .= " WHERE ".$this->where; $sql .= " GROUP BY year"; $sql .= $this->db->order('year', 'DESC'); @@ -221,6 +242,7 @@ class PropaleStats extends Stats $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 (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $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))."'"; diff --git a/htdocs/comm/propal/stats/index.php b/htdocs/comm/propal/stats/index.php index 3fee370c89b..78fbf725929 100644 --- a/htdocs/comm/propal/stats/index.php +++ b/htdocs/comm/propal/stats/index.php @@ -4,6 +4,7 @@ * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2012 Marcos García * Copyright (C) 2015 Jean-François Ferry + * Copyright (C) 2020 Maxime DEMAREST * * 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 @@ -28,7 +29,10 @@ require '../../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propalestats.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/dolgraph.class.php'; +require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formpropal.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; $WIDTH = DolGraph::getDefaultGraphSizeForStats('width'); $HEIGHT = DolGraph::getDefaultGraphSizeForStats('height'); @@ -38,6 +42,8 @@ if ($mode == 'customer' && !$user->rights->propale->lire) accessforbidden(); if ($mode == 'supplier' && !$user->rights->supplier_proposal->lire) accessforbidden(); $object_status = GETPOST('object_status'); +$typent_id = GETPOST('typent_id', 'int'); +$categ_id = GETPOST('categ_id', 'categ_id'); $userid = GETPOST('userid', 'int'); $socid = GETPOST('socid', 'int'); @@ -64,17 +70,26 @@ $langs->loadLangs(array('orders', 'companies', 'other', 'suppliers', 'supplier_p $form = new Form($db); $formpropal = new FormPropal($db); +$formcompany = new FormCompany($db); +$formother = new FormOther($db); $langs->loadLangs(array('propal', 'other', 'companies')); -$picto = 'propal'; -$title = $langs->trans("ProposalsStatistics"); -$dir = $conf->propale->dir_temp; +if ($mode == 'customer') +{ + $picto = 'propal'; + $title = $langs->trans("ProposalsStatistics"); + $dir = $conf->propale->dir_temp; + $cat_type = Categorie::TYPE_CUSTOMER; + $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Customer")); +} if ($mode == 'supplier') { $picto = 'supplier_proposal'; $title = $langs->trans("ProposalsStatisticsSuppliers").' ('.$langs->trans("SentToSuppliers").")"; $dir = $conf->supplier_proposal->dir_temp; + $cat_type = Categorie::TYPE_SUPPLIER; + $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Customer")); } llxHeader('', $title); @@ -85,7 +100,7 @@ print load_fiche_titre($title, '', $picto); dol_mkdir($dir); -$stats = new PropaleStats($db, $socid, ($userid > 0 ? $userid : 0), $mode); +$stats = new PropaleStats($db, $socid, ($userid > 0 ? $userid : 0), $mode, ($typent_id > 0 ? $typent_id : 0), ($categ_id > 0 ? $categ_id : 0)); if ($object_status != '' && $object_status >= 0) $stats->where .= ' AND p.fk_statut IN ('.$db->escape($object_status).')'; // Build graphic number of object @@ -251,6 +266,16 @@ print '
'; $filter = 's.client IN (1,2,3)'; print $form->select_company($socid, 'socid', $filter, 1, 0, 0, array(), 0, '', 'style="width: 95%"'); print '
'.$langs->trans("ThirdPartyType").''; + $sortparam_typent = (empty($conf->global->SOCIETE_SORT_ON_TYPEENT) ? 'ASC' : $conf->global->SOCIETE_SORT_ON_TYPEENT); // NONE means we keep sort of original array, so we sort on position. ASC, means next function will sort on label. + print $form->selectarray("typent_id", $formcompany->typent_array(0), $typent_id, 0, 0, 0, '', 0, 0, 0, $sortparam_typent); + if ($user->admin) print ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); + print '
'.$cat_label.''; + print $formother->select_categories($cat_type, $categ_id, 'categ_id', true); + print '
'.$langs->trans("CreatedBy").''; print $form->select_dolusers($userid, 'userid', 1, '', 0, '', '', 0, 0, 0, '', 0, '', 'maxwidth300'); diff --git a/htdocs/commande/class/commandestats.class.php b/htdocs/commande/class/commandestats.class.php index 8b6dc4db6ec..e040a1b1ce1 100644 --- a/htdocs/commande/class/commandestats.class.php +++ b/htdocs/commande/class/commandestats.class.php @@ -3,6 +3,7 @@ * Copyright (c) 2005-2013 Laurent Destailleur * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2012 Marcos García + * Copyright (C) 2020 Maxime DEMAREST * * 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 @@ -45,6 +46,7 @@ class CommandeStats extends Stats public $from; public $field; public $where; + public $join; /** @@ -55,7 +57,7 @@ class CommandeStats extends Stats * @param string $mode Option ('customer', 'supplier') * @param int $userid Id user for filter (creation user) */ - public function __construct($db, $socid, $mode, $userid = 0) + public function __construct($db, $socid, $mode, $userid = 0, $typentid = 0, $categid = 0) { global $user, $conf; @@ -64,6 +66,7 @@ class CommandeStats extends Stats $this->socid = ($socid > 0 ? $socid : 0); $this->userid = $userid; $this->cachefilesuffix = $mode; + $this->join = ''; if ($mode == 'customer') { @@ -92,6 +95,19 @@ class CommandeStats extends Stats $this->where .= " AND c.fk_soc = ".$this->socid; } if ($this->userid > 0) $this->where .= ' AND c.fk_user_author = '.$this->userid; + + if ($typentid) + { + $this->join .= ' LEFT JOIN '.MAIN_DB_PREFIX.'societe as s ON s.rowid = c.fk_soc'; + $this->where .= ' AND s.fk_typent = '.$typentid; + } + + if ($categid) + { + $this->join .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie_societe as cats ON cats.fk_soc = c.fk_soc'; + $this->join .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie as cat ON cat.rowid = cats.fk_categorie'; + $this->where .= ' AND cat.rowid = '.$categid; + } } /** @@ -108,6 +124,7 @@ class CommandeStats extends Stats $sql = "SELECT date_format(c.date_commande,'%m') as dm, COUNT(*) as nb"; $sql .= " FROM ".$this->from; if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= $this->join; $sql .= " WHERE c.date_commande BETWEEN '".$this->db->idate(dol_get_first_day($year))."' AND '".$this->db->idate(dol_get_last_day($year))."'"; $sql .= " AND ".$this->where; $sql .= " GROUP BY dm"; @@ -130,6 +147,7 @@ class CommandeStats extends Stats $sql = "SELECT date_format(c.date_commande,'%Y') as dm, COUNT(*) as nb, SUM(c.".$this->field.")"; $sql .= " FROM ".$this->from; if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= $this->join; $sql .= " WHERE ".$this->where; $sql .= " GROUP BY dm"; $sql .= $this->db->order('dm', 'DESC'); @@ -151,6 +169,7 @@ class CommandeStats extends Stats $sql = "SELECT date_format(c.date_commande,'%m') as dm, SUM(c.".$this->field.")"; $sql .= " FROM ".$this->from; if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= $this->join; $sql .= " WHERE c.date_commande BETWEEN '".$this->db->idate(dol_get_first_day($year))."' AND '".$this->db->idate(dol_get_last_day($year))."'"; $sql .= " AND ".$this->where; $sql .= " GROUP BY dm"; @@ -173,6 +192,7 @@ class CommandeStats extends Stats $sql = "SELECT date_format(c.date_commande,'%m') as dm, AVG(c.".$this->field.")"; $sql .= " FROM ".$this->from; if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= $this->join; $sql .= " WHERE c.date_commande BETWEEN '".$this->db->idate(dol_get_first_day($year))."' AND '".$this->db->idate(dol_get_last_day($year))."'"; $sql .= " AND ".$this->where; $sql .= " GROUP BY dm"; @@ -193,6 +213,7 @@ class CommandeStats extends Stats $sql = "SELECT date_format(c.date_commande,'%Y') as year, COUNT(*) as nb, SUM(c.".$this->field.") as total, AVG(".$this->field.") as avg"; $sql .= " FROM ".$this->from; if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= $this->join; $sql .= " WHERE ".$this->where; $sql .= " GROUP BY year"; $sql .= $this->db->order('year', 'DESC'); @@ -214,6 +235,7 @@ class CommandeStats extends Stats $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 (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= $this->join; $sql .= " WHERE ".$this->where; $sql .= " AND c.rowid = tl.fk_commande AND tl.fk_product = product.rowid"; $sql .= " AND c.date_commande BETWEEN '".$this->db->idate(dol_get_first_day($year, 1, false))."' AND '".$this->db->idate(dol_get_last_day($year, 12, false))."'"; diff --git a/htdocs/commande/stats/index.php b/htdocs/commande/stats/index.php index 16cef93d228..d009621dc82 100644 --- a/htdocs/commande/stats/index.php +++ b/htdocs/commande/stats/index.php @@ -4,6 +4,7 @@ * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2012 Marcos García * Copyright (C) 2015 Jean-François Ferry + * Copyright (C) 2020 Maxime DEMAREST * * 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 @@ -28,7 +29,10 @@ require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; require_once DOL_DOCUMENT_ROOT.'/commande/class/commandestats.class.php'; +require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formorder.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/dolgraph.class.php'; $WIDTH = DolGraph::getDefaultGraphSizeForStats('width'); @@ -39,6 +43,8 @@ if ($mode == 'customer' && !$user->rights->commande->lire) accessforbidden(); if ($mode == 'supplier' && !$user->rights->fournisseur->commande->lire) accessforbidden(); $object_status = GETPOST('object_status'); +$typent_id = GETPOST('typent_id', 'int'); +$categ_id = GETPOST('categ_id', 'categ_id'); $userid = GETPOST('userid', 'int'); $socid = GETPOST('socid', 'int'); @@ -65,6 +71,8 @@ $langs->loadLangs(array('orders', 'companies', 'other', 'suppliers')); $form = new Form($db); $formorder = new FormOrder($db); +$formcompany = new FormCompany($db); +$formother = new FormOther($db); $picto = 'order'; $title = $langs->trans("OrdersStatistics"); @@ -83,7 +91,7 @@ print load_fiche_titre($title, '', $picto); dol_mkdir($dir); -$stats = new CommandeStats($db, $socid, $mode, ($userid > 0 ? $userid : 0)); +$stats = new CommandeStats($db, $socid, $mode, ($userid > 0 ? $userid : 0), ($typent_id > 0 ? $typent_id : 0), ($categ_id > 0 ? $categ_id : 0)); if ($mode == 'customer') { if ($object_status != '' && $object_status >= -1) $stats->where .= ' AND c.fk_statut IN ('.$db->escape($object_status).')'; @@ -266,6 +274,26 @@ if ($mode == 'customer') $filter = 's.client IN (1,2,3)'; if ($mode == 'supplier') $filter = 's.fournisseur = 1'; print $form->select_company($socid, 'socid', $filter, 1, 0, 0, array(), 0, '', 'style="width: 95%"'); print '
'.$langs->trans("ThirdPartyType").''; +$sortparam_typent = (empty($conf->global->SOCIETE_SORT_ON_TYPEENT) ? 'ASC' : $conf->global->SOCIETE_SORT_ON_TYPEENT); // NONE means we keep sort of original array, so we sort on position. ASC, means next function will sort on label. +print $form->selectarray("typent_id", $formcompany->typent_array(0), $typent_id, 0, 0, 0, '', 0, 0, 0, $sortparam_typent); +if ($user->admin) print ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); +print '
'.$cat_label.''; +print $formother->select_categories($cat_type, $categ_id, 'categ_id', true); +print '
'.$langs->trans("CreatedBy").''; print $form->select_dolusers($userid, 'userid', 1, '', 0, '', '', 0, 0, 0, '', 0, '', 'maxwidth300'); diff --git a/htdocs/compta/facture/class/facturestats.class.php b/htdocs/compta/facture/class/facturestats.class.php index ea0b17bc59a..d280b7745e2 100644 --- a/htdocs/compta/facture/class/facturestats.class.php +++ b/htdocs/compta/facture/class/facturestats.class.php @@ -2,6 +2,7 @@ /* Copyright (C) 2003 Rodolphe Quiedeville * Copyright (c) 2005-2013 Laurent Destailleur * Copyright (C) 2005-2009 Regis Houssin + * Copyright (C) 2020 Maxime DEMAREST * * 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 @@ -43,6 +44,7 @@ class FactureStats extends Stats public $from; public $field; public $where; + public $join; /** @@ -52,8 +54,9 @@ class FactureStats extends Stats * @param int $socid Id third party for filter. This value must be forced during the new to external user company if user is an external user. * @param string $mode Option ('customer', 'supplier') * @param int $userid Id user for filter (creation user) + * @param int $ Id user for filter (creation user) */ - public function __construct($db, $socid, $mode, $userid = 0) + public function __construct($db, $socid, $mode, $userid = 0, $typentid = 0, $categid = 0) { global $user, $conf; @@ -61,6 +64,7 @@ class FactureStats extends Stats $this->socid = ($socid > 0 ? $socid : 0); $this->userid = $userid; $this->cachefilesuffix = $mode; + $this->join = ''; if ($mode == 'customer') { @@ -79,6 +83,7 @@ class FactureStats extends Stats $this->field_line = 'total_ht'; } + $this->where = " f.fk_statut >= 0"; $this->where .= " AND f.entity IN (".getEntity('invoice').")"; if (!$user->rights->societe->client->voir && !$this->socid) $this->where .= " AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".$user->id; @@ -90,6 +95,19 @@ class FactureStats extends Stats if ($this->userid > 0) $this->where .= ' AND f.fk_user_author = '.$this->userid; if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $this->where .= " AND f.type IN (0,1,2,5)"; else $this->where .= " AND f.type IN (0,1,2,3,5)"; + + if ($typentid) + { + $this->join .= ' LEFT JOIN '.MAIN_DB_PREFIX.'societe as s ON s.rowid = f.fk_soc'; + $this->where .= ' AND s.fk_typent = '.$typentid; + } + + if ($categid) + { + $this->join .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie_societe as cs ON cs.fk_soc = f.fk_soc'; + $this->join .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie as c ON c.rowid = cs.fk_categorie'; + $this->where .= ' AND c.rowid = '.$categid; + } } @@ -107,6 +125,7 @@ class FactureStats extends Stats $sql = "SELECT date_format(f.datef,'%m') as dm, COUNT(*) as nb"; $sql .= " FROM ".$this->from; if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= $this->join; $sql .= " WHERE f.datef BETWEEN '".$this->db->idate(dol_get_first_day($year))."' AND '".$this->db->idate(dol_get_last_day($year))."'"; $sql .= " AND ".$this->where; $sql .= " GROUP BY dm"; @@ -130,6 +149,7 @@ class FactureStats extends Stats $sql = "SELECT date_format(f.datef,'%Y') as dm, COUNT(*), SUM(c.".$this->field.")"; $sql .= " FROM ".$this->from; if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= $this->join; $sql .= " WHERE ".$this->where; $sql .= " GROUP BY dm"; $sql .= $this->db->order('dm', 'DESC'); @@ -152,6 +172,7 @@ class FactureStats extends Stats $sql = "SELECT date_format(datef,'%m') as dm, SUM(f.".$this->field.")"; $sql .= " FROM ".$this->from; if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= $this->join; $sql .= " WHERE f.datef BETWEEN '".$this->db->idate(dol_get_first_day($year))."' AND '".$this->db->idate(dol_get_last_day($year))."'"; $sql .= " AND ".$this->where; $sql .= " GROUP BY dm"; @@ -175,6 +196,7 @@ class FactureStats extends Stats $sql = "SELECT date_format(datef,'%m') as dm, AVG(f.".$this->field.")"; $sql .= " FROM ".$this->from; if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= $this->join; $sql .= " WHERE f.datef BETWEEN '".$this->db->idate(dol_get_first_day($year))."' AND '".$this->db->idate(dol_get_last_day($year))."'"; $sql .= " AND ".$this->where; $sql .= " GROUP BY dm"; @@ -195,6 +217,7 @@ class FactureStats extends Stats $sql = "SELECT date_format(datef,'%Y') as year, COUNT(*) as nb, SUM(f.".$this->field.") as total, AVG(f.".$this->field.") as avg"; $sql .= " FROM ".$this->from; if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= $this->join; $sql .= " WHERE ".$this->where; $sql .= " GROUP BY year"; $sql .= $this->db->order('year', 'DESC'); @@ -216,6 +239,7 @@ class FactureStats extends Stats $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 (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= $this->join; $sql .= " WHERE ".$this->where; $sql .= " AND f.rowid = tl.fk_facture AND tl.fk_product = product.rowid"; $sql .= " AND f.datef BETWEEN '".$this->db->idate(dol_get_first_day($year, 1, false))."' AND '".$this->db->idate(dol_get_last_day($year, 12, false))."'"; diff --git a/htdocs/compta/facture/stats/index.php b/htdocs/compta/facture/stats/index.php index 36dfab5a3c4..b1af8064d9f 100644 --- a/htdocs/compta/facture/stats/index.php +++ b/htdocs/compta/facture/stats/index.php @@ -4,6 +4,7 @@ * Copyright (C) 2012 Marcos García * Copyright (C) 2013 Juanjo Menent * Copyright (C) 2015 Jean-François Ferry + * Copyright (C) 2020 Maxime DEMAREST * * 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 @@ -27,6 +28,9 @@ require '../../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/dolgraph.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; +require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facturestats.class.php'; $WIDTH = DolGraph::getDefaultGraphSizeForStats('width'); @@ -40,6 +44,8 @@ if ($mode == 'customer' && !$user->rights->facture->lire) accessforbidden(); if ($mode == 'supplier' && !$user->rights->fournisseur->facture->lire) accessforbidden(); $object_status = GETPOST('object_status'); +$typent_id = GETPOST('typent_id', 'int'); +$categ_id = GETPOST('categ_id', 'categ_id'); $userid = GETPOST('userid', 'int'); $socid = GETPOST('socid', 'int'); @@ -62,6 +68,8 @@ $endyear = $year; */ $form = new Form($db); +$formcompany = new FormCompany($db); +$formother = new FormOther($db); llxHeader(); @@ -81,7 +89,7 @@ print load_fiche_titre($title, '', $picto); dol_mkdir($dir); -$stats = new FactureStats($db, $socid, $mode, ($userid > 0 ? $userid : 0)); +$stats = new FactureStats($db, $socid, $mode, ($userid > 0 ? $userid : 0), ($typent_id > 0 ? $typent_id : 0), ($categ_id > 0 ? $categ_id : 0)); if ($mode == 'customer') { if ($object_status != '' && $object_status >= 0) $stats->where .= ' AND f.fk_statut IN ('.$db->escape($object_status).')'; @@ -248,6 +256,26 @@ if ($mode == 'customer') $filter = 's.client in (1,2,3)'; if ($mode == 'supplier') $filter = 's.fournisseur = 1'; print $form->selectarray('socid', $companies, $socid, 1, 0, 0, 'style="width: 95%"', 0, 0, 0, '', '', 1); print '
'.$langs->trans("ThirdPartyType").''; +$sortparam_typent = (empty($conf->global->SOCIETE_SORT_ON_TYPEENT) ? 'ASC' : $conf->global->SOCIETE_SORT_ON_TYPEENT); // NONE means we keep sort of original array, so we sort on position. ASC, means next function will sort on label. +print $form->selectarray("typent_id", $formcompany->typent_array(0), $typent_id, 0, 0, 0, '', 0, 0, 0, $sortparam_typent); +if ($user->admin) print ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); +print '
'.$cat_label.''; +if ($mode == 'customer') +{ + $cat_type = Categorie::TYPE_CUSTOMER; + $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Customer")); +} +if ($mode == 'supplier') +{ + $cat_type = Categorie::TYPE_SUPPLIER; + $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Customer")); +} +print $formother->select_categories($cat_type, $categ_id, 'categ_id', true); +print '
'.$langs->trans("CreatedBy").''; print $form->select_dolusers($userid, 'userid', 1, '', 0, '', '', 0, 0, 0, '', 0, '', 'maxwidth300'); @@ -256,7 +284,7 @@ print '
'.$langs->trans("Status").''; if ($mode == 'customer') { - $liststatus = array('0'=>$langs->trans("BillStatusDraft"), '1'=>$langs->trans("BillStatusNotPaid"), '2'=>$langs->trans("BillStatusPaid"), '3'=>$langs->trans("BillStatusCanceled")); + $liststatus = array('0'=>$langs->trans("BillStatusDraft"), '1'=>$langs->trans("BillStatusNotPaid"), '2'=>$langs->trans("BillStatusPaid"), '1,2'=>$langs->trans("BillStatusNotPaid").' / '.$langs->trans("BillStatusPaid"), '3'=>$langs->trans("BillStatusCanceled")); print $form->selectarray('object_status', $liststatus, $object_status, 1); } if ($mode == 'supplier') From 1bd93720222243a017cd50822843849622149fd8 Mon Sep 17 00:00:00 2001 From: "DEMAREST Maxime (Indelog)" Date: Wed, 29 Apr 2020 10:00:29 +0200 Subject: [PATCH 023/120] Forgot comments to document news params for the modified methods --- htdocs/comm/propal/class/propalestats.class.php | 10 ++++++---- htdocs/commande/class/commandestats.class.php | 10 ++++++---- htdocs/compta/facture/class/facturestats.class.php | 3 ++- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/htdocs/comm/propal/class/propalestats.class.php b/htdocs/comm/propal/class/propalestats.class.php index 655ccda2a80..747bb75433c 100644 --- a/htdocs/comm/propal/class/propalestats.class.php +++ b/htdocs/comm/propal/class/propalestats.class.php @@ -53,10 +53,12 @@ class PropaleStats extends Stats /** * Constructor * - * @param DoliDB $db Database handler - * @param int $socid Id third party for filter. This value must be forced during the new to external user company if user is an external user. - * @param int $userid Id user for filter (creation user) - * @param string $mode Option ('customer', 'supplier') + * @param DoliDB $db Database handler + * @param int $socid Id third party for filter. This value must be forced during the new to external user company if user is an external user. + * @param int $userid Id user for filter (creation user) + * @param string $mode Option ('customer', 'supplier') + * @param int $typentid Id typent of thirdpary for filter + * @param int $categid Id category of thirdpary for filter */ public function __construct($db, $socid = 0, $userid = 0, $mode = 'customer', $typentid = 0, $categid = 0) { diff --git a/htdocs/commande/class/commandestats.class.php b/htdocs/commande/class/commandestats.class.php index e040a1b1ce1..cbb93b940de 100644 --- a/htdocs/commande/class/commandestats.class.php +++ b/htdocs/commande/class/commandestats.class.php @@ -52,10 +52,12 @@ class CommandeStats extends Stats /** * Constructor * - * @param DoliDB $db Database handler - * @param int $socid Id third party for filter. This value must be forced during the new to external user company if user is an external user. - * @param string $mode Option ('customer', 'supplier') - * @param int $userid Id user for filter (creation user) + * @param DoliDB $db Database handler + * @param int $socid Id third party for filter. This value must be forced during the new to external user company if user is an external user. + * @param string $mode Option ('customer', 'supplier') + * @param int $userid Id user for filter (creation user) + * @param int $typentid Id typent of thirdpary for filter + * @param int $categid Id category of thirdpary for filter */ public function __construct($db, $socid, $mode, $userid = 0, $typentid = 0, $categid = 0) { diff --git a/htdocs/compta/facture/class/facturestats.class.php b/htdocs/compta/facture/class/facturestats.class.php index d280b7745e2..6b95c939e2a 100644 --- a/htdocs/compta/facture/class/facturestats.class.php +++ b/htdocs/compta/facture/class/facturestats.class.php @@ -54,7 +54,8 @@ class FactureStats extends Stats * @param int $socid Id third party for filter. This value must be forced during the new to external user company if user is an external user. * @param string $mode Option ('customer', 'supplier') * @param int $userid Id user for filter (creation user) - * @param int $ Id user for filter (creation user) + * @param int $typentid Id typent of thirdpary for filter + * @param int $categid Id category of thirdpary for filter */ public function __construct($db, $socid, $mode, $userid = 0, $typentid = 0, $categid = 0) { From 56dee72b66a6300cd2ac2b12598bfe0334b73297 Mon Sep 17 00:00:00 2001 From: Tobias Sekan Date: Wed, 29 Apr 2020 13:30:14 +0200 Subject: [PATCH 024/120] add tooltip for unit_type and scale (admin) --- htdocs/admin/dict.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php index 3c19121d424..15cfd9ed9db 100644 --- a/htdocs/admin/dict.php +++ b/htdocs/admin/dict.php @@ -503,7 +503,7 @@ $tabhelp[33] = array('code'=>$langs->trans("EnterAnyCode")); $tabhelp[34] = array('code'=>$langs->trans("EnterAnyCode")); $tabhelp[35] = array(); $tabhelp[36] = array('range_ik'=>$langs->trans('PrevRangeToThisRange')); -$tabhelp[37] = array('code'=>$langs->trans("EnterAnyCode")); +$tabhelp[37] = array('code'=>$langs->trans("EnterAnyCode"), 'unit_type' => $langs->trans('MeasuringUnitTypeDesc'), 'scale' => $langs->trans('MeasuringScaleDesc')); $tabhelp[38] = array('code'=>$langs->trans("EnterAnyCode"), 'url' => $langs->trans('UrlSocialNetworksDesc'), 'icon' => $langs->trans('FafaIconSocialNetworksDesc')); // List of check for fields (NOT USED YET) From 9e7c0c14d95ef8764a29d8755f9235a1733b05a7 Mon Sep 17 00:00:00 2001 From: Tobias Sekan Date: Wed, 29 Apr 2020 13:30:58 +0200 Subject: [PATCH 025/120] Add two new lang entries (admin) --- htdocs/langs/en_US/admin.lang | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 96bb77a5064..d19d928cdbd 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -1995,3 +1995,5 @@ PDF_USE_ALSO_LANGUAGE_CODE=If you want to have some texts in your PDF duplicated FafaIconSocialNetworksDesc=Enter here the code of a FontAwesome icon. If you don't know what is FontAwesome, you can use the generic value fa-address-book. RssNote=Note: Each RSS feed definition provides a widget that you must enable to have it available in dashboard JumpToBoxes=Jump to Setup -> Widgets +MeasuringUnitTypeDesc=For the product units like weight, length, area and volume use "size", "surface", "volume" or "weight" as Unit_type +MeasuringScaleDesc=The scale for the Unit_types "size", "surface", "volume" and "weight" can only we have values from -127 up to 128. From 398b0234ea95309a3d85245c1844bf3e51502527 Mon Sep 17 00:00:00 2001 From: "DEMAREST Maxime (Indelog)" Date: Wed, 29 Apr 2020 14:08:31 +0200 Subject: [PATCH 026/120] Correct label for select thirdparty categorie in invoice stats --- htdocs/compta/facture/stats/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/compta/facture/stats/index.php b/htdocs/compta/facture/stats/index.php index b1af8064d9f..513e1d6a0a2 100644 --- a/htdocs/compta/facture/stats/index.php +++ b/htdocs/compta/facture/stats/index.php @@ -263,7 +263,6 @@ print $form->selectarray("typent_id", $formcompany->typent_array(0), $typent_id, if ($user->admin) print ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); print '
'.$cat_label.''; if ($mode == 'customer') { $cat_type = Categorie::TYPE_CUSTOMER; @@ -274,6 +273,7 @@ if ($mode == 'supplier') $cat_type = Categorie::TYPE_SUPPLIER; $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Customer")); } +print '
'.$cat_label.''; print $formother->select_categories($cat_type, $categ_id, 'categ_id', true); print '
'.$cat_label.''; print $formother->select_categories($cat_type, $categ_id, 'categ_id', true); diff --git a/htdocs/compta/facture/stats/index.php b/htdocs/compta/facture/stats/index.php index 513e1d6a0a2..f5472196cc2 100644 --- a/htdocs/compta/facture/stats/index.php +++ b/htdocs/compta/facture/stats/index.php @@ -271,7 +271,7 @@ if ($mode == 'customer') if ($mode == 'supplier') { $cat_type = Categorie::TYPE_SUPPLIER; - $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Customer")); + $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Supplier")); } print '
'.$cat_label.''; print $formother->select_categories($cat_type, $categ_id, 'categ_id', true); From 84bca036c9eb20c073b1a6549d090deed4a808a6 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 29 Apr 2020 18:03:28 +0200 Subject: [PATCH 028/120] FIX Link missing into email of some notification --- htdocs/core/class/notify.class.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/htdocs/core/class/notify.class.php b/htdocs/core/class/notify.class.php index 99910e82ecc..db0e490a6c6 100644 --- a/htdocs/core/class/notify.class.php +++ b/htdocs/core/class/notify.class.php @@ -482,26 +482,31 @@ class Notify $mesg.= "\n\n".$outputlangs->transnoentitiesnoconv("Sincerely").".\n\n"; break; case 'SHIPPING_VALIDATE': + $link = ''.$newref.''; $dir_output = $conf->expedition->dir_output.'/sending/'; - $object_type = 'order_supplier'; + $object_type = 'expedition'; $mesg = $outputlangs->transnoentitiesnoconv("EMailTextExpeditionValidated", $newref); break; case 'EXPENSE_REPORT_VALIDATE': + $link = ''.$newref.''; $dir_output = $conf->expensereport->dir_output; $object_type = 'expensereport'; $mesg = $outputlangs->transnoentitiesnoconv("EMailTextExpenseReportValidated", $newref); break; case 'EXPENSE_REPORT_APPROVE': + $link = ''.$newref.''; $dir_output = $conf->expensereport->dir_output; $object_type = 'expensereport'; $mesg = $outputlangs->transnoentitiesnoconv("EMailTextExpenseReportApproved", $newref); break; case 'HOLIDAY_VALIDATE': + $link = ''.$newref.''; $dir_output = $conf->holiday->dir_output; $object_type = 'holiday'; $mesg = $outputlangs->transnoentitiesnoconv("EMailTextHolidayValidated", $newref); break; case 'HOLIDAY_APPROVE': + $link = ''.$newref.''; $dir_output = $conf->holiday->dir_output; $object_type = 'holiday'; $mesg = $outputlangs->transnoentitiesnoconv("EMailTextHolidayApproved", $newref); @@ -692,6 +697,7 @@ class Notify $mesg.= "\n\n".$langs->transnoentitiesnoconv("Sincerely").".\n\n"; break; case 'SHIPPING_VALIDATE': + $link = ''.$newref.''; $dir_output = $conf->expedition->dir_output.'/sending/'; $object_type = 'order_supplier'; $mesg = $langs->transnoentitiesnoconv("EMailTextExpeditionValidated", $newref); From 6ec6a4465ad95fb16a660f87653a8e397596d1a0 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 29 Apr 2020 20:21:17 +0200 Subject: [PATCH 029/120] FIX Setup of thirdparty or contact for external users --- htdocs/core/class/html.form.class.php | 8 +++---- htdocs/user/card.php | 30 +++++++++++++++++++++------ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 25ed9f86625..b2c677ed29d 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -1298,11 +1298,11 @@ class Form // Construct $out and $outarray $out .= ''; if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) $out .= ''; - if ($showempty == 2) $out .= ''; + if ($showempty == 2) $out .= ''; $num = $this->db->num_rows($resql); $i = 0; diff --git a/htdocs/user/card.php b/htdocs/user/card.php index 22b591dd53f..cd115dbe292 100644 --- a/htdocs/user/card.php +++ b/htdocs/user/card.php @@ -481,17 +481,22 @@ if (empty($reshook)) { if (!$error && GETPOSTISSET('contactid')) { $contactid = GETPOST('contactid', 'int'); + $socid = GETPOST('socid', 'int'); - if ($contactid > 0) { + if ($contactid > 0) { // The 'contactid' is used inpriority over the 'socid' $contact = new Contact($db); $contact->fetch($contactid); $sql = "UPDATE ".MAIN_DB_PREFIX."user"; - $sql .= " SET fk_socpeople=".$db->escape($contactid); + $sql .= " SET fk_socpeople=".((int) $contactid); if (!empty($contact->socid)) { - $sql .= ", fk_soc=".$db->escape($contact->socid); + $sql .= ", fk_soc=".((int) $contact->socid); } $sql .= " WHERE rowid=".$object->id; + } elseif ($socid > 0) { + $sql = "UPDATE ".MAIN_DB_PREFIX."user"; + $sql .= " SET fk_socpeople=NULL, fk_soc=".((int) $socid); + $sql .= " WHERE rowid=".$object->id; } else { $sql = "UPDATE ".MAIN_DB_PREFIX."user"; $sql .= " SET fk_socpeople=NULL, fk_soc=NULL"; @@ -1831,7 +1836,7 @@ else $contact->fetch($object->contactid); if ($object->socid > 0) print ' / '; else print '
'; - print ''.img_object($langs->trans("ShowContact"), 'contact').' '.dol_trunc($contact->getFullName($langs), 32).''; + print $contact->getNomUrl(1, ''); } print '
'; if ($user->id == $object->id || !$user->admin) { + // Read mode $type = $langs->trans("Internal"); if ($object->socid) $type = $langs->trans("External"); print $form->textwithpicto($type, $langs->trans("InternalExternalDesc")); @@ -2294,10 +2300,22 @@ else } else { + // Select mode $type = 0; if ($object->contactid) $type = $object->contactid; - print $form->selectcontacts(0, $type, 'contactid', 2, '', '', 1, '', false, 1); - if ($object->ldap_sid) print ' ('.$langs->trans("DomainUser").')'; + + if ($object->socid > 0 && ! ($object->contactid > 0)) { // external user but no link to a contact + print img_picto('', 'company').$form->select_company($object->socid, 'socid', '', ' '); + print img_picto('', 'contact').$form->selectcontacts(0, 0, 'contactid', 1, '', '', 1, '', false, 1); + if ($object->ldap_sid) print ' ('.$langs->trans("DomainUser").')'; + } elseif ($object->socid > 0 && $object->contactid > 0) { // external user with a link to a contact + print img_picto('', 'company').$form->select_company(0, 'socid', '', ' '); // We keep thirdparty empty, contact is already set + print img_picto('', 'contact').$form->selectcontacts(0, $object->contactid, 'contactid', 1, '', '', 1, '', false, 1); + if ($object->ldap_sid) print ' ('.$langs->trans("DomainUser").')'; + } else { // $object->socid is not > 0 here + print img_picto('', 'company').$form->select_company(0, 'socid', '', ' '); // We keep thirdparty empty, contact is already set + print img_picto('', 'contact').$form->selectcontacts(0, 0, 'contactid', 1, '', '', 1, '', false, 1); + } } print '
'.$form->editfieldkey('Phone', 'phone', '', $object, 0).''.img_picto('', 'object_phoning').'
'.$form->editfieldkey('Fax', 'fax', '', $object, 0).''.img_picto('', 'object_phoning_fax').'
'.$form->editfieldkey('EMail', 'email', '', $object, 0, 'string', '', $conf->global->SOCIETE_EMAIL_MANDATORY).'
'.$form->editfieldkey('ThirdPartyType', 'typent_id', '', $object, 0).''."\n"; + print '
'.$form->editfieldkey('ThirdPartyType', 'typent_id', '', $object, 0).'browser->layout == 'phone' ? ' colspan="3"': '').'>'."\n"; $sortparam = (empty($conf->global->SOCIETE_SORT_ON_TYPEENT) ? 'ASC' : $conf->global->SOCIETE_SORT_ON_TYPEENT); // NONE means we keep sort of original array, so we sort on position. ASC, means next function will sort on label. print $form->selectarray("typent_id", $formcompany->typent_array(0), $object->typent_id, 0, 0, 0, '', 0, 0, 0, $sortparam); if ($user->admin) print ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); print '
'.$form->editfieldkey('Staff', 'effectif_id', '', $object, 0).''; + print ''.$form->editfieldkey('Staff', 'effectif_id', '', $object, 0).'browser->layout == 'phone' ? ' colspan="3"': '').'>'; print $form->selectarray("effectif_id", $formcompany->effectif_array(0), $object->effectif_id); if ($user->admin) print ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); print '
';
@@ -211,6 +221,7 @@ print '
';
+
global->MYSQL_OLD_OPTION_DISABLE_FK)) { ?> @@ -233,14 +244,6 @@ print '
';
- - -
@@ -453,8 +456,10 @@ print "\n";
-
" id="buttonGo" />
+
+ " id="buttonGo"> + +

'.$langs->trans("BackupResult").': '; print $_SESSION["commandbackupresult"]; @@ -476,7 +481,7 @@ if (! empty($_SESSION["commandbackuplastdone"])) } if (! empty($_SESSION["commandbackuptorun"])) { - print '
'.$langs->trans("YouMustRunCommandFromCommandLineAfterLoginToUser",$dolibarr_main_db_user,$dolibarr_main_db_user).':
'."\n"; + print '
'.$langs->trans("YouMustRunCommandFromCommandLineAfterLoginToUser", $dolibarr_main_db_user, $dolibarr_main_db_user).':
'."\n"; print '
'."\n"; print ajax_autoselect("commandbackuptoruntext", 0); print '
'; @@ -505,8 +510,8 @@ print '
';
admin->dir_output.'/backup','files',0,'','',$sortfield,(strtolower($sortorder)=='asc'?SORT_ASC:SORT_DESC),1); -$result=$formfile->list_of_documents($filearray,null,'systemtools','',1,'backup/',1,0,$langs->trans("NoBackupFileAvailable"),0,$langs->trans("PreviousDumpFiles")); +$filearray=dol_dir_list($conf->admin->dir_output.'/backup', 'files', 0, '', '', $sortfield, (strtolower($sortorder)=='asc'?SORT_ASC:SORT_DESC), 1); +$result=$formfile->list_of_documents($filearray, null, 'systemtools', '', 1, 'backup/', 1, 0, $langs->trans("NoBackupFileAvailable"), 0, $langs->trans("PreviousDumpFiles")); print '
'; ?> @@ -526,7 +531,7 @@ print '
';
2 trans("BackupDesc2",DOL_DATA_ROOT).'
'; +print $langs->trans("BackupDesc2", DOL_DATA_ROOT).'
'; print $langs->trans("BackupDescX").'

'; ?> @@ -582,7 +587,7 @@ print "\n"; ?>
-
" id="buttonGo" />

@@ -593,8 +598,8 @@ print "\n";
admin->dir_output.'/documents','files',0,'','',$sortfield,(strtolower($sortorder)=='asc'?SORT_ASC:SORT_DESC),1); -$result=$formfile->list_of_documents($filearray,null,'systemtools','',1,'documents/',1,0,$langs->trans("NoBackupFileAvailable"),0,$langs->trans("PreviousDumpFiles")); +$filearray=dol_dir_list($conf->admin->dir_output.'/documents', 'files', 0, '', '', $sortfield, (strtolower($sortorder)=='asc'?SORT_ASC:SORT_DESC), 1); +$result=$formfile->list_of_documents($filearray, null, 'systemtools', '', 1, 'documents/', 1, 0, $langs->trans("NoBackupFileAvailable"), 0, $langs->trans("PreviousDumpFiles")); print '
'; ?> @@ -605,9 +610,6 @@ print '
';
- - - load("admin"); -$action=GETPOST('action','alpha'); -$what=GETPOST('what','alpha'); -$export_type=GETPOST('export_type','alpha'); -$file=GETPOST('zipfilename_template','alpha'); +$action=GETPOST('action', 'alpha'); +$what=GETPOST('what', 'alpha'); +$export_type=GETPOST('export_type', 'alpha'); +$file=GETPOST('zipfilename_template', 'alpha'); $compression = GETPOST('compression'); $file = dol_sanitizeFileName($file); -$sortfield = GETPOST('sortfield','alpha'); -$sortorder = GETPOST('sortorder','alpha'); -$page = GETPOST("page",'int'); +$sortfield = GETPOST('sortfield', 'alpha'); +$sortorder = GETPOST('sortorder', 'alpha'); +$page = GETPOST("page", 'int'); if (! $sortorder) $sortorder="DESC"; if (! $sortfield) $sortfield="date"; if ($page < 0) { $page = 0; } elseif (empty($page)) $page = 0; -$limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit; +$limit = GETPOST('limit', 'int')?GETPOST('limit', 'int'):$conf->liste_limit; $offset = $limit * $page; if (! $user->admin) accessforbidden(); @@ -112,21 +112,27 @@ $utils = new Utils($db); if ($compression == 'zip') { - $ret = dol_compress_dir(DOL_DATA_ROOT, $outputdir."/".$file, $compression); + $ret = dol_compress_dir(DOL_DATA_ROOT, $outputdir."/".$file, $compression, '/(\.log|\/temp\/|documents\/admin\/documents\/)/'); if ($ret < 0) { - $errormsg = $langs->trans("ErrorFailedToWriteInDir",$outputfile); + $errormsg = $langs->trans("ErrorFailedToWriteInDir", $outputdir); } } elseif (in_array($compression, array('gz', 'bz'))) { - $file = substr($file, 0, strrpos($file, '.')); - $file .= '.tar'; - $cmd = 'tar -cf '.$outputdir."/".$file." --exclude=documents/admin/documents -C ".DOL_DATA_ROOT." ".DOL_DATA_ROOT."/../documents/"; - exec($cmd, $out, $retval); - //var_dump($cmd, DOL_DATA_ROOT);exit; + $userlogin = ($user->login ? $user->login : 'unknown'); - if ($retval != 0) + $outputfile = $conf->admin->dir_temp.'/export_files.'.$userlogin.'.out'; // File used with popen method + + $file = substr($file, 0, strrpos($file, '.')); + $file .= '.tar'; + // We also exclude '/temp/' dir and 'documents/admin/documents' + $cmd = "tar -cf ".$outputdir."/".$file." --exclude-vcs --exclude 'temp' --exclude 'dolibarr.log' --exclude='documents/admin/documents' -C ".dirname(DOL_DATA_ROOT)." ".basename(DOL_DATA_ROOT); + + $result = $utils->executeCLI($cmd, $outputfile); + + $retval = $result['error']; + if ($result['result'] || ! empty($retval)) { $langs->load("errors"); dol_syslog("Documents tar retval after exec=".$retval, LOG_ERR); @@ -136,15 +142,17 @@ elseif (in_array($compression, array('gz', 'bz'))) { if ($compression == 'gz') { - $cmd = "gzip " . $outputdir."/".$file; + $cmd = "gzip -f " . $outputdir."/".$file; } if ($compression == 'bz') { - $cmd = "bzip2 " . $outputdir."/".$file; + $cmd = "bzip2 -f " . $outputdir."/".$file; } - exec($cmd, $out, $retval); - if ($retval != 0) + $result = $utils->executeCLI($cmd, $outputfile); + + $retval = $result['error']; + if ($result['result'] || ! empty($retval)) { $errormsg = 'Error '.$compression.' generation return '.$retval; unlink($outputdir."/".$file); @@ -166,4 +174,3 @@ header("Location: dolibarr_export.php"); $time_end = time(); $db->close(); - diff --git a/htdocs/core/class/utils.class.php b/htdocs/core/class/utils.class.php index 5007e642300..86eff6613c1 100644 --- a/htdocs/core/class/utils.class.php +++ b/htdocs/core/class/utils.class.php @@ -32,15 +32,15 @@ class Utils */ public $db; - var $output; // Used by Cron method to return message - var $result; // Used by Cron method to return data + public $output; // Used by Cron method to return message + public $result; // Used by Cron method to return data /** * Constructor * * @param DoliDB $db Database handler */ - function __construct($db) + public function __construct($db) { $this->db = $db; } @@ -54,7 +54,7 @@ class Utils * @param int $nbsecondsold Nb of seconds old to accept deletion of a directory if $choice is 'tempfilesold' * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK) */ - function purgeFiles($choice = 'tempfilesold', $nbsecondsold = 86400) + public function purgeFiles($choice = 'tempfilesold', $nbsecondsold = 86400) { global $conf, $langs, $dolibarr_main_data_root; @@ -106,7 +106,7 @@ class Utils if (! empty($conf->syslog->enabled)) { $filelog=$conf->global->SYSLOG_FILE; - $filelog=preg_replace('/DOL_DATA_ROOT/i',DOL_DATA_ROOT,$filelog); + $filelog=preg_replace('/DOL_DATA_ROOT/i', DOL_DATA_ROOT, $filelog); $alreadyincluded=false; foreach ($filesarray as $tmpcursor) @@ -193,7 +193,7 @@ class Utils * @param int $execmethod 0=Use default method (that is 1 by default), 1=Use the PHP 'exec', 2=Use the 'popen' method * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK) */ - function dumpDatabase($compression='none', $type='auto', $usedefault=1, $file='auto', $keeplastnfiles=0, $execmethod=0) + public function dumpDatabase($compression = 'none', $type = 'auto', $usedefault = 1, $file = 'auto', $keeplastnfiles = 0, $execmethod = 0) { global $db, $conf, $langs, $dolibarr_main_data_root; global $dolibarr_main_db_name, $dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_port, $dolibarr_main_db_pass; @@ -251,8 +251,8 @@ class Utils // Parameteres execution $command = $cmddump; - $command = preg_replace('/(\$|%)/', '', $command); // We removed chars that can be used to inject vars that contains space inside path of command without seeing there is a space to bypass the escapeshellarg. - if (preg_match("/\s/",$command)) $command=escapeshellarg($command); // If there is spaces, we add quotes on command to be sure $command is only a program and not a program+parameters + $command = preg_replace('/(\$|%)/', '', $command); // We removed chars that can be used to inject vars that contains space inside path of command without seeing there is a space to bypass the escapeshellarg. + if (preg_match("/\s/", $command)) $command=escapeshellarg($command); // If there is spaces, we add quotes on command to be sure $command is only a program and not a program+parameters //$param=escapeshellarg($dolibarr_main_db_name)." -h ".escapeshellarg($dolibarr_main_db_host)." -u ".escapeshellarg($dolibarr_main_db_user)." -p".escapeshellarg($dolibarr_main_db_pass); $param=$dolibarr_main_db_name." -h ".$dolibarr_main_db_host; @@ -262,7 +262,6 @@ class Utils if (GETPOST("disable_fk", "alpha") || $usedefault) $param.=" -K"; if (GETPOST("sql_compat", "alpha") && GETPOST("sql_compat", "alpha") != 'NONE') $param.=" --compatible=".escapeshellarg(GETPOST("sql_compat", "alpha")); if (GETPOST("drop_database", "alpha")) $param.=" --add-drop-database"; - if (GETPOST("use_mysql_quick_param", "alpha"))$param.=" --quick"; if (GETPOST("sql_structure", "alpha") || $usedefault) { if (GETPOST("drop", "alpha") || $usedefault) $param.=" --add-drop-table=TRUE"; @@ -292,8 +291,8 @@ class Utils $paramclear=$param; if (! empty($dolibarr_main_db_pass)) { - $paramcrypted.=' -p"'.preg_replace('/./i','*',$dolibarr_main_db_pass).'"'; - $paramclear.=' -p"'.str_replace(array('"','`'),array('\"','\`'),$dolibarr_main_db_pass).'"'; + $paramcrypted.=' -p"'.preg_replace('/./i', '*', $dolibarr_main_db_pass).'"'; + $paramclear.=' -p"'.str_replace(array('"','`'), array('\"','\`'), $dolibarr_main_db_pass).'"'; } $errormsg=''; @@ -317,27 +316,29 @@ class Utils // TODO Replace with executeCLI function if ($execmethod == 1) { - exec($fullcommandclear, $readt, $retval); - $result = $retval; + $output_arr = array(); $retval = null; + exec($fullcommandclear, $output_arr, $retval); if ($retval != 0) { $langs->load("errors"); dol_syslog("Datadump retval after exec=".$retval, LOG_ERR); - $error = 'Error '.$retval; + $errormsg = 'Error '.$retval; $ok=0; } else { $i=0; - if (!empty($readt)) - foreach($readt as $key=>$read) + if (!empty($output_arr)) { - $i++; // output line number - if ($i == 1 && preg_match('/Warning.*Using a password/i', $read)) continue; - fwrite($handle, $read.($execmethod == 2 ? '' : "\n")); - if (preg_match('/'.preg_quote('-- Dump completed').'/i',$read)) $ok=1; - elseif (preg_match('/'.preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES').'/i',$read)) $ok=1; + foreach($output_arr as $key => $read) + { + $i++; // output line number + if ($i == 1 && preg_match('/Warning.*Using a password/i', $read)) continue; + fwrite($handle, $read.($execmethod == 2 ? '' : "\n")); + if (preg_match('/'.preg_quote('-- Dump completed').'/i', $read)) $ok=1; + elseif (preg_match('/'.preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES').'/i', $read)) $ok=1; + } } } } @@ -351,9 +352,9 @@ class Utils $read = fgets($handlein); // Exclude warning line we don't want if ($i == 1 && preg_match('/Warning.*Using a password/i', $read)) continue; - fwrite($handle,$read); - if (preg_match('/'.preg_quote('-- Dump completed').'/i',$read)) $ok=1; - elseif (preg_match('/'.preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES').'/i',$read)) $ok=1; + fwrite($handle, $read); + if (preg_match('/'.preg_quote('-- Dump completed').'/i', $read)) $ok=1; + elseif (preg_match('/'.preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES').'/i', $read)) $ok=1; } pclose($handlein); } @@ -369,7 +370,7 @@ class Utils else { $langs->load("errors"); - dol_syslog("Failed to open file ".$outputfile,LOG_ERR); + dol_syslog("Failed to open file ".$outputfile, LOG_ERR); $errormsg=$langs->trans("ErrorFailedToWriteInDir"); } @@ -380,18 +381,18 @@ class Utils if ($handle) { // Get 2048 first chars of error message. - $errormsg = fgets($handle,2048); + $errormsg = fgets($handle, 2048); // Close file if ($compression == 'none') fclose($handle); if ($compression == 'gz') gzclose($handle); if ($compression == 'bz') bzclose($handle); - if ($ok && preg_match('/^-- MySql/i',$errormsg)) $errormsg=''; // Pas erreur + if ($ok && preg_match('/^-- MySql/i', $errormsg)) $errormsg=''; // Pas erreur else { // Renommer fichier sortie en fichier erreur //print "$outputfile -> $outputerror"; @dol_delete_file($outputerror, 1, 0, 0, null, false, 0); - @rename($outputfile,$outputerror); + @rename($outputfile, $outputerror); // Si safe_mode on et command hors du parametre exec, on a un fichier out vide donc errormsg vide if (! $errormsg) { @@ -450,8 +451,8 @@ class Utils // Parameteres execution $command = $cmddump; - $command = preg_replace('/(\$|%)/', '', $command); // We removed chars that can be used to inject vars that contains space inside path of command without seeing there is a space to bypass the escapeshellarg. - if (preg_match("/\s/",$command)) $command=escapeshellarg($command); // If there is spaces, we add quotes on command to be sure $command is only a program and not a program+parameters + $command = preg_replace('/(\$|%)/', '', $command); // We removed chars that can be used to inject vars that contains space inside path of command without seeing there is a space to bypass the escapeshellarg. + if (preg_match("/\s/", $command)) $command=escapeshellarg($command); // If there is spaces, we add quotes on command to be sure $command is only a program and not a program+parameters //$param=escapeshellarg($dolibarr_main_db_name)." -h ".escapeshellarg($dolibarr_main_db_host)." -u ".escapeshellarg($dolibarr_main_db_user)." -p".escapeshellarg($dolibarr_main_db_pass); //$param="-F c"; @@ -515,7 +516,7 @@ class Utils * @param int $execmethod 0=Use default method (that is 1 by default), 1=Use the PHP 'exec', 2=Use the 'popen' method * @return array array('result'=>...,'output'=>...,'error'=>...). result = 0 means OK. */ - function executeCLI($command, $outputfile, $execmethod=0) + public function executeCLI($command, $outputfile, $execmethod = 0) { global $conf, $langs; @@ -535,6 +536,7 @@ class Utils if ($execmethod == 1) { + $retval = null; exec($command, $output_arr, $retval); $result = $retval; if ($retval != 0) @@ -546,7 +548,6 @@ class Utils } if ($execmethod == 2) // With this method, there is no way to get the return code, only output { - $ok=0; $handle = fopen($outputfile, 'w+b'); if ($handle) { @@ -555,7 +556,7 @@ class Utils while (!feof($handlein)) { $read = fgets($handlein); - fwrite($handle,$read); + fwrite($handle, $read); $output_arr[]=$read; } pclose($handlein); @@ -584,14 +585,15 @@ class Utils * @param string $module Module name * @return int <0 if KO, >0 if OK */ - function generateDoc($module) + public function generateDoc($module) { - global $conf, $langs; + global $conf, $langs, $user, $mysoc; global $dirins; $error = 0; $modulelowercase=strtolower($module); + $now=dol_now(); // Dir for module $dir = $dirins.'/'.$modulelowercase; @@ -621,11 +623,12 @@ class Utils exit; } - $arrayversion=explode('.',$moduleobj->version,3); + $arrayversion=explode('.', $moduleobj->version, 3); if (count($arrayversion)) { $FILENAMEASCII=strtolower($module).'.asciidoc'; - $FILENAMEDOC=strtolower($module).'.html'; // TODO Use/text PDF + $FILENAMEDOC=strtolower($module).'.html'; + $FILENAMEDOCPDF=strtolower($module).'.pdf'; $dirofmodule = dol_buildpath(strtolower($module), 0); $dirofmoduledoc = dol_buildpath(strtolower($module), 0).'/doc'; @@ -641,13 +644,25 @@ class Utils return -1; } - $conf->global->MODULEBUILDER_ASCIIDOCTOR='asciidoctor'; - if (empty($conf->global->MODULEBUILDER_ASCIIDOCTOR)) + if (empty($conf->global->MODULEBUILDER_ASCIIDOCTOR) && empty($conf->global->MODULEBUILDER_ASCIIDOCTORPDF)) { $this->error = 'Setup of module ModuleBuilder not complete'; return -1; } + // Copy some files into temp directory, so instruction include::ChangeLog.md[] will works inside the asciidoc file. + dol_copy($dirofmodule.'/README.md', $dirofmoduletmp.'/README.md', 0, 1); + dol_copy($dirofmodule.'/ChangeLog.md', $dirofmoduletmp.'/ChangeLog.md', 0, 1); + + // Replace into README.md and ChangeLog.md (in case they are included into documentation with tag __README__ or __CHANGELOG__) + $arrayreplacement=array(); + $arrayreplacement['/^#\s.*/m']=''; // Remove first level of title into .md files + $arrayreplacement['/^#/m']='##'; // Add on # to increase level + + dolReplaceInFile($dirofmoduletmp.'/README.md', $arrayreplacement, '', 0, 0, 1); + dolReplaceInFile($dirofmoduletmp.'/ChangeLog.md', $arrayreplacement, '', 0, 0, 1); + + $destfile=$dirofmoduletmp.'/'.$FILENAMEASCII; $fhandle = fopen($destfile, 'w+'); @@ -680,35 +695,48 @@ class Utils $i++; } - fwrite($fhandle, "\n\n\n== DATA SPECIFICATIONS...\n\n"); - - // TODO - fwrite($fhandle, "TODO..."); - - - fwrite($fhandle, "\n\n\n== CHANGELOG...\n\n"); - - // TODO - fwrite($fhandle, "TODO..."); - - - fclose($fhandle); - } - // Copy some files into temp directory - dol_copy($dirofmodule.'/README.md', $dirofmoduletmp.'/README.md', 0, 1); - dol_copy($dirofmodule.'/ChangeLog.md', $dirofmoduletmp.'/ChangeLog.md', 0, 1); + $contentreadme=file_get_contents($dirofmoduletmp.'/README.md'); + $contentchangelog=file_get_contents($dirofmoduletmp.'/ChangeLog.md'); + + include DOL_DOCUMENT_ROOT.'/core/lib/parsemd.lib.php'; + + //var_dump($phpfileval['fullname']); + $arrayreplacement=array( + 'mymodule'=>strtolower($module), + 'MyModule'=>$module, + 'MYMODULE'=>strtoupper($module), + 'My module'=>$module, + 'my module'=>$module, + 'Mon module'=>$module, + 'mon module'=>$module, + 'htdocs/modulebuilder/template'=>strtolower($module), + '__MYCOMPANY_NAME__'=>$mysoc->name, + '__KEYWORDS__'=>$module, + '__USER_FULLNAME__'=>$user->getFullName($langs), + '__USER_EMAIL__'=>$user->email, + '__YYYY-MM-DD__'=>dol_print_date($now, 'dayrfc'), + '---Put here your own copyright and developer email---'=>dol_print_date($now, 'dayrfc').' '.$user->getFullName($langs).($user->email?' <'.$user->email.'>':''), + '__DATA_SPECIFICATION__'=>'Not yet available', + '__README__'=>dolMd2Asciidoc($contentreadme), + '__CHANGELOG__'=>dolMd2Asciidoc($contentchangelog), + ); + + dolReplaceInFile($destfile, $arrayreplacement); + } // Launch doc generation $currentdir = getcwd(); chdir($dirofmodule); + require_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php'; + $utils = new Utils($db); + + // Build HTML doc $command=$conf->global->MODULEBUILDER_ASCIIDOCTOR.' '.$destfile.' -n -o '.$dirofmoduledoc.'/'.$FILENAMEDOC; $outfile=$dirofmoduletmp.'/out.tmp'; - require_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php'; - $utils = new Utils($this->db); $resarray = $utils->executeCLI($command, $outfile); if ($resarray['result'] != '0') { @@ -716,6 +744,16 @@ class Utils } $result = ($resarray['result'] == 0) ? 1 : 0; + // Build PDF doc + $command=$conf->global->MODULEBUILDER_ASCIIDOCTORPDF.' '.$destfile.' -n -o '.$dirofmoduledoc.'/'.$FILENAMEDOCPDF; + $outfile=$dirofmoduletmp.'/outpdf.tmp'; + $resarray = $utils->executeCLI($command, $outfile); + if ($resarray['result'] != '0') + { + $this->error = $resarray['error'].' '.$resarray['output']; + } + $result = ($resarray['result'] == 0) ? 1 : 0; + chdir($currentdir); } else @@ -751,7 +789,7 @@ class Utils * * @return int 0 if OK, < 0 if KO */ - function compressSyslogs() + public function compressSyslogs() { global $conf; @@ -857,7 +895,7 @@ class Utils $this->output = 'Archive log files (keeping last SYSLOG_FILE_SAVES='.$nbSaves.' files) done.'; return 0; - } + } /** Backup the db OR just a table without mysqldump binary, with PHP only (does not require any exec permission) * Author: David Walsh (http://davidwalsh.name/backup-mysql-database-php) @@ -869,7 +907,7 @@ class Utils * @param string $tables Table name or '*' for all * @return int <0 if KO, >0 if OK */ - function backupTables($outputfile, $tables='*') + public function backupTables($outputfile, $tables = '*') { global $db, $langs; global $errormsg; @@ -896,7 +934,7 @@ class Utils } else { - $tables = is_array($tables) ? $tables : explode(',',$tables); + $tables = is_array($tables) ? $tables : explode(',', $tables); } //cycle through @@ -904,7 +942,7 @@ class Utils if (fwrite($handle, '') === false) { $langs->load("errors"); - dol_syslog("Failed to open file ".$outputfile,LOG_ERR); + dol_syslog("Failed to open file ".$outputfile, LOG_ERR); $errormsg=$langs->trans("ErrorFailedToWriteInDir"); return -1; } @@ -947,9 +985,9 @@ class Utils // Saving the table structure fwrite($handle, "\n--\n-- Table structure for table `".$table."`\n--\n"); - if (GETPOST("nobin_drop")) fwrite($handle,"DROP TABLE IF EXISTS `".$table."`;\n"); // Dropping table if exists prior to re create it - fwrite($handle,"/*!40101 SET @saved_cs_client = @@character_set_client */;\n"); - fwrite($handle,"/*!40101 SET character_set_client = utf8 */;\n"); + if (GETPOST("nobin_drop")) fwrite($handle, "DROP TABLE IF EXISTS `".$table."`;\n"); // Dropping table if exists prior to re create it + fwrite($handle, "/*!40101 SET @saved_cs_client = @@character_set_client */;\n"); + fwrite($handle, "/*!40101 SET character_set_client = utf8 */;\n"); $resqldrop=$db->query('SHOW CREATE TABLE '.$table); $row2 = $db->fetch_row($resqldrop); if (empty($row2[1])) @@ -958,7 +996,7 @@ class Utils } else { - fwrite($handle,$row2[1].";\n"); + fwrite($handle, $row2[1].";\n"); //fwrite($handle,"/*!40101 SET character_set_client = @saved_cs_client */;\n\n"); // Dumping the data (locking the table and disabling the keys check while doing the process) @@ -972,7 +1010,7 @@ class Utils while($row = $db->fetch_row($result)) { // For each row of data we print a line of INSERT - fwrite($handle,'INSERT '.$delayed.$ignore.'INTO `'.$table.'` VALUES ('); + fwrite($handle, 'INSERT '.$delayed.$ignore.'INTO `'.$table.'` VALUES ('); $columns = count($row); for($j=0; $j<$columns; $j++) { // Processing each columns of the row to ensure that we correctly save the value (eg: add quotes for string - in fact we add quotes for everything, it's easier) @@ -991,11 +1029,11 @@ class Utils $row[$j] = "'".$row[$j]."'"; } } - fwrite($handle,implode(',', $row).");\n"); + fwrite($handle, implode(',', $row).");\n"); } if (GETPOST("nobin_disable_fk")) fwrite($handle, "ALTER TABLE `".$table."` ENABLE KEYS;\n"); // Enabling back the keys/index checking if (!GETPOST("nobin_nolocks")) fwrite($handle, "UNLOCK TABLES;\n"); // Unlocking the table - fwrite($handle,"\n\n\n"); + fwrite($handle, "\n\n\n"); } } diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 295bda85d53..d2aee3e6a30 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -4,6 +4,7 @@ * Copyright (C) 2012-2016 Juanjo Menent * Copyright (C) 2015 Marcos García * Copyright (C) 2016 Raphaël Doursenaud + * Copyright (C) 2019 Frédéric France * * 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 @@ -34,7 +35,7 @@ */ function dol_basename($pathfile) { - return preg_replace('/^.*\/([^\/]+)$/','$1',rtrim($pathfile,'/')); + return preg_replace('/^.*\/([^\/]+)$/', '$1', rtrim($pathfile, '/')); } /** @@ -54,9 +55,9 @@ function dol_basename($pathfile) * @param string $relativename For recursive purpose only. Must be "" at first call. * @param string $donotfollowsymlinks Do not follow symbolic links * @return array Array of array('name'=>'xxx','fullname'=>'/abc/xxx','date'=>'yyy','size'=>99,'type'=>'dir|file',...) - * @see dol_dir_list_indatabase + * @see dol_dir_list_in_database() */ -function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0) +function dol_dir_list($path, $types = "all", $recursive = 0, $filter = "", $excludefilter = null, $sortcriteria = "name", $sortorder = SORT_ASC, $mode = 0, $nohook = 0, $relativename = "", $donotfollowsymlinks = 0) { global $db, $hookmanager; global $object; @@ -68,7 +69,7 @@ function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefil $loadsize=($mode==1||$mode==3)?true:false; // Clean parameters - $path=preg_replace('/([\\/]+)$/i','',$path); + $path=preg_replace('/([\\/]+)$/i', '', $path); $newpath=dol_osencode($path); $reshook = 0; @@ -116,9 +117,9 @@ function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefil $excludefilterarray=array('^\.'); if (is_array($excludefilter)) { - $excludefilterarray=array_merge($excludefilterarray,$excludefilter); + $excludefilterarray=array_merge($excludefilterarray, $excludefilter); } - else if ($excludefilter) $excludefilterarray[]=$excludefilter; + elseif ($excludefilter) $excludefilterarray[]=$excludefilter; // Check if file is qualified foreach($excludefilterarray as $filt) { @@ -140,9 +141,9 @@ function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefil if ($loaddate || $sortcriteria == 'date') $filedate=dol_filemtime($path."/".$file); if ($loadsize || $sortcriteria == 'size') $filesize=dol_filesize($path."/".$file); - if (! $filter || preg_match('/'.$filter.'/i',$file)) // We do not search key $filter into all $path, only into $file part + if (! $filter || preg_match('/'.$filter.'/i', $file)) // We do not search key $filter into all $path, only into $file part { - preg_match('/([^\/]+)\/[^\/]+$/',$path.'/'.$file,$reg); + preg_match('/([^\/]+)\/[^\/]+$/', $path.'/'.$file, $reg); $level1name=(isset($reg[1])?$reg[1]:''); $file_list[] = array( "name" => $file, @@ -167,15 +168,15 @@ function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefil } } } - else if (! $isdir && (($types == "files") || ($types == "all"))) + elseif (! $isdir && (($types == "files") || ($types == "all"))) { // Add file into file_list array if ($loaddate || $sortcriteria == 'date') $filedate=dol_filemtime($path."/".$file); if ($loadsize || $sortcriteria == 'size') $filesize=dol_filesize($path."/".$file); - if (! $filter || preg_match('/'.$filter.'/i',$file)) // We do not search key $filter into $path, only into $file + if (! $filter || preg_match('/'.$filter.'/i', $file)) // We do not search key $filter into $path, only into $file { - preg_match('/([^\/]+)\/[^\/]+$/',$path.'/'.$file,$reg); + preg_match('/([^\/]+)\/[^\/]+$/', $path.'/'.$file, $reg); $level1name=(isset($reg[1])?$reg[1]:''); $file_list[] = array( "name" => $file, @@ -194,15 +195,9 @@ function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefil closedir($dir); // Obtain a list of columns - if (! empty($sortcriteria)) + if (! empty($sortcriteria) && $sortorder) { - $myarray=array(); - foreach ($file_list as $key => $row) - { - $myarray[$key] = (isset($row[$sortcriteria])?$row[$sortcriteria]:''); - } - // Sort the data - if ($sortorder) array_multisort($myarray, $sortorder, $file_list); + $file_list = dol_sort_array($file_list, $sortcriteria, ($sortorder == SORT_ASC ? 'asc' : 'desc')); } } } @@ -224,9 +219,9 @@ function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefil * @param string $sortorder Sort order (SORT_ASC, SORT_DESC) * @param int $mode 0=Return array minimum keys loaded (faster), 1=Force all keys like description * @return array Array of array('name'=>'xxx','fullname'=>'/abc/xxx','type'=>'dir|file',...) - * @see dol_dir_list + * @see dol_dir_list() */ -function dol_dir_list_in_database($path, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0) +function dol_dir_list_in_database($path, $filter = "", $excludefilter = null, $sortcriteria = "name", $sortorder = SORT_ASC, $mode = 0) { global $conf, $db; @@ -248,7 +243,7 @@ function dol_dir_list_in_database($path, $filter="", $excludefilter=null, $sortc $obj = $db->fetch_object($resql); if ($obj) { - preg_match('/([^\/]+)\/[^\/]+$/',DOL_DATA_ROOT.'/'.$obj->filepath.'/'.$obj->filename,$reg); + preg_match('/([^\/]+)\/[^\/]+$/', DOL_DATA_ROOT.'/'.$obj->filepath.'/'.$obj->filename, $reg); $level1name=(isset($reg[1])?$reg[1]:''); $file_list[] = array( "rowid" => $obj->rowid, @@ -313,11 +308,11 @@ function completeFileArrayWithDatabaseInfo(&$filearray, $relativedir) global $object; if (! empty($object->id)) { - if (! empty($conf->product->enabled)) $upload_dirold = $conf->product->multidir_output[$object->entity].'/'.substr(substr("000".$object->id, -2),1,1).'/'.substr(substr("000".$object->id, -2),0,1).'/'.$object->id."/photos"; - else $upload_dirold = $conf->service->multidir_output[$object->entity].'/'.substr(substr("000".$object->id, -2),1,1).'/'.substr(substr("000".$object->id, -2),0,1).'/'.$object->id."/photos"; + if (! empty($conf->product->enabled)) $upload_dirold = $conf->product->multidir_output[$object->entity].'/'.substr(substr("000".$object->id, -2), 1, 1).'/'.substr(substr("000".$object->id, -2), 0, 1).'/'.$object->id."/photos"; + else $upload_dirold = $conf->service->multidir_output[$object->entity].'/'.substr(substr("000".$object->id, -2), 1, 1).'/'.substr(substr("000".$object->id, -2), 0, 1).'/'.$object->id."/photos"; - $relativedirold = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $upload_dirold); - $relativedirold = preg_replace('/^[\\/]/','',$relativedirold); + $relativedirold = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $upload_dirold); + $relativedirold = preg_replace('/^[\\/]/', '', $relativedirold); $filearrayindatabase = array_merge($filearrayindatabase, dol_dir_list_in_database($relativedirold, '', null, 'name', SORT_ASC)); } @@ -353,7 +348,7 @@ function completeFileArrayWithDatabaseInfo(&$filearray, $relativedir) $filearray[$key]['cover']=0; $filearray[$key]['acl']=''; - $rel_filename = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $filearray[$key]['fullname']); + $rel_filename = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $filearray[$key]['fullname']); if (! preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filetorenameafter)) // If not a tmp file { dol_syslog("list_of_documents We found a file called '".$filearray[$key]['name']."' not indexed into database. We add it"); @@ -442,6 +437,18 @@ function dol_is_dir($folder) else return false; } +/** + * Return if path is empty + * + * @param string $dir Path of Directory + * @return boolean True or false + */ +function dol_is_dir_empty($dir) +{ + if (!is_readable($dir)) return false; + return (count(scandir($dir)) == 2); +} + /** * Return if path is a file * @@ -477,7 +484,7 @@ function dol_is_url($url) $tmpprot=array('file','http','https','ftp','zlib','data','ssh','ssh2','ogg','expect'); foreach($tmpprot as $prot) { - if (preg_match('/^'.$prot.':/i',$url)) return true; + if (preg_match('/^'.$prot.':/i', $url)) return true; } return false; } @@ -515,7 +522,7 @@ function dol_dir_is_emtpy($folder) * * @param string $file Filename * @return int <0 if KO, Number of lines in files if OK - * @see dol_nboflines + * @see dol_nboflines() */ function dol_count_nb_of_line($file) { @@ -523,7 +530,7 @@ function dol_count_nb_of_line($file) $newfile=dol_osencode($file); //print 'x'.$file; - $fp=fopen($newfile,'r'); + $fp=fopen($newfile, 'r'); if ($fp) { while (!feof($fp)) @@ -570,19 +577,20 @@ function dol_filemtime($pathoffile) /** * Make replacement of strings into a file. * - * @param string $srcfile Source file (can't be a directory) - * @param array $arrayreplacement Array with strings to replace. Example: array('valuebefore'=>'valueafter', ...) - * @param string $destfile Destination file (can't be a directory). If empty, will be same than source file. - * @param int $newmask Mask for new file (0 by default means $conf->global->MAIN_UMASK). Example: '0666' - * @param int $indexdatabase 1=index new file into database. - * @return int <0 if error, 0 if nothing done (dest file already exists), >0 if OK - * @see dol_copy dolReplaceRegExInFile + * @param string $srcfile Source file (can't be a directory) + * @param array $arrayreplacement Array with strings to replace. Example: array('valuebefore'=>'valueafter', ...) + * @param string $destfile Destination file (can't be a directory). If empty, will be same than source file. + * @param int $newmask Mask for new file (0 by default means $conf->global->MAIN_UMASK). Example: '0666' + * @param int $indexdatabase 1=index new file into database. + * @param int $arrayreplacementisregex 1=Array of replacement is regex + * @return int <0 if error, 0 if nothing done (dest file already exists), >0 if OK + * @see dol_copy() */ -function dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask=0, $indexdatabase=0) +function dolReplaceInFile($srcfile, $arrayreplacement, $destfile = '', $newmask = 0, $indexdatabase = 0, $arrayreplacementisregex = 0) { global $conf; - dol_syslog("files.lib.php::dolReplaceInFile srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." indexdatabase=".$indexdatabase); + dol_syslog("files.lib.php::dolReplaceInFile srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." indexdatabase=".$indexdatabase." arrayreplacementisregex=".$arrayreplacementisregex); if (empty($srcfile)) return -1; if (empty($destfile)) $destfile=$srcfile; @@ -613,7 +621,17 @@ function dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask=0, // Create $newpathoftmpdestfile from $newpathofsrcfile $content = file_get_contents($newpathofsrcfile, 'r'); - $content = make_substitutions($content, $arrayreplacement, null); + if (empty($arrayreplacementisregex)) + { + $content = make_substitutions($content, $arrayreplacement, null); + } + else + { + foreach ($arrayreplacement as $key => $value) + { + $content = preg_replace($key, $value, $content); + } + } file_put_contents($newpathoftmpdestfile, $content); @chmod($newpathoftmpdestfile, octdec($newmask)); @@ -637,21 +655,6 @@ function dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask=0, return 1; } -/** - * Make replacement of strings into a file. - * - * @param string $srcfile Source file (can't be a directory) - * @param array $arrayreplacement Array with strings to replace. Example: array('valuebefore'=>'valueafter', ...) - * @param string $destfile Destination file (can't be a directory). If empty, will be same than source file. - * @param int $newmask Mask for new file (0 by default means $conf->global->MAIN_UMASK). Example: '0666' - * @param int $indexdatabase Index new file into database. - * @return int <0 if error, 0 if nothing done (dest file already exists), >0 if OK - * @see dol_copy dolReplaceInFile - */ -function dolReplaceRegExInFile($srcfile, $arrayreplacement, $destfile='', $newmask=0, $indexdatabase=0) -{ - // TODO -} /** * Copy a file to another file. @@ -661,9 +664,9 @@ function dolReplaceRegExInFile($srcfile, $arrayreplacement, $destfile='', $newma * @param int $newmask Mask for new file (0 by default means $conf->global->MAIN_UMASK). Example: '0666' * @param int $overwriteifexists Overwrite file if exists (1 by default) * @return int <0 if error, 0 if nothing done (dest file already exists and overwriteifexists=0), >0 if OK - * @see dol_delete_file + * @see dol_delete_file() dolCopyDir() */ -function dol_copy($srcfile, $destfile, $newmask=0, $overwriteifexists=1) +function dol_copy($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1) { global $conf; @@ -717,9 +720,9 @@ function dol_copy($srcfile, $destfile, $newmask=0, $overwriteifexists=1) * @param int $overwriteifexists Overwrite file if exists (1 by default) * @param array $arrayreplacement Array to use to replace filenames with another one during the copy (works only on file names, not on directory names). * @return int <0 if error, 0 if nothing done (all files already exists and overwriteifexists=0), >0 if OK - * @see dol_copy + * @see dol_copy() */ -function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement=null) +function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement = null) { global $conf; @@ -809,9 +812,9 @@ function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayrep * @param int $testvirus Do an antivirus test. Move is canceled if a virus is found. * @param int $indexdatabase Index new file into database. * @return boolean True if OK, false if KO - * @see dol_move_uploaded_file + * @see dol_move_uploaded_file() */ -function dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=1) +function dol_move($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1, $testvirus = 0, $indexdatabase = 1) { global $user, $db, $conf; $result=false; @@ -860,8 +863,8 @@ function dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvi if ($result && $indexdatabase) { // Rename entry into ecm database - $rel_filetorenamebefore = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $srcfile); - $rel_filetorenameafter = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $destfile); + $rel_filetorenamebefore = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $srcfile); + $rel_filetorenameafter = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $destfile); if (! preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filetorenameafter)) // If not a tmp file { $rel_filetorenamebefore = preg_replace('/^[\\/]/', '', $rel_filetorenamebefore); @@ -956,18 +959,18 @@ function dol_unescapefile($filename) */ function dolCheckVirus($src_file) { - global $conf, $db; + global $conf; if (! empty($conf->global->MAIN_ANTIVIRUS_COMMAND)) { if (! class_exists('AntiVir')) { require_once DOL_DOCUMENT_ROOT.'/core/class/antivir.class.php'; } - $antivir = new AntiVir($db); + $antivir=new AntiVir($db); $result = $antivir->dol_avscan_file($src_file); if ($result < 0) // If virus or error, we stop here { - $reterrors = $antivir->errors; + $reterrors=$antivir->errors; return $reterrors; } } @@ -982,6 +985,7 @@ function dolCheckVirus($src_file) * - This function can be used only into a HTML page context. Use dol_move if you are outside. * - Test on antivirus is always done (if antivirus set). * - Database of files is NOT updated (this is done by dol_add_file_process() that calls this function). + * - Extension .noexe may be added if file is executable and MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED is not set. * * @param string $src_file Source full path filename ($_FILES['field']['tmp_name']) * @param string $dest_file Target full path filename ($_FILES['field']['name']) @@ -990,10 +994,10 @@ function dolCheckVirus($src_file) * @param integer $uploaderrorcode Value of PHP upload error code ($_FILES['field']['error']) * @param int $nohook Disable all hooks * @param string $varfiles _FILES var name - * @return int|string >0 if OK, <0 or string if KO - * @see dol_move + * @return int >0 if OK, <0 or string if KO + * @see dol_move() */ -function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $varfiles='addedfile') +function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan = 0, $uploaderrorcode = 0, $nohook = 0, $varfiles = 'addedfile') { global $conf, $db, $user, $langs; global $object, $hookmanager; @@ -1045,8 +1049,8 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable $checkvirusarray=dolCheckVirus($src_file); if (count($checkvirusarray)) { - dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: result='.$result.' errors='.join(',',$checkvirusarray), LOG_WARNING); - return 'ErrorFileIsInfectedWithAVirus: '.join(',',$checkvirusarray); + dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.join(',', $checkvirusarray), LOG_WARNING); + return 'ErrorFileIsInfectedWithAVirus: '.join(',', $checkvirusarray); } } @@ -1060,15 +1064,15 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable // Security: // We refuse cache files/dirs, upload using .. and pipes into filenames. - if (preg_match('/^\./',$src_file) || preg_match('/\.\./',$src_file) || preg_match('/[<>|]/',$src_file)) + if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file)) { dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING); return -1; } // Security: - // On interdit fichiers caches, remontees de repertoire ainsi que les pipe dans les noms de fichiers. - if (preg_match('/^\./',$dest_file) || preg_match('/\.\./',$dest_file) || preg_match('/[<>|]/',$dest_file)) + // We refuse cache files/dirs, upload using .. and pipes into filenames. + if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) { dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING); return -2; @@ -1134,9 +1138,9 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable * @param boolean $allowdotdot Allow to delete file path with .. inside. Never use this, it is reserved for migration purpose. * @param int $indexdatabase Try to remove also index entries. * @return boolean True if no error (file is deleted or if glob is used and there's nothing to delete), False if error - * @see dol_delete_dir + * @see dol_delete_dir() */ -function dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1) +function dol_delete_file($file, $disableglob = 0, $nophperrors = 0, $nohook = 0, $object = null, $allowdotdot = false, $indexdatabase = 1) { global $db, $conf, $user, $langs; global $hookmanager; @@ -1148,7 +1152,7 @@ function dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $obje // Security: // We refuse transversal using .. and pipes into filenames. - if ((! $allowdotdot && preg_match('/\.\./',$file)) || preg_match('/[<>|]/',$file)) + if ((! $allowdotdot && preg_match('/\.\./', $file)) || preg_match('/[<>|]/', $file)) { dol_syslog("Refused to delete file ".$file, LOG_WARNING); return false; @@ -1181,8 +1185,8 @@ function dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $obje if (empty($disableglob) && ! empty($file_osencoded)) { $ok=true; - $globencoded=str_replace('[','\[',$file_osencoded); - $globencoded=str_replace(']','\]',$globencoded); + $globencoded=str_replace('[', '\[', $file_osencoded); + $globencoded=str_replace(']', '\]', $globencoded); $listofdir=glob($globencoded); if (! empty($listofdir) && is_array($listofdir)) { @@ -1195,7 +1199,7 @@ function dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $obje dol_syslog("Removed file ".$filename, LOG_DEBUG); // Delete entry into ecm database - $rel_filetodelete = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $filename); + $rel_filetodelete = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $filename); if (! preg_match('/(\/temp\/|\/thumbs\/|\.meta$)/', $rel_filetodelete)) // If not a tmp file { $rel_filetodelete = preg_replace('/^[\\/]/', '', $rel_filetodelete); @@ -1217,9 +1221,12 @@ function dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $obje } } } - else dol_syslog("Failed to remove file ".$filename, LOG_WARNING); - // TODO Failure to remove can be because file was already removed or because of permission - // If error because it does not exists, we should return true, and we should return false if this is a permission problem + else + { + dol_syslog("Failed to remove file ".$filename, LOG_WARNING); + // TODO Failure to remove can be because file was already removed or because of permission + // If error because it does not exists, we should return true, and we should return false if this is a permission problem + } } } else dol_syslog("No files to delete found", LOG_DEBUG); @@ -1244,13 +1251,13 @@ function dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $obje * @param string $dir Directory to delete * @param int $nophperrors Disable all PHP output errors * @return boolean True if success, false if error - * @see dol_delete_file dol_copy + * @see dol_delete_file() dolCopyDir() */ -function dol_delete_dir($dir,$nophperrors=0) +function dol_delete_dir($dir, $nophperrors = 0) { // Security: // We refuse transversal using .. and pipes into filenames. - if (preg_match('/\.\./',$dir) || preg_match('/[<>|]/',$dir)) + if (preg_match('/\.\./', $dir) || preg_match('/[<>|]/', $dir)) { dol_syslog("Refused to delete dir ".$dir, LOG_WARNING); return false; @@ -1270,9 +1277,9 @@ function dol_delete_dir($dir,$nophperrors=0) * @param int $countdeleted Counter to count nb of elements found really deleted * @return int Number of files and directory we try to remove. NB really removed is returned into var by reference $countdeleted. */ -function dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0) +function dol_delete_dir_recursive($dir, $count = 0, $nophperrors = 0, $onlysub = 0, &$countdeleted = 0) { - dol_syslog("functions.lib:dol_delete_dir_recursive ".$dir,LOG_DEBUG); + dol_syslog("functions.lib:dol_delete_dir_recursive ".$dir, LOG_DEBUG); if (dol_is_dir($dir)) { $dir_osencoded=dol_osencode($dir); @@ -1319,7 +1326,7 @@ function dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$ * * @param object $object Object to clean * @return int 0 if error, 1 if OK - * @see dol_convert_file + * @see dol_convert_file() */ function dol_delete_preview($object) { @@ -1347,26 +1354,26 @@ function dol_delete_preview($object) // For new preview files if (file_exists($filepreviewnew) && is_writable($filepreviewnew)) { - if (! dol_delete_file($filepreviewnew,1)) + if (! dol_delete_file($filepreviewnew, 1)) { - $object->error=$langs->trans("ErrorFailedToDeleteFile",$filepreviewnew); + $object->error=$langs->trans("ErrorFailedToDeleteFile", $filepreviewnew); return 0; } } if (file_exists($filepreviewnewbis) && is_writable($filepreviewnewbis)) { - if (! dol_delete_file($filepreviewnewbis,1)) + if (! dol_delete_file($filepreviewnewbis, 1)) { - $object->error=$langs->trans("ErrorFailedToDeleteFile",$filepreviewnewbis); + $object->error=$langs->trans("ErrorFailedToDeleteFile", $filepreviewnewbis); return 0; } } // For old preview files if (file_exists($filepreviewold) && is_writable($filepreviewold)) { - if (! dol_delete_file($filepreviewold,1)) + if (! dol_delete_file($filepreviewold, 1)) { - $object->error=$langs->trans("ErrorFailedToDeleteFile",$filepreviewold); + $object->error=$langs->trans("ErrorFailedToDeleteFile", $filepreviewold); return 0; } } @@ -1379,9 +1386,9 @@ function dol_delete_preview($object) if (file_exists($preview) && is_writable($preview)) { - if ( ! dol_delete_file($preview,1) ) + if ( ! dol_delete_file($preview, 1) ) { - $object->error=$langs->trans("ErrorFailedToOpenFile",$preview); + $object->error=$langs->trans("ErrorFailedToOpenFile", $preview); return 0; } } @@ -1435,7 +1442,7 @@ function dol_meta_create($object) $nblignes = count($object->lines); $client = $object->thirdparty->name . " " . $object->thirdparty->address . " " . $object->thirdparty->zip . " " . $object->thirdparty->town; $meta = "REFERENCE=\"" . $object->ref . "\" - DATE=\"" . dol_print_date($object->date,'') . "\" + DATE=\"" . dol_print_date($object->date, '') . "\" NB_ITEMS=\"" . $nblignes . "\" CLIENT=\"" . $client . "\" AMOUNT_EXCL_TAX=\"" . $object->total_ht . "\" @@ -1447,13 +1454,13 @@ function dol_meta_create($object) $meta .= "ITEM_" . $i . "_QUANTITY=\"" . $object->lines[$i]->qty . "\" ITEM_" . $i . "_AMOUNT_WO_TAX=\"" . $object->lines[$i]->total_ht . "\" ITEM_" . $i . "_VAT=\"" .$object->lines[$i]->tva_tx . "\" - ITEM_" . $i . "_DESCRIPTION=\"" . str_replace("\r\n","",nl2br($object->lines[$i]->desc)) . "\" + ITEM_" . $i . "_DESCRIPTION=\"" . str_replace("\r\n", "", nl2br($object->lines[$i]->desc)) . "\" "; } } - $fp = fopen($file,"w"); - fputs($fp,$meta); + $fp = fopen($file, "w"); + fputs($fp, $meta); fclose($fp); if (! empty($conf->global->MAIN_UMASK)) @chmod($file, octdec($conf->global->MAIN_UMASK)); @@ -1478,7 +1485,7 @@ function dol_meta_create($object) * @param string $trackid Track id (used to prefix name of session vars to avoid conflict) * @return void */ -function dol_init_file_process($pathtoscan='', $trackid='') +function dol_init_file_process($pathtoscan = '', $trackid = '') { $listofpaths=array(); $listofnames=array(); @@ -1486,7 +1493,7 @@ function dol_init_file_process($pathtoscan='', $trackid='') if ($pathtoscan) { - $listoffiles=dol_dir_list($pathtoscan,'files'); + $listoffiles=dol_dir_list($pathtoscan, 'files'); foreach($listoffiles as $key => $val) { $listofpaths[]=$val['fullname']; @@ -1495,9 +1502,9 @@ function dol_init_file_process($pathtoscan='', $trackid='') } } $keytoavoidconflict = empty($trackid)?'':'-'.$trackid; - $_SESSION["listofpaths".$keytoavoidconflict]=join(';',$listofpaths); - $_SESSION["listofnames".$keytoavoidconflict]=join(';',$listofnames); - $_SESSION["listofmimes".$keytoavoidconflict]=join(';',$listofmimes); + $_SESSION["listofpaths".$keytoavoidconflict]=join(';', $listofpaths); + $_SESSION["listofnames".$keytoavoidconflict]=join(';', $listofnames); + $_SESSION["listofmimes".$keytoavoidconflict]=join(';', $listofmimes); } @@ -1516,7 +1523,7 @@ function dol_init_file_process($pathtoscan='', $trackid='') * @param int $generatethumbs 1=Generate also thumbs for uploaded image files * @return int <=0 if KO, >0 if OK */ -function dol_add_file_process($upload_dir, $allowoverwrite=0, $donotupdatesession=0, $varfiles='addedfile', $savingdocmask='', $link=null, $trackid='', $generatethumbs=1) +function dol_add_file_process($upload_dir, $allowoverwrite = 0, $donotupdatesession = 0, $varfiles = 'addedfile', $savingdocmask = '', $link = null, $trackid = '', $generatethumbs = 1) { global $db,$user,$conf,$langs; @@ -1546,8 +1553,8 @@ function dol_add_file_process($upload_dir, $allowoverwrite=0, $donotupdatesessio if ($savingdocmask) { - $destfull=$upload_dir . "/" . preg_replace('/__file__/',$TFile['name'][$i],$savingdocmask); - $destfile=preg_replace('/__file__/',$TFile['name'][$i],$savingdocmask); + $destfull=$upload_dir . "/" . preg_replace('/__file__/', $TFile['name'][$i], $savingdocmask); + $destfile=preg_replace('/__file__/', $TFile['name'][$i], $savingdocmask); } // dol_sanitizeFileName the file name and lowercase extension @@ -1614,7 +1621,7 @@ function dol_add_file_process($upload_dir, $allowoverwrite=0, $donotupdatesessio { setEventMessages($langs->trans("ErrorFileNotUploaded"), null, 'errors'); } - else if (preg_match('/ErrorFileIsInfectedWithAVirus/',$resupload)) // Files infected by a virus + elseif (preg_match('/ErrorFileIsInfectedWithAVirus/', $resupload)) // Files infected by a virus { setEventMessages($langs->trans("ErrorFileIsInfectedWithAVirus"), null, 'errors'); } @@ -1666,7 +1673,7 @@ function dol_add_file_process($upload_dir, $allowoverwrite=0, $donotupdatesessio * @param string $trackid Track id (used to prefix name of session vars to avoid conflict) * @return void */ -function dol_remove_file_process($filenb,$donotupdatesession=0,$donotdeletefile=1,$trackid='') +function dol_remove_file_process($filenb, $donotupdatesession = 0, $donotdeletefile = 1, $trackid = '') { global $db,$user,$conf,$langs,$_FILES; @@ -1677,22 +1684,22 @@ function dol_remove_file_process($filenb,$donotupdatesession=0,$donotdeletefile= $listofnames=array(); $listofmimes=array(); $keytoavoidconflict = empty($trackid)?'':'-'.$trackid; - if (! empty($_SESSION["listofpaths".$keytoavoidconflict])) $listofpaths=explode(';',$_SESSION["listofpaths".$keytoavoidconflict]); - if (! empty($_SESSION["listofnames".$keytoavoidconflict])) $listofnames=explode(';',$_SESSION["listofnames".$keytoavoidconflict]); - if (! empty($_SESSION["listofmimes".$keytoavoidconflict])) $listofmimes=explode(';',$_SESSION["listofmimes".$keytoavoidconflict]); + if (! empty($_SESSION["listofpaths".$keytoavoidconflict])) $listofpaths=explode(';', $_SESSION["listofpaths".$keytoavoidconflict]); + if (! empty($_SESSION["listofnames".$keytoavoidconflict])) $listofnames=explode(';', $_SESSION["listofnames".$keytoavoidconflict]); + if (! empty($_SESSION["listofmimes".$keytoavoidconflict])) $listofmimes=explode(';', $_SESSION["listofmimes".$keytoavoidconflict]); if ($keytodelete >= 0) { $pathtodelete=$listofpaths[$keytodelete]; $filetodelete=$listofnames[$keytodelete]; - if (empty($donotdeletefile)) $result = dol_delete_file($pathtodelete,1); // The delete of ecm database is inside the function dol_delete_file + if (empty($donotdeletefile)) $result = dol_delete_file($pathtodelete, 1); // The delete of ecm database is inside the function dol_delete_file else $result=0; if ($result >= 0) { if (empty($donotdeletefile)) { $langs->load("other"); - setEventMessages($langs->trans("FileWasRemoved",$filetodelete), null, 'mesgs'); + setEventMessages($langs->trans("FileWasRemoved", $filetodelete), null, 'mesgs'); } if (empty($donotupdatesession)) { @@ -1718,13 +1725,13 @@ function dol_remove_file_process($filenb,$donotupdatesession=0,$donotdeletefile= * @param int $setsharekey Set also the share key * @return int <0 if KO, 0 if nothing done, >0 if OK */ -function addFileIntoDatabaseIndex($dir, $file, $fullpathorig='', $mode='uploaded', $setsharekey=0) +function addFileIntoDatabaseIndex($dir, $file, $fullpathorig = '', $mode = 'uploaded', $setsharekey = 0) { global $db, $user; $result = 0; - $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $dir); + $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir); if (! preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir)) // If not a tmp dir { @@ -1766,7 +1773,7 @@ function addFileIntoDatabaseIndex($dir, $file, $fullpathorig='', $mode='uploaded * @param string $mode How file was created ('uploaded', 'generated', ...) * @return int <0 if KO, 0 if nothing done, >0 if OK */ -function deleteFilesIntoDatabaseIndex($dir, $file, $mode='uploaded') +function deleteFilesIntoDatabaseIndex($dir, $file, $mode = 'uploaded') { global $conf, $db, $user; @@ -1780,7 +1787,7 @@ function deleteFilesIntoDatabaseIndex($dir, $file, $mode='uploaded') $db->begin(); - $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $dir); + $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir); $filename = basename($file); $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir); @@ -1820,38 +1827,36 @@ function deleteFilesIntoDatabaseIndex($dir, $file, $mode='uploaded') * @param string $fileinput Input file name * @param string $ext Format of target file (It is also extension added to file if fileoutput is not provided). * @param string $fileoutput Output filename + * @param string $page Page number if we convert a PDF into png * @return int <0 if KO, 0=Nothing done, >0 if OK */ -function dol_convert_file($fileinput, $ext='png', $fileoutput='') +function dol_convert_file($fileinput, $ext = 'png', $fileoutput = '', $page = '') { global $langs; - if (class_exists('Imagick')) { - $image=new Imagick(); + $image=new Imagick(); try { - $ret = $image->readImage($fileinput); + $filetoconvert=$fileinput.(($page != '')?'['.$page.']':''); + //var_dump($filetoconvert); + $ret = $image->readImage($filetoconvert); } catch(Exception $e) { - dol_syslog("Failed to read image using Imagick. Try to install package 'apt-get install ghostscript'.", LOG_WARNING); + $ext = pathinfo($fileinput, PATHINFO_EXTENSION); + dol_syslog("Failed to read image using Imagick (Try to install package 'apt-get install php-imagick ghostscript' and check there is no policy to disable ".$ext." convertion in /etc/ImageMagick*/policy.xml): ".$e->getMessage(), LOG_WARNING); return 0; } if ($ret) { - $ret = $image->setImageFormat($ext); + $ret = $image->setImageFormat($ext); if ($ret) { if (empty($fileoutput)) $fileoutput=$fileinput.".".$ext; $count = $image->getNumberImages(); + if (! dol_is_file($fileoutput) || is_writeable($fileoutput)) { - try { - $ret = $image->writeImages($fileoutput, true); - } - catch(Exception $e) - { - dol_syslog($e->getMessage(), LOG_WARNING); - } + $ret = $image->writeImages($fileoutput, true); } else { @@ -1885,26 +1890,89 @@ function dol_convert_file($fileinput, $ext='png', $fileoutput='') * @param string $mode 'gz' or 'bz' or 'zip' * @return int <0 if KO, >0 if OK */ -function dol_compress_file($inputfile, $outputfile, $mode="gz") +function dol_compress_file($inputfile, $outputfile, $mode = "gz") { + global $conf; + $foundhandler=0; try { + dol_syslog("dol_compress_file mode=".$mode." inputfile=".$inputfile." outputfile=".$outputfile); + $data = implode("", file(dol_osencode($inputfile))); if ($mode == 'gz') { $foundhandler=1; $compressdata = gzencode($data, 9); } elseif ($mode == 'bz') { $foundhandler=1; $compressdata = bzcompress($data, 9); } elseif ($mode == 'zip') { + if (class_exists('ZipArchive') && ! empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS)) + { + $foundhandler=1; + + $rootPath = realpath($inputfile); + + dol_syslog("Class ZipArchive is set so we zip using ZipArchive to zip into ".$outputfile.' rootPath='.$rootPath); + $zip = new ZipArchive; + + if ($zip->open($outputfile, ZipArchive::CREATE) !== true) { + $errormsg="Failed to open file ".$outputfile."\n"; + dol_syslog("dol_compress_file failure - ".$errormsg, LOG_ERR); + return -6; + } + + // Create recursive directory iterator + /** @var SplFileInfo[] $files */ + $files = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($rootPath), + RecursiveIteratorIterator::LEAVES_ONLY + ); + + foreach ($files as $name => $file) + { + // Skip directories (they would be added automatically) + if (!$file->isDir()) + { + // Get real and relative path for current file + $filePath = $file->getRealPath(); + $relativePath = substr($filePath, strlen($rootPath) + 1); + + // Add current file to archive + $zip->addFile($filePath, $relativePath); + } + } + + // Zip archive will be created only after closing object + $zip->close(); + + dol_syslog("dol_compress_file success - ".count($zip->numFiles)." files"); + return 1; + } + if (defined('ODTPHP_PATHTOPCLZIP')) { $foundhandler=1; include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php'; $archive = new PclZip($outputfile); - $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile)); - //$archive->add($inputfile); - return 1; + $result = $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile)); + + if ($result === 0) + { + global $errormsg; + $errormsg=$archive->errorInfo(true); + dol_syslog("dol_compress_file failure - ".$errormsg, LOG_ERR); + if ($archive->errorCode() == PCLZIP_ERR_WRITE_OPEN_FAIL) + { + dol_syslog("dol_compress_file error PCLZIP_ERR_WRITE_OPEN_FAIL", LOG_ERR); + return -4; + } + return -3; + } + else + { + dol_syslog("dol_compress_file success - ".count($result)." files"); + return 1; + } } } @@ -1917,7 +1985,7 @@ function dol_compress_file($inputfile, $outputfile, $mode="gz") } else { - dol_syslog("Try to zip with format ".$mode." with no handler for this format",LOG_ERR); + dol_syslog("Try to zip with format ".$mode." with no handler for this format", LOG_ERR); return -2; } } @@ -1925,7 +1993,7 @@ function dol_compress_file($inputfile, $outputfile, $mode="gz") { global $langs, $errormsg; $langs->load("errors"); - dol_syslog("Failed to open file ".$outputfile,LOG_ERR); + dol_syslog("Failed to open file ".$outputfile, LOG_ERR); $errormsg=$langs->trans("ErrorFailedToWriteInDir"); return -1; } @@ -1938,11 +2006,11 @@ function dol_compress_file($inputfile, $outputfile, $mode="gz") * @param string $outputdir Target dir name * @return array array('error'=>'Error code') or array() if no error */ -function dol_uncompress($inputfile,$outputdir) +function dol_uncompress($inputfile, $outputdir) { - global $langs; + global $conf, $langs; - if (defined('ODTPHP_PATHTOPCLZIP')) + if (defined('ODTPHP_PATHTOPCLZIP') && empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_UNCOMPRESS)) { dol_syslog("Constant ODTPHP_PATHTOPCLZIP for pclzip library is set to ".ODTPHP_PATHTOPCLZIP.", so we use Pclzip to unzip into ".$outputdir); include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php'; @@ -1997,9 +2065,10 @@ function dol_uncompress($inputfile,$outputdir) * @param string $inputdir Source dir name * @param string $outputfile Target file name (output directory must exists and be writable) * @param string $mode 'zip' + * @param string $excludefiles A regex pattern. For example: '/\.log$|\/temp\//' * @return int <0 if KO, >0 if OK */ -function dol_compress_dir($inputdir, $outputfile, $mode="zip") +function dol_compress_dir($inputdir, $outputfile, $mode = "zip", $excludefiles = '') { $foundhandler=0; @@ -2009,7 +2078,7 @@ function dol_compress_dir($inputdir, $outputfile, $mode="zip") { global $langs, $errormsg; $langs->load("errors"); - $errormsg=$langs->trans("ErrorFailedToWriteInDir",$outputfile); + $errormsg=$langs->trans("ErrorFailedToWriteInDir", $outputfile); return -3; } @@ -2030,6 +2099,7 @@ function dol_compress_dir($inputdir, $outputfile, $mode="zip") return 1; } else*/ + //if (class_exists('ZipArchive') && ! empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS)) if (class_exists('ZipArchive')) { $foundhandler=1; @@ -2037,6 +2107,13 @@ function dol_compress_dir($inputdir, $outputfile, $mode="zip") // Initialize archive object $zip = new ZipArchive(); $result = $zip->open($outputfile, ZipArchive::CREATE | ZipArchive::OVERWRITE); + if (! $result) + { + global $langs, $errormsg; + $langs->load("errors"); + $errormsg=$langs->trans("ErrorFailedToWriteInFile", $outputfile); + return -4; + } // Create recursive directory iterator /** @var SplFileInfo[] $files */ @@ -2053,9 +2130,11 @@ function dol_compress_dir($inputdir, $outputfile, $mode="zip") // Get real and relative path for current file $filePath = $file->getRealPath(); $relativePath = substr($filePath, strlen($inputdir) + 1); - - // Add current file to archive - $zip->addFile($filePath, $relativePath); + if (empty($excludefiles) || ! preg_match($excludefiles, $filePath)) + { + // Add current file to archive + $zip->addFile($filePath, $relativePath); + } } } @@ -2068,7 +2147,7 @@ function dol_compress_dir($inputdir, $outputfile, $mode="zip") if (! $foundhandler) { - dol_syslog("Try to zip with format ".$mode." with no handler for this format",LOG_ERR); + dol_syslog("Try to zip with format ".$mode." with no handler for this format", LOG_ERR); return -2; } else @@ -2082,7 +2161,7 @@ function dol_compress_dir($inputdir, $outputfile, $mode="zip") $langs->load("errors"); dol_syslog("Failed to open file ".$outputfile, LOG_ERR); dol_syslog($e->getMessage(), LOG_ERR); - $errormsg=$langs->trans("ErrorFailedToWriteInDir",$outputfile); + $errormsg=$langs->trans("ErrorFailedToWriteInDir", $outputfile); return -1; } } @@ -2099,9 +2178,9 @@ function dol_compress_dir($inputdir, $outputfile, $mode="zip") * @param int $mode 0=Return array minimum keys loaded (faster), 1=Force all keys like date and size to be loaded (slower), 2=Force load of date only, 3=Force load of size only * @return string Full path to most recent file */ -function dol_most_recent_file($dir,$regexfilter='',$excludefilter=array('(\.meta|_preview.*\.png)$','^\.'),$nohook=false,$mode='') +function dol_most_recent_file($dir, $regexfilter = '', $excludefilter = array('(\.meta|_preview.*\.png)$','^\.'), $nohook = false, $mode = '') { - $tmparray=dol_dir_list($dir,'files',0,$regexfilter,$excludefilter,'date',SORT_DESC,$mode,$nohook); + $tmparray=dol_dir_list($dir, 'files', 0, $regexfilter, $excludefilter, 'date', SORT_DESC, $mode, $nohook); return $tmparray[0]; } @@ -2115,9 +2194,9 @@ function dol_most_recent_file($dir,$regexfilter='',$excludefilter=array('(\.meta * @param string $refname Ref of object to check permission for external users (autodetect if not provided) * @param string $mode Check permission for 'read' or 'write' * @return mixed Array with access information : 'accessallowed' & 'sqlprotectagainstexternals' & 'original_file' (as a full path name) - * @see restrictedArea + * @see restrictedArea() */ -function dol_check_secure_access_document($modulepart, $original_file, $entity, $fuser='', $refname='', $mode='read') +function dol_check_secure_access_document($modulepart, $original_file, $entity, $fuser = '', $refname = '', $mode = 'read') { global $conf, $db, $user; global $dolibarr_main_data_root, $dolibarr_main_document_root_alt; @@ -2134,6 +2213,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, if ($modulepart == 'users') $modulepart='user'; dol_syslog('modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity); + // We define $accessallowed and $sqlprotectagainstexternals $accessallowed=0; $sqlprotectagainstexternals=''; @@ -2142,8 +2222,6 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, // Find the subdirectory name as the reference. For exemple original_file='10/myfile.pdf' -> refname='10' if (empty($refname)) $refname=basename(dirname($original_file)."/"); - $relative_original_file = $original_file; - // Define possible keys to use for permission check $lire='lire'; $read='read'; $download='download'; if ($mode == 'write') @@ -2293,7 +2371,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, $original_file=$conf->adherent->dir_temp.'/'.$original_file; } // Wrapping pour les images des stats produits - elseif (preg_match('/^productstats_/i',$modulepart) && !empty($conf->product->dir_temp)) + elseif (preg_match('/^productstats_/i', $modulepart) && !empty($conf->product->dir_temp)) { if ($fuser->rights->produit->{$lire} || $fuser->rights->service->{$lire}) $accessallowed=1; $original_file=(!empty($conf->product->multidir_temp[$entity])?$conf->product->multidir_temp[$entity]:$conf->service->multidir_temp[$entity]).'/'.$original_file; @@ -2320,7 +2398,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, // Wrapping pour les prelevements elseif ($modulepart == 'prelevement' && !empty($conf->prelevement->dir_output)) { - if ($fuser->rights->prelevement->bons->{$lire} || preg_match('/^specimen/i',$original_file)) $accessallowed=1; + if ($fuser->rights->prelevement->bons->{$lire} || preg_match('/^specimen/i', $original_file)) $accessallowed=1; $original_file=$conf->prelevement->dir_output.'/'.$original_file; } // Wrapping pour les graph energie @@ -2369,11 +2447,11 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for users - else if ($modulepart == 'user' && !empty($conf->user->dir_output)) + elseif ($modulepart == 'user' && !empty($conf->user->dir_output)) { $canreaduser=(! empty($fuser->admin) || $fuser->rights->user->user->{$lire}); if ($fuser->id == (int) $refname) { $canreaduser=1; } // A user can always read its own card - if ($canreaduser || preg_match('/^specimen/i',$original_file)) + if ($canreaduser || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2381,10 +2459,10 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for third parties - else if (($modulepart == 'company' || $modulepart == 'societe') && !empty($conf->societe->dir_output)) + elseif (($modulepart == 'company' || $modulepart == 'societe' || $modulepart == 'thirdparty') && !empty($conf->societe->dir_output)) { if (empty($entity) || empty($conf->societe->multidir_output[$entity])) return array('accessallowed'=>0, 'error'=>'Value entity must be provided'); - if ($fuser->rights->societe->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->societe->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2393,7 +2471,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for contact - else if ($modulepart == 'contact' && !empty($conf->societe->dir_output)) + elseif ($modulepart == 'contact' && !empty($conf->societe->dir_output)) { if (empty($entity) || empty($conf->societe->multidir_output[$entity])) return array('accessallowed'=>0, 'error'=>'Value entity must be provided'); if ($fuser->rights->societe->{$lire}) @@ -2404,9 +2482,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for invoices - else if (($modulepart == 'facture' || $modulepart == 'invoice') && !empty($conf->facture->dir_output)) + elseif (($modulepart == 'facture' || $modulepart == 'invoice') && !empty($conf->facture->dir_output)) { - if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2414,73 +2492,73 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity; } // Wrapping for mass actions - else if ($modulepart == 'massfilesarea_proposals' && !empty($conf->propal->multidir_output[$entity])) + elseif ($modulepart == 'massfilesarea_proposals' && !empty($conf->propal->multidir_output[$entity])) { - if ($fuser->rights->propal->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->propal->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->propal->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file; } - else if ($modulepart == 'massfilesarea_orders') + elseif ($modulepart == 'massfilesarea_orders') { - if ($fuser->rights->commande->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->commande->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->commande->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } - else if ($modulepart == 'massfilesarea_invoices') + elseif ($modulepart == 'massfilesarea_invoices') { - if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->facture->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } - else if ($modulepart == 'massfilesarea_expensereport') + elseif ($modulepart == 'massfilesarea_expensereport') { - if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->expensereport->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } - else if ($modulepart == 'massfilesarea_interventions') + elseif ($modulepart == 'massfilesarea_interventions') { - if ($fuser->rights->ficheinter->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->ficheinter->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->ficheinter->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } - else if ($modulepart == 'massfilesarea_supplier_proposal' && !empty($conf->supplier_proposal->dir_output)) + elseif ($modulepart == 'massfilesarea_supplier_proposal' && !empty($conf->supplier_proposal->dir_output)) { - if ($fuser->rights->supplier_proposal->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->supplier_proposal->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->supplier_proposal->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } - else if ($modulepart == 'massfilesarea_supplier_order') + elseif ($modulepart == 'massfilesarea_supplier_order') { - if ($fuser->rights->fournisseur->commande->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->fournisseur->commande->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->fournisseur->commande->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } - else if ($modulepart == 'massfilesarea_supplier_invoice') + elseif ($modulepart == 'massfilesarea_supplier_invoice') { - if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->fournisseur->facture->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } - else if ($modulepart == 'massfilesarea_contract' && !empty($conf->contrat->dir_output)) + elseif ($modulepart == 'massfilesarea_contract' && !empty($conf->contrat->dir_output)) { - if ($fuser->rights->contrat->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->contrat->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2488,9 +2566,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for interventions - else if (($modulepart == 'fichinter' || $modulepart == 'ficheinter') && !empty($conf->ficheinter->dir_output)) + elseif (($modulepart == 'fichinter' || $modulepart == 'ficheinter') && !empty($conf->ficheinter->dir_output)) { - if ($fuser->rights->ficheinter->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->ficheinter->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2499,9 +2577,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les deplacements et notes de frais - else if ($modulepart == 'deplacement' && !empty($conf->deplacement->dir_output)) + elseif ($modulepart == 'deplacement' && !empty($conf->deplacement->dir_output)) { - if ($fuser->rights->deplacement->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->deplacement->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2509,9 +2587,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, //$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity; } // Wrapping pour les propales - else if (($modulepart == 'propal' || $modulepart == 'propale') && !empty($conf->propal->multidir_output[$entity])) + elseif (($modulepart == 'propal' || $modulepart == 'propale') && !empty($conf->propal->multidir_output[$entity])) { - if ($fuser->rights->propale->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->propale->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2520,9 +2598,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les commandes - else if (($modulepart == 'commande' || $modulepart == 'order') && !empty($conf->commande->dir_output)) + elseif (($modulepart == 'commande' || $modulepart == 'order') && !empty($conf->commande->dir_output)) { - if ($fuser->rights->commande->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->commande->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2531,18 +2609,18 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les projets - else if ($modulepart == 'project' && !empty($conf->projet->dir_output)) + elseif ($modulepart == 'project' && !empty($conf->projet->dir_output)) { - if ($fuser->rights->projet->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->projet->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->projet->dir_output.'/'.$original_file; $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")"; } - else if ($modulepart == 'project_task' && !empty($conf->projet->dir_output)) + elseif ($modulepart == 'project_task' && !empty($conf->projet->dir_output)) { - if ($fuser->rights->projet->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->projet->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2551,9 +2629,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les commandes fournisseurs - else if (($modulepart == 'commande_fournisseur' || $modulepart == 'order_supplier') && !empty($conf->fournisseur->commande->dir_output)) + elseif (($modulepart == 'commande_fournisseur' || $modulepart == 'order_supplier') && !empty($conf->fournisseur->commande->dir_output)) { - if ($fuser->rights->fournisseur->commande->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->fournisseur->commande->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2562,19 +2640,19 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les factures fournisseurs - else if (($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') && !empty($conf->fournisseur->facture->dir_output)) + elseif (($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') && !empty($conf->fournisseur->facture->dir_output)) { - if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->fournisseur->facture->dir_output.'/'.$original_file; - $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture_fourn WHERE facnumber='".$db->escape($refname)."' AND entity=".$conf->entity; + $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture_fourn WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity; } // Wrapping pour les rapport de paiements - else if ($modulepart == 'supplier_payment') + elseif ($modulepart == 'supplier_payment') { - if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2583,9 +2661,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les rapport de paiements - else if ($modulepart == 'facture_paiement' && !empty($conf->facture->dir_output)) + elseif ($modulepart == 'facture_paiement' && !empty($conf->facture->dir_output)) { - if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2594,9 +2672,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for accounting exports - else if ($modulepart == 'export_compta' && !empty($conf->accounting->dir_output)) + elseif ($modulepart == 'export_compta' && !empty($conf->accounting->dir_output)) { - if ($fuser->rights->accounting->bind->write || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->accounting->bind->write || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2604,18 +2682,18 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les expedition - else if ($modulepart == 'expedition' && !empty($conf->expedition->dir_output)) + elseif ($modulepart == 'expedition' && !empty($conf->expedition->dir_output)) { - if ($fuser->rights->expedition->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->expedition->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->expedition->dir_output."/sending/".$original_file; } // Wrapping pour les bons de livraison - else if ($modulepart == 'livraison' && !empty($conf->expedition->dir_output)) + elseif ($modulepart == 'livraison' && !empty($conf->expedition->dir_output)) { - if ($fuser->rights->expedition->livraison->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->expedition->livraison->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2623,9 +2701,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les actions - else if ($modulepart == 'actions' && !empty($conf->agenda->dir_output)) + elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output)) { - if ($fuser->rights->agenda->myactions->{$read} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->agenda->myactions->{$read} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2633,9 +2711,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les actions - else if ($modulepart == 'actionsreport' && !empty($conf->agenda->dir_temp)) + elseif ($modulepart == 'actionsreport' && !empty($conf->agenda->dir_temp)) { - if ($fuser->rights->agenda->allactions->{$read} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->agenda->allactions->{$read} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2643,10 +2721,10 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les produits et services - else if ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') + elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') { if (empty($entity) || (empty($conf->product->multidir_output[$entity]) && empty($conf->service->multidir_output[$entity]))) return array('accessallowed'=>0, 'error'=>'Value entity must be provided'); - if (($fuser->rights->produit->{$lire} || $fuser->rights->service->{$lire}) || preg_match('/^specimen/i',$original_file)) + if (($fuser->rights->produit->{$lire} || $fuser->rights->service->{$lire}) || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2655,20 +2733,31 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les lots produits - else if ($modulepart == 'product_batch' || $modulepart == 'produitlot') + elseif ($modulepart == 'product_batch' || $modulepart == 'produitlot') { if (empty($entity) || (empty($conf->productbatch->multidir_output[$entity]))) return array('accessallowed'=>0, 'error'=>'Value entity must be provided'); - if (($fuser->rights->produit->{$lire} ) || preg_match('/^specimen/i',$original_file)) + if (($fuser->rights->produit->{$lire} ) || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } if (! empty($conf->productbatch->enabled)) $original_file=$conf->productbatch->multidir_output[$entity].'/'.$original_file; } - // Wrapping pour les contrats - else if ($modulepart == 'contract' && !empty($conf->contrat->dir_output)) + // Wrapping for stock movements + elseif ($modulepart == 'movement' || $modulepart == 'mouvement') { - if ($fuser->rights->contrat->{$lire} || preg_match('/^specimen/i',$original_file)) + if (empty($entity) || empty($conf->stock->multidir_output[$entity])) return array('accessallowed'=>0, 'error'=>'Value entity must be provided'); + if (($fuser->rights->stock->{$lire} || $fuser->rights->stock->movement->{$lire} || $fuser->rights->stock->mouvement->{$lire}) || preg_match('/^specimen/i', $original_file)) + { + $accessallowed=1; + } + if (! empty($conf->stock->enabled)) $original_file=$conf->stock->multidir_output[$entity].'/movement/'.$original_file; + } + + // Wrapping pour les contrats + elseif ($modulepart == 'contract' && !empty($conf->contrat->dir_output)) + { + if ($fuser->rights->contrat->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2677,9 +2766,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les dons - else if ($modulepart == 'donation' && !empty($conf->don->dir_output)) + elseif ($modulepart == 'donation' && !empty($conf->don->dir_output)) { - if ($fuser->rights->don->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->don->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2687,9 +2776,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les dons - else if ($modulepart == 'dolresource' && !empty($conf->resource->dir_output)) + elseif ($modulepart == 'dolresource' && !empty($conf->resource->dir_output)) { - if ($fuser->rights->resource->{$read} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->resource->{$read} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2697,9 +2786,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les remises de cheques - else if ($modulepart == 'remisecheque' && !empty($conf->banque->dir_output)) + elseif ($modulepart == 'remisecheque' && !empty($conf->bank->dir_output)) { - if ($fuser->rights->banque->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->banque->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2708,7 +2797,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for bank - else if ($modulepart == 'bank' && !empty($conf->bank->dir_output)) + elseif (($modulepart == 'banque' || $modulepart == 'bank') && !empty($conf->bank->dir_output)) { if ($fuser->rights->banque->{$lire}) { @@ -2718,7 +2807,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for export module - else if ($modulepart == 'export' && !empty($conf->export->dir_temp)) + elseif ($modulepart == 'export' && !empty($conf->export->dir_temp)) { // Aucun test necessaire car on force le rep de download sur // le rep export qui est propre a l'utilisateur @@ -2727,35 +2816,35 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for import module - else if ($modulepart == 'import' && !empty($conf->import->dir_temp)) + elseif ($modulepart == 'import' && !empty($conf->import->dir_temp)) { $accessallowed=1; $original_file=$conf->import->dir_temp.'/'.$original_file; } // Wrapping pour l'editeur wysiwyg - else if ($modulepart == 'editor' && !empty($conf->fckeditor->dir_output)) + elseif ($modulepart == 'editor' && !empty($conf->fckeditor->dir_output)) { $accessallowed=1; $original_file=$conf->fckeditor->dir_output.'/'.$original_file; } // Wrapping for backups - else if ($modulepart == 'systemtools' && !empty($conf->admin->dir_output)) + elseif ($modulepart == 'systemtools' && !empty($conf->admin->dir_output)) { if ($fuser->admin) $accessallowed=1; $original_file=$conf->admin->dir_output.'/'.$original_file; } // Wrapping for upload file test - else if ($modulepart == 'admin_temp' && !empty($conf->admin->dir_temp)) + elseif ($modulepart == 'admin_temp' && !empty($conf->admin->dir_temp)) { if ($fuser->admin) $accessallowed=1; $original_file=$conf->admin->dir_temp.'/'.$original_file; } // Wrapping pour BitTorrent - else if ($modulepart == 'bittorrent' && !empty($conf->bittorrent->dir_output)) + elseif ($modulepart == 'bittorrent' && !empty($conf->bittorrent->dir_output)) { $accessallowed=1; $dir='files'; @@ -2764,9 +2853,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour Foundation module - else if ($modulepart == 'member' && !empty($conf->adherent->dir_output)) + elseif ($modulepart == 'member' && !empty($conf->adherent->dir_output)) { - if ($fuser->rights->adherent->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->adherent->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2774,7 +2863,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for Scanner - else if ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp)) + elseif ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp)) { $accessallowed=1; $original_file=$conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file; @@ -2787,45 +2876,58 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, // If modulepart=module Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart else { - if (preg_match('/^specimen/i',$original_file)) $accessallowed=1; // If link to a file called specimen. Test must be done before changing $original_file int full path. + if (preg_match('/^specimen/i', $original_file)) $accessallowed=1; // If link to a file called specimen. Test must be done before changing $original_file int full path. if ($fuser->admin) $accessallowed=1; // If user is admin // Define $accessallowed - if (preg_match('/^([a-z]+)_user_temp$/i',$modulepart,$reg)) + if (preg_match('/^([a-z]+)_user_temp$/i', $modulepart, $reg)) { if (empty($conf->{$reg[1]}->dir_temp)) // modulepart not supported { - dol_print_error('','Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); + dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); exit; } if ($fuser->rights->{$reg[1]}->{$lire} || $fuser->rights->{$reg[1]}->{$read} || ($fuser->rights->{$reg[1]}->{$download})) $accessallowed=1; $original_file=$conf->{$reg[1]}->dir_temp.'/'.$fuser->id.'/'.$original_file; } - else if (preg_match('/^([a-z]+)_temp$/i',$modulepart,$reg)) + elseif (preg_match('/^([a-z]+)_temp$/i', $modulepart, $reg)) { if (empty($conf->{$reg[1]}->dir_temp)) // modulepart not supported { - dol_print_error('','Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); + dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); exit; } if ($fuser->rights->{$reg[1]}->{$lire} || $fuser->rights->{$reg[1]}->{$read} || ($fuser->rights->{$reg[1]}->{$download})) $accessallowed=1; $original_file=$conf->{$reg[1]}->dir_temp.'/'.$original_file; } - else if (preg_match('/^([a-z]+)_user$/i',$modulepart,$reg)) + elseif (preg_match('/^([a-z]+)_user$/i', $modulepart, $reg)) { if (empty($conf->{$reg[1]}->dir_output)) // modulepart not supported { - dol_print_error('','Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); + dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); exit; } if ($fuser->rights->{$reg[1]}->{$lire} || $fuser->rights->{$reg[1]}->{$read} || ($fuser->rights->{$reg[1]}->{$download})) $accessallowed=1; $original_file=$conf->{$reg[1]}->dir_output.'/'.$fuser->id.'/'.$original_file; } + elseif (preg_match('/^massfilesarea_([a-z]+)$/i', $modulepart, $reg)) + { + if (empty($conf->{$reg[1]}->dir_output)) // modulepart not supported + { + dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); + exit; + } + if ($fuser->rights->{$reg[1]}->{$lire} || preg_match('/^specimen/i', $original_file)) + { + $accessallowed=1; + } + $original_file=$conf->{$reg[1]}->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; + } else { if (empty($conf->$modulepart->dir_output)) // modulepart not supported { - dol_print_error('','Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); + dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); exit; } @@ -2971,4 +3073,3 @@ function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '', $pathre return $file_list; } - From 5948d385a36b149cc3555d6c9a235dd4819c5a98 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 30 Apr 2020 14:46:49 +0200 Subject: [PATCH 034/120] Look and feel v12 --- htdocs/core/lib/functions.lib.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 94a32ceacaf..3bf1be1d772 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -3145,13 +3145,14 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ 'cash-register', 'check', 'close_title', 'company', 'contact', 'contract', 'cubes', 'delete', 'dolly', 'dollyrevert', 'edit', 'ellipsis-h', 'external-link-alt', 'external-link-square-alt', 'filter', 'file-code', 'file-export', 'file-import', 'file-upload', 'folder', 'folder-open', 'globe', 'globe-americas', 'grip', 'grip_title', 'help', - 'intervention', 'language', 'list', 'listlight', 'lot', + 'intervention', 'label', 'language', 'list', 'listlight', 'lot', 'map-marker-alt', 'money-bill-alt', 'mrp', 'note', 'object_accounting', 'object_action', 'object_account', 'object_barcode', 'object_bill', 'object_billa', 'object_billd', 'object_bom', 'object_category', 'object_bookmark', 'object_bug', 'object_dolly', 'object_dollyrevert', 'object_generic', 'object_folder', 'object_list-alt', 'object_calendar', 'object_calendarweek', 'object_calendarmonth', 'object_calendarday', 'object_calendarperuser', 'object_cash-register', 'object_company', 'object_contact', 'object_contract', 'object_donation', 'object_dynamicprice', - 'object_holiday', 'object_hrm', 'object_intervention', 'object_margin', 'object_money-bill-alt', 'object_multicurrency', 'object_order', 'object_payment', + 'object_holiday', 'object_hrm', 'object_intervention', 'object_label', + 'object_margin', 'object_money-bill-alt', 'object_multicurrency', 'object_order', 'object_payment', 'object_lot', 'object_mrp', 'object_payment', 'object_product', 'object_propal', 'object_other', 'object_paragraph', 'object_poll', 'object_printer', 'object_project', 'object_projectpub', 'object_propal', 'object_resource', 'object_rss', 'object_projecttask', 'object_supplier_invoice', 'object_supplier_order', 'object_supplier_proposal', 'object_service', 'object_stock', @@ -3188,7 +3189,8 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ 'hrm'=>'umbrella-beach', 'margin'=>'calculator', 'members'=>'users', 'ticket'=>'ticket-alt', 'globe'=>'external-link-alt', 'lot'=>'barcode', 'email'=>'at', 'edit'=>'pencil-alt', 'grip_title'=>'arrows-alt', 'grip'=>'arrows-alt', 'help'=>'info-circle', - 'generic'=>'file', 'holiday'=>'umbrella-beach', 'member'=>'users', 'mrp'=>'cubes', 'trip'=>'wallet', 'group'=>'users', + 'generic'=>'file', 'holiday'=>'umbrella-beach', 'label'=>'layer-group', + 'member'=>'users', 'mrp'=>'cubes', 'trip'=>'wallet', 'group'=>'users', 'sign-out'=>'sign-out-alt', 'switch_off'=>'toggle-off', 'switch_on'=>'toggle-on', 'check'=>'check', 'bookmark'=>'star', 'bookmark'=>'star', 'bank'=>'university', 'close_title'=>'window-close', 'delete'=>'trash', 'edit'=>'pencil-alt', 'filter'=>'filter', From 14a3aa2165ad75986d4960b3ab881bdbd12e26a6 Mon Sep 17 00:00:00 2001 From: Maxime Lecoq Date: Thu, 30 Apr 2020 18:21:25 +0200 Subject: [PATCH 035/120] FIX: add auto incrementation to llx_c_typent.sql --- htdocs/install/mysql/tables/llx_c_typent.sql | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/htdocs/install/mysql/tables/llx_c_typent.sql b/htdocs/install/mysql/tables/llx_c_typent.sql index 0b15e70b15b..130e9d8784f 100644 --- a/htdocs/install/mysql/tables/llx_c_typent.sql +++ b/htdocs/install/mysql/tables/llx_c_typent.sql @@ -19,11 +19,11 @@ create table llx_c_typent ( - id integer PRIMARY KEY, - code varchar(12) NOT NULL, - libelle varchar(64), - fk_country integer NULL, -- Defined only to have specific list for countries that can't use generic list (like argentina that need type A or B) - active tinyint DEFAULT 1 NOT NULL, - module varchar(32) NULL, - position integer NOT NULL DEFAULT 0 + id integer AUTO_INCREMENT PRIMARY KEY, + code varchar(12) NOT NULL, + libelle varchar(64), + fk_country integer NULL, -- Defined only to have specific list for countries that can't use generic list (like argentina that need type A or B) + active tinyint DEFAULT 1 NOT NULL, + module varchar(32) NULL, + position integer NOT NULL DEFAULT 0 )ENGINE=innodb; From b1495e12ce4cec42eaca686bc30f12b5be70a869 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 30 Apr 2020 18:45:00 +0200 Subject: [PATCH 036/120] FIX A variable was erased by a temporary variable --- htdocs/compta/facture/card.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index 934916fa31e..9fa696c69b3 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -4202,7 +4202,7 @@ elseif ($id > 0 || ! empty($ref)) $current_situation_counter = array(); foreach ($object->tab_previous_situation_invoice as $prev_invoice) { - $totalpaye = $prev_invoice->getSommePaiement(); + $tmptotalpaidforthisinvoice = $prev_invoice->getSommePaiement(); $total_prev_ht += $prev_invoice->total_ht; $total_prev_ttc += $prev_invoice->total_ttc; $current_situation_counter[] = (($prev_invoice->type == Facture::TYPE_CREDIT_NOTE)?-1:1) * $prev_invoice->situation_counter; @@ -4213,7 +4213,7 @@ elseif ($id > 0 || ! empty($ref)) if (! empty($conf->banque->enabled)) print ''; print '' . price($prev_invoice->total_ht) . ''; print '' . price($prev_invoice->total_ttc) . ''; - print '' . $prev_invoice->getLibStatut(3, $totalpaye) . ''; + print '' . $prev_invoice->getLibStatut(3, $tmptotalpaidforthisinvoice) . ''; print ''; } } From e4edd143c5945c4581a11d1acbb03198af3400da Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 30 Apr 2020 19:41:46 +0200 Subject: [PATCH 037/120] Fix field name --- htdocs/accountancy/expensereport/list.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/htdocs/accountancy/expensereport/list.php b/htdocs/accountancy/expensereport/list.php index e03c717039f..148a1d8fe1f 100644 --- a/htdocs/accountancy/expensereport/list.php +++ b/htdocs/accountancy/expensereport/list.php @@ -42,6 +42,9 @@ $massaction = GETPOST('massaction', 'alpha'); $show_files = GETPOST('show_files', 'int'); $confirm = GETPOST('confirm', 'alpha'); $toselect = GETPOST('toselect', 'array'); +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'myobjectlist'; // To manage different context of search +$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') + // Select Box $mesCasesCochees = GETPOST('toselect', 'array'); @@ -240,8 +243,8 @@ if ($result) { $arrayofselected = is_array($toselect) ? $toselect : array(); $param = ''; - if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.$contextpage; - if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.$limit; + if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage); + if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit); if ($search_lineid) $param .= '&search_lineid='.urlencode($search_lineid); if ($search_day) $param .= '&search_day='.urlencode($search_day); if ($search_month) $param .= '&search_month='.urlencode($search_month); @@ -308,7 +311,7 @@ if ($result) { print ''; print_liste_field_titre("LineId", $_SERVER["PHP_SELF"], "erd.rowid", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("ExpenseReport", $_SERVER["PHP_SELF"], "er.ref", "", $param, '', $sortfield, $sortorder); - print_liste_field_titre("Date", $_SERVER["PHP_SELF"], "erd.date, erd.rowid", "", $param, '', $sortfield, $sortorder, 'center '); + print_liste_field_titre("DateOfLine", $_SERVER["PHP_SELF"], "erd.date, erd.rowid", "", $param, '', $sortfield, $sortorder, 'center '); print_liste_field_titre("TypeFees", $_SERVER["PHP_SELF"], "f.label", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("Description", $_SERVER["PHP_SELF"], "erd.comments", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("Amount", $_SERVER["PHP_SELF"], "erd.total_ht", "", $param, '', $sortfield, $sortorder, 'right maxwidth50 '); From 625c7216a986d309f4abbe147e9f8a8eafe85d20 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 30 Apr 2020 19:51:24 +0200 Subject: [PATCH 038/120] Can show date of validation in list --- htdocs/accountancy/expensereport/lines.php | 13 ++++++++++++- htdocs/accountancy/expensereport/list.php | 15 +++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/htdocs/accountancy/expensereport/lines.php b/htdocs/accountancy/expensereport/lines.php index 8cc398a00bf..4cd51fb3a63 100644 --- a/htdocs/accountancy/expensereport/lines.php +++ b/htdocs/accountancy/expensereport/lines.php @@ -252,6 +252,9 @@ if ($result) { print ''; print ''; print ''; + if (! empty($conf->global->ACCOUNTANCY_USE_EXPENSE_REPORT_VALIDATION_DATE)) { + print ''; + } print ''; if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print ''; print ''; @@ -272,7 +275,10 @@ if ($result) { print ''; print_liste_field_titre("LineId", $_SERVER["PHP_SELF"], "erd.rowid", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("ExpenseReport", $_SERVER["PHP_SELF"], "er.ref", "", $param, '', $sortfield, $sortorder); - print_liste_field_titre("Date", $_SERVER["PHP_SELF"], "erd.date, erd.rowid", "", $param, '', $sortfield, $sortorder, 'center '); + if (! empty($conf->global->ACCOUNTANCY_USE_EXPENSE_REPORT_VALIDATION_DATE)) { + print_liste_field_titre("DateValidation", $_SERVER["PHP_SELF"], "er.date_valid", "", $param, '', $sortfield, $sortorder, 'center '); + } + print_liste_field_titre("DateOfLine", $_SERVER["PHP_SELF"], "erd.date, erd.rowid", "", $param, '', $sortfield, $sortorder, 'center '); print_liste_field_titre("TypeFees", $_SERVER["PHP_SELF"], "f.label", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("Description", $_SERVER["PHP_SELF"], "erd.comments", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("Amount", $_SERVER["PHP_SELF"], "erd.total_ht", "", $param, '', $sortfield, $sortorder, 'right '); @@ -299,6 +305,11 @@ if ($result) { // Ref Invoice print ''.$expensereport_static->getNomUrl(1).''; + // Date validation + if (! empty($conf->global->ACCOUNTANCY_USE_EXPENSE_REPORT_VALIDATION_DATE)) { + print ''.dol_print_date($db->jdate($objp->date_valid), 'day').''; + } + print ''.dol_print_date($db->jdate($objp->date), 'day').''; print ''.($langs->trans($objp->type_fees_code) == $objp->type_fees_code ? $objp->type_fees_label : $langs->trans(($objp->type_fees_code))).''; diff --git a/htdocs/accountancy/expensereport/list.php b/htdocs/accountancy/expensereport/list.php index 148a1d8fe1f..96eebd49b36 100644 --- a/htdocs/accountancy/expensereport/list.php +++ b/htdocs/accountancy/expensereport/list.php @@ -43,7 +43,7 @@ $show_files = GETPOST('show_files', 'int'); $confirm = GETPOST('confirm', 'alpha'); $toselect = GETPOST('toselect', 'array'); $contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'myobjectlist'; // To manage different context of search -$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') +$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') // Select Box @@ -186,7 +186,7 @@ if (empty($chartaccountcode)) } // Expense report lines -$sql = "SELECT er.ref, er.rowid as erid, er.date_debut,"; +$sql = "SELECT er.ref, er.rowid as erid, er.date_debut, er.date_valid,"; $sql .= " erd.rowid, erd.fk_c_type_fees, erd.comments, erd.total_ht as price, erd.fk_code_ventilation, erd.tva_tx as tva_tx_line, erd.vat_src_code, erd.date,"; $sql .= " f.id as type_fees_id, f.code as type_fees_code, f.label as type_fees_label, f.accountancy_code as code_buy,"; $sql .= " aa.rowid as aarowid"; @@ -291,6 +291,9 @@ if ($result) { print ''; print ''; print ''; + if (! empty($conf->global->ACCOUNTANCY_USE_EXPENSE_REPORT_VALIDATION_DATE)) { + print ''; + } print ''; if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print ''; print ''; @@ -311,6 +314,9 @@ if ($result) { print ''; print_liste_field_titre("LineId", $_SERVER["PHP_SELF"], "erd.rowid", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("ExpenseReport", $_SERVER["PHP_SELF"], "er.ref", "", $param, '', $sortfield, $sortorder); + if (! empty($conf->global->ACCOUNTANCY_USE_EXPENSE_REPORT_VALIDATION_DATE)) { + print_liste_field_titre("DateValidation", $_SERVER["PHP_SELF"], "er.date_valid", "", $param, '', $sortfield, $sortorder, 'center '); + } print_liste_field_titre("DateOfLine", $_SERVER["PHP_SELF"], "erd.date, erd.rowid", "", $param, '', $sortfield, $sortorder, 'center '); print_liste_field_titre("TypeFees", $_SERVER["PHP_SELF"], "f.label", "", $param, '', $sortfield, $sortorder); print_liste_field_titre("Description", $_SERVER["PHP_SELF"], "erd.comments", "", $param, '', $sortfield, $sortorder); @@ -344,6 +350,11 @@ if ($result) { // Ref Expense report print ''.$expensereport_static->getNomUrl(1).''; + // Date validation + if (! empty($conf->global->ACCOUNTANCY_USE_EXPENSE_REPORT_VALIDATION_DATE)) { + print ''.dol_print_date($db->jdate($objp->date_valid), 'day').''; + } + // Date print ''.dol_print_date($db->jdate($objp->date), 'day').''; From fddbe7c9292bbe2d808104e55e89b1df92b6274b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Fri, 1 May 2020 07:50:46 +0200 Subject: [PATCH 039/120] $tmpplugin was defined after use --- htdocs/core/class/html.form.class.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index b2c677ed29d..5eaa7d5ede8 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -6634,11 +6634,11 @@ class Form // Add code for jquery to use multiselect if (!empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT')) { - $out .= "\n".' - - - - - - - -
- - - -
- - - - From a88ab40384f9ec359f289148d0e5ea5052c52c1a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sat, 2 May 2020 15:18:59 +0200 Subject: [PATCH 057/120] Clean phpcs --- README.md | 2 +- dev/setup/codesniffer/ruleset.xml | 52 ++++++++++--------- htdocs/api/class/api_access.class.php | 2 +- htdocs/api/index.php | 2 +- .../core/class/commondocgenerator.class.php | 2 +- .../core/modules/modEmailCollector.class.php | 7 ++- htdocs/dav/fileserver.php | 2 +- htdocs/debugbar/class/autoloader.php | 2 +- htdocs/don/class/paymentdonation.class.php | 52 +++++++++++-------- htdocs/product/admin/price_rules.php | 2 +- htdocs/product/inventory/inventory.php | 6 +-- 11 files changed, 71 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 3f329c678a7..f611f333e6a 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Other licenses apply for some included dependencies. See [COPYRIGHT](https://git If you have low technical skills and you're looking to install Dolibarr ERP/CRM in just a few clicks, you can use one of the packaged versions: - [DoliWamp for Windows](https://wiki.dolibarr.org/index.php/Dolibarr_for_Windows_(DoliWamp) -- DoliDeb for Debian or Ubuntu +- [DoliDeb for Debian](https://wiki.dolibarr.org/index.php/Dolibarr_for_Ubuntu_or_Debian - DoliRpm for Redhat, Fedora, OpenSuse, Mandriva or Mageia Releases can be downloaded from [official website](https://www.dolibarr.org/). diff --git a/dev/setup/codesniffer/ruleset.xml b/dev/setup/codesniffer/ruleset.xml index f8219fc7119..421acfeed1f 100644 --- a/dev/setup/codesniffer/ruleset.xml +++ b/dev/setup/codesniffer/ruleset.xml @@ -67,19 +67,11 @@ - + - - - @@ -99,19 +91,33 @@ + + + + 0 - - + + + @@ -127,7 +133,7 @@ - + @@ -190,13 +196,10 @@ - - 0 - - - 0 - - + + + + 0 @@ -208,7 +211,6 @@ - 0 diff --git a/htdocs/api/class/api_access.class.php b/htdocs/api/class/api_access.class.php index 866de6a53d2..339ddfd2ad6 100644 --- a/htdocs/api/class/api_access.class.php +++ b/htdocs/api/class/api_access.class.php @@ -18,7 +18,7 @@ // Create the autoloader for Luracast require_once DOL_DOCUMENT_ROOT.'/includes/restler/framework/Luracast/Restler/AutoLoader.php'; -call_user_func(function() { +call_user_func(function () { $loader = Luracast\Restler\AutoLoader::instance(); spl_autoload_register($loader); return $loader; diff --git a/htdocs/api/index.php b/htdocs/api/index.php index d27bd39e966..c5edbc74d66 100644 --- a/htdocs/api/index.php +++ b/htdocs/api/index.php @@ -44,7 +44,7 @@ if (!$res) die("Include of main fails"); require_once DOL_DOCUMENT_ROOT.'/includes/restler/framework/Luracast/Restler/AutoLoader.php'; -call_user_func(function() { +call_user_func(function () { $loader = Luracast\Restler\AutoLoader::instance(); spl_autoload_register($loader); return $loader; diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index 4bcfbafa9d8..1f5ef0a5a9e 100644 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -1295,7 +1295,7 @@ abstract class CommonDocGenerator if (!empty($fields)) { // Sort extrafields by rank - uasort($fields, function($a, $b) { + uasort($fields, function ($a, $b) { return ($a->rank > $b->rank) ? -1 : 1; }); diff --git a/htdocs/core/modules/modEmailCollector.class.php b/htdocs/core/modules/modEmailCollector.class.php index ed37a3a70ab..ce8ea9436e8 100644 --- a/htdocs/core/modules/modEmailCollector.class.php +++ b/htdocs/core/modules/modEmailCollector.class.php @@ -282,7 +282,8 @@ class modEmailCollector extends DolibarrModules $tmpresql = $this->db->query($tmpsql); if ($tmpresql) { if ($this->db->num_rows($tmpresql) == 0) { - $descriptionA1 = 'This collector will scan your mailbox to find emails that match some rules and create automatically a ticket (Module Ticket must be enabled) with the email informations. You can use this collector if you provide some support by email, so your ticket request will be automatically generated. If the collector Collect_Responses is also enabled, when you send an email from the ticket, you may also see answers of your customers or partners directly on the ticket view.'; + $descriptionA1 = 'This collector will scan your mailbox to find emails that match some rules and create automatically a ticket (Module Ticket must be enabled) with the email informations. You can use this collector if you provide some support by email, so your ticket request will be automatically generated.'; + $descriptionA1 .= ' If the collector Collect_Responses is also enabled, when you send an email from the ticket, you may also see answers of your customers or partners directly on the ticket view.'; $sqlforexampleA1 = "INSERT INTO ".MAIN_DB_PREFIX."emailcollector_emailcollector (entity, ref, label, description, source_directory, date_creation, fk_user_creat, status)"; $sqlforexampleA1 .= " VALUES (".$conf->entity.", 'Collect_Ticket_Requets', 'Example to collect ticket requests', '".$this->db->escape($descriptionA1)."', 'INBOX', '".$this->db->idate(dol_now())."', ".$user->id.", 0)"; $sqlforexampleA2 = "INSERT INTO ".MAIN_DB_PREFIX."emailcollector_emailcollectorfilter (fk_emailcollector, type, date_creation, fk_user_creat, status)"; @@ -319,7 +320,9 @@ class modEmailCollector extends DolibarrModules $tmpresql = $this->db->query($tmpsql); if ($tmpresql) { if ($this->db->num_rows($tmpresql) == 0) { - $descriptionC1 = "This collector will scan your mailbox to find emails that match some rules and create automatically a lead (Module Project must be enabled) with the email informations. You can use this collector if you want to follow your lead using the module Project (1 lead = 1 project), so your leads will be automatically generated. If the collector Collect_Responses is also enabled, when you send an email from your leads, proposals or any other object, you may also see answers of your customers or partners directly on the application.
Note: With this initial example, the title of the lead is generated including the email. If the thirdparty can't be found in database (new customer), the lead will be attached to the thirdparty with ID 1."; + $descriptionC1 = "This collector will scan your mailbox to find emails that match some rules and create automatically a lead (Module Project must be enabled) with the email informations. You can use this collector if you want to follow your lead using the module Project (1 lead = 1 project), so your leads will be automatically generated."; + $descriptionC1 .= " If the collector Collect_Responses is also enabled, when you send an email from your leads, proposals or any other object, you may also see answers of your customers or partners directly on the application.
"; + $descriptionC1 .= "Note: With this initial example, the title of the lead is generated including the email. If the thirdparty can't be found in database (new customer), the lead will be attached to the thirdparty with ID 1."; $sqlforexampleC1 = "INSERT INTO ".MAIN_DB_PREFIX."emailcollector_emailcollector (entity, ref, label, description, source_directory, date_creation, fk_user_creat, status)"; $sqlforexampleC1 .= " VALUES (".$conf->entity.", 'Collect_Leads', 'Example to collect leads', '".$this->db->escape($descriptionC1)."', 'INBOX', '".$this->db->idate(dol_now())."', ".$user->id.", 0)"; $sqlforexampleC2 = "INSERT INTO ".MAIN_DB_PREFIX."emailcollector_emailcollectorfilter (fk_emailcollector, type, date_creation, fk_user_creat, status)"; diff --git a/htdocs/dav/fileserver.php b/htdocs/dav/fileserver.php index ce3157414f5..18b8bc8b07c 100644 --- a/htdocs/dav/fileserver.php +++ b/htdocs/dav/fileserver.php @@ -82,7 +82,7 @@ $tmpDir = $conf->dav->multidir_output[$entity]; // We need root dir, not a dir t // Authentication callback function -$authBackend = new \Sabre\DAV\Auth\Backend\BasicCallBack(function($username, $password) { +$authBackend = new \Sabre\DAV\Auth\Backend\BasicCallBack(function ($username, $password) { global $user; global $conf; global $dolibarr_main_authentication, $dolibarr_auto_user; diff --git a/htdocs/debugbar/class/autoloader.php b/htdocs/debugbar/class/autoloader.php index a68ace2c3c0..1d5c85c975d 100644 --- a/htdocs/debugbar/class/autoloader.php +++ b/htdocs/debugbar/class/autoloader.php @@ -4,7 +4,7 @@ * Simple autoloader, so we don't need Composer just for this. */ -spl_autoload_register(function($class) { +spl_autoload_register(function ($class) { if (preg_match('/^DebugBar/', $class) || preg_match('/^'.preg_quote('Psr\Log', '/').'/', $class)) { $file = DOL_DOCUMENT_ROOT.'/includes/'.str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php'; //var_dump($class.' - '.file_exists($file).' - '.$file); diff --git a/htdocs/don/class/paymentdonation.class.php b/htdocs/don/class/paymentdonation.class.php index ee8156c229e..64644d18971 100644 --- a/htdocs/don/class/paymentdonation.class.php +++ b/htdocs/don/class/paymentdonation.class.php @@ -55,11 +55,17 @@ class PaymentDonation extends CommonObject public $fk_donation; public $datec = ''; + public $tms = ''; + public $datep = ''; - public $amount; // Total amount of payment - public $amounts = array(); // Array of amounts + + public $amount; // Total amount of payment + + public $amounts = array(); // Array of amounts + public $typepayment; + public $num_payment; /** @@ -121,14 +127,14 @@ class PaymentDonation extends CommonObject } // Clean parameters - if (isset($this->fk_donation)) $this->fk_donation = (int) $this->fk_donation; - if (isset($this->amount)) $this->amount = trim($this->amount); + if (isset($this->fk_donation)) $this->fk_donation = (int) $this->fk_donation; + if (isset($this->amount)) $this->amount = trim($this->amount); if (isset($this->fk_typepayment)) $this->fk_typepayment = trim($this->fk_typepayment); - if (isset($this->num_payment)) $this->num_payment = trim($this->num_payment); - if (isset($this->note_public)) $this->note_public = trim($this->note_public); - if (isset($this->fk_bank)) $this->fk_bank = (int) $this->fk_bank; - if (isset($this->fk_user_creat)) $this->fk_user_creat = (int) $this->fk_user_creat; - if (isset($this->fk_user_modif)) $this->fk_user_modif = (int) $this->fk_user_modif; + if (isset($this->num_payment)) $this->num_payment = trim($this->num_payment); + if (isset($this->note_public)) $this->note_public = trim($this->note_public); + if (isset($this->fk_bank)) $this->fk_bank = (int) $this->fk_bank; + if (isset($this->fk_user_creat)) $this->fk_user_creat = (int) $this->fk_user_creat; + if (isset($this->fk_user_modif)) $this->fk_user_modif = (int) $this->fk_user_modif; $totalamount = 0; foreach ($this->amounts as $key => $value) // How payment is dispatch @@ -228,26 +234,26 @@ class PaymentDonation extends CommonObject { $obj = $this->db->fetch_object($resql); - $this->id = $obj->rowid; - $this->ref = $obj->rowid; + $this->id = $obj->rowid; + $this->ref = $obj->rowid; - $this->fk_donation = $obj->fk_donation; - $this->datec = $this->db->jdate($obj->datec); - $this->tms = $this->db->jdate($obj->tms); - $this->datep = $this->db->jdate($obj->datep); - $this->amount = $obj->amount; + $this->fk_donation = $obj->fk_donation; + $this->datec = $this->db->jdate($obj->datec); + $this->tms = $this->db->jdate($obj->tms); + $this->datep = $this->db->jdate($obj->datep); + $this->amount = $obj->amount; $this->fk_typepayment = $obj->fk_typepayment; - $this->num_payment = $obj->num_payment; - $this->note_public = $obj->note_public; - $this->fk_bank = $obj->fk_bank; - $this->fk_user_creat = $obj->fk_user_creat; - $this->fk_user_modif = $obj->fk_user_modif; + $this->num_payment = $obj->num_payment; + $this->note_public = $obj->note_public; + $this->fk_bank = $obj->fk_bank; + $this->fk_user_creat = $obj->fk_user_creat; + $this->fk_user_modif = $obj->fk_user_modif; - $this->type_code = $obj->type_code; + $this->type_code = $obj->type_code; $this->type_label = $obj->type_label; $this->bank_account = $obj->fk_account; - $this->bank_line = $obj->fk_bank; + $this->bank_line = $obj->fk_bank; } $this->db->free($resql); diff --git a/htdocs/product/admin/price_rules.php b/htdocs/product/admin/price_rules.php index 6da4d65925b..64bf5702996 100644 --- a/htdocs/product/admin/price_rules.php +++ b/htdocs/product/admin/price_rules.php @@ -141,7 +141,7 @@ for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) { $price_options[$i] = $langs->trans('SellingPrice').' '.$i; } -$genPriceOptions = function($level) use ($price_options) { +$genPriceOptions = function ($level) use ($price_options) { $return = array(); diff --git a/htdocs/product/inventory/inventory.php b/htdocs/product/inventory/inventory.php index b6021c82cb8..3f0989251b5 100644 --- a/htdocs/product/inventory/inventory.php +++ b/htdocs/product/inventory/inventory.php @@ -31,10 +31,10 @@ $langs->loadLangs(array("stocks", "other")); // Get parameters $id = GETPOST('id', 'int'); -$ref = GETPOST('ref', 'alpha'); +$ref = GETPOST('ref', 'alpha'); $action = GETPOST('action', 'aZ09'); -$confirm = GETPOST('confirm', 'alpha'); -$cancel = GETPOST('cancel', 'aZ09'); +$confirm = GETPOST('confirm', 'alpha'); +$cancel = GETPOST('cancel', 'aZ09'); $contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'myobjectcard'; // To manage different context of search $backtopage = GETPOST('backtopage', 'alpha'); From 99d7cb72a170286366cdb759e6721f8d8beafcbf Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sat, 2 May 2020 15:40:23 +0200 Subject: [PATCH 058/120] Fix duplicate --- .scrutinizer.yml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 7c43ab24aef..6dbf39bde26 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -194,22 +194,6 @@ tools: - 'test/*' - 'htdocs/includes/*' paths: { } - - php_changetracking: - enabled: false - bug_patterns: - - '\bfix(?:es|ed)?\b' - feature_patterns: - - '\badd(?:s|ed)?\b' - - '\bimplement(?:s|ed)?\b' - filter: - excluded_paths: - - 'build/*' - - 'dev/*' - - 'doc/*' - - 'test/*' - - 'htdocs/includes/*' - paths: { } # Coding-Style / Bug Detection js_hint: From b5abb72c5b5b1ab74cce3700b20bc2c3cf03a9dd Mon Sep 17 00:00:00 2001 From: Marc Guenneugues Date: Sat, 2 May 2020 16:36:40 +0200 Subject: [PATCH 059/120] Add / as a delimiter for replacement pattern in select_produits* --- htdocs/core/class/html.form.class.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 5eaa7d5ede8..f48ce989a7a 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -2507,7 +2507,7 @@ class Form $label = $objp->label; if (!empty($objp->label_translated)) $label = $objp->label_translated; - if (!empty($filterkey) && $filterkey != '') $label = preg_replace('/('.preg_quote($filterkey).')/i', '$1', $label, 1); + if (!empty($filterkey) && $filterkey != '') $label = preg_replace('/('.preg_quote($filterkey, '/').')/i', '$1', $label, 1); $outkey = $objp->rowid; $outref = $objp->ref; @@ -2579,7 +2579,7 @@ class Form if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) $opt .= ' ('.getCountry($outorigin, 1).')'; $objRef = $objp->ref; - if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey).')/i', '$1', $objRef, 1); + if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '$1', $objRef, 1); $outval .= $objRef; if ($outbarcode) $outval .= ' ('.$outbarcode.')'; $outval .= ' - '.dol_trunc($label, $maxlengtharticle); @@ -2948,11 +2948,11 @@ class Form } $objRef = $objp->ref; - if ($filterkey && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey).')/i', '$1', $objRef, 1); + if ($filterkey && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '$1', $objRef, 1); $objRefFourn = $objp->ref_fourn; - if ($filterkey && $filterkey != '') $objRefFourn = preg_replace('/('.preg_quote($filterkey).')/i', '$1', $objRefFourn, 1); + if ($filterkey && $filterkey != '') $objRefFourn = preg_replace('/('.preg_quote($filterkey, '/').')/i', '$1', $objRefFourn, 1); $label = $objp->label; - if ($filterkey && $filterkey != '') $label = preg_replace('/('.preg_quote($filterkey).')/i', '$1', $label, 1); + if ($filterkey && $filterkey != '') $label = preg_replace('/('.preg_quote($filterkey, '/').')/i', '$1', $label, 1); $optlabel = $objp->ref; if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) { From 1929f9132db3c67023ce284a935943a8c47b232a Mon Sep 17 00:00:00 2001 From: proprum <51385888+proprum@users.noreply.github.com> Date: Sat, 2 May 2020 17:25:22 +0200 Subject: [PATCH 060/120] MAIN_NO_CONCAT_DESCRIPTION in contrat/card.php Idem to propal/card.php --- htdocs/contrat/card.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/contrat/card.php b/htdocs/contrat/card.php index 3c64b627a5c..111a446d9ae 100644 --- a/htdocs/contrat/card.php +++ b/htdocs/contrat/card.php @@ -521,7 +521,8 @@ if (empty($reshook)) } $desc = $prod->description; - $desc = dol_concatdesc($desc, $product_desc, '', !empty($conf->global->MAIN_CHANGE_ORDER_CONCAT_DESCRIPTION)); + if (!empty($product_desc) && !empty($conf->global->MAIN_NO_CONCAT_DESCRIPTION)) $desc = $product_desc; + else $desc = dol_concatdesc($desc, $product_desc, '', !empty($conf->global->MAIN_CHANGE_ORDER_CONCAT_DESCRIPTION)); $fk_unit = $prod->fk_unit; } else From 518853bb9614343369e0fa2c1f3f0430a95072db Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sat, 2 May 2020 18:37:34 +0200 Subject: [PATCH 061/120] Add image --- doc/images/background_dolibarr.jpg | Bin 0 -> 175643 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/images/background_dolibarr.jpg diff --git a/doc/images/background_dolibarr.jpg b/doc/images/background_dolibarr.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6c4cc11460d334442b8f53e41054c333a626db18 GIT binary patch literal 175643 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 z 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 z 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 M0e$3v%zu;r2ThWJWdHyG literal 0 HcmV?d00001 From 81c808692e13f45922f7716b8c698e1537bc2e1a Mon Sep 17 00:00:00 2001 From: "jove@bisquerra.com" Date: Sat, 2 May 2020 22:00:04 +0200 Subject: [PATCH 062/120] NEW Bar Restaurant tab and Auto order --- htdocs/core/lib/takepos.lib.php | 8 ++ htdocs/langs/en_US/cashdesk.lang | 4 +- htdocs/takepos/admin/bar.php | 178 +++++++++++++++++++++++++++++++ htdocs/takepos/admin/setup.php | 55 ---------- htdocs/takepos/ajax/ajax.php | 6 ++ htdocs/takepos/auto_order.php | 29 +++++ htdocs/takepos/genimg/qr.php | 33 ++++++ htdocs/takepos/invoice.php | 7 +- htdocs/takepos/phone.php | 31 ++++-- 9 files changed, 287 insertions(+), 64 deletions(-) create mode 100644 htdocs/takepos/admin/bar.php create mode 100644 htdocs/takepos/auto_order.php create mode 100644 htdocs/takepos/genimg/qr.php diff --git a/htdocs/core/lib/takepos.lib.php b/htdocs/core/lib/takepos.lib.php index 8a883ceef91..729952916ad 100644 --- a/htdocs/core/lib/takepos.lib.php +++ b/htdocs/core/lib/takepos.lib.php @@ -42,6 +42,14 @@ function takepos_prepare_head() $head[$h][1] = $langs->trans("Receipt"); $head[$h][2] = 'receipt'; $h++; + + if ($conf->global->TAKEPOS_BAR_RESTAURANT) + { + $head[$h][0] = DOL_URL_ROOT.'/takepos/admin/bar.php'; + $head[$h][1] = $langs->trans("BarRestaurant"); + $head[$h][2] = 'bar'; + $h++; + } $numterminals = max(1, $conf->global->TAKEPOS_NUM_TERMINALS); for ($i = 1; $i <= $numterminals; $i++) diff --git a/htdocs/langs/en_US/cashdesk.lang b/htdocs/langs/en_US/cashdesk.lang index f2bc989b953..b22a7b83166 100644 --- a/htdocs/langs/en_US/cashdesk.lang +++ b/htdocs/langs/en_US/cashdesk.lang @@ -105,4 +105,6 @@ CashReport=Cash report MainPrinterToUse=Main printer to use OrderPrinterToUse=Order printer to use MainTemplateToUse=Main template to use -OrderTemplateToUse=Order template to use \ No newline at end of file +OrderTemplateToUse=Order template to use +BarRestaurant=Bar Restaurant +AutoOrder=Customer auto order \ No newline at end of file diff --git a/htdocs/takepos/admin/bar.php b/htdocs/takepos/admin/bar.php new file mode 100644 index 00000000000..16fccf85147 --- /dev/null +++ b/htdocs/takepos/admin/bar.php @@ -0,0 +1,178 @@ + + * Copyright (C) 2011-2017 Juanjo Menent + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/takepos/admin/bar.php + * \ingroup takepos + * \brief Setup page for TakePos module - Bar Restaurant features + */ + +require '../../main.inc.php'; // Load $user and permissions +require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; +require_once DOL_DOCUMENT_ROOT."/core/lib/takepos.lib.php"; + +// Security check +if (!$user->admin) accessforbidden(); + +$langs->loadLangs(array("admin", "cashdesk", "printing")); + +global $db; + +/* + * Actions + */ + +if (GETPOST('action', 'alpha') == 'set') +{ + $db->begin(); + + dol_syslog("admin/cashdesk: level ".GETPOST('level', 'alpha')); + + if (!$res > 0) $error++; + + if (!$error) + { + $db->commit(); + setEventMessages($langs->trans("SetupSaved"), null, 'mesgs'); + } + else + { + $db->rollback(); + setEventMessages($langs->trans("Error"), null, 'errors'); + } +} + + +/* + * View + */ + +$form = new Form($db); +$formproduct = new FormProduct($db); + +llxHeader('', $langs->trans("CashDeskSetup")); + +$linkback = ''.$langs->trans("BackToModuleList").''; +print load_fiche_titre($langs->trans("CashDeskSetup").' (TakePOS)', $linkback, 'title_setup'); +$head = takepos_prepare_head(); +dol_fiche_head($head, 'bar', 'TakePOS', -1); +print '
'; + + +// Mode +print '
'; +print ''; +print ''; + +print '
'; +print ''; +print ''; +print ''; +print "\n"; + +if ($conf->global->TAKEPOS_BAR_RESTAURANT && $conf->global->TAKEPOS_PRINT_METHOD != "browser") { + print ''; + + print ''; +} + +print ''; + +print ''; + +if ($conf->global->TAKEPOS_SUPPLEMENTS) +{ + print '\n"; +} + +print ''; + + +print '
'.$langs->trans("Parameters").''.$langs->trans("Value").'
'; + print $langs->trans("OrderPrinters").' ('.$langs->trans("Setup").')'; + print ''; + print ajax_constantonoff("TAKEPOS_ORDER_PRINTERS", array(), $conf->entity, 0, 0, 1, 0); + //print $form->selectyesno("TAKEPOS_ORDER_PRINTERS", $conf->global->TAKEPOS_ORDER_PRINTERS, 1); + print '
'; + print $langs->trans("OrderNotes"); + print ''; + print ajax_constantonoff("TAKEPOS_ORDER_NOTES", array(), $conf->entity, 0, 0, 1, 0); + //print $form->selectyesno("TAKEPOS_ORDER_NOTES", $conf->global->TAKEPOS_ORDER_NOTES, 1); + print '
'; +print $langs->trans("BasicPhoneLayout"); +print ''; +//print $form->selectyesno("TAKEPOS_PHONE_BASIC_LAYOUT", $conf->global->TAKEPOS_PHONE_BASIC_LAYOUT, 1); +print ajax_constantonoff("TAKEPOS_PHONE_BASIC_LAYOUT", array(), $conf->entity, 0, 0, 1, 0); +print '
'; +print $langs->trans("ProductSupplements"); +print ''; +//print $form->selectyesno("TAKEPOS_SUPPLEMENTS", $conf->global->TAKEPOS_SUPPLEMENTS, 1); +print ajax_constantonoff("TAKEPOS_SUPPLEMENTS", array(), $conf->entity, 0, 0, 1, 0); +print '
'; + print $langs->trans("SupplementCategory"); + print ''; + print $form->select_all_categories(Categorie::TYPE_PRODUCT, $conf->global->TAKEPOS_SUPPLEMENTS_CATEGORY, 'TAKEPOS_SUPPLEMENTS_CATEGORY', 64, 0, 0); + print ajax_combobox('TAKEPOS_SUPPLEMENTS_CATEGORY'); + print "
'; +print $langs->trans("AutoOrder"); +print ''; +print ajax_constantonoff("TAKEPOS_AUTO_ORDER", array(), $conf->entity, 0, 0, 1, 0); +print '
'; + +if ($conf->global->TAKEPOS_AUTO_ORDER) +{ + print '
'; + print ''; + print ''; + print ''; + print "\n"; + + //global $dolibarr_main_url_root; + $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root)); + $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file + $sql = "SELECT rowid, entity, label, leftpos, toppos, floor FROM ".MAIN_DB_PREFIX."takepos_floor_tables"; + $resql = $db->query($sql); + $rows = array(); + while ($row = $db->fetch_array($resql)) { + print ''; + } + + print '
'.$langs->trans("Table").''.$langs->trans("URL").''.$langs->trans("QR").'
'; + print $langs->trans("Table")." ".$row['label']; + print ''; + print "".$urlwithroot."/takepos/auto_order.php?key=".dol_encode($row['rowid']).""; + print ''; + print ""; + print '
'; +} + +print '
'; + +print '
'; + +print '
'; + +print "
\n"; + +print '
'; + +llxFooter(); +$db->close(); diff --git a/htdocs/takepos/admin/setup.php b/htdocs/takepos/admin/setup.php index 3e12fdce5c9..59fe85e66ef 100644 --- a/htdocs/takepos/admin/setup.php +++ b/htdocs/takepos/admin/setup.php @@ -434,19 +434,6 @@ print "\n"; //print $form->selectarray('TAKEPOS_ADDON', $array, (empty($conf->global->TAKEPOS_ADDON) ? '0' : $conf->global->TAKEPOS_ADDON), 0); //print "\n"; -print ''; -print '
'; - -print '
'; - -// Bar Restaurant mode -print '
'; -print ''; - -print ''; -print ''; -print "\n"; - print ''; @@ -455,48 +442,6 @@ print ajax_constantonoff("TAKEPOS_BAR_RESTAURANT", array(), $conf->entity, 0, 0, //print $form->selectyesno("TAKEPOS_BAR_RESTAURANT", $conf->global->TAKEPOS_BAR_RESTAURANT, 1); print "\n"; -if ($conf->global->TAKEPOS_BAR_RESTAURANT && $conf->global->TAKEPOS_PRINT_METHOD != "browser") { - print ''; - - print ''; -} - -if ($conf->global->TAKEPOS_BAR_RESTAURANT) -{ - print ''; - - print ''; - - if ($conf->global->TAKEPOS_SUPPLEMENTS) - { - print '\n"; - } -} print '
'.$langs->trans("Other").''.$langs->trans("Value").'
'; print $langs->trans("EnableBarOrRestaurantFeatures"); print '
'; - print $langs->trans("OrderPrinters").' ('.$langs->trans("Setup").')'; - print ''; - print ajax_constantonoff("TAKEPOS_ORDER_PRINTERS", array(), $conf->entity, 0, 0, 1, 0); - //print $form->selectyesno("TAKEPOS_ORDER_PRINTERS", $conf->global->TAKEPOS_ORDER_PRINTERS, 1); - print '
'; - print $langs->trans("OrderNotes"); - print ''; - print ajax_constantonoff("TAKEPOS_ORDER_NOTES", array(), $conf->entity, 0, 0, 1, 0); - //print $form->selectyesno("TAKEPOS_ORDER_NOTES", $conf->global->TAKEPOS_ORDER_NOTES, 1); - print '
'; - print $langs->trans("BasicPhoneLayout"); - print ''; - //print $form->selectyesno("TAKEPOS_PHONE_BASIC_LAYOUT", $conf->global->TAKEPOS_PHONE_BASIC_LAYOUT, 1); - print ajax_constantonoff("TAKEPOS_PHONE_BASIC_LAYOUT", array(), $conf->entity, 0, 0, 1, 0); - print '
'; - print $langs->trans("ProductSupplements"); - print ''; - //print $form->selectyesno("TAKEPOS_SUPPLEMENTS", $conf->global->TAKEPOS_SUPPLEMENTS, 1); - print ajax_constantonoff("TAKEPOS_SUPPLEMENTS", array(), $conf->entity, 0, 0, 1, 0); - print '
'; - print $langs->trans("SupplementCategory"); - print ''; - print $form->select_all_categories(Categorie::TYPE_PRODUCT, $conf->global->TAKEPOS_SUPPLEMENTS_CATEGORY, 'TAKEPOS_SUPPLEMENTS_CATEGORY', 64, 0, 0); - print ajax_combobox('TAKEPOS_SUPPLEMENTS_CATEGORY'); - print "
'; print '
'; diff --git a/htdocs/takepos/ajax/ajax.php b/htdocs/takepos/ajax/ajax.php index f3b5ba15716..d1f59325c1f 100644 --- a/htdocs/takepos/ajax/ajax.php +++ b/htdocs/takepos/ajax/ajax.php @@ -142,4 +142,10 @@ elseif ($action == 'search' && $term != '') { } echo json_encode($object); +} elseif ($action == 'thecheck') { + $place = GETPOST('place', 'alpha'); + require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; + require_once DOL_DOCUMENT_ROOT.'/core/class/dolreceiptprinter.class.php'; + $printer = new dolReceiptPrinter($db); + $printer->sendToPrinter($object, $conf->global->{'TAKEPOS_TEMPLATE_TO_USE_FOR_INVOICES'.$term}, $conf->global->{'TAKEPOS_PRINTER_TO_USE'.$term}); } diff --git a/htdocs/takepos/auto_order.php b/htdocs/takepos/auto_order.php new file mode 100644 index 00000000000..5305b4da81f --- /dev/null +++ b/htdocs/takepos/auto_order.php @@ -0,0 +1,29 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/takepos/auto_order.php + * \ingroup takepos + * \brief Public orders for customers + */ + +if (!defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session) +if (!defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip + +$_SESSION["basiclayout"] = 1; +$_SESSION["publicterminal"] = true; // Is a public customer +require 'phone.php'; diff --git a/htdocs/takepos/genimg/qr.php b/htdocs/takepos/genimg/qr.php new file mode 100644 index 00000000000..23b033f3da5 --- /dev/null +++ b/htdocs/takepos/genimg/qr.php @@ -0,0 +1,33 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +if (!defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session) +if (!defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +if (!defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); +if (!defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); +if (!defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); +if (!defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); +if (!defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); +if (!defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); + +require '../../main.inc.php'; // Load $user and permissions +require '../../core/modules/barcode/doc/tcpdfbarcode.modules.php'; + +$key = GETPOST('key'); + +$module = new modtcpdfbarcode($db); +$result = $module->buildBarCode("http://www.takepos.com", 'QRCODE', 'Y'); \ No newline at end of file diff --git a/htdocs/takepos/invoice.php b/htdocs/takepos/invoice.php index fa5ca2f83be..f59a3b5c97d 100644 --- a/htdocs/takepos/invoice.php +++ b/htdocs/takepos/invoice.php @@ -47,13 +47,16 @@ $idproduct = GETPOST('idproduct', 'int'); $place = (GETPOST('place', 'aZ09') ? GETPOST('place', 'aZ09') : 0); // $place is id of table for Bar or Restaurant $placeid = 0; // $placeid is ID of invoice -if (empty($user->rights->takepos->run)) { +if ($_SESSION["publicterminal"]) { + $_SESSION["takeposterminal"] = 1; // Use Terminal 1 for public customers +} +else if (empty($user->rights->takepos->run)) { accessforbidden(); } -if ($conf->global->TAKEPOS_PHONE_BASIC_LAYOUT == 1 && $conf->browser->layout == 'phone') +if (($conf->global->TAKEPOS_PHONE_BASIC_LAYOUT == 1 && $conf->browser->layout == 'phone') || $_SESSION["publicterminal"]) { // DIRECT LINK TO THIS PAGE FROM MOBILE AND NO TERMINAL SELECTED if ($_SESSION["takeposterminal"] == "") diff --git a/htdocs/takepos/phone.php b/htdocs/takepos/phone.php index b2526ef885e..224cf3dd1c3 100644 --- a/htdocs/takepos/phone.php +++ b/htdocs/takepos/phone.php @@ -37,7 +37,12 @@ require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; -$place = (GETPOST('place', 'aZ09') ? GETPOST('place', 'aZ09') : 0); // $place is id of table for Ba or Restaurant +if ($_SESSION["publicterminal"]){ + // Decode place if is a order from customer phone + $key = GETPOST('key'); + $place=dol_decode($key); +} +else $place = (GETPOST('place', 'aZ09') ? GETPOST('place', 'aZ09') : 0); // $place is id of table for Ba or Restaurant $action = GETPOST('action', 'alpha'); $setterminal = GETPOST('setterminal', 'int'); @@ -48,7 +53,10 @@ if ($setterminal > 0) $langs->loadLangs(array("bills", "orders", "commercial", "cashdesk", "receiptprinter")); -if (empty($user->rights->takepos->run)) { +if ($_SESSION["publicterminal"]) { + $_SESSION["takeposterminal"] = 1; // Use Terminal 1 for public customers +} +else if (empty($user->rights->takepos->run)) { accessforbidden(); } @@ -167,6 +175,14 @@ function Exit(){ window.location.href='../user/logout.php'; } +function CheckPlease(){ + console.log("Request the check to the waiter"); + $.ajax({ + type: "GET", + url: "", + }); +} + @@ -175,10 +191,13 @@ if ($conf->global->TAKEPOS_NUM_TERMINALS != "1" && $_SESSION["takeposterminal"] ?>
- - - - + '.strtoupper(substr($langs->trans('Floors'), 0, 3)).''; + print ''; + print ''; + print ''; + if ($_SESSION["publicterminal"]) print ''; + ?>
From 35713ef0046b22f31c848fef1ea6facbb004b712 Mon Sep 17 00:00:00 2001 From: andreubisquerra Date: Sun, 3 May 2020 00:05:59 +0200 Subject: [PATCH 063/120] Fix travis --- htdocs/takepos/genimg/qr.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/takepos/genimg/qr.php b/htdocs/takepos/genimg/qr.php index 23b033f3da5..f0c3bea82b9 100644 --- a/htdocs/takepos/genimg/qr.php +++ b/htdocs/takepos/genimg/qr.php @@ -30,4 +30,4 @@ require '../../core/modules/barcode/doc/tcpdfbarcode.modules.php'; $key = GETPOST('key'); $module = new modtcpdfbarcode($db); -$result = $module->buildBarCode("http://www.takepos.com", 'QRCODE', 'Y'); \ No newline at end of file +$result = $module->buildBarCode("http://www.takepos.com", 'QRCODE', 'Y'); From ac75cf318eba8edaa0be6ed9fd7bee7f8a31f1d8 Mon Sep 17 00:00:00 2001 From: andreubisquerra Date: Sun, 3 May 2020 00:07:04 +0200 Subject: [PATCH 064/120] Fix travis --- htdocs/takepos/invoice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/takepos/invoice.php b/htdocs/takepos/invoice.php index f59a3b5c97d..b1641072829 100644 --- a/htdocs/takepos/invoice.php +++ b/htdocs/takepos/invoice.php @@ -50,7 +50,7 @@ $placeid = 0; // $placeid is ID of invoice if ($_SESSION["publicterminal"]) { $_SESSION["takeposterminal"] = 1; // Use Terminal 1 for public customers } -else if (empty($user->rights->takepos->run)) { +elseif (empty($user->rights->takepos->run)) { accessforbidden(); } From 32923daa9decc772155f713ea5aedfa9ff7c029b Mon Sep 17 00:00:00 2001 From: andreubisquerra Date: Sun, 3 May 2020 00:07:52 +0200 Subject: [PATCH 065/120] Fix travis --- htdocs/takepos/phone.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/takepos/phone.php b/htdocs/takepos/phone.php index 224cf3dd1c3..80d67513bf2 100644 --- a/htdocs/takepos/phone.php +++ b/htdocs/takepos/phone.php @@ -56,7 +56,7 @@ $langs->loadLangs(array("bills", "orders", "commercial", "cashdesk", "receiptpri if ($_SESSION["publicterminal"]) { $_SESSION["takeposterminal"] = 1; // Use Terminal 1 for public customers } -else if (empty($user->rights->takepos->run)) { +elseif (empty($user->rights->takepos->run)) { accessforbidden(); } From 8530db6dab7d7d8a068cac0705c47541f5062fc3 Mon Sep 17 00:00:00 2001 From: andreubisquerra Date: Sun, 3 May 2020 00:09:17 +0200 Subject: [PATCH 066/120] Fix travis --- htdocs/takepos/admin/bar.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/takepos/admin/bar.php b/htdocs/takepos/admin/bar.php index 16fccf85147..672041d3bb3 100644 --- a/htdocs/takepos/admin/bar.php +++ b/htdocs/takepos/admin/bar.php @@ -138,13 +138,13 @@ print ''; print ''; if ($conf->global->TAKEPOS_AUTO_ORDER) -{ +{ print '
'; print ''; print ''; print ''; print "\n"; - + //global $dolibarr_main_url_root; $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root)); $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file From fe98e430ceaa18d98a26706c7515e3d09201b86e Mon Sep 17 00:00:00 2001 From: andreubisquerra Date: Sun, 3 May 2020 00:10:12 +0200 Subject: [PATCH 067/120] Fix travis --- htdocs/core/lib/takepos.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/takepos.lib.php b/htdocs/core/lib/takepos.lib.php index 729952916ad..d04fa5f77ef 100644 --- a/htdocs/core/lib/takepos.lib.php +++ b/htdocs/core/lib/takepos.lib.php @@ -42,7 +42,7 @@ function takepos_prepare_head() $head[$h][1] = $langs->trans("Receipt"); $head[$h][2] = 'receipt'; $h++; - + if ($conf->global->TAKEPOS_BAR_RESTAURANT) { $head[$h][0] = DOL_URL_ROOT.'/takepos/admin/bar.php'; From c3521502deff79b1ca166a51aca9552b13708fcf Mon Sep 17 00:00:00 2001 From: Anthony Berton <34568357+bb2a@users.noreply.github.com> Date: Sun, 3 May 2020 10:34:56 +0200 Subject: [PATCH 068/120] Update global.inc.php --- htdocs/theme/eldy/global.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index 7b8e1373df9..786bdbd431b 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -3360,7 +3360,7 @@ tr.liste_titre th, th.liste_titre, tr.liste_titre td, td.liste_titre, form.liste } tr.liste_titre th a, th.liste_titre a, tr.liste_titre td a, td.liste_titre a, form.liste_titre div a, div.liste_titre a { text-shadow: none !important; - color: unset; + color: rgb(); } tr.liste_titre_topborder td { border-top-width: px; From 87d86f32ee28ca4012a7a977fd4fdd17872b69a5 Mon Sep 17 00:00:00 2001 From: Anthony Berton <34568357+bb2a@users.noreply.github.com> Date: Sun, 3 May 2020 10:40:52 +0200 Subject: [PATCH 069/120] Update usergroups.lib.php --- htdocs/core/lib/usergroups.lib.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/htdocs/core/lib/usergroups.lib.php b/htdocs/core/lib/usergroups.lib.php index 5b7c923001b..003d1260252 100644 --- a/htdocs/core/lib/usergroups.lib.php +++ b/htdocs/core/lib/usergroups.lib.php @@ -732,7 +732,34 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false) print ''; } + + // TextTitleLinkColor + if ($foruserprofile) + { + } + else + { + $default=(empty($colortexttitlelink) ? $langs->trans("Unknown") : colorArrayToHex(colorStringToArray($colortexttitlelink))); + print ''; + print ''; + print ''; + + print ''; + } + // BackgroundTableLineOddColor if ($foruserprofile) { From 5c1eb08b3fdbb6fcfa72203d90d58d7795781758 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Sun, 3 May 2020 08:42:45 +0000 Subject: [PATCH 070/120] Fixing style errors. --- htdocs/core/lib/usergroups.lib.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/lib/usergroups.lib.php b/htdocs/core/lib/usergroups.lib.php index 003d1260252..8be3e234273 100644 --- a/htdocs/core/lib/usergroups.lib.php +++ b/htdocs/core/lib/usergroups.lib.php @@ -732,7 +732,7 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false) print ''; } - + // TextTitleLinkColor if ($foruserprofile) { @@ -759,7 +759,7 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false) print ''; } - + // BackgroundTableLineOddColor if ($foruserprofile) { From f299f0f849d7a745cabcfdcc8d8b41347f59dbee Mon Sep 17 00:00:00 2001 From: Anthony Berton <34568357+bb2a@users.noreply.github.com> Date: Sun, 3 May 2020 10:42:49 +0200 Subject: [PATCH 071/120] Update theme_vars.inc.php --- htdocs/theme/eldy/theme_vars.inc.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/theme/eldy/theme_vars.inc.php b/htdocs/theme/eldy/theme_vars.inc.php index f6324f0146f..823b8168b4c 100644 --- a/htdocs/theme/eldy/theme_vars.inc.php +++ b/htdocs/theme/eldy/theme_vars.inc.php @@ -69,6 +69,7 @@ $colorbacklinebreak = '233,228,230'; // line break $colorbackbody = '255,255,255'; $colortexttitlenotab = '0,113,120'; // 150,90,121 140,80,10 or 10,140,80 #875a7b green=0,113,120, violet: 0,50,120 $colortexttitle = '0,0,0'; +$colortexttitlelink = '10, 20, 100'; $colortext = '0,0,0'; $colortextlink = '10, 20, 100'; $fontsize = '0.86em'; From 2f18b444d7946335604dfd2cd19a831540a2fd37 Mon Sep 17 00:00:00 2001 From: Anthony Berton <34568357+bb2a@users.noreply.github.com> Date: Sun, 3 May 2020 10:44:37 +0200 Subject: [PATCH 072/120] Update style.css.php --- htdocs/theme/eldy/style.css.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/theme/eldy/style.css.php b/htdocs/theme/eldy/style.css.php index 39fcd003335..927d29e1919 100644 --- a/htdocs/theme/eldy/style.css.php +++ b/htdocs/theme/eldy/style.css.php @@ -128,6 +128,7 @@ $colorbacklinebreak = empty($user->conf->THEME_ELDY_ENABLE_PERSONALIZED) ? (emp $colorbackbody = empty($user->conf->THEME_ELDY_ENABLE_PERSONALIZED) ? (empty($conf->global->THEME_ELDY_BACKBODY) ? $colorbackbody : $conf->global->THEME_ELDY_BACKBODY) : (empty($user->conf->THEME_ELDY_BACKBODY) ? $colorbackbody : $user->conf->THEME_ELDY_BACKBODY); $colortexttitlenotab = empty($user->conf->THEME_ELDY_ENABLE_PERSONALIZED) ? (empty($conf->global->THEME_ELDY_TEXTTITLENOTAB) ? $colortexttitlenotab : $conf->global->THEME_ELDY_TEXTTITLENOTAB) : (empty($user->conf->THEME_ELDY_TEXTTITLENOTAB) ? $colortexttitlenotab : $user->conf->THEME_ELDY_TEXTTITLENOTAB); $colortexttitle = empty($user->conf->THEME_ELDY_ENABLE_PERSONALIZED) ? (empty($conf->global->THEME_ELDY_TEXTTITLE) ? $colortexttitle : $conf->global->THEME_ELDY_TEXTTITLE) : (empty($user->conf->THEME_ELDY_TEXTTITLE) ? $colortexttitle : $user->conf->THEME_ELDY_TEXTTITLE); +$colortexttitlelink = empty($user->conf->THEME_ELDY_ENABLE_PERSONALIZED) ? (empty($conf->global->THEME_ELDY_TEXTTITLELINK) ? $colortexttitlelink : $conf->global->THEME_ELDY_TEXTTITLELINK) : (empty($user->conf->THEME_ELDY_TEXTTITLELINK) ? $colortexttitlelink : $user->conf->THEME_ELDY_TEXTTITLELINK); $colortext = empty($user->conf->THEME_ELDY_ENABLE_PERSONALIZED) ? (empty($conf->global->THEME_ELDY_TEXT) ? $colortext : $conf->global->THEME_ELDY_TEXT) : (empty($user->conf->THEME_ELDY_TEXT) ? $colortext : $user->conf->THEME_ELDY_TEXT); $colortextlink = empty($user->conf->THEME_ELDY_ENABLE_PERSONALIZED) ? (empty($conf->global->THEME_ELDY_TEXTLINK) ? $colortextlink : $conf->global->THEME_ELDY_TEXTLINK) : (empty($user->conf->THEME_ELDY_TEXTLINK) ? $colortextlink : $user->conf->THEME_ELDY_TEXTLINK); $fontsize = empty($user->conf->THEME_ELDY_ENABLE_PERSONALIZED) ? (empty($conf->global->THEME_ELDY_FONT_SIZE1) ? $fontsize : $conf->global->THEME_ELDY_FONT_SIZE1) : (empty($user->conf->THEME_ELDY_FONT_SIZE1) ? $fontsize : $user->conf->THEME_ELDY_FONT_SIZE1); From 44bafb7225555aff485d418b6440ee01a82f694a Mon Sep 17 00:00:00 2001 From: Anthony Berton <34568357+bb2a@users.noreply.github.com> Date: Sun, 3 May 2020 10:46:48 +0200 Subject: [PATCH 073/120] Update ihm.php --- htdocs/admin/ihm.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/htdocs/admin/ihm.php b/htdocs/admin/ihm.php index ab67974c920..c83dd83a9c9 100644 --- a/htdocs/admin/ihm.php +++ b/htdocs/admin/ihm.php @@ -121,6 +121,10 @@ if ($action == 'update') $val = (implode(',', (colorStringToArray(GETPOST('THEME_ELDY_TEXTTITLE'), array())))); if ($val == '') dolibarr_del_const($db, 'THEME_ELDY_TEXTTITLE', $conf->entity); else dolibarr_set_const($db, 'THEME_ELDY_TEXTTITLE', $val, 'chaine', 0, '', $conf->entity); + + $val=(implode(',', (colorStringToArray(GETPOST('THEME_ELDY_TEXTTITLELINK'), array())))); + if ($val == '') dolibarr_del_const($db, 'THEME_ELDY_TEXTTITLELINK', $conf->entity); + else dolibarr_set_const($db, 'THEME_ELDY_TEXTTITLELINK', $val, 'chaine', 0, '', $conf->entity); $val = (implode(',', (colorStringToArray(GETPOST('THEME_ELDY_LINEIMPAIR1'), array())))); if ($val == '') dolibarr_del_const($db, 'THEME_ELDY_LINEIMPAIR1', $conf->entity); From 30cb4f0151133291de49b144a2c511a85a3c4bf7 Mon Sep 17 00:00:00 2001 From: Anthony Berton <34568357+bb2a@users.noreply.github.com> Date: Sun, 3 May 2020 10:48:16 +0200 Subject: [PATCH 074/120] Update admin.lang --- htdocs/langs/en_US/admin.lang | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 58e5cecf39d..bb1b56d4465 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -1803,6 +1803,7 @@ TopMenuDisableImages=Hide images in Top menu LeftMenuBackgroundColor=Background color for Left menu BackgroundTableTitleColor=Background color for Table title line BackgroundTableTitleTextColor=Text color for Table title line +BackgroundTableTitleTextlinkColor=Text color for Table title link line BackgroundTableLineOddColor=Background color for odd table lines BackgroundTableLineEvenColor=Background color for even table lines MinimumNoticePeriod=Minimum notice period (Your leave request must be done before this delay) From fdb98dd6ed66396087a139c508310b01a7be5a5f Mon Sep 17 00:00:00 2001 From: Anthony Berton <34568357+bb2a@users.noreply.github.com> Date: Sun, 3 May 2020 10:49:57 +0200 Subject: [PATCH 075/120] Update admin.lang --- htdocs/langs/fr_FR/admin.lang | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/langs/fr_FR/admin.lang b/htdocs/langs/fr_FR/admin.lang index 6363b8b710d..6545b71ede3 100644 --- a/htdocs/langs/fr_FR/admin.lang +++ b/htdocs/langs/fr_FR/admin.lang @@ -1803,6 +1803,7 @@ TopMenuDisableImages=Cacher les images du menu principal LeftMenuBackgroundColor=Couleur de fond pour le menu Gauche BackgroundTableTitleColor=Couleur de fond pour la ligne de titres des liste/tableaux BackgroundTableTitleTextColor=Couleur du texte pour la ligne de titre des tableaux +BackgroundTableTitleTextlinkColor=Couleur du texte pour la ligne de titre lien des tableaux BackgroundTableLineOddColor=Couleur de fond pour les lignes impaires des tables BackgroundTableLineEvenColor=Couleur de fond pour les lignes paires des tales MinimumNoticePeriod=Période de préavis minimum (Votre demande de congé doit être faite avant ce délai) From ef3f121c88a926d7b02a780bceb587bf67abafdf Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Sun, 3 May 2020 08:51:50 +0000 Subject: [PATCH 076/120] Fixing style errors. --- htdocs/admin/ihm.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/admin/ihm.php b/htdocs/admin/ihm.php index c83dd83a9c9..ba849a267e7 100644 --- a/htdocs/admin/ihm.php +++ b/htdocs/admin/ihm.php @@ -121,7 +121,7 @@ if ($action == 'update') $val = (implode(',', (colorStringToArray(GETPOST('THEME_ELDY_TEXTTITLE'), array())))); if ($val == '') dolibarr_del_const($db, 'THEME_ELDY_TEXTTITLE', $conf->entity); else dolibarr_set_const($db, 'THEME_ELDY_TEXTTITLE', $val, 'chaine', 0, '', $conf->entity); - + $val=(implode(',', (colorStringToArray(GETPOST('THEME_ELDY_TEXTTITLELINK'), array())))); if ($val == '') dolibarr_del_const($db, 'THEME_ELDY_TEXTTITLELINK', $conf->entity); else dolibarr_set_const($db, 'THEME_ELDY_TEXTTITLELINK', $val, 'chaine', 0, '', $conf->entity); From fcee3a68f488d337e2d4295658faed84796010c3 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 3 May 2020 13:00:39 +0200 Subject: [PATCH 077/120] Fix sort on file manager of website --- htdocs/theme/eldy/global.inc.php | 5 +++-- htdocs/website/index.php | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index c559fcec9ad..28fa0ecfa65 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -1132,6 +1132,9 @@ table[summary="list_of_modules"] .fa-cog { padding-left: 5px; padding-right: 5px; } + + .hideonsmartphone { display: none; } + .hideonsmartphoneimp { display: none !important; } } /* Force values for small screen 570 */ @@ -1189,8 +1192,6 @@ table[summary="list_of_modules"] .fa-cog { max-width: 138px; /* length of input text in the quick search box when using a smartphone and without dolidroid */ } - .hideonsmartphone { display: none; } - .hideonsmartphoneimp { display: none !important; } .noenlargeonsmartphone { width : 50px !important; display: inline !important; } .maxwidthonsmartphone, #search_newcompany.ui-autocomplete-input { max-width: 100px; } .maxwidth50onsmartphone { max-width: 40px; } diff --git a/htdocs/website/index.php b/htdocs/website/index.php index a617d9ae018..ebfbc7a2ac3 100644 --- a/htdocs/website/index.php +++ b/htdocs/website/index.php @@ -271,7 +271,11 @@ if (GETPOST('optioncontent')) $algo .= 'content'; if (GETPOST('optionsitefiles')) $algo .= 'sitefiles'; if (empty($sortfield)) { - $sortfield = 'pageurl'; $sortorder = 'ASC'; + if ($action == 'file_manager') { + $sortfield='name'; $sortorder = 'ASC'; + } else { + $sortfield = 'pageurl'; $sortorder = 'ASC'; + } } $searchkey = GETPOST('searchstring', 'none'); From a31eaf2eb813fe7ef1b04b940d756b8176018a40 Mon Sep 17 00:00:00 2001 From: Anthony Berton <34568357+bb2a@users.noreply.github.com> Date: Sun, 3 May 2020 13:59:40 +0200 Subject: [PATCH 078/120] Update style.css.php --- htdocs/theme/md/style.css.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index dcc9ce34886..5c3de3d7612 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -130,6 +130,7 @@ $colorbacklinebreak = empty($user->conf->THEME_ELDY_ENABLE_PERSONALIZED) ? (emp $colorbackbody = empty($user->conf->THEME_ELDY_ENABLE_PERSONALIZED) ? (empty($conf->global->THEME_ELDY_BACKBODY) ? $colorbackbody : $conf->global->THEME_ELDY_BACKBODY) : (empty($user->conf->THEME_ELDY_BACKBODY) ? $colorbackbody : $user->conf->THEME_ELDY_BACKBODY); $colortexttitlenotab = empty($user->conf->THEME_ELDY_ENABLE_PERSONALIZED) ? (empty($conf->global->THEME_ELDY_TEXTTITLENOTAB) ? $colortexttitlenotab : $conf->global->THEME_ELDY_TEXTTITLENOTAB) : (empty($user->conf->THEME_ELDY_TEXTTITLENOTAB) ? $colortexttitlenotab : $user->conf->THEME_ELDY_TEXTTITLENOTAB); $colortexttitle = empty($user->conf->THEME_ELDY_ENABLE_PERSONALIZED) ? (empty($conf->global->THEME_ELDY_TEXTTITLE) ? $colortext : $conf->global->THEME_ELDY_TEXTTITLE) : (empty($user->conf->THEME_ELDY_TEXTTITLE) ? $colortexttitle : $user->conf->THEME_ELDY_TEXTTITLE); +$colortexttitlelink = empty($user->conf->THEME_ELDY_ENABLE_PERSONALIZED) ? (empty($conf->global->THEME_ELDY_TEXTTITLELINK) ? $colortexttitlelink : $conf->global->THEME_ELDY_TEXTTITLELINK) : (empty($user->conf->THEME_ELDY_TEXTTITLELINK) ? $colortexttitlelink : $user->conf->THEME_ELDY_TEXTTITLELINK); $colortext = empty($user->conf->THEME_ELDY_ENABLE_PERSONALIZED) ? (empty($conf->global->THEME_ELDY_TEXT) ? $colortext : $conf->global->THEME_ELDY_TEXT) : (empty($user->conf->THEME_ELDY_TEXT) ? $colortext : $user->conf->THEME_ELDY_TEXT); $colortextlink = empty($user->conf->THEME_ELDY_ENABLE_PERSONALIZED) ? (empty($conf->global->THEME_ELDY_TEXTLINK) ? $colortext : $conf->global->THEME_ELDY_TEXTLINK) : (empty($user->conf->THEME_ELDY_TEXTLINK) ? $colortextlink : $user->conf->THEME_ELDY_TEXTLINK); $fontsize = empty($user->conf->THEME_ELDY_ENABLE_PERSONALIZED) ? (empty($conf->global->THEME_ELDY_FONT_SIZE1) ? $fontsize : $conf->global->THEME_ELDY_FONT_SIZE1) : (empty($user->conf->THEME_ELDY_FONT_SIZE1) ? $fontsize : $user->conf->THEME_ELDY_FONT_SIZE1); From dabb2f4ad39e26438d8e528a78124a4eb4f2b41c Mon Sep 17 00:00:00 2001 From: Anthony Berton <34568357+bb2a@users.noreply.github.com> Date: Sun, 3 May 2020 14:01:42 +0200 Subject: [PATCH 079/120] Update theme_vars.inc.php --- htdocs/theme/md/theme_vars.inc.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/theme/md/theme_vars.inc.php b/htdocs/theme/md/theme_vars.inc.php index d15444acb6c..6cdd37fe913 100644 --- a/htdocs/theme/md/theme_vars.inc.php +++ b/htdocs/theme/md/theme_vars.inc.php @@ -65,6 +65,7 @@ $colorbacklinebreak = '214,218,220'; $colorbackbody = '248,248,248'; $colortexttitlenotab = '80,71,5'; $colortexttitle = '20,20,20'; +$colortexttitlelink = '0,0,120'; $colortext = '0,0,0'; $colortextlink = '0,0,120'; $fontsize = '14'; From d81ae29ab7723262a705e20cdf5af5ae3588ae2c Mon Sep 17 00:00:00 2001 From: Anthony Berton <34568357+bb2a@users.noreply.github.com> Date: Sun, 3 May 2020 14:05:18 +0200 Subject: [PATCH 080/120] Update style.css.php --- htdocs/theme/md/style.css.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index 5c3de3d7612..2becbf57324 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -3399,6 +3399,7 @@ tr.liste_titre th, th.liste_titre, tr.liste_titre td, td.liste_titre, form.liste } tr.liste_titre th a, th.liste_titre a, tr.liste_titre td a, td.liste_titre a, form.liste_titre div a, div.liste_titre a { text-shadow: none !important; + color: rgb(); } tr.liste_titre_topborder td { border-top-width: px; From 77cf9fb569ad67aac1df9c2180656f1b396dcd55 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 3 May 2020 14:28:23 +0200 Subject: [PATCH 081/120] Add .dolibarr file into CMS --- htdocs/website/class/website.class.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/htdocs/website/class/website.class.php b/htdocs/website/class/website.class.php index 2691dd9ebfd..6455b7538e0 100644 --- a/htdocs/website/class/website.class.php +++ b/htdocs/website/class/website.class.php @@ -249,6 +249,12 @@ class Website extends CommonObject // } } + if (! $error) { + $stringtodolibarrfile = "# Some properties for Dolibarr web site CMS\n"; + $stringtodolibarrfile .= "noclone=dir_list_to_exclude_when_cloning_separated_with_comma\n"; + file_put_contents('.dolibarr', $stringtodolibarrfile); + } + // Commit or rollback if ($error) { $this->db->rollback(); From da91a857a5fe7566a51236e94e294f8bff43a84f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 3 May 2020 14:49:06 +0200 Subject: [PATCH 082/120] Fix pb of lang subdir in cloning website --- htdocs/core/lib/files.lib.php | 9 ++++++--- htdocs/website/class/website.class.php | 7 ++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index bad0bf9f48c..941cb03d6c4 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -720,10 +720,11 @@ function dol_copy($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1) * @param int $newmask Mask for new file (0 by default means $conf->global->MAIN_UMASK). Example: '0666' * @param int $overwriteifexists Overwrite file if exists (1 by default) * @param array $arrayreplacement Array to use to replace filenames with another one during the copy (works only on file names, not on directory names). + * @param int $excludesubdir 0=Do not exclude subdirectories, 1=Exclude subdirectories, 2=Exclude subdirectories if name is not a 2 chars (used for country codes subdirectories). * @return int <0 if error, 0 if nothing done (all files already exists and overwriteifexists=0), >0 if OK * @see dol_copy() */ -function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement = null) +function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement = null, $excludesubdir = 0) { global $conf; @@ -759,8 +760,10 @@ function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayrep { if (is_dir($ossrcfile."/".$file)) { - //var_dump("xxx dolCopyDir $srcfile/$file, $destfile/$file, $newmask, $overwriteifexists"); - $tmpresult = dolCopyDir($srcfile."/".$file, $destfile."/".$file, $newmask, $overwriteifexists, $arrayreplacement); + if (empty($excludesubdir) || ($excludesubdir == 2 && strlen($file) == 2)) { + //var_dump("xxx dolCopyDir $srcfile/$file, $destfile/$file, $newmask, $overwriteifexists"); + $tmpresult = dolCopyDir($srcfile."/".$file, $destfile."/".$file, $newmask, $overwriteifexists, $arrayreplacement, $excludesubdir); + } } else { diff --git a/htdocs/website/class/website.class.php b/htdocs/website/class/website.class.php index 6455b7538e0..4edd2367758 100644 --- a/htdocs/website/class/website.class.php +++ b/htdocs/website/class/website.class.php @@ -251,8 +251,9 @@ class Website extends CommonObject if (! $error) { $stringtodolibarrfile = "# Some properties for Dolibarr web site CMS\n"; - $stringtodolibarrfile .= "noclone=dir_list_to_exclude_when_cloning_separated_with_comma\n"; - file_put_contents('.dolibarr', $stringtodolibarrfile); + $stringtodolibarrfile .= "param=value\n"; + //print $conf->website->dir_output.'/'.$this->ref.'/.dolibarr';exit; + file_put_contents($conf->website->dir_output.'/'.$this->ref.'/.dolibarr', $stringtodolibarrfile); } // Commit or rollback @@ -674,7 +675,7 @@ class Website extends CommonObject if (!$error) { - dolCopyDir($pathofwebsiteold, $pathofwebsitenew, $conf->global->MAIN_UMASK, 0); + dolCopyDir($pathofwebsiteold, $pathofwebsitenew, $conf->global->MAIN_UMASK, 0, null, 2); // Check symlink to medias and restore it if ko $pathtomedias = DOL_DATA_ROOT.'/medias'; // Target From d27ccb02333dfdf9513de33f24d3f478df9a952a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 3 May 2020 14:58:53 +0200 Subject: [PATCH 083/120] Fix pb of lang subdir in exporting website --- htdocs/website/class/website.class.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/htdocs/website/class/website.class.php b/htdocs/website/class/website.class.php index 4edd2367758..be91f6640a1 100644 --- a/htdocs/website/class/website.class.php +++ b/htdocs/website/class/website.class.php @@ -934,30 +934,34 @@ class Website extends CommonObject $arrayreplacementincss['file=logos%2Fthumbs%2F'.$mysoc->logo] = "file=logos%2Fthumbs%2F__LOGO_KEY__"; } + // Create output directories + dol_syslog("Create containers dir"); + dol_mkdir($conf->website->dir_temp.'/'.$website->ref.'/containers'); + dol_mkdir($conf->website->dir_temp.'/'.$website->ref.'/medias/image/websitekey'); + dol_mkdir($conf->website->dir_temp.'/'.$website->ref.'/medias/js/websitekey'); + + // Copy files into 'containers' $srcdir = $conf->website->dir_output.'/'.$website->ref; $destdir = $conf->website->dir_temp.'/'.$website->ref.'/containers'; - // Create containers dir - dol_syslog("Create containers dir"); - dol_mkdir($conf->website->dir_temp.'/'.$website->ref.'/containers'); - - // Copy files into medias dol_syslog("Copy content from ".$srcdir." into ".$destdir); - dolCopyDir($srcdir, $destdir, 0, 1, $arrayreplacementinfilename); + dolCopyDir($srcdir, $destdir, 0, 1, $arrayreplacementinfilename, 2); + // Copy files into medias/image $srcdir = DOL_DATA_ROOT.'/medias/image/'.$website->ref; $destdir = $conf->website->dir_temp.'/'.$website->ref.'/medias/image/websitekey'; dol_syslog("Copy content from ".$srcdir." into ".$destdir); dolCopyDir($srcdir, $destdir, 0, 1, $arrayreplacementinfilename); + // Copy files into medias/js $srcdir = DOL_DATA_ROOT.'/medias/js/'.$website->ref; $destdir = $conf->website->dir_temp.'/'.$website->ref.'/medias/js/websitekey'; - // Copy containers files dol_syslog("Copy content from ".$srcdir." into ".$destdir); dolCopyDir($srcdir, $destdir, 0, 1, $arrayreplacementinfilename); + // Make some replacement into some files $cssindestdir = $conf->website->dir_temp.'/'.$website->ref.'/containers/styles.css.php'; dolReplaceInFile($cssindestdir, $arrayreplacementincss); From f42492764d9a6e8821cf6938025c68426dadf3dc Mon Sep 17 00:00:00 2001 From: Anthony Berton Date: Sun, 3 May 2020 17:16:25 +0200 Subject: [PATCH 084/120] Update html.formproduct.class.php DEFAULT_WAREHOUSE is not select in sherch --- htdocs/product/class/html.formproduct.class.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/htdocs/product/class/html.formproduct.class.php b/htdocs/product/class/html.formproduct.class.php index efde996b927..d6ae705b651 100644 --- a/htdocs/product/class/html.formproduct.class.php +++ b/htdocs/product/class/html.formproduct.class.php @@ -253,10 +253,12 @@ class FormProduct $comboenhancement = ajax_combobox($htmlname, $events); $out .= $comboenhancement; } - - if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_WAREHOUSE)) $selected = $conf->global->MAIN_DEFAULT_WAREHOUSE; - if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_WAREHOUSE_USER)) $selected = $user->fk_warehouse; - + + if ($htmlname != 'search_warehouse'){ + if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_WAREHOUSE)) $selected = $conf->global->MAIN_DEFAULT_WAREHOUSE; + if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_WAREHOUSE_USER)) $selected = $user->fk_warehouse; + } + $out .= ''; if ($empty) $out .= ''; foreach ($this->cache_warehouses as $id => $arraytypes) From 33669b6fd8e2300c64e3a6abec008309915739a6 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 3 May 2020 21:15:23 +0200 Subject: [PATCH 086/120] Update html.formproduct.class.php --- htdocs/product/class/html.formproduct.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/product/class/html.formproduct.class.php b/htdocs/product/class/html.formproduct.class.php index 4887f749d60..0eeddd15c07 100644 --- a/htdocs/product/class/html.formproduct.class.php +++ b/htdocs/product/class/html.formproduct.class.php @@ -254,7 +254,7 @@ class FormProduct $out .= $comboenhancement; } - if ($htmlname != 'search_warehouse'){ + if (strpos($htmlname, 'search_') !== 0) { if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_WAREHOUSE)) $selected = $conf->global->MAIN_DEFAULT_WAREHOUSE; if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_WAREHOUSE_USER)) $selected = $user->fk_warehouse; } From 2eb027833c644a2e946f286f38bad9703c1bf642 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 3 May 2020 21:25:49 +0200 Subject: [PATCH 087/120] Update card.php --- htdocs/contrat/card.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/contrat/card.php b/htdocs/contrat/card.php index 111a446d9ae..e898ef9e8f4 100644 --- a/htdocs/contrat/card.php +++ b/htdocs/contrat/card.php @@ -523,6 +523,7 @@ if (empty($reshook)) $desc = $prod->description; if (!empty($product_desc) && !empty($conf->global->MAIN_NO_CONCAT_DESCRIPTION)) $desc = $product_desc; else $desc = dol_concatdesc($desc, $product_desc, '', !empty($conf->global->MAIN_CHANGE_ORDER_CONCAT_DESCRIPTION)); + $fk_unit = $prod->fk_unit; } else From ab20b5cb616f1e10add360171fd6e84a652072c9 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Sun, 3 May 2020 19:26:35 +0000 Subject: [PATCH 088/120] Fixing style errors. --- htdocs/contrat/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/contrat/card.php b/htdocs/contrat/card.php index e898ef9e8f4..21d46fb2974 100644 --- a/htdocs/contrat/card.php +++ b/htdocs/contrat/card.php @@ -523,7 +523,7 @@ if (empty($reshook)) $desc = $prod->description; if (!empty($product_desc) && !empty($conf->global->MAIN_NO_CONCAT_DESCRIPTION)) $desc = $product_desc; else $desc = dol_concatdesc($desc, $product_desc, '', !empty($conf->global->MAIN_CHANGE_ORDER_CONCAT_DESCRIPTION)); - + $fk_unit = $prod->fk_unit; } else From 4d6a45d491d3ad303cb6b060053303a44d216f6a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 3 May 2020 22:47:43 +0200 Subject: [PATCH 089/120] Major doxygen fix --- dev/setup/codesniffer/ruleset.xml | 62 +++------ htdocs/bom/class/bom.class.php | 1 - htdocs/core/class/html.formcategory.class.php | 4 + htdocs/core/class/html.formcompany.class.php | 4 + .../core/filemanagerdol/connectors/php/io.php | 31 ++++- .../modules/product/modules_product.class.php | 4 +- htdocs/ecm/class/ecmfiles.class.php | 4 +- htdocs/install/upgrade2.php | 11 +- .../template/class/myobject.class.php | 2 +- htdocs/mrp/class/mo.class.php | 2 +- htdocs/product/class/product.class.php | 16 +-- htdocs/product/index.php | 7 +- htdocs/public/stripe/confirm_payment.php | 4 +- htdocs/resource/class/dolresource.class.php | 6 +- htdocs/ticket/class/utils_diff.class.php | 125 ++++++++---------- htdocs/webservices/server_other.php | 7 +- htdocs/zapier/class/hook.class.php | 1 - test/phpunit/AccountingAccountTest.php | 12 +- test/phpunit/ActionCommTest.php | 12 +- test/phpunit/AdherentTest.php | 12 +- test/phpunit/AdminLibTest.php | 12 +- test/phpunit/BOMTest.php | 12 +- test/phpunit/BankAccountTest.php | 12 +- test/phpunit/BuildDocTest.php | 12 +- test/phpunit/CMailFileTest.php | 12 +- test/phpunit/CategorieTest.php | 12 +- test/phpunit/ChargeSocialesTest.php | 12 +- test/phpunit/CodingPhpTest.php | 12 +- test/phpunit/CodingSqlTest.php | 12 +- test/phpunit/CommandeFournisseurTest.php | 12 +- test/phpunit/CommandeTest.php | 12 +- test/phpunit/CommonInvoiceTest.php | 12 +- test/phpunit/CommonObjectTest.php | 12 +- test/phpunit/CompanyBankAccountTest.php | 12 +- test/phpunit/CompanyLibTest.php | 12 +- test/phpunit/ContactTest.php | 12 +- test/phpunit/ContratTest.php | 12 +- test/phpunit/CoreTest.php | 12 +- test/phpunit/DateLibTest.php | 12 +- test/phpunit/DateLibTzFranceTest.php | 12 +- test/phpunit/DiscountTest.php | 12 +- test/phpunit/EntrepotTest.php | 12 +- test/phpunit/ExpenseReportTest.php | 12 +- test/phpunit/ExportTest.php | 12 +- test/phpunit/FactureFournisseurTest.php | 12 +- test/phpunit/FactureRecTest.php | 12 +- test/phpunit/FactureTest.php | 12 +- test/phpunit/FactureTestRounding.php | 12 +- test/phpunit/FichinterTest.php | 12 +- test/phpunit/FilesLibTest.php | 12 +- test/phpunit/FormAdminTest.php | 12 +- test/phpunit/FormTest.php | 12 +- test/phpunit/Functions2LibTest.php | 12 +- test/phpunit/FunctionsLibTest.php | 12 +- test/phpunit/GetUrlLibTest.php | 12 +- test/phpunit/HolidayTest.php | 12 +- test/phpunit/ImagesLibTest.php | 12 +- test/phpunit/ImportTest.php | 12 +- test/phpunit/JsonLibTest.php | 12 +- test/phpunit/LangTest.php | 12 +- test/phpunit/LesscTest.php | 12 +- test/phpunit/LoanTest.php | 12 +- test/phpunit/MarginsLibTest.php | 12 +- test/phpunit/ModulesTest.php | 12 +- test/phpunit/MouvementStockTest.php | 12 +- test/phpunit/NumberingModulesTest.php | 12 +- test/phpunit/PaypalTest.php | 12 +- test/phpunit/PdfDocTest.php | 12 +- test/phpunit/PgsqlTest.php | 12 +- test/phpunit/PricesTest.php | 12 +- test/phpunit/ProductTest.php | 13 +- test/phpunit/ProjectTest.php | 12 +- test/phpunit/PropalTest.php | 12 +- test/phpunit/RestAPIDocumentTest.php | 12 +- test/phpunit/RestAPIUserTest.php | 12 +- test/phpunit/ScriptsTest.php | 12 +- test/phpunit/SecurityTest.php | 12 +- test/phpunit/SocieteTest.php | 12 +- test/phpunit/SupplierProposalTest.php | 12 +- test/phpunit/TicketTest.php | 12 +- test/phpunit/UserGroupTest.php | 12 +- test/phpunit/UserTest.php | 12 +- test/phpunit/UtilsTest.php | 12 +- test/phpunit/WebservicesOrdersTest.php | 12 +- test/phpunit/WebservicesOtherTest.php | 12 +- test/phpunit/WebservicesProductsTest.php | 13 +- test/phpunit/WebservicesThirdpartyTest.php | 12 +- test/phpunit/WebservicesUserTest.php | 12 +- test/phpunit/XCalLibTest.php | 12 +- 89 files changed, 871 insertions(+), 286 deletions(-) diff --git a/dev/setup/codesniffer/ruleset.xml b/dev/setup/codesniffer/ruleset.xml index 421acfeed1f..ad26c7f0bdc 100644 --- a/dev/setup/codesniffer/ruleset.xml +++ b/dev/setup/codesniffer/ruleset.xml @@ -187,6 +187,13 @@ + + + + + @@ -222,23 +229,16 @@ + - - - - - - 0 - + - - 0 - + 0 @@ -247,67 +247,38 @@ 0 - 0 - 0 - 0 - - - - - - 5 - - - - + 0 - 0 - - - - 0 - + - 0 + + + + 0 @@ -344,6 +315,7 @@ 0 + 0 diff --git a/htdocs/bom/class/bom.class.php b/htdocs/bom/class/bom.class.php index a9ed7ee3a00..c2c18dae6e5 100644 --- a/htdocs/bom/class/bom.class.php +++ b/htdocs/bom/class/bom.class.php @@ -979,7 +979,6 @@ class BOM extends CommonObject * * @return int 0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK) */ - //public function doScheduledJob($param1, $param2, ...) public function doScheduledJob() { global $conf, $langs; diff --git a/htdocs/core/class/html.formcategory.class.php b/htdocs/core/class/html.formcategory.class.php index 4dd8bed247b..41e39cc93a2 100644 --- a/htdocs/core/class/html.formcategory.class.php +++ b/htdocs/core/class/html.formcategory.class.php @@ -23,6 +23,10 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php'; + +/** + * Class to manage forms for categories + */ class FormCategory extends Form { /** diff --git a/htdocs/core/class/html.formcompany.class.php b/htdocs/core/class/html.formcompany.class.php index 5f32f5063d6..6fb02454311 100644 --- a/htdocs/core/class/html.formcompany.class.php +++ b/htdocs/core/class/html.formcompany.class.php @@ -32,6 +32,10 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php'; + +/** + * Class of forms component to manage companies + */ class FormCompany extends Form { diff --git a/htdocs/core/filemanagerdol/connectors/php/io.php b/htdocs/core/filemanagerdol/connectors/php/io.php index 68aa46ef9fb..2a9ac9f146b 100644 --- a/htdocs/core/filemanagerdol/connectors/php/io.php +++ b/htdocs/core/filemanagerdol/connectors/php/io.php @@ -236,8 +236,11 @@ function GetRootPath() return substr($sRealPath, 0, $position); } -// Emulate the asp Server.mapPath function. -// given an url path return the physical directory that it corresponds to +/** + * Emulate the asp Server.mapPath function. + * @param string $path given an url path return the physical directory that it corresponds to + * @return string Path + */ function Server_MapPath($path) { // This function is available only for Apache @@ -338,7 +341,12 @@ function GetCurrentFolder() return $sCurrentFolder; } -// Do a cleanup of the folder name to avoid possible problems +/** + * Do a cleanup of the folder name to avoid possible problems + * + * @param string $sNewFolderName Folder + * @return string Folder sanitized + */ function SanitizeFolderName($sNewFolderName) { $sNewFolderName = stripslashes($sNewFolderName); @@ -349,7 +357,12 @@ function SanitizeFolderName($sNewFolderName) return $sNewFolderName; } -// Do a cleanup of the file name to avoid possible problems +/** + * Do a cleanup of the file name to avoid possible problems + * + * @param string $sNewFileName Folder + * @return string Folder sanitized + */ function SanitizeFileName($sNewFileName) { global $Config; @@ -366,7 +379,15 @@ function SanitizeFileName($sNewFileName) return $sNewFileName; } -// This is the function that sends the results of the uploading process. +/** + * This is the function that sends the results of the uploading process. + * + * @param string $errorNumber errorNumber + * @param string $fileUrl fileUrl + * @param string $fileName fileName + * @param string $customMsg customMsg + * @return void + */ function SendUploadResults($errorNumber, $fileUrl = '', $fileName = '', $customMsg = '') { // Minified version of the document.domain automatic fix script (#1919). diff --git a/htdocs/core/modules/product/modules_product.class.php b/htdocs/core/modules/product/modules_product.class.php index 5031b4079e4..80bc9f7ce0a 100644 --- a/htdocs/core/modules/product/modules_product.class.php +++ b/htdocs/core/modules/product/modules_product.class.php @@ -61,6 +61,9 @@ abstract class ModelePDFProduct extends CommonDocGenerator } } +/** + * Class template for classes of numbering product + */ abstract class ModeleProductCode { /** @@ -97,7 +100,6 @@ abstract class ModeleProductCode */ public function getExample($langs) { - $langs->load("bills"); return $langs->trans("NoExample"); } diff --git a/htdocs/ecm/class/ecmfiles.class.php b/htdocs/ecm/class/ecmfiles.class.php index 0c7c4c4cebb..6921b8aabd6 100644 --- a/htdocs/ecm/class/ecmfiles.class.php +++ b/htdocs/ecm/class/ecmfiles.class.php @@ -772,7 +772,6 @@ class EcmFiles extends CommonObject if (!empty($conf->dol_no_mouse_hover)) $notooltip = 1; // Force disable tooltips $result = ''; - $companylink = ''; $label = ''.$langs->trans("MyModule").''; $label .= '
'; @@ -867,6 +866,9 @@ class EcmFiles extends CommonObject } +/** + * Class of an index line of a document + */ class EcmfilesLine { /** diff --git a/htdocs/install/upgrade2.php b/htdocs/install/upgrade2.php index 0fb36466a02..765a8796a76 100644 --- a/htdocs/install/upgrade2.php +++ b/htdocs/install/upgrade2.php @@ -1,4 +1,6 @@ * Copyright (C) 2005-2018 Laurent Destailleur * Copyright (C) 2005-2011 Regis Houssin @@ -1185,8 +1187,13 @@ function migrate_contracts_date1($db, $langs, $conf) print ''; } -/* - * Mise a jour date contrat avec date min effective mise en service si inferieur +/** + * Update contracts with date min real if service date is lower + * + * @param DoliDB $db Database handler + * @param Translate $langs Language + * @param Conf $conf Conf + * @return void */ function migrate_contracts_date2($db, $langs, $conf) { diff --git a/htdocs/modulebuilder/template/class/myobject.class.php b/htdocs/modulebuilder/template/class/myobject.class.php index af707c3c87d..fad19564fdc 100644 --- a/htdocs/modulebuilder/template/class/myobject.class.php +++ b/htdocs/modulebuilder/template/class/myobject.class.php @@ -1047,10 +1047,10 @@ class MyObject extends CommonObject /** * Action executed by scheduler * CAN BE A CRON TASK. In such a case, parameters come from the schedule job setup field 'Parameters' + * Use public function doScheduledJob($param1, $param2, ...) to get parameters * * @return int 0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK) */ - //public function doScheduledJob($param1, $param2, ...) public function doScheduledJob() { global $conf, $langs; diff --git a/htdocs/mrp/class/mo.class.php b/htdocs/mrp/class/mo.class.php index 65ba9597b8a..42d97ee81d9 100644 --- a/htdocs/mrp/class/mo.class.php +++ b/htdocs/mrp/class/mo.class.php @@ -1226,10 +1226,10 @@ class Mo extends CommonObject /** * Action executed by scheduler * CAN BE A CRON TASK. In such a case, parameters come from the schedule job setup field 'Parameters' + * Use public function doScheduledJob($param1, $param2, ...) to get parameters * * @return int 0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK) */ - //public function doScheduledJob($param1, $param2, ...) public function doScheduledJob() { global $conf, $langs; diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 0db9a411b19..2499ee958de 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -1443,14 +1443,14 @@ class Product extends CommonObject } } - /* - * Sets an accountancy code for a product. - * Also calls PRODUCT_MODIFY trigger when modified - * - * @param string $type It can be 'buy', 'buy_intra', 'buy_export', 'sell', 'sell_intra' or 'sell_export' - * @param string $value Accountancy code - * @return int <0 KO >0 OK - */ + /** + * Sets an accountancy code for a product. + * Also calls PRODUCT_MODIFY trigger when modified + * + * @param string $type It can be 'buy', 'buy_intra', 'buy_export', 'sell', 'sell_intra' or 'sell_export' + * @param string $value Accountancy code + * @return int <0 KO >0 OK + */ public function setAccountancyCode($type, $value) { global $user, $langs, $conf; diff --git a/htdocs/product/index.php b/htdocs/product/index.php index 4d0f2e220b7..3067cc63733 100644 --- a/htdocs/product/index.php +++ b/htdocs/product/index.php @@ -101,7 +101,7 @@ if (!empty($conf->global->MAIN_SEARCH_FORM_ON_HOME_AREAS)) // This is useles foreach ($listofsearchfields as $key => $value) { if ($i == 0) print '
'; - print ''; + print ''; print ''; if ($i == 0) print ''; print ''; @@ -201,7 +201,7 @@ if (!empty($conf->categorie->enabled) && !empty($conf->global->CATEGORY_GRAPHSTA print '
'; print '
'.$langs->trans("Table").''.$langs->trans("URL").''.$langs->trans("QR").'
'.$langs->trans("BackgroundTableTitleTextlinkColor").''; + if ($edit) + { + print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_TEXTTITLELINK, array()), ''), 'THEME_ELDY_TEXTTITLELINK', 'formcolor', 1).' '; + } + else + { + print $formother->showColor($conf->global->THEME_ELDY_TEXTTITLELINK, $langs->trans("Default")); + } + print '   ('.$langs->trans("Default").': '.$default.') '; + print $form->textwithpicto('', $langs->trans("NotSupportedByAllThemes").', '.$langs->trans("PressF5AfterChangingThis")); + print ''; + print '
'.$langs->trans("Search").'
'; print ''; - print ''; } diff --git a/htdocs/takepos/auto_order.php b/htdocs/takepos/public/auto_order.php similarity index 83% rename from htdocs/takepos/auto_order.php rename to htdocs/takepos/public/auto_order.php index 5305b4da81f..c97edfdc0e7 100644 --- a/htdocs/takepos/auto_order.php +++ b/htdocs/takepos/public/auto_order.php @@ -16,14 +16,14 @@ */ /** - * \file htdocs/takepos/auto_order.php + * \file htdocs/takepos/public/auto_order.php * \ingroup takepos * \brief Public orders for customers */ if (!defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session) -if (!defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +if (!defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip $_SESSION["basiclayout"] = 1; $_SESSION["publicterminal"] = true; // Is a public customer -require 'phone.php'; +require '../phone.php'; From abd37c78f92dbd968982700e574348d1d853638c Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 4 May 2020 17:07:18 +0200 Subject: [PATCH 095/120] Fix responsive --- htdocs/contrat/index.php | 8 ++++---- htdocs/contrat/list.php | 7 +++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/htdocs/contrat/index.php b/htdocs/contrat/index.php index 1f3a9fa5b99..2a7c9c0d91a 100644 --- a/htdocs/contrat/index.php +++ b/htdocs/contrat/index.php @@ -360,7 +360,7 @@ if ($result) $obj = $db->fetch_object($result); print ''; - print ''; - print ''; - print ''; - print ''; + + // Ref if (!empty($arrayfields['c.ref']['checked'])) { - print ''; } + if (!empty($arrayfields['c.ref_customer']['checked'])) { print ''; From 821e11ca3c0ba8bc15690835cb25aac56dd917bd Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 4 May 2020 17:13:31 +0200 Subject: [PATCH 096/120] Look and feel v12 --- htdocs/core/ajax/selectsearchbox.php | 4 ++-- htdocs/langs/en_US/main.lang | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/core/ajax/selectsearchbox.php b/htdocs/core/ajax/selectsearchbox.php index cd019b9ce38..2f8ad4ab5f7 100644 --- a/htdocs/core/ajax/selectsearchbox.php +++ b/htdocs/core/ajax/selectsearchbox.php @@ -56,7 +56,7 @@ $arrayresult = array(); if (!empty($conf->adherent->enabled) && empty($conf->global->MAIN_SEARCHFORM_ADHERENT_DISABLED) && $user->rights->adherent->lire) { - $arrayresult['searchintomember'] = array('position'=>8, 'shortcut'=>'M', 'img'=>'object_user', 'label'=>$langs->trans("SearchIntoMembers", $search_boxvalue), 'text'=>img_picto('', 'object_user').' '.$langs->trans("SearchIntoMembers", $search_boxvalue), 'url'=>DOL_URL_ROOT.'/adherents/list.php'.($search_boxvalue ? '?sall='.urlencode($search_boxvalue) : '')); + $arrayresult['searchintomember'] = array('position'=>8, 'shortcut'=>'M', 'img'=>'object_member', 'label'=>$langs->trans("SearchIntoMembers", $search_boxvalue), 'text'=>img_picto('', 'object_member').' '.$langs->trans("SearchIntoMembers", $search_boxvalue), 'url'=>DOL_URL_ROOT.'/adherents/list.php'.($search_boxvalue ? '?sall='.urlencode($search_boxvalue) : '')); } if (((!empty($conf->societe->enabled) && (empty($conf->global->SOCIETE_DISABLE_PROSPECTS) || empty($conf->global->SOCIETE_DISABLE_CUSTOMERS))) || !empty($conf->fournisseur->enabled)) && empty($conf->global->MAIN_SEARCHFORM_SOCIETE_DISABLED) && $user->rights->societe->lire) @@ -86,7 +86,7 @@ if (!empty($conf->projet->enabled) && empty($conf->global->MAIN_SEARCHFORM_PROJE } if (!empty($conf->projet->enabled) && empty($conf->global->MAIN_SEARCHFORM_TASK_DISABLED) && $user->rights->projet->lire) { - $arrayresult['searchintotasks'] = array('position'=>45, 'img'=>'object_task', 'label'=>$langs->trans("SearchIntoTasks", $search_boxvalue), 'text'=>img_picto('', 'object_task').' '.$langs->trans("SearchIntoTasks", $search_boxvalue), 'url'=>DOL_URL_ROOT.'/projet/tasks/list.php'.($search_boxvalue ? '?search_all='.urlencode($search_boxvalue) : '')); + $arrayresult['searchintotasks'] = array('position'=>45, 'img'=>'object_projecttask', 'label'=>$langs->trans("SearchIntoTasks", $search_boxvalue), 'text'=>img_picto('', 'object_projecttask').' '.$langs->trans("SearchIntoTasks", $search_boxvalue), 'url'=>DOL_URL_ROOT.'/projet/tasks/list.php'.($search_boxvalue ? '?search_all='.urlencode($search_boxvalue) : '')); } if (!empty($conf->propal->enabled) && empty($conf->global->MAIN_SEARCHFORM_CUSTOMER_PROPAL_DISABLED) && $user->rights->propal->lire) diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang index 38a4bcd2bad..fb0808e0953 100644 --- a/htdocs/langs/en_US/main.lang +++ b/htdocs/langs/en_US/main.lang @@ -959,7 +959,7 @@ SearchIntoCustomerInvoices=Customer invoices SearchIntoSupplierInvoices=Vendor invoices SearchIntoCustomerOrders=Sales orders SearchIntoSupplierOrders=Purchase orders -SearchIntoCustomerProposals=Customer proposals +SearchIntoCustomerProposals=Commercial proposals SearchIntoSupplierProposals=Vendor proposals SearchIntoInterventions=Interventions SearchIntoContracts=Contracts From 5e4ef9266ee33bf3df042ed09091e98937686186 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 4 May 2020 20:30:02 +0200 Subject: [PATCH 097/120] Fix update template to use for notifications --- htdocs/admin/notification.php | 101 +++++++++++++++++++++++++++------- htdocs/core/lib/admin.lib.php | 10 +++- 2 files changed, 88 insertions(+), 23 deletions(-) diff --git a/htdocs/admin/notification.php b/htdocs/admin/notification.php index 97b09861a42..ba92aa1ec21 100644 --- a/htdocs/admin/notification.php +++ b/htdocs/admin/notification.php @@ -34,10 +34,12 @@ require_once DOL_DOCUMENT_ROOT.'/core/triggers/interface_50_modNotification_Noti $langs->loadLangs(array('admin', 'other', 'orders', 'propal', 'bills', 'errors', 'mails')); // Security check -if (!$user->admin) - accessforbidden(); +if (!$user->admin) { + accessforbidden(); +} $action = GETPOST('action', 'aZ09'); +$error = 0; /* @@ -45,27 +47,48 @@ $action = GETPOST('action', 'aZ09'); */ // Action to update or add a constant -if ($action == 'update' || $action == 'add') +if ($action == 'settemplates') { - $constlineid = GETPOST('rowid', 'int'); - $constname = GETPOST('constname', 'alpha'); + $db->begin(); - $constvalue = (GETPOSTISSET('constvalue_'.$constname) ? GETPOST('constvalue_'.$constname, 'alpha') : GETPOST('constvalue')); - $consttype = (GETPOSTISSET('consttype_'.$constname) ? GETPOST('consttype_'.$constname, 'alphanohtml') : GETPOST('consttype')); - $constnote = (GETPOSTISSET('constnote_'.$constname) ? GETPOST('constnote_'.$constname, 'none') : GETPOST('constnote')); + if (!$error && is_array($_POST)) + { + $reg = array(); + foreach ($_POST as $key => $val) + { + if (!preg_match('/^constvalue_(.*)_TEMPLATE/', $key, $reg)) continue; - $typetouse = empty($oldtypetonewone[$consttype]) ? $consttype : $oldtypetonewone[$consttype]; + $triggername = $reg[1]; + $constvalue = GETPOST($key, 'alpha'); + $consttype = 'emailtemplate:xxx'; + $tmparray=explode(':', $constvalue); + if (! empty($tmparray[0]) && ! empty($tmparray[1])) { + $constvalue = $tmparray[0]; + $consttype = 'emailtemplate:'.$tmparray[1]; + //var_dump($constvalue); + //var_dump($consttype); + $res = dolibarr_set_const($db, $triggername.'_TEMPLATE', $constvalue, $consttype, 0, '', $conf->entity); + if ($res < 0) { + $error++; + break; + } + } else { + $res = dolibarr_del_const($db, $triggername.'_TEMPLATE', $conf->entity); + } + } + } - $res = dolibarr_set_const($db, $constname, $constvalue, $typetouse, 0, $constnote, $conf->entity); - - if (!$res > 0) $error++; if (!$error) { + $db->commit(); + setEventMessages($langs->trans("SetupSaved"), null, 'mesgs'); } else { + $db->rollback(); + setEventMessages($langs->trans("Error"), null, 'errors'); } } @@ -74,12 +97,31 @@ if ($action == 'setvalue' && $user->admin) { $db->begin(); - $result = dolibarr_set_const($db, "NOTIFICATION_EMAIL_FROM", $_POST["email_from"], 'chaine', 0, '', $conf->entity); + $result = dolibarr_set_const($db, "NOTIFICATION_EMAIL_FROM", GETPOST("email_from", "none"), 'chaine', 0, '', $conf->entity); if ($result < 0) $error++; + + if (!$error) + { + $db->commit(); + + setEventMessages($langs->trans("SetupSaved"), null, 'mesgs'); + } + else + { + $db->rollback(); + + setEventMessages($langs->trans("Error"), null, 'errors'); + } +} + + +if ($action == 'setfixednotif' && $user->admin) +{ + $db->begin(); + if (!$error && is_array($_POST)) { - //var_dump($_POST); $reg = array(); foreach ($_POST as $key => $val) { @@ -101,7 +143,7 @@ if ($action == 'setvalue' && $user->admin) } elseif (preg_match('/^NOTIF_(.*)_new_key/', $key, $reg)) { - // Add a new entry + // Add a new entry $newkey = 'NOTIFICATION_FIXEDEMAIL_'.$reg[1].'_THRESHOLD_HIGHER_'.((int) GETPOST($shortkey.'_amount')); $newval = GETPOST($shortkey.'_key'); } @@ -168,9 +210,18 @@ print ''; print ''; print '
'.$langs->trans("Categories").'
'; + print '
'; $sql = "SELECT c.label, count(*) as nb"; $sql .= " FROM ".MAIN_DB_PREFIX."categorie_product as cs"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."categorie as c ON cs.fk_categorie = c.rowid"; @@ -413,7 +413,7 @@ llxFooter(); $db->close(); -/* +/** * Print html activity for product type * * @param int $product_type Type of product @@ -422,7 +422,6 @@ $db->close(); function activitytrim($product_type) { global $conf, $langs, $db; - global $bc; // We display the last 3 years $yearofbegindate = date('Y', dol_time_plus_duree(time(), -3, "y")); diff --git a/htdocs/public/stripe/confirm_payment.php b/htdocs/public/stripe/confirm_payment.php index 25cb358ccea..9a45a2cbeec 100644 --- a/htdocs/public/stripe/confirm_payment.php +++ b/htdocs/public/stripe/confirm_payment.php @@ -129,8 +129,8 @@ try { )); } -/* - * generate payment response +/** + * Generate payment response * * @param \Stripe\PaymentIntent $intent PaymentIntent * @return void diff --git a/htdocs/resource/class/dolresource.class.php b/htdocs/resource/class/dolresource.class.php index 4cda97b39d1..1b4223e1fff 100644 --- a/htdocs/resource/class/dolresource.class.php +++ b/htdocs/resource/class/dolresource.class.php @@ -871,10 +871,12 @@ class Dolresource extends CommonObject return $resources; } - /* + /** * Return an int number of resources linked to the element * - * @return int + * @param string $element Element type + * @param int $element_id Element id + * @return int Nb of resources loaded */ public function fetchElementResources($element, $element_id) { diff --git a/htdocs/ticket/class/utils_diff.class.php b/htdocs/ticket/class/utils_diff.class.php index 03dff5506b4..84075d395ab 100644 --- a/htdocs/ticket/class/utils_diff.class.php +++ b/htdocs/ticket/class/utils_diff.class.php @@ -20,24 +20,21 @@ class Diff const DELETED = 1; const INSERTED = 2; - /* Returns the diff for two strings. The return value is an array, each of + /** + * Returns the diff for two strings. The return value is an array, each of * whose values is an array containing two values: a line (or character, if * $compareCharacters is true), and one of the constants DIFF::UNMODIFIED (the * line or character is in both strings), DIFF::DELETED (the line or character * is only in the first string), and DIFF::INSERTED (the line or character is * only in the second string). The parameters are: * - * $string1 - the first string - * $string2 - the second string - * $compareCharacters - true to compare characters, and false to compare - * lines; this optional parameter defaults to false + * @param string $string1 First string + * @param string $string2 Second string + * @param string $compareCharacters true to compare characters, and false to compare lines; this optional parameter defaults to false + * @return array Array of diff */ - public static function compare( - $string1, - $string2, - $compareCharacters = false - ) { - + public static function compare($string1, $string2, $compareCharacters = false) + { // initialise the sequences and comparison start and end positions $start = 0; if ($compareCharacters) { @@ -90,12 +87,13 @@ class Diff return $diff; } - /* Returns the diff for two files. The parameters are: + /** + * Returns the diff for two files. The parameters are: * - * $file1 - the path to the first file - * $file2 - the path to the second file - * $compareCharacters - true to compare characters, and false to compare - * lines; this optional parameter defaults to false + * @param string $file1 Path to the first file + * @param string $file2 Path to the second file + * @param boolean $compareCharacters true to compare characters, and false to compare lines; this optional parameter defaults to false + * @return array Array of diff */ public static function compareFiles( $file1, @@ -111,23 +109,18 @@ class Diff ); } - /* Returns the table of longest common subsequence lengths for the specified - * sequences. The parameters are: + /** + * Returns the table of longest common subsequence lengths for the specified sequences. The parameters are: * - * $sequence1 - the first sequence - * $sequence2 - the second sequence - * $start - the starting index - * $end1 - the ending index for the first sequence - * $end2 - the ending index for the second sequence + * @param string $sequence1 the first sequence + * @param string $sequence2 the second sequence + * @param string $start the starting index + * @param string $end1 the ending index for the first sequence + * @param string $end2 the ending index for the second sequence + * @return array array of diff */ - private static function computeTable( - $sequence1, - $sequence2, - $start, - $end1, - $end2 - ) { - + private static function computeTable($sequence1, $sequence2, $start, $end1, $end2) + { // determine the lengths to be compared $length1 = $end1 - $start + 1; $length2 = $end2 - $start + 1; @@ -156,21 +149,18 @@ class Diff return $table; } - /* Returns the partial diff for the specificed sequences, in reverse order. - * The parameters are: + /** + * Returns the partial diff for the specificed sequences, in reverse order. + * The parameters are: * - * $table - the table returned by the computeTable function - * $sequence1 - the first sequence - * $sequence2 - the second sequence - * $start - the starting index + * @param string $table the table returned by the computeTable function + * @param string $sequence1 the first sequence + * @param string $sequence2 the second sequence + * @param string $start the starting index + * @return array array of diff */ - private static function generatePartialDiff( - $table, - $sequence1, - $sequence2, - $start - ) { - + private static function generatePartialDiff($table, $sequence1, $sequence2, $start) + { // initialise the diff $diff = array(); @@ -205,17 +195,17 @@ class Diff return $diff; } - /* Returns a diff as a string, where unmodified lines are prefixed by ' ', + /** + * Returns a diff as a string, where unmodified lines are prefixed by ' ', * deletions are prefixed by '- ', and insertions are prefixed by '+ '. The * parameters are: * - * $diff - the diff array - * $separator - the separator between lines; this optional parameter defaults - * to "\n" + * @param array $diff the diff array + * @param string $separator the separator between lines; this optional parameter defaults to "\n" + * @return string String */ public static function toString($diff, $separator = "\n") { - // initialise the string $string = ''; @@ -242,17 +232,17 @@ class Diff return $string; } - /* Returns a diff as an HTML string, where unmodified lines are contained + /** + * Returns a diff as an HTML string, where unmodified lines are contained * within 'span' elements, deletions are contained within 'del' elements, and * insertions are contained within 'ins' elements. The parameters are: * - * $diff - the diff array - * $separator - the separator between lines; this optional parameter defaults - * to '
' + * @param string $diff the diff array + * @param string $separator the separator between lines; this optional parameter defaults to '
' + * @return string HTML string */ public static function toHTML($diff, $separator = '
') { - // initialise the HTML $html = ''; @@ -283,17 +273,16 @@ class Diff return $html; } - /* Returns a diff as an HTML table. The parameters are: + /** + * Returns a diff as an HTML table. The parameters are: * - * $diff - the diff array - * $indentation - indentation to add to every line of the generated HTML; this - * optional parameter defaults to '' - * $separator - the separator between lines; this optional parameter - * defaults to '
' + * @param string $diff the diff array + * @param string $indentation indentation to add to every line of the generated HTML; this optional parameter defaults to '' + * @param string $separator the separator between lines; this optional parameter defaults to '
' + * @return string HTML string */ public static function toTable($diff, $indentation = '', $separator = '
') { - // initialise the HTML $html = $indentation."\n"; @@ -373,14 +362,16 @@ class Diff return $html.$indentation."
\n"; } - /* Returns the content of the cell, for use in the toTable function. The + /** + * Returns the content of the cell, for use in the toTable function. The * parameters are: * - * $diff - the diff array - * $indentation - indentation to add to every line of the generated HTML - * $separator - the separator between lines - * $index - the current index, passes by reference - * $type - the type of line + * @param string $diff the diff array + * @param string $indentation indentation to add to every line of the generated HTML + * @param string $separator the separator between lines + * @param string $index the current index, passes by reference + * @param string $type the type of line + * @return string HTML string */ private static function getCellContent($diff, $indentation, $separator, &$index, $type) { diff --git a/htdocs/webservices/server_other.php b/htdocs/webservices/server_other.php index 3944ef5befa..4ae702ade15 100644 --- a/htdocs/webservices/server_other.php +++ b/htdocs/webservices/server_other.php @@ -137,7 +137,12 @@ $server->register( -// Full methods code +/** + * Full methods code + * + * @param string $authentication Authentication string + * @return array Array of data + */ function getVersions($authentication) { global $db, $conf, $langs; diff --git a/htdocs/zapier/class/hook.class.php b/htdocs/zapier/class/hook.class.php index 32268b039b4..b985c77434e 100644 --- a/htdocs/zapier/class/hook.class.php +++ b/htdocs/zapier/class/hook.class.php @@ -715,7 +715,6 @@ class Hook extends CommonObject * * @return int 0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK) */ - //public function doScheduledJob($param1, $param2, ...) public function doScheduledJob() { global $conf, $langs; diff --git a/test/phpunit/AccountingAccountTest.php b/test/phpunit/AccountingAccountTest.php index ea1651c5902..b4367e96f49 100644 --- a/test/phpunit/AccountingAccountTest.php +++ b/test/phpunit/AccountingAccountTest.php @@ -73,7 +73,11 @@ class AccountingAccountTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -84,7 +88,11 @@ class AccountingAccountTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/ActionCommTest.php b/test/phpunit/ActionCommTest.php index 34d67341afb..0dd4946f69c 100644 --- a/test/phpunit/ActionCommTest.php +++ b/test/phpunit/ActionCommTest.php @@ -73,7 +73,11 @@ class ActionCommTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -84,7 +88,11 @@ class ActionCommTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/AdherentTest.php b/test/phpunit/AdherentTest.php index 89e78b32bd9..f19e88c36a6 100644 --- a/test/phpunit/AdherentTest.php +++ b/test/phpunit/AdherentTest.php @@ -75,7 +75,11 @@ class AdherentTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -91,7 +95,11 @@ class AdherentTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/AdminLibTest.php b/test/phpunit/AdminLibTest.php index 7f3c9030725..e3c38c1df86 100644 --- a/test/phpunit/AdminLibTest.php +++ b/test/phpunit/AdminLibTest.php @@ -73,7 +73,11 @@ class AdminLibTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -82,7 +86,11 @@ class AdminLibTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/BOMTest.php b/test/phpunit/BOMTest.php index 41cbdd9f247..39268bdeaea 100644 --- a/test/phpunit/BOMTest.php +++ b/test/phpunit/BOMTest.php @@ -74,7 +74,11 @@ class BOMTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class BOMTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/BankAccountTest.php b/test/phpunit/BankAccountTest.php index 416a17f0c0f..1007db02dad 100644 --- a/test/phpunit/BankAccountTest.php +++ b/test/phpunit/BankAccountTest.php @@ -75,7 +75,11 @@ class BankAccountTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -84,7 +88,11 @@ class BankAccountTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/BuildDocTest.php b/test/phpunit/BuildDocTest.php index 61d7b7f1199..de4da3790b5 100644 --- a/test/phpunit/BuildDocTest.php +++ b/test/phpunit/BuildDocTest.php @@ -103,7 +103,11 @@ class BuildDocTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -121,7 +125,11 @@ class BuildDocTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/CMailFileTest.php b/test/phpunit/CMailFileTest.php index 8029959c22b..d407b67d991 100755 --- a/test/phpunit/CMailFileTest.php +++ b/test/phpunit/CMailFileTest.php @@ -73,7 +73,11 @@ class CMailFileTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -82,7 +86,11 @@ class CMailFileTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/CategorieTest.php b/test/phpunit/CategorieTest.php index 3c81a7aee21..a62d362a972 100644 --- a/test/phpunit/CategorieTest.php +++ b/test/phpunit/CategorieTest.php @@ -74,7 +74,11 @@ class CategorieTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class CategorieTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/ChargeSocialesTest.php b/test/phpunit/ChargeSocialesTest.php index b1a3fd87b30..33349449795 100644 --- a/test/phpunit/ChargeSocialesTest.php +++ b/test/phpunit/ChargeSocialesTest.php @@ -74,7 +74,11 @@ class ChargeSocialesTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class ChargeSocialesTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/CodingPhpTest.php b/test/phpunit/CodingPhpTest.php index 733071c0f58..5c3c6d7d54e 100644 --- a/test/phpunit/CodingPhpTest.php +++ b/test/phpunit/CodingPhpTest.php @@ -86,7 +86,11 @@ class CodingPhpTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -95,7 +99,11 @@ class CodingPhpTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/CodingSqlTest.php b/test/phpunit/CodingSqlTest.php index b62b9befcc7..f56d00b5bcd 100644 --- a/test/phpunit/CodingSqlTest.php +++ b/test/phpunit/CodingSqlTest.php @@ -86,7 +86,11 @@ class CodingSqlTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -95,7 +99,11 @@ class CodingSqlTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/CommandeFournisseurTest.php b/test/phpunit/CommandeFournisseurTest.php index 7ccbf5d0b76..bebd65634bf 100644 --- a/test/phpunit/CommandeFournisseurTest.php +++ b/test/phpunit/CommandeFournisseurTest.php @@ -75,7 +75,11 @@ class CommandeFournisseurTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -84,7 +88,11 @@ class CommandeFournisseurTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/CommandeTest.php b/test/phpunit/CommandeTest.php index ad2920282b2..990ef41f0b7 100644 --- a/test/phpunit/CommandeTest.php +++ b/test/phpunit/CommandeTest.php @@ -73,7 +73,11 @@ class CommandeTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -84,7 +88,11 @@ class CommandeTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/CommonInvoiceTest.php b/test/phpunit/CommonInvoiceTest.php index 9f4b5998455..5e9c45825ec 100644 --- a/test/phpunit/CommonInvoiceTest.php +++ b/test/phpunit/CommonInvoiceTest.php @@ -73,7 +73,11 @@ class CommonInvoiceTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -82,7 +86,11 @@ class CommonInvoiceTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/CommonObjectTest.php b/test/phpunit/CommonObjectTest.php index e32952c167d..6c68423e8a9 100644 --- a/test/phpunit/CommonObjectTest.php +++ b/test/phpunit/CommonObjectTest.php @@ -74,7 +74,11 @@ class CommonObjectTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class CommonObjectTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/CompanyBankAccountTest.php b/test/phpunit/CompanyBankAccountTest.php index 7410e1f15f9..1979f89fabb 100644 --- a/test/phpunit/CompanyBankAccountTest.php +++ b/test/phpunit/CompanyBankAccountTest.php @@ -74,7 +74,11 @@ class CompanyBankAccountTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class CompanyBankAccountTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/CompanyLibTest.php b/test/phpunit/CompanyLibTest.php index c45f6ebd208..ab9eb414634 100644 --- a/test/phpunit/CompanyLibTest.php +++ b/test/phpunit/CompanyLibTest.php @@ -73,7 +73,11 @@ class CompanyLibTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -82,7 +86,11 @@ class CompanyLibTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/ContactTest.php b/test/phpunit/ContactTest.php index 8fdaea0cbe7..0c5687e67c9 100755 --- a/test/phpunit/ContactTest.php +++ b/test/phpunit/ContactTest.php @@ -82,7 +82,11 @@ class ContactTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -92,7 +96,11 @@ class ContactTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/ContratTest.php b/test/phpunit/ContratTest.php index 7c302105aa2..d364d6c9dff 100644 --- a/test/phpunit/ContratTest.php +++ b/test/phpunit/ContratTest.php @@ -74,7 +74,11 @@ class ContratTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class ContratTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/CoreTest.php b/test/phpunit/CoreTest.php index c34bbffba95..87c43798a0f 100644 --- a/test/phpunit/CoreTest.php +++ b/test/phpunit/CoreTest.php @@ -76,7 +76,11 @@ class CoreTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -85,7 +89,11 @@ class CoreTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/DateLibTest.php b/test/phpunit/DateLibTest.php index dd32e02cee6..062bdb6dd11 100644 --- a/test/phpunit/DateLibTest.php +++ b/test/phpunit/DateLibTest.php @@ -74,7 +74,11 @@ class DateLibTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class DateLibTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/DateLibTzFranceTest.php b/test/phpunit/DateLibTzFranceTest.php index 895599becde..7e96e39030e 100644 --- a/test/phpunit/DateLibTzFranceTest.php +++ b/test/phpunit/DateLibTzFranceTest.php @@ -74,7 +74,11 @@ class DateLibTzFranceTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -88,7 +92,11 @@ class DateLibTzFranceTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/DiscountTest.php b/test/phpunit/DiscountTest.php index 202c41958d0..9eba2460655 100644 --- a/test/phpunit/DiscountTest.php +++ b/test/phpunit/DiscountTest.php @@ -74,7 +74,11 @@ class DiscountTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class DiscountTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/EntrepotTest.php b/test/phpunit/EntrepotTest.php index 2ab2fc2aff3..27fd3dabbf3 100644 --- a/test/phpunit/EntrepotTest.php +++ b/test/phpunit/EntrepotTest.php @@ -74,7 +74,11 @@ class EntrepotTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -86,7 +90,11 @@ class EntrepotTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/ExpenseReportTest.php b/test/phpunit/ExpenseReportTest.php index 67467ac6c81..3f6402262c3 100644 --- a/test/phpunit/ExpenseReportTest.php +++ b/test/phpunit/ExpenseReportTest.php @@ -74,7 +74,11 @@ class ExpenseReportTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class ExpenseReportTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/ExportTest.php b/test/phpunit/ExportTest.php index 3abec2ee0e1..590accccbed 100644 --- a/test/phpunit/ExportTest.php +++ b/test/phpunit/ExportTest.php @@ -78,7 +78,11 @@ class ExportTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -87,7 +91,11 @@ class ExportTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/FactureFournisseurTest.php b/test/phpunit/FactureFournisseurTest.php index b277ba5c1b3..d9cd44a40d2 100644 --- a/test/phpunit/FactureFournisseurTest.php +++ b/test/phpunit/FactureFournisseurTest.php @@ -75,7 +75,11 @@ class FactureFournisseurTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -84,7 +88,11 @@ class FactureFournisseurTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/FactureRecTest.php b/test/phpunit/FactureRecTest.php index 71caddeb491..f89ab4b1f13 100644 --- a/test/phpunit/FactureRecTest.php +++ b/test/phpunit/FactureRecTest.php @@ -75,7 +75,11 @@ class FactureRecTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -84,7 +88,11 @@ class FactureRecTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/FactureTest.php b/test/phpunit/FactureTest.php index 4e361895fcc..47f3a639b29 100644 --- a/test/phpunit/FactureTest.php +++ b/test/phpunit/FactureTest.php @@ -74,7 +74,11 @@ class FactureTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -87,7 +91,11 @@ class FactureTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/FactureTestRounding.php b/test/phpunit/FactureTestRounding.php index 59ecc240461..f0165a88d0b 100644 --- a/test/phpunit/FactureTestRounding.php +++ b/test/phpunit/FactureTestRounding.php @@ -74,7 +74,11 @@ class FactureTestRounding extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class FactureTestRounding extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/FichinterTest.php b/test/phpunit/FichinterTest.php index ba9408441a1..f78e9250471 100644 --- a/test/phpunit/FichinterTest.php +++ b/test/phpunit/FichinterTest.php @@ -74,7 +74,11 @@ class FichinterTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class FichinterTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/FilesLibTest.php b/test/phpunit/FilesLibTest.php index fb3ce8f5814..9d476953381 100644 --- a/test/phpunit/FilesLibTest.php +++ b/test/phpunit/FilesLibTest.php @@ -75,7 +75,11 @@ class FilesLibTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -84,7 +88,11 @@ class FilesLibTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/FormAdminTest.php b/test/phpunit/FormAdminTest.php index e6b92b698d9..a434841930c 100644 --- a/test/phpunit/FormAdminTest.php +++ b/test/phpunit/FormAdminTest.php @@ -74,7 +74,11 @@ class FormAdminTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class FormAdminTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/FormTest.php b/test/phpunit/FormTest.php index 59cfeb3fa3d..bec23048e9f 100644 --- a/test/phpunit/FormTest.php +++ b/test/phpunit/FormTest.php @@ -74,7 +74,11 @@ class FormTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class FormTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/Functions2LibTest.php b/test/phpunit/Functions2LibTest.php index 4304251d7f1..21fa1f29257 100644 --- a/test/phpunit/Functions2LibTest.php +++ b/test/phpunit/Functions2LibTest.php @@ -77,7 +77,11 @@ class Functions2LibTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -86,7 +90,11 @@ class Functions2LibTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/FunctionsLibTest.php b/test/phpunit/FunctionsLibTest.php index dff6b3a7d06..e3dabff6df9 100644 --- a/test/phpunit/FunctionsLibTest.php +++ b/test/phpunit/FunctionsLibTest.php @@ -77,7 +77,11 @@ class FunctionsLibTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -88,7 +92,11 @@ class FunctionsLibTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/GetUrlLibTest.php b/test/phpunit/GetUrlLibTest.php index ba074459f44..268122c8d48 100644 --- a/test/phpunit/GetUrlLibTest.php +++ b/test/phpunit/GetUrlLibTest.php @@ -75,7 +75,11 @@ class GetUrlLibTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -84,7 +88,11 @@ class GetUrlLibTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/HolidayTest.php b/test/phpunit/HolidayTest.php index cd5a9f28138..e7e3e8749cd 100644 --- a/test/phpunit/HolidayTest.php +++ b/test/phpunit/HolidayTest.php @@ -76,7 +76,11 @@ class HolidayTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -86,7 +90,11 @@ class HolidayTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/ImagesLibTest.php b/test/phpunit/ImagesLibTest.php index 71474ba1847..3bfb676f3be 100644 --- a/test/phpunit/ImagesLibTest.php +++ b/test/phpunit/ImagesLibTest.php @@ -75,7 +75,11 @@ class ImagesLibTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -84,7 +88,11 @@ class ImagesLibTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/ImportTest.php b/test/phpunit/ImportTest.php index 9e6b973500a..ce689fda4a4 100644 --- a/test/phpunit/ImportTest.php +++ b/test/phpunit/ImportTest.php @@ -76,7 +76,11 @@ class ImportTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -85,7 +89,11 @@ class ImportTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/JsonLibTest.php b/test/phpunit/JsonLibTest.php index 0b5d3dd53e6..7d2678b0ec7 100644 --- a/test/phpunit/JsonLibTest.php +++ b/test/phpunit/JsonLibTest.php @@ -76,7 +76,11 @@ class JsonLibTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -85,7 +89,11 @@ class JsonLibTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/LangTest.php b/test/phpunit/LangTest.php index 3ff2917a9f2..f4a14373ebe 100644 --- a/test/phpunit/LangTest.php +++ b/test/phpunit/LangTest.php @@ -86,7 +86,11 @@ class LangTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -95,7 +99,11 @@ class LangTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/LesscTest.php b/test/phpunit/LesscTest.php index ca64853b381..a4ce302c540 100644 --- a/test/phpunit/LesscTest.php +++ b/test/phpunit/LesscTest.php @@ -86,7 +86,11 @@ class LesscTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -95,7 +99,11 @@ class LesscTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/LoanTest.php b/test/phpunit/LoanTest.php index 71a61c80ae0..253e779ac03 100644 --- a/test/phpunit/LoanTest.php +++ b/test/phpunit/LoanTest.php @@ -74,7 +74,11 @@ class LoanTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class LoanTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/MarginsLibTest.php b/test/phpunit/MarginsLibTest.php index fc25d929b38..e451262546d 100644 --- a/test/phpunit/MarginsLibTest.php +++ b/test/phpunit/MarginsLibTest.php @@ -74,7 +74,11 @@ class MarginsLibTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class MarginsLibTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/ModulesTest.php b/test/phpunit/ModulesTest.php index 5a43de21167..f8feaa8f829 100755 --- a/test/phpunit/ModulesTest.php +++ b/test/phpunit/ModulesTest.php @@ -73,7 +73,11 @@ class ModulesTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -82,7 +86,11 @@ class ModulesTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/MouvementStockTest.php b/test/phpunit/MouvementStockTest.php index 85137234a3b..23b6b2b0111 100644 --- a/test/phpunit/MouvementStockTest.php +++ b/test/phpunit/MouvementStockTest.php @@ -76,7 +76,11 @@ class MouvementStockTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -85,7 +89,11 @@ class MouvementStockTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/NumberingModulesTest.php b/test/phpunit/NumberingModulesTest.php index 099d6d2052c..089a2c2f4cf 100644 --- a/test/phpunit/NumberingModulesTest.php +++ b/test/phpunit/NumberingModulesTest.php @@ -73,7 +73,11 @@ class NumberingModulesTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class NumberingModulesTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/PaypalTest.php b/test/phpunit/PaypalTest.php index 96bfbefdf17..47d8341f501 100644 --- a/test/phpunit/PaypalTest.php +++ b/test/phpunit/PaypalTest.php @@ -75,7 +75,11 @@ class PaypalTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -87,7 +91,11 @@ class PaypalTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/PdfDocTest.php b/test/phpunit/PdfDocTest.php index 9c9c0bb666f..276deada0c6 100644 --- a/test/phpunit/PdfDocTest.php +++ b/test/phpunit/PdfDocTest.php @@ -77,7 +77,11 @@ class PdfDocTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -86,7 +90,11 @@ class PdfDocTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/PgsqlTest.php b/test/phpunit/PgsqlTest.php index 4b2a5f98746..5a09e7fc55a 100644 --- a/test/phpunit/PgsqlTest.php +++ b/test/phpunit/PgsqlTest.php @@ -76,7 +76,11 @@ class PgsqlTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -86,7 +90,11 @@ class PgsqlTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/PricesTest.php b/test/phpunit/PricesTest.php index d7f9e310088..0c47ec4f275 100755 --- a/test/phpunit/PricesTest.php +++ b/test/phpunit/PricesTest.php @@ -81,7 +81,11 @@ class PricesTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -90,7 +94,11 @@ class PricesTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/ProductTest.php b/test/phpunit/ProductTest.php index 8a848416318..650d8a93e37 100644 --- a/test/phpunit/ProductTest.php +++ b/test/phpunit/ProductTest.php @@ -74,7 +74,11 @@ class ProductTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -85,7 +89,12 @@ class ProductTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // teardownafterclass + + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/ProjectTest.php b/test/phpunit/ProjectTest.php index 84a6411082f..8a7e0540b9a 100644 --- a/test/phpunit/ProjectTest.php +++ b/test/phpunit/ProjectTest.php @@ -75,7 +75,11 @@ class ProjectTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -84,7 +88,11 @@ class ProjectTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/PropalTest.php b/test/phpunit/PropalTest.php index 709c5bbcfb7..068fb53b052 100644 --- a/test/phpunit/PropalTest.php +++ b/test/phpunit/PropalTest.php @@ -74,7 +74,11 @@ class PropalTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class PropalTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/RestAPIDocumentTest.php b/test/phpunit/RestAPIDocumentTest.php index 9ce14a4ac92..65b8c206c9d 100644 --- a/test/phpunit/RestAPIDocumentTest.php +++ b/test/phpunit/RestAPIDocumentTest.php @@ -76,7 +76,11 @@ class RestAPIDocumentTest extends PHPUnit\Framework\TestCase echo "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -85,7 +89,11 @@ class RestAPIDocumentTest extends PHPUnit\Framework\TestCase echo __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/RestAPIUserTest.php b/test/phpunit/RestAPIUserTest.php index ea3970e5a4b..9d49d10af73 100644 --- a/test/phpunit/RestAPIUserTest.php +++ b/test/phpunit/RestAPIUserTest.php @@ -80,7 +80,11 @@ class RestAPIUserTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -89,7 +93,11 @@ class RestAPIUserTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/ScriptsTest.php b/test/phpunit/ScriptsTest.php index e490054edfa..16884214418 100644 --- a/test/phpunit/ScriptsTest.php +++ b/test/phpunit/ScriptsTest.php @@ -86,7 +86,11 @@ class ScriptsTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -95,7 +99,11 @@ class ScriptsTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/SecurityTest.php b/test/phpunit/SecurityTest.php index 4130426d806..5a248006498 100644 --- a/test/phpunit/SecurityTest.php +++ b/test/phpunit/SecurityTest.php @@ -86,7 +86,11 @@ class SecurityTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -95,7 +99,11 @@ class SecurityTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/SocieteTest.php b/test/phpunit/SocieteTest.php index 070a8999bb2..4ed0771d668 100755 --- a/test/phpunit/SocieteTest.php +++ b/test/phpunit/SocieteTest.php @@ -74,7 +74,11 @@ class SocieteTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -88,7 +92,11 @@ class SocieteTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/SupplierProposalTest.php b/test/phpunit/SupplierProposalTest.php index 42d7e5842a6..27414ecab0a 100644 --- a/test/phpunit/SupplierProposalTest.php +++ b/test/phpunit/SupplierProposalTest.php @@ -77,7 +77,11 @@ class SupplierProposalTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -88,7 +92,11 @@ class SupplierProposalTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/TicketTest.php b/test/phpunit/TicketTest.php index fa7ea8df98f..c13bdcfb959 100644 --- a/test/phpunit/TicketTest.php +++ b/test/phpunit/TicketTest.php @@ -74,7 +74,11 @@ class TicketTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class TicketTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/UserGroupTest.php b/test/phpunit/UserGroupTest.php index fe08af2bce7..7e3cdd24b3a 100644 --- a/test/phpunit/UserGroupTest.php +++ b/test/phpunit/UserGroupTest.php @@ -73,7 +73,11 @@ class UserGroupTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -82,7 +86,11 @@ class UserGroupTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/UserTest.php b/test/phpunit/UserTest.php index 3c89bd52d06..10b0bd7b0b7 100644 --- a/test/phpunit/UserTest.php +++ b/test/phpunit/UserTest.php @@ -73,7 +73,11 @@ class UserTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -85,7 +89,11 @@ class UserTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/UtilsTest.php b/test/phpunit/UtilsTest.php index a1b9eafa45e..dd5ba68ca8f 100644 --- a/test/phpunit/UtilsTest.php +++ b/test/phpunit/UtilsTest.php @@ -73,7 +73,11 @@ class UtilsTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -83,7 +87,11 @@ class UtilsTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/WebservicesOrdersTest.php b/test/phpunit/WebservicesOrdersTest.php index 8afd50a0394..33d842f6d39 100644 --- a/test/phpunit/WebservicesOrdersTest.php +++ b/test/phpunit/WebservicesOrdersTest.php @@ -77,7 +77,11 @@ class WebservicesOrdersTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -86,7 +90,11 @@ class WebservicesOrdersTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/WebservicesOtherTest.php b/test/phpunit/WebservicesOtherTest.php index 7304e2bf367..34686cbec92 100644 --- a/test/phpunit/WebservicesOtherTest.php +++ b/test/phpunit/WebservicesOtherTest.php @@ -77,7 +77,11 @@ class WebservicesOtherTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -86,7 +90,11 @@ class WebservicesOtherTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/WebservicesProductsTest.php b/test/phpunit/WebservicesProductsTest.php index 3d74deb721c..70a8c12a498 100644 --- a/test/phpunit/WebservicesProductsTest.php +++ b/test/phpunit/WebservicesProductsTest.php @@ -84,7 +84,11 @@ class WebservicesProductsTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -92,7 +96,12 @@ class WebservicesProductsTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/WebservicesThirdpartyTest.php b/test/phpunit/WebservicesThirdpartyTest.php index 9aefd6c5ce6..1106164b4ee 100644 --- a/test/phpunit/WebservicesThirdpartyTest.php +++ b/test/phpunit/WebservicesThirdpartyTest.php @@ -94,7 +94,11 @@ class WebservicesThirdpartyTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -103,7 +107,11 @@ class WebservicesThirdpartyTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/WebservicesUserTest.php b/test/phpunit/WebservicesUserTest.php index de51431b046..bb68f413741 100644 --- a/test/phpunit/WebservicesUserTest.php +++ b/test/phpunit/WebservicesUserTest.php @@ -77,7 +77,11 @@ class WebservicesUserTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -86,7 +90,11 @@ class WebservicesUserTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; diff --git a/test/phpunit/XCalLibTest.php b/test/phpunit/XCalLibTest.php index 26d5e25c54b..9fb1975a1fd 100644 --- a/test/phpunit/XCalLibTest.php +++ b/test/phpunit/XCalLibTest.php @@ -73,7 +73,11 @@ class XCalLibTest extends PHPUnit\Framework\TestCase print "\n"; } - // Static methods + /** + * setUpBeforeClass + * + * @return void + */ public static function setUpBeforeClass() { global $conf,$user,$langs,$db; @@ -82,7 +86,11 @@ class XCalLibTest extends PHPUnit\Framework\TestCase print __METHOD__."\n"; } - // tear down after class + /** + * tearDownAfterClass + * + * @return void + */ public static function tearDownAfterClass() { global $conf,$user,$langs,$db; From 4b34a6bd4acb766242eaaac072dbe68c9a9466d9 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 4 May 2020 12:43:47 +0200 Subject: [PATCH 090/120] Look and feel --- htdocs/core/class/html.formfile.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index 075fb95066b..98d781a51c1 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -1393,7 +1393,7 @@ class FormFile if ($permtoeditline) { $paramsectiondir = (in_array($modulepart, array('medias', 'ecm')) ? '§ion_dir='.urlencode($relativepath) : ''); - print ''.img_edit('default', 0, 'class="paddingrightonly"').''; + print ''.img_edit('default', 0, 'class="paddingrightonly"').''; } } if ($permonobject) From 3857c082776324938d38fdb0a5d82ca1b156c640 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 4 May 2020 13:24:09 +0200 Subject: [PATCH 091/120] Fix quick search on MO --- htdocs/core/ajax/selectsearchbox.php | 21 ++++++++++++------- htdocs/langs/en_US/main.lang | 1 + .../modulebuilder/template/myobject_list.php | 2 +- htdocs/mrp/mo_list.php | 2 +- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/htdocs/core/ajax/selectsearchbox.php b/htdocs/core/ajax/selectsearchbox.php index bc5287a51f9..cd019b9ce38 100644 --- a/htdocs/core/ajax/selectsearchbox.php +++ b/htdocs/core/ajax/selectsearchbox.php @@ -75,9 +75,14 @@ if (((!empty($conf->product->enabled) && $user->rights->produit->lire) || (!empt $arrayresult['searchintoproduct'] = array('position'=>30, 'shortcut'=>'P', 'img'=>'object_product', 'label'=>$langs->trans("SearchIntoProductsOrServices", $search_boxvalue), 'text'=>img_picto('', 'object_product').' '.$langs->trans("SearchIntoProductsOrServices", $search_boxvalue), 'url'=>DOL_URL_ROOT.'/product/list.php'.($search_boxvalue ? '?sall='.urlencode($search_boxvalue) : '')); } +if (!empty($conf->mrp->enabled) && $user->rights->mrp->read && empty($conf->global->MAIN_SEARCHFORM_MRP_DISABLED)) +{ + $arrayresult['searchintomo'] = array('position'=>35, 'shortcut'=>'', 'img'=>'object_mrp', 'label'=>$langs->trans("SearchIntoMO", $search_boxvalue), 'text'=>img_picto('', 'object_mrp').' '.$langs->trans("SearchIntoMO", $search_boxvalue), 'url'=>DOL_URL_ROOT.'/mrp/mo_list.php'.($search_boxvalue ? '?search_all='.urlencode($search_boxvalue) : '')); +} + if (!empty($conf->projet->enabled) && empty($conf->global->MAIN_SEARCHFORM_PROJECT_DISABLED) && $user->rights->projet->lire) { - $arrayresult['searchintoprojects'] = array('position'=>40, 'shortcut'=>'Q', 'img'=>'object_projectpub', 'label'=>$langs->trans("SearchIntoProjects", $search_boxvalue), 'text'=>img_picto('', 'object_projectpub').' '.$langs->trans("SearchIntoProjects", $search_boxvalue), 'url'=>DOL_URL_ROOT.'/projet/list.php'.($search_boxvalue ? '?search_all='.urlencode($search_boxvalue) : '')); + $arrayresult['searchintoprojects'] = array('position'=>40, 'shortcut'=>'Q', 'img'=>'object_projectpub', 'label'=>$langs->trans("SearchIntoProjects", $search_boxvalue), 'text'=>img_picto('', 'object_project').' '.$langs->trans("SearchIntoProjects", $search_boxvalue), 'url'=>DOL_URL_ROOT.'/projet/list.php'.($search_boxvalue ? '?search_all='.urlencode($search_boxvalue) : '')); } if (!empty($conf->projet->enabled) && empty($conf->global->MAIN_SEARCHFORM_TASK_DISABLED) && $user->rights->projet->lire) { @@ -103,15 +108,15 @@ if (!empty($conf->facture->enabled) && empty($conf->global->MAIN_SEARCHFORM_CUST if (!empty($conf->supplier_proposal->enabled) && empty($conf->global->MAIN_SEARCHFORM_SUPPLIER_PROPAL_DISABLED) && $user->rights->supplier_proposal->lire) { - $arrayresult['searchintosupplierpropal'] = array('position'=>100, 'img'=>'object_propal', 'label'=>$langs->trans("SearchIntoSupplierProposals", $search_boxvalue), 'text'=>img_picto('', 'object_propal').' '.$langs->trans("SearchIntoSupplierProposals", $search_boxvalue), 'url'=>DOL_URL_ROOT.'/supplier_proposal/list.php'.($search_boxvalue ? '?sall='.urlencode($search_boxvalue) : '')); + $arrayresult['searchintosupplierpropal'] = array('position'=>100, 'img'=>'object_propal', 'label'=>$langs->trans("SearchIntoSupplierProposals", $search_boxvalue), 'text'=>img_picto('', 'object_supplier_proposal').' '.$langs->trans("SearchIntoSupplierProposals", $search_boxvalue), 'url'=>DOL_URL_ROOT.'/supplier_proposal/list.php'.($search_boxvalue ? '?sall='.urlencode($search_boxvalue) : '')); } if ((! empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_SEARCHFORM_SUPPLIER_ORDER_DISABLED) || ! empty($conf->supplier_order->enabled)) && $user->rights->fournisseur->commande->lire) { - $arrayresult['searchintosupplierorder'] = array('position'=>110, 'img'=>'object_order', 'label'=>$langs->trans("SearchIntoSupplierOrders", $search_boxvalue), 'text'=>img_picto('', 'object_order').' '.$langs->trans("SearchIntoSupplierOrders", $search_boxvalue), 'url'=>DOL_URL_ROOT.'/fourn/commande/list.php'.($search_boxvalue ? '?search_all='.urlencode($search_boxvalue) : '')); + $arrayresult['searchintosupplierorder'] = array('position'=>110, 'img'=>'object_order', 'label'=>$langs->trans("SearchIntoSupplierOrders", $search_boxvalue), 'text'=>img_picto('', 'object_supplier_order').' '.$langs->trans("SearchIntoSupplierOrders", $search_boxvalue), 'url'=>DOL_URL_ROOT.'/fourn/commande/list.php'.($search_boxvalue ? '?search_all='.urlencode($search_boxvalue) : '')); } if ((! empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_SEARCHFORM_SUPPLIER_INVOICE_DISABLED) || ! empty($conf->supplier_invoice->enabled)) && $user->rights->fournisseur->facture->lire) { - $arrayresult['searchintosupplierinvoice'] = array('position'=>120, 'img'=>'object_bill', 'label'=>$langs->trans("SearchIntoSupplierInvoices", $search_boxvalue), 'text'=>img_picto('', 'object_bill').' '.$langs->trans("SearchIntoSupplierInvoices", $search_boxvalue), 'url'=>DOL_URL_ROOT.'/fourn/facture/list.php'.($search_boxvalue ? '?sall='.urlencode($search_boxvalue) : '')); + $arrayresult['searchintosupplierinvoice'] = array('position'=>120, 'img'=>'object_bill', 'label'=>$langs->trans("SearchIntoSupplierInvoices", $search_boxvalue), 'text'=>img_picto('', 'object_supplier_invoice').' '.$langs->trans("SearchIntoSupplierInvoices", $search_boxvalue), 'url'=>DOL_URL_ROOT.'/fourn/facture/list.php'.($search_boxvalue ? '?sall='.urlencode($search_boxvalue) : '')); } if (!empty($conf->contrat->enabled) && empty($conf->global->MAIN_SEARCHFORM_CONTRACT_DISABLED) && $user->rights->contrat->lire) @@ -122,6 +127,10 @@ if (!empty($conf->ficheinter->enabled) && empty($conf->global->MAIN_SEARCHFORM_F { $arrayresult['searchintointervention'] = array('position'=>140, 'img'=>'object_intervention', 'label'=>$langs->trans("SearchIntoInterventions", $search_boxvalue), 'text'=>img_picto('', 'object_intervention').' '.$langs->trans("SearchIntoInterventions", $search_boxvalue), 'url'=>DOL_URL_ROOT.'/fichinter/list.php'.($search_boxvalue ? '?sall='.urlencode($search_boxvalue) : '')); } +if (!empty($conf->ticket->enabled) && empty($conf->global->MAIN_SEARCHFORM_TICKET_DISABLED) && $user->rights->ticket->read) +{ + $arrayresult['searchintotickets'] = array('position'=>145, 'img'=>'object_ticket', 'label'=>$langs->trans("SearchIntoTickets", $search_boxvalue), 'text'=>img_picto('', 'object_ticket').' '.$langs->trans("SearchIntoTickets", $search_boxvalue), 'url'=>DOL_URL_ROOT.'/ticket/list.php?mainmenu=ticket'.($search_boxvalue ? '&sall='.urlencode($search_boxvalue) : '')); +} // HR if (!empty($conf->user->enabled) && empty($conf->global->MAIN_SEARCHFORM_USER_DISABLED) && $user->rights->user->user->lire) @@ -136,10 +145,6 @@ if (!empty($conf->holiday->enabled) && empty($conf->global->MAIN_SEARCHFORM_HOLI { $arrayresult['searchintoleaves'] = array('position'=>220, 'img'=>'object_holiday', 'label'=>$langs->trans("SearchIntoLeaves", $search_boxvalue), 'text'=>img_picto('', 'object_holiday').' '.$langs->trans("SearchIntoLeaves", $search_boxvalue), 'url'=>DOL_URL_ROOT.'/holiday/list.php?mainmenu=hrm'.($search_boxvalue ? '&sall='.urlencode($search_boxvalue) : '')); } -if (!empty($conf->ticket->enabled) && empty($conf->global->MAIN_SEARCHFORM_TICKET_DISABLED) && $user->rights->ticket->read) -{ - $arrayresult['searchintotickets'] = array('position'=>220, 'img'=>'object_ticket', 'label'=>$langs->trans("SearchIntoTickets", $search_boxvalue), 'text'=>img_picto('', 'object_ticket').' '.$langs->trans("SearchIntoTickets", $search_boxvalue), 'url'=>DOL_URL_ROOT.'/ticket/list.php?mainmenu=ticket'.($search_boxvalue ? '&sall='.urlencode($search_boxvalue) : '')); -} /* Do we really need this. We already have a select for users, and we should be able to filter into user list on employee flag diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang index 7cb9b21791a..38a4bcd2bad 100644 --- a/htdocs/langs/en_US/main.lang +++ b/htdocs/langs/en_US/main.lang @@ -953,6 +953,7 @@ SearchIntoMembers=Members SearchIntoUsers=Users SearchIntoProductsOrServices=Products or services SearchIntoProjects=Projects +SearchIntoMO=Manufacturing Orders SearchIntoTasks=Tasks SearchIntoCustomerInvoices=Customer invoices SearchIntoSupplierInvoices=Vendor invoices diff --git a/htdocs/modulebuilder/template/myobject_list.php b/htdocs/modulebuilder/template/myobject_list.php index 18c0b1bda2b..a0fcb744bb1 100644 --- a/htdocs/modulebuilder/template/myobject_list.php +++ b/htdocs/modulebuilder/template/myobject_list.php @@ -108,7 +108,7 @@ if (!$sortfield) $sortfield = "t.".key($object->fields); // Set here default sea if (!$sortorder) $sortorder = "ASC"; // Initialize array of search criterias -$search_all = trim(GETPOST("search_all", 'alpha')); +$search_all = GETPOST('search_all', 'alphanohtml') ? trim(GETPOST('search_all', 'alphanohtml')) : trim(GETPOST('sall', 'alphanohtml')); $search = array(); foreach ($object->fields as $key => $val) { diff --git a/htdocs/mrp/mo_list.php b/htdocs/mrp/mo_list.php index b51171e6684..4807c47fb53 100644 --- a/htdocs/mrp/mo_list.php +++ b/htdocs/mrp/mo_list.php @@ -107,7 +107,7 @@ if ($user->socid > 0) // Protection if external user // Initialize array of search criterias -$search_all = trim(GETPOST("search_all", 'alpha')); +$search_all = GETPOST('search_all', 'alphanohtml') ? trim(GETPOST('search_all', 'alphanohtml')) : trim(GETPOST('sall', 'alphanohtml')); $search = array(); foreach ($object->fields as $key => $val) { From 358bc6d5df27ea701b5d3b6cfde6cd06ee9ea501 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 4 May 2020 14:29:25 +0200 Subject: [PATCH 092/120] Fix search on entities --- htdocs/website/index.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/htdocs/website/index.php b/htdocs/website/index.php index ebfbc7a2ac3..0db6aad1d1c 100644 --- a/htdocs/website/index.php +++ b/htdocs/website/index.php @@ -282,6 +282,7 @@ $searchkey = GETPOST('searchstring', 'none'); if ($action == 'replacesiteconfirm') { $listofpages = getPagesFromSearchCriterias('', $algo, $searchkey, 1000, $sortfield, $sortorder); + var_dump($listofpages); } @@ -3531,9 +3532,10 @@ if ($action == 'replacesite' || $action == 'replacesiteconfirm' || $massaction = print $langs->trans("SearchString"); print ''; print '
'; - print ''; - print ''; + print ''; + + print ''; print '
'; print ''; From f6e055309360eb518754e1e84626d7385234f61c Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 4 May 2020 14:29:57 +0200 Subject: [PATCH 093/120] fix var_dump --- htdocs/website/index.php | 1 - 1 file changed, 1 deletion(-) diff --git a/htdocs/website/index.php b/htdocs/website/index.php index 0db6aad1d1c..690dc0efe3b 100644 --- a/htdocs/website/index.php +++ b/htdocs/website/index.php @@ -282,7 +282,6 @@ $searchkey = GETPOST('searchstring', 'none'); if ($action == 'replacesiteconfirm') { $listofpages = getPagesFromSearchCriterias('', $algo, $searchkey, 1000, $sortfield, $sortorder); - var_dump($listofpages); } From f4a9490e7fa3c7bf54bb204cd2e73c742531524f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 4 May 2020 16:55:53 +0200 Subject: [PATCH 094/120] Fix a page with NOLOGIN const set to 1 must be into "public" dir. --- htdocs/takepos/admin/bar.php | 4 ++-- htdocs/takepos/{ => public}/auto_order.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) rename htdocs/takepos/{ => public}/auto_order.php (83%) diff --git a/htdocs/takepos/admin/bar.php b/htdocs/takepos/admin/bar.php index 672041d3bb3..7b6e1d9a98c 100644 --- a/htdocs/takepos/admin/bar.php +++ b/htdocs/takepos/admin/bar.php @@ -155,9 +155,9 @@ if ($conf->global->TAKEPOS_AUTO_ORDER) print '
'; print $langs->trans("Table")." ".$row['label']; print ''; - print "".$urlwithroot."/takepos/auto_order.php?key=".dol_encode($row['rowid']).""; + print "".$urlwithroot."/takepos/public/auto_order.php?key=".dol_encode($row['rowid']).""; print ''; - print ""; + print ""; print '
'; + print ''; $staticcontrat->ref = ($obj->ref ? $obj->ref : $obj->cid); $staticcontrat->id = $obj->cid; print $staticcontrat->getNomUrl(1, 16); @@ -425,7 +425,7 @@ if ($resql) $obj = $db->fetch_object($resql); print '
'; + print ''; $staticcontrat->ref = ($obj->ref ? $obj->ref : $obj->fk_contrat); $staticcontrat->id = $obj->fk_contrat; print $staticcontrat->getNomUrl(1, 16); @@ -506,7 +506,7 @@ if ($resql) print '
'; + print ''; $staticcontrat->ref = ($obj->ref ? $obj->ref : $obj->fk_contrat); $staticcontrat->id = $obj->fk_contrat; print $staticcontrat->getNomUrl(1, 16); @@ -586,7 +586,7 @@ if ($resql) print '
'; + print ''; $staticcontrat->ref = ($obj->ref ? $obj->ref : $obj->fk_contrat); $staticcontrat->id = $obj->fk_contrat; print $staticcontrat->getNomUrl(1, 16); diff --git a/htdocs/contrat/list.php b/htdocs/contrat/list.php index 70ab37c0380..4b163480035 100644 --- a/htdocs/contrat/list.php +++ b/htdocs/contrat/list.php @@ -1,6 +1,6 @@ - * Copyright (C) 2004-2019 Laurent Destailleur + * Copyright (C) 2004-2020 Laurent Destailleur * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2013 Cédric Salvador * Copyright (C) 2014-2019 Juanjo Menent @@ -612,9 +612,11 @@ while ($i < min($num, $limit)) } print '
'; + print ''; print $contracttmp->getNomUrl(1); if ($obj->nb_late) print img_warning($langs->trans("Late")); if (!empty($obj->note_private) || !empty($obj->note_public)) { @@ -631,6 +633,7 @@ while ($i < min($num, $limit)) print ''.$contracttmp->getFormatedCustomerRef($obj->ref_customer).'
'; +print '
'; + +print ''; + + print '

'; +print '
'; +print ''; +print ''; + // Notification per contacts $title = $langs->trans("ListOfNotificationsPerUser"); if (!empty($conf->societe->enabled)) $title = $langs->trans("ListOfNotificationsPerUserOrContact"); @@ -211,7 +262,7 @@ if ($conf->global->MAIN_FEATURES_LEVEL >= 2) { } $helptext = ''; - form_constantes($constantes, 0, $helptext); + form_constantes($constantes, 2, $helptext); } else { print ''; print ''; @@ -248,14 +299,18 @@ if ($conf->global->MAIN_FEATURES_LEVEL >= 2) { print '
'; } -print '
'; -print '* '.$langs->trans("GoOntoUserCardToAddMore").'
'; -if (!empty($conf->societe->enabled)) print '** '.$langs->trans("GoOntoContactCardToAddMore").'
'; +print '
'; + +print ''; + -print '
'; print '

'; +print '
'; +print ''; +print ''; + print load_fiche_titre($langs->trans("ListOfFixedNotifications"), '', ''); print ''; @@ -333,6 +388,12 @@ foreach ($listofnotifiedevents as $notifiedevent) } print '
'; +print '
'; +print '* '.$langs->trans("GoOntoUserCardToAddMore").'
'; +if (!empty($conf->societe->enabled)) print '** '.$langs->trans("GoOntoContactCardToAddMore").'
'; + +print '
'; + print '
'; print '
'; diff --git a/htdocs/core/lib/admin.lib.php b/htdocs/core/lib/admin.lib.php index f2e8e94ab78..b78c0478370 100644 --- a/htdocs/core/lib/admin.lib.php +++ b/htdocs/core/lib/admin.lib.php @@ -1409,7 +1409,7 @@ function complete_elementList_with_modules(&$elementList) * * @param array $tableau Array of constants array('key'=>array('type'=>type, 'label'=>label) * where type can be 'string', 'text', 'textarea', 'html', 'yesno', 'emailtemplate:xxx', ... - * @param int $strictw3c 0=Include form into table (deprecated), 1=Form is outside table to respect W3C (no form into table), 2=No form nor button at all (form is output by caller, recommanded) + * @param int $strictw3c 0=Include form into table (deprecated), 1=Form is outside table to respect W3C (deprecated), 2=No form nor button at all (form is output by caller, recommended) * @param string $helptext Help * @return void */ @@ -1420,6 +1420,9 @@ function form_constantes($tableau, $strictw3c = 0, $helptext = '') $form = new Form($db); + if (empty($strictw3c)) { + dol_syslog("Warning: Function form_constantes is calle with parameter strictw3c = 0, this is deprecated. Value must be 2 now.", LOG_DEBUG); + } if (!empty($strictw3c) && $strictw3c == 1) { print "\n".''; @@ -1584,12 +1587,13 @@ function form_constantes($tableau, $strictw3c = 0, $helptext = '') //var_dump($modelmail); $moreonlabel = ''; if (!empty($arrayofmessagename[$modelmail->label])) $moreonlabel = ' ('.$langs->trans("SeveralLangugeVariatFound").')'; - $arrayofmessagename[$modelmail->label] = $langs->trans(preg_replace('/\(|\)/', '', $modelmail->label)).$moreonlabel; + // The 'label' is the key that is unique if we exclude the language + $arrayofmessagename[$modelmail->label.':'.$tmp[1]] = $langs->trans(preg_replace('/\(|\)/', '', $modelmail->label)).$moreonlabel; } } //var_dump($arraydefaultmessage); //var_dump($arrayofmessagename); - print $form->selectarray('constvalue_'.$obj->name, $arrayofmessagename, $obj->value, 'None', 1, 0, '', 0, 0, 0, '', '', 1); + print $form->selectarray('constvalue_'.$obj->name, $arrayofmessagename, $obj->value.':'.$tmp[1], 'None', 0, 0, '', 0, 0, 0, '', '', 1); } else // type = 'string' ou 'chaine' { From 93e69d515d66542609e281fa2293c82790d108b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Tue, 5 May 2020 06:38:24 +0200 Subject: [PATCH 098/120] nowtime is not defined --- htdocs/core/js/lib_notification.js.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/core/js/lib_notification.js.php b/htdocs/core/js/lib_notification.js.php index 769e0a36157..250eb0231a6 100644 --- a/htdocs/core/js/lib_notification.js.php +++ b/htdocs/core/js/lib_notification.js.php @@ -37,8 +37,9 @@ if (!($_SERVER['HTTP_REFERER'] === $dolibarr_main_url_root.'/' || $_SERVER['HTTP top_httphead('text/javascript; charset=UTF-8'); print 'var login = \''.$_SESSION['dol_login'].'\';'."\n"; + print 'var nowtime = Date.now();'; print 'var time_auto_update = '.$conf->global->MAIN_BROWSER_NOTIFICATION_FREQUENCY.';'."\n"; // Always defined - print 'var time_js_next_test = (Date.now() + time_auto_update);'."\n"; + print 'var time_js_next_test = (nowtime + time_auto_update);'."\n"; ?> /* Check if permission ok */ From d6de46cc05abc417b72624534c84a8075642edf1 Mon Sep 17 00:00:00 2001 From: oscim Date: Tue, 5 May 2020 08:54:52 +0200 Subject: [PATCH 099/120] Update list.php Add massaction for payment invoice --- htdocs/compta/facture/list.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php index ed773b038bb..7caef50c223 100644 --- a/htdocs/compta/facture/list.php +++ b/htdocs/compta/facture/list.php @@ -297,7 +297,16 @@ if (empty($reshook)) include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php'; } -if ($massaction == 'withdrawrequest') +if($massaction == 'reglement'){ + + $arrayofselected=is_array($toselect)?$toselect:array(); + + $loc = dol_buildpath('/compta/paiement.php', 2).'?facids='.implode(',', $arrayofselected); + + header('Location: '.$loc); + exit; +} +elseif ($massaction == 'withdrawrequest') { $langs->load("withdrawals"); @@ -657,6 +666,7 @@ if ($resql) 'generate_doc'=>$langs->trans("ReGeneratePDF"), 'builddoc'=>$langs->trans("PDFMerge"), 'presend'=>$langs->trans("SendByMail"), + 'reglement'=>$langs->trans("InvoicePaymentsLimits"), ); if ($conf->prelevement->enabled) { $langs->load("withdrawals"); From 204c788dec7fae27cfe6e0da5d1a6afa34baba67 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Tue, 5 May 2020 06:56:54 +0000 Subject: [PATCH 100/120] Fixing style errors. --- htdocs/compta/facture/list.php | 1 - 1 file changed, 1 deletion(-) diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php index 7caef50c223..a06230ab60b 100644 --- a/htdocs/compta/facture/list.php +++ b/htdocs/compta/facture/list.php @@ -298,7 +298,6 @@ if (empty($reshook)) } if($massaction == 'reglement'){ - $arrayofselected=is_array($toselect)?$toselect:array(); $loc = dol_buildpath('/compta/paiement.php', 2).'?facids='.implode(',', $arrayofselected); From c7753dd2e0198a5a0d8c08684aff391cf1e1571c Mon Sep 17 00:00:00 2001 From: oscim Date: Tue, 5 May 2020 09:44:46 +0200 Subject: [PATCH 101/120] Update list.php --- htdocs/compta/facture/list.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php index a06230ab60b..3d7493312d1 100644 --- a/htdocs/compta/facture/list.php +++ b/htdocs/compta/facture/list.php @@ -300,7 +300,7 @@ if (empty($reshook)) if($massaction == 'reglement'){ $arrayofselected=is_array($toselect)?$toselect:array(); - $loc = dol_buildpath('/compta/paiement.php', 2).'?facids='.implode(',', $arrayofselected); + $loc = dol_buildpath('/compta/paiement.php', 2).'?action=create&facids='.implode(',', $arrayofselected); header('Location: '.$loc); exit; From db591cdcd8b9920455af51ce28267b075cbebf13 Mon Sep 17 00:00:00 2001 From: kamel Date: Tue, 5 May 2020 14:47:31 +0200 Subject: [PATCH 102/120] FIX: show value of the extrafields in the bank list --- htdocs/compta/bank/list.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/htdocs/compta/bank/list.php b/htdocs/compta/bank/list.php index eaefdfb6573..457a5986dea 100644 --- a/htdocs/compta/bank/list.php +++ b/htdocs/compta/bank/list.php @@ -556,6 +556,12 @@ foreach ($accounts as $key=>$type) } // Extra fields + if (is_array($objecttmp->array_options)) { + $obj = new stdClass(); + foreach ($objecttmp->array_options as $k => $v) { + $obj->$k = $v; + } + } include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; // Fields from hook $parameters = array('arrayfields'=>$arrayfields); From 7e6b5a384d00ea1d92a6b66f84f1a7e11c4df1a1 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 5 May 2020 15:16:30 +0200 Subject: [PATCH 103/120] Code comment --- htdocs/core/class/html.form.class.php | 36 +++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index f48ce989a7a..7073fd41989 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -1669,24 +1669,24 @@ class Form /** * Return select list of users * - * @param string $selected User id or user object of user preselected. If 0 or < -2, we use id of current user. If -1, keep unselected (if empty is allowed) - * @param string $htmlname Field name in form - * @param int $show_empty 0=list with no empty value, 1=add also an empty value into list - * @param array $exclude Array list of users id to exclude - * @param int $disabled If select list must be disabled - * @param array|string $include Array list of users id to include or 'hierarchy' to have only supervised users or 'hierarchyme' to have supervised + me - * @param array $enableonly Array list of users id to be enabled. If defined, it means that others will be disabled - * @param string $force_entity '0' or Ids of environment to force - * @param int $maxlength Maximum length of string into list (0=no limit) - * @param int $showstatus 0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status - * @param string $morefilter Add more filters into sql request (Example: 'employee = 1') - * @param integer $show_every 0=default list, 1=add also a value "Everybody" at beginning of list - * @param string $enableonlytext If option $enableonlytext is set, we use this text to explain into label why record is disabled. Not used if enableonly is empty. - * @param string $morecss More css - * @param int $noactive Show only active users (this will also happened whatever is this option if USER_HIDE_INACTIVE_IN_COMBOBOX is on). - * @param int $outputmode 0=HTML select string, 1=Array - * @param bool $multiple add [] in the name of element and add 'multiple' attribut - * @return string HTML select string + * @param string $selected User id or user object of user preselected. If 0 or < -2, we use id of current user. If -1, keep unselected (if empty is allowed) + * @param string $htmlname Field name in form + * @param int $show_empty 0=list with no empty value, 1=add also an empty value into list + * @param array $exclude Array list of users id to exclude + * @param int $disabled If select list must be disabled + * @param array|string $include Array list of users id to include. User '' for all users or 'hierarchy' to have only supervised users or 'hierarchyme' to have supervised + me + * @param array $enableonly Array list of users id to be enabled. If defined, it means that others will be disabled + * @param string $force_entity '0' or Ids of environment to force + * @param int $maxlength Maximum length of string into list (0=no limit) + * @param int $showstatus 0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status + * @param string $morefilter Add more filters into sql request (Example: 'employee = 1') + * @param integer $show_every 0=default list, 1=add also a value "Everybody" at beginning of list + * @param string $enableonlytext If option $enableonlytext is set, we use this text to explain into label why record is disabled. Not used if enableonly is empty. + * @param string $morecss More css + * @param int $noactive Show only active users (this will also happened whatever is this option if USER_HIDE_INACTIVE_IN_COMBOBOX is on). + * @param int $outputmode 0=HTML select string, 1=Array + * @param bool $multiple add [] in the name of element and add 'multiple' attribut + * @return string HTML select string * @see select_dolgroups() */ public function select_dolusers($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $show_every = 0, $enableonlytext = '', $morecss = '', $noactive = 0, $outputmode = 0, $multiple = false) From 797beef79f7c351e59cb566f5909cafc81c23c92 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 5 May 2020 15:26:41 +0200 Subject: [PATCH 104/120] Fix --- htdocs/compta/facture/list.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php index 3d7493312d1..c5a3d60f99c 100644 --- a/htdocs/compta/facture/list.php +++ b/htdocs/compta/facture/list.php @@ -297,7 +297,7 @@ if (empty($reshook)) include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php'; } -if($massaction == 'reglement'){ +if ($massaction == 'makepayment'){ $arrayofselected=is_array($toselect)?$toselect:array(); $loc = dol_buildpath('/compta/paiement.php', 2).'?action=create&facids='.implode(',', $arrayofselected); @@ -665,7 +665,7 @@ if ($resql) 'generate_doc'=>$langs->trans("ReGeneratePDF"), 'builddoc'=>$langs->trans("PDFMerge"), 'presend'=>$langs->trans("SendByMail"), - 'reglement'=>$langs->trans("InvoicePaymentsLimits"), + //'makepayment'=>$langs->trans("InvoicePaymentsLimits"), TODO Blank page when using this ); if ($conf->prelevement->enabled) { $langs->load("withdrawals"); From b2a9791dca9bd3872ba359a77439290167820ce9 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 5 May 2020 16:33:02 +0200 Subject: [PATCH 105/120] Fix pagination on pages "Related items" --- htdocs/core/lib/product.lib.php | 42 +++++++++---------- htdocs/product/stats/commande.php | 22 ++++------ htdocs/product/stats/commande_fournisseur.php | 20 ++++----- htdocs/product/stats/contrat.php | 21 ++++------ htdocs/product/stats/facture.php | 20 ++++----- htdocs/product/stats/facture_fournisseur.php | 22 ++++------ htdocs/product/stats/mo.php | 22 ++++------ htdocs/product/stats/propal.php | 20 ++++----- htdocs/product/stats/supplier_proposal.php | 22 ++++------ 9 files changed, 90 insertions(+), 121 deletions(-) diff --git a/htdocs/core/lib/product.lib.php b/htdocs/core/lib/product.lib.php index a6ee33e9a65..0615ff127b0 100644 --- a/htdocs/core/lib/product.lib.php +++ b/htdocs/core/lib/product.lib.php @@ -353,6 +353,24 @@ function show_stats_for_company($product, $socid) print ''.$langs->trans("TotalQuantity").''; print ''; + // MO + if (!empty($conf->mrp->enabled) && $user->rights->mrp->read) + { + $nblines++; + //$ret = $product->load_stats_mo($socid); + if ($ret < 0) dol_print_error($db); + $langs->load("orders"); + print ''; + print ''.img_object('', 'mrp').' '.$langs->trans("MO").''; + print ''; + print $product->stats_mo['suppliers']; + print ''; + print $product->stats_mo['nb']; + print ''; + print $product->stats_mo['qty']; + print ''; + print ''; + } // Customer proposals if (!empty($conf->propal->enabled) && $user->rights->propale->lire) { @@ -379,7 +397,7 @@ function show_stats_for_company($product, $socid) if ($ret < 0) dol_print_error($db); $langs->load("propal"); print ''; - print ''.img_object('', 'propal').' '.$langs->trans("SupplierProposals").''; + print ''.img_object('', 'supplier_proposal').' '.$langs->trans("SupplierProposals").''; print ''; print $product->stats_proposal_supplier['suppliers']; print ''; @@ -415,7 +433,7 @@ function show_stats_for_company($product, $socid) if ($ret < 0) dol_print_error($db); $langs->load("orders"); print ''; - print ''.img_object('', 'order').' '.$langs->trans("SuppliersOrders").''; + print ''.img_object('', 'supplier_order').' '.$langs->trans("SuppliersOrders").''; print ''; print $product->stats_commande_fournisseur['suppliers']; print ''; @@ -425,24 +443,6 @@ function show_stats_for_company($product, $socid) print ''; print ''; } - // MO - if (!empty($conf->mrp->enabled) && $user->rights->mrp->read) - { - $nblines++; - //$ret = $product->load_stats_mo($socid); - if ($ret < 0) dol_print_error($db); - $langs->load("orders"); - print ''; - print ''.img_object('', 'mrp').' '.$langs->trans("MO").''; - print ''; - print $product->stats_mo['suppliers']; - print ''; - print $product->stats_mo['nb']; - print ''; - print $product->stats_mo['qty']; - print ''; - print ''; - } // Customer invoices if (!empty($conf->facture->enabled) && $user->rights->facture->lire) { @@ -469,7 +469,7 @@ function show_stats_for_company($product, $socid) if ($ret < 0) dol_print_error($db); $langs->load("bills"); print ''; - print ''.img_object('', 'bill').' '.$langs->trans("SuppliersInvoices").''; + print ''.img_object('', 'supplier_invoice').' '.$langs->trans("SuppliersInvoices").''; print ''; print $product->stats_facture_fournisseur['suppliers']; print ''; diff --git a/htdocs/product/stats/commande.php b/htdocs/product/stats/commande.php index 71c1b0f1ef7..9898c13f21b 100644 --- a/htdocs/product/stats/commande.php +++ b/htdocs/product/stats/commande.php @@ -164,26 +164,22 @@ if ($id > 0 || !empty($ref)) { $num = $db->num_rows($result); - if (!empty($id)) - $option .= '&id='.$product->id; - if (!empty($search_month)) - $option .= '&search_month='.$search_month; - if (!empty($search_year)) - $option .= '&search_year='.$search_year; - if ($limit > 0 && $limit != $conf->liste_limit) $option .= '&limit='.urlencode($limit); + if ($limit > 0 && $limit != $conf->liste_limit) $option .= '&limit='.urlencode($limit); + if (!empty($id)) $option .= '&id='.$product->id; + if (!empty($search_month)) $option .= '&search_month='.urlencode($search_month); + if (!empty($search_year)) $option .= '&search_year='.urlencode($search_year); print ''."\n"; if (!empty($sortfield)) print ''; if (!empty($sortorder)) print ''; - if (!empty($page)) { - print ''; - $option .= '&page='.$page; - } - print_barre_liste($langs->trans("CustomersOrders"), $page, $_SERVER["PHP_SELF"], "&id=".$product->id, $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit); - print '
'; + print_barre_liste($langs->trans("CustomersOrders"), $page, $_SERVER["PHP_SELF"], $option, $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit, 0, 0, 1); + + if (!empty($page)) $option .= '&page='.urlencode($page); + + print '
'; print '
'; print $langs->trans('Period').' ('.$langs->trans("OrderDate").') - '; print $langs->trans('Month').': '; diff --git a/htdocs/product/stats/commande_fournisseur.php b/htdocs/product/stats/commande_fournisseur.php index 7a5b88000e1..61024cdd7ff 100644 --- a/htdocs/product/stats/commande_fournisseur.php +++ b/htdocs/product/stats/commande_fournisseur.php @@ -172,26 +172,22 @@ if ($id > 0 || !empty($ref)) { if ($result) { $num = $db->num_rows($result); - if (!empty($id)) - $option .= '&id='.$product->id; - if (!empty($search_month)) - $option .= '&search_month='.$search_month; - if (!empty($search_year)) - $option .= '&search_year='.$search_year; if ($limit > 0 && $limit != $conf->liste_limit) $option .= '&limit='.urlencode($limit); + if (!empty($id)) $option .= '&id='.$product->id; + if (!empty($search_month)) $option .= '&search_month='.urlencode($search_month); + if (!empty($search_year)) $option .= '&search_year='.urlencode($search_year); print ''."\n"; if (!empty($sortfield)) print ''; if (!empty($sortorder)) print ''; - if (!empty($page)) { - print ''; - $option .= '&page='.$page; - } - print_barre_liste($langs->trans("SuppliersOrders"), $page, $_SERVER["PHP_SELF"], "&id=".$product->id, $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit); - print '
'; + print_barre_liste($langs->trans("SuppliersOrders"), $page, $_SERVER["PHP_SELF"], $option, $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit, 0, 0, 1); + + if (!empty($page)) $option .= '&page='.urlencode($page); + + print '
'; print '
'; print $langs->trans('Period').' ('.$langs->trans("OrderDate").') - '; print $langs->trans('Month').': '; diff --git a/htdocs/product/stats/contrat.php b/htdocs/product/stats/contrat.php index 8e61446a834..8f88044d913 100644 --- a/htdocs/product/stats/contrat.php +++ b/htdocs/product/stats/contrat.php @@ -153,27 +153,24 @@ if ($id > 0 || !empty($ref)) if ($result) { $num = $db->num_rows($result); - if (!empty($id)) - $option .= '&id='.$product->id; - if (!empty($search_month)) - $option .= '&search_month='.$search_month; - if (!empty($search_year)) - $option .= '&search_year='.$search_year; + if ($limit > 0 && $limit != $conf->liste_limit) $option .= '&limit='.urlencode($limit); + if (!empty($id)) $option .= '&id='.$product->id; + if (!empty($search_month)) $option .= '&search_month='.urlencode($search_month); + if (!empty($search_year)) $option .= '&search_year='.urlencode($search_year); print ''."\n"; + if (!empty($sortfield)) print ''; if (!empty($sortorder)) print ''; - if (!empty($page)) { - print ''; - $option .= '&page='.$page; - } - print_barre_liste($langs->trans("Contrats"), $page, $_SERVER["PHP_SELF"], "&id=".$product->id, $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit); + print_barre_liste($langs->trans("Contrats"), $page, $_SERVER["PHP_SELF"], $option, $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit, 0, 0, 1); - $i = 0; + if (!empty($page)) $option .= '&page='.urlencode($page); + + $i = 0; print '
'; print ''; diff --git a/htdocs/product/stats/facture.php b/htdocs/product/stats/facture.php index e42afd9f28c..342cd3058a2 100644 --- a/htdocs/product/stats/facture.php +++ b/htdocs/product/stats/facture.php @@ -32,7 +32,7 @@ require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; // Load translation files required by the page -$langs->loadLangs(array('companies', 'bills', 'products')); +$langs->loadLangs(array('companies', 'bills', 'products', 'supplier_proposal')); $id = GETPOST('id', 'int'); $ref = GETPOST('ref', 'alpha'); @@ -185,25 +185,21 @@ if ($id > 0 || !empty($ref)) { $num = $db->num_rows($result); - if (!empty($id)) - $option .= '&id='.$product->id; - if (!empty($search_month)) - $option .= '&search_month='.$search_month; - if (!empty($search_year)) - $option .= '&search_year='.$search_year; if ($limit > 0 && $limit != $conf->liste_limit) $option .= '&limit='.urlencode($limit); + if (!empty($id)) $option .= '&id='.$product->id; + if (!empty($search_month)) $option .= '&search_month='.urlencode($search_month); + if (!empty($search_year)) $option .= '&search_year='.urlencode($search_year); print ''."\n"; if (!empty($sortfield)) print ''; if (!empty($sortorder)) print ''; - if (!empty($page)) { - print ''; - $option .= '&page='.$page; - } - print_barre_liste($langs->trans("CustomersInvoices"), $page, $_SERVER["PHP_SELF"], "&id=".$product->id, $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit); + print_barre_liste($langs->trans("CustomersInvoices"), $page, $_SERVER["PHP_SELF"], $option, $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit, 0, 0, 1); + + if (!empty($page)) $option .= '&page='.urlencode($page); + print '
'; print '
'; print $langs->trans('Period').' ('.$langs->trans("DateInvoice").') - '; diff --git a/htdocs/product/stats/facture_fournisseur.php b/htdocs/product/stats/facture_fournisseur.php index 29774709e5e..f39d4ab73b3 100644 --- a/htdocs/product/stats/facture_fournisseur.php +++ b/htdocs/product/stats/facture_fournisseur.php @@ -32,7 +32,7 @@ require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; // Load translation files required by the page -$langs->loadLangs(array('companies', 'bills', 'products', 'companies')); +$langs->loadLangs(array('companies', 'bills', 'products', 'companies', 'supplier_proposal')); $id = GETPOST('id', 'int'); $ref = GETPOST('ref', 'alpha'); @@ -165,26 +165,22 @@ if ($id > 0 || !empty($ref)) { $num = $db->num_rows($result); - if (!empty($id)) - $option .= '&id='.$product->id; - if (!empty($search_month)) - $option .= '&search_month='.$search_month; - if (!empty($search_year)) - $option .= '&search_year='.$search_year; if ($limit > 0 && $limit != $conf->liste_limit) $option .= '&limit='.urlencode($limit); + if (!empty($id)) $option .= '&id='.$product->id; + if (!empty($search_month)) $option .= '&search_month='.urlencode($search_month); + if (!empty($search_year)) $option .= '&search_year='.urlencode($search_year); print ''."\n"; if (!empty($sortfield)) print ''; if (!empty($sortorder)) print ''; - if (!empty($page)) { - print ''; - $option .= '&page='.$page; - } - print_barre_liste($langs->trans("SuppliersInvoices"), $page, $_SERVER["PHP_SELF"], "&id=$product->id", $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit); - print '
'; + print_barre_liste($langs->trans("SuppliersInvoices"), $page, $_SERVER["PHP_SELF"], $option, $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit, 0, 0, 1); + + if (!empty($page)) $option .= '&page='.urlencode($page); + + print '
'; print '
'; print $langs->trans('Period').' ('.$langs->trans("DateInvoice").') - '; print $langs->trans('Month').': '; diff --git a/htdocs/product/stats/mo.php b/htdocs/product/stats/mo.php index 0a148ad2c8a..51e91aeaaac 100644 --- a/htdocs/product/stats/mo.php +++ b/htdocs/product/stats/mo.php @@ -150,27 +150,23 @@ if ($id > 0 || !empty($ref)) if ($result) { $num = $db->num_rows($result); - if (!empty($id)) - $option .= '&id='.$product->id; - if (!empty($search_month)) - $option .= '&search_month='.urlencode($search_month); - if (!empty($search_year)) - $option .= '&search_year='.urlencode($search_year); - if ($limit > 0 && $limit != $conf->liste_limit) $option .= '&limit='.urlencode($limit); + + if ($limit > 0 && $limit != $conf->liste_limit) $option .= '&limit='.urlencode($limit); + if (!empty($id)) $option .= '&id='.$product->id; + if (!empty($search_month)) $option .= '&search_month='.urlencode($search_month); + if (!empty($search_year)) $option .= '&search_year='.urlencode($search_year); print ''."\n"; if (!empty($sortfield)) print ''; if (!empty($sortorder)) print ''; - if (!empty($page)) { - print ''; - $option .= '&page='.$page; - } - print_barre_liste($langs->trans("Mos"), $page, $_SERVER["PHP_SELF"], "&id=".$product->id, $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit); + print_barre_liste($langs->trans("Mos"), $page, $_SERVER["PHP_SELF"], $option, $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit, 0, 0, 1); - $i = 0; + if (!empty($page)) $option .= '&page='.urlencode($page); + + $i = 0; print '
'; print '
'; diff --git a/htdocs/product/stats/propal.php b/htdocs/product/stats/propal.php index d65b88ccabc..35b93cac8b9 100644 --- a/htdocs/product/stats/propal.php +++ b/htdocs/product/stats/propal.php @@ -169,26 +169,22 @@ if ($id > 0 || !empty($ref)) { $num = $db->num_rows($result); - if (!empty($id)) - $option .= '&id='.$product->id; - if (!empty($search_month)) - $option .= '&search_month='.$search_month; - if (!empty($search_year)) - $option .= '&search_year='.$search_year; if ($limit > 0 && $limit != $conf->liste_limit) $option .= '&limit='.urlencode($limit); + if (!empty($id)) $option .= '&id='.$product->id; + if (!empty($search_month)) $option .= '&search_month='.urlencode($search_month); + if (!empty($search_year)) $option .= '&search_year='.urlencode($search_year); print ''."\n"; if (!empty($sortfield)) print ''; if (!empty($sortorder)) print ''; - if (!empty($page)) { - print ''; - $option .= '&page='.$page; - } - print_barre_liste($langs->trans("Proposals"), $page, $_SERVER["PHP_SELF"], "&id=".$product->id, $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit); - print '
'; + print_barre_liste($langs->trans("Proposals"), $page, $_SERVER["PHP_SELF"], $option, $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit, 0, 0, 1); + + if (!empty($page)) $option .= '&page='.urlencode($page); + + print '
'; print '
'; print $langs->trans('Period').' ('.$langs->trans("DatePropal").') - '; print $langs->trans('Month').': '; diff --git a/htdocs/product/stats/supplier_proposal.php b/htdocs/product/stats/supplier_proposal.php index a7fede51aa1..5a59cbb9c83 100644 --- a/htdocs/product/stats/supplier_proposal.php +++ b/htdocs/product/stats/supplier_proposal.php @@ -31,7 +31,7 @@ require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; // Load translation files required by the page -$langs->loadLangs(array('products', 'companies')); +$langs->loadLangs(array('products', 'companies', 'supplier_proposal')); $id = GETPOST('id', 'int'); $ref = GETPOST('ref', 'alpha'); @@ -169,26 +169,22 @@ if ($id > 0 || !empty($ref)) { $num = $db->num_rows($result); - if (!empty($id)) - $option .= '&id='.$product->id; - if (!empty($search_month)) - $option .= '&search_month='.$search_month; - if (!empty($search_year)) - $option .= '&search_year='.$search_year; if ($limit > 0 && $limit != $conf->liste_limit) $option .= '&limit='.urlencode($limit); + if (!empty($id)) $option .= '&id='.$product->id; + if (!empty($search_month)) $option .= '&search_month='.urlencode($search_month); + if (!empty($search_year)) $option .= '&search_year='.urlencode($search_year); print ''."\n"; if (!empty($sortfield)) print ''; if (!empty($sortorder)) print ''; - if (!empty($page)) { - print ''; - $option .= '&page='.$page; - } - print_barre_liste($langs->trans("Proposals"), $page, $_SERVER["PHP_SELF"], "&id=".$product->id, $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit); - print '
'; + print_barre_liste($langs->trans("Proposals"), $page, $_SERVER["PHP_SELF"], $option, $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit, 0, 0, 1); + + if (!empty($page)) $option .= '&page='.urlencode($page); + + print '
'; print '
'; print $langs->trans('Period').' ('.$langs->trans("DatePropal").') - '; print $langs->trans('Month').': '; From e871e736ebc18b39473b2227b631160444b07498 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 5 May 2020 17:54:01 +0200 Subject: [PATCH 106/120] Fix for #5824 --- htdocs/modulebuilder/template/myobject_card.php | 2 +- htdocs/mrp/class/mo.class.php | 2 +- htdocs/mrp/mo_card.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/modulebuilder/template/myobject_card.php b/htdocs/modulebuilder/template/myobject_card.php index 336b410022a..c0b33be2bf8 100644 --- a/htdocs/modulebuilder/template/myobject_card.php +++ b/htdocs/modulebuilder/template/myobject_card.php @@ -533,7 +533,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea */ // Delete (need delete permission, or if draft, just need create/modify permission) - if ($permissiontodelete) + if ($permissiontodelete || ($object->status == $object::STATUS_DRAFT && $permissiontoadd)) { print ''.$langs->trans('Delete').''."\n"; } diff --git a/htdocs/mrp/class/mo.class.php b/htdocs/mrp/class/mo.class.php index 42d97ee81d9..07c6eae52a1 100644 --- a/htdocs/mrp/class/mo.class.php +++ b/htdocs/mrp/class/mo.class.php @@ -1008,7 +1008,7 @@ class Mo extends CommonObject } $url = dol_buildpath('/mrp/mo_card.php', 1).'?id='.$this->id; - if ($option = 'production') $url = dol_buildpath('/mrp/mo_production.php', 1).'?id='.$this->id; + if ($option == 'production') $url = dol_buildpath('/mrp/mo_production.php', 1).'?id='.$this->id; if ($option != 'nolink') { diff --git a/htdocs/mrp/mo_card.php b/htdocs/mrp/mo_card.php index 59dd5ed7a7c..92f68785856 100644 --- a/htdocs/mrp/mo_card.php +++ b/htdocs/mrp/mo_card.php @@ -639,7 +639,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea } // Delete (need delete permission, or if draft, just need create/modify permission) - if ($permissiontodelete) + if ($permissiontodelete || ($object->status == $object::STATUS_DRAFT && $permissiontoadd)) { print ''.$langs->trans('Delete').''."\n"; } From ea145188b90b5515e6d1fd4bcb5c0de9c1cc3729 Mon Sep 17 00:00:00 2001 From: florian HENRY Date: Tue, 5 May 2020 18:14:38 +0200 Subject: [PATCH 107/120] fix filter on date service contrat with hour --- htdocs/contrat/services_list.php | 33 ++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/htdocs/contrat/services_list.php b/htdocs/contrat/services_list.php index b8ab4cfe1ce..b250ea23378 100644 --- a/htdocs/contrat/services_list.php +++ b/htdocs/contrat/services_list.php @@ -247,22 +247,31 @@ if ($search_name) $sql .= " AND s.nom LIKE '%".$db->escape($search_name)."%' if ($search_contract) $sql .= " AND c.ref LIKE '%".$db->escape($search_contract)."%' "; if ($search_service) $sql .= " AND (p.ref LIKE '%".$db->escape($search_service)."%' OR p.description LIKE '%".$db->escape($search_service)."%' OR cd.description LIKE '%".$db->escape($search_service)."%')"; if ($socid > 0) $sql .= " AND s.rowid = ".$socid; -$filter_dateouvertureprevue = dol_mktime(0, 0, 0, $opouvertureprevuemonth, $opouvertureprevueday, $opouvertureprevueyear); -if ($filter_dateouvertureprevue != '' && $filter_opouvertureprevue == -1) $filter_opouvertureprevue = '='; -$filter_date1 = dol_mktime(0, 0, 0, $op1month, $op1day, $op1year); -if ($filter_date1 != '' && $filter_op1 == -1) $filter_op1 = '='; +$filter_dateouvertureprevue_start=dol_mktime(0, 0, 0, $opouvertureprevuemonth, $opouvertureprevueday, $opouvertureprevueyear); +$filter_dateouvertureprevue_end=dol_mktime(23, 59, 59, $opouvertureprevuemonth, $opouvertureprevueday, $opouvertureprevueyear); +if ($filter_dateouvertureprevue_start != '' && $filter_opouvertureprevue == -1) $filter_opouvertureprevue = ' BETWEEN '; -$filter_date2 = dol_mktime(0, 0, 0, $op2month, $op2day, $op2year); -if ($filter_date2 != '' && $filter_op2 == -1) $filter_op2 = '='; +$filter_date1_start =dol_mktime(0, 0, 0, $op1month, $op1day, $op1year); +$filter_date1_end =dol_mktime(23, 59, 59, $op1month, $op1day, $op1year); +if ($filter_date1_start != '' && $filter_op1 == -1) $filter_op1 = ' BETWEEN '; -$filter_datecloture = dol_mktime(0, 0, 0, $opcloturemonth, $opclotureday, $opclotureyear); -if ($filter_datecloture != '' && $filter_opcloture == -1) $filter_opcloture = '='; +$filter_date2_start=dol_mktime(0, 0, 0, $op2month, $op2day, $op2year); +$filter_date2_end=dol_mktime(23, 59, 59, $op2month, $op2day, $op2year); +if ($filter_date2_start != '' && $filter_op2 == -1) $filter_op2 = ' BETWEEN '; -if (!empty($filter_opouvertureprevue) && $filter_opouvertureprevue != -1 && $filter_dateouvertureprevue != '') $sql .= " AND cd.date_ouverture_prevue ".$filter_opouvertureprevue." '".$db->idate($filter_dateouvertureprevue)."'"; -if (!empty($filter_op1) && $filter_op1 != -1 && $filter_date1 != '') $sql .= " AND cd.date_ouverture ".$filter_op1." '".$db->idate($filter_date1)."'"; -if (!empty($filter_op2) && $filter_op2 != -1 && $filter_date2 != '') $sql .= " AND cd.date_fin_validite ".$filter_op2." '".$db->idate($filter_date2)."'"; -if (!empty($filter_opcloture) && $filter_opcloture != -1 && $filter_datecloture != '') $sql .= " AND cd.date_cloture ".$filter_opcloture." '".$db->idate($filter_datecloture)."'"; +$filter_datecloture_start=dol_mktime(0, 0, 0, $opcloturemonth, $opclotureday, $opclotureyear); +$filter_datecloture_end=dol_mktime(23, 59, 59, $opcloturemonth, $opclotureday, $opclotureyear); +if ($filter_datecloture_start != '' && $filter_opcloture == -1) $filter_opcloture = ' BETWEEN '; + +if (! empty($filter_opouvertureprevue) && $filter_opouvertureprevue != -1 && $filter_opouvertureprevue != ' BETWEEN ' && $filter_dateouvertureprevue_start != '') $sql.= " AND cd.date_ouverture_prevue ".$filter_opouvertureprevue." '".$db->idate($filter_dateouvertureprevue_start)."'"; +if (! empty($filter_opouvertureprevue) && $filter_opouvertureprevue == ' BETWEEN ') $sql.= " AND '".$db->idate($filter_dateouvertureprevue_end)."'"; +if (! empty($filter_op1) && $filter_op1 != -1 && $filter_op1 != ' BETWEEN ' && $filter_date1_start != '') $sql.= " AND cd.date_ouverture ".$filter_op1." '".$db->idate($filter_date1_start)."'"; +if (! empty($filter_op1) && $filter_op1==' BETWEEN ') $sql.= " AND '".$db->idate($filter_date1_end)."'"; +if (! empty($filter_op2) && $filter_op2 != -1 && $filter_op2 != ' BETWEEN ' && $filter_date2_start != '') $sql.= " AND cd.date_fin_validite ".$filter_op2." '".$db->idate($filter_date2_start)."'"; +if (! empty($filter_op2) && $filter_op2==' BETWEEN ') $sql.= " AND '".$db->idate($filter_date2_end)."'"; +if (! empty($filter_opcloture) && $filter_opcloture != ' BETWEEN ' && $filter_opcloture != -1 && $filter_datecloture_start != '') $sql.= " AND cd.date_cloture ".$filter_opcloture." '".$db->idate($filter_datecloture_start)."'"; +if (! empty($filter_opcloture) && $filter_opcloture==' BETWEEN ') $sql.= " AND '".$db->idate($filter_datecloture_end)."'"; // Add where from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; $sql .= $db->order($sortfield, $sortorder); From 49f9e88cc179162ffcc510a82f95011eefd9f126 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 5 May 2020 18:16:30 +0200 Subject: [PATCH 108/120] Look and feel v12 --- htdocs/core/lib/usergroups.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/usergroups.lib.php b/htdocs/core/lib/usergroups.lib.php index 3be6a5b44ba..f25d8058e8f 100644 --- a/htdocs/core/lib/usergroups.lib.php +++ b/htdocs/core/lib/usergroups.lib.php @@ -745,7 +745,7 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false) { print $formother->showColor($conf->global->THEME_ELDY_TEXTTITLELINK, $langs->trans("Default")); } - print '   ('.$langs->trans("Default").': '.$default.') '; + print '   '.$langs->trans("Default").': '.$default.' '; print $form->textwithpicto('', $langs->trans("NotSupportedByAllThemes").', '.$langs->trans("PressF5AfterChangingThis")); print ''; print ''; From e354e714256ab661736b2edd7f1ef6376d640b35 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 5 May 2020 18:19:48 +0200 Subject: [PATCH 109/120] Fix link to themes on dolistore --- htdocs/core/lib/usergroups.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/usergroups.lib.php b/htdocs/core/lib/usergroups.lib.php index f25d8058e8f..9ac9383e516 100644 --- a/htdocs/core/lib/usergroups.lib.php +++ b/htdocs/core/lib/usergroups.lib.php @@ -359,7 +359,7 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false) print $form->textwithpicto($langs->trans("DefaultSkin"), $langs->trans("ThemeDir").' : '.$dirthemestring); print ''; print '
'; - $url = 'https://www.dolistore.com/4-skins'; + $url = 'https://www.dolistore.com/9-skins'; print ''; print $langs->trans('DownloadMoreSkins'); print ''; From 41aaf5363dd3b4807bc52e86a568a94f7d78d825 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 5 May 2020 18:53:41 +0200 Subject: [PATCH 110/120] Fix templates --- .../template/myobject_agenda.php | 70 +++++++++-------- .../modulebuilder/template/myobject_card.php | 72 +++++++++--------- .../template/myobject_document.php | 40 ++++++++++ .../modulebuilder/template/myobject_note.php | 76 +++++++++---------- htdocs/mrp/mo_agenda.php | 2 +- htdocs/mrp/mo_card.php | 5 +- htdocs/mrp/mo_document.php | 2 +- htdocs/mrp/mo_note.php | 2 +- 8 files changed, 153 insertions(+), 116 deletions(-) diff --git a/htdocs/modulebuilder/template/myobject_agenda.php b/htdocs/modulebuilder/template/myobject_agenda.php index 559c5ed47b0..9b71971b6cf 100644 --- a/htdocs/modulebuilder/template/myobject_agenda.php +++ b/htdocs/modulebuilder/template/myobject_agenda.php @@ -148,44 +148,42 @@ if ($object->id > 0) $morehtmlref = '
'; /* - // Ref customer - $morehtmlref.=$form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', 0, 1); - $morehtmlref.=$form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', null, null, '', 1); - // Thirdparty - $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . $object->thirdparty->getNomUrl(1); - // Project - if (! empty($conf->projet->enabled)) - { - $langs->load("projects"); - $morehtmlref.='
'.$langs->trans('Project') . ' '; - if ($permissiontoadd) - { - if ($action != 'classify') - //$morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; - $morehtmlref.=' : '; - if ($action == 'classify') { - //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); - $morehtmlref.=''; - $morehtmlref.=''; - $morehtmlref.=''; - $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); - $morehtmlref.=''; - $morehtmlref.=''; + // Ref customer + $morehtmlref.=$form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . (is_object($object->thirdparty) ? $object->thirdparty->getNomUrl(1) : ''); + // Project + if (! empty($conf->projet->enabled)) + { + $langs->load("projects"); + $morehtmlref.='
'.$langs->trans('Project') . ' '; + if ($permissiontoadd) + { + if ($action != 'classify') + //$morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + $morehtmlref.=' : '; + if ($action == 'classify') { + //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref.='
'; + $morehtmlref.=''; + $morehtmlref.=''; + $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref.=''; + $morehtmlref.='
'; + } else { + $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } } else { - $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + if (! empty($object->fk_project)) { + $proj = new Project($db); + $proj->fetch($object->fk_project); + $morehtmlref .= ': '.$proj->getNomUrl(); + } else { + $morehtmlref .= ''; + } } - } else { - if (! empty($object->fk_project)) { - $proj = new Project($db); - $proj->fetch($object->fk_project); - $morehtmlref.=''; - $morehtmlref.=$proj->ref; - $morehtmlref.=''; - } else { - $morehtmlref.=''; - } - } - }*/ + }*/ $morehtmlref .= '
'; diff --git a/htdocs/modulebuilder/template/myobject_card.php b/htdocs/modulebuilder/template/myobject_card.php index c0b33be2bf8..e92c88f1364 100644 --- a/htdocs/modulebuilder/template/myobject_card.php +++ b/htdocs/modulebuilder/template/myobject_card.php @@ -331,42 +331,42 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea $morehtmlref = '
'; /* - // Ref bis - $morehtmlref.=$form->editfieldkey("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->mymodule->myobject->creer, 'string', '', 0, 1); - $morehtmlref.=$form->editfieldval("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->mymodule->myobject->creer, 'string', '', null, null, '', 1); - // Thirdparty - $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . (is_object($object->thirdparty) ? $object->thirdparty->getNomUrl(1) : ''); - // Project - if (! empty($conf->projet->enabled)) - { - $langs->load("projects"); - $morehtmlref.='
'.$langs->trans('Project') . ' '; - if ($permissiontoadd) - { - if ($action != 'classify') - $morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; - if ($action == 'classify') { - //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); - $morehtmlref.='
'; - $morehtmlref.=''; - $morehtmlref.=''; - $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', 0, 0, 1, 0, 1, 0, 0, '', 1); - $morehtmlref.=''; - $morehtmlref.='
'; - } else { - $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); - } - } else { - if (! empty($object->fk_project)) { - $proj = new Project($db); - $proj->fetch($object->fk_project); - $morehtmlref.=$proj->getNomUrl(); - } else { - $morehtmlref.=''; - } - } - } - */ + // Ref customer + $morehtmlref.=$form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . (is_object($object->thirdparty) ? $object->thirdparty->getNomUrl(1) : ''); + // Project + if (! empty($conf->projet->enabled)) + { + $langs->load("projects"); + $morehtmlref.='
'.$langs->trans('Project') . ' '; + if ($permissiontoadd) + { + if ($action != 'classify') + //$morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + $morehtmlref.=' : '; + if ($action == 'classify') { + //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref.='
'; + $morehtmlref.=''; + $morehtmlref.=''; + $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref.=''; + $morehtmlref.='
'; + } else { + $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + if (! empty($object->fk_project)) { + $proj = new Project($db); + $proj->fetch($object->fk_project); + $morehtmlref .= ': '.$proj->getNomUrl(); + } else { + $morehtmlref .= ''; + } + } + }*/ $morehtmlref .= '
'; diff --git a/htdocs/modulebuilder/template/myobject_document.php b/htdocs/modulebuilder/template/myobject_document.php index 5f3cdf02684..63b114ffc10 100644 --- a/htdocs/modulebuilder/template/myobject_document.php +++ b/htdocs/modulebuilder/template/myobject_document.php @@ -129,6 +129,46 @@ if ($object->id) // ------------------------------------------------------------ $linkback = ''.$langs->trans("BackToList").''; + $morehtmlref = '
'; + /* + // Ref customer + $morehtmlref.=$form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . (is_object($object->thirdparty) ? $object->thirdparty->getNomUrl(1) : ''); + // Project + if (! empty($conf->projet->enabled)) + { + $langs->load("projects"); + $morehtmlref.='
'.$langs->trans('Project') . ' '; + if ($permissiontoadd) + { + if ($action != 'classify') + //$morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + $morehtmlref.=' : '; + if ($action == 'classify') { + //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref.='
'; + $morehtmlref.=''; + $morehtmlref.=''; + $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref.=''; + $morehtmlref.='
'; + } else { + $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + if (! empty($object->fk_project)) { + $proj = new Project($db); + $proj->fetch($object->fk_project); + $morehtmlref .= ': '.$proj->getNomUrl(); + } else { + $morehtmlref .= ''; + } + } + }*/ + $morehtmlref .= '
'; + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); print '
'; diff --git a/htdocs/modulebuilder/template/myobject_note.php b/htdocs/modulebuilder/template/myobject_note.php index f116bf51f5b..aece1f98f29 100644 --- a/htdocs/modulebuilder/template/myobject_note.php +++ b/htdocs/modulebuilder/template/myobject_note.php @@ -103,45 +103,43 @@ if ($id > 0 || !empty($ref)) $morehtmlref = '
'; /* - // Ref customer - $morehtmlref.=$form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', 0, 1); - $morehtmlref.=$form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', null, null, '', 1); - // Thirdparty - $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . $object->thirdparty->getNomUrl(1); - // Project - if (! empty($conf->projet->enabled)) - { - $langs->load("projects"); - $morehtmlref.='
'.$langs->trans('Project') . ' '; - if ($permissiontoadd) - { - if ($action != 'classify') - //$morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; - $morehtmlref.=' : '; - if ($action == 'classify') { - //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); - $morehtmlref.='
'; - $morehtmlref.=''; - $morehtmlref.=''; - $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); - $morehtmlref.=''; - $morehtmlref.='
'; - } else { - $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); - } - } else { - if (! empty($object->fk_project)) { - $proj = new Project($db); - $proj->fetch($object->fk_project); - $morehtmlref.=''; - $morehtmlref.=$proj->ref; - $morehtmlref.=''; - } else { - $morehtmlref.=''; - } - } - }*/ - $morehtmlref .= '
'; + // Ref customer + $morehtmlref.=$form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . (is_object($object->thirdparty) ? $object->thirdparty->getNomUrl(1) : ''); + // Project + if (! empty($conf->projet->enabled)) + { + $langs->load("projects"); + $morehtmlref.='
'.$langs->trans('Project') . ' '; + if ($permissiontoadd) + { + if ($action != 'classify') + //$morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + $morehtmlref.=' : '; + if ($action == 'classify') { + //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref.='
'; + $morehtmlref.=''; + $morehtmlref.=''; + $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref.=''; + $morehtmlref.='
'; + } else { + $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + if (! empty($object->fk_project)) { + $proj = new Project($db); + $proj->fetch($object->fk_project); + $morehtmlref .= ': '.$proj->getNomUrl(); + } else { + $morehtmlref .= ''; + } + } + }*/ + $morehtmlref .= '
'; dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); diff --git a/htdocs/mrp/mo_agenda.php b/htdocs/mrp/mo_agenda.php index 6da02f8d5bd..eee839c8a83 100644 --- a/htdocs/mrp/mo_agenda.php +++ b/htdocs/mrp/mo_agenda.php @@ -169,7 +169,7 @@ if ($object->id > 0) if (!empty($object->fk_project)) { $proj = new Project($db); $proj->fetch($object->fk_project); - $morehtmlref .= $proj->getNomUrl(); + $morehtmlref .= ': '.$proj->getNomUrl(); } else { $morehtmlref .= ''; } diff --git a/htdocs/mrp/mo_card.php b/htdocs/mrp/mo_card.php index 92f68785856..86b2b886dea 100644 --- a/htdocs/mrp/mo_card.php +++ b/htdocs/mrp/mo_card.php @@ -427,7 +427,8 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea $morehtmlref.=$form->editfieldkey("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->mrp->creer, 'string', '', 0, 1); $morehtmlref.=$form->editfieldval("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->mrp->creer, 'string', '', null, null, '', 1);*/ // Thirdparty - $morehtmlref .= $langs->trans('ThirdParty').' : '.(is_object($object->thirdparty) ? $object->thirdparty->getNomUrl(1) : ''); + $morehtmlref .= $langs->trans('ThirdParty').' '; + $morehtmlref .= ': '.(is_object($object->thirdparty) ? $object->thirdparty->getNomUrl(1) : ''); // Project if (!empty($conf->projet->enabled)) { @@ -452,7 +453,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea if (!empty($object->fk_project)) { $proj = new Project($db); $proj->fetch($object->fk_project); - $morehtmlref .= $proj->getNomUrl(); + $morehtmlref .= ' : '.$proj->getNomUrl(); } else { $morehtmlref .= ''; } diff --git a/htdocs/mrp/mo_document.php b/htdocs/mrp/mo_document.php index a7baa2d9144..48031b6f372 100644 --- a/htdocs/mrp/mo_document.php +++ b/htdocs/mrp/mo_document.php @@ -147,7 +147,7 @@ if ($object->id) if (!empty($object->fk_project)) { $proj = new Project($db); $proj->fetch($object->fk_project); - $morehtmlref .= $proj->getNomUrl(); + $morehtmlref .= ': '.$proj->getNomUrl(); } else { $morehtmlref .= ''; } diff --git a/htdocs/mrp/mo_note.php b/htdocs/mrp/mo_note.php index e22d3e4b610..d8b72fc348c 100644 --- a/htdocs/mrp/mo_note.php +++ b/htdocs/mrp/mo_note.php @@ -122,7 +122,7 @@ if ($id > 0 || !empty($ref)) if (!empty($object->fk_project)) { $proj = new Project($db); $proj->fetch($object->fk_project); - $morehtmlref .= $proj->getNomUrl(); + $morehtmlref .= ' : '.$proj->getNomUrl(); } else { $morehtmlref .= ''; } From d6c8988cec406432a4aa45834bbef5745a5074a4 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 5 May 2020 19:29:47 +0200 Subject: [PATCH 111/120] Look and field v12 --- htdocs/contrat/card.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/contrat/card.php b/htdocs/contrat/card.php index 21d46fb2974..52144d44d34 100644 --- a/htdocs/contrat/card.php +++ b/htdocs/contrat/card.php @@ -1644,13 +1644,13 @@ else } if ($user->rights->contrat->creer && ($object->statut >= 0)) { - print ''; + print ''; print img_edit(); print ''; } if ($user->rights->contrat->creer && ($object->statut >= 0)) { - print ''; + print ''; print img_delete(); print ''; } From ebe169b9ef0b97282cf1c2f9c254ae72ca57355a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 5 May 2020 20:51:29 +0200 Subject: [PATCH 112/120] Fix objects used for profit calculation. --- htdocs/projet/element.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/htdocs/projet/element.php b/htdocs/projet/element.php index 34dace09e93..23fa6551656 100644 --- a/htdocs/projet/element.php +++ b/htdocs/projet/element.php @@ -526,6 +526,32 @@ $listofreferent = array( */ ); +// Change rules for benefit calculation +if (! empty($conf->global->PROJECT_ELEMENTS_FOR_PLUS_MARGIN)) { + foreach($listofreferent as $key => $element) { + if ($listofreferent[$key]['margin'] == 'add') { + unset($listofreferent[$key]['margin']); + } + } + $newelementforplusmargin = explode(',', $conf->global->PROJECT_ELEMENTS_FOR_PLUS_MARGIN); + foreach($newelementforplusmargin as $value) { + $listofreferent[$value]['margin']='add'; + } +} +if (! empty($conf->global->PROJECT_ELEMENTS_FOR_MINUS_MARGIN)) { + foreach($listofreferent as $key => $element) { + if ($listofreferent[$key]['margin'] == 'add') { + unset($listofreferent[$key]['margin']); + } + } + $newelementforplusmargin = explode(',', $conf->global->PROJECT_ELEMENTS_FOR_MINUS_MARGIN); + foreach($newelementforplusmargin as $value) { + $listofreferent[$value]['margin']='minus'; + } +} + + + $parameters = array('listofreferent'=>$listofreferent); $resHook = $hookmanager->executeHooks('completeListOfReferent', $parameters, $object, $action); From 07178fb6c09458801bad16e4e0618e77e96fc583 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 5 May 2020 20:52:50 +0200 Subject: [PATCH 113/120] Fix look and feel --- htdocs/admin/const.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/admin/const.php b/htdocs/admin/const.php index 9f3accfe549..bc22a2020fb 100644 --- a/htdocs/admin/const.php +++ b/htdocs/admin/const.php @@ -328,10 +328,10 @@ if ($conf->use_javascript_ajax) { print '
'; print '
'; - print ''; + print ''; print '
'; print '
'; - print ''; + print ''; print '
'; } From 650096ea0f4a95b4dd5542f7b2e801e9e94fedcd Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 5 May 2020 21:27:40 +0200 Subject: [PATCH 114/120] Fix look and feel v12 --- htdocs/modulebuilder/index.php | 49 +++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/htdocs/modulebuilder/index.php b/htdocs/modulebuilder/index.php index 5b90f2a8f98..1be2ac09971 100644 --- a/htdocs/modulebuilder/index.php +++ b/htdocs/modulebuilder/index.php @@ -2122,7 +2122,7 @@ elseif (!empty($module)) print '
'; print ' '.$langs->trans("DescriptorFile").' : '.$pathtofile.''; - print ' '.img_picto($langs->trans("Edit"), 'edit').''; + print ' '.img_picto($langs->trans("Edit"), 'edit').''; print '
'; print ' '.$langs->trans("LanguageFile").' : '; if (!is_array($dicts) || empty($dicts)) print ''.$langs->trans("NoDictionaries").''; @@ -2867,7 +2867,7 @@ elseif (!empty($module)) print '
'; print ' '.$langs->trans("DescriptorFile").' : '.$pathtofile.''; - print ' '.img_picto($langs->trans("Edit"), 'edit').''; + print ' '.img_picto($langs->trans("Edit"), 'edit').''; print '
'; print '
'; @@ -3007,7 +3007,7 @@ elseif (!empty($module)) print '
'; print ' '.$langs->trans("DescriptorFile").' : '.$pathtofile.''; - print ' '.img_picto($langs->trans("Edit"), 'edit').''; + print ' '.img_picto($langs->trans("Edit"), 'edit').''; print '
'; print '
'; @@ -3099,12 +3099,13 @@ elseif (!empty($module)) print ''.$langs->trans("HooksDefDesc").'
'; print '
'; - print ''; + print ''; print ''; } else @@ -3279,7 +3292,7 @@ elseif (!empty($module)) if (dol_is_file($dirins.'/'.$pathtohook)) { print ''.$pathtohook.''; - print ''; + print ''; print ''; } else @@ -3335,7 +3348,7 @@ elseif (!empty($module)) $pathtofile = $widget['relpath']; print ''; print ''; } @@ -3473,7 +3486,7 @@ elseif (!empty($module)) print '
'; print ' '.$langs->trans("DescriptorFile").' : '.$pathtofile.''; - print ' '.img_picto($langs->trans("Edit"), 'edit').''; + print ' '.img_picto($langs->trans("Edit"), 'edit').''; print '
'; print '
'; @@ -3602,7 +3615,7 @@ elseif (!empty($module)) if (preg_match('/\.md$/i', $spec['name'])) $format = 'markdown'; print ''; + print ''; print ''; print ''; } @@ -3657,7 +3670,7 @@ elseif (!empty($module)) // HTML print ' '.$langs->trans("PathToModuleDocumentation", "HTML").' : '; - if (!dol_is_file($outputfiledoc)) print ''.$langs->trans("FileNotYetGenerated").''; + if (!dol_is_file($outputfiledoc)) print ''.$langs->trans("FileNotYetGenerated").''; else { print ''; print ''; @@ -3670,7 +3683,7 @@ elseif (!empty($module)) // PDF print ' '.$langs->trans("PathToModuleDocumentation", "PDF").' : '; - if (!dol_is_file($outputfiledocpdf)) print ''.$langs->trans("FileNotYetGenerated").''; + if (!dol_is_file($outputfiledocpdf)) print ''.$langs->trans("FileNotYetGenerated").''; else { print ''; print ''; @@ -3744,7 +3757,7 @@ elseif (!empty($module)) print '
'; print ' '.$langs->trans("PathToModulePackage").' : '; - if (!dol_is_file($outputfilezip)) print ''.$langs->trans("FileNotYetGenerated").''; + if (!dol_is_file($outputfilezip)) print ''.$langs->trans("FileNotYetGenerated").''; else { $relativepath = $modulelowercase.'/bin/'.$FILENAMEZIP; print '
'.$outputfilezip.''; From eacb1b3b2e399d365bab45e58e3cf184b3d42af7 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 5 May 2020 21:45:10 +0200 Subject: [PATCH 115/120] Debug modulebuilder --- htdocs/core/lib/files.lib.php | 11 ++++++++++- htdocs/modulebuilder/index.php | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 941cb03d6c4..dbea182fb9b 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -761,8 +761,17 @@ function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayrep if (is_dir($ossrcfile."/".$file)) { if (empty($excludesubdir) || ($excludesubdir == 2 && strlen($file) == 2)) { + $newfile = $file; + // Replace destination filename with a new one + if (is_array($arrayreplacement)) + { + foreach ($arrayreplacement as $key => $val) + { + $newfile = str_replace($key, $val, $newfile); + } + } //var_dump("xxx dolCopyDir $srcfile/$file, $destfile/$file, $newmask, $overwriteifexists"); - $tmpresult = dolCopyDir($srcfile."/".$file, $destfile."/".$file, $newmask, $overwriteifexists, $arrayreplacement, $excludesubdir); + $tmpresult = dolCopyDir($srcfile."/".$file, $destfile."/".$newfile, $newmask, $overwriteifexists, $arrayreplacement, $excludesubdir); } } else diff --git a/htdocs/modulebuilder/index.php b/htdocs/modulebuilder/index.php index 1be2ac09971..d813c3b291b 100644 --- a/htdocs/modulebuilder/index.php +++ b/htdocs/modulebuilder/index.php @@ -180,8 +180,10 @@ if ($dirins && $action == 'initmodule' && $modulename) dol_delete_file($destdir.'/sql/llx_'.strtolower($modulename).'_myobject.sql'); dol_delete_file($destdir.'/sql/llx_'.strtolower($modulename).'_myobject_extrafields.sql'); dol_delete_file($destdir.'/sql/llx_'.strtolower($modulename).'_myobject.key.sql'); + dol_delete_file($destdir.'/sql/llx_'.strtolower($modulename).'_myobject_extrafields.key.sql'); dol_delete_file($destdir.'/img/object_myobject.png'); dol_delete_file($destdir.'/class/myobject.class.php'); + dol_delete_dir($destdir.'/class'); dol_delete_dir($destdir.'/sql'); } From 9f176c5e2d8733114ed712f7d2f8ba8b3b69801a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 6 May 2020 01:41:10 +0200 Subject: [PATCH 116/120] Fix trans --- htdocs/langs/en_US/companies.lang | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/langs/en_US/companies.lang b/htdocs/langs/en_US/companies.lang index f8b3d0354e2..0fad58c9389 100644 --- a/htdocs/langs/en_US/companies.lang +++ b/htdocs/langs/en_US/companies.lang @@ -325,7 +325,8 @@ CompanyDeleted=Company "%s" deleted from database. ListOfContacts=List of contacts/addresses ListOfContactsAddresses=List of contacts/addresses ListOfThirdParties=List of Third Parties -ShowContact=Show contact +ShowCompany=Third Party +ShowContact=Contact-Address ContactsAllShort=All (No filter) ContactType=Contact type ContactForOrders=Order's contact From 247acdd27446434927a8727506cacdd58985fc8f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 6 May 2020 03:47:28 +0200 Subject: [PATCH 117/120] Fix position of custom groups of modules --- htdocs/admin/company.php | 2 +- htdocs/admin/modules.php | 10 ++++++---- htdocs/core/lib/functions.lib.php | 1 + htdocs/core/modules/DolibarrModules.class.php | 2 +- htdocs/theme/eldy/info-box.inc.php | 5 +++++ htdocs/theme/eldy/progress.inc.php | 2 +- htdocs/theme/md/info-box.inc.php | 4 ++++ 7 files changed, 19 insertions(+), 7 deletions(-) diff --git a/htdocs/admin/company.php b/htdocs/admin/company.php index d4664a13de1..f33a3ea6f93 100644 --- a/htdocs/admin/company.php +++ b/htdocs/admin/company.php @@ -693,7 +693,7 @@ print '
'; // Sales taxes (VAT, IRPF, ...) -print load_fiche_titre($langs->trans("TypeOfSaleTaxes")); +print load_fiche_titre($langs->trans("TypeOfSaleTaxes"), '', 'object_payment'); print '
'; + print ''; $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath']; + print ''; print ''; - print ''; + print ''; + print ''; } else { print ''.$langs->trans("FileNotYetGenerated").''; - print ''; + print ''; + print ''; } print ''; } @@ -3163,6 +3166,14 @@ elseif (!empty($module)) print '
'; print '
'; print ' '.$langs->trans("DescriptorFile").' : '.$pathtofile.''; print ''; - print ''.img_picto($langs->trans("Edit"), 'edit').''; + print ''.img_picto($langs->trans("Edit"), 'edit').''; print '
'; @@ -3113,13 +3114,15 @@ elseif (!empty($module)) if (dol_is_file($dirins.'/'.$pathtohook)) { print ''.$pathtohook.''; - print ''.img_picto($langs->trans("Edit"), 'edit').''.img_picto($langs->trans("Delete"), 'delete').''.img_picto($langs->trans("Edit"), 'edit').' '; + print ''.img_picto($langs->trans("Delete"), 'delete').'
'; + + $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath']; + print ''; + if (!empty($triggers)) { foreach ($triggers as $trigger) @@ -3171,7 +3182,7 @@ elseif (!empty($module)) print ''; + print ''; print ''; print ''; } @@ -3180,9 +3191,11 @@ elseif (!empty($module)) { print ''; + print ''; + print ''; print ''; } + print '
'; + print ' '.$langs->trans("DescriptorFile").' : '.$pathtofile.''; + print ''; + print ''.img_picto($langs->trans("Edit"), 'edit').''; + print '
'; print ' '.$langs->trans("TriggersFile").' : '.$pathtofile.''; - print ''.img_picto($langs->trans("Edit"), 'edit').''.img_picto($langs->trans("Edit"), 'edit').''.img_picto($langs->trans("Delete"), 'delete').'
'; print ' '.$langs->trans("NoTrigger"); - print '
'; } else @@ -3227,7 +3240,7 @@ elseif (!empty($module)) if (dol_is_file($dirins.'/'.$pathtohook)) { print ''.$pathtohook.''; - print '
'.img_picto($langs->trans("Edit"), 'edit').''.img_picto($langs->trans("Edit"), 'edit').''.img_picto($langs->trans("Delete"), 'delete').''.img_picto($langs->trans("Edit"), 'edit').''.img_picto($langs->trans("Edit"), 'edit').''.img_picto($langs->trans("Delete"), 'delete').'
'.$langs->trans("WidgetFile").' : '.$pathtofile.''; - print ''.img_picto($langs->trans("Edit"), 'edit').''; + print ''.img_picto($langs->trans("Edit"), 'edit').''; print ''.img_picto($langs->trans("Delete"), 'delete').'
'; print ' '.$langs->trans("SpecificationFile").' : '.$pathtofile.''; - print ''.img_picto($langs->trans("Edit"), 'edit').''.img_picto($langs->trans("Edit"), 'edit').''.img_picto($langs->trans("Delete"), 'delete').'
'; print ''; diff --git a/htdocs/admin/modules.php b/htdocs/admin/modules.php index 926a4c34f70..6a0ff450346 100644 --- a/htdocs/admin/modules.php +++ b/htdocs/admin/modules.php @@ -412,11 +412,13 @@ foreach ($modulesdir as $dir) } $familyposition = $familyinfo[$familykey]['position']; - if ($external) + $listOfOfficialModuleGroups = array('hr', 'technic', 'interface', 'technic', 'portal', 'financial', 'crm', 'base', 'products', 'srm', 'ecm', 'projects', 'other'); + if ($external && ! in_array($familykey, $listOfOfficialModuleGroups)) { - // TODO Find a solution so modules with their own family are always at end - //var_dump($familyposition); - //$familyposition += 100; + // If module is extern and into a custom group (not into an official predefined one), it must appear at end (custom groups should not be before official groups). + if (is_numeric($familyposition)) { + $familyposition = sprintf("%03d", (int) $familyposition + 100); + } } $orders[$i] = $familyposition."_".$familykey."_".$moduleposition."_".$j; // Sort by family, then by module position then number diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 14531947574..f456ec311ac 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -3268,6 +3268,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ 'payment'=>'bg-infobox-bank_account', 'poll'=>'bg-infobox-adherent', 'project'=>'bg-infobox-project', 'projecttask'=>'bg-infobox-project', 'propal'=>'bg-infobox-propal', 'resource'=>'bg-infobox-action', 'supplier_invoice'=>'bg-infobox-order_supplier', 'supplier_order'=>'bg-infobox-order_supplier', 'supplier_proposal'=>'bg-infobox-supplier_proposal', 'ticket'=>'bg-infobox-contrat', 'title_accountancy'=>'bg-infobox-bank_account', 'title_hrm'=>'bg-infobox-holiday', 'trip'=>'bg-infobox-expensereport', 'title_agenda'=>'bg-infobox-action', + //'title_setup'=>'bg-infobox-action', 'tools'=>'bg-infobox-action', 'list-alt'=>'imgforviewmode', 'calendar'=>'imgforviewmode', 'calendarweek'=>'imgforviewmode', 'calendarmonth'=>'imgforviewmode', 'calendarday'=>'imgforviewmode', 'calendarperuser'=>'imgforviewmode' ); if (!empty($arrayconvpictotomorcess[$pictowithouttext])) { diff --git a/htdocs/core/modules/DolibarrModules.class.php b/htdocs/core/modules/DolibarrModules.class.php index cd3fe7922ee..c592cb69959 100644 --- a/htdocs/core/modules/DolibarrModules.class.php +++ b/htdocs/core/modules/DolibarrModules.class.php @@ -2279,7 +2279,7 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it $const_name = 'MAIN_MODULE_'.strtoupper(preg_replace('/^mod/i', '', get_class($this))); print ' -
+
'; diff --git a/htdocs/theme/eldy/info-box.inc.php b/htdocs/theme/eldy/info-box.inc.php index 028039f6c8b..7f62fe39689 100644 --- a/htdocs/theme/eldy/info-box.inc.php +++ b/htdocs/theme/eldy/info-box.inc.php @@ -6,6 +6,11 @@ if (!defined('ISLOADEDBYSTEELSHEET')) die('Must be call by steelsheet'); ?> * Component: Info Box * ------------------- */ + +.info-box-module-external span.info-box-icon-version { + background: #999; +} + .info-box { display: block; position: relative; diff --git a/htdocs/theme/eldy/progress.inc.php b/htdocs/theme/eldy/progress.inc.php index b0bd96df1d2..71f25ff35ba 100644 --- a/htdocs/theme/eldy/progress.inc.php +++ b/htdocs/theme/eldy/progress.inc.php @@ -123,7 +123,7 @@ if (!defined('ISLOADEDBYSTEELSHEET')) die('Must be call by steelsheet'); ?> width: 3px; } .progress-group .progress-text { - font-weight: 600; + /* font-weight: 600; */ } .progress-group .progress-number { float: right; diff --git a/htdocs/theme/md/info-box.inc.php b/htdocs/theme/md/info-box.inc.php index d9b467f130b..d866cab96a6 100644 --- a/htdocs/theme/md/info-box.inc.php +++ b/htdocs/theme/md/info-box.inc.php @@ -7,6 +7,10 @@ if (!defined('ISLOADEDBYSTEELSHEET')) die('Must be call by steelsheet'); ?> * ------------------- */ +.info-box-module-external span.info-box-icon-version { + background: #999; +} + span.info-box-icon-text { /* hide box text number due to problems */ display: none; } From 30fede216c7cb7b95e5db3d26cf338b88ad62b61 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 6 May 2020 04:03:07 +0200 Subject: [PATCH 118/120] Fix Add '_pw' var as var sensibles. --- htdocs/api/class/api_setup.class.php | 2 +- htdocs/core/class/commondocgenerator.class.php | 2 +- htdocs/core/lib/functions.lib.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/api/class/api_setup.class.php b/htdocs/api/class/api_setup.class.php index ec7a6b89596..fd6432b553f 100644 --- a/htdocs/api/class/api_setup.class.php +++ b/htdocs/api/class/api_setup.class.php @@ -1429,7 +1429,7 @@ class Setup extends DolibarrApi if (!preg_match('/^[a-zA-Z0-9_]+$/', $constantname) || !isset($conf->global->$constantname)) { throw new RestException(500, 'Error Bad or unknown value for constantname'); } - if (preg_match('/(_pass|password|secret|_key|key$)/i', $constantname)) { + if (preg_match('/(_pass|_pw|password|secret|_key|key$)/i', $constantname)) { throw new RestException(403, 'Forbidden'); } diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index 1f5ef0a5a9e..df80aab7a1f 100644 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -325,7 +325,7 @@ abstract class CommonDocGenerator foreach ($conf->global as $key => $val) { - if (preg_match('/(_pass|password|secret|_key|key$)/i', $key)) $newval = '*****forbidden*****'; + if (preg_match('/(_pass|_pw|password|secret|_key|key$)/i', $key)) $newval = '*****forbidden*****'; else $newval = $val; $array_other['__['.$key.']__'] = $newval; } diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index f456ec311ac..28a44562b28 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -6523,7 +6523,7 @@ function make_substitutions($text, $substitutionarray, $outputlangs = null) if (dol_textishtml($text, 1)) $msgishtml = 1; $keyfound = $reg[1]; - if (preg_match('/(_pass|password|secret|_key|key$)/i', $keyfound)) $newval = '*****forbidden*****'; + if (preg_match('/(_pass|_pw|password|secret|_key|key$)/i', $keyfound)) $newval = '*****forbidden*****'; else $newval = empty($conf->global->$keyfound) ? '' : $conf->global->$keyfound; $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $msgishtml ?dol_htmlentitiesbr($newval) : $newval, $text); } From b09f179a16759ee8213c51ebf0726f57decf3a3c Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 6 May 2020 04:32:48 +0200 Subject: [PATCH 119/120] NEW Website logs are now into a separated log file. --- htdocs/core/lib/functions.lib.php | 7 +++++++ htdocs/core/lib/website2.lib.php | 5 ++++- htdocs/core/website.inc.php | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 28a44562b28..1a4ab00b7d6 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -1078,6 +1078,13 @@ function dol_syslog($message, $level = LOG_INFO, $ident = 0, $suffixinfilename = // If syslog module enabled if (empty($conf->syslog->enabled)) return; + // Check if we are into execution of code of a website + if (defined('USEEXTERNALSERVER') && ! defined('USEDOLIBARRSERVER') && ! defined('USEDOLIBARREDITOR')) { + global $website, $websitekey; + if (is_object($website) && ! empty($website->ref)) $suffixinfilename.='_website_'.$website->ref; + elseif (! empty($websitekey)) $suffixinfilename.='_website_'.$websitekey; + } + if ($ident < 0) { foreach ($conf->loghandlers as $loghandlerinstance) diff --git a/htdocs/core/lib/website2.lib.php b/htdocs/core/lib/website2.lib.php index 6ef17220283..fc56a489d75 100644 --- a/htdocs/core/lib/website2.lib.php +++ b/htdocs/core/lib/website2.lib.php @@ -39,7 +39,10 @@ function dolSaveMasterFile($filemaster) $mastercontent = ''."\n"; $result = file_put_contents($filemaster, $mastercontent); if (!empty($conf->global->MAIN_UMASK)) diff --git a/htdocs/core/website.inc.php b/htdocs/core/website.inc.php index b90da632fac..3e54f6ec2ad 100644 --- a/htdocs/core/website.inc.php +++ b/htdocs/core/website.inc.php @@ -19,7 +19,7 @@ /** * \file htdocs/core/website.inc.php * \brief Common file loaded by all website pages (after master.inc.php). It set the new object $weblangs, using parameter 'l'. - * This file is included in top of all container pages. + * This file is included in top of all container pages and is run only when a web page is called. * The global variable $websitekey must be defined. */ From a8222c2651591a657767b8bf95cc04fa37752866 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 6 May 2020 05:10:42 +0200 Subject: [PATCH 120/120] Look and feel v12 --- htdocs/admin/menus/index.php | 4 ++-- htdocs/admin/tools/purge.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/admin/menus/index.php b/htdocs/admin/menus/index.php index 56251e48f7b..97f0246ac88 100644 --- a/htdocs/admin/menus/index.php +++ b/htdocs/admin/menus/index.php @@ -277,8 +277,8 @@ print '
'; print ''; print ''; -print ''; +print ''; print ''; print ''; diff --git a/htdocs/admin/tools/purge.php b/htdocs/admin/tools/purge.php index 43cf81b41ba..9898e290ddc 100644 --- a/htdocs/admin/tools/purge.php +++ b/htdocs/admin/tools/purge.php @@ -78,7 +78,7 @@ $form = new Form($db); print load_fiche_titre($langs->trans("Purge"), '', 'title_setup'); -print $langs->trans("PurgeAreaDesc", $dolibarr_main_data_root).'
'; +print ''.$langs->trans("PurgeAreaDesc", $dolibarr_main_data_root).'
'; print '
';
'.$langs->trans("TreeMenuPersonalized").'