diff --git a/dev/build/phpstan/phpstan-baseline.neon b/dev/build/phpstan/phpstan-baseline.neon index 4cd32f7ad49..a825625573e 100644 --- a/dev/build/phpstan/phpstan-baseline.neon +++ b/dev/build/phpstan/phpstan-baseline.neon @@ -2502,78 +2502,6 @@ parameters: count: 1 path: ../../../htdocs/commande/class/api_orders.class.php - - - message: '#^Negated boolean expression is always true\.$#' - identifier: booleanNot.alwaysTrue - count: 5 - path: ../../../htdocs/commande/class/commande.class.php - - - - message: '#^Property Commande\:\:\$mode_reglement_id \(int\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 1 - path: ../../../htdocs/commande/class/commande.class.php - - - - message: '#^Property Commande\:\:\$ref_client \(string\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 2 - path: ../../../htdocs/commande/class/commande.class.php - - - - message: '#^Property Commande\:\:\$ref_customer \(string\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 1 - path: ../../../htdocs/commande/class/commande.class.php - - - - message: '#^Property Commande\:\:\$socid \(int\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 1 - path: ../../../htdocs/commande/class/commande.class.php - - - - message: '#^Property CommonObject\:\:\$total_ht \(float\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 1 - path: ../../../htdocs/commande/class/commande.class.php - - - - message: '#^Property CommonObject\:\:\$total_localtax1 \(float\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 1 - path: ../../../htdocs/commande/class/commande.class.php - - - - message: '#^Property CommonObject\:\:\$total_localtax2 \(float\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 1 - path: ../../../htdocs/commande/class/commande.class.php - - - - message: '#^Property CommonObject\:\:\$total_ttc \(float\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 1 - path: ../../../htdocs/commande/class/commande.class.php - - - - message: '#^Property CommonObject\:\:\$total_tva \(float\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 1 - path: ../../../htdocs/commande/class/commande.class.php - - - - message: '#^Right side of && is always true\.$#' - identifier: booleanAnd.rightAlwaysTrue - count: 2 - path: ../../../htdocs/commande/class/commande.class.php - - - - message: '#^Negated boolean expression is always true\.$#' - identifier: booleanNot.alwaysTrue - count: 2 - path: ../../../htdocs/commande/class/orderline.class.php - - message: '#^Variable \$socid might not be defined\.$#' identifier: variable.undefined @@ -3672,12 +3600,6 @@ parameters: count: 4 path: ../../../htdocs/compta/paiement/class/cpaiement.class.php - - - message: '#^Property Cpaiement\:\:\$active \(int\<0, 1\>\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 4 - path: ../../../htdocs/compta/paiement/class/cpaiement.class.php - - message: '#^Property Cpaiement\:\:\$libelle \(string\) in isset\(\) is not nullable\.$#' identifier: isset.property @@ -3882,18 +3804,6 @@ parameters: count: 1 path: ../../../htdocs/compta/recap-compta.php - - - message: '#^Parameter \#1 \$array of function dol_sort_array contains unresolvable type\.$#' - identifier: argument.unresolvableType - count: 2 - path: ../../../htdocs/compta/recap-compta.php - - - - message: '#^Return type of call to function dol_sort_array contains unresolvable type\.$#' - identifier: function.unresolvableReturnType - count: 2 - path: ../../../htdocs/compta/recap-compta.php - - message: '#^Variable \$description might not be defined\.$#' identifier: variable.undefined @@ -3972,12 +3882,6 @@ parameters: count: 2 path: ../../../htdocs/compta/sociales/class/cchargesociales.class.php - - - message: '#^Property Cchargesociales\:\:\$active \(string\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 2 - path: ../../../htdocs/compta/sociales/class/cchargesociales.class.php - - message: '#^Property Cchargesociales\:\:\$code \(string\) in isset\(\) is not nullable\.$#' identifier: isset.property @@ -5472,12 +5376,6 @@ parameters: count: 4 path: ../../../htdocs/core/class/ccountry.class.php - - - message: '#^Property CommonDict\:\:\$active \(int\<0, 1\>\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 4 - path: ../../../htdocs/core/class/ccountry.class.php - - message: '#^Property CommonDict\:\:\$code \(string\) in isset\(\) is not nullable\.$#' identifier: isset.property @@ -5502,12 +5400,6 @@ parameters: count: 1 path: ../../../htdocs/core/class/cgenericdic.class.php - - - message: '#^Property CGenericDic\:\:\$active \(int\<0, 1\>\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 4 - path: ../../../htdocs/core/class/cgenericdic.class.php - - message: '#^Property CGenericDic\:\:\$code \(string\) in isset\(\) is not nullable\.$#' identifier: isset.property @@ -5538,12 +5430,6 @@ parameters: count: 2 path: ../../../htdocs/core/class/cleadstatus.class.php - - - message: '#^Property CommonDict\:\:\$active \(int\<0, 1\>\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 2 - path: ../../../htdocs/core/class/cleadstatus.class.php - - message: '#^Property CommonDict\:\:\$code \(string\) in isset\(\) is not nullable\.$#' identifier: isset.property @@ -5994,12 +5880,6 @@ parameters: count: 1 path: ../../../htdocs/core/class/conf.class.php - - - message: '#^Property CommonDict\:\:\$active \(int\<0, 1\>\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 2 - path: ../../../htdocs/core/class/cproductnature.class.php - - message: '#^Property CommonDict\:\:\$code \(string\) in isset\(\) is not nullable\.$#' identifier: isset.property @@ -6018,48 +5898,6 @@ parameters: count: 2 path: ../../../htdocs/core/class/cproductnature.class.php - - - message: '#^Property CommonDict\:\:\$active \(int\<0, 1\>\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 4 - path: ../../../htdocs/core/class/cregion.class.php - - - - message: '#^Property CommonDict\:\:\$id \(int\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 1 - path: ../../../htdocs/core/class/cregion.class.php - - - - message: '#^Property Cregion\:\:\$cheflieu \(string\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 4 - path: ../../../htdocs/core/class/cregion.class.php - - - - message: '#^Property Cregion\:\:\$code_region \(int\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 4 - path: ../../../htdocs/core/class/cregion.class.php - - - - message: '#^Property Cregion\:\:\$fk_pays \(int\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 4 - path: ../../../htdocs/core/class/cregion.class.php - - - - message: '#^Property Cregion\:\:\$name \(string\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 4 - path: ../../../htdocs/core/class/cregion.class.php - - - - message: '#^Property CommonDict\:\:\$active \(int\<0, 1\>\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 4 - path: ../../../htdocs/core/class/cstate.class.php - - message: '#^Property Cstate\:\:\$code_departement \(string\) in isset\(\) is not nullable\.$#' identifier: isset.property @@ -6084,12 +5922,6 @@ parameters: count: 1 path: ../../../htdocs/core/class/cstate.class.php - - - message: '#^Property CommonDict\:\:\$active \(int\<0, 1\>\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 4 - path: ../../../htdocs/core/class/ctypent.class.php - - message: '#^Property CommonDict\:\:\$code \(string\) in isset\(\) is not nullable\.$#' identifier: isset.property @@ -6120,12 +5952,6 @@ parameters: count: 1 path: ../../../htdocs/core/class/ctyperesource.class.php - - - message: '#^Property CommonDict\:\:\$active \(int\<0, 1\>\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 4 - path: ../../../htdocs/core/class/ctyperesource.class.php - - message: '#^Property CommonDict\:\:\$code \(string\) in isset\(\) is not nullable\.$#' identifier: isset.property @@ -6156,12 +5982,6 @@ parameters: count: 4 path: ../../../htdocs/core/class/cunits.class.php - - - message: '#^Property CommonDict\:\:\$active \(int\<0, 1\>\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 3 - path: ../../../htdocs/core/class/cunits.class.php - - message: '#^Property CommonDict\:\:\$code \(string\) in isset\(\) is not nullable\.$#' identifier: isset.property @@ -18690,12 +18510,6 @@ parameters: count: 1 path: ../../../htdocs/webportal/class/webportalpropal.class.php - - - message: '#^Property Propal\:\:\$status \(int\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 1 - path: ../../../htdocs/webportal/class/webportalpropal.class.php - - message: '#^Strict comparison using \=\=\= between ''nolink'' and ''nolink'' will always evaluate to true\.$#' identifier: identical.alwaysTrue diff --git a/dev/tools/phan/config.php b/dev/tools/phan/config.php index 6c2270351be..e6670afe368 100644 --- a/dev/tools/phan/config.php +++ b/dev/tools/phan/config.php @@ -1,6 +1,6 @@ - * Copyright (C) 2024 Frédéric France + * Copyright (C) 2024-2025 Frédéric France * * This is the phan config file used by .github/workflows/phan.yml */ diff --git a/htdocs/admin/mails.php b/htdocs/admin/mails.php index 37435f6b0cb..cb01acc2e45 100644 --- a/htdocs/admin/mails.php +++ b/htdocs/admin/mails.php @@ -4,7 +4,7 @@ * Copyright (C) 2013 Juanjo Menent * Copyright (C) 2016 Jonathan TISSEAU * Copyright (C) 2023 Anthony Berton - * Copyright (C) 2024 Frédéric France + * Copyright (C) 2024-2025 Frédéric France * Copyright (C) 2024-2025 MDW * * This program is free software; you can redistribute it and/or modify @@ -68,12 +68,12 @@ $substitutionarrayfortest = array( '__SENDEREMAIL_SIGNATURE__' => (($user->signature && !getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN')) ? $usersignature : ''), // Done into actions_sendmails //'__ID__' => 'RecipientID', //'__EMAIL__' => 'RecipientEMail', // Done into actions_sendmails - '__LASTNAME__' => $langs->trans("Lastname").' ('.$langs->trans("Recipient").')', - '__FIRSTNAME__' => $langs->trans("Firstname").' ('.$langs->trans("Recipient").')', - //'__ADDRESS__'=> $langs->trans("Address").' ('.$langs->trans("Recipient").')', - //'__ZIP__'=> $langs->trans("Zip").' ('.$langs->trans("Recipient").')', - //'__TOWN_'=> $langs->trans("Town").' ('.$langs->trans("Recipient").')', - //'__COUNTRY__'=> $langs->trans("Country").' ('.$langs->trans("Recipient").')', + '__LASTNAME__' => $langs->trans("Lastname").' ('.$langs->trans("MailRecipient").')', + '__FIRSTNAME__' => $langs->trans("Firstname").' ('.$langs->trans("MailRecipient").')', + //'__ADDRESS__'=> $langs->trans("Address").' ('.$langs->trans("MailRecipient").')', + //'__ZIP__'=> $langs->trans("Zip").' ('.$langs->trans("MailRecipient").')', + //'__TOWN_'=> $langs->trans("Town").' ('.$langs->trans("MailRecipient").')', + //'__COUNTRY__'=> $langs->trans("Country").' ('.$langs->trans("MailRecipient").')', '__DOL_MAIN_URL_ROOT__' => DOL_MAIN_URL_ROOT, '__CHECK_READ__' => '', ); diff --git a/htdocs/api/class/api_setup.class.php b/htdocs/api/class/api_setup.class.php index 164f2134b88..adfd077542c 100644 --- a/htdocs/api/class/api_setup.class.php +++ b/htdocs/api/class/api_setup.class.php @@ -3,7 +3,7 @@ * Copyright (C) 2016 Laurent Destailleur * Copyright (C) 2017 Regis Houssin * Copyright (C) 2017 Neil Orley - * Copyright (C) 2018-2024 Frédéric France + * Copyright (C) 2018-2025 Frédéric France * Copyright (C) 2018-2022 Thibault FOUCART * Copyright (C) 2024 Jon Bendtsen * Copyright (C) 2024-2025 MDW @@ -389,7 +389,7 @@ class Setup extends DolibarrApi $obj = $this->db->fetch_object($result); $region = new Cregion($this->db); if ($region->fetch($obj->rowid) > 0) { - if (empty($filter) || stripos($region->name, $filter) !== false) { + if (empty($filter) || stripos((string) $region->name, $filter) !== false) { $list[] = $this->_cleanObjectDatas($region); } } diff --git a/htdocs/comm/propal/list.php b/htdocs/comm/propal/list.php index d19cfbba32c..0dc0770f528 100644 --- a/htdocs/comm/propal/list.php +++ b/htdocs/comm/propal/list.php @@ -1855,7 +1855,7 @@ while ($i < $imaxinloop) { print ''; } } else { - print ''; + print ''; // Action column if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index 70bce59f557..e890c721790 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -100,17 +100,17 @@ class Commande extends CommonOrder protected $table_ref_field = 'ref'; /** - * @var int Thirdparty ID + * @var ?int Thirdparty ID */ public $socid; /** - * @var string Thirdparty ref of order + * @var ?string Thirdparty ref of order */ public $ref_client; /** - * @var string Thirdparty ref of order + * @var ?string Thirdparty ref of order */ public $ref_customer; @@ -169,7 +169,7 @@ class Commande extends CommonOrder public $mode_reglement; /** - * @var int Payment mode id + * @var ?int Payment mode id */ public $mode_reglement_id; @@ -525,6 +525,10 @@ class Commande extends CommonOrder dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR); return -1; } + if (empty($this->socid)) { + $this->error = 'ErrorWrongParameters'; + return -1; + } $now = dol_now(); @@ -538,7 +542,7 @@ class Commande extends CommonOrder $result = $soc->setAsCustomer(); // Define new ref - if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life + if (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref)) { // empty should not happened, but when it occurs, the test save life $num = $this->getNextNumRef($soc); } else { $num = (string) $this->ref; @@ -695,9 +699,7 @@ class Commande extends CommonOrder $sql .= " WHERE rowid = ".((int) $this->id); if ($this->db->query($sql)) { - if (!$error) { - $this->oldcopy = clone $this; - } + $this->oldcopy = clone $this; // If stock is decremented on validate order, we must reincrement it if (isModEnabled('stock') && getDolGlobalInt('STOCK_CALCULATE_ON_VALIDATE_ORDER') == 1) { @@ -919,7 +921,7 @@ class Commande extends CommonOrder $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, 0, $langs->trans("OrderCanceledInDolibarr", $this->ref)); // price is 0, we don't want WAP to be changed if ($result < 0) { $error++; - $this->error = $mouvP->error; + $this->setErrorsFromObject($mouvP); break; } } @@ -970,6 +972,11 @@ class Commande extends CommonOrder // Clean parameters + if (empty($this->socid)) { + $this->error = 'ErrorWrongParameters'; + return -1; + } + // Set tmp vars $date = ($this->date_commande ? $this->date_commande : $this->date); $this->import_key = trim((string) $this->import_key); @@ -1174,7 +1181,7 @@ class Commande extends CommonOrder } // Add object linked - if (!$error && $this->id && !empty($this->linked_objects) && is_array($this->linked_objects)) { + if (!empty($this->linked_objects) && is_array($this->linked_objects)) { foreach ($this->linked_objects as $origin => $tmp_origin_id) { if (is_array($tmp_origin_id)) { // New behaviour, if linked_object can have several links per type, so is something like array('contract'=>array(id1, id2, ...)) foreach ($tmp_origin_id as $origin_id) { @@ -1195,7 +1202,7 @@ class Commande extends CommonOrder } } - if (!$error && $this->id && getDolGlobalString('MAIN_PROPAGATE_CONTACTS_FROM_ORIGIN') && !empty($this->origin) && !empty($this->origin_id)) { // Get contact from origin object + if (!$error && getDolGlobalString('MAIN_PROPAGATE_CONTACTS_FROM_ORIGIN') && !empty($this->origin) && !empty($this->origin_id)) { // Get contact from origin object $originforcontact = empty($this->origin_type) ? $this->origin : $this->origin_type; $originidforcontact = $this->origin_id; if ($originforcontact == 'shipping') { // shipment and order share the same contacts. If creating from shipment we take data of order @@ -3007,10 +3014,8 @@ class Commande extends CommonOrder dol_syslog(get_class($this)."::classifyBilled", LOG_DEBUG); if ($this->db->query($sql)) { - if (!$error) { - $this->oldcopy = clone $this; - $this->billed = 1; - } + $this->oldcopy = clone $this; + $this->billed = 1; if (!$notrigger && empty($error)) { // Call trigger @@ -3057,10 +3062,8 @@ class Commande extends CommonOrder dol_syslog(get_class($this)."::classifyUnBilled", LOG_DEBUG); if ($this->db->query($sql)) { - if (!$error) { - $this->oldcopy = clone $this; - $this->billed = 1; - } + $this->oldcopy = clone $this; + $this->billed = 1; if (!$notrigger && empty($error)) { // Call trigger diff --git a/htdocs/commande/class/orderline.class.php b/htdocs/commande/class/orderline.class.php index a5ca253bbdd..a333f17733b 100644 --- a/htdocs/commande/class/orderline.class.php +++ b/htdocs/commande/class/orderline.class.php @@ -508,11 +508,9 @@ class OrderLine extends CommonOrderLine $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'commandedet'); $this->rowid = $this->id; - if (!$error) { - $result = $this->insertExtraFields(); - if ($result < 0) { - $error++; - } + $result = $this->insertExtraFields(); + if ($result < 0) { + $error++; } if (!$error && !$notrigger) { @@ -673,12 +671,10 @@ class OrderLine extends CommonOrderLine dol_syslog(get_class($this)."::update", LOG_DEBUG); $resql = $this->db->query($sql); if ($resql) { - if (!$error) { - $this->id = $this->rowid; - $result = $this->insertExtraFields(); - if ($result < 0) { - $error++; - } + $this->id = $this->rowid; + $result = $this->insertExtraFields(); + if ($result < 0) { + $error++; } if (!$error && !$notrigger) { diff --git a/htdocs/commande/list.php b/htdocs/commande/list.php index 6f685abbebe..fe8238a27aa 100644 --- a/htdocs/commande/list.php +++ b/htdocs/commande/list.php @@ -2419,7 +2419,7 @@ while ($i < $imaxinloop) { } else { // Show line of result $j = 0; - print ''; + print ''; // Action column if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php index 8eff70c8ba6..6413de08d75 100644 --- a/htdocs/compta/facture/list.php +++ b/htdocs/compta/facture/list.php @@ -2327,7 +2327,7 @@ if ($num > 0) { } else { // Show line of result $j = 0; - print 'db->escape($this->libelle)."'").','; $sql .= ' '.(!isset($this->deductible) ? 'NULL' : $this->deductible).','; - $sql .= ' '.(!isset($this->active) ? 'NULL' : $this->active).','; + $sql .= ' ' . (int) $this->active . ','; $sql .= ' '.(!isset($this->code) ? 'NULL' : "'".$this->db->escape($this->code)."'").','; $sql .= ' '.(!isset($this->fk_pays) ? 'NULL' : $this->fk_pays).','; $sql .= ' '.(!isset($this->module) ? 'NULL' : "'".$this->db->escape($this->module)."'").','; @@ -271,14 +274,17 @@ class Cchargesociales array( 'libelle', 'deductible', - 'active', 'code', - 'fk_pays', 'module', 'accountancy_code', ) ); - + if (isset($this->fk_pays)) { + $this->fk_pays = (int) $this->fk_pays; + } + if (isset($this->active)) { + $this->active = (int) $this->active; + } // Check parameters // Put here code to add a control on parameters values @@ -542,7 +548,7 @@ class Cchargesociales $this->libelle = ''; $this->label = ''; $this->deductible = ''; - $this->active = ''; + $this->active = 0; $this->code = ''; $this->fk_pays = 0; $this->module = ''; diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php index f0dbbd884c1..b0ac57c956b 100644 --- a/htdocs/core/actions_massactions.inc.php +++ b/htdocs/core/actions_massactions.inc.php @@ -248,7 +248,7 @@ if (!$error && $massaction == 'confirm_presend') { } if (!trim(GETPOST('sendto', 'alphawithlgt')) && count($receiver) == 0 && count($listofobjectthirdparties) == 1) { // if only one recipient, receiver is mandatory $error++; - setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Recipient")), null, 'warnings'); + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("MailRecipient")), null, 'warnings'); $massaction = 'presend'; } diff --git a/htdocs/core/class/cgenericdic.class.php b/htdocs/core/class/cgenericdic.class.php index 9c4e3317775..137b828db78 100644 --- a/htdocs/core/class/cgenericdic.class.php +++ b/htdocs/core/class/cgenericdic.class.php @@ -1,10 +1,10 @@ - * Copyright (C) 2014-2016 Juanjo Menent - * Copyright (C) 2016 Florian Henry - * Copyright (C) 2015 Raphaël Doursenaud - * Copyright (C) 2024 Frédéric France - * Copyright (C) 2024 MDW +/* Copyright (C) 2007-2012 Laurent Destailleur + * Copyright (C) 2014-2016 Juanjo Menent + * Copyright (C) 2016 Florian Henry + * Copyright (C) 2015 Raphaël Doursenaud + * Copyright (C) 2024-2025 Frédéric France + * Copyright (C) 2024 MDW * * 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 @@ -58,12 +58,6 @@ class CGenericDic extends CommonDict */ public $label; - /** - * @var int<0,1> - */ - public $active; - - /** * Constructor * diff --git a/htdocs/core/class/commondict.class.php b/htdocs/core/class/commondict.class.php index f6dc107025b..240fded7ea9 100644 --- a/htdocs/core/class/commondict.class.php +++ b/htdocs/core/class/commondict.class.php @@ -1,5 +1,6 @@ +/* Copyright (C) 2023 Laurent Destailleur + * Copyright (C) 2025 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 @@ -64,7 +65,7 @@ abstract class CommonDict public $label; /** - * @var int<0,1> 1 if the entry is active, 0 if not + * @var ?int<0,1> 1 if the entry is active, 0 if not */ public $active; } diff --git a/htdocs/core/class/conf.class.php b/htdocs/core/class/conf.class.php index 3a82dc1d029..2e53465afbf 100644 --- a/htdocs/core/class/conf.class.php +++ b/htdocs/core/class/conf.class.php @@ -346,6 +346,12 @@ class Conf extends stdClass * @var stdClass */ public $productbatch; + + /** + * @var stdClass + */ + public $api; + /** * @var ?stdClass * @deprecated Use project diff --git a/htdocs/core/class/cregion.class.php b/htdocs/core/class/cregion.class.php index 6d5801f5279..54431f9a933 100644 --- a/htdocs/core/class/cregion.class.php +++ b/htdocs/core/class/cregion.class.php @@ -1,7 +1,8 @@ - * Copyright (C) 2007-2011 Laurent Destailleur - * Copyright (C) 2024-2025 MDW +/* Copyright (C) Richard Rondu + * Copyright (C) 2007-2011 Laurent Destailleur + * Copyright (C) 2024-2025 MDW + * Copyright (C) 2025 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 @@ -36,22 +37,22 @@ class Cregion extends CommonDict //public $table_element = 'c_regions'; //!< Name of table without prefix where object is stored /** - * @var int The code of the region + * @var ?int The code of the region */ public $code_region; /** - * @var int The ID of the country of the region + * @var ?int The ID of the country of the region */ public $fk_pays; /** - * @var string The name of the region + * @var ?string The name of the region */ public $name; /** - * @var string The reference of the "chef-lieu" of the region + * @var ?string The reference of the "chef-lieu" of the region * A.k.a. the administrative headquarter of the region * (examples: HU33, PT9, 97601) */ @@ -89,10 +90,10 @@ class Cregion extends CommonDict $this->fk_pays = (int) $this->fk_pays; } if (isset($this->name)) { - $this->name = trim($this->name); + $this->name = trim((string) $this->name); } if (isset($this->cheflieu)) { - $this->cheflieu = trim($this->cheflieu); + $this->cheflieu = trim((string) $this->cheflieu); } if (isset($this->active)) { $this->active = (int) $this->active; @@ -110,12 +111,12 @@ class Cregion extends CommonDict $sql .= "cheflieu,"; $sql .= "active"; $sql .= ") VALUES ("; - $sql .= " ".(!isset($this->id) ? 'NULL' : (int) $this->id).","; - $sql .= " ".(!isset($this->code_region) ? 'NULL' : (int) $this->code_region).","; - $sql .= " ".(!isset($this->fk_pays) ? 'NULL' : (int) $this->fk_pays).","; - $sql .= " ".(!isset($this->name) ? 'NULL' : "'".$this->db->escape($this->name)."'").","; - $sql .= " ".(!isset($this->cheflieu) ? 'NULL' : "'".$this->db->escape($this->cheflieu)."'").","; - $sql .= " ".(!isset($this->active) ? 'NULL' : "'".$this->db->escape((string) $this->active)."'"); + $sql .= (int) $this->id; + $sql .= ", " . (!isset($this->code_region) ? 'NULL' : (int) $this->code_region); + $sql .= ", " . (int) $this->fk_pays; + $sql .= ", " . (!isset($this->name) ? 'NULL' : "'".$this->db->escape($this->name) . "'"); + $sql .= ", " . (!isset($this->cheflieu) ? 'NULL' : "'".$this->db->escape($this->cheflieu) . "'"); + $sql .= ", " . (int) $this->active; $sql .= ")"; $this->db->begin(); @@ -160,7 +161,7 @@ class Cregion extends CommonDict $sql .= " t.rowid,"; $sql .= " t.code_region,"; $sql .= " t.fk_pays,"; - $sql .= " t.nom,"; + $sql .= " t.nom as name,"; $sql .= " t.cheflieu,"; $sql .= " t.active"; $sql .= " FROM ".$this->db->prefix()."c_regions as t"; @@ -182,9 +183,9 @@ class Cregion extends CommonDict $this->id = $obj->rowid; $this->code_region = (int) $obj->code_region; $this->fk_pays = (int) $obj->fk_pays; - $this->name = $obj->nom; + $this->name = $obj->name; $this->cheflieu = $obj->cheflieu; - $this->active = $obj->active; + $this->active = (int) $obj->active; } $this->db->free($resql); diff --git a/htdocs/core/js/lib_head.js.php b/htdocs/core/js/lib_head.js.php index a856187b20d..953c28dfb6f 100644 --- a/htdocs/core/js/lib_head.js.php +++ b/htdocs/core/js/lib_head.js.php @@ -1704,5 +1704,94 @@ function onKanbanColumnChange(item, newColumn) { item.data('original-column', newColumn); } +/* +* Intuitive table selection +*/ +$(function() { + + /** + * @param {jQuery} el + * @param {Integer} status + */ + let setLastClickedRowStatus = function (el, status = 1){ + $('.row-with-select').attr('data-is-last-changed', 0); + el.attr('data-is-last-changed', status === 0 ? 0 : 1); + } + + /** + * Remove data-is-last-changed on double click + * Because if data-is-last-changed is present the user can't select text + */ + $(document).on("dblclick", ".row-with-select", function(e) { + $('.row-with-select[data-is-last-changed]').removeAttr( 'data-is-last-changed' ); + }); + + /** + * DISABLE on click a and button + * Because Ctrl + Click on link is also used for open ion a new tab + * we need to block select tool + */ + $(document).on("click", ".row-with-select a, .row-with-select button", function (e) { + // we need to block select tool + if (e.ctrlKey) { + e.stopPropagation(); + } + }); + + $(document).on("mousedown click", ".row-with-select input.checkforselect", function (e) { + // Prevents automatic change of “checked” + e.preventDefault(); + e.stopPropagation(); // parent click trigger will be done below + + let parentRow = $(this).closest(".row-with-select"); + + // this part of code prevent weird behavior when user (ctrl or maj) + click directly on checkbox + // We simulate a click on the parent line + parentRow.trigger({ + type: "click", + ctrlKey: !e.shiftKey, // simulate ctrlKey click will automatically prop activate the checkbox with parent event but not if shift key is pressed. + metaKey: !e.shiftKey, // simulate metaKey click will automatically prop activate the checkbox with parent event but not if shift key is pressed. + shiftKey: e.shiftKey, + originalEvent: e + }); + + }); + + $(document).on("click", ".row-with-select", function (e) { + let checkBox = $(this).find('.checkforselect'); + let nextCheckStatus = !checkBox.is(':checked') + + if (e.ctrlKey || e.metaKey) { + // Add line to selection + if(checkBox){ + checkBox.prop('checked', nextCheckStatus).trigger('change'); + } + setLastClickedRowStatus($(this), 1); + } + + if (e.shiftKey) { + let lastLastChanged = $(this).closest('table').find('.row-with-select[data-is-last-changed="1"]'); + + if(lastLastChanged.length>0){ + // Add all lines to selection betwin last selected line + if($(this).index() === lastLastChanged.index()) { + return null; + } + + if($(this).index() < lastLastChanged.index()) { + $(this).nextUntil(lastLastChanged, ".row-with-select" ).find('.checkforselect').prop('checked', nextCheckStatus).trigger('change'); + }else{ + lastLastChanged.nextUntil($(this), ".row-with-select" ).find('.checkforselect').prop('checked', nextCheckStatus).trigger('change'); + } + + + lastLastChanged.find('.checkforselect').prop('checked', nextCheckStatus).trigger('change'); + checkBox.prop('checked', nextCheckStatus).trigger('change'); + + setLastClickedRowStatus($(this), 1); + } + } + }); +}); // End of lib_head.js.php diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 2eec22e20d3..37c56cce7ff 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -15011,6 +15011,7 @@ function fetchObjectByElement($element_id, $element_type, $element_ref = '', $us $className = $element_prop['classname']; $objecttmp = new $className($db); '@phan-var-force CommonObject $objecttmp'; + /** @var CommonObject $objecttmp */ if ($element_id > 0 || !empty($element_ref)) { $ret = $objecttmp->fetch($element_id, $element_ref); diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index 3ab373ff21c..7cdba6b1406 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -967,6 +967,7 @@ function print_left_eldy_menu($db, $menu_array_before, $menu_array_after, &$tabM // Force the typing at this point to get useful analysis below: '@phan-var-force array,type:string,fk_mainmenu:string,fk_leftmenu:string,url:string,titre:string,perms:string,target:string,mainmenu:string,leftmenu:string,position:int,positionfull:int|string,showtopmenuinframe:int,level?:int,prefix:string}> $menu_array'; + /** @var array,type:string,fk_mainmenu:string,fk_leftmenu:string,url:string,titre:string,perms:string,target:string,mainmenu:string,leftmenu:string,position:int,positionfull:int|string,showtopmenuinframe:int,level?:int,prefix:string}> $menu_array */ // Show menu diff --git a/htdocs/langs/en_US/sendings.lang b/htdocs/langs/en_US/sendings.lang index 089ccdb4f6e..83f74081d11 100644 --- a/htdocs/langs/en_US/sendings.lang +++ b/htdocs/langs/en_US/sendings.lang @@ -100,7 +100,7 @@ ToAndDate=To___________________________________ on ____/_____/__________ GoodStatusDeclaration=Have received the goods above in good condition, Deliverer=Deliverer: Sender=Sender -Recipient=Recipient +Recipient=Delivery recipient ErrorStockIsNotEnough=There's not enough stock Shippable=Shippable NonShippable=Not Shippable diff --git a/htdocs/langs/fr_FR/sendings.lang b/htdocs/langs/fr_FR/sendings.lang index 159fe540d46..23fb33a1c58 100644 --- a/htdocs/langs/fr_FR/sendings.lang +++ b/htdocs/langs/fr_FR/sendings.lang @@ -99,7 +99,7 @@ ToAndDate=A___________________________________ le ____/_____/__________ GoodStatusDeclaration=Déclare avoir reçu les marchandises ci-dessus en bon état, Deliverer=Livreur(s) : Sender=Émetteur -Recipient=Email fixe cible destinataires +Recipient=Destinataire ErrorStockIsNotEnough=Le stock est insuffisant Shippable=Expédiable NonShippable=Non expédiable diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index e31905ab1b1..c74ad39961f 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -9190,6 +9190,16 @@ print getDolGlobalString('THEME_CUSTOM_CSS'); ?> +/* Remove text selection - Intuitive table selection */ +.row-with-select[data-is-last-changed] * { + -webkit-touch-callout: none; /* iOS Safari */ + -webkit-user-select: none; /* Safari */ + -khtml-user-select: none; /* Konqueror HTML */ + -moz-user-select: none; /* Old versions of Firefox */ + -ms-user-select: none; /* Internet Explorer/Edge */ + user-select: none; /* Non-prefixed version, currently supported by Chrome, Edge, Opera and Firefox */ +} + div.extra_inline_chkbxlst, div.extra_inline_checkbox { min-width:150px; } diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index 4f3274c0a05..ce71528704e 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -8998,9 +8998,18 @@ if (is_object($db)) { } ::-webkit-scrollbar-thumb { background: #ddd; -}​ - +} +/* Remove text selection - Intuitive table selection */ +.row-with-select[data-is-last-changed] * { + -webkit-touch-callout: none; /* iOS Safari */ + -webkit-user-select: none; /* Safari */ + -khtml-user-select: none; /* Konqueror HTML */ + -moz-user-select: none; /* Old versions of Firefox */ + -ms-user-select: none; /* Internet Explorer/Edge */ + user-select: none; /* Non-prefixed version, currently + supported by Chrome, Edge, Opera and Firefox */ +} /* Must be at end */ div.flot-text .flot-tick-label .tickLabel, .fa-color-unset {