diff --git a/.travis.yml b/.travis.yml index eef14f01386..1f4fc328a49 100644 --- a/.travis.yml +++ b/.travis.yml @@ -473,7 +473,7 @@ script: - | echo "Unit testing" - # Ensure we catch errors. Set this to +e if you want to go to the end to see dolibarr.log file. + # Ensure we catch errors. Set this to +e instead of -e if you want to go to the end to see dolibarr.log file. set -e phpunit -d memory_limit=-1 -c test/phpunit/phpunittest.xml test/phpunit/AllTests.php phpunitresult=$? @@ -501,7 +501,7 @@ after_failure: # Show upgrade log files for ficlog in `ls $TRAVIS_BUILD_DIR/*.log` do - echo "Debugging informations for file $ficlog" + #echo "Debugging informations for file $ficlog" #cat $ficlog done # Show Apache log file diff --git a/COPYRIGHT b/COPYRIGHT index d04c007ff65..93f4a43fee1 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -26,14 +26,14 @@ PHP libraries: EvalMath 1.0 BSD Yes Safe math expressions evaluation Escpos-php 2.2 MIT License Yes Thermal receipt printer library, for use with ESC/POS compatible printers GeoIP2 0.2.0 Apache License 2.0 Yes Lib to make geoip convert -Mobiledetect 2.8.39 MIT License Yes Detect mobile devices browsers +Mobiledetect 2.8.41 MIT License Yes Detect mobile devices browsers NuSoap 0.9.5 LGPL 2.1+ Yes Library to develop SOAP Web services (not into rpm and deb package) PEAR Mail_MIME 1.8.9 BSD Yes NuSoap dependency ParseDown 1.6 MIT License Yes Markdown parser PCLZip 2.8.4 LGPL-3+ Yes Library to zip/unzip files PHPDebugBar 1.18.2 MIT License Yes Used only by the module "debugbar" for developers PHP-Imap 2.7.2 MIT License Yes Library to use IMAP with OAuth -PHPSpreadSheet 1.8.2 LGPL-2.1+ Yes Read/Write XLS files, read ODS files +PHPSpreadSheet 1.12.0 LGPL-2.1+ Yes Read/Write XLS files, read ODS files php-iban 4.1.1 LGPL-3+ Yes Parse and validate IBAN (and IIBAN) bank account information in PHP PHPoAuthLib 0.8.2 MIT License Yes Library to provide oauth1 and oauth2 to different service PHPPrintIPP 1.3 GPL-2+ Yes Library to send print IPP requests @@ -51,7 +51,7 @@ JS libraries: Ace 1.4.14 BSD Yes JS library to get code syntaxique coloration in a textarea. ChartJS 3.7.1 MIT License Yes JS library for graph CKEditor 4.18 LGPL-2.1+ Yes Editor WYSIWYG -jQuery 3.6.0 MIT License Yes JS library +jQuery 3.6.4 MIT License Yes JS library jQuery UI 1.13.2 GPL and MIT License Yes JS library plugin UI jQuery select2 4.0.13 GPL and Apache License Yes JS library plugin for sexier multiselect. Warning: 4.0.6+ create troubles without patching css jQuery blockUI 2.70.0 GPL and MIT License Yes JS library plugin blockUI (to use ajax popups) diff --git a/ChangeLog b/ChangeLog index 8721e272aa7..ce8c34636f6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -17,12 +17,63 @@ Following changes may create regressions for some external modules, but were nec * Revert default type of hooks. Default is now 'addreplace' hooks (and exception become 'output' hooks, that become deprecated). * Deprecated property libelle removed from entrepot class. * The type 'text' in ->fields property dos not accept html content anymore. Use the type 'html' for that. +* The module for WebService SOAP API have been deprecated. Use instead the Webservice REST API module. +* The method htmlPrintOnlinePaymentFooter() used for public footer pages has been renamed into htmlPrintOnlineFooter() and moved into company.lib.php ***** ChangeLog for 17.0.1 compared to 17.0.0 ***** -TODO +FIX: 17.0 PHP Warning invalid argument supplied for foreach +FIX: #[23799] - External users are not able to create events - correction +FIX: #23966 Error "Param dbt_keyfield is required but not defined +FIX: #24138 Fix box_birthdays SQL for postgres +FIX: #24201 Upload of external module fails to copy from incorrectly generated temp source dir +FIX: #24240 Dolibarr V17.0.0 PHP8 fatal error +FIX: accountancy lettering: better error management +FIX: accountancy lettering: correctly calculated number of lettering operations done +FIX: accountancy lettering: error management and prevention +FIX: accountancy lettering: prevent null results when fetching link with payments +FIX: action delete card fac rec +FIX: Add bookmark with search fields that are arrays (backport 4157263cb898f1847cfcfc22dee6007c01b13a4d) +FIX: Add missing hook on LibStatut +FIX: Add more context for selectForFormsListWhere Hook +FIX: Autofill / clear qty in inventory page +FIX: avoid php8 warnings +FIX: avoid phpunit error +FIX: can not show all csv fields (a reason for that ?) +FIX: change date on select date input when prefix is used +FIX: dol_textishtml() function +FIX: expense report accountancy: sql syntax error when performing automatic linking +FIX: Extrafields in Notes to unify with orders or invoices. +FIX: fatal error when margin enable (missing check on element), fix User::hasRight() when checking a margin right +FIX: feedbacks +FIX: FILTER_VALIDATE_EMAIL param is not a string +FIX: #24298 No error or 0.00 instead of NULL in database anymore when emptying an extrafield of type price on a propal card +FIX: full group by handle +FIX: holiday counter massaction: ErrorBadValueForParamNotAString and PHP 8 warning when no approval user right +FIX: installation superadmin creation: PHP 8 warning +FIX: invoices order on sells journal +FIX: it was not possible to update extrafields of expedition lines with batch without editing batch value +FIX: limit after order in get objects in category +FIX: method dolGetGlobalString not defined with saphir +FIX: missing column default workstation +FIX: missing drop foreign key before modify field +FIX: missing "multidir_output" for project sharing (Multicompany) +FIX: missing protection on ajax public ticket page for valid email +FIX: ODT management inverted between purchase invoice and order +FIX: PDF Espadon => display extrafields +FIX: PDF Espadon Expedition : notes and tracking number +FIX: Phpunit Rename WebsiteTest.class.php to WebsiteTest.php +FIX: project referent elements list: conf to hide tasks was flipped +FIX: Protection on agenda view for a thirdparty id that does not exist +FIX: search_project_user +FIX: societe list: regression to redirection to customer card when single result of search filters +FIX: SQL error "unknown column p.fk_soc" because ANSI-92 joins take precedence over ANSI-89 joins +FIX: task have the same entity of project +FIX: token error when closing ticket from public interface +FIX: Warning on purchase order + Property fk_commande not defined + ***** ChangeLog for 17.0.0 compared to 16.0.0 ***** @@ -232,7 +283,51 @@ Following changes may create regressions for some external modules, but were nec ***** ChangeLog for 16.0.5 compared to 16.0.4 ***** -TODO +FIX: 16.0 propalestats Unknown column 'p.fk_soc' in 'on clause' +FIX: #23804 +FIX: #23860 +FIX: #23966 Error "Param dbt_keyfield is required but not defined" +FIX: accountancy lettering: better error management +FIX: accountancy lettering: correctly calculated number of lettering operations done +FIX: accountancy lettering: error management and prevention +FIX: accountancy lettering: prevent null results when fetching link with payments +FIX: Add missing hook on LibStatut +FIX: Add more context for selectForFormsListWhere Hook +FIX: attach file and send by mail in ticket +FIX: bad check on if in get_all_ways +FIX: Cannot import find type_fees with cgenericdic.class because it has id and not rowid +FIX: clicktodial backtopage +FIX: discount wasn't taken into account when adding a line in BOM +FIX: expense reports: error when selecting mileage fees expense type if MAIN_USE_EXPENSE_IK disabled +FIX: expense reports: JS error when selecting mileage fees expense type if MAIN_USE_EXPENSE_IK disabled +FIX: Extrafields in Notes to unify with orders or invoices. +FIX: fatal error on clicktodial backtopage +FIX: filter sql accounting account +FIX: Get data back on product update +FIX: Get data back when error on command create +FIX: label dictionary is used by barcode and member module +FIX: mandatory date for service didnt work for invoice +FIX: missing "authorid" for getNomUrl link right access +FIX: missing getEntity filter +FIX: vulnerability: missing protection on ajax public ticket page for valid email. +FIX: Missing right to edit service note when module product is disabled +FIX: multicompany compatibility +FIX: object $user is not defined +FIX: Object of class LDAP\Connection could not be converted to string +FIX: parse error and NAN +FIX: product ref fourn same size in supplier order/invoice as in product price fourn +FIX: Profit calculation on project preview tab. +FIX: Remove orphelan $this->db->rollback() in the function insertExtrafields() +FIX: request new password with "mc" and "twofactor" authentication +FIX: Resolve error message due to missing arguments +FIX: select for task in event card +FIX: several email sent to the same recipient when adding message from ticket +FIX: shipping list for external user +FIX: SQL error "unknown column p.fk_soc" because ANSI-92 joins take precedence over ANSI-89 joins +FIX: strato pdf +FIX: typos in getAttchments() $arrayobject +FIX: whitespaces +FIX: wrong url param name action ***** ChangeLog for 16.0.4 compared to 16.0.3 ***** diff --git a/build/generate_filelist_xml.php b/build/generate_filelist_xml.php index 45d649d90d9..5614b5323bd 100755 --- a/build/generate_filelist_xml.php +++ b/build/generate_filelist_xml.php @@ -56,7 +56,7 @@ if (empty($argv[1])) { $i=0; -$result=array(); +$result = array(); while ($i < $argc) { if (!empty($argv[$i])) { parse_str($argv[$i], $result); // set all params $release, $includecustom, $includeconstant, $buildzip ... diff --git a/htdocs/accountancy/admin/export.php b/htdocs/accountancy/admin/export.php index 23a16340c0b..30cc0144a1f 100644 --- a/htdocs/accountancy/admin/export.php +++ b/htdocs/accountancy/admin/export.php @@ -269,9 +269,9 @@ if ($num2) { // Value print ''; if (is_array($key['param'])) { - print $form->selectarray($label, $key['param'], $conf->global->$label, 0); + print $form->selectarray($label, $key['param'], getDolGlobalString($label), 0); } else { - print ''; + print ''; } print ''; diff --git a/htdocs/accountancy/expensereport/index.php b/htdocs/accountancy/expensereport/index.php index 339ffe68b96..f11ccbf512e 100644 --- a/htdocs/accountancy/expensereport/index.php +++ b/htdocs/accountancy/expensereport/index.php @@ -112,7 +112,7 @@ if ($action == 'validatehistory') { $sql1 = "SELECT erd.rowid, accnt.rowid as suggestedid"; $sql1 .= " FROM ".MAIN_DB_PREFIX."expensereport_det as erd"; $sql1 .= " LEFT JOIN ".MAIN_DB_PREFIX."c_type_fees as t ON erd.fk_c_type_fees = t.id"; - $sql1 .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as accnt ON t.accountancy_code = accnt.account_number AND accnt.active = 1 AND accnt.fk_pcg_version = '".$db->escape($chartaccountcode)."' AND accnt.entity =".((int) $conf->entity); + $sql1 .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as accnt ON t.accountancy_code = accnt.account_number AND accnt.active = 1 AND accnt.fk_pcg_version = '".$db->escape($chartaccountcode)."' AND accnt.entity =".((int) $conf->entity).","; $sql1 .= " ".MAIN_DB_PREFIX."expensereport as er"; $sql1 .= " WHERE erd.fk_expensereport = er.rowid AND er.entity = ".((int) $conf->entity); $sql1 .= " AND er.fk_statut IN (".ExpenseReport::STATUS_APPROVED.", ".ExpenseReport::STATUS_CLOSED.") AND erd.fk_code_ventilation <= 0"; diff --git a/htdocs/accountancy/journal/sellsjournal.php b/htdocs/accountancy/journal/sellsjournal.php index 565a3a59222..96555b960c0 100644 --- a/htdocs/accountancy/journal/sellsjournal.php +++ b/htdocs/accountancy/journal/sellsjournal.php @@ -158,7 +158,7 @@ if ($in_bookkeeping == 'notyet') { $sql .= " AND f.rowid NOT IN (SELECT fk_doc FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as ab WHERE ab.doc_type='customer_invoice')"; // $sql .= " AND fd.rowid NOT IN (SELECT fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as ab WHERE ab.doc_type='customer_invoice')"; // Useless, we save one line for all products with same account } -$sql .= " ORDER BY f.datef"; +$sql .= " ORDER BY f.datef, f.ref"; //print $sql; exit; dol_syslog('accountancy/journal/sellsjournal.php', LOG_DEBUG); diff --git a/htdocs/adherents/admin/member.php b/htdocs/adherents/admin/member.php index f9e15e88fca..5a562fec537 100644 --- a/htdocs/adherents/admin/member.php +++ b/htdocs/adherents/admin/member.php @@ -511,7 +511,7 @@ foreach ($dirmodels as $reldir) { // Defaut print ''; - if (getDolGlobalString('MEMBER_ADDON_PDF') == $name) { + if (getDolGlobalString('MEMBER_ADDON_PDF_ODT') == $name) { print img_picto($langs->trans("Default"), 'on'); } else { print 'scandir) ? $module->scandir : '').'&label='.urlencode($module->name).'" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"), 'off').''; diff --git a/htdocs/adherents/admin/member_emails.php b/htdocs/adherents/admin/member_emails.php index 4f942d1f6a8..a1e28904d8c 100644 --- a/htdocs/adherents/admin/member_emails.php +++ b/htdocs/adherents/admin/member_emails.php @@ -48,18 +48,23 @@ $action = GETPOST('action', 'aZ09'); $error = 0; +$helptext = '*'.$langs->trans("FollowingConstantsWillBeSubstituted").'
'; +$helptext .= '__DOL_MAIN_URL_ROOT__, __ID__, __FIRSTNAME__, __LASTNAME__, __FULLNAME__, __LOGIN__, __PASSWORD__, '; +$helptext .= '__COMPANY__, __ADDRESS__, __ZIP__, __TOWN__, __COUNTRY__, __EMAIL__, __BIRTH__, __PHOTO__, __TYPE__, '; +//$helptext.='__YEAR__, __MONTH__, __DAY__'; // Not supported + // Editing global variables not related to a specific theme $constantes = array( 'MEMBER_REMINDER_EMAIL'=>array('type'=>'yesno', 'label'=>$langs->trans('MEMBER_REMINDER_EMAIL', $langs->transnoentities("Module2300Name"))), - 'ADHERENT_EMAIL_TEMPLATE_REMIND_EXPIRATION' =>'emailtemplate:member', - 'ADHERENT_EMAIL_TEMPLATE_AUTOREGISTER' =>'emailtemplate:member', // until Dolibarr 7 it was ADHERENT_AUTOREGISTER_MAIL - 'ADHERENT_EMAIL_TEMPLATE_MEMBER_VALIDATION' =>'emailtemplate:member', // until Dolibarr 7 it was ADHERENT_MAIL_VALID - 'ADHERENT_EMAIL_TEMPLATE_SUBSCRIPTION' =>'emailtemplate:member', // until Dolibarr 7 it was ADHERENT_MAIL_COTIS - 'ADHERENT_EMAIL_TEMPLATE_CANCELATION' =>'emailtemplate:member', // until Dolibarr 7 it was ADHERENT_MAIL_RESIL - 'ADHERENT_EMAIL_TEMPLATE_EXCLUSION' =>'emailtemplate:member', - 'ADHERENT_MAIL_FROM' =>'string', - 'ADHERENT_AUTOREGISTER_NOTIF_MAIL_SUBJECT' =>'string', - 'ADHERENT_AUTOREGISTER_NOTIF_MAIL' =>'html', + 'ADHERENT_EMAIL_TEMPLATE_REMIND_EXPIRATION' =>array('type'=>'emailtemplate:member'), + 'ADHERENT_EMAIL_TEMPLATE_AUTOREGISTER' =>array('type'=>'emailtemplate:member'), + 'ADHERENT_EMAIL_TEMPLATE_MEMBER_VALIDATION' =>array('type'=>'emailtemplate:member'), + 'ADHERENT_EMAIL_TEMPLATE_SUBSCRIPTION' =>array('type'=>'emailtemplate:member'), + 'ADHERENT_EMAIL_TEMPLATE_CANCELATION' =>array('type'=>'emailtemplate:member'), + 'ADHERENT_EMAIL_TEMPLATE_EXCLUSION' =>array('type'=>'emailtemplate:member'), + 'ADHERENT_MAIL_FROM' =>array('type'=>'string'), + 'ADHERENT_AUTOREGISTER_NOTIF_MAIL_SUBJECT' =>array('type'=>'string'), + 'ADHERENT_AUTOREGISTER_NOTIF_MAIL' =>array('type'=>'html', 'tooltip'=>$helptext) ); @@ -147,12 +152,7 @@ print '
'; print ''; print ''; -$helptext = '*'.$langs->trans("FollowingConstantsWillBeSubstituted").'
'; -$helptext .= '__DOL_MAIN_URL_ROOT__, __ID__, __FIRSTNAME__, __LASTNAME__, __FULLNAME__, __LOGIN__, __PASSWORD__, '; -$helptext .= '__COMPANY__, __ADDRESS__, __ZIP__, __TOWN__, __COUNTRY__, __EMAIL__, __BIRTH__, __PHOTO__, __TYPE__, '; -//$helptext.='__YEAR__, __MONTH__, __DAY__'; // Not supported - -form_constantes($constantes, 3, $helptext); +form_constantes($constantes, 3, ''); print '
'; print '
'; diff --git a/htdocs/adherents/admin/website.php b/htdocs/adherents/admin/website.php index dd44ce0cece..6b7d12c122a 100644 --- a/htdocs/adherents/admin/website.php +++ b/htdocs/adherents/admin/website.php @@ -60,7 +60,7 @@ if ($action == 'update') { $amount = price2num(GETPOST('MEMBER_NEWFORM_AMOUNT'), 'MT', 2); $minamount = GETPOST('MEMBER_MIN_AMOUNT'); $publiccounters = GETPOST('MEMBER_COUNTERS_ARE_PUBLIC'); - $showtable = GETPOST('MEMBER_SHOW_TABLE');; + $showtable = GETPOST('MEMBER_SHOW_TABLE'); $showvoteallowed = GETPOST('MEMBER_SHOW_VOTE_ALLOWED'); $payonline = GETPOST('MEMBER_NEWFORM_PAYONLINE'); $forcetype = GETPOST('MEMBER_NEWFORM_FORCETYPE', 'int'); diff --git a/htdocs/adherents/class/adherent.class.php b/htdocs/adherents/class/adherent.class.php index e06ce655c73..7f9adb32266 100644 --- a/htdocs/adherents/class/adherent.class.php +++ b/htdocs/adherents/class/adherent.class.php @@ -2365,10 +2365,11 @@ class Adherent extends CommonObject ]; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { $classfortooltip = 'classforajaxtooltip'; - $dataparams = ' data-params='.json_encode($params); - // $label = $langs->trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); $url = DOL_URL_ROOT.'/adherents/card.php?rowid='.((int) $this->id); if ($option == 'subscription') { @@ -2394,7 +2395,7 @@ class Adherent extends CommonObject $label = $langs->trans("ShowUser"); $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; } - $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"'); $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"'; } diff --git a/htdocs/adherents/class/adherent_type.class.php b/htdocs/adherents/class/adherent_type.class.php index 141a2264113..9ee0de6c055 100644 --- a/htdocs/adherents/class/adherent_type.class.php +++ b/htdocs/adherents/class/adherent_type.class.php @@ -749,12 +749,12 @@ class AdherentType extends CommonObject ]; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { $classfortooltip = 'classforajaxtooltip'; - $dataparams = ' data-params='.json_encode($params); - // $label = $langs->trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); - $url = DOL_URL_ROOT.'/adherents/type.php?rowid='.((int) $this->id); if ($option != 'nolink') { // Add param to save lastsearch_values or not @@ -766,7 +766,10 @@ class AdherentType extends CommonObject $url .= '&save_lastsearch_values=1'; } } - $linkstart = ''; + $linkstart = ''; + $linkend = ''; $result .= $linkstart; @@ -993,8 +996,6 @@ class AdherentType extends CommonObject { global $langs, $user; - $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']); - $return = '
'; $return .= '
'; $return .= ''; @@ -1002,9 +1003,12 @@ class AdherentType extends CommonObject $return .= ''; $return .= '
'; $return .= ''.(method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref).''; - $return .= ''; + + //$selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']); + //$return .= ''; + if ($user->rights->adherent->configurer) { - $return .= 'ref.'">'.img_edit().''; + $return .= 'ref).'">'.img_edit().''; } else { $return .= ' '; } diff --git a/htdocs/adherents/list.php b/htdocs/adherents/list.php index f4208f590fd..35d4015e270 100644 --- a/htdocs/adherents/list.php +++ b/htdocs/adherents/list.php @@ -424,10 +424,10 @@ if ($search_filter == 'waitingsubscription') { $sql .= " AND (datefin IS NULL AND t.subscription = '1')"; } if ($search_filter == 'uptodate') { - $sql .= " AND (datefin >= '".$db->idate($now)."' OR t.subscription = '0')"; + $sql .= " AND (datefin >= '".$db->idate($now)."' OR (datefin IS NULL AND t.subscription = '0'))"; } if ($search_filter == 'outofdate') { - $sql .= " AND (datefin < '".$db->idate($now)."' AND t.subscription = '1')"; + $sql .= " AND (datefin < '".$db->idate($now)."')"; } if ($search_status != '') { // Peut valoir un nombre ou liste de nombre separes par virgules @@ -516,6 +516,7 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { } $db->free($resql); } +//print $sql; // Complete request and execute it with limit $sql .= $db->order($sortfield, $sortorder); diff --git a/htdocs/adherents/subscription/card.php b/htdocs/adherents/subscription/card.php index b97fac372e5..d6ce54a20e9 100644 --- a/htdocs/adherents/subscription/card.php +++ b/htdocs/adherents/subscription/card.php @@ -352,10 +352,10 @@ if ($rowid && $action != 'edit') { print '
'; if ($user->hasRight('adherent', 'cotisation', 'creer')) { - if (!empty($bankline->rappro)) { + if (!empty($bankline->rappro) || empty($bankline)) { print '"; } else { - print '"; + print '"; } } diff --git a/htdocs/adherents/subscription/list.php b/htdocs/adherents/subscription/list.php index 4cd21775ae7..10b711e943f 100644 --- a/htdocs/adherents/subscription/list.php +++ b/htdocs/adherents/subscription/list.php @@ -32,13 +32,16 @@ require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php'; $langs->loadLangs(array("members", "companies")); -$action = GETPOST('action', 'aZ09'); -$massaction = GETPOST('massaction', 'alpha'); -$confirm = GETPOST('confirm', 'alpha'); -$toselect = GETPOST('toselect', 'array'); -$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'subscriptionlist'; // To manage different context of search -$mode = GETPOST('mode', 'alpha'); - +$action = GETPOST('action', 'aZ09') ? GETPOST('action', 'aZ09') : 'view'; // The action 'create'/'add', 'edit'/'update', 'view', ... +$massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists) +$show_files = GETPOST('show_files', 'int'); // Show files area generated by bulk actions ? +$confirm = GETPOST('confirm', 'alpha'); // Result of a confirmation +$cancel = GETPOST('cancel', 'alpha'); // We click on a Cancel button +$toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected into a list +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : str_replace('_', '', basename(dirname(__FILE__)).basename(__FILE__, '.php')); // To manage different context of search +$backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page +$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') +$mode = GETPOST('mode', 'aZ'); // The output mode ('list', 'kanban', 'hierarchy', 'calendar', ...) $statut = (GETPOSTISSET("statut") ?GETPOST("statut", "alpha") : 1); $search_ref = GETPOST('search_ref', 'alpha'); @@ -49,18 +52,19 @@ $search_login = GETPOST('search_login', 'alpha'); $search_note = GETPOST('search_note', 'alpha'); $search_account = GETPOST('search_account', 'int'); $search_amount = GETPOST('search_amount', 'alpha'); -$optioncss = GETPOST('optioncss', 'alpha'); -$sall = ''; +$search_all = ''; $date_select = GETPOST("date_select", 'alpha'); -$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit; +// Load variable for pagination +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; $sortfield = GETPOST('sortfield', 'aZ09comma'); $sortorder = GETPOST('sortorder', 'aZ09comma'); $page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); -if (empty($page) || $page == -1) { +if (empty($page) || $page < 0 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha')) { + // If $page is not defined, or '' or -1 or if we click on clear filters $page = 0; -} // If $page is not defined, or '' or -1 +} $offset = $limit * $page; $pageprev = $page - 1; $pagenext = $page + 1; @@ -71,13 +75,12 @@ if (!$sortfield) { $sortfield = "c.dateadh"; } +// Initialize technical objects $object = new Subscription($db); - -// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context -$hookmanager->initHooks(array('subscriptionlist')); $extrafields = new ExtraFields($db); +$hookmanager->initHooks(array('subscriptionlist')); -// fetch optionals attributes and labels +// Fetch optionals attributes and labels $extrafields->fetch_name_optionals_label($object->table_element); $search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); @@ -106,13 +109,16 @@ $arrayfields = array( // Security check $result = restrictedArea($user, 'adherent', '', '', 'cotisation'); +$permissiontodelete = $user->hasRight('adherent', 'cotisation', 'creer'); + /* * Actions */ if (GETPOST('cancel', 'alpha')) { - $action = 'list'; $massaction = ''; + $action = 'list'; + $massaction = ''; } if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') { $massaction = ''; @@ -141,6 +147,16 @@ if (empty($reshook)) { $toselect = array(); $search_array_options = array(); } + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha') + || GETPOST('button_search_x', 'alpha') || GETPOST('button_search.x', 'alpha') || GETPOST('button_search', 'alpha')) { + $massaction = ''; // Protection to avoid mass action if we force a new search during a mass action confirmation + } + + // Mass actions + $objectclass = 'Subscription'; + $objectlabel = 'Subscription'; + $uploaddir = $conf->adherent->dir_output; + include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php'; } @@ -162,6 +178,20 @@ $sql .= " c.rowid as crowid, c.fk_type, c.subscription,"; $sql .= " c.dateadh, c.datef, c.datec as date_creation, c.tms as date_update,"; $sql .= " c.fk_bank as bank, c.note,"; $sql .= " b.fk_account"; +// Add fields from extrafields +if (!empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key." as options_".$key : ''); + } +} +// Add fields from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object, $action); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; +$sql = preg_replace('/,\s*$/', '', $sql); + +$sqlfields = $sql; // $sql fields to remove for count total + $sql .= " FROM ".MAIN_DB_PREFIX."adherent as d"; $sql .= " JOIN ".MAIN_DB_PREFIX."subscription as c on d.rowid = c.fk_adherent"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."adherent_extrafields as ef on (d.rowid = ef.fk_object)"; @@ -199,60 +229,72 @@ if ($search_account > 0) { if ($search_amount) { $sql .= natural_search('c.subscription', $search_amount, 1); } - +if ($search_all) { + $sql .= natural_search(array_keys($fieldstosearchall), $search_all); +} // Add where from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; - // Add where from hooks $parameters = array(); -$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook +$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object, $action); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; -$sql .= $db->order($sortfield, $sortorder); - -// Count total nb of records with no order and no limits +// Count total nb of records $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { - $resql = $db->query($sql); + /* The fast and low memory method to get and count full list converts the sql into a sql count */ + $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); + $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); + $resql = $db->query($sqlforcount); if ($resql) { - $nbtotalofrecords = $db->num_rows($resql); + $objforcount = $db->fetch_object($resql); + $nbtotalofrecords = $objforcount->nbtotalofrecords; } else { dol_print_error($db); } - if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0 + + if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller than the paging size (filtering), goto and load page 0 $page = 0; $offset = 0; } + $db->free($resql); } -// Add limit -$sql .= $db->plimit($limit + 1, $offset); -$result = $db->query($sql); -if (!$result) { +// Complete request and execute it with limit +$sql .= $db->order($sortfield, $sortorder); +if ($limit) { + $sql .= $db->plimit($limit + 1, $offset); +} + +$resql = $db->query($sql); +if (!$resql) { dol_print_error($db); exit; } -$num = $db->num_rows($result); +$num = $db->num_rows($resql); -$arrayofselected = is_array($toselect) ? $toselect : array(); -if ($num == 1 && !empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $sall) { +// Direct jump if only one record found +if ($num == 1 && !empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $search_all && !$page) { $obj = $db->fetch_object($resql); $id = $obj->rowid; header("Location: ".DOL_URL_ROOT.'/adherents/subscription/card.php?id='.$id); exit; } +// Output page +// -------------------------------------------------------------------- + $title = $langs->trans("Subscriptions"); if (!empty($date_select)) { $title .= ' ('.$langs->trans("Year").' '.$date_select.')'; } - $help_url = 'EN:Module_Foundations|FR:Module_Adhérents|ES:Módulo_Miembros|DE:Modul_Mitglieder'; + llxHeader('', $title, $help_url); -$i = 0; +$arrayofselected = is_array($toselect) ? $toselect : array(); $param = ''; if (!empty($mode)) { @@ -262,7 +304,7 @@ if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { $param .= '&contextpage='.urlencode($contextpage); } if ($limit > 0 && $limit != $conf->liste_limit) { - $param .= '&limit='.urlencode($limit); + $param .= '&limit='.((int) $limit); } if ($statut != '') { $param .= "&statut=".urlencode($statut); @@ -290,27 +332,25 @@ if ($optioncss != '') { } // Add $param from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; +// Add $param from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object, $action); // Note that $action and $object may have been modified by hook +$param .= $hookmanager->resPrint; // List of mass actions available $arrayofmassactions = array( //'presend'=>img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail"), //'builddoc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("PDFMerge"), ); -//if ($user->hasRight('adherent', 'supprimer')) $arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete"); -if (in_array($massaction, array('presend', 'predelete'))) { +if (!empty($permissiontodelete)) { + $arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete"); +} +if (GETPOST('nomassaction', 'int') || in_array($massaction, array('presend', 'predelete'))) { $arrayofmassactions = array(); } $massactionbutton = $form->selectMassAction('', $arrayofmassactions); -$newcardbutton = ''; -$newcardbutton .= dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-bars imgforviewmode', $_SERVER["PHP_SELF"].'?mode=common'.preg_replace('/(&|\?)*mode=[^&]+/', '', $param), '', ((empty($mode) || $mode == 'common') ? 2 : 1), array('morecss'=>'reposition')); -$newcardbutton .= dolGetButtonTitle($langs->trans('ViewKanban'), '', 'fa fa-th-list imgforviewmode', $_SERVER["PHP_SELF"].'?mode=kanban'.preg_replace('/(&|\?)*mode=[^&]+/', '', $param), '', ($mode == 'kanban' ? 2 : 1), array('morecss'=>'reposition')); - -if ($user->hasRight('adherent', 'cotisation', 'creer')) { - $newcardbutton .= dolGetButtonTitle($langs->trans('NewSubscription'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/adherents/list.php?status=-1,1'); -} - -print '
'; +print ''."\n"; if ($optioncss != '') { print ''; } @@ -319,10 +359,19 @@ print ''; print ''; print ''; +print ''; print ''; print ''; +print ''; print ''; +$newcardbutton = ''; +$newcardbutton .= dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-bars imgforviewmode', $_SERVER["PHP_SELF"].'?mode=common'.preg_replace('/(&|\?)*mode=[^&]+/', '', $param), '', ((empty($mode) || $mode == 'common') ? 2 : 1), array('morecss'=>'reposition')); +$newcardbutton .= dolGetButtonTitle($langs->trans('ViewKanban'), '', 'fa fa-th-list imgforviewmode', $_SERVER["PHP_SELF"].'?mode=kanban'.preg_replace('/(&|\?)*mode=[^&]+/', '', $param), '', ($mode == 'kanban' ? 2 : 1), array('morecss'=>'reposition')); +if ($user->hasRight('adherent', 'cotisation', 'creer')) { + $newcardbutton .= dolGetButtonTitleSeparator(); + $newcardbutton .= dolGetButtonTitle($langs->trans('NewSubscription'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/adherents/list.php?status=-1,1'); +} print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, $subscription->picto, 0, $newcardbutton, '', $limit, 0, 0, 1); @@ -332,30 +381,51 @@ $objecttmp = new Subscription($db); $trackid = 'sub'.$object->id; include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php'; -if ($sall) { +if ($search_all) { + $setupstring = ''; foreach ($fieldstosearchall as $key => $val) { $fieldstosearchall[$key] = $langs->trans($val); + $setupstring .= $key."=".$val.";"; } - print '
'.$langs->trans("FilterOnInto", $sall).join(', ', $fieldstosearchall).'
'; + print ''."\n"; + print '
'.$langs->trans("FilterOnInto", $search_all).join(', ', $fieldstosearchall).'
'."\n"; } $moreforfilter = ''; +/*$moreforfilter.='
'; + $moreforfilter.= $langs->trans('MyFilter') . ': '; + $moreforfilter.= '
';*/ -$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; -$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')); // This also change content of $arrayfields -if ($massactionbutton) { - $selectedfields .= $form->showCheckAddButtons('checkforselect', 1); +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook +if (empty($reshook)) { + $moreforfilter .= $hookmanager->resPrint; +} else { + $moreforfilter = $hookmanager->resPrint; } -print '
'; +if (!empty($moreforfilter)) { + print '
'; + print $moreforfilter; + $parameters = array(); + $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + print '
'; +} + +$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; +$selectedfields = ($mode != 'kanban' ? $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN', '')) : ''); // This also change content of $arrayfields +$selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); + +print '
'; // You can use div-table-responsive-no-min if you dont need reserved height for your table print ''."\n"; - -// Line for filters fields +// Fields title search +// -------------------------------------------------------------------- print ''; // Action column if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { - print ''; @@ -423,7 +493,7 @@ include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; // Fields from hook $parameters = array('arrayfields'=>$arrayfields); -$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook +$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object, $action); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; // Date creation if (!empty($arrayfields['c.datec']['checked'])) { @@ -438,55 +508,71 @@ if (!empty($arrayfields['c.tms']['checked'])) { // Action column if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { - print ''; } -print "\n"; +print ''."\n"; +$totalarray = array(); +$totalarray['nbfield'] = 0; +// Fields title label +// -------------------------------------------------------------------- print ''; +// Action column if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], '', '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch '); + $totalarray['nbfield']++; } if (!empty($arrayfields['d.ref']['checked'])) { print_liste_field_titre($arrayfields['d.ref']['label'], $_SERVER["PHP_SELF"], "c.rowid", $param, "", "", $sortfield, $sortorder); + $totalarray['nbfield']++; } if (!empty($arrayfields['d.fk_type']['checked'])) { print_liste_field_titre($arrayfields['d.fk_type']['label'], $_SERVER["PHP_SELF"], "c.fk_type", $param, "", "", $sortfield, $sortorder); + $totalarray['nbfield']++; } if (!empty($arrayfields['d.lastname']['checked'])) { print_liste_field_titre($arrayfields['d.lastname']['label'], $_SERVER["PHP_SELF"], "d.lastname", $param, "", "", $sortfield, $sortorder); + $totalarray['nbfield']++; } if (!empty($arrayfields['d.firstname']['checked'])) { print_liste_field_titre($arrayfields['d.firstname']['label'], $_SERVER["PHP_SELF"], "d.firstname", $param, "", "", $sortfield, $sortorder); + $totalarray['nbfield']++; } if (!empty($arrayfields['d.login']['checked'])) { print_liste_field_titre($arrayfields['d.login']['label'], $_SERVER["PHP_SELF"], "d.login", $param, "", "", $sortfield, $sortorder); + $totalarray['nbfield']++; } if (!empty($arrayfields['t.libelle']['checked'])) { print_liste_field_titre($arrayfields['t.libelle']['label'], $_SERVER["PHP_SELF"], "c.note", $param, "", '', $sortfield, $sortorder); + $totalarray['nbfield']++; } if (!empty($arrayfields['d.bank']['checked'])) { print_liste_field_titre($arrayfields['d.bank']['label'], $_SERVER["PHP_SELF"], "b.fk_account", $param, "", "", $sortfield, $sortorder); + $totalarray['nbfield']++; } if (!empty($arrayfields['c.dateadh']['checked'])) { print_liste_field_titre($arrayfields['c.dateadh']['label'], $_SERVER["PHP_SELF"], "c.dateadh", $param, "", '', $sortfield, $sortorder, 'center nowraponall '); + $totalarray['nbfield']++; } if (!empty($arrayfields['c.datef']['checked'])) { print_liste_field_titre($arrayfields['c.datef']['label'], $_SERVER["PHP_SELF"], "c.datef", $param, "", '', $sortfield, $sortorder, 'center nowraponall '); + $totalarray['nbfield']++; } if (!empty($arrayfields['d.amount']['checked'])) { print_liste_field_titre($arrayfields['d.amount']['label'], $_SERVER["PHP_SELF"], "c.subscription", $param, "", '', $sortfield, $sortorder, 'right '); + $totalarray['nbfield']++; } // Extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; // Hook fields -$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); -$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook +$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder, 'totalarray'=>&$totalarray); +$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; if (!empty($arrayfields['c.datec']['checked'])) { print_liste_field_titre($arrayfields['c.datec']['label'], $_SERVER["PHP_SELF"], "c.datec", "", $param, 'align="center" class="nowrap"', $sortfield, $sortorder); @@ -494,17 +580,25 @@ if (!empty($arrayfields['c.datec']['checked'])) { if (!empty($arrayfields['c.tms']['checked'])) { print_liste_field_titre($arrayfields['c.tms']['label'], $_SERVER["PHP_SELF"], "c.tms", "", $param, 'align="center" class="nowrap"', $sortfield, $sortorder); } +// Action column if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { - print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], '', '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch '); + print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; + $totalarray['nbfield']++; } -print "\n"; - +print ''."\n"; +// Loop on record +// -------------------------------------------------------------------- +$i = 0; +$savnbfield = $totalarray['nbfield']; $totalarray = array(); $totalarray['nbfield'] = 0; $imaxinloop = ($limit ? min($num, $limit) : $num); while ($i < $imaxinloop) { - $obj = $db->fetch_object($result); + $obj = $db->fetch_object($resql); + if (empty($obj)) { + break; // Should not happen + } $subscription->ref = $obj->crowid; $subscription->id = $obj->crowid; @@ -532,9 +626,16 @@ while ($i < $imaxinloop) { if ($mode == 'kanban') { if ($i == 0) { - print ''; } } else { - print ''; + // Show here line of result + $j = 0; + print ''; // Action column if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { - print '\n"; + + print ''."\n"; } $i++; } @@ -720,19 +824,19 @@ if ($num == 0) { $colspan++; } } - print ''; + print ''; } $db->free($resql); -$parameters = array('sql' => $sql); -$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters); // Note that $action and $object may have been modified by hook +$parameters = array('arrayfields'=>$arrayfields, 'sql' => $sql); +$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object, $action); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; -print "
'; + print ''; $searchpicto = $form->showFilterButtons('left'); print $searchpicto; print ''; + print ''; $searchpicto = $form->showFilterButtons(); print $searchpicto; print '
'; + print '
'; print '
'; } + // Output Kanban + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($object->id, $arrayofselected)) { + $selected = 1; + } + } //fetch informations needs on this mode $subscription->fk_adherent = $adherent->getNomUrl(1); @@ -552,10 +653,12 @@ while ($i < $imaxinloop) { print '
'; + print ''; if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined $selected = 0; if (in_array($obj->crowid, $arrayofselected)) { @@ -690,7 +793,7 @@ while ($i < $imaxinloop) { } // Action column if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { - print ''; + print ''; if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined $selected = 0; if (in_array($obj->crowid, $arrayofselected)) { @@ -703,7 +806,8 @@ while ($i < $imaxinloop) { $totalarray['nbfield']++; } } - print "
'.$langs->trans("NoRecordFound").'
'.$langs->trans("NoRecordFound").'
"; -print '
'; -print ''; +print ''."\n"; +print '
'."\n"; +print ''."\n"; // End of page llxFooter(); diff --git a/htdocs/adherents/type.php b/htdocs/adherents/type.php index 207acc53e6f..394a17433f4 100644 --- a/htdocs/adherents/type.php +++ b/htdocs/adherents/type.php @@ -433,7 +433,7 @@ if ($action == 'create') { print $form->selectarray("morphy", $morphys, GETPOSTISSET("morphy") ? GETPOST("morphy", 'aZ09') : 'morphy'); print ""; - print ''.$langs->trans("SubscriptionRequired").''; + print ''.$form->textwithpicto($langs->trans("SubscriptionRequired"), $langs->trans("SubscriptionRequiredDesc")).''; print $form->selectyesno("subscription", 1, 1); print ''; @@ -509,7 +509,7 @@ if ($rowid > 0) { print ''.$langs->trans("MembersNature").''.$object->getmorphylib($object->morphy).''; print ''; - print ''.$langs->trans("SubscriptionRequired").''; + print ''.$form->textwithpicto($langs->trans("SubscriptionRequired"), $langs->trans("SubscriptionRequiredDesc")).''; print yn($object->subscription); print ''; @@ -585,6 +585,9 @@ if ($rowid > 0) { $sql .= " d.datefin,"; $sql .= " d.email, d.fk_adherent_type as type_id, d.morphy, d.statut as status,"; $sql .= " t.libelle as type, t.subscription, t.amount"; + + $sqlfields = $sql; // $sql fields to remove for count total + $sql .= " FROM ".MAIN_DB_PREFIX."adherent as d, ".MAIN_DB_PREFIX."adherent_type as t"; $sql .= " WHERE d.fk_adherent_type = t.rowid "; $sql .= " AND d.entity IN (".getEntity('adherent').")"; @@ -616,24 +619,32 @@ if ($rowid > 0) { $sql .= " AND (datefin < '".$db->idate($now)."' AND t.subscription = 1)"; } - $sql .= " ".$db->order($sortfield, $sortorder); - // Count total nb of records $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { - $resql = $db->query($sql); + /* The fast and low memory method to get and count full list converts the sql into a sql count */ + $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); + $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); + $resql = $db->query($sqlforcount); if ($resql) { - $nbtotalofrecords = $db->num_rows($result); + $objforcount = $db->fetch_object($resql); + $nbtotalofrecords = $objforcount->nbtotalofrecords; } else { dol_print_error($db); } - if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0 + + if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller than the paging size (filtering), goto and load page 0 $page = 0; $offset = 0; } + $db->free($resql); } - $sql .= " ".$db->plimit($conf->liste_limit + 1, $offset); + // Complete request and execute it with limit + $sql .= $db->order($sortfield, $sortorder); + if ($limit) { + $sql .= $db->plimit($limit + 1, $offset); + } $resql = $db->query($sql); if ($resql) { @@ -668,6 +679,15 @@ if ($rowid > 0) { } $param = "&rowid=".urlencode($object->id); + if (!empty($mode)) { + $param .= '&mode='.urlencode($mode); + } + if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { + $param .= '&contextpage='.urlencode($contextpage); + } + if ($limit > 0 && $limit != $conf->liste_limit) { + $param .= '&limit='.((int) $limit); + } if (!empty($status)) { $param .= "&status=".urlencode($status); } @@ -691,12 +711,11 @@ if ($rowid > 0) { print $langs->trans("Filter")." (".$langs->trans("Lastname").", ".$langs->trans("Firstname").", ".$langs->trans("EMail").", ".$langs->trans("Address")." ".$langs->trans("or")." ".$langs->trans("Town")."): ".$sall; } - print '
'; + print ''; print ''; - print ''; + print ''; - print '
'; - print_barre_liste('', $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords); + print_barre_liste('', $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'generic', 0, '', '', $limit); $moreforfilter = ''; @@ -706,24 +725,35 @@ if ($rowid > 0) { // Fields title search print ''; - print ''; - print ''; + if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + $searchpicto = $form->showFilterButtons('left'); + print $searchpicto; + print ''; + } print ''; - print ''; + print ''; + + print ''; + print ''; print ' '; print ''; - print ''; + print ''; print ' '; - print ''; - print ''; - print '  '; - print ''; - print ''; + print ' '; + + if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + print ''; + print '  '; + print ''; + print ''; + } print "\n"; diff --git a/htdocs/admin/emailcollector_card.php b/htdocs/admin/emailcollector_card.php index 054fa0bec31..880589fb5b1 100644 --- a/htdocs/admin/emailcollector_card.php +++ b/htdocs/admin/emailcollector_card.php @@ -684,18 +684,18 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ''; print '
'; - print '

'; + print '


'; // Operations - print '
'; - print ''; + print '
'; + print '
'; print ''; print ''; print ''; $arrayoftypes = array( - 'loadthirdparty' => $langs->trans('LoadThirdPartyFromName', $langs->transnoentities("ThirdPartyName")), - 'loadandcreatethirdparty' => $langs->trans('LoadThirdPartyFromNameOrCreate', $langs->transnoentities("ThirdPartyName")), + 'loadthirdparty' => $langs->trans('LoadThirdPartyFromName', $langs->transnoentities("ThirdPartyName").'/'.$langs->transnoentities("AliasNameShort").'/'.$langs->transnoentities("Email").'/'.$langs->transnoentities("ID")), + 'loadandcreatethirdparty' => $langs->trans('LoadThirdPartyFromNameOrCreate', $langs->transnoentities("ThirdPartyName").'/'.$langs->transnoentities("AliasNameShort").'/'.$langs->transnoentities("Email").'/'.$langs->transnoentities("ID")), 'recordjoinpiece' => 'AttachJoinedDocumentsToObject', 'recordevent' => 'RecordEvent' ); diff --git a/htdocs/admin/emailcollector_list.php b/htdocs/admin/emailcollector_list.php index b58bb5bb15d..ccee1f604b2 100644 --- a/htdocs/admin/emailcollector_list.php +++ b/htdocs/admin/emailcollector_list.php @@ -597,7 +597,7 @@ while ($i < $imaxinloop) { if (!empty($arrayfields['t.'.$key]['checked'])) { print '$key)) { print ' title="'.dol_escape_htmltag($object->$key).'"'; } print '>'; diff --git a/htdocs/admin/mails.php b/htdocs/admin/mails.php index 06f4dfdea85..504197fac7a 100644 --- a/htdocs/admin/mails.php +++ b/htdocs/admin/mails.php @@ -924,7 +924,7 @@ if ($action == 'edit') { print ''.$langs->trans("DoTestServerAvailability").''; } } else { - print ''.$langs->trans("DoTestServerAvailability").''; + //print ''.$langs->trans("DoTestServerAvailability").''; } print ''.$langs->trans("DoTestSend").''; @@ -1028,7 +1028,7 @@ if ($action == 'edit') { print '
'; print load_fiche_titre($action == 'testhtml' ? $langs->trans("DoTestSendHTML") : $langs->trans("DoTestSend")); - print dol_get_fiche_head(''); + print dol_get_fiche_head(array(), '', '', -1); // Cree l'objet formulaire mail include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; @@ -1073,6 +1073,7 @@ if ($action == 'edit') { print dol_get_fiche_end(); // References + print '

'; print ''.$langs->trans("EMailsWillHaveMessageID").': '; print dol_escape_htmltag(''); print ''; diff --git a/htdocs/admin/mails_senderprofile_list.php b/htdocs/admin/mails_senderprofile_list.php index 38fb81c6430..dbf47365440 100644 --- a/htdocs/admin/mails_senderprofile_list.php +++ b/htdocs/admin/mails_senderprofile_list.php @@ -670,7 +670,7 @@ if ($num == 0) { $colspan++; } } - print '
'; + print ''; } diff --git a/htdocs/admin/modules.php b/htdocs/admin/modules.php index 5dbc6625ba2..68bec8431a7 100644 --- a/htdocs/admin/modules.php +++ b/htdocs/admin/modules.php @@ -4,7 +4,7 @@ * Copyright (C) 2004-2017 Laurent Destailleur * Copyright (C) 2004 Eric Seigne * Copyright (C) 2005-2017 Regis Houssin - * Copyright (C) 2011 Juanjo Menent + * Copyright (C) 2011-2023 Juanjo Menent * Copyright (C) 2015 Jean-François Ferry * Copyright (C) 2015 Raphaël Doursenaud * Copyright (C) 2018 Nicolas ZABOURI @@ -230,7 +230,10 @@ if ($action == 'install') { // Now we install the module if (!$error) { @dol_delete_dir_recursive($dirins.'/'.$modulenameval); // delete the target directory - $submodulenamedir = $conf->admin->dir_temp.'/'.$tmpdir.'/htdocs/'.$modulenameval; + $submodulenamedir = $conf->admin->dir_temp.'/'.$tmpdir.'/'.$modulenameval; + if (!dol_is_dir($modulenamedir)) { + $submodulenamedir = $conf->admin->dir_temp.'/'.$tmpdir.'/htdocs/'.$modulenameval; + } dol_syslog("We copy now directory ".$submodulenamedir." into target dir ".$dirins.'/'.$modulenameval); $result = dolCopyDir($submodulenamedir, $dirins.'/'.$modulenameval, '0444', 1); if ($result <= 0) { diff --git a/htdocs/admin/system/browser.php b/htdocs/admin/system/browser.php index 7e2c772183d..f86b6404019 100644 --- a/htdocs/admin/system/browser.php +++ b/htdocs/admin/system/browser.php @@ -1,5 +1,5 @@ +/* Copyright (C) 2005-2023 Laurent Destailleur * Copyright (C) 2007 Rodolphe Quiedeville * Copyright (C) 2007-2012 Regis Houssin * @@ -65,7 +65,7 @@ if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { } print ''."\n"; print ''."\n"; -print ''."\n"; +print ''."\n"; print ''; print ''; + // Show progression + print ''; + print ''; + print ''; + print ''; + // Also send to main email address if ($conf->global->MAIN_FEATURES_LEVEL >= 2) { print ''; diff --git a/htdocs/admin/tools/dolibarr_export.php b/htdocs/admin/tools/dolibarr_export.php index 3ce6dbd48a4..856113eef4d 100644 --- a/htdocs/admin/tools/dolibarr_export.php +++ b/htdocs/admin/tools/dolibarr_export.php @@ -163,13 +163,13 @@ $title = $langs->trans("BackupDumpWizard"); print load_fiche_titre($title); -print '
'.img_picto('', 'technic', 'class="pictofixedwidth"').$form->textwithpicto($langs->trans("EmailcollectorOperations"), $langs->trans("EmailcollectorOperationsDesc")).'
'.$langs->trans("NoRecordFound").'
'.$langs->trans("NoRecordFound").'
'.$langs->trans("SessionName").''.session_name().'
'.$langs->trans("SessionId").''.session_id().'
'.$langs->trans("SessionId").'********
'.$langs->trans("Screen").''; print $_SESSION['dol_screenwidth'].' x '.$_SESSION['dol_screenheight']; diff --git a/htdocs/admin/system/security.php b/htdocs/admin/system/security.php index 90bb35320c0..15db7d2ba0d 100644 --- a/htdocs/admin/system/security.php +++ b/htdocs/admin/system/security.php @@ -241,14 +241,41 @@ print '
'; print '
'; $installlock = DOL_DATA_ROOT.'/install.lock'; +$upgradeunlock = DOL_DATA_ROOT.'/upgrade.unlock'; +$installmoduleslock = DOL_DATA_ROOT.'/installmodules.lock'; + +// Is install (upgrade) locked print ''.$langs->trans("DolibarrSetup").': '; if (file_exists($installlock)) { - print img_picto('', 'tick').' '.$langs->trans("InstallAndUpgradeLockedBy", $installlock); + if (file_exists($upgradeunlock)) { + print img_picto('', 'tick').' '.$langs->trans("InstallLockedBy", $installlock); + } else { + print img_picto('', 'tick').' '.$langs->trans("InstallAndUpgradeLockedBy", $installlock); + } } else { print img_warning().' '.$langs->trans("WarningLockFileDoesNotExists", DOL_DATA_ROOT); } print '
'; +// Is upgrade unlocked +if (file_exists($installlock)) { // If install not locked, no need to show this. + if (file_exists($upgradeunlock)) { + print ''.$langs->trans("DolibarrUpgrade").': '; + print img_warning().' '.$langs->trans("UpgradeHasBeenUnlocked", $upgradeunlock); + print '
'; + } +} + +// Is addon install locked ? +print ''.$langs->trans("DolibarrAddonInstall").': '; +if (file_exists($installmoduleslock)) { + print img_picto('', 'tick').' '.$langs->trans("InstallAndUpgradeLockedBy", $installmoduleslock); +} else { + print $langs->trans("InstallOfAddonIsNotBlocked", DOL_DATA_ROOT); +} +print '
'; + + // File conf.php @@ -286,7 +313,7 @@ if (empty($dolibarr_main_restrict_os_commands)) { } else { print $dolibarr_main_restrict_os_commands; } -print ' ('.$langs->trans("RecommendedValueIs", 'mysqldump, mysql, pg_dump, pgrestore').')'; +print ' ('.$langs->trans("RecommendedValueIs", 'mysqldump, mysql, pg_dump, pgrestore, clamdscan').')'; print '
'; if (empty($conf->global->SECURITY_DISABLE_TEST_ON_OBFUSCATED_CONF)) { diff --git a/htdocs/admin/ticket_public.php b/htdocs/admin/ticket_public.php index 1f32fec97aa..2bd16271650 100644 --- a/htdocs/admin/ticket_public.php +++ b/htdocs/admin/ticket_public.php @@ -379,6 +379,20 @@ if (!empty($conf->global->TICKET_ENABLE_PUBLIC_INTERFACE)) { print '
'.$langs->trans("TicketsShowProgression").''; + if (empty(getDolGlobalInt('TICKET_SHOW_PROGRESSION'))) { + print '' . img_picto($langs->trans('Disabled'), 'switch_off') . ''; + } else { + print '' . img_picto($langs->trans('Enabled'), 'switch_on') . ''; + } + print ''; + print $form->textwithpicto('', $langs->trans("TicketsShowProgressionHelp"), 1, 'help'); + print '
'.$langs->trans("TicketsEmailAlsoSendToMainAddress").'
'; -print ''; -print ''; -print ''; -print ''; + print ''; } diff --git a/htdocs/blockedlog/class/authority.class.php b/htdocs/blockedlog/class/authority.class.php index b3dd9b45f47..e274ff4175d 100644 --- a/htdocs/blockedlog/class/authority.class.php +++ b/htdocs/blockedlog/class/authority.class.php @@ -20,6 +20,11 @@ */ class BlockedLogAuthority { + /** + * DoliDB + * @var DoliDB + */ + public $db; /** * Id of the log @@ -45,6 +50,12 @@ class BlockedLogAuthority */ public $tms = 0; + /** + * Error message + * @var string + */ + public $error; + /** * Constructor * diff --git a/htdocs/bom/bom_agenda.php b/htdocs/bom/bom_agenda.php index d22f457df85..ddd57d34e76 100644 --- a/htdocs/bom/bom_agenda.php +++ b/htdocs/bom/bom_agenda.php @@ -92,7 +92,7 @@ if ($id > 0 || !empty($ref)) { //if ($user->socid > 0) accessforbidden(); //if ($user->socid > 0) $socid = $user->socid; $isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); -restrictedArea($user, 'bom', $object->id, 'bom_bom', '', '', 'rowid', $isdraft); +restrictedArea($user, 'bom', $object->id, $object->table_element, '', '', 'rowid', $isdraft); /* diff --git a/htdocs/bom/bom_card.php b/htdocs/bom/bom_card.php index 33e562a8a20..e27cd0a2e1c 100644 --- a/htdocs/bom/bom_card.php +++ b/htdocs/bom/bom_card.php @@ -84,7 +84,7 @@ if ($object->id > 0) { //if ($user->socid > 0) accessforbidden(); //if ($user->socid > 0) $socid = $user->socid; $isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); -$result = restrictedArea($user, 'bom', $object->id, 'bom_bom', '', '', 'rowid', $isdraft); +$result = restrictedArea($user, 'bom', $object->id, $object->table_element, '', '', 'rowid', $isdraft); // Permissions $permissionnote = $user->hasRight('bom', 'write'); // Used by the include of actions_setnotes.inc.php diff --git a/htdocs/bom/bom_document.php b/htdocs/bom/bom_document.php index 03b9f416d43..88fbdde11c7 100644 --- a/htdocs/bom/bom_document.php +++ b/htdocs/bom/bom_document.php @@ -83,7 +83,7 @@ if ($id > 0 || !empty($ref)) { //if ($user->socid > 0) accessforbidden(); //if ($user->socid > 0) $socid = $user->socid; $isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); -restrictedArea($user, 'bom', $object->id, 'bom_bom', '', '', 'rowid', $isdraft); +restrictedArea($user, 'bom', $object->id, $object->table_element, '', '', 'rowid', $isdraft); $permissiontoadd = $user->hasRight('bom', 'write'); // Used by the include of actions_addupdatedelete.inc.php and actions_linkedfiles.inc.php diff --git a/htdocs/bom/bom_list.php b/htdocs/bom/bom_list.php index a12bd7fdb2d..065a3a578b7 100644 --- a/htdocs/bom/bom_list.php +++ b/htdocs/bom/bom_list.php @@ -728,8 +728,8 @@ while ($i < $imaxinloop) { } if (!empty($arrayfields['t.'.$key]['checked'])) { - print '$key)) { print ' title="'.dol_escape_htmltag($object->$key).'"'; } print '>'; diff --git a/htdocs/bom/bom_net_needs.php b/htdocs/bom/bom_net_needs.php index 56683e82338..f0e993d6eea 100644 --- a/htdocs/bom/bom_net_needs.php +++ b/htdocs/bom/bom_net_needs.php @@ -81,7 +81,7 @@ if ($object->id > 0) { //if ($user->socid > 0) accessforbidden(); //if ($user->socid > 0) $socid = $user->socid; $isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); -$result = restrictedArea($user, 'bom', $object->id, 'bom_bom', '', '', 'rowid', $isdraft); +$result = restrictedArea($user, 'bom', $object->id, $object->table_element, '', '', 'rowid', $isdraft); // Permissions $permissionnote = $user->hasRight('bom', 'write'); // Used by the include of actions_setnotes.inc.php diff --git a/htdocs/bom/bom_note.php b/htdocs/bom/bom_note.php index 10c64a1b104..188c34c8c05 100644 --- a/htdocs/bom/bom_note.php +++ b/htdocs/bom/bom_note.php @@ -67,7 +67,7 @@ $permissionnote = $user->hasRight('bom', 'write'); // Used by the include of act //if ($user->socid > 0) accessforbidden(); //if ($user->socid > 0) $socid = $user->socid; $isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); -restrictedArea($user, 'bom', $object->id, 'bom_bom', '', '', 'rowid', $isdraft); +restrictedArea($user, 'bom', $object->id, $object->table_element, '', '', 'rowid', $isdraft); /* diff --git a/htdocs/bom/class/bom.class.php b/htdocs/bom/class/bom.class.php index c00b9781756..45cbfdef383 100644 --- a/htdocs/bom/class/bom.class.php +++ b/htdocs/bom/class/bom.class.php @@ -1131,13 +1131,12 @@ class BOM extends CommonObject $dataparams = ''; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { $classfortooltip = 'classforajaxtooltip'; - $dataparams = ' data-params='.json_encode($params); - // $label = $langs->trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); - - $url = DOL_URL_ROOT.'/bom/bom_card.php?id='.$this->id; if ($option != 'nolink') { @@ -1157,7 +1156,7 @@ class BOM extends CommonObject $label = $langs->trans("ShowBillOfMaterials"); $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; } - $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"'); $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"'; } else { $linkclose = ($morecss ? ' class="'.$morecss.'"' : ''); diff --git a/htdocs/bom/tpl/objectline_create.tpl.php b/htdocs/bom/tpl/objectline_create.tpl.php index e87d526302b..0d49937e6d2 100644 --- a/htdocs/bom/tpl/objectline_create.tpl.php +++ b/htdocs/bom/tpl/objectline_create.tpl.php @@ -114,17 +114,18 @@ if (isModEnabled("product") || isModEnabled("service")) { $statustoshow = -1; if (!empty($conf->global->ENTREPOT_EXTRA_STATUS)) { // hide products in closed warehouse, but show products for internal transfer - $form->select_produits(GETPOST('idprod', 'int'), (($filtertype == 1) ? 'idprodservice' : 'idprod'), $filtertype, $conf->product->limit_size, $buyer->price_level, $statustoshow, 2, '', 1, array(), $buyer->id, '1', 0, 'maxwidth500', 0, 'warehouseopen,warehouseinternal', GETPOST('combinations', 'array')); + print $form->select_produits(GETPOST('idprod', 'int'), (($filtertype == 1) ? 'idprodservice' : 'idprod'), $filtertype, $conf->product->limit_size, $buyer->price_level, $statustoshow, 2, '', 1, array(), $buyer->id, '1', 0, 'maxwidth500', 0, 'warehouseopen,warehouseinternal', GETPOST('combinations', 'array'), 1); } else { - $form->select_produits(GETPOST('idprod', 'int'), (($filtertype == 1) ? 'idprodservice' : 'idprod'), $filtertype, $conf->product->limit_size, $buyer->price_level, $statustoshow, 2, '', 1, array(), $buyer->id, '1', 0, 'maxwidth500', 0, '', GETPOST('combinations', 'array')); + print $form->select_produits(GETPOST('idprod', 'int'), (($filtertype == 1) ? 'idprodservice' : 'idprod'), $filtertype, $conf->product->limit_size, $buyer->price_level, $statustoshow, 2, '', 1, array(), $buyer->id, '1', 0, 'maxwidth500', 0, '', GETPOST('combinations', 'array'), 1); } + $urltocreateproduct = DOL_URL_ROOT.'/product/card.php?action=create&backtopage='.urlencode($_SERVER["PHP_SELF"].'?id='.$object->id); + print ''; echo ''; } if (!empty($conf->global->BOM_SUB_BOM) && $filtertype!=1) { print '
'.$langs->trans("or").'
'.$langs->trans("BOM"); - // TODO Add component to select a BOM - $form->select_bom(); + print $form->select_bom('', 'bom_id', 0, 1, 0, '1', '', 1); } if (is_object($objectline)) { diff --git a/htdocs/bookcal/availabilities_list.php b/htdocs/bookcal/availabilities_list.php index 208190aaad5..fd5866eaff8 100644 --- a/htdocs/bookcal/availabilities_list.php +++ b/htdocs/bookcal/availabilities_list.php @@ -682,8 +682,8 @@ while ($i < $imaxinloop) { //if (in_array($key, array('fk_soc', 'fk_user', 'fk_warehouse'))) $cssforfield = 'tdoverflowmax100'; if (!empty($arrayfields['t.'.$key]['checked'])) { - print '$key)) { print ' title="'.dol_escape_htmltag($object->$key).'"'; } print '>'; diff --git a/htdocs/bookcal/booking_list.php b/htdocs/bookcal/booking_list.php index 033c8ec121f..e030a52b7e3 100644 --- a/htdocs/bookcal/booking_list.php +++ b/htdocs/bookcal/booking_list.php @@ -682,8 +682,8 @@ while ($i < $imaxinloop) { //if (in_array($key, array('fk_soc', 'fk_user', 'fk_warehouse'))) $cssforfield = 'tdoverflowmax100'; if (!empty($arrayfields['t.'.$key]['checked'])) { - print '$key)) { print ' title="'.dol_escape_htmltag($object->$key).'"'; } print '>'; diff --git a/htdocs/categories/class/categorie.class.php b/htdocs/categories/class/categorie.class.php index 6762770d564..fc0246e1a02 100644 --- a/htdocs/categories/class/categorie.class.php +++ b/htdocs/categories/class/categorie.class.php @@ -1624,6 +1624,8 @@ class Categorie extends CommonObject { global $langs; + $langs->load('categories'); + $datas = []; $datas['label'] = $langs->trans("ShowCategory").': '.($this->ref ? $this->ref : $this->label); @@ -1655,10 +1657,11 @@ class Categorie extends CommonObject $dataparams = ''; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { $classfortooltip = 'classforajaxtooltip'; - $dataparams = ' data-params='.json_encode($params); - // $label = $langs->trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); // Check contrast with background and correct text color $forced_color = 'categtextwhite'; @@ -1668,7 +1671,9 @@ class Categorie extends CommonObject } } $link = ''; + $link .= '"'.$dataparams; + $link .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"'); + $link .= ' class="'.$classfortooltip.' '.$forced_color.'">'; $linkend = ''; $picto = 'category'; diff --git a/htdocs/comm/action/card.php b/htdocs/comm/action/card.php index 4dc5221cea3..942d4d2e75e 100644 --- a/htdocs/comm/action/card.php +++ b/htdocs/comm/action/card.php @@ -32,7 +32,6 @@ // Load Dolibarr environment require '../../main.inc.php'; - require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php'; @@ -102,8 +101,8 @@ if (GETPOST('datep')) { // Security check $socid = GETPOST('socid', 'int'); $id = GETPOST('id', 'int'); -if ($user->socid) { - $socid = $user->socid; +if ($user->socid && ($socid != $user->socid)) { + accessforbidden(); } $error = GETPOST("error"); @@ -154,7 +153,7 @@ if (!empty($conf->global->AGENDA_REMINDER_EMAIL)) { $TDurationTypes = array('y'=>$langs->trans('Years'), 'm'=>$langs->trans('Month'), 'w'=>$langs->trans('Weeks'), 'd'=>$langs->trans('Days'), 'h'=>$langs->trans('Hours'), 'i'=>$langs->trans('Minutes')); -$result = restrictedArea($user, 'agenda', $object->id, 'actioncomm&societe', 'myactions|allactions', 'fk_soc', 'id'); +$result = restrictedArea($user, 'agenda', $object, 'actioncomm&societe', 'myactions|allactions', 'fk_soc', 'id'); $usercancreate = $user->hasRight('agenda', 'allactions', 'create') || (($object->authorid == $user->id || $object->userownerid == $user->id) && $user->rights->agenda->myactions->create); diff --git a/htdocs/comm/action/class/actioncomm.class.php b/htdocs/comm/action/class/actioncomm.class.php index 48c51840e83..5822e6dd9d2 100644 --- a/htdocs/comm/action/class/actioncomm.class.php +++ b/htdocs/comm/action/class/actioncomm.class.php @@ -1319,15 +1319,17 @@ class ActionComm extends CommonObject */ public function getActions($socid = 0, $fk_element = 0, $elementtype = '', $filter = '', $sortfield = 'a.datep', $sortorder = 'DESC', $limit = 0) { - global $conf, $langs; + global $conf, $langs, $hookmanager; $resarray = array(); dol_syslog(get_class()."::getActions", LOG_DEBUG); - require_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php'; - $hookmanager = new HookManager($this->db); // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context + if (!is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($db); + } $hookmanager->initHooks(array('agendadao')); $sql = "SELECT a.id"; @@ -1744,8 +1746,8 @@ class ActionComm extends CommonObject 'nofetch' => 1, ]; $classfortooltip = 'classforajaxtooltip'; - $dataparams = ' data-params='.json_encode($params); - // $label = $langs->trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $tooltip = ''; } //if (!empty($conf->global->AGENDA_USE_EVENT_TYPE) && $this->type_color) // $linkclose = ' style="background-color:#'.$this->type_color.'"'; @@ -1755,7 +1757,7 @@ class ActionComm extends CommonObject $label = $langs->trans("ShowAction"); $linkclose .= ' alt="'.dol_escape_htmltag($tooltip, 1).'"'; } - $linkclose .= ' title="'.dol_escape_htmltag($tooltip, 1, 0, '', 1).'"'; + $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"'); $linkclose .= $dataparams.' class="'.$classname.' '.$classfortooltip.'"'; } else { $linkclose .= ' class="'.$classname.'"'; diff --git a/htdocs/comm/action/index.php b/htdocs/comm/action/index.php index 91f749a1cd0..ed96199e4c3 100644 --- a/htdocs/comm/action/index.php +++ b/htdocs/comm/action/index.php @@ -927,6 +927,7 @@ if ($resql) { } //var_dump($eventarray); + // BIRTHDATES CALENDAR // Complete $eventarray with birthdates if ($showbirthday) { @@ -972,6 +973,8 @@ if ($showbirthday) { $event->percentage = 100; $event->fulldayevent = 1; + $event->contact_id = $obj->rowid; + $event->date_start_in_calendar = $db->jdate($event->datep); $event->date_end_in_calendar = $db->jdate($event->datef); @@ -1000,7 +1003,7 @@ if ($showbirthday) { } } -// LEAVE CALENDAR +// LEAVE-HOLIDAY CALENDAR $sql = "SELECT u.rowid as uid, u.lastname, u.firstname, u.statut, x.rowid, x.date_debut as date_start, x.date_fin as date_end, x.halfday, x.statut as status"; $sql .= " FROM ".MAIN_DB_PREFIX."holiday as x, ".MAIN_DB_PREFIX."user as u"; $sql .= " WHERE u.rowid = x.fk_user"; @@ -1012,12 +1015,12 @@ if ($mode == 'show_day') { $sql .= " AND '".$db->escape($year)."-".$db->escape($month)."-".$db->escape($day)."' BETWEEN x.date_debut AND x.date_fin"; // date_debut and date_fin are date without time } elseif ($mode == 'show_week') { // Restrict on current month (we get more, but we will filter later) - $sql .= " AND date_debut < '".dol_get_last_day($year, $month)."'"; - $sql .= " AND date_fin >= '".dol_get_first_day($year, $month)."'"; + $sql .= " AND date_debut < '".$db->idate(dol_get_last_day($year, $month))."'"; + $sql .= " AND date_fin >= '".$db->idate(dol_get_first_day($year, $month))."'"; } elseif ($mode == 'show_month') { // Restrict on current month - $sql .= " AND date_debut <= '".dol_get_last_day($year, $month)."'"; - $sql .= " AND date_fin >= '".dol_get_first_day($year, $month)."'"; + $sql .= " AND date_debut <= '".$db->idate(dol_get_last_day($year, $month))."'"; + $sql .= " AND date_fin >= '".$db->idate(dol_get_first_day($year, $month))."'"; } $resql = $db->query($sql); @@ -1800,7 +1803,10 @@ function show_day_events($db, $day, $month, $year, $monthshown, $style, &$eventa $color = ($event->icalcolor ? $event->icalcolor : -1); $cssclass = (!empty($event->icalname) ? 'family_ext'.md5($event->icalname) : 'family_other'); } elseif ($event->type_code == 'BIRTHDAY') { - $numbirthday++; $colorindex = 2; $cssclass = 'family_birthday '; $color = sprintf("%02x%02x%02x", $theme_datacolor[$colorindex][0], $theme_datacolor[$colorindex][1], $theme_datacolor[$colorindex][2]); + $numbirthday++; + $colorindex = 2; + $cssclass = 'family_birthday '; + $color = sprintf("%02x%02x%02x", $theme_datacolor[$colorindex][0], $theme_datacolor[$colorindex][1], $theme_datacolor[$colorindex][2]); } else { $numother++; $color = ($event->icalcolor ? $event->icalcolor : -1); @@ -1930,9 +1936,31 @@ function show_day_events($db, $day, $month, $year, $monthshown, $style, &$eventa $daterange = ''; - if ($event->type_code == 'BIRTHDAY') { // It's birthday calendar - print $event->getNomUrl(1, $maxnbofchar, 'cal_event', 'birthday', 'contact'); - } elseif ($event->type_code == 'HOLIDAY') { // It's holiday calendar + if ($event->type_code == 'BIRTHDAY') { + // It's birthday calendar + $picb = ''; + //$pice = ''; + //$typea = ($objp->typea == 'birth') ? $picb : $pice; + //var_dump($event); + print $picb.' '.$langs->trans("Birthday").'
'; + //print img_picto($langs->trans("Birthday"), 'birthday-cake').' '; + + $tmpid = $event->id; + if (empty($cachecontacts[$tmpid])) { + $newcontact = new Contact($db); + $newcontact->fetch($tmpid); + $cachecontact[$tmpid] = $newcontact; + } + print $cachecontact[$tmpid]->getNomUrl(1); + + //$event->picto = 'birthday-cake'; + //print $event->getNomUrl(1, $maxnbofchar, 'cal_event', 'birthday', 'contact'); + /*$listofcontacttoshow = ''; + $listofcontacttoshow .= '
'.$cacheusers[$tmpid]->getNomUrl(-1, '', 0, 0, 0, 0, '', 'paddingright valignmiddle'); + print $listofcontacttoshow; + */ + } elseif ($event->type_code == 'HOLIDAY') { + // It's holiday calendar $tmpholiday->fetch($event->id); print $tmpholiday->getNomUrl(1); @@ -1947,8 +1975,8 @@ function show_day_events($db, $day, $month, $year, $monthshown, $style, &$eventa $listofusertoshow = ''; $listofusertoshow .= '
'.$cacheusers[$tmpid]->getNomUrl(-1, '', 0, 0, 0, 0, '', 'paddingright valignmiddle'); print $listofusertoshow; - } else { // Other calendar - // Picto + } else { + // Other calendar if (empty($event->fulldayevent)) { //print $event->getNomUrl(2).' '; } diff --git a/htdocs/comm/action/info.php b/htdocs/comm/action/info.php index aa14224014a..ee34d07ea4b 100644 --- a/htdocs/comm/action/info.php +++ b/htdocs/comm/action/info.php @@ -1,6 +1,6 @@ - * Copyright (C) 2004-2010 Laurent Destailleur + * Copyright (C) 2004-2023 Laurent Destailleur * * 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 @@ -98,8 +98,6 @@ if (empty($reshook)) { $linkback .= $out; $morehtmlref = '
'; -// Thirdparty -//$morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . $object->thirdparty->getNomUrl(1); // Project if (isModEnabled('project')) { $langs->load("projects"); diff --git a/htdocs/comm/mailing/class/mailing.class.php b/htdocs/comm/mailing/class/mailing.class.php index 75bfce98496..ef83c5d1470 100644 --- a/htdocs/comm/mailing/class/mailing.class.php +++ b/htdocs/comm/mailing/class/mailing.class.php @@ -792,10 +792,11 @@ class Mailing extends CommonObject $dataparams = ''; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { $classfortooltip = 'classforajaxtooltip'; - $dataparams = ' data-params='.json_encode($params); - // $label = $langs->trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); $url = DOL_URL_ROOT.'/comm/mailing/card.php?id='.$this->id; @@ -816,8 +817,8 @@ class Mailing extends CommonObject $label = $langs->trans("ShowEMailing"); $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; } - $linkclose .= $dataparams.' title="'.dol_escape_htmltag($label, 1).'"'; - $linkclose .= ' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"'; + $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"'); + $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"'; } else { $linkclose = ($morecss ? ' class="'.$morecss.'"' : ''); } diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index 5c4c4aae9f1..abf68f1d30e 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -221,7 +221,7 @@ if (empty($reshook)) { } } - $result = $object->createFromClone($user, $socid, (GETPOSTISSET('entity') ? GETPOST('entity', 'int') : null), (GETPOST('update_prices', 'aZ') ? true : false)); + $result = $object->createFromClone($user, $socid, (GETPOSTISSET('entity') ? GETPOST('entity', 'int') : null), (GETPOST('update_prices', 'aZ') ? true : false), (GETPOST('update_desc', 'aZ') ? true : false)); if ($result > 0) { header("Location: ".$_SERVER['PHP_SELF'].'?id='.$result); exit(); @@ -1599,7 +1599,7 @@ if (empty($reshook)) { $error++; } if (!$error) { - $result = $object->updateExtraField(GETPOST('attribute', 'restricthtml'), 'PROPAL_MODIFY', $user); + $result = $object->insertExtraFields('PROPAL_MODIFY'); if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); $error++; @@ -2137,7 +2137,8 @@ if ($action == 'create') { // 'text' => $langs->trans("ConfirmClone"), // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1), array('type' => 'other', 'name' => 'socid', 'label' => $langs->trans("SelectThirdParty"), 'value' => $form->select_company(GETPOST('socid', 'int'), 'socid', '(s.client=1 OR s.client=2 OR s.client=3)', '', 0, 0, null, 0, 'maxwidth300')), - array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans('PuttingPricesUpToDate'), 'value' => (!empty($conf->global->PROPOSAL_CLONE_UPDATE_PRICES) ? 1 : 0)), + array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans('PuttingPricesUpToDate'), 'value' => 0), + array('type' => 'checkbox', 'name' => 'update_desc', 'label' => $langs->trans('PuttingDescUpToDate'), 'value' => 0), ); if (!empty($conf->global->PROPAL_CLONE_DATE_DELIVERY) && !empty($object->delivery_date)) { $formquestion[] = array('type' => 'date', 'name' => 'date_delivery', 'label' => $langs->trans("DeliveryDate"), 'value' => $object->delivery_date); diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index 40e8fe385d7..3a247a11ec2 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -1360,9 +1360,10 @@ class Propal extends CommonObject * @param int $socid Id of thirdparty * @param int $forceentity Entity id to force * @param bool $update_prices [=false] Update prices if true + * @param bool $update_desc [=false] Update description if true * @return int New id of clone */ - public function createFromClone(User $user, $socid = 0, $forceentity = null, $update_prices = false) + public function createFromClone(User $user, $socid = 0, $forceentity = null, $update_prices = false, $update_desc = false) { global $conf, $hookmanager, $mysoc; @@ -1413,9 +1414,9 @@ class Propal extends CommonObject } // update prices - if ($update_prices === true) { + if ($update_prices === true || $update_desc === true) { if ($objsoc->id > 0 && !empty($object->lines)) { - if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) { + if ($update_prices === true && !empty($conf->global->PRODUIT_CUSTOMER_PRICES)) { // If price per customer require_once DOL_DOCUMENT_ROOT . '/product/class/productcustomerprice.class.php'; } @@ -1425,36 +1426,41 @@ class Propal extends CommonObject $prod = new Product($this->db); $res = $prod->fetch($line->fk_product); if ($res > 0) { - $pu_ht = $prod->price; - $tva_tx = get_default_tva($mysoc, $objsoc, $prod->id); - $remise_percent = $objsoc->remise_percent; + if ($update_prices === true) { + $pu_ht = $prod->price; + $tva_tx = get_default_tva($mysoc, $objsoc, $prod->id); + $remise_percent = $objsoc->remise_percent; - if (!empty($conf->global->PRODUIT_MULTIPRICES) && $objsoc->price_level > 0) { - $pu_ht = $prod->multiprices[$objsoc->price_level]; - if (!empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) { // using this option is a bug. kept for backward compatibility - if (isset($prod->multiprices_tva_tx[$objsoc->price_level])) { - $tva_tx = $prod->multiprices_tva_tx[$objsoc->price_level]; + if (!empty($conf->global->PRODUIT_MULTIPRICES) && $objsoc->price_level > 0) { + $pu_ht = $prod->multiprices[$objsoc->price_level]; + if (!empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) { // using this option is a bug. kept for backward compatibility + if (isset($prod->multiprices_tva_tx[$objsoc->price_level])) { + $tva_tx = $prod->multiprices_tva_tx[$objsoc->price_level]; + } } - } - } elseif (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) { - $prodcustprice = new Productcustomerprice($this->db); - $filter = array('t.fk_product' => $prod->id, 't.fk_soc' => $objsoc->id); - $result = $prodcustprice->fetchAll('', '', 0, 0, $filter); - if ($result) { - // If there is some prices specific to the customer - if (count($prodcustprice->lines) > 0) { - $pu_ht = price($prodcustprice->lines[0]->price); - $tva_tx = ($prodcustprice->lines[0]->default_vat_code ? $prodcustprice->lines[0]->tva_tx.' ('.$prodcustprice->lines[0]->default_vat_code.' )' : $prodcustprice->lines[0]->tva_tx); - if ($prodcustprice->lines[0]->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) { - $tva_tx .= ' ('.$prodcustprice->lines[0]->default_vat_code.')'; + } elseif (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) { + $prodcustprice = new Productcustomerprice($this->db); + $filter = array('t.fk_product' => $prod->id, 't.fk_soc' => $objsoc->id); + $result = $prodcustprice->fetchAll('', '', 0, 0, $filter); + if ($result) { + // If there is some prices specific to the customer + if (count($prodcustprice->lines) > 0) { + $pu_ht = price($prodcustprice->lines[0]->price); + $tva_tx = ($prodcustprice->lines[0]->default_vat_code ? $prodcustprice->lines[0]->tva_tx.' ('.$prodcustprice->lines[0]->default_vat_code.' )' : $prodcustprice->lines[0]->tva_tx); + if ($prodcustprice->lines[0]->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) { + $tva_tx .= ' ('.$prodcustprice->lines[0]->default_vat_code.')'; + } } } } - } - $line->subprice = $pu_ht; - $line->tva_tx = $tva_tx; - $line->remise_percent = $remise_percent; + $line->subprice = $pu_ht; + $line->tva_tx = $tva_tx; + $line->remise_percent = $remise_percent; + } + if ($update_desc === true) { + $line->desc = $prod->description; + } } } } @@ -3790,10 +3796,11 @@ class Propal extends CommonObject $dataparams = ''; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { $classfortooltip = 'classforajaxtooltip'; - $dataparams = ' data-params='.json_encode($params); - // $label = $langs->trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); $url = ''; if ($user->rights->propal->lire) { @@ -3825,7 +3832,7 @@ class Propal extends CommonObject $label = $langs->trans("Proposal"); $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; } - $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"'); $linkclose .= $dataparams.' class="'.$classfortooltip.'"'; } diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index 2b11588b854..f707714d772 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -3834,19 +3834,19 @@ class Commande extends CommonOrder $dataparams = ''; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { $classfortooltip = 'classforajaxtooltip'; - $dataparams = ' data-params='.json_encode($params); - // $label = $langs->trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); - $linkclose = ''; if (empty($notooltip) && $user->hasRight('commande', 'lire')) { if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { $label = $langs->trans("Order"); $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; } - $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"'); $linkclose .= $dataparams.' class="'.$classfortooltip.'"'; $target_value = array('_self', '_blank', '_parent', '_top'); diff --git a/htdocs/commande/list.php b/htdocs/commande/list.php index c665166b0af..27b9a05181b 100644 --- a/htdocs/commande/list.php +++ b/htdocs/commande/list.php @@ -893,19 +893,19 @@ if ($search_status <> '') { if ($search_status == 1 && empty($conf->expedition->enabled)) { $sql .= ' AND c.fk_statut IN (1,2)'; // If module expedition disabled, we include order with status 'sending in process' into 'validated' } else { - $sql .= ' AND c.fk_statut = '.((int) $search_status); // brouillon, validee, en cours, annulee + $sql .= ' AND c.fk_statut = '.((int) $search_status); // draft, validated, in process or canceled } } - if ($search_status == -2) { // To process + if ($search_status == -2) { // "validated + in process" //$sql.= ' AND c.fk_statut IN (1,2,3) AND c.facture = 0'; - $sql .= " AND ((c.fk_statut IN (1,2)) OR (c.fk_statut = 3 AND c.facture = 0))"; // If status is 2 and facture=1, it must be selected + $sql .= " AND (c.fk_statut IN (1,2))"; } - if ($search_status == -3) { // To bill + if ($search_status == -3) { // "validated + in process + delivered" //$sql.= ' AND c.fk_statut in (1,2,3)'; //$sql.= ' AND c.facture = 0'; // invoice not created - $sql .= ' AND ((c.fk_statut IN (1,2)) OR (c.fk_statut = 3 AND c.facture = 0))'; // validated, in process or closed but not billed + $sql .= ' AND (c.fk_statut IN (1,2,3))'; // validated, in process or closed } - if ($search_status == -4) { // "validate and in progress" + if ($search_status == -4) { // "validate + in progress" $sql .= ' AND (c.fk_statut IN (1,2))'; // validated, in process } } diff --git a/htdocs/compta/bank/class/account.class.php b/htdocs/compta/bank/class/account.class.php index 35b9dba1e54..f9a665640cd 100644 --- a/htdocs/compta/bank/class/account.class.php +++ b/htdocs/compta/bank/class/account.class.php @@ -1409,13 +1409,15 @@ class Account extends CommonObject /** * getTooltipContentArray - * @param array $params params to construct tooltip data - * @since v18 - * @return array + * + * @param array $params Params to construct tooltip data + * @since v18 + * @return array */ public function getTooltipContentArray($params) { global $langs; + $langs->loadLangs(['banks', 'compta']); include_once DOL_DOCUMENT_ROOT.'/core/lib/bank.lib.php'; $datas = array(); @@ -1461,6 +1463,7 @@ class Account extends CommonObject public function getNomUrl($withpicto = 0, $mode = '', $option = '', $save_lastsearch_value = -1, $notooltip = 0) { global $conf, $langs, $user; + include_once DOL_DOCUMENT_ROOT.'/core/lib/bank.lib.php'; $result = ''; @@ -1474,11 +1477,15 @@ class Account extends CommonObject ]; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { $classfortooltip = 'classforajaxtooltip'; - $dataparams = ' data-params='.json_encode($params); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); - $linkclose = '"'.$dataparams.' title="'.dol_escape_htmltag($label, 1).'" class="'.$classfortooltip.'">'; + $linkclose = ''; + $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"'); + $linkclose .= $dataparams.' class="'.$classfortooltip.'">'; $url = DOL_URL_ROOT.'/compta/bank/card.php?id='.$this->id; if ($mode == 'transactions') { @@ -1498,7 +1505,7 @@ class Account extends CommonObject } } - $linkstart = 'fetch('', $valuetoshow, 1); + }*/ + + return length_accountg($account); + } + + /** + * Return Auxiliary accounting account of thirdparties with defined length + * + * @param string $account Auxiliary accounting account + * @return string String with defined length + */ + public function lengthAccounta($account) + { + include_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php'; + + return length_accounta($account); + } } diff --git a/htdocs/compta/bank/transfer.php b/htdocs/compta/bank/transfer.php index 5f33afbae7f..724e09554db 100644 --- a/htdocs/compta/bank/transfer.php +++ b/htdocs/compta/bank/transfer.php @@ -346,7 +346,7 @@ for ($i = 1 ; $i < $MAXLINES; $i++) { print '
'; print ''; -}; +} print '
'; -print $langs->trans("DatabaseName").' : '.$dolibarr_main_db_name.'
'; -print '
'; +//print ''; +//print ''; +//print ''; +//print ''; +//print ''; +//print '
'; +print ''.$langs->trans("DatabaseName").' : '.$dolibarr_main_db_name.'

'; +//print '
'; print ''; @@ -589,8 +589,8 @@ if (!empty($_SESSION["commandbackuptorun"])) { print "\n"; -print ''; -print '
'; +//print '
'; print " \n"; @@ -598,7 +598,7 @@ print " \n"; print '
'; $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"), '', 0, -1, '', '', 'ASC', 1, 0, -1, 'style="height:480px; overflow: auto;"'); +$result = $formfile->list_of_documents($filearray, null, 'systemtools', '', 1, 'backup/', 1, 0, $langs->trans("NoBackupFileAvailable"), 0, $langs->trans("PreviousDumpFiles"), '', 0, -1, '', '', 'ASC', 1, 0, -1, 'style="height:250px; overflow: auto;"'); print '
'; print '
'; @@ -652,12 +652,12 @@ foreach ($filecompression as $key => $val) { if ($key == 'gz') { $checked = ' checked'; } - print ''; - print ' '; + print ''; + print ' '; } else // Disabled export format { - print ''; - print ' '; + print ''; + print ' '; print ' ('.$langs->trans("NotAvailable").')'; } print '     '; @@ -686,6 +686,8 @@ print ''; print ''; print ''; +print '
'; + // End of page llxFooter(); $db->close(); diff --git a/htdocs/asset/class/asset.class.php b/htdocs/asset/class/asset.class.php index 8e69cb19a1a..e2d93806ca3 100644 --- a/htdocs/asset/class/asset.class.php +++ b/htdocs/asset/class/asset.class.php @@ -162,20 +162,6 @@ class Asset extends CommonObject */ public $oldcopy; - // /** - // * @var string Field with ID of parent key if this object has a parent - // */ - // public $fk_element = 'fk_asset'; - // /** - // * @var array List of child tables. To test if we can delete object. - // */ - // protected $childtables = array(); - // /** - // * @var array List of child tables. To know object to delete on cascade. - // * If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will - // * call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object - // */ - // protected $childtablesoncascade = array('asset_assetdet'); /** * @var AssetDepreciationOptions Used for computed fields of depreciation options class. diff --git a/htdocs/asset/list.php b/htdocs/asset/list.php index d98165d28a2..4b3b530148d 100644 --- a/htdocs/asset/list.php +++ b/htdocs/asset/list.php @@ -639,7 +639,7 @@ if ($num == 0) { $colspan++; } } - print '
'.$langs->trans("NoRecordFound").'
'.$langs->trans("NoRecordFound").'
'; print '
'; diff --git a/htdocs/compta/bank/various_payment/card.php b/htdocs/compta/bank/various_payment/card.php index 1eb552fd711..7fbf2774e85 100644 --- a/htdocs/compta/bank/various_payment/card.php +++ b/htdocs/compta/bank/various_payment/card.php @@ -1,6 +1,7 @@ * Copyright (C) 2018-2020 Frédéric France + * Copyright (C) 2023 Laurent Destailleur * * 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 @@ -71,6 +72,8 @@ $object = new PaymentVarious($db); // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context $hookmanager->initHooks(array('variouscard', 'globalcard')); +$permissiontoadd = $user->hasRight('banque', 'modifier'); + /** * Actions @@ -83,14 +86,8 @@ if ($reshook < 0) { } if (empty($reshook)) { - // Link to a project - if ($action == 'classin' && $user->rights->banque->modifier) { - $object->fetch($id); - $object->setProject(GETPOST('projectid')); - } - if ($cancel) { - if ($action != 'addlink') { + if ($action != 'addlink' && $action != 'setaccountancy_code' && $action != 'setsubledger_account') { $urltogo = $backtopage ? $backtopage : dol_buildpath('/compta/bank/various_payment/list.php', 1); header("Location: ".$urltogo); exit; @@ -101,6 +98,12 @@ if (empty($reshook)) { $action = ''; } + // Link to a project + if ($action == 'classin' && $permissiontoadd) { + $object->fetch($id); + $object->setProject(GETPOST('projectid', 'int')); + } + if ($action == 'add') { $error = 0; @@ -214,6 +217,22 @@ if (empty($reshook)) { } } + if ($action == 'setaccountancy_code') { + $db->begin(); + + $result = $object->fetch($id); + + $object->accountancy_code = GETPOST('accountancy_code', 'alpha'); + + $res = $object->update($user); + if ($res > 0) { + $db->commit(); + } else { + $db->rollback(); + setEventMessages($object->error, $object->errors, 'errors'); + } + } + if ($action == 'setsubledger_account') { $db->begin(); @@ -236,7 +255,7 @@ if ($action == 'confirm_clone' && $confirm != 'yes') { $action = ''; } -if ($action == 'confirm_clone' && $confirm == 'yes' && ($user->rights->banque->modifier)) { +if ($action == 'confirm_clone' && $confirm == 'yes' && $permissiontoadd) { $db->begin(); $originalId = $id; @@ -560,32 +579,25 @@ if ($id) { // Project if (isModEnabled('project')) { $langs->load("projects"); - $morehtmlref .= $langs->trans('Project').' '; - if ($user->rights->banque->modifier) { + //$morehtmlref .= '
'; + if ($permissiontoadd) { + $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"'); 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(0, $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, '', 'maxwidth300'); + $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($object->fk_project)) { $proj = new Project($db); $proj->fetch($object->fk_project); $morehtmlref .= $proj->getNomUrl(1); - } else { - $morehtmlref .= ''; + if ($proj->title) { + $morehtmlref .= ' - '.dol_escape_htmltag($proj->title).''; + } } } } + $morehtmlref .= '
'; $linkback = ''.$langs->trans("BackToList").''; @@ -622,25 +634,24 @@ if ($id) { print ''.$langs->trans("Amount").''.price($object->amount, 0, $langs, 1, -1, -1, $conf->currency).''; - // Accountancy code - print ''; - print $langs->trans("AccountAccounting"); - print ''; + // Account of Chart of account + $editvalue = ''; if (isModEnabled('accounting')) { - $accountingaccount = new AccountingAccount($db); - $accountingaccount->fetch('', $object->accountancy_code, 1); - - print $accountingaccount->getNomUrl(0, 1, 1, '', 1); - } else { - print $object->accountancy_code; + $editvalue = $formaccounting->select_account($object->accountancy_code, 'accountancy_code', 1, null, 1, 1); } + + print ''; + print ''; + print $form->editfieldkey('AccountAccounting', 'accountancy_code', $object->accountancy_code, $object, (!$alreadyaccounted && $permissiontoadd), 'string', '', 0); + print ''; + print $form->editfieldval('AccountAccounting', 'accountancy_code', $object->accountancy_code, $object, (!$alreadyaccounted && $permissiontoadd), 'asis', $editvalue, 0, null, '', 1, 'lengthAccountg'); print ''; // Subledger account print ''; - print $form->editfieldkey('SubledgerAccount', 'subledger_account', $object->subledger_account, $object, (!$alreadyaccounted && $user->rights->banque->modifier), 'string', '', 0); + print $form->editfieldkey('SubledgerAccount', 'subledger_account', $object->subledger_account, $object, (!$alreadyaccounted && $permissiontoadd), 'string', '', 0); print ''; - print $form->editfieldval('SubledgerAccount', 'subledger_account', $object->subledger_account, $object, (!$alreadyaccounted && $user->rights->banque->modifier), 'string', '', 0); + print $form->editfieldval('SubledgerAccount', 'subledger_account', $object->subledger_account, $object, (!$alreadyaccounted && $permissiontoadd), 'string', '', 0, null, '', 1, 'lengthAccounta'); print ''; $bankaccountnotfound = 0; @@ -689,13 +700,13 @@ if ($id) { // Add button modify // Clone - if ($user->rights->banque->modifier) { + if ($permissiontoadd) { print '"; } // Delete if (empty($object->rappro) || $bankaccountnotfound) { - if (!empty($user->rights->banque->modifier)) { + if ($permissiontoadd) { if ($alreadyaccounted) { print ''; } else { diff --git a/htdocs/compta/bank/various_payment/document.php b/htdocs/compta/bank/various_payment/document.php index 43259727917..58e4d3680b9 100644 --- a/htdocs/compta/bank/various_payment/document.php +++ b/htdocs/compta/bank/various_payment/document.php @@ -100,7 +100,6 @@ if ($object->id) { // Project if (isModEnabled('project')) { $langs->load("projects"); - $morehtmlref .= $langs->trans('Project').' : '; if ($user->rights->banque->modifier && 0) { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' : '; diff --git a/htdocs/compta/bank/various_payment/info.php b/htdocs/compta/bank/various_payment/info.php index ca31915d2f4..06f243a9847 100644 --- a/htdocs/compta/bank/various_payment/info.php +++ b/htdocs/compta/bank/various_payment/info.php @@ -60,7 +60,6 @@ $morehtmlref = '
'; // Project if (isModEnabled('project')) { $langs->load("projects"); - $morehtmlref .= $langs->trans('Project').' : '; if ($user->rights->banque->modifier && 0) { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' : '; diff --git a/htdocs/compta/cashcontrol/cashcontrol_list.php b/htdocs/compta/cashcontrol/cashcontrol_list.php index a050cf7ffec..1333a6b2346 100644 --- a/htdocs/compta/cashcontrol/cashcontrol_list.php +++ b/htdocs/compta/cashcontrol/cashcontrol_list.php @@ -622,8 +622,8 @@ while ($i < ($limit ? min($num, $limit) : $num)) { //if (in_array($key, array('fk_soc', 'fk_user', 'fk_warehouse'))) $cssforfield = 'tdoverflowmax100'; if (!empty($arrayfields['t.'.$key]['checked'])) { - print '$key)) { print ' title="'.dol_escape_htmltag($object->$key).'"'; } print '>'; diff --git a/htdocs/compta/facture/agenda.php b/htdocs/compta/facture/agenda.php index a7930660378..a452a8dd6aa 100644 --- a/htdocs/compta/facture/agenda.php +++ b/htdocs/compta/facture/agenda.php @@ -29,7 +29,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; // Load translation files required by the page -$langs->loadLangs(array("facture", "other")); +$langs->loadLangs(array("bills", "other")); // Get parameters $id = GETPOST('id', 'int'); diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index a4e7bd52430..5d69bb2b6dd 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -574,6 +574,7 @@ class Facture extends CommonInvoice $this->type = self::TYPE_STANDARD; } $this->ref_client = trim($this->ref_client); + $this->ref_customer = trim($this->ref_customer); $this->note_public = trim($this->note_public); $this->note_private = trim($this->note_private); $this->note_private = dol_concatdesc($this->note_private, $langs->trans("GeneratedFromRecurringInvoice", $_facrec->ref)); @@ -591,8 +592,6 @@ class Facture extends CommonInvoice // We do not add link to template invoice or next invoice will be linked to all generated invoices //$this->linked_objects['facturerec'][0] = $this->fac_rec; - $forceduedate = $this->calculate_date_lim_reglement(); - // For recurring invoices, update date and number of last generation of recurring template invoice, before inserting new invoice if ($_facrec->frequency > 0) { dol_syslog("This is a recurring invoice so we set date_last_gen and next date_when"); @@ -1897,10 +1896,11 @@ class Facture extends CommonInvoice $dataparams = ''; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { $classfortooltip = 'classforajaxtooltip'; - $dataparams = ' data-params='.json_encode($params); - // $label = $langs->trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); $linkclose = ($target ? ' target="'.$target.'"' : ''); if (empty($notooltip) && $user->hasRight("facture", "read")) { @@ -1908,8 +1908,8 @@ class Facture extends CommonInvoice $label = $langs->trans("Invoice"); $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; } - $linkclose .= $dataparams.' title="'.dol_escape_htmltag($label, 1).'"'; - $linkclose .= ' class="'.$classfortooltip.'"'; + $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"'); + $linkclose .= $dataparams.' class="'.$classfortooltip.'"'; } $linkstart = 'contact_id = 0; $actioncomm->code = 'AC_EMAIL'; - $actioncomm->label = 'sendEmailsRemindersOnInvoiceDueDateOK'; + $actioncomm->label = 'sendEmailsRemindersOnInvoiceDueDateOK (nbdays='.$nbdays.' paymentmode='.$paymentmode.' template='.$template.' forcerecipient='.$forcerecipient.')'; $actioncomm->note_private = $sendContent; $actioncomm->fk_project = $tmpinvoice->fk_project; $actioncomm->datep = dol_now(); @@ -5666,6 +5666,7 @@ class Facture extends CommonInvoice $actioncomm->userownerid = $user->id; // Owner of action // Fields when action is an email (content should be added into note) $actioncomm->email_msgid = $cMailFile->msgid; + $actioncomm->email_subject = $sendTopic; $actioncomm->email_from = $from; $actioncomm->email_sender = ''; $actioncomm->email_to = $to; diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php index 83b609f91f7..928ffcfc4bd 100644 --- a/htdocs/compta/facture/list.php +++ b/htdocs/compta/facture/list.php @@ -1952,7 +1952,7 @@ if ($resql) { // Action column if (!empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) { - print ''; + print ''; if (($massactionbutton || $massaction) && $contextpage != 'poslist') { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined $selected = 0; if (in_array($obj->id, $arrayofselected)) { @@ -2430,7 +2430,7 @@ if ($resql) { } } if (!empty($arrayfields['multicurrency_dynamount_payed']['checked'])) { - print ''.(!empty($multicurrency_totalpay) ?price($multicurrency_totalpay, 0, $langs) : ' ').''; // TODO Use a denormalized field + print ''.(!empty($multicurrency_totalpay) ? price($multicurrency_totalpay, 0, $langs) : ' ').''; // TODO Use a denormalized field if (!$i) { $totalarray['nbfield']++; } @@ -2440,7 +2440,7 @@ if ($resql) { if (!empty($arrayfields['multicurrency_rtp']['checked'])) { print ''; print (!empty($multicurrency_remaintopay) ? price($multicurrency_remaintopay, 0, $langs) : ' '); - print ''; // TODO Use a denormalized field + print ''; // TODO Use a denormalized field ? if (!$i) { $totalarray['nbfield']++; } @@ -2448,14 +2448,14 @@ if ($resql) { // Total buying or cost price if (!empty($arrayfields['total_pa']['checked'])) { - print ''.price($marginInfo['pa_total']).''; + print ''.price($marginInfo['pa_total'], 0, $langs, 1, -1, 'MT').''; if (!$i) { $totalarray['nbfield']++; } } // Total margin if (!empty($arrayfields['total_margin']['checked'])) { - print ''.price($marginInfo['total_margin']).''; + print ''.price($marginInfo['total_margin'], 0, $langs, 1, -1, 'MT').''; if (!$i) { $totalarray['nbfield']++; } @@ -2570,7 +2570,7 @@ if ($resql) { // Action column (Show the massaction button only when this page is not opend from the Extended POS) if (empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) { - print ''; + print ''; if (($massactionbutton || $massaction) && $contextpage != 'poslist') { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined $selected = 0; if (in_array($obj->id, $arrayofselected)) { diff --git a/htdocs/compta/facture/prelevement.php b/htdocs/compta/facture/prelevement.php index 5f027960ee8..948bb42337a 100644 --- a/htdocs/compta/facture/prelevement.php +++ b/htdocs/compta/facture/prelevement.php @@ -693,6 +693,16 @@ if ($object->id > 0) { $resteapayer = price2num($object->total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits, 'MT'); + // Hook to change amount for other reasons, e.g. apply cash discount for payment before agreed date + $parameters = array('remaintopay' => $resteapayer); + $reshook = $hookmanager->executeHooks('finalizeAmountOfSupplierInvoice', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook > 0) { + print $hookmanager->resPrint; + if (!empty($remaintopay = $hookmanager->resArray['remaintopay'])) { + $resteapayer = $remaintopay; + } + } + // TODO Replace this by an include with same code to show already done payment visible in invoice card print ''.$langs->trans('RemainderToPay').''.price($resteapayer, 1, '', 1, - 1, - 1, $conf->currency).''; diff --git a/htdocs/compta/paiement/card.php b/htdocs/compta/paiement/card.php index 39dac0352e6..4fb3cfa41aa 100644 --- a/htdocs/compta/paiement/card.php +++ b/htdocs/compta/paiement/card.php @@ -36,6 +36,9 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php'; if (isModEnabled("banque")) { require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php'; } +if (!empty($conf->margin->enabled)) { + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formmargin.class.php'; +} // Load translation files required by the page $langs->loadLangs(array('bills', 'banks', 'companies')); @@ -432,6 +435,10 @@ if ($resql) { if (isModEnabled('multicompany') && !empty($conf->global->MULTICOMPANY_INVOICE_SHARING_ENABLED)) { print ''.$langs->trans('Entity').''; } + //Add Margin + if (!empty($conf->margin->enabled) && getDolGlobalInt('MARGIN_SHOW_MARGIN_ON_PAYMENT')) { + print ''.$langs->trans('Margin').''; + } print ''.$langs->trans('ExpectedToPay').''; print ''.$langs->trans('PayedByThisPayment').''; print ''.$langs->trans('RemainderToPay').''; @@ -447,6 +454,14 @@ if ($resql) { $invoice = new Facture($db); $invoice->fetch($objp->facid); + // Add Margin + if (!empty($conf->margin->enabled) && getDolGlobalInt('MARGIN_SHOW_MARGIN_ON_PAYMENT')) { + $formmargin = new FormMargin($db); + $marginInfo = array(); + $invoice->fetch_lines(); + $marginInfo = $formmargin->getMarginInfosArray($invoice); + } + $paiement = $invoice->getSommePaiement(); $creditnotes = $invoice->getSumCreditNotesUsed(); $deposits = $invoice->getSumDepositsUsed(); @@ -472,6 +487,12 @@ if ($resql) { print $mc->label; print ''; } + + // Add margin + if (!empty($conf->margin->enabled) && getDolGlobalInt('MARGIN_SHOW_MARGIN_ON_PAYMENT')) { + print ''.price($marginInfo['total_margin']).''; + } + // Expected to pay print ''.price($objp->total_ttc).''; diff --git a/htdocs/compta/paiement/class/paiement.class.php b/htdocs/compta/paiement/class/paiement.class.php index e16834e5707..f573ec5be56 100644 --- a/htdocs/compta/paiement/class/paiement.class.php +++ b/htdocs/compta/paiement/class/paiement.class.php @@ -11,6 +11,7 @@ * Copyright (C) 2018-2022 Frédéric France * Copyright (C) 2020 Andreu Bisquerra Gaya * Copyright (C) 2021 OpenDsi + * Copyright (C) 2023 Joachim Kueter * * 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 @@ -382,7 +383,19 @@ class Paiement extends CommonObject if (!in_array($invoice->type, $affected_types)) { dol_syslog("Invoice ".$facid." is not a standard, nor replacement invoice, nor credit note, nor deposit invoice, nor situation invoice. We do nothing more."); } elseif ($remaintopay) { - dol_syslog("Remain to pay for invoice ".$facid." not null. We do nothing more."); + // hook to have an option to automatically close a closable invoice with less payment than the total amount (e.g. agreed cash discount terms) + global $hookmanager; + $hookmanager->initHooks(array('paymentdao')); + $parameters = array('facid' => $facid, 'invoice' => $invoice, 'remaintopay' => $remaintopay); + $action = 'CLOSEPAIDINVOICE'; + $reshook = $hookmanager->executeHooks('createPayment', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook < 0) { + $this->errors[] = $hookmanager->error; + $this->error = $hookmanager->error; + $error++; + } elseif ($reshook == 0) { + dol_syslog("Remain to pay for invoice " . $facid . " not null. We do nothing more."); + } // } else if ($mustwait) dol_syslog("There is ".$mustwait." differed payment to process, we do nothing more."); } else { // If invoice is a down payment, we also convert down payment to discount diff --git a/htdocs/compta/prelevement/line.php b/htdocs/compta/prelevement/line.php index b668880e9d3..7809e894af8 100644 --- a/htdocs/compta/prelevement/line.php +++ b/htdocs/compta/prelevement/line.php @@ -119,7 +119,13 @@ if ($action == 'confirm_rejet') { * View */ -$invoicestatic = new Facture($db); +if ($type == 'bank-transfer') { + require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php'; + $invoicestatic = new FactureFournisseur($db); +} else { + require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; + $invoicestatic = new Facture($db); +} $title = $langs->trans("WithdrawalsLine"); if ($type == 'bank-transfer') { @@ -318,7 +324,11 @@ if ($id) { print ''.$obj->ref."\n"; } - print ''; + if ($type == 'bank-transfer') { + print ''; + } else { + print ''; + } print img_object($langs->trans("ShowCompany"), "company").' '.$obj->name."\n"; print ''.price($obj->total_ttc)."\n"; diff --git a/htdocs/contact/card.php b/htdocs/contact/card.php index 7197eabb19c..cbdce0c5d04 100644 --- a/htdocs/contact/card.php +++ b/htdocs/contact/card.php @@ -680,6 +680,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { print 'lastname).'" autofocus="autofocus">'; print ''; + // Firstname print ''; print ''; diff --git a/htdocs/contact/class/contact.class.php b/htdocs/contact/class/contact.class.php index 379cda22d43..eddba0b5ad3 100644 --- a/htdocs/contact/class/contact.class.php +++ b/htdocs/contact/class/contact.class.php @@ -1495,10 +1495,11 @@ class Contact extends CommonObject $dataparams = ''; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { $classfortooltip = 'classforajaxtooltip'; - $dataparams = ' data-params='.json_encode($params); - // $label = $langs->trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); $url = DOL_URL_ROOT.'/contact/card.php?id='.$this->id; @@ -1521,7 +1522,7 @@ class Contact extends CommonObject $label = $langs->trans("ShowContact"); $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; } - $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"'); $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"'; } diff --git a/htdocs/contact/consumption.php b/htdocs/contact/consumption.php index 93acb2ab463..8efae5a836d 100644 --- a/htdocs/contact/consumption.php +++ b/htdocs/contact/consumption.php @@ -377,7 +377,7 @@ if ($sql_select) { $num = $db->num_rows($resql); - $param = "&socid=".urlencode($socid)."&type_element=".urlencode($type_element); + $param = "&socid=".urlencode($socid)."&type_element=".urlencode($type_element)."&id=".urlencode($id); if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { $param .= '&contextpage='.urlencode($contextpage); } diff --git a/htdocs/contact/perso.php b/htdocs/contact/perso.php index 0fd23753fdf..ba5fde87468 100644 --- a/htdocs/contact/perso.php +++ b/htdocs/contact/perso.php @@ -27,6 +27,7 @@ // Load Dolibarr environment require '../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/contact.lib.php'; // Load translation files required by the page @@ -42,6 +43,9 @@ if ($user->socid) { $result = restrictedArea($user, 'contact', $id, 'socpeople&societe'); $object = new Contact($db); +$errors = array(); + + /* * Action */ @@ -123,6 +127,7 @@ $help_url = 'EN:Module_Third_Parties|FR:Module_Tiers|ES:Empresas'; llxHeader('', $title, $help_url); $form = new Form($db); +$formcompany = new FormCompany($db); $object->fetch($id, $user); @@ -143,38 +148,13 @@ if ($action == 'edit') { print ''; // Ref - print ''; - // Photo - print ''; - // Name - print ''; - print ''; + print ''; + print ''; // Company if (empty($conf->global->SOCIETE_DISABLE_CONTACTS)) { @@ -182,31 +162,62 @@ if ($action == 'edit') { $objsoc = new Societe($db); $objsoc->fetch($object->socid); - print ''; + print ''; } else { - print ''; } } // Civility - print ''; + // Photo + print ''; + print ''; + print ''; + print ''; + // Date To Birth print ''; - - print ''; + print ''; } else { - print ''; + print ''; } + print ''; print ''; print "
'.$langs->trans("Ref").''; + print '
'.$langs->trans("Ref").''; print $object->id; print ''; - print $form->showphoto('contact', $object)."\n"; - if ($object->photo) { - print "
\n"; - } - - print ''; - - if ($object->photo) { - print ''; - } - print ''; - print ''; - print '
'.$langs->trans("Delete").'

'.$langs->trans("PhotoFile").'
'; - $maxfilesizearray = getMaxFileSizeArray(); - $maxmin = $maxfilesizearray['maxmin']; - if ($maxmin > 0) { - print ''; // MAX_FILE_SIZE must precede the field type=file - } - print ''; - print '
'; - - print '
'.$langs->trans("Lastname").' / '.$langs->trans("Label").''.$object->lastname.'
'.$langs->trans("Firstname").''.$object->firstname.'
'.$langs->trans("Lastname").' / '.$langs->trans("Label").''.$object->lastname.'
'.$langs->trans("Firstname").''.$object->firstname.'
'.$langs->trans("ThirdParty").''.$objsoc->getNomUrl(1).'
'.$langs->trans("ThirdParty").''.$objsoc->getNomUrl(1).'
'.$langs->trans("ThirdParty").''; + print '
'.$langs->trans("ThirdParty").''; print $langs->trans("ContactNotLinkedToCompany"); print '
'.$langs->trans("UserTitle").''; + print '
'; print $object->getCivilityLabel(); + //print $formcompany->select_civility(GETPOSTISSET("civility_code") ? GETPOST("civility_code", 'alpha') : $object->civility_code, 'civility_code'); print '
'.$form->editfieldkey('PhotoFile', 'photoinput', '', $object, 0).''; + if ($object->photo) { + print $form->showphoto('contact', $object); + } + $caneditfield = 1; + if ($caneditfield) { + if ($object->photo) { + print "
\n"; + } + print ''; + if ($object->photo) { + print ''; + } + //print ''; + print ''; + print '
'.$langs->trans("PhotoFile").'
'; + $maxfilesizearray = getMaxFileSizeArray(); + $maxmin = $maxfilesizearray['maxmin']; + if ($maxmin > 0) { + print ''; // MAX_FILE_SIZE must precede the field type=file + } + print ''; + print '
'; + } + print '
'.$langs->trans("DateOfBirth").''; $form = new Form($db); print $form->selectDate($object->birthday, 'birthday', 0, 0, 1, "perso", 1, 0); - print ''.$langs->trans("Alert").': '; + print '     '; + print ' '; if (!empty($object->birthday_alert)) { - print '
"; diff --git a/htdocs/contrat/class/contrat.class.php b/htdocs/contrat/class/contrat.class.php index 8e6c2ea0161..e05aeb678ee 100644 --- a/htdocs/contrat/class/contrat.class.php +++ b/htdocs/contrat/class/contrat.class.php @@ -2075,19 +2075,19 @@ class Contrat extends CommonObject $dataparams = ''; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { $classfortooltip = 'classforajaxtooltip'; - $dataparams = ' data-params='.json_encode($params); - // $label = $langs->trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); - $linkclose = ''; if (empty($notooltip) && $user->hasRight('contrat', 'lire')) { if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { $label = $langs->trans("ShowContract"); $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; } - $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"'); $linkclose .= $dataparams.' class="'.$classfortooltip.'"'; } $linkstart = ' $this->element, ]; $classfortooltip = 'classforajaxtooltip'; - $dataparams = ' data-params='.json_encode($params); - // $label = $langs->trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; } - $link = ''; + + $link = ''; $linkend = ''; $picto = 'service'; diff --git a/htdocs/core/ajax/ajaxcompanies.php b/htdocs/core/ajax/ajaxcompanies.php index ef0d7303715..086d20e7967 100644 --- a/htdocs/core/ajax/ajaxcompanies.php +++ b/htdocs/core/ajax/ajaxcompanies.php @@ -31,6 +31,14 @@ if (!defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Load Dolibarr environment require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php'; + +$object = new Societe($db); + +$usesublevelpermission = ''; + +// Security check +restrictedArea($user, $object->module, $object, $object->table_element, $usesublevelpermission); /* @@ -54,9 +62,9 @@ if (GETPOST('newcompany') || GETPOST('socid', 'int') || GETPOST('id_fourn')) { $return_arr = array(); // Define filter on text typed - $socid = $_GET['newcompany'] ? $_GET['newcompany'] : ''; - if (!$socid) $socid = $_GET['socid'] ? $_GET['socid'] : ''; - if (!$socid) $socid = $_GET['id_fourn'] ? $_GET['id_fourn'] : ''; + $socid = GETPOST('newcompany'); + if (!$socid) $socid = GETPOST('socid'); + if (!$socid) $socid = GETPOST('id_fourn'); $sql = "SELECT s.rowid, s.nom, s.name_alias, s.code_client, s.code_fournisseur, s.address, s.zip, s.town, s.email, s.siren, s.siret, s.ape, s.idprof4, s.client, s.fournisseur, s.datec, s.logo"; $sql .= " , c.label as country, d.nom as departement"; @@ -68,17 +76,22 @@ if (GETPOST('newcompany') || GETPOST('socid', 'int') || GETPOST('id_fourn')) { $sql .= " AND ("; // Add criteria on name/code if (!empty($conf->global->COMPANY_DONOTSEARCH_ANYWHERE)) { // Can use index - $sql .= "s.nom LIKE '".$db->escape($socid)."%'"; - $sql .= " OR s.code_client LIKE '".$db->escape($socid)."%'"; - $sql .= " OR s.code_fournisseur LIKE '".$db->escape($socid)."%'"; + $sql .= "s.nom LIKE '".$db->escape($db->escapeforlike($socid))."%'"; + $sql .= " OR s.code_client LIKE '".$db->escape($db->escapeforlike($socid))."%'"; + $sql .= " OR s.code_fournisseur LIKE '".$db->escape($db->escapeforlike($socid))."%'"; } else { - $sql .= "s.nom LIKE '%".$db->escape($socid)."%'"; - $sql .= " OR s.code_client LIKE '%".$db->escape($socid)."%'"; - $sql .= " OR s.code_fournisseur LIKE '%".$db->escape($socid)."%'"; + $sql .= "s.nom LIKE '%".$db->escape($db->escapeforlike($socid))."%'"; + $sql .= " OR s.code_client LIKE '%".$db->escape($db->escapeforlike($socid))."%'"; + $sql .= " OR s.code_fournisseur LIKE '%".$db->escape($db->escapeforlike($socid))."%'"; + } + if (!empty($conf->global->SOCIETE_ALLOW_SEARCH_ON_ROWID)) { + $sql .= " OR s.rowid = ".((int) $socid); } - if (!empty($conf->global->SOCIETE_ALLOW_SEARCH_ON_ROWID)) $sql .= " OR s.rowid = '".$db->escape($socid)."'"; $sql .= ")"; } + if ($user->socid > 0) { + $sql .= " AND s.rowid = ".((int) $user->socid); + } //if (GETPOST("filter")) $sql.= " AND (".GETPOST("filter", "alpha").")"; // Add other filters $sql .= " ORDER BY s.nom ASC"; diff --git a/htdocs/core/ajax/ajaxdirpreview.php b/htdocs/core/ajax/ajaxdirpreview.php index 2f763c4e576..b5f772212b9 100644 --- a/htdocs/core/ajax/ajaxdirpreview.php +++ b/htdocs/core/ajax/ajaxdirpreview.php @@ -117,14 +117,14 @@ if (empty($url)) { // autoset $url but it is better to have it defined before in // Load translation files required by the page $langs->loadLangs(array("ecm", "companies", "other")); +if (empty($modulepart)) { + $modulepart = $module; +} + // Security check if ($user->socid > 0) { $socid = $user->socid; } - -//print 'xxx'.$upload_dir; - -// Security: // On interdit les remontees de repertoire ainsi que les pipe dans les noms de fichiers. if (preg_match('/\.\./', $upload_dir) || preg_match('/[<>|]/', $upload_dir)) { dol_syslog("Refused to deliver file ".$upload_dir); @@ -132,11 +132,6 @@ if (preg_match('/\.\./', $upload_dir) || preg_match('/[<>|]/', $upload_dir)) { dol_print_error(0, $langs->trans("ErrorFileNameInvalid", $upload_dir)); exit; } - -if (empty($modulepart)) { - $modulepart = $module; -} - // Check permissions if ($modulepart == 'ecm') { if (!$user->hasRight('ecm', 'read')) { diff --git a/htdocs/core/ajax/ajaxdirtree.php b/htdocs/core/ajax/ajaxdirtree.php index 61fdabb70c3..5c281eff5ca 100644 --- a/htdocs/core/ajax/ajaxdirtree.php +++ b/htdocs/core/ajax/ajaxdirtree.php @@ -103,7 +103,7 @@ if (empty($modulepart)) { $modulepart = $module; } -// Check permissions +// Security check if ($modulepart == 'ecm') { if (!$user->hasRight('ecm', 'read')) { accessforbidden(); diff --git a/htdocs/core/ajax/ajaxinvoiceline.php b/htdocs/core/ajax/ajaxinvoiceline.php index 432ad15b151..f575bf326ac 100644 --- a/htdocs/core/ajax/ajaxinvoiceline.php +++ b/htdocs/core/ajax/ajaxinvoiceline.php @@ -39,7 +39,6 @@ $action = GETPOST('action', 'aZ09'); $htmlname = GETPOST('htmlname', 'alpha'); - // Security check restrictedArea($user, 'facture', $invoice_id, '', '', 'fk_soc', 'rowid'); diff --git a/htdocs/core/ajax/ajaxtooltip.php b/htdocs/core/ajax/ajaxtooltip.php index 8652908eced..33cdfb4831f 100644 --- a/htdocs/core/ajax/ajaxtooltip.php +++ b/htdocs/core/ajax/ajaxtooltip.php @@ -1,5 +1,5 @@ +/* Copyright (C) 2007-2023 Laurent Destailleur * Copyright (C) 2018-2023 Frédéric France * * This program is free software; you can redistribute it and/or modify @@ -22,7 +22,6 @@ * \brief This script returns content of tooltip */ - if (!defined('NOTOKENRENEWAL')) { define('NOTOKENRENEWAL', 1); // Disables token renewal } @@ -36,17 +35,13 @@ if (!defined('NOREQUIREAJAX')) { define('NOREQUIREAJAX', '1'); } include '../../main.inc.php'; -include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; include_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php'; -top_httphead(); -// opensurvey as aZ09 id + $id = GETPOST('id', 'aZ09'); -$objecttype = GETPOST('objecttype', 'aZ09'); +$objecttype = GETPOST('objecttype', 'aZ09arobase'); // 'module' or 'myobject@mymodule', 'mymodule_myobject' -$html = ''; -$regs = array(); $params = array(); if (GETPOSTISSET('infologin')) { $params['infologin'] = GETPOST('infologin', 'int'); @@ -54,182 +49,42 @@ if (GETPOSTISSET('infologin')) { if (GETPOSTISSET('option')) { $params['option'] = GETPOST('option', 'restricthtml'); } -// If we ask a resource form external module (instead of default path) -if (preg_match('/^([^@]+)@([^@]+)$/i', $objecttype, $regs)) { - $myobject = $regs[1]; - $module = $regs[2]; -} else { - // Parse $objecttype (ex: project_task) - $module = $myobject = $objecttype; - if (preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) { - $module = $regs[1]; - $myobject = $regs[2]; - } -} - -// Generic case for $classpath -$classpath = $module.'/class'; - -// Special cases, to work with non standard path -if ($objecttype == 'facture' || $objecttype == 'invoice') { - $langs->load('bills'); - $classpath = 'compta/facture/class'; - $module = 'facture'; - $myobject = 'facture'; -} elseif ($objecttype == 'bank_account') { - $langs->loadLangs(['banks', 'compta']); - $classpath = 'compta/bank/class'; - $module = 'banque'; - $myobject = 'account'; -} elseif ($objecttype == 'category') { - $langs->loadLangs(['categories']); - $classpath = 'categories/class'; - $module = 'categorie'; - $myobject = 'categorie'; -} elseif ($objecttype == 'commande' || $objecttype == 'order') { - $langs->load('orders'); - $classpath = 'commande/class'; - $module = 'commande'; - $myobject = 'commande'; -} elseif ($objecttype == 'propal') { - $langs->load('propal'); - $classpath = 'comm/propal/class'; -} elseif ($objecttype == 'action') { - $langs->load('agenda'); - $classpath = 'comm/action/class'; - $module = 'agenda'; - $myobject = 'actioncomm'; -} elseif ($objecttype == 'supplier_proposal') { - $langs->load('supplier_proposal'); - $classpath = 'supplier_proposal/class'; -} elseif ($objecttype == 'shipping') { - $langs->load('sendings'); - $classpath = 'expedition/class'; - $myobject = 'expedition'; - $module = 'expedition_bon'; -} elseif ($objecttype == 'delivery') { - $langs->load('deliveries'); - $classpath = 'delivery/class'; - $myobject = 'delivery'; - $module = 'delivery_note'; -} elseif ($objecttype == 'contract') { - $langs->load('contracts'); - $classpath = 'contrat/class'; - $module = 'contrat'; - $myobject = 'contrat'; -} elseif ($objecttype == 'member') { - $classpath = 'adherents/class'; - $module = 'adherent'; - $myobject = 'adherent'; -} elseif ($objecttype == 'fichinter') { - $langs->load('interventions'); - $classpath = 'fichinter/class'; - $module = 'ficheinter'; - $myobject = 'fichinter'; -} elseif ($objecttype == 'project') { - $langs->load('projects'); - $classpath = 'projet/class'; - $module = 'projet'; -} elseif ($objecttype == 'project_task') { - $classpath = 'projet/class'; - $module = 'projet'; - $myobject = 'task'; -} elseif ($objecttype == 'stock') { - $classpath = 'product/stock/class'; - $module = 'stock'; - $myobject = 'stock'; -} elseif ($objecttype == 'inventory') { - $classpath = 'product/inventory/class'; - $module = 'stock'; - $myobject = 'inventory'; -} elseif ($objecttype == 'mo') { - $classpath = 'mrp/class'; - $module = 'mrp'; - $myobject = 'mo'; -} elseif ($objecttype == 'productlot') { - $classpath = 'product/stock/class'; - $module = 'stock'; - $myobject = 'productlot'; -} elseif ($objecttype == 'usergroup') { - $classpath = 'user/class'; - $module = 'user'; - $myobject = 'usergroup'; -} elseif ($objecttype == 'dolresource') { - $classpath = 'resource/class'; - $module = 'resource'; - $myobject = 'dolresource'; -} elseif ($objecttype == 'opensurvey_sondage') { - $classpath = 'opensurvey/class'; - $module = 'opensurvey'; - $myobject = 'opensurveysondage'; -} elseif ($objecttype == 'knowledgerecord') { - $classpath = 'knowledgemanagement/class'; - $module = 'knowledgemanagement'; - $myobject = 'knowledgerecord'; -} - -// Generic case for $classfile and $classname -$classfile = strtolower($myobject); -$classname = ucfirst($myobject); - -if ($objecttype == 'invoice_supplier') { - $classfile = 'fournisseur.facture'; - $classname = 'FactureFournisseur'; - $classpath = 'fourn/class'; - $module = 'fournisseur'; -} elseif ($objecttype == 'order_supplier') { - $classfile = 'fournisseur.commande'; - $classname = 'CommandeFournisseur'; - $classpath = 'fourn/class'; - $module = 'fournisseur'; -} elseif ($objecttype == 'supplier_proposal') { - $classfile = 'supplier_proposal'; - $classname = 'SupplierProposal'; - $classpath = 'supplier_proposal/class'; - $module = 'supplier_proposal'; -} elseif ($objecttype == 'stock') { - $classpath = 'product/stock/class'; - $classfile = 'entrepot'; - $classname = 'Entrepot'; -} elseif ($objecttype == 'facturerec') { - $classpath = 'compta/facture/class'; - $classfile = 'facture-rec'; - $classname = 'FactureRec'; - $module = 'facture'; -} elseif ($objecttype == 'mailing') { - $classpath = 'comm/mailing/class'; - $classfile = 'mailing'; - $classname = 'Mailing'; -} elseif ($objecttype == 'adherent_type') { - $classpath = 'adherents/class'; - $classfile = 'adherent_type'; - $module = 'adherent'; - $myobject = 'adherent_type'; - $classname = 'AdherentType'; -} elseif ($objecttype == 'contact') { - $module = 'societe'; -} elseif ($objecttype == 'salary') { - $classpath = 'salaries/class'; - $module = 'salaries'; -} -// print "objecttype=".$objecttype." module=".$module." subelement=".$subelement." classfile=".$classfile." classname=".$classname." classpath=".$classpath."
"; - -if (isModEnabled($module)) { - $res = dol_include_once('/'.$classpath.'/'.$classfile.'.class.php'); - if ($res) { - if (class_exists($classname)) { - $object = new $classname($db); - $res = $object->fetch($id); - if ($res > 0) { - $html = $object->getTooltipContent($params); - } elseif ($res == 0) { - $html = $langs->trans('Deleted'); - } - unset($object); - } else { - dol_syslog("Class with classname ".$classname." is unknown even after the include", LOG_ERR); - } + +// Load object according to $element +$object = fetchObjectByElement($id, $objecttype); +if (empty($object->element)) { + httponly_accessforbidden('Failed to get object with fetchObjectByElement(id='.$id.', objectype='.$objecttype.')'); +} + +$module = $object->module; +$element = $object->element; + +$usesublevelpermission = ($module != $element ? $element : ''); +if ($usesublevelpermission && !isset($user->rights->$module->$element)) { // There is no permission on object defined, we will check permission on module directly + $usesublevelpermission = ''; +} + +//print $object->id.' - '.$object->module.' - '.$object->element.' - '.$object->table_element.' - '.$usesublevelpermission."\n"; + +// Security check +restrictedArea($user, $object->module, $object, $object->table_element, $usesublevelpermission); + + +/* + * View + */ + +top_httphead(); + +$html = ''; + +if (is_object($object)) { + if ($object->id > 0 || !empty($object->ref)) { + $html = $object->getTooltipContent($params); + } elseif ($res == 0) { + $html = $langs->trans('Deleted'); } + unset($object); } print $html; diff --git a/htdocs/core/ajax/bankconciliate.php b/htdocs/core/ajax/bankconciliate.php index 5407c30545d..c340dd47a06 100644 --- a/htdocs/core/ajax/bankconciliate.php +++ b/htdocs/core/ajax/bankconciliate.php @@ -44,6 +44,9 @@ require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php'; $action = GETPOST('action', 'aZ09'); +// Security check +// Checks are done later + /* * View diff --git a/htdocs/core/ajax/box.php b/htdocs/core/ajax/box.php index a6a93c69f68..621d6878098 100644 --- a/htdocs/core/ajax/box.php +++ b/htdocs/core/ajax/box.php @@ -18,7 +18,7 @@ /** * \file htdocs/core/ajax/box.php - * \brief File to return Ajax response on Box move or close + * \brief File to return Ajax response on a Box move or close */ if (!defined('NOTOKENRENEWAL')) { @@ -46,16 +46,16 @@ $boxorder = GETPOST('boxorder'); $zone = GETPOST('zone', 'int'); $userid = GETPOST('userid', 'int'); +// Security check +if ($userid != $user->id) { + httponly_accessforbidden('Bad userid parameter. Must match logged user.'); +} + /* * View */ -// Ajout directives pour resoudre bug IE -//header('Cache-Control: Public, must-revalidate'); -//header('Pragma: public'); - -//top_htmlhead("", "", 1); // Replaced with top_httphead. An ajax page does not need html header. top_httphead(); print ''."\n"; diff --git a/htdocs/core/ajax/check_notifications.php b/htdocs/core/ajax/check_notifications.php index 344a2b19229..18c1a1ece79 100644 --- a/htdocs/core/ajax/check_notifications.php +++ b/htdocs/core/ajax/check_notifications.php @@ -44,6 +44,9 @@ $time = dol_now(); $action = GETPOST('action', 'aZ09'); $listofreminderids = GETPOST('listofreminderids', 'aZ09'); +// Security check +// No permission check at top, but action later are all done with a test on $user->id. + /* * Actions @@ -68,6 +71,7 @@ if ($action == 'stopreminder') { // Clean database $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'actioncomm_reminder'; $sql .= " WHERE dateremind < '".$db->idate(dol_time_plus_duree(dol_now(), -1, 'm'))."'"; + $sql .= " AND fk_user = ".((int) $user->id).' AND entity = '.((int) $conf->entity); $resql = $db->query($sql); if (!$resql) { dol_print_error($db); @@ -124,18 +128,10 @@ if (empty($_SESSION['auto_check_events_not_before']) || $time >= $_SESSION['auto $sql = 'SELECT a.id as id_agenda, a.code, a.datep, a.label, a.location, ar.rowid as id_reminder, ar.dateremind, ar.fk_user as id_user_reminder'; $sql .= ' FROM '.MAIN_DB_PREFIX.'actioncomm as a'; - if (!empty($user->conf->MAIN_USER_WANT_ALL_EVENTS_NOTIFICATIONS)) { - $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'actioncomm_reminder as ar ON a.id = ar.fk_actioncomm AND ar.fk_user = '.((int) $user->id); - $sql .= ' WHERE a.code <> "AC_OTH_AUTO"'; - $sql .= ' AND ('; - $sql .= " ar.typeremind = 'browser' AND ar.dateremind < '".$db->idate(dol_now())."' AND ar.status = 0 AND ar.entity = ".$conf->entity; - $sql .= ' )'; - } else { - $sql .= ' JOIN '.MAIN_DB_PREFIX.'actioncomm_reminder as ar ON a.id = ar.fk_actioncomm AND ar.fk_user = '.((int) $user->id); - $sql .= " AND ar.typeremind = 'browser' AND ar.dateremind < '".$db->idate(dol_now())."' AND ar.status = 0 AND ar.entity = ".$conf->entity; - } + $sql .= ' INNER JOIN '.MAIN_DB_PREFIX.'actioncomm_reminder as ar ON a.id = ar.fk_actioncomm AND ar.fk_user = '.((int) $user->id); + $sql .= " AND ar.typeremind = 'browser' AND ar.dateremind < '".$db->idate(dol_now())."' AND ar.status = 0 AND ar.entity = ".((int) $conf->entity); // No sharing of entity for alerts $sql .= $db->order('datep', 'ASC'); - $sql .= ' LIMIT 10'; // Avoid too many notification at once + $sql .= $db->plimit(10); // Avoid too many notification at once $resql = $db->query($sql); if ($resql) { diff --git a/htdocs/core/ajax/constantonoff.php b/htdocs/core/ajax/constantonoff.php index 3a8ffda3ae6..603de7408c0 100644 --- a/htdocs/core/ajax/constantonoff.php +++ b/htdocs/core/ajax/constantonoff.php @@ -52,28 +52,26 @@ $name = GETPOST('name', 'alpha'); $entity = GETPOST('entity', 'int'); $value = (GETPOST('value', 'aZ09') != '' ? GETPOST('value', 'aZ09') : 1); +// Security check +if (empty($user->admin)) { + httponly_accessforbidden('This ajax component can be called by admin user only'); +} + /* * View */ -// Ajout directives pour resoudre bug IE -//header('Cache-Control: Public, must-revalidate'); -//header('Pragma: public'); - -//top_htmlhead("", "", 1); // Replaced with top_httphead. An ajax page does not need html header. top_httphead(); //print ''."\n"; // Registering the new value of constant if (!empty($action) && !empty($name)) { - if ($user->admin) { - if ($action == 'set') { - dolibarr_set_const($db, $name, $value, 'chaine', 0, '', $entity); - } elseif ($action == 'del') { - dolibarr_del_const($db, $name, $entity); - } + if ($action == 'set') { + dolibarr_set_const($db, $name, $value, 'chaine', 0, '', $entity); + } elseif ($action == 'del') { + dolibarr_del_const($db, $name, $entity); } } else { http_response_code(403); diff --git a/htdocs/core/ajax/extraparams.php b/htdocs/core/ajax/extraparams.php index ccd8d1bc2ce..80f280e7a06 100644 --- a/htdocs/core/ajax/extraparams.php +++ b/htdocs/core/ajax/extraparams.php @@ -17,7 +17,8 @@ /** * \file /htdocs/core/ajax/extraparams.php - * \brief File to make Ajax action on setting extra parameters of elements + * \brief File to make Ajax action on setting extra parameters of elements. + * Called bu bloc_showhide.tpl.php, itself called when MAIN_DISABLE_CONTACTS_TAB or MAIN_DISABLE_NOTES_TAB are set */ if (!defined('NOTOKENRENEWAL')) { @@ -39,10 +40,29 @@ if (!defined('NOREQUIRESOC')) { include '../../main.inc.php'; $id = GETPOST('id', 'int'); -$element = GETPOST('element', 'alpha'); +$element = GETPOST('element', 'aZ09arobase'); $htmlelement = GETPOST('htmlelement', 'alpha'); $type = GETPOST('type', 'alpha'); +// Load object according to $id and $element +$object = fetchObjectByElement($id, $element); + +$module = $object->module; +$element = $object->element; +$usesublevelpermission = ($module != $element ? $element : ''); +if ($usesublevelpermission && !isset($user->rights->$module->$element)) { // There is no permission on object defined, we will check permission on module directly + $usesublevelpermission = ''; +} + +//print $object->id.' - '.$object->module.' - '.$object->element.' - '.$object->table_element.' - '.$usesublevelpermission."\n"; + +// Security check +$result = restrictedArea($user, $object->module, $object, $object->table_element, $usesublevelpermission, 'fk_soc', 'rowid', 0, 1); // Call with mode return +if (!$result) { + httponly_accessforbidden('Not allowed by restrictArea'); +} + + /* * View */ @@ -57,47 +77,10 @@ if (!empty($id) && !empty($element) && !empty($htmlelement) && !empty($type)) { dol_syslog("AjaxSetExtraParameters id=".$id." element=".$element." htmlelement=".$htmlelement." type=".$type." value=".$value, LOG_DEBUG); - $classpath = $subelement = $element; + if (is_object($object)) { + $params[$htmlelement] = array($type => $value); + $object->extraparams = array_merge($object->extraparams, $params); - // For compatibility - if ($element == 'order' || $element == 'commande') { - $classpath = $subelement = 'commande'; - } elseif ($element == 'propal') { - $classpath = 'comm/propal'; - $subelement = 'propal'; - } elseif ($element == 'facture') { - $classpath = 'compta/facture'; - $subelement = 'facture'; - } elseif ($element == 'contract') { - $classpath = $subelement = 'contrat'; - } elseif ($element == 'shipping') { - $classpath = $subelement = 'expedition'; - } elseif ($element == 'deplacement') { - $classpath = 'compta/deplacement'; - $subelement = 'deplacement'; - } elseif ($element == 'order_supplier') { - $classpath = 'fourn'; - $subelement = 'fournisseur.commande'; - } elseif ($element == 'invoice_supplier') { - $classpath = 'fourn'; - $subelement = 'fournisseur.facture'; + $result = $object->setExtraParameters(); } - - dol_include_once('/'.$classpath.'/class/'.$subelement.'.class.php'); - - if ($element == 'order_supplier') { - $classname = 'CommandeFournisseur'; - } elseif ($element == 'invoice_supplier') { - $classname = 'FactureFournisseur'; - } else { - $classname = ucfirst($subelement); - } - - $object = new $classname($db); - $object->fetch($id); - - $params[$htmlelement] = array($type => $value); - $object->extraparams = array_merge($object->extraparams, $params); - - $result = $object->setExtraParameters(); } diff --git a/htdocs/core/ajax/fetchKnowledgeRecord.php b/htdocs/core/ajax/fetchKnowledgeRecord.php index 295d164022f..6e4f1ddd953 100644 --- a/htdocs/core/ajax/fetchKnowledgeRecord.php +++ b/htdocs/core/ajax/fetchKnowledgeRecord.php @@ -36,7 +36,7 @@ if (!defined('NOREQUIREMENU')) { define('NOREQUIREMENU', '1'); } // If there is no need to load and show top and left menu -if (!empty($_GET['public'])) { +if (!empty($_GET['public'])) { // GETPOST() is not yet defined so we use $_GET if (!defined("NOLOGIN")) { define("NOLOGIN", '1'); } @@ -54,10 +54,10 @@ $idticketgroup = GETPOST('idticketgroup', 'aZ09'); $idticketgroup = GETPOST('idticketgroup', 'aZ09'); $lang = GETPOST('lang', 'aZ09'); -/*if (defined("NOLOGIN") && !getDolGlobalString('TICKET_ENABLE_PUBLIC_INTERFACE')) { - // If we ask public content (so without login), we block if option TICKET_ENABLE_PUBLIC_INTERFACE is not enabled - httponly_accessforbidden(''); -}*/ +// Security check +if (!defined("NOLOGIN")) { // No need of restrictedArea if not logged: Later the select will filter on public articles only if not logged. + restrictedArea($user, 'knowledgemanagement', 0, 'knowledgemanagement_knowledgerecord', 'knowledgerecord'); +} /* diff --git a/htdocs/core/ajax/fileupload.php b/htdocs/core/ajax/fileupload.php index 4e05c7d8cb6..963fa60b05b 100644 --- a/htdocs/core/ajax/fileupload.php +++ b/htdocs/core/ajax/fileupload.php @@ -19,24 +19,25 @@ /** * \file htdocs/core/ajax/fileupload.php * \brief File to return Ajax response on file upload - * - * Option MAIN_USE_JQUERY_FILEUPLOAD must be enabled to have this feature working. Use is NOT secured ! */ -if (!defined('NOTOKENRENEWAL')) { - define('NOTOKENRENEWAL', '1'); -} if (!defined('NOREQUIREMENU')) { define('NOREQUIREMENU', '1'); // If there is no menu to show } if (!defined('NOREQUIREHTML')) { define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php } - +if (!defined('NOREQUIREAJAX')) { + define('NOREQUIREAJAX', '1'); +} +if (!defined('NOREQUIRESOC')) { + define('NOREQUIRESOC', '1'); +} // Load Dolibarr environment require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/fileupload.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/genericobject.class.php'; error_reporting(E_ALL | E_STRICT); @@ -44,14 +45,33 @@ error_reporting(E_ALL | E_STRICT); //print_r($_GET); //print 'upload_dir='.GETPOST('upload_dir'); -$fk_element = GETPOST('fk_element', 'int'); -$element = GETPOST('element', 'alpha'); +$id = GETPOST('fk_element', 'int'); +$element = GETPOST('element', 'alpha'); // 'myobject' (myobject=mymodule) or 'myobject@mymodule' or 'myobject_mysubobject' (myobject=mymodule) +$elementupload = $element; -$upload_handler = new FileUpload(null, $fk_element, $element); +// Load object according to $id and $element +$object = fetchObjectByElement($id, $element); -// Feature not enabled. Warning feature not used and not secured so disabled. -if (!getDolGlobalInt('MAIN_USE_JQUERY_FILEUPLOAD')) { - return; +$module = $object->module; +$element = $object->element; +$usesublevelpermission = ($module != $element ? $element : ''); +if ($usesublevelpermission && !isset($user->rights->$module->$element)) { // There is no permission on object defined, we will check permission on module directly + $usesublevelpermission = ''; +} + +//print $object->id.' - '.$object->module.' - '.$object->element.' - '.$object->table_element.' - '.$usesublevelpermission."\n"; + +// Security check +if (!empty($user->socid)) { + $socid = $user->socid; + if (!empty($object->socid) && $socid != $object->socid) { + httponly_accessforbidden("Access on object not allowed for this external user."); // This includes the exit. + } +} + +$result = restrictedArea($user, $object->module, $object, $object->table_element, $usesublevelpermission, 'fk_soc', 'rowid', 0, 1); // Call with mode return +if (!$result) { + httponly_accessforbidden('Not allowed by restrictArea'); } @@ -59,6 +79,8 @@ if (!getDolGlobalInt('MAIN_USE_JQUERY_FILEUPLOAD')) { * View */ +$upload_handler = new FileUpload(null, $id, $elementupload); + top_httphead(); header('Pragma: no-cache'); diff --git a/htdocs/core/ajax/flowjs-server.php b/htdocs/core/ajax/flowjs-server.php index d520c57c9c5..901d119332f 100644 --- a/htdocs/core/ajax/flowjs-server.php +++ b/htdocs/core/ajax/flowjs-server.php @@ -1,5 +1,5 @@ +/* Copyright (C) 2023 Laurent Destailleur * * 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 @@ -16,8 +16,8 @@ */ /** - * \file htdocs/core/ajax/bankconciliate.php - * \brief File to set data for bank concilation + * \file htdocs/core/ajax/flowjs-server.php + * \brief File to upload very large file, higher than PHP limit. Using flowjs library. */ if (!defined('NOTOKENRENEWAL')) { @@ -46,20 +46,33 @@ require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; $action = GETPOST('action', 'aZ09'); -$module = GETPOST('module', 'aZ09'); -$upload_dir = GETPOST('upload_dir', 'alpha'); + +$module = GETPOST('module', 'aZ09arobase'); + $flowFilename = GETPOST('flowFilename', 'alpha'); $flowIdentifier = GETPOST('flowIdentifier', 'alpha'); $flowChunkNumber = GETPOST('flowChunkNumber', 'alpha'); $flowChunkSize = GETPOST('flowChunkSize', 'alpha'); $flowTotalSize = GETPOST('flowTotalSize', 'alpha'); +$result = restrictedArea($user, $module, 0, '', 0, 'fk_soc', 'rowid', 0, 1); // Call with mode return + +if ($action != 'upload') { + httponly_accessforbidden("Param action must be 'upload'"); +} + +if (!empty($conf->$module->dir_temp)) { + $upload_dir = $conf->$module->dir_temp; +} else { + httponly_accessforbidden("Param module does not has a dir_temp directory. Module does not exists or is not activated."); +} + /* * Action */ - top_httphead(); + dol_syslog(join(',', $_GET)); $result = false; @@ -123,19 +136,19 @@ if ($result) { /** - * Check if all the parts exist, and - * gather all the parts of the file together - * @param string $temp_dir - the temporary directory holding all the parts of the file - * @param string $upload_dir - the temporary directory to create file - * @param string $fileName - the original file name - * @param string $chunkSize - each chunk size (in bytes) - * @param string $totalSize - original file size (in bytes) - * @return bool true if Ok false else + * Check if all the parts exist, and gather all the parts of the file together. + * + * @param string $temp_dir the temporary directory holding all the parts of the file + * @param string $upload_dir the temporary directory to create file + * @param string $fileName the original file name + * @param string $chunkSize each chunk size (in bytes) + * @param string $totalSize original file size (in bytes) + * @return bool true if Ok false else */ function createFileFromChunks($temp_dir, $upload_dir, $fileName, $chunkSize, $totalSize) { - dol_syslog(__METHOD__, LOG_DEBUG); + // count all the parts of this file $total_files = 0; $files = dol_dir_list($temp_dir, 'files'); @@ -164,5 +177,6 @@ function createFileFromChunks($temp_dir, $upload_dir, $fileName, $chunkSize, $to // concurrent chunks uploads) @rename($temp_dir, $temp_dir.'_UNUSED'); } + return true; } diff --git a/htdocs/core/ajax/getaccountcurrency.php b/htdocs/core/ajax/getaccountcurrency.php index ff27812aaa2..20061dcdf2b 100644 --- a/htdocs/core/ajax/getaccountcurrency.php +++ b/htdocs/core/ajax/getaccountcurrency.php @@ -35,6 +35,9 @@ require '../../main.inc.php'; $id = GETPOST('id', 'int'); +// Security check +$result = restrictedArea($user, 'banque', $id, 'bank_account&bank_account'); + /* * View diff --git a/htdocs/core/ajax/loadinplace.php b/htdocs/core/ajax/loadinplace.php index af033c8cdd3..415e51af8e5 100644 --- a/htdocs/core/ajax/loadinplace.php +++ b/htdocs/core/ajax/loadinplace.php @@ -17,7 +17,7 @@ /** * \file htdocs/core/ajax/loadinplace.php - * \brief File to load field value + * \brief File to load field value. used only when option "Edit In Place" is set (MAIN_USE_JQUERY_JEDITABLE). */ if (!defined('NOTOKENRENEWAL')) { @@ -41,6 +41,30 @@ $field = GETPOST('field', 'alpha'); $element = GETPOST('element', 'alpha'); $table_element = GETPOST('table_element', 'alpha'); $fk_element = GETPOST('fk_element', 'alpha'); +$id = $fk_element; + +// Load object according to $id and $element +$object = fetchObjectByElement($id, $element); + +$module = $object->module; +$element = $object->element; +$usesublevelpermission = ($module != $element ? $element : ''); +if ($usesublevelpermission && !isset($user->rights->$module->$element)) { // There is no permission on object defined, we will check permission on module directly + $usesublevelpermission = ''; +} + +//print $object->id.' - '.$object->module.' - '.$object->element.' - '.$object->table_element.' - '.$usesublevelpermission."\n"; + +// Security check +$result = restrictedArea($user, $object->module, $object, $object->table_element, $usesublevelpermission, 'fk_soc', 'rowid', 0, 1); // Call with mode return +if (!$result) { + httponly_accessforbidden('Not allowed by restrictArea'); +} + +if (!getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE')) { + httponly_accessforbidden('Can be used only when option MAIN_USE_JQUERY_JEDITABLE is set'); +} + /* * View @@ -94,6 +118,7 @@ if (!empty($field) && !empty($element) && !empty($table_element) && !empty($fk_e } } elseif (!empty($ext_element)) { $module = $subelement = $ext_element; + $regs = array(); if (preg_match('/^([^_]+)_([^_]+)/i', $ext_element, $regs)) { $module = $regs[1]; $subelement = $regs[2]; diff --git a/htdocs/core/ajax/locationincoterms.php b/htdocs/core/ajax/locationincoterms.php index 057322ec5fb..f3e621abc85 100644 --- a/htdocs/core/ajax/locationincoterms.php +++ b/htdocs/core/ajax/locationincoterms.php @@ -43,6 +43,12 @@ if (!defined('NOREQUIRESOC')) { require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php'; +// Security check +if (!isModEnabled('incoterm')) { + httponly_accessforbidden("Module incoterm not enabled"); // This includes the exit. +} +// There is no other permission on this component. Everybody connected can read content of the incoterm table + /* * View @@ -70,13 +76,12 @@ if (GETPOST('location_incoterms')) { if (!empty($conf->global->MAIN_USE_LOCATION_INCOTERMS_DICTIONNARY)) { // Use location_incoterms $sql = "SELECT z.location as location_incoterms, z.label as label"; $sql .= " FROM ".MAIN_DB_PREFIX."c_location_incoterms as z"; - $sql .= " WHERE z.active = 1 AND UPPER(z.location) LIKE UPPER('%".$db->escape($location_incoterms)."%')"; + $sql .= " WHERE z.active = 1 AND z.location LIKE '%".$db->escape($db->escapeforlike($location_incoterms))."%'"; $sql .= " ORDER BY z.location"; $sql .= $db->plimit(100); // Avoid pb with bad criteria - } else // Use table of commande - { + } else { // Use table of sale orders $sql = "SELECT DISTINCT s.location_incoterms FROM ".MAIN_DB_PREFIX.'commande as s'; - $sql .= " WHERE UPPER(s.location_incoterms) LIKE UPPER('%".$db->escape($location_incoterms)."%')"; + $sql .= " WHERE s.location_incoterms LIKE '%".$db->escape($db->escapeforlike($location_incoterms))."%'"; //Todo: merge with data from table of supplier order /* $sql .=" UNION"; diff --git a/htdocs/core/ajax/objectonoff.php b/htdocs/core/ajax/objectonoff.php index 77cd3234cd8..ed670627a90 100644 --- a/htdocs/core/ajax/objectonoff.php +++ b/htdocs/core/ajax/objectonoff.php @@ -18,7 +18,7 @@ /** * \file htdocs/core/ajax/objectonoff.php * \brief File to set status for an object - * This Ajax service is called when option MAIN_DIRECT_STATUS_UPDATE is set. + * This Ajax service is oftenly called when option MAIN_DIRECT_STATUS_UPDATE is set. */ if (!defined('NOTOKENRENEWAL')) { @@ -45,37 +45,46 @@ require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/genericobject.class.php'; $action = GETPOST('action', 'aZ09'); + $id = GETPOST('id', 'int'); -$value = GETPOST('value', 'int'); +$element = GETPOST('element', 'alpha'); // 'myobject' (myobject=mymodule) or 'myobject@mymodule' or 'myobject_mysubobject' (myobject=mymodule) $field = GETPOST('field', 'alpha'); -$element = GETPOST('element', 'alpha'); +$value = GETPOST('value', 'int'); $format = 'int'; -$object = new GenericObject($db); - -$tablename = $element; -if ($tablename == 'websitepage') { - $tablename = 'website_page'; +// Load object according to $id and $element +$object = fetchObjectByElement($id, $element); +if (!is_object($object)) { + httponly_accessforbidden("Bad value for combination of parameters element/field: Object not found."); // This includes the exit. } -$object->table_element = $tablename; -$object->id = $id; $object->fields[$field] = array('type' => $format, 'enabled' => 1); +$module = $object->module; +$element = $object->element; +$usesublevelpermission = ($module != $element ? $element : ''); +if ($usesublevelpermission && !isset($user->rights->$module->$element)) { // There is no permission on object defined, we will check permission on module directly + $usesublevelpermission = ''; +} + +//print $object->id.' - '.$object->module.' - '.$object->element.' - '.$object->table_element.' - '.$usesublevelpermission."\n"; + // Security check if (!empty($user->socid)) { $socid = $user->socid; + if (!empty($object->socid) && $socid != $object->socid) { + httponly_accessforbidden("Access on object not allowed for this external user."); // This includes the exit. + } } -//$user->hasRight('societe', 'lire') = 0;$user->rights->fournisseur->lire = 0; -//restrictedArea($user, 'societe', $id); - -if (in_array($field, array('status'))) { - restrictedArea($user, $element, $id); +// We check permission. +// Check is done on $user->rights->element->create or $user->rights->element->subelement->create (because $action = 'set') +if (preg_match('/status$/', $field)) { + restrictedArea($user, $object->module, $object, $object->table_element, $usesublevelpermission); } elseif ($element == 'product' && in_array($field, array('tosell', 'tobuy', 'tobatch'))) { // Special case for products - restrictedArea($user, 'produit|service', $id, 'product&product', '', '', 'rowid'); + restrictedArea($user, 'produit|service', $object, 'product&product', '', '', 'rowid'); } else { - httponly_accessforbidden("Bad value for combination of parameters element/field."); + httponly_accessforbidden("Bad value for combination of parameters element/field: Field not supported."); // This includes the exit. } @@ -89,7 +98,7 @@ print ''."\n"; diff --git a/htdocs/core/ajax/price.php b/htdocs/core/ajax/price.php index 283afb77653..e2a8829fc14 100644 --- a/htdocs/core/ajax/price.php +++ b/htdocs/core/ajax/price.php @@ -40,6 +40,10 @@ $output = GETPOST('output', 'alpha'); $amount = price2num(GETPOST('amount', 'alpha')); $tva_tx = str_replace('*', '', GETPOST('tva_tx', 'alpha')); +// Security check +// None. This is a formatting only component. + + /* * View */ diff --git a/htdocs/core/ajax/row.php b/htdocs/core/ajax/row.php index ec3ee105420..a20034ba0fe 100644 --- a/htdocs/core/ajax/row.php +++ b/htdocs/core/ajax/row.php @@ -49,7 +49,9 @@ if (!defined('NOREQUIRETRAN')) { // Load Dolibarr environment require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/genericobject.class.php'; + $hookmanager->initHooks(array('rowinterface')); + // Security check // This is done later into view. diff --git a/htdocs/core/ajax/saveinplace.php b/htdocs/core/ajax/saveinplace.php index 32fdae72835..9cbecc8e9c7 100644 --- a/htdocs/core/ajax/saveinplace.php +++ b/htdocs/core/ajax/saveinplace.php @@ -17,7 +17,7 @@ /** * \file htdocs/core/ajax/saveinplace.php - * \brief File to save field value + * \brief File to load field value. used only when option "Edit In Place" is set (MAIN_USE_JQUERY_JEDITABLE). */ if (!defined('NOTOKENRENEWAL')) { @@ -41,6 +41,7 @@ $field = GETPOST('field', 'alpha', 2); $element = GETPOST('element', 'alpha', 2); $table_element = GETPOST('table_element', 'alpha', 2); $fk_element = GETPOST('fk_element', 'alpha', 2); +$id = $fk_element; /* Example: field:editval_ref_customer (8 first chars will removed to know name of property) @@ -54,6 +55,28 @@ savemethod: savemethodname: */ +// Load object according to $id and $element +$object = fetchObjectByElement($id, $element); + +$module = $object->module; +$element = $object->element; +$usesublevelpermission = ($module != $element ? $element : ''); +if ($usesublevelpermission && !isset($user->rights->$module->$element)) { // There is no permission on object defined, we will check permission on module directly + $usesublevelpermission = ''; +} + +//print $object->id.' - '.$object->module.' - '.$object->element.' - '.$object->table_element.' - '.$usesublevelpermission."\n"; + +// Security check +$result = restrictedArea($user, $object->module, $object, $object->table_element, $usesublevelpermission, 'fk_soc', 'rowid', 0, 1); // Call with mode return +if (!$result) { + httponly_accessforbidden('Not allowed by restrictArea'); +} + +if (!getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE')) { + httponly_accessforbidden('Can be used only when option MAIN_USE_JQUERY_JEDITABLE is set'); +} + /* * View diff --git a/htdocs/core/ajax/security.php b/htdocs/core/ajax/security.php index 2a836359e1c..8602190db73 100644 --- a/htdocs/core/ajax/security.php +++ b/htdocs/core/ajax/security.php @@ -17,8 +17,8 @@ /** * \file htdocs/core/ajax/security.php - * \brief This ajax component is used to generated hash keys for security purposes - * like key to use into URL to protect them. + * \brief This ajax component is used to generated hash keys for security purposes, + * like the key to use into URL to protect them. */ if (!defined('NOTOKENRENEWAL')) { @@ -46,6 +46,9 @@ require '../../main.inc.php'; $action = GETPOST('action'); +// Security check +// None. This is public component with no effect on data. + /* * View diff --git a/htdocs/core/ajax/selectobject.php b/htdocs/core/ajax/selectobject.php index 079224c62a2..14372a405b4 100644 --- a/htdocs/core/ajax/selectobject.php +++ b/htdocs/core/ajax/selectobject.php @@ -38,33 +38,18 @@ if (!defined('NOREQUIRESOC')) { // Load Dolibarr environment require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php'; $objectdesc = GETPOST('objectdesc', 'alpha'); $htmlname = GETPOST('htmlname', 'aZ09'); $outjson = (GETPOST('outjson', 'int') ? GETPOST('outjson', 'int') : 0); $id = GETPOST('id', 'int'); -$filter = GETPOST('filter', 'alphanohtml'); - - -/* - * View - */ - -//print ''."\n"; -//print_r($_GET); - -require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php'; -$form = new Form($db); - -//$langs->load("companies"); - -top_httphead(); +$filter = GETPOST('filter', 'alphanohtml'); // Universal Syntax filter if (empty($htmlname)) { - return; + httponly_accessforbidden('Bad value for param htmlname'); } - $InfoFieldList = explode(":", $objectdesc); $classname = $InfoFieldList[0]; $classpath = $InfoFieldList[1]; @@ -75,16 +60,41 @@ if (!empty($classpath)) { } } if (!is_object($objecttmp)) { - dol_syslog('Error bad param objectdesc', LOG_WARNING); - print 'Error bad param objectdesc'; + httponly_accessforbidden('Bad value for param objectdesc'); } +/* +// Load object according to $id and $element +$object = fetchObjectByElement($id, $element); + +$module = $object->module; +$element = $object->element; +$usesublevelpermission = ($module != $element ? $element : ''); +if ($usesublevelpermission && !isset($user->rights->$module->$element)) { // There is no permission on object defined, we will check permission on module directly + $usesublevelpermission = ''; +} +*/ + // When used from jQuery, the search term is added as GET param "term". $searchkey = (($id && GETPOST($id, 'alpha')) ? GETPOST($id, 'alpha') : (($htmlname && GETPOST($htmlname, 'alpha')) ? GETPOST($htmlname, 'alpha') : '')); // Add a security test to avoid to get content of all tables restrictedArea($user, $objecttmp->element, $id); + +/* + * View + */ + +//print ''."\n"; +//print_r($_GET); + +//$langs->load("companies"); + +$form = new Form($db); + +top_httphead($outjson ? 'application/json' : 'text/html'); + $arrayresult = $form->selectForFormsList($objecttmp, $htmlname, '', 0, $searchkey, '', '', '', 0, 1, 0, '', $filter); $db->close(); diff --git a/htdocs/core/ajax/selectsearchbox.php b/htdocs/core/ajax/selectsearchbox.php index d2379f46966..615872eb101 100644 --- a/htdocs/core/ajax/selectsearchbox.php +++ b/htdocs/core/ajax/selectsearchbox.php @@ -1,5 +1,5 @@ +/* Copyright (C) 2015-2023 Laurent Destailleur * * 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 @@ -18,7 +18,7 @@ /** * \file htdocs/core/ajax/selectsearchbox.php * \ingroup core - * \brief This script returns content of possible search + * \brief This script returns json array of possible searches or just set the array if called by an include */ // This script is called with a POST method or as an include. @@ -43,6 +43,9 @@ if (!isset($usedbyinclude) || empty($usedbyinclude)) { $res = @include '../../main.inc.php'; + // Security check + // None. Beeing connected is enough. + top_httphead('application/json'); if ($res == 'ERROR_NOT_LOGGED') { diff --git a/htdocs/core/ajax/vatrates.php b/htdocs/core/ajax/vatrates.php index 56cb4c788e3..1b4a0c79c80 100644 --- a/htdocs/core/ajax/vatrates.php +++ b/htdocs/core/ajax/vatrates.php @@ -17,7 +17,7 @@ /** * \file htdocs/core/ajax/vatrates.php - * \brief File to load vat rates combobox + * \brief File to load vat rates combobox according to thirdparty ID. Values are returned in JSON format. */ if (!defined('NOTOKENRENEWAL')) { @@ -34,16 +34,20 @@ if (!defined('NOREQUIREAJAX')) { require '../../main.inc.php'; $id = GETPOST('id', 'int'); -$action = GETPOST('action', 'aZ09'); +$action = GETPOST('action', 'aZ09'); // 'getSellerVATRates' or 'getBuyerVATRates' $htmlname = GETPOST('htmlname', 'alpha'); $selected = (GETPOST('selected') ?GETPOST('selected') : '-1'); $productid = (GETPOST('productid', 'int') ?GETPOST('productid', 'int') : 0); +// Security check +$result = restrictedArea($user, 'societe', $id, '&societe', '', 'fk_soc', 'rowid', 0); + + /* * View */ -top_httphead(); +top_httphead('application/json'); //print ''."\n"; @@ -63,7 +67,6 @@ if (!empty($id) && !empty($action) && !empty($htmlname)) { } $return = array(); - $return['value'] = $form->load_tva('tva_tx', $selected, $seller, $buyer, $productid, 0, '', true); $return['num'] = $form->num; $return['error'] = $form->error; diff --git a/htdocs/core/ajax/ziptown.php b/htdocs/core/ajax/ziptown.php index f6869e9ffcf..92db98c250d 100644 --- a/htdocs/core/ajax/ziptown.php +++ b/htdocs/core/ajax/ziptown.php @@ -42,6 +42,11 @@ if (!defined('NOREQUIRESOC')) { require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +// Security check +if (!getDolGlobalString('MAIN_USE_ZIPTOWN_DICTIONNARY')) { + // If MAIN_USE_ZIPTOWN_DICTIONNARY is set, we make a search into a public page. If not we search into societe so we must check we have read permission. + $result = restrictedArea($user, 'societe', 0, '&societe', '', 'fk_soc', 'rowid', 0); +} /* @@ -53,11 +58,11 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; //header('Pragma: public'); //top_htmlhead("", "", 1); // Replaced with top_httphead. An ajax page does not need html header. -top_httphead(); +top_httphead('application/json'); //print ''."\n"; -dol_syslog('ziptown call with MAIN_USE_ZIPTOWN_DICTIONNARY='.(empty($conf->global->MAIN_USE_ZIPTOWN_DICTIONNARY) ? '' : $conf->global->MAIN_USE_ZIPTOWN_DICTIONNARY)); +dol_syslog('ziptown call with MAIN_USE_ZIPTOWN_DICTIONNARY='.getDolGlobalString('MAIN_USE_ZIPTOWN_DICTIONNARY')); //var_dump($_GET); // Generation of list of zip-town @@ -69,7 +74,7 @@ if (GETPOST('zipcode') || GETPOST('town')) { $zipcode = GETPOST('zipcode'); $town = GETPOST('town'); - if (!empty($conf->global->MAIN_USE_ZIPTOWN_DICTIONNARY)) { // Use zip-town table + if (getDolGlobalString('MAIN_USE_ZIPTOWN_DICTIONNARY')) { // Use zip-town table $sql = "SELECT z.rowid, z.zip, z.town, z.fk_county, z.fk_pays as fk_country"; $sql .= ", c.rowid as fk_country, c.code as country_code, c.label as country"; $sql .= ", d.rowid as fk_county, d.code_departement as county_code, d.nom as county"; @@ -80,15 +85,14 @@ if (GETPOST('zipcode') || GETPOST('town')) { $sql .= " WHERE z.fk_pays = c.rowid"; $sql .= " AND z.active = 1 AND c.active = 1"; if ($zipcode) { - $sql .= " AND z.zip LIKE '".$db->escape($zipcode)."%'"; + $sql .= " AND z.zip LIKE '".$db->escape($db->escapeforlike($zipcode))."%'"; } if ($town) { - $sql .= " AND z.town LIKE '%".$db->escape($town)."%'"; + $sql .= " AND z.town LIKE '%".$db->escape($db->escapeforlike($town))."%'"; } $sql .= " ORDER BY z.zip, z.town"; $sql .= $db->plimit(100); // Avoid pb with bad criteria - } else // Use table of third parties - { + } else { // Use table of third parties $sql = "SELECT DISTINCT s.zip, s.town, s.fk_departement as fk_county, s.fk_pays as fk_country"; $sql .= ", c.code as country_code, c.label as country"; $sql .= ", d.code_departement as county_code , d.nom as county"; @@ -97,10 +101,10 @@ if (GETPOST('zipcode') || GETPOST('town')) { $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.'c_country as c ON s.fk_pays = c.rowid'; $sql .= " WHERE"; if ($zipcode) { - $sql .= " s.zip LIKE '".$db->escape($zipcode)."%'"; + $sql .= " s.zip LIKE '".$db->escape($db->escapeforlike($zipcode))."%'"; } if ($town) { - $sql .= " s.town LIKE '%".$db->escape($town)."%'"; + $sql .= " s.town LIKE '%".$db->escape($db->escapeforlike($town))."%'"; } $sql .= " ORDER BY s.fk_pays, s.zip, s.town"; $sql .= $db->plimit(100); // Avoid pb with bad criteria diff --git a/htdocs/core/boxes/box_members_by_tags.php b/htdocs/core/boxes/box_members_by_tags.php index d4e78f7efe9..6341fb9f899 100644 --- a/htdocs/core/boxes/box_members_by_tags.php +++ b/htdocs/core/boxes/box_members_by_tags.php @@ -2,7 +2,7 @@ /* Copyright (C) 2003-2007 Rodolphe Quiedeville * Copyright (C) 2004-2017 Laurent Destailleur * Copyright (C) 2005-2012 Regis Houssin - * Copyright (C) 2015-2020 Frederic France + * Copyright (C) 2015-2023 Frédéric France * Copyright (C) 2021-2022 Waël Almoman * * This program is free software; you can redistribute it and/or modify @@ -87,6 +87,7 @@ class box_members_by_tags extends ModeleBoxes include_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php'; $staticmember = new Adherent($this->db); + $now = dol_now(); $year = date('Y'); $numberyears = empty(getDolGlobalInt("MAIN_NB_OF_YEAR_IN_WIDGET_GRAPH")) ? 2 : getDolGlobalInt("MAIN_NB_OF_YEAR_IN_WIDGET_GRAPH"); diff --git a/htdocs/core/class/CMailFile.class.php b/htdocs/core/class/CMailFile.class.php index 04da241f16c..eef112a00e2 100644 --- a/htdocs/core/class/CMailFile.class.php +++ b/htdocs/core/class/CMailFile.class.php @@ -641,7 +641,7 @@ class CMailFile */ public function sendfile() { - global $conf, $db, $langs; + global $conf, $db, $langs, $hookmanager; $errorlevel = error_reporting(); //error_reporting($errorlevel ^ E_WARNING); // Desactive warnings @@ -649,8 +649,10 @@ class CMailFile $res = false; if (empty($conf->global->MAIN_DISABLE_ALL_MAILS)) { - require_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; - $hookmanager = new HookManager($db); + if (!is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($db); + } $hookmanager->initHooks(array('mail')); $parameters = array(); @@ -686,6 +688,8 @@ class CMailFile $this->error .= '
'.$langs->trans("MailSendSetupIs3", $conf->global->MAILING_SMTP_SETUP_EMAILS_FOR_QUESTIONS); $this->errors[] = $langs->trans("MailSendSetupIs3", $conf->global->MAILING_SMTP_SETUP_EMAILS_FOR_QUESTIONS); } + + dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_WARNING); return false; } @@ -756,7 +760,7 @@ class CMailFile // Use mail php function (default PHP method) // ------------------------------------------ dol_syslog("CMailFile::sendfile addr_to=".$this->addr_to.", subject=".$this->subject, LOG_DEBUG); - dol_syslog("CMailFile::sendfile header=\n".$this->headers, LOG_DEBUG); + //dol_syslog("CMailFile::sendfile header=\n".$this->headers, LOG_DEBUG); //dol_syslog("CMailFile::sendfile message=\n".$message); // If Windows, sendmail_from must be defined @@ -845,7 +849,7 @@ class CMailFile dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR); if (!empty($conf->global->MAIN_MAIL_DEBUG)) { - $this->save_dump_mail_in_err(); + $this->save_dump_mail_in_err('Mail with topic '.$this->subject); } } else { dol_syslog("CMailFile::sendfile: mail end success", LOG_DEBUG); @@ -995,7 +999,26 @@ class CMailFile $this->dump_mail(); } - $result = $this->smtps->getErrors(); + if (! $result) { + $smtperrorcode = $this->smtps->lastretval; // SMTP error code + dol_syslog("CMailFile::sendfile: mail SMTP error code ".$smtperrorcode, LOG_WARNING); + + if ($smtperrorcode == '421') { // Try later + // TODO Add a delay and try again + /* + dol_syslog("CMailFile::sendfile: Try later error, so we wait and we retry"); + sleep(2); + + $result = $this->smtps->sendMsg(); + + if (!empty($conf->global->MAIN_MAIL_DEBUG)) { + $this->dump_mail(); + } + */ + } + } + + $result = $this->smtps->getErrors(); // applicative error code (not SMTP error code) if (empty($this->error) && empty($result)) { dol_syslog("CMailFile::sendfile: mail end success", LOG_DEBUG); $res = true; @@ -1007,7 +1030,7 @@ class CMailFile $res = false; if (!empty($conf->global->MAIN_MAIL_DEBUG)) { - $this->save_dump_mail_in_err(); + $this->save_dump_mail_in_err('Mail smtp error '.$smtperrorcode.' with topic '.$this->subject); } } } @@ -1147,7 +1170,7 @@ class CMailFile $res = false; if (!empty($conf->global->MAIN_MAIL_DEBUG)) { - $this->save_dump_mail_in_err(); + $this->save_dump_mail_in_err('Mail with topic '.$this->subject); } } else { dol_syslog("CMailFile::sendfile: mail end success", LOG_DEBUG); @@ -1258,16 +1281,40 @@ class CMailFile * Save content if mail is in error * Used for debugging. * + * @param string $message Add also a message * @return void */ - public function save_dump_mail_in_err() + public function save_dump_mail_in_err($message = '') { global $dolibarr_main_data_root; if (@is_writeable($dolibarr_main_data_root)) { // Avoid fatal error on fopen with open_basedir $srcfile = $dolibarr_main_data_root."/dolibarr_mail.log"; - $destfile = $dolibarr_main_data_root."/dolibarr_mail.err"; + // Add message to dolibarr_mail.log. We do not use dol_syslog() on purpose, + // to be sure to write into dolibarr_mail.log + if ($message) { + // Test constant SYSLOG_FILE_NO_ERROR (should stay a constant defined with define('SYSLOG_FILE_NO_ERROR',1); + if (defined('SYSLOG_FILE_NO_ERROR')) { + $filefd = @fopen($srcfile, 'a+'); + } else { + $filefd = fopen($srcfile, 'a+'); + } + if ($filefd) { + fwrite($filefd, $message."\n"); + fclose($filefd); + dolChmod($srcfile); + } + } + + // Move dolibarr_mail.log into a dolibarr_mail.err or dolibarr_mail.date.err + if (getDolGlobalString('MAIN_MAIL_DEBUG_ERR_WITH_DATE')) { + $destfile = $dolibarr_main_data_root."/dolibarr_mail.".dol_print_date(dol_now(), 'dayhourlog', 'gmt').".err"; + } else { + $destfile = $dolibarr_main_data_root."/dolibarr_mail.err"; + } + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; dol_move($srcfile, $destfile, 0, 1, 0, 0); } } diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index cec7408f1ca..127584e3f9f 100644 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -1582,7 +1582,7 @@ abstract class CommonDocGenerator $colDef['title']['label'] = !empty($colDef['title']['label']) ? $colDef['title']['label'] : $outputlangs->transnoentities($colDef['title']['textkey']); // Add column separator - if (!empty($colDef['border-left'])) { + if (!empty($colDef['border-left']) && isset($colDef['xStartPos'])) { $pdf->line($colDef['xStartPos'], $tab_top, $colDef['xStartPos'], $tab_top + $tab_height); } @@ -1599,17 +1599,21 @@ abstract class CommonDocGenerator // set cell padding with column title definition $pdf->setCellPaddings($colDef['title']['padding'][3], $colDef['title']['padding'][0], $colDef['title']['padding'][1], $colDef['title']['padding'][2]); } - + if (isset($colDef['title']['align'])) { + $align = $colDef['title']['align']; + } else { + $align = ''; + } $pdf->SetXY($colDef['xStartPos'], $tab_top); $textWidth = $colDef['width']; - $pdf->MultiCell($textWidth, 2, $colDef['title']['label'], '', $colDef['title']['align']); + $pdf->MultiCell($textWidth, 2, $colDef['title']['label'], '', $align); // Add variant of translation if $outputlangsbis is an object if (is_object($outputlangsbis) && trim($colDef['title']['label'])) { $pdf->setCellPaddings($colDef['title']['padding'][3], 0, $colDef['title']['padding'][1], $colDef['title']['padding'][2]); $pdf->SetXY($colDef['xStartPos'], $pdf->GetY()); $textbis = $outputlangsbis->transnoentities($colDef['title']['textkey']); - $pdf->MultiCell($textWidth, 2, $textbis, '', $colDef['title']['align']); + $pdf->MultiCell($textWidth, 2, $textbis, '', $align); } $this->tabTitleHeight = max($pdf->GetY() - $tab_top, $this->tabTitleHeight); diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index c85f66ca2c6..e53cc85c21f 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -86,6 +86,11 @@ abstract class CommonObject */ public $element; + /** + * @var int The related element + */ + public $fk_element; + /** * @var string Name to use for 'features' parameter to check module permissions user->rights->feature with restrictedArea(). * Undefined means same value than $element. Can be use to force a check on another element for example for class of line, we mention here the parent element. @@ -391,6 +396,22 @@ abstract class CommonObject */ public $shipping_method_id; + /** + * @var string Shipping method label + * @see setShippingMethod() + */ + public $shipping_method; + + /** + * @var string multicurrency code + */ + public $multicurrency_code; + + /** + * @var string multicurrency tx + */ + public $multicurrency_tx; + /** * @var string * @see SetDocModel() @@ -710,19 +731,24 @@ abstract class CommonObject { global $action, $extrafields, $langs, $hookmanager; + $MAX_EXTRAFIELDS_TO_SHOW_IN_TOOLTIP = 5; // If there is too much extrafields, we do not include them into tooltip + $datas = $this->getTooltipContentArray($params); + // Add extrafields if (!empty($extrafields->attributes[$this->table_element]['label'])) { - foreach ($extrafields->attributes[$this->table_element]['label'] as $key => $val) { - if (!empty($extrafields->attributes[$this->table_element]['langfile'][$key])) { - $langs->load($extrafields->attributes[$this->table_element]['langfile'][$key]); - } - $labelextra = $langs->trans((string) $extrafields->attributes[$this->table_element]['label'][$key]); - if ($extrafields->attributes[$this->table_element]['type'][$key] == 'separate') { - $datas[$key]= '
'. $labelextra . ''; - } else { - $value = $this->array_options['options_' . $key]; - $datas[$key]= '
'. $labelextra . ': ' . $extrafields->showOutputField($key, $value, '', $this->table_element); + if (count($extrafields->attributes[$this->table_element]['label']) < $MAX_EXTRAFIELDS_TO_SHOW_IN_TOOLTIP) { + foreach ($extrafields->attributes[$this->table_element]['label'] as $key => $val) { + if (!empty($extrafields->attributes[$this->table_element]['langfile'][$key])) { + $langs->load($extrafields->attributes[$this->table_element]['langfile'][$key]); + } + $labelextra = $langs->trans((string) $extrafields->attributes[$this->table_element]['label'][$key]); + if ($extrafields->attributes[$this->table_element]['type'][$key] == 'separate') { + $datas[$key]= '
'. $labelextra . ''; + } else { + $value = (empty($this->array_options['options_' . $key]) ? '' : $this->array_options['options_' . $key]); + $datas[$key]= '
'. $labelextra . ': ' . $extrafields->showOutputField($key, $value, '', $this->table_element); + } } } } @@ -2122,6 +2148,8 @@ abstract class CommonObject $error = 0; + dol_syslog(__METHOD__, LOG_DEBUG); + $this->db->begin(); $sql = "UPDATE ".$this->db->prefix().$table." SET "; @@ -2146,7 +2174,6 @@ abstract class CommonObject $sql .= " WHERE ".$id_field." = ".((int) $id); - dol_syslog(__METHOD__, LOG_DEBUG); $resql = $this->db->query($sql); if ($resql) { if ($trigkey) { @@ -4623,7 +4650,7 @@ abstract class CommonObject } /** - * Function to check if an object is used by others. + * Function to check if an object is used by others (by children). * Check is done into this->childtables. There is no check into llx_element_element. * * @param int $id Force id of object @@ -4644,8 +4671,8 @@ abstract class CommonObject return -1; } - $arraytoscan = $this->childtables; - // For backward compatibility, we check if array is old format array('table1', 'table2', ...) + $arraytoscan = $this->childtables; // array('tablename'=>array('fk_element'=>'parentfield'), ...) or array('tablename'=>array('parent'=>table_parent, 'parentkey'=>'nameoffieldforparentfkkey'), ...) + // For backward compatibility, we check if array is old format array('tablename1', 'tablename2', ...) $tmparray = array_keys($this->childtables); if (is_numeric($tmparray[0])) { $arraytoscan = array_flip($this->childtables); @@ -4661,7 +4688,11 @@ abstract class CommonObject if (!empty($element['parent']) && !empty($element['parentkey'])) { $sql.= ", ".$this->db->prefix().$element['parent']." as p"; } - $sql.= " WHERE c.".$this->fk_element." = ".((int) $id); + if (!empty($element['fk_element'])) { + $sql.= " WHERE c.".$element['fk_element']." = ".((int) $id); + } else { + $sql.= " WHERE c.".$this->fk_element." = ".((int) $id); + } if (!empty($element['parent']) && !empty($element['parentkey'])) { $sql.= " AND c.".$element['parentkey']." = p.rowid"; } @@ -4675,6 +4706,7 @@ abstract class CommonObject $sql.= " AND c.entity = ".((int) $entity); } } + $resql = $this->db->query($sql); if ($resql) { $obj = $this->db->fetch_object($resql); @@ -9684,7 +9716,7 @@ abstract class CommonObject return -1; } } - } elseif (!empty($this->fk_element) && !empty($this->childtables)) { // If object has childs linked with a foreign key field, we check all child tables. + } elseif (!empty($this->childtables)) { // If object has childs linked with a foreign key field, we check all child tables. $objectisused = $this->isObjectUsed($this->id); if (!empty($objectisused)) { dol_syslog(get_class($this)."::deleteCommon Can't delete record as it has some child", LOG_WARNING); diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index fd6e9aa6efb..73a8b86ea47 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -1124,6 +1124,9 @@ class ExtraFields continue; } + $valarray = explode('|', $val); + $val = $valarray[0]; + if ($langfile && $val) { $options[$okey] = $langs->trans($val); } else { diff --git a/htdocs/core/class/fileupload.class.php b/htdocs/core/class/fileupload.class.php index 980f87e2d28..4dcfb55f781 100644 --- a/htdocs/core/class/fileupload.class.php +++ b/htdocs/core/class/fileupload.class.php @@ -19,8 +19,6 @@ /** * \file htdocs/core/class/fileupload.class.php * \brief File to return Ajax response on file upload - * - * Option MAIN_USE_JQUERY_FILEUPLOAD must be enabled to have feature working. Use is NOT secured ! */ require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; @@ -49,17 +47,13 @@ class FileUpload global $object; global $hookmanager; - // Feature not enabled. Warning feature not used and not secured so disabled. - if (!getDolGlobalInt('MAIN_USE_JQUERY_FILEUPLOAD')) { - return; - } - $hookmanager->initHooks(array('fileupload')); $this->fk_element = $fk_element; $this->element = $element; $pathname = $filename = $element; + $regs = array(); if (preg_match('/^([^_]+)_([^_]+)/i', $element, $regs)) { $pathname = $regs[1]; $filename = $regs[2]; @@ -265,9 +259,6 @@ class FileUpload */ protected function getFileObject($file_name) { - if (!getDolGlobalInt('MAIN_USE_JQUERY_FILEUPLOAD')) { - return null; - } $file_path = $this->options['upload_dir'].$file_name; if (is_file($file_path) && $file_name[0] !== '.') { @@ -309,10 +300,6 @@ class FileUpload { global $maxwidthmini, $maxheightmini; - if (!getDolGlobalInt('MAIN_USE_JQUERY_FILEUPLOAD')) { - return false; - } - $file_path = $this->options['upload_dir'].$file_name; $new_file_path = $options['upload_dir'].$file_name; @@ -344,10 +331,6 @@ class FileUpload */ protected function validate($uploaded_file, $file, $error, $index) { - if (!getDolGlobalInt('MAIN_USE_JQUERY_FILEUPLOAD')) { - return false; - } - if ($error) { $file->error = $error; return false; @@ -463,10 +446,6 @@ class FileUpload */ protected function handleFileUpload($uploaded_file, $name, $size, $type, $error, $index) { - if (!getDolGlobalInt('MAIN_USE_JQUERY_FILEUPLOAD')) { - return null; - } - $file = new stdClass(); $file->name = $this->trimFileName($name, $type, $index); $file->mime = dol_mimetype($file->name, '', 2); @@ -513,10 +492,6 @@ class FileUpload */ public function get() { - if (!getDolGlobalInt('MAIN_USE_JQUERY_FILEUPLOAD')) { - return; - } - $file_name = isset($_REQUEST['file']) ? basename(stripslashes($_REQUEST['file'])) : null; if ($file_name) { @@ -535,10 +510,6 @@ class FileUpload */ public function post() { - if (!getDolGlobalInt('MAIN_USE_JQUERY_FILEUPLOAD')) { - return; - } - if (isset($_REQUEST['_method']) && $_REQUEST['_method'] === 'DELETE') { return $this->delete(); } @@ -594,10 +565,6 @@ class FileUpload */ public function delete() { - if (!getDolGlobalInt('MAIN_USE_JQUERY_FILEUPLOAD')) { - return null; - } - $file_name = isset($_REQUEST['file']) ? basename(stripslashes($_REQUEST['file'])) : null; $file_path = $this->options['upload_dir'].$file_name; diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 96aa566ab2e..cf512d5f173 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -191,23 +191,23 @@ class Form /** * Output value of a field for an editable field * - * @param string $text Text of label (not used in this function) - * @param string $htmlname Name of select field - * @param string $value Value to show/edit - * @param object $object Object (that we want to show) - * @param boolean $perm Permission to allow button to edit parameter - * @param string $typeofdata Type of data ('string' by default, 'email', 'amount:99', 'numeric:99', 'text' or 'textarea:rows:cols%', 'datepicker' ('day' do not work, don't know why), 'dayhour' or 'datehourpicker', 'ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols', 'select;xkey:xval,ykey:yval,...') - * @param string $editvalue When in edit mode, use this value as $value instead of value (for example, you can provide here a formated price instead of numeric value). Use '' to use same than $value - * @param object $extObject External object ??? - * @param mixed $custommsg String or Array of custom messages : eg array('success' => 'MyMessage', 'error' => 'MyMessage') - * @param string $moreparam More param to add on the form on action href URL parameter - * @param int $notabletag Do no output table tags - * @param string $formatfunc Call a specific function to output field in view mode (For example: 'dol_print_email') - * @param string $paramid Key of parameter for id ('id', 'socid') - * @param string $gm 'auto' or 'tzuser' or 'tzuserrel' or 'tzserver' (when $typeofdata is a date) - * @param array $moreoptions Array with more options. For example array('addnowlink'=>1), array('valuealreadyhtmlescaped'=>1) - * @param string $editaction [=''] use GETPOST default action or set action to edit mode - * @return string HTML edit field + * @param string $text Text of label (not used in this function) + * @param string $htmlname Name of select field + * @param string $value Value to show/edit + * @param object $object Object (that we want to show) + * @param boolean $perm Permission to allow button to edit parameter + * @param string $typeofdata Type of data ('string' by default, 'email', 'amount:99', 'numeric:99', 'text' or 'textarea:rows:cols%', 'datepicker' ('day' do not work, don't know why), 'dayhour' or 'datehourpicker', 'ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols', 'select;xkey:xval,ykey:yval,...') + * @param string $editvalue When in edit mode, use this value as $value instead of value (for example, you can provide here a formated price instead of numeric value, or a select combo). Use '' to use same than $value + * @param object $extObject External object ??? + * @param mixed $custommsg String or Array of custom messages : eg array('success' => 'MyMessage', 'error' => 'MyMessage') + * @param string $moreparam More param to add on the form on action href URL parameter + * @param int $notabletag Do no output table tags + * @param string $formatfunc Call a specific method of $object->$formatfunc to output field in view mode (For example: 'dol_print_email') + * @param string $paramid Key of parameter for id ('id', 'socid') + * @param string $gm 'auto' or 'tzuser' or 'tzuserrel' or 'tzserver' (when $typeofdata is a date) + * @param array $moreoptions Array with more options. For example array('addnowlink'=>1), array('valuealreadyhtmlescaped'=>1) + * @param string $editaction [=''] use GETPOST default action or set action to edit mode + * @return string HTML edit field */ public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 1, $formatfunc = '', $paramid = 'id', $gm = 'auto', $moreoptions = array(), $editaction = '') { @@ -310,6 +310,8 @@ class Form require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php'; $doleditor = new DolEditor($htmlname, ($editvalue ? $editvalue : $value), (empty($tmp[2]) ? '' : $tmp[2]), (empty($tmp[3]) ? '100' : $tmp[3]), (empty($tmp[1]) ? 'dolibarr_notes' : $tmp[1]), 'In', (empty($tmp[5]) ? 0 : $tmp[5]), (isset($tmp[8]) ? ($tmp[8] ? true : false) : true), true, (empty($tmp[6]) ? '20' : $tmp[6]), (empty($tmp[7]) ? '100' : $tmp[7])); $ret .= $doleditor->Create(1); + } elseif ($typeofdata == 'asis') { + $ret .= ($editvalue ? $editvalue : $value); } if (empty($notabletag)) { $ret .= ''; @@ -607,22 +609,22 @@ class Form } /** - * Show a text and picto with tooltip on text or picto. + * Show a text and picto with tooltip on text or picto. * Can be called by an instancied $form->textwithtooltip or by a static call Form::textwithtooltip * - * @param string $text Text to show - * @param string $htmltext HTML content of tooltip. Must be HTML/UTF8 encoded. - * @param int $tooltipon 1=tooltip on text, 2=tooltip on image, 3=tooltip sur les 2 - * @param int $direction -1=image is before, 0=no image, 1=image is after - * @param string $img Html code for image (use img_xxx() function to get it) - * @param string $extracss Add a CSS style to td tags - * @param int $notabs 0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span - * @param string $incbefore Include code before the text - * @param int $noencodehtmltext Do not encode into html entity the htmltext - * @param string $tooltiptrigger ''=Tooltip on hover, 'abc'=Tooltip on click (abc is a unique key) - * @param int $forcenowrap Force no wrap between text and picto (works with notabs=2 only) - * @return string Code html du tooltip (texte+picto) - * @see textwithpicto() Use thisfunction if you can. + * @param string $text Text to show + * @param string $htmltext HTML content of tooltip. Must be HTML/UTF8 encoded. + * @param int $tooltipon 1=tooltip on text, 2=tooltip on image, 3=tooltip sur les 2 + * @param int $direction -1=image is before, 0=no image, 1=image is after + * @param string $img Html code for image (use img_xxx() function to get it) + * @param string $extracss Add a CSS style to td tags + * @param int $notabs 0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span + * @param string $incbefore Include code before the text + * @param int $noencodehtmltext Do not encode into html entity the htmltext + * @param string $tooltiptrigger ''=Tooltip on hover, 'abc'=Tooltip on click (abc is a unique key) + * @param int $forcenowrap Force no wrap between text and picto (works with notabs=2 only) + * @return string Code html du tooltip (texte+picto) + * @see textwithpicto() Use thisfunction if you can. */ public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0) { @@ -723,16 +725,16 @@ class Form /** * Show a text with a picto and a tooltip on picto * - * @param string $text Text to show - * @param string $htmltext Content of tooltip - * @param int $direction 1=Icon is after text, -1=Icon is before text, 0=no icon - * @param string $type Type of picto ('info', 'infoclickable', 'help', 'helpclickable', 'warning', 'superadmin', 'mypicto@mymodule', ...) or image filepath or 'none' - * @param string $extracss Add a CSS style to td, div or span tag - * @param int $noencodehtmltext Do not encode into html entity the htmltext - * @param int $notabs 0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span - * @param string $tooltiptrigger ''=Tooltip on hover and hidden on smartphone, 'abconsmartphone'=Tooltip on hover and on click on smartphone, 'abc'=Tooltip on click (abc is a unique key, clickable link is on image or on link if param $type='none' or on both if $type='xxxclickable') - * @param int $forcenowrap Force no wrap between text and picto (works with notabs=2 only) - * @return string HTML code of text, picto, tooltip + * @param string $text Text to show + * @param string $htmltext Content of tooltip + * @param int $direction 1=Icon is after text, -1=Icon is before text, 0=no icon + * @param string $type Type of picto ('info', 'infoclickable', 'help', 'helpclickable', 'warning', 'superadmin', 'mypicto@mymodule', ...) or image filepath or 'none' + * @param string $extracss Add a CSS style to td, div or span tag + * @param int $noencodehtmltext Do not encode into html entity the htmltext + * @param int $notabs 0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span + * @param string $tooltiptrigger ''=Tooltip on hover and hidden on smartphone, 'abconsmartphone'=Tooltip on hover and on click on smartphone, 'abc'=Tooltip on click (abc is a unique key, clickable link is on image or on link if param $type='none' or on both if $type='xxxclickable') + * @param int $forcenowrap Force no wrap between text and picto (works with notabs=2 only) + * @return string HTML code of text, picto, tooltip */ public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = '', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0) { @@ -1953,25 +1955,25 @@ 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|string $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'). This value must not come from user input. - * @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 $notdisabled 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 - * @param int $forcecombo Force the component to be a simple combo box without ajax - * @return array|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|string $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|string $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'). This value must not come from user input. + * @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 $notdisabled 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 + * @param int $forcecombo Force the component to be a simple combo box without ajax + * @return array|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 = '', $notdisabled = 0, $outputmode = 0, $multiple = false, $forcecombo = 0) @@ -2011,6 +2013,7 @@ class Form $out = ''; $outarray = array(); + $outarray2 = array(); // Forge request to select users $sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut as status, u.login, u.admin, u.entity, u.photo"; @@ -2149,7 +2152,7 @@ class Form } } $moreinfo .= ($moreinfo ? ')' : ''); - $moreinfohtml .= ($moreinfohtml ? ')' : ''); + $moreinfohtml .= ($moreinfohtml ? ')' : ''); if ($disableline && $disableline != '1') { // Add text from $enableonlytext parameter $moreinfo .= ' - ' . $disableline; @@ -2180,6 +2183,11 @@ class Form $out .= ''; $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength) . $moreinfo; + $outarray2[$userstatic->id] = array( + 'id'=>$userstatic->id, + 'label'=>$labeltoshow, + 'labelhtml'=>$labeltoshowhtml + ); $i++; } @@ -2198,7 +2206,9 @@ class Form dol_print_error($this->db); } - if ($outputmode) { + if ($outputmode == 2) { + return $outarray2; + } elseif ($outputmode) { return $outarray; } @@ -2604,7 +2614,15 @@ class Form } $sql = "SELECT "; - $sql .= $selectFields . $selectFieldsGrouped; + + // Add select from hooks + $parameters = array(); + $reshook = $hookmanager->executeHooks('selectProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook + if (empty($reshook)) { + $sql .= $selectFields.$selectFieldsGrouped.$hookmanager->resPrint; + } else { + $sql .= $hookmanager->resPrint; + } if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY)) { //Product category @@ -2650,7 +2668,13 @@ class Form $sql .= " DESC LIMIT 1) as price_by_qty"; $selectFields .= ", price_rowid, price_by_qty"; } - $sql .= " FROM " . $this->db->prefix() . "product as p"; + + $sql .= " FROM ".$this->db->prefix()."product as p"; + // Add from (left join) from hooks + $parameters = array(); + $reshook = $hookmanager->executeHooks('selectProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook + $sql .= $hookmanager->resPrint; + if (count($warehouseStatusArray)) { $sql .= " LEFT JOIN " . $this->db->prefix() . "product_stock as ps on ps.fk_product = p.rowid"; $sql .= " LEFT JOIN " . $this->db->prefix() . "entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (" . getEntity('stock') . ")"; @@ -2922,6 +2946,7 @@ class Form protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0) { global $langs, $conf, $user; + global $hookmanager; $outkey = ''; $outval = ''; @@ -3207,6 +3232,14 @@ class Form } } + $parameters = array('objp'=>$objp); + $reshook = $hookmanager->executeHooks('constructProductListOption', $parameters); // Note that $action and $object may have been modified by hook + if (empty($reshook)) { + $opt .= $hookmanager->resPrint; + } else { + $opt = $hookmanager->resPrint; + } + $opt .= "\n"; $optJson = array( 'key' => $outkey, @@ -4877,6 +4910,8 @@ class Form print '' . $langs->trans("NoEstablishmentFound") . ''; } } + + return $num; } else { dol_print_error($this->db); return -1; @@ -5194,15 +5229,20 @@ class Form $more .= '
' . $input['label'] . '
'; $more .= '
'; $addnowlink = (empty($input['datenow']) ? 0 : 1); - $more .= $this->selectDate($input['value'], $input['name'], ($input['type'] == 'datetime' ? 1 : 0), ($input['type'] == 'datetime' ? 1 : 0), 0, '', 1, $addnowlink); - $more .= '
' . "\n"; - $formquestion[] = array('name' => $input['name'] . 'day'); - $formquestion[] = array('name' => $input['name'] . 'month'); - $formquestion[] = array('name' => $input['name'] . 'year'); - $formquestion[] = array('name' => $input['name'] . 'hour'); - $formquestion[] = array('name' => $input['name'] . 'min'); - } elseif ($input['type'] == 'other') { // can be 1 column or 2 depending if label is set or not - $more .= '
'; + $h = $m = 0; + if ($input['type'] == 'datetime') { + $h = isset($input['hours']) ? $input['hours'] : 1; + $m = isset($input['minutes']) ? $input['minutes'] : 1; + } + $more .= $this->selectDate($input['value'], $input['name'], $h, $m, 0, '', 1, $addnowlink); + $more .= '
'."\n"; + $formquestion[] = array('name'=>$input['name'].'day'); + $formquestion[] = array('name'=>$input['name'].'month'); + $formquestion[] = array('name'=>$input['name'].'year'); + $formquestion[] = array('name'=>$input['name'].'hour'); + $formquestion[] = array('name'=>$input['name'].'min'); + } elseif ($input['type'] == 'other') { // can be 1 column or 2 depending if label is set or not + $more .= '
'; if (!empty($input['label'])) { $more .= $input['label'] . '
'; } @@ -6989,7 +7029,12 @@ class Form if (empty($labeladddateof)) { $labeladddateof = $langs->trans("DateInvoice"); } - $retstring .= ' -
'; - - return $nbofdifferenttypes; } + + return $nbofdifferenttypes; } /** * Show block with links to link to other objects. * - * @param CommonObject $object Object we want to show links to - * @param array $restrictlinksto Restrict links to some elements, for exemple array('order') or array('supplier_order'). null or array() if no restriction. - * @param array $excludelinksto Do not show links of this type, for exemple array('order') or array('supplier_order'). null or array() if no exclusion. - * @return string <0 if KO, >0 if OK + * @param CommonObject $object Object we want to show links to + * @param array $restrictlinksto Restrict links to some elements, for exemple array('order') or array('supplier_order'). null or array() if no restriction. + * @param array $excludelinksto Do not show links of this type, for exemple array('order') or array('supplier_order'). null or array() if no exclusion. + * @return string HTML block */ public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array()) { @@ -9829,8 +9879,8 @@ class Form { $out = '
'; if ($pos == 'left') { - $out .= ''; $out .= ''; + $out .= ''; } else { $out .= ''; $out .= ''; diff --git a/htdocs/core/class/html.formaccounting.class.php b/htdocs/core/class/html.formaccounting.class.php index d12c5e5eb99..47dab9f6fda 100644 --- a/htdocs/core/class/html.formaccounting.class.php +++ b/htdocs/core/class/html.formaccounting.class.php @@ -451,7 +451,7 @@ class FormAccounting extends Form * @param string $labelhtmlname HTML name of label for autofill of account from name. * @return string String with HTML select */ - public function select_auxaccount($selectid, $htmlname = 'account_num_aux', $showempty = 0, $morecss = 'maxwidth250', $usecache = '', $labelhtmlname = '') + public function select_auxaccount($selectid, $htmlname = 'account_num_aux', $showempty = 0, $morecss = 'minwidth100 maxwidth300 maxwidthonsmartphone', $usecache = '', $labelhtmlname = '') { // phpcs:enable diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index 215e729a278..b9c4239d4dc 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -1457,10 +1457,13 @@ class FormFile if ($modulepart == 'medias' && !GETPOST('website')) { $moreparaminurl .= '&backtourl='.urlencode(DOL_URL_ROOT.'/ecm/index_medias.php?file_manager=1&modulepart='.$modulepart.'§ion_dir='.$relativepath); } - if ($modulepart == 'medias' && !GETPOST('website')) { - print ''.img_picto('', 'images', 'class="flip marginrightonly"').''; - } elseif ($modulepart == 'medias' && GETPOST('website')) { - print ''.img_picto('', 'images', 'class="flip marginrightonly"').''; + // Link to convert into webp + if (!preg_match('/\.webp$/i', $file['name'])) { + if ($modulepart == 'medias' && !GETPOST('website')) { + print ''.img_picto('', 'images', 'class="flip marginrightonly"').''; + } elseif ($modulepart == 'medias' && GETPOST('website')) { + print ''.img_picto('', 'images', 'class="flip marginrightonly"').''; + } } } } diff --git a/htdocs/core/class/html.formmail.class.php b/htdocs/core/class/html.formmail.class.php index e3a60fbf6ab..1eb3ec15f9f 100644 --- a/htdocs/core/class/html.formmail.class.php +++ b/htdocs/core/class/html.formmail.class.php @@ -1324,10 +1324,10 @@ class FormMail extends Form $sql .= " AND (lang = '".$dbs->escape($languagetosearch)."'".($languagetosearchmain ? " OR lang = '".$dbs->escape($languagetosearchmain)."'" : "")." OR lang IS NULL OR lang = '')"; } if ($id > 0) { - $sql .= " AND rowid=".(int) $id; + $sql .= " AND rowid = ".(int) $id; } if ($id == -1) { - $sql .= " AND position=0"; + $sql .= " AND position = 0"; } if ($languagetosearch) { $sql .= $dbs->order("position,lang,label", "ASC,DESC,ASC"); // We want line with lang set first, then with lang null or '' diff --git a/htdocs/core/class/html.formother.class.php b/htdocs/core/class/html.formother.class.php index 21e5b608a41..118e75773c1 100644 --- a/htdocs/core/class/html.formother.class.php +++ b/htdocs/core/class/html.formother.class.php @@ -1289,18 +1289,21 @@ class FormOther containment: \'document\', connectWith: \'#boxhalfleft, #boxhalfright\', stop: function(event, ui) { + console.log("We moved box so we call updateBoxOrder with ajax actions"); updateBoxOrder(1); /* 1 to avoid message after a move */ } }); jQuery(".boxclose").click(function() { var self = this; // because JQuery can modify this - var boxid=self.id.substring(8); - var label=jQuery(\'#boxlabelentry\'+boxid).val(); - console.log("We close box "+boxid); - jQuery(\'#boxto_\'+boxid).remove(); - if (boxid > 0) jQuery(\'#boxcombo\').append(new Option(label, boxid)); - updateBoxOrder(1); /* 1 to avoid message after a remove */ + var boxid = self.id.substring(8); + if (boxid > 0) { + var label = jQuery(\'#boxlabelentry\'+boxid).val(); + console.log("We close box "+boxid); + jQuery(\'#boxto_\'+boxid).remove(); + jQuery(\'#boxcombo\').append(new Option(label, boxid)); + updateBoxOrder(1); /* 1 to avoid message after a remove */ + } }); });'."\n"; diff --git a/htdocs/core/class/html.formsetup.class.php b/htdocs/core/class/html.formsetup.class.php index 13afc43cb51..a3908df0adb 100644 --- a/htdocs/core/class/html.formsetup.class.php +++ b/htdocs/core/class/html.formsetup.class.php @@ -834,6 +834,8 @@ class FormSetupItem $out.= $this->generateInputFieldMultiSelect(); } elseif ($this->type == 'select') { $out.= $this->generateInputFieldSelect(); + } elseif ($this->type == 'selectUser') { + $out.= $this->generateInputFieldSelectUser(); } elseif ($this->type == 'textarea') { $out.= $this->generateInputFieldTextarea(); } elseif ($this->type== 'html') { @@ -993,6 +995,14 @@ class FormSetupItem return $this->form->selectarray($this->confKey, $this->fieldOptions, $this->fieldValue); } + /** + * @return string + */ + public function generateInputFieldSelectUser() + { + return $this->form->select_dolusers($this->fieldValue, $this->confKey); + } + /** * get the type : used for old module builder setup conf style conversion and tests * because this two class will quickly evolve it's important to not set or get directly $this->type (will be protected) so this method exist @@ -1067,6 +1077,8 @@ class FormSetupItem $out.= $this->generateOutputFieldMultiSelect(); } elseif ($this->type == 'select') { $out.= $this->generateOutputFieldSelect(); + } elseif ($this->type == 'selectUser') { + $out.= $this->generateOutputFieldSelectUser(); } elseif ($this->type== 'html') { $out.= $this->fieldValue; } elseif ($this->type== 'color') { @@ -1136,6 +1148,8 @@ class FormSetupItem /** + * generateOutputFieldMultiSelect + * * @return string */ public function generateOutputFieldMultiSelect() @@ -1157,6 +1171,8 @@ class FormSetupItem } /** + * generateOutputFieldColor + * * @return string */ public function generateOutputFieldColor() @@ -1165,6 +1181,8 @@ class FormSetupItem return $this->generateInputField(); } /** + * generateInputFieldColor + * * @return string */ public function generateInputFieldColor() @@ -1174,6 +1192,8 @@ class FormSetupItem } /** + * generateOutputFieldSelect + * * @return string */ public function generateOutputFieldSelect() @@ -1186,12 +1206,27 @@ class FormSetupItem return $outPut; } + /** + * generateOutputFieldSelectUser + * + * @return string + */ + public function generateOutputFieldSelectUser() + { + $outPut = ''; + $user = new User($this->db); + $user->fetch($this->fieldValue); + $outPut = $user->firstname . " " . $user->lastname; + return $outPut; + } + /* * METHODS FOR SETTING DISPLAY TYPE */ /** * Set type of input as string + * * @return self */ public function setAsString() @@ -1202,6 +1237,7 @@ class FormSetupItem /** * Set type of input as color + * * @return self */ public function setAsColor() @@ -1212,6 +1248,7 @@ class FormSetupItem /** * Set type of input as textarea + * * @return self */ public function setAsTextarea() @@ -1222,6 +1259,7 @@ class FormSetupItem /** * Set type of input as html editor + * * @return self */ public function setAsHtml() @@ -1232,6 +1270,7 @@ class FormSetupItem /** * Set type of input as emailtemplate selector + * * @param string $templateType email template type * @return self */ @@ -1243,6 +1282,7 @@ class FormSetupItem /** * Set type of input as thirdparty_type selector + * * @return self */ public function setAsThirdpartyType() @@ -1253,6 +1293,7 @@ class FormSetupItem /** * Set type of input as Yes + * * @return self */ public function setAsYesNo() @@ -1263,6 +1304,7 @@ class FormSetupItem /** * Set type of input as secure key + * * @return self */ public function setAsSecureKey() @@ -1273,6 +1315,7 @@ class FormSetupItem /** * Set type of input as product + * * @return self */ public function setAsProduct() @@ -1284,6 +1327,7 @@ class FormSetupItem /** * Set type of input as a category selector * TODO add default value + * * @param int $catType Type of category ('customer', 'supplier', 'contact', 'product', 'member'). Old mode (0, 1, 2, ...) is deprecated. * @return self */ @@ -1294,8 +1338,8 @@ class FormSetupItem } /** - * Set type of input as a simple title - * no data to store + * Set type of input as a simple title. No data to store + * * @return self */ public function setAsTitle() @@ -1306,8 +1350,8 @@ class FormSetupItem /** - * Set type of input as a simple title - * no data to store + * Set type of input as a simple title. No data to store + * * @param array $fieldOptions A table of field options * @return self */ @@ -1322,8 +1366,8 @@ class FormSetupItem } /** - * Set type of input as a simple title - * no data to store + * Set type of input as a simple title. No data to store + * * @param array $fieldOptions A table of field options * @return self */ @@ -1336,4 +1380,15 @@ class FormSetupItem $this->type = 'select'; return $this; } + + /** + * Set type of input as a simple title. No data to store + * + * @return self + */ + public function setAsSelectUser() + { + $this->type = 'selectUser'; + return $this; + } } diff --git a/htdocs/core/class/html.formticket.class.php b/htdocs/core/class/html.formticket.class.php index 3f3a038b88c..2257e563865 100644 --- a/htdocs/core/class/html.formticket.class.php +++ b/htdocs/core/class/html.formticket.class.php @@ -701,7 +701,7 @@ class FormTicket { global $langs, $user; - $selected = is_array($selected) ? $selected : (!empty($selected) ? array($selected) : array()); + $selected = is_array($selected) ? $selected : (!empty($selected) ? explode(',', $selected) : array()); $ticketstat = new Ticket($this->db); dol_syslog(get_class($this) . "::select_types_tickets " . implode(';', $selected) . ", " . $htmlname . ", " . $filtertype . ", " . $format . ", " . $multiselect, LOG_DEBUG); diff --git a/htdocs/core/class/menubase.class.php b/htdocs/core/class/menubase.class.php index 3630d137136..2965db0f7c5 100644 --- a/htdocs/core/class/menubase.class.php +++ b/htdocs/core/class/menubase.class.php @@ -49,6 +49,11 @@ class Menubase */ public $id; + /** + * @var int Entity + */ + public $entity; + /** * @var string Menu handler */ @@ -185,6 +190,7 @@ class Menubase if (!isset($this->enabled)) { $this->enabled = '1'; } + $this->entity = (isset($this->entity) && (int) $this->entity >= 0 ? (int) $this->entity : $conf->entity); $this->menu_handler = trim((string) $this->menu_handler); $this->module = trim((string) $this->module); $this->type = trim((string) $this->type); @@ -246,7 +252,7 @@ class Menubase $sql .= " AND fk_menu = ".((int) $this->fk_menu); $sql .= " AND position = ".((int) $this->position); $sql .= " AND url = '".$this->db->escape($this->url)."'"; - $sql .= " AND entity = ".$conf->entity; + $sql .= " AND entity IN (0, ".$conf->entity.")"; $result = $this->db->query($sql); if ($result) { @@ -275,7 +281,7 @@ class Menubase $sql .= "usertype"; $sql .= ") VALUES ("; $sql .= " '".$this->db->escape($this->menu_handler)."',"; - $sql .= " '".$this->db->escape($conf->entity)."',"; + $sql .= " '".$this->db->escape($this->entity)."',"; $sql .= " '".$this->db->escape($this->module)."',"; $sql .= " '".$this->db->escape($this->type)."',"; $sql .= " ".($this->mainmenu ? "'".$this->db->escape($this->mainmenu)."'" : "''").","; // Can't be null diff --git a/htdocs/core/class/notify.class.php b/htdocs/core/class/notify.class.php index 3a668d3c0c6..d7bfd4a3f21 100644 --- a/htdocs/core/class/notify.class.php +++ b/htdocs/core/class/notify.class.php @@ -69,6 +69,7 @@ class Notify 'BILL_PAYED', 'ORDER_CREATE', 'ORDER_VALIDATE', + 'ORDER_CLOSE', 'PROPAL_VALIDATE', 'PROPAL_CLOSE_SIGNED', 'PROPAL_CLOSE_REFUSED', @@ -503,6 +504,13 @@ class Notify $labeltouse = $conf->global->ORDER_VALIDATE_TEMPLATE; $mesg = $outputlangs->transnoentitiesnoconv("EMailTextOrderValidated", $link); break; + case 'ORDER_CLOSE': + $link = ''.$newref.''; + $dir_output = $conf->commande->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'commande'); + $object_type = 'order'; + $labeltouse = $conf->global->ORDER_CLOSE_TEMPLATE; + $mesg = $outputlangs->transnoentitiesnoconv("EMailTextOrderClose", $link); + break; case 'PROPAL_VALIDATE': $link = ''.$newref.''; $dir_output = $conf->propal->multidir_output[$object->entity]."/".get_exdir(0, 0, 0, 1, $object, 'propal'); @@ -783,6 +791,12 @@ class Notify $object_type = 'order'; $mesg = $langs->transnoentitiesnoconv("EMailTextOrderValidated", $link); break; + case 'ORDER_CLOSE': + $link = ''.$newref.''; + $dir_output = $conf->commande->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'commande'); + $object_type = 'order'; + $mesg = $langs->transnoentitiesnoconv("EMailTextOrderClose", $link); + break; case 'PROPAL_VALIDATE': $link = ''.$newref.''; $dir_output = $conf->propal->multidir_output[$object->entity]."/".get_exdir(0, 0, 0, 1, $object, 'propal'); diff --git a/htdocs/core/class/smtps.class.php b/htdocs/core/class/smtps.class.php index 46193e1efea..c6eb249be5c 100644 --- a/htdocs/core/class/smtps.class.php +++ b/htdocs/core/class/smtps.class.php @@ -228,6 +228,7 @@ class SMTPs // @CHANGE LDR public $log = ''; + public $lastretval = ''; private $_errorsTo = ''; private $_deliveryReceipt = 0; private $_trackId = ''; @@ -564,7 +565,7 @@ class SMTPs // Most servers expect a 2nd pass of EHLO after TLS is established to get another time // the answer with list of supported AUTH methods. They may differs between non STARTTLS and with STARTTLS. if (! $_retVal = $this->socket_send_str('EHLO '.$hosth, '250')) { - $this->_setErr(126, '"'.$hosth.'" does not support authenticated connections. Error after sending EHLO '.$hosth); + $this->_setErr(126, '"'.$hosth.'" does not support authenticated connections or temporary error. Error after 2nd sending EHLO '.$hosth.' : '.$this->lastretval); return $_retVal; } } @@ -614,7 +615,7 @@ class SMTPs $this->_setErr(130, 'Invalid Authentication Credentials.'); } } else { - $this->_setErr(126, '"'.$host.'" does not support authenticated connections. Error after sending EHLO '.$hosth); + $this->_setErr(126, '"'.$host.'" does not support authenticated connections or temporary error. Error after sending EHLO '.$hosth.' : '.$this->lastretval); } return $_retVal; @@ -670,10 +671,11 @@ class SMTPs } } + // Send the HELO message to the SMTP server $_retVal = $this->socket_send_str('HELO '.$hosth, '250'); } - // Well, did we get to the server? + // Well, did we get the server answer with correct code ? if ($_retVal) { // From this point onward most server response codes should be 250 // Specify who the mail is from.... @@ -716,8 +718,11 @@ class SMTPs // Now tell the server we are done and close the socket... fputs($this->socket, 'QUIT'); - fclose($this->socket); + } else { + // We got error code into $this->lastretval } + + fclose($this->socket); } return $_retVal; @@ -1871,7 +1876,9 @@ class SMTPs * using SMTP Extensions * * @param resource $socket Socket handler - * @param string $response Response. Example: "550 5.7.1 https://support.google.com/a/answer/6140680#invalidcred j21sm814390wre.3" + * @param string $response Expected response ('250', ...). Example of response we can get: + * "421 4.7.0 Try again later, closing connection. (EHLO) nb21-20020a1709071c9500b0093d0d964affsm869534ejc.73 - gsmtp" + * "550 5.7.1 https://support.google.com/a/answer/6140680#invalidcred j21sm814390wre.3" * @return boolean True or false */ public function server_parse($socket, $response) @@ -1898,8 +1905,10 @@ class SMTPs $limit++; } + $this->lastretval = substr($server_response, 0, 3); + if (!(substr($server_response, 0, 3) == $response)) { - $this->_setErr(120, "Ran into problems sending Mail.\r\nResponse:".$server_response); + $this->_setErr(120, "Ran into problems sending Mail.\r\nResponse: ".$server_response); $_retVal = false; } @@ -1911,9 +1920,9 @@ class SMTPs * Send str * * @param string $_strSend String to send - * @param string $_returnCode Return code + * @param string $_returnCode Expected return code * @param string $CRLF CRLF - * @return boolean|null True or false + * @return boolean|null True or false */ public function socket_send_str($_strSend, $_returnCode = null, $CRLF = "\r\n") { @@ -1929,6 +1938,8 @@ class SMTPs if ($_returnCode) { return $this->server_parse($this->socket, $_returnCode); } + + return null; } // ============================================================= @@ -1950,7 +1961,7 @@ class SMTPs } /** - * Returns errors codes and messages for Class + * Returns applicative errors codes and messages for Class (not the SMTP error code) * * @return string $_errMsg Error Message */ diff --git a/htdocs/core/class/timespent.class.php b/htdocs/core/class/timespent.class.php index f6ae2b45c71..0f91b53e26a 100755 --- a/htdocs/core/class/timespent.class.php +++ b/htdocs/core/class/timespent.class.php @@ -752,10 +752,11 @@ class TimeSpent extends CommonObject $dataparams = ''; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { $classfortooltip = 'classforajaxtooltip'; - $dataparams = " data-params='".json_encode($params)."'"; - // $label = $langs->trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); $url = dol_buildpath('/timespent/timespent_card.php', 1).'?id='.$this->id; @@ -776,7 +777,7 @@ class TimeSpent extends CommonObject $label = $langs->trans("ShowTimeSpent"); $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; } - $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"'); $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"'; } else { $linkclose = ($morecss ? ' class="'.$morecss.'"' : ''); diff --git a/htdocs/core/class/vcard.class.php b/htdocs/core/class/vcard.class.php index 7b5a320f678..0bb532e33c4 100644 --- a/htdocs/core/class/vcard.class.php +++ b/htdocs/core/class/vcard.class.php @@ -421,6 +421,9 @@ class vCard if (!empty($object->socialnetworks)) { foreach ($object->socialnetworks as $key => $val) { + if (empty($val)) { // Disacard social network if empty + continue; + } $urlsn = ''; if ($key == 'linkedin') { if (!preg_match('/^http/', $val)) { diff --git a/htdocs/core/db/mysqli.class.php b/htdocs/core/db/mysqli.class.php index 593fa770536..e36fc547fa0 100644 --- a/htdocs/core/db/mysqli.class.php +++ b/htdocs/core/db/mysqli.class.php @@ -935,17 +935,17 @@ class DoliDBMysqli extends DoliDB if ($field_desc['null'] == 'not null' || $field_desc['null'] == 'NOT NULL') { // We will try to change format of column to NOT NULL. To be sure the ALTER works, we try to update fields that are NULL if ($field_desc['type'] == 'varchar' || $field_desc['type'] == 'text') { - $sqlbis = "UPDATE ".$table." SET ".$field_name." = '".$this->escape($field_desc['default'] ? $field_desc['default'] : '')."' WHERE ".$field_name." IS NULL"; + $sqlbis = "UPDATE ".$table." SET ".$field_name." = '".$this->escape(isset($field_desc['default']) ? $field_desc['default'] : '')."' WHERE ".$field_name." IS NULL"; $this->query($sqlbis); } elseif ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') { - $sqlbis = "UPDATE ".$table." SET ".$field_name." = ".((int) $this->escape($field_desc['default'] ? $field_desc['default'] : 0))." WHERE ".$field_name." IS NULL"; + $sqlbis = "UPDATE ".$table." SET ".$field_name." = ".((int) $this->escape(isset($field_desc['default']) ? $field_desc['default'] : 0))." WHERE ".$field_name." IS NULL"; $this->query($sqlbis); } $sql .= " NOT NULL"; } - if ($field_desc['default'] != '') { + if (isset($field_desc['default']) && $field_desc['default'] != '') { if ($field_desc['type'] == 'double' || $field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') { $sql .= " DEFAULT ".$this->escape($field_desc['default']); } elseif ($field_desc['type'] != 'text') { diff --git a/htdocs/core/db/pgsql.class.php b/htdocs/core/db/pgsql.class.php index 069afeca4ff..fb18ed0f161 100644 --- a/htdocs/core/db/pgsql.class.php +++ b/htdocs/core/db/pgsql.class.php @@ -1183,7 +1183,7 @@ class DoliDBPgsql extends DoliDB $sql = "ALTER TABLE ".$table." ADD ".$field_name." "; $sql .= $field_desc['type']; if (preg_match("/^[^\s]/i", $field_desc['value'])) { - if (!in_array($field_desc['type'], array('int', 'date', 'datetime')) && $field_desc['value']) { + if (!in_array($field_desc['type'], array('smallint', 'int', 'date', 'datetime')) && $field_desc['value']) { $sql .= "(".$field_desc['value'].")"; } } @@ -1225,23 +1225,25 @@ class DoliDBPgsql extends DoliDB { // phpcs:enable $sql = "ALTER TABLE ".$table; - $sql .= " MODIFY COLUMN ".$field_name." ".$field_desc['type']; - if (in_array($field_desc['type'], array('double', 'varchar')) && $field_desc['value']) { - $sql .= "(".$field_desc['value'].")"; + $sql .= " ALTER COLUMN ".$this->escape($field_name)." TYPE ".$field_desc['type']; + if (preg_match("/^[^\s]/i", $field_desc['value'])) { + if (!in_array($field_desc['type'], array('smallint', 'int', 'date', 'datetime')) && $field_desc['value']) { + $sql .= "(".$field_desc['value'].")"; + } } if ($field_desc['null'] == 'not null' || $field_desc['null'] == 'NOT NULL') { // We will try to change format of column to NOT NULL. To be sure the ALTER works, we try to update fields that are NULL if ($field_desc['type'] == 'varchar' || $field_desc['type'] == 'text') { - $sqlbis = "UPDATE ".$table." SET ".$field_name." = '".$this->escape($field_desc['default'] ? $field_desc['default'] : '')."' WHERE ".$field_name." IS NULL"; + $sqlbis = "UPDATE ".$table." SET ".$this->escape($field_name)." = '".$this->escape(isset($field_desc['default']) ? $field_desc['default'] : '')."' WHERE ".$this->escape($field_name)." IS NULL"; $this->query($sqlbis); } elseif ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') { - $sqlbis = "UPDATE ".$table." SET ".$field_name." = ".((int) $this->escape($field_desc['default'] ? $field_desc['default'] : 0))." WHERE ".$field_name." IS NULL"; + $sqlbis = "UPDATE ".$table." SET ".$this->escape($field_name)." = ".((int) $this->escape(isset($field_desc['default']) ? $field_desc['default'] : 0))." WHERE ".$this->escape($field_name)." IS NULL"; $this->query($sqlbis); } } - if ($field_desc['default'] != '') { + if (isset($field_desc['default']) && $field_desc['default'] != '') { if ($field_desc['type'] == 'double' || $field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') { $sql .= " DEFAULT ".$this->escape($field_desc['default']); } elseif ($field_desc['type'] != 'text') { diff --git a/htdocs/core/js/lib_foot.js.php b/htdocs/core/js/lib_foot.js.php index 963e357199a..297a33b93f5 100644 --- a/htdocs/core/js/lib_foot.js.php +++ b/htdocs/core/js/lib_foot.js.php @@ -85,12 +85,13 @@ if (empty($conf->dol_no_mouse_hover)) { tooltipClass: "mytooltip", open: function (event, ui) { var elem = $(this); - var params = $(this).attr("data-params"); + var params = JSON.parse($(this).attr("data-params")); + params.token = "'.currentToken().'"; $.ajax({ url:"' . dol_buildpath('/core/ajax/ajaxtooltip.php', 1) . '", type: "post", async: false, - data: JSON.parse(params), + data: params, success: function(response){ // Setting content option elem.tooltip("option","content",response); diff --git a/htdocs/core/js/lib_head.js.php b/htdocs/core/js/lib_head.js.php index 8c4d958abac..d721ec78873 100644 --- a/htdocs/core/js/lib_head.js.php +++ b/htdocs/core/js/lib_head.js.php @@ -1292,21 +1292,4 @@ $(document).ready(function() { }); -/* - * Hacky fix for a bug in select2 with jQuery 3.6.0's new nested-focus "protection" - * see: https://github.com/select2/select2/issues/5993 - * see: https://github.com/jquery/jquery/issues/4382 - * - * TODO: Recheck with the select2 GH issue and remove once this is fixed on their side - */ -$(document).on('select2:open', () => { - console.log("Execute the focus (click on combo or use space when on component"); - let allFound = document.querySelectorAll('.select2-container--open .select2-search__field'); - $(this).one('mouseup keyup',()=>{ - setTimeout(()=>{ - allFound[allFound.length - 1].focus(); - },0); - }); -}); - // End of lib_head.js.php diff --git a/htdocs/core/lib/admin.lib.php b/htdocs/core/lib/admin.lib.php index 04a04ee8cac..0064fad3bc7 100644 --- a/htdocs/core/lib/admin.lib.php +++ b/htdocs/core/lib/admin.lib.php @@ -1716,7 +1716,7 @@ function form_constantes($tableau, $strictw3c = 0, $helptext = '', $text = 'Valu print ''; - // Show constant + // Show label of parameter print ''; if (empty($strictw3c)) { print ''; @@ -1725,8 +1725,11 @@ function form_constantes($tableau, $strictw3c = 0, $helptext = '', $text = 'Valu print ''; print ''; print ''; - - print ($label ? $label : $langs->trans('Desc'.$const)); + if (!empty($tableau[$key]['tooltip'])) { + print $form->textwithpicto($label ? $label : $langs->trans('Desc'.$const), $tableau[$key]['tooltip']); + } else { + print ($label ? $label : $langs->trans('Desc'.$const)); + } if ($const == 'ADHERENT_MAILMAN_URL') { print '. '.$langs->trans("Example").': '.img_down().'
'; diff --git a/htdocs/core/lib/ajax.lib.php b/htdocs/core/lib/ajax.lib.php index fde2a988cf7..043d9e6e18e 100644 --- a/htdocs/core/lib/ajax.lib.php +++ b/htdocs/core/lib/ajax.lib.php @@ -696,8 +696,8 @@ function ajax_constantonoff($code, $input = array(), $entity = null, $revertonof * @param Object $object Object to set * @param string $code Name of property in object : 'status' or 'status_buy' for product by example * @param string $field Name of database field : 'tosell' or 'tobuy' for product by example - * @param string $text_on Text if on - * @param string $text_off Text if off + * @param string $text_on Text if on ('Text' or 'Text:css picto on') + * @param string $text_off Text if off ('Text' or 'Text:css picto on') * @param array $input Array of type->list of CSS element to switch. Example: array('disabled'=>array(0=>'cssid')) * @param string $morecss More CSS * @param string $htmlname Name of HTML component. Keep '' or use a different value if you need to use this component several time on same page for same property. @@ -710,6 +710,7 @@ function ajax_object_onoff($object, $code, $field, $text_on, $text_off, $input = if (empty($htmlname)) { $htmlname = $code; } + //var_dump($object->module); var_dump($object->element); $out = ''; - $out .= ''.img_picto($langs->trans($text_off), 'switch_off').''; - $out .= ''.img_picto($langs->trans($text_on), 'switch_on').''; + + $switchon = 'switch_on'; + $switchoff = 'switch_off'; + $tmparray = explode(':', $text_on); + if (!empty($tmparray[1])) { + $text_on = $tmparray[0]; + $switchon = $tmparray[1]; + } + $tmparray = explode(':', $text_off); + if (!empty($tmparray[1])) { + $text_off = $tmparray[0]; + $switchoff = $tmparray[1]; + } + + $out .= ''.img_picto($langs->trans($text_off), $switchoff).''; + $out .= ''.img_picto($langs->trans($text_on), $switchon).''; return $out; } diff --git a/htdocs/core/lib/company.lib.php b/htdocs/core/lib/company.lib.php index 04874dd9d90..e2e10a8de48 100644 --- a/htdocs/core/lib/company.lib.php +++ b/htdocs/core/lib/company.lib.php @@ -1380,7 +1380,7 @@ function show_contacts($conf, $langs, $db, $object, $backtopage = '', $showuserl // Birthday if (!empty($arrayfields['t.birthday']['checked'])) { print ''; - print dol_print_date($obj->birthday); + print dol_print_date($db->jdate($obj->birthday)); print ''; } @@ -2297,3 +2297,109 @@ function addMailingEventTypeSQL($actioncode, $objcon, $filterobj) return ''; } } + + + +/** + * Show footer of company in HTML pages + * + * @param Societe $fromcompany Third party + * @param Translate $langs Output language + * @param int $addformmessage Add the payment form message + * @param string $suffix Suffix to use on constants + * @param Object $object Object related to payment + * @return void + */ +function htmlPrintOnlineFooter($fromcompany, $langs, $addformmessage = 0, $suffix = '', $object = null) +{ + global $conf; + + $reg = array(); + + // Juridical status + $line1 = ""; + if ($fromcompany->forme_juridique_code) { + $line1 .= ($line1 ? " - " : "").getFormeJuridiqueLabel($fromcompany->forme_juridique_code); + } + // Capital + if ($fromcompany->capital) { + $line1 .= ($line1 ? " - " : "").$langs->transnoentities("CapitalOf", $fromcompany->capital)." ".$langs->transnoentities("Currency".$conf->currency); + } + // Prof Id 1 + if ($fromcompany->idprof1 && ($fromcompany->country_code != 'FR' || !$fromcompany->idprof2)) { + $field = $langs->transcountrynoentities("ProfId1", $fromcompany->country_code); + if (preg_match('/\((.*)\)/i', $field, $reg)) { + $field = $reg[1]; + } + $line1 .= ($line1 ? " - " : "").$field.": ".$fromcompany->idprof1; + } + // Prof Id 2 + if ($fromcompany->idprof2) { + $field = $langs->transcountrynoentities("ProfId2", $fromcompany->country_code); + if (preg_match('/\((.*)\)/i', $field, $reg)) { + $field = $reg[1]; + } + $line1 .= ($line1 ? " - " : "").$field.": ".$fromcompany->idprof2; + } + + // Second line of company infos + $line2 = ""; + // Prof Id 3 + if ($fromcompany->idprof3) { + $field = $langs->transcountrynoentities("ProfId3", $fromcompany->country_code); + if (preg_match('/\((.*)\)/i', $field, $reg)) { + $field = $reg[1]; + } + $line2 .= ($line2 ? " - " : "").$field.": ".$fromcompany->idprof3; + } + // Prof Id 4 + if ($fromcompany->idprof4) { + $field = $langs->transcountrynoentities("ProfId4", $fromcompany->country_code); + if (preg_match('/\((.*)\)/i', $field, $reg)) { + $field = $reg[1]; + } + $line2 .= ($line2 ? " - " : "").$field.": ".$fromcompany->idprof4; + } + // IntraCommunautary VAT + if ($fromcompany->tva_intra != '') { + $line2 .= ($line2 ? " - " : "").$langs->transnoentities("VATIntraShort").": ".$fromcompany->tva_intra; + } + + print ''."\n"; + + print '
'."\n"; + print '
'; + if ($addformmessage) { + print ''; + print '
'; + + $parammessageform = 'ONLINE_PAYMENT_MESSAGE_FORM_'.$suffix; + if (!empty($conf->global->$parammessageform)) { + print $langs->transnoentities($conf->global->$parammessageform); + } elseif (!empty($conf->global->ONLINE_PAYMENT_MESSAGE_FORM)) { + print $langs->transnoentities($conf->global->ONLINE_PAYMENT_MESSAGE_FORM); + } + + // Add other message if VAT exists + if (!empty($object->total_vat) || !empty($object->total_tva)) { + $parammessageform = 'ONLINE_PAYMENT_MESSAGE_FORMIFVAT_'.$suffix; + if (!empty($conf->global->$parammessageform)) { + print $langs->transnoentities($conf->global->$parammessageform); + } elseif (!empty($conf->global->ONLINE_PAYMENT_MESSAGE_FORMIFVAT)) { + print $langs->transnoentities($conf->global->ONLINE_PAYMENT_MESSAGE_FORMIFVAT); + } + } + } + + print '

'."\n"; + print $fromcompany->name.'
'; + print $line1; + if (strlen($line1.$line2) > 50) { + print '
'; + } else { + print ' - '; + } + print $line2; + print '
'; + print '
'."\n"; +} diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 60adcc64003..d0c2d9998b4 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -5,6 +5,7 @@ * Copyright (C) 2015 Marcos García * Copyright (C) 2016 Raphaël Doursenaud * Copyright (C) 2019 Frédéric France + * Copyright (C) 2023 Lenin Rivas * * 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 @@ -707,12 +708,14 @@ function dolReplaceInFile($srcfile, $arrayreplacement, $destfile = '', $newmask * @param string $destfile Destination file (can't be a directory) * @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 int $testvirus Do an antivirus test. Move is canceled if a virus is found. + * @param int $indexdatabase Index new file into database. * @return int <0 if error, 0 if nothing done (dest file already exists and overwriteifexists=0), >0 if OK * @see dol_delete_file() dolCopyDir() */ -function dol_copy($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1) +function dol_copy($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1, $testvirus = 0, $indexdatabase = 0) { - global $conf; + global $conf, $db, $user; dol_syslog("files.lib.php::dol_copy srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwriteifexists=".$overwriteifexists); @@ -737,6 +740,17 @@ function dol_copy($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1) dol_syslog("files.lib.php::dol_copy failed Permission denied to write into target directory ".$newdirdestfile, LOG_WARNING); return -2; } + + // Check virus + $testvirusarray = array(); + if ($testvirus) { + $testvirusarray = dolCheckVirus($srcfile); + if (count($testvirusarray)) { + dol_syslog("files.lib.php::dol_copy canceled because a virus was found into source file. we ignore the copy request.", LOG_WARNING); + return -3; + } + } + // Copy with overwriting if exists $result = @copy($newpathofsrcfile, $newpathofdestfile); //$result=copy($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @ @@ -754,7 +768,64 @@ function dol_copy($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1) dolChmod($newpathofdestfile, $newmask); - return 1; + if ($result && $indexdatabase) { + // Add entry into ecm database + $rel_filetocopyafter = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $newpathofdestfile); + if (!preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filetocopyafter)) { // If not a tmp file + $rel_filetocopyafter = preg_replace('/^[\\/]/', '', $rel_filetocopyafter); + //var_dump($rel_filetorenamebefore.' - '.$rel_filetocopyafter);exit; + + dol_syslog("Try to copy also entries in database for: ".$rel_filetocopyafter, LOG_DEBUG); + include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php'; + + $ecmfiletarget = new EcmFiles($db); + $resultecmtarget = $ecmfiletarget->fetch(0, '', $rel_filetocopyafter); + if ($resultecmtarget > 0) { // An entry for target name already exists for target, we delete it, a new one will be created. + dol_syslog("ECM dest file found, remove it", LOG_DEBUG); + $ecmfiletarget->delete($user); + } else { + dol_syslog("ECM dest file not found, create it", LOG_DEBUG); + } + + $ecmSrcfile = new EcmFiles($db); + $resultecm = $ecmSrcfile->fetch(0, '', $srcfile); + if ($resultecm) { + dol_syslog("Fetch src file ok", LOG_DEBUG); + } else { + dol_syslog("Fetch src file error", LOG_DEBUG); + } + + $ecmfile = new EcmFiles($db); + $filename = basename($rel_filetocopyafter); + $rel_dir = dirname($rel_filetocopyafter); + $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir); + $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir); + + $ecmfile->filepath = $rel_dir; + $ecmfile->filename = $filename; + $ecmfile->label = md5_file(dol_osencode($destfile)); // $destfile is a full path to file + $ecmfile->fullpath_orig = $srcfile; + $ecmfile->gen_or_uploaded = 'copy'; + $ecmfile->description = $ecmSrcfile->description; + $ecmfile->keywords = $ecmSrcfile->keywords; + $resultecm = $ecmfile->create($user); + if ($resultecm < 0) { + dol_syslog("Create ECM file ok", LOG_DEBUG); + setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings'); + } else { + dol_syslog("Create ECM file error", LOG_DEBUG); + setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings'); + } + + if ($resultecm > 0) { + $result = 1; + } else { + $result = -1; + } + } + } + + return $result; } /** @@ -2488,6 +2559,10 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, if ($modulepart == 'tva') { $modulepart = 'tax-vat'; } + // Fix modulepart delivery + if ($modulepart == 'expedition' && strpos($original_file, 'receipt/') === 0) { + $modulepart = 'delivery'; + } //print 'dol_check_secure_access_document modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity; dol_syslog('dol_check_secure_access_document modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity); @@ -2901,7 +2976,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } $original_file = $conf->commande->multidir_output[$entity].'/'.$original_file; $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('order').")"; - } elseif ($modulepart == 'project' && !empty($conf->project->dir_output)) { + } elseif ($modulepart == 'project' && !empty($conf->project->multidir_output[$entity])) { // Wrapping pour les projets if ($fuser->hasRight('projet', $lire) || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; @@ -2913,9 +2988,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, $accessallowed = checkUserAccessToObject($user, array('projet'), $tmpproject->id, 'projet&project', '', '', 'rowid', ''); } } - $original_file = $conf->project->dir_output.'/'.$original_file; + $original_file = $conf->project->multidir_output[$entity].'/'.$original_file; $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")"; - } elseif ($modulepart == 'project_task' && !empty($conf->project->dir_output)) { + } elseif ($modulepart == 'project_task' && !empty($conf->project->multidir_output[$entity])) { if ($fuser->hasRight('projet', $lire) || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; // If we known $id of project, call checkUserAccessToObject to check permission on properties and contact of project @@ -2926,7 +3001,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, $accessallowed = checkUserAccessToObject($user, array('projet_task'), $tmptask->id, 'projet_task&project', '', '', 'rowid', ''); } } - $original_file = $conf->project->dir_output.'/'.$original_file; + $original_file = $conf->project->multidir_output[$entity].'/'.$original_file; $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")"; } elseif (($modulepart == 'commande_fournisseur' || $modulepart == 'order_supplier') && !empty($conf->fournisseur->commande->dir_output)) { // Wrapping pour les commandes fournisseurs @@ -2970,14 +3045,14 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, if ($fuser->hasRight('expedition', $lire) || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } - $original_file = $conf->expedition->dir_output."/".(strpos('sending/', $original_file) === 0 ? '' : 'sending/').$original_file; + $original_file = $conf->expedition->dir_output."/".(strpos($original_file, 'sending/') === 0 ? '' : 'sending/').$original_file; //$original_file = $conf->expedition->dir_output."/".$original_file; } elseif (($modulepart == 'livraison' || $modulepart == 'delivery') && !empty($conf->expedition->dir_output)) { // Delivery Note Wrapping if ($fuser->hasRight('expedition', 'delivery', $lire) || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } - $original_file = $conf->expedition->dir_output."/".(strpos('receipt/', $original_file) === 0 ? '' : 'receipt/').$original_file; + $original_file = $conf->expedition->dir_output."/".(strpos($original_file, 'receipt/') === 0 ? '' : 'receipt/').$original_file; } elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output)) { // Wrapping pour les actions if ($fuser->hasRight('agenda', 'myactions', $read) || preg_match('/^specimen/i', $original_file)) { @@ -3129,41 +3204,45 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, // Define $accessallowed $reg = array(); if (preg_match('/^([a-z]+)_user_temp$/i', $modulepart, $reg)) { - if (empty($conf->{$reg[1]}->dir_temp)) { // modulepart not supported + $tmpmodule = $reg[1]; + if (empty($conf->$tmpmodule->dir_temp)) { // 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} || $fuser->rights->{$reg[1]}->{$read} || ($fuser->rights->{$reg[1]}->{$download})) { + if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) { $accessallowed = 1; } $original_file = $conf->{$reg[1]}->dir_temp.'/'.$fuser->id.'/'.$original_file; } elseif (preg_match('/^([a-z]+)_temp$/i', $modulepart, $reg)) { - if (empty($conf->{$reg[1]}->dir_temp)) { // modulepart not supported + $tmpmodule = $reg[1]; + if (empty($conf->$tmpmodule->dir_temp)) { // 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} || $fuser->rights->{$reg[1]}->{$read} || ($fuser->rights->{$reg[1]}->{$download})) { + if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) { $accessallowed = 1; } - $original_file = $conf->{$reg[1]}->dir_temp.'/'.$original_file; + $original_file = $conf->$tmpmodule->dir_temp.'/'.$original_file; } elseif (preg_match('/^([a-z]+)_user$/i', $modulepart, $reg)) { - if (empty($conf->{$reg[1]}->dir_output)) { // modulepart not supported + $tmpmodule = $reg[1]; + if (empty($conf->$tmpmodule->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} || $fuser->rights->{$reg[1]}->{$read} || ($fuser->rights->{$reg[1]}->{$download})) { + if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) { $accessallowed = 1; } - $original_file = $conf->{$reg[1]}->dir_output.'/'.$fuser->id.'/'.$original_file; + $original_file = $conf->$tmpmodule->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 + $tmpmodule = $reg[1]; + if (empty($conf->$tmpmodule->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)) { + if ($fuser->hasRight($tmpmodule, $lire) || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } - $original_file = $conf->{$reg[1]}->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; + $original_file = $conf->$tmpmodule->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.'). The module for this modulepart value may not be activated.'); @@ -3178,7 +3257,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, $accessallowed = 1; } } - if (!empty($fuser->rights->$modulepart->{$lire}) || !empty($fuser->rights->$modulepart->{$read})) { + if ($fuser->hasRight($modulepart, $lire) || $fuser->hasRight($modulepart, $read)) { $accessallowed = 1; } @@ -3316,3 +3395,87 @@ function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '', $pathre return $file_list; } + +/** + * Function to manage the drag and drop of a file. + * We use global variable $object + * + * @param string $htmlname The id of the component where we need to drag and drop + * @return string Js script to display + */ +function dragAndDropFileUpload($htmlname) +{ + global $object, $langs; + + $out = ""; + $out .= ''; + $out .= "\n\n"; + $out .= "\n"; + return $out; +} diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 24dafa06f69..2da236006c0 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -210,7 +210,8 @@ function getEntity($element, $shared = 1, $currentobject = null) { global $conf, $mc, $hookmanager, $object, $action, $db; - if (! is_object($hookmanager)) { + if (!is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; $hookmanager = new HookManager($db); } @@ -535,6 +536,7 @@ function GETPOSTISARRAY($paramname, $method = 0) * 'alphanohtml'=check there is no html content and no " and no ../ * 'aZ'=check it's a-z only * 'aZ09'=check it's simple alpha string (recommended for keys) + * 'aZ09arobase'=check it's a string for an element type * 'aZ09comma'=check it's a string for a sortfield or sortorder * 'san_alpha'=Use filter_var with FILTER_SANITIZE_STRING (do not use this for free text string) * 'nohtml'=check there is no html content @@ -617,7 +619,7 @@ function GETPOST($paramname, $check = 'alphanohtml', $method = 0, $filter = null } } if (!empty($conf->global->MAIN_ENABLE_DEFAULT_VALUES)) { - if (!empty($_GET['action']) && (preg_match('/^create/', $_GET['action']) || preg_match('/^presend/', $_GET['action'])) && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) { + if (!empty($_GET['action']) && (preg_match('/^create|^add_price|^make/', $_GET['action']) || preg_match('/^presend/', $_GET['action'])) && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) { // Now search in setup to overwrite default values if (!empty($user->default_values)) { // $user->default_values defined from menu 'Setup - Default values' if (isset($user->default_values[$relativepathstring]['createform'])) { @@ -934,6 +936,14 @@ function sanitizeVal($out = '', $check = 'alphanohtml', $filter = null, $options } } break; + case 'aZ09arobase': // great to sanitize objecttype parameter + if (!is_array($out)) { + $out = trim($out); + if (preg_match('/[^a-z0-9_\-\.@]+/i', $out)) { + $out = ''; + } + } + break; case 'aZ09comma': // great to sanitize sortfield or sortorder params that can be t.abc,t.def_gh if (!is_array($out)) { $out = trim($out); @@ -1651,7 +1661,7 @@ function dol_ucwords($string, $encoding = "UTF-8") * On Windows LOG_ERR=4, LOG_WARNING=5, LOG_NOTICE=LOG_INFO=6, LOG_DEBUG=6 si define_syslog_variables ou PHP 5.3+, 7 si dolibarr * On Linux LOG_ERR=3, LOG_WARNING=4, LOG_NOTICE=5, LOG_INFO=6, LOG_DEBUG=7 * @param int $ident 1=Increase ident of 1 (after log), -1=Decrease ident of 1 (before log) - * @param string $suffixinfilename When output is a file, append this suffix into default log filename. + * @param string $suffixinfilename When output is a file, append this suffix into default log filename. Example '_stripe', '_mail' * @param string $restricttologhandler Force output of log only to this log handler * @param array|null $logcontext If defined, an array with extra informations (can be used by some log handlers) * @return void @@ -1890,9 +1900,10 @@ function dol_fiche_head($links = array(), $active = '0', $title = '', $notab = 0 * @param string $morecss More CSS on the link * @param int $limittoshow Limit number of tabs to show. Use 0 to use automatic default value. * @param string $moretabssuffix A suffix to use when you have several dol_get_fiche_head() in same page + * @param int $dragdropfile 0 (default) or 1. 1 enable a drop zone for file to be upload, 0 disable it * @return string */ -function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '') +function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '', $dragdropfile = 0) { global $conf, $langs, $hookmanager; @@ -2058,9 +2069,11 @@ function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab } if (!$notab || $notab == -1 || $notab == -2 || $notab == -3) { - $out .= "\n".'
'."\n"; + $out .= "\n".'
'."\n"; + } + if (!empty($dragdropfile)) { + $out .= dragAndDropFileUpload("dragDropAreaTabBar"); } - $parameters = array('tabname' => $active, 'out' => $out); $reshook = $hookmanager->executeHooks('printTabsHead', $parameters); // This hook usage is called just before output the head of tabs. Take also a look at "completeTabsHead" if ($reshook > 0) { @@ -4118,9 +4131,9 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ if (empty($srconly) && in_array($pictowithouttext, array( '1downarrow', '1uparrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected', 'accountancy', 'accounting_account', 'account', 'accountline', 'action', 'add', 'address', 'angle-double-down', 'angle-double-up', 'asset', - 'bank_account', 'barcode', 'bank', 'bell', 'bill', 'billa', 'billr', 'billd', 'bookmark', 'bom', 'briefcase-medical', 'bug', 'building', + 'bank_account', 'barcode', 'bank', 'bell', 'bill', 'billa', 'billr', 'billd', 'birthday-cake', 'bookmark', 'bom', 'briefcase-medical', 'bug', 'building', 'card', 'calendarlist', 'calendar', 'calendarmonth', 'calendarweek', 'calendarday', 'calendarperuser', 'calendarpertype', - 'cash-register', 'category', 'chart', 'check', 'clock', 'close_title', 'cog', 'collab', 'company', 'contact', 'country', 'contract', 'conversation', 'cron', 'cubes', + 'cash-register', 'category', 'chart', 'check', 'clock', 'close_title', 'cog', 'collab', 'company', 'contact', 'country', 'contract', 'conversation', 'cron', 'cross', 'cubes', 'currency', 'multicurrency', 'delete', 'dolly', 'dollyrevert', 'donation', 'download', 'dynamicprice', 'edit', 'ellipsis-h', 'email', 'entity', 'envelope', 'eraser', 'establishment', 'expensereport', 'external-link-alt', 'external-link-square-alt', 'eye', @@ -4134,7 +4147,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ 'off', 'on', 'order', 'paiment', 'paragraph', 'play', 'pdf', 'phone', 'phoning', 'phoning_mobile', 'phoning_fax', 'playdisabled', 'previous', 'poll', 'pos', 'printer', 'product', 'propal', 'proposal', 'puce', 'stock', 'resize', 'service', 'stats', 'trip', - 'security', 'setup', 'share-alt', 'sign-out', 'split', 'stripe', 'stripe-s', 'switch_off', 'switch_on', 'switch_on_red', 'tools', 'unlink', 'uparrow', 'user', 'user-tie', 'vcard', 'wrench', + 'security', 'setup', 'share-alt', 'sign-out', 'split', 'stripe', 'stripe-s', 'switch_off', 'switch_on', 'switch_on_warning', 'switch_on_red', 'tools', 'unlink', 'uparrow', 'user', 'user-tie', 'vcard', 'wrench', 'github', 'google', 'jabber', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'youtube', 'google-plus-g', 'whatsapp', 'chevron-left', 'chevron-right', 'chevron-down', 'chevron-top', 'commercial', 'companies', 'generic', 'home', 'hrm', 'members', 'products', 'invoicing', @@ -4166,7 +4179,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ 'bill'=>'file-invoice-dollar', 'billa'=>'file-excel', 'billr'=>'file-invoice-dollar', 'billd'=>'file-medical', 'supplier_invoice'=>'file-invoice-dollar', 'supplier_invoicea'=>'file-excel', 'supplier_invoicer'=>'file-invoice-dollar', 'supplier_invoiced'=>'file-medical', 'bom'=>'shapes', - 'card'=>'address-card', 'chart'=>'chart-line', 'company'=>'building', 'contact'=>'address-book', 'contract'=>'suitcase', 'collab'=>'people-arrows', 'conversation'=>'comments', 'country'=>'globe-americas', 'cron'=>'business-time', + 'card'=>'address-card', 'chart'=>'chart-line', 'company'=>'building', 'contact'=>'address-book', 'contract'=>'suitcase', 'collab'=>'people-arrows', 'conversation'=>'comments', 'country'=>'globe-americas', 'cron'=>'business-time', 'cross'=>'times', 'donation'=>'file-alt', 'dynamicprice'=>'hand-holding-usd', 'setup'=>'cog', 'companies'=>'building', 'products'=>'cube', 'commercial'=>'suitcase', 'invoicing'=>'coins', 'accounting'=>'search-dollar', 'category'=>'tag', 'dollyrevert'=>'dolly', @@ -4180,7 +4193,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ 'member'=>'user-alt', 'meeting'=>'chalkboard-teacher', 'mrp'=>'cubes', 'next'=>'arrow-alt-circle-right', 'trip'=>'wallet', 'expensereport'=>'wallet', 'group'=>'users', 'movement'=>'people-carry', 'sign-out'=>'sign-out-alt', - 'switch_off'=>'toggle-off', 'switch_on'=>'toggle-on', 'switch_on_red'=>'toggle-on', 'check'=>'check', 'bookmark'=>'star', + 'switch_off'=>'toggle-off', 'switch_on'=>'toggle-on', 'switch_on_warning'=>'toggle-on', 'switch_on_red'=>'toggle-on', 'check'=>'check', 'bookmark'=>'star', 'bank'=>'university', 'close_title'=>'times', 'delete'=>'trash', 'filter'=>'filter', 'list-alt'=>'list-alt', 'calendarlist'=>'bars', 'calendar'=>'calendar-alt', 'calendarmonth'=>'calendar-alt', 'calendarweek'=>'calendar-week', 'calendarday'=>'calendar-day', 'calendarperuser'=>'table', 'intervention'=>'ambulance', 'invoice'=>'file-invoice-dollar', 'currency'=>'dollar-sign', 'multicurrency'=>'dollar-sign', 'order'=>'file-invoice', @@ -4264,7 +4277,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ 'members'=>'infobox-adherent', 'member'=>'infobox-adherent', 'money-bill-alt'=>'infobox-bank_account', 'order'=>'infobox-commande', 'user'=>'infobox-adherent', 'users'=>'infobox-adherent', - 'error'=>'pictoerror', 'warning'=>'pictowarning', 'switch_on'=>'font-status4', 'switch_on_red'=>'font-status8', + 'error'=>'pictoerror', 'warning'=>'pictowarning', 'switch_on'=>'font-status4', 'switch_on_warning'=>'font-status4 warning', 'switch_on_red'=>'font-status8', 'holiday'=>'infobox-holiday', 'info'=>'opacityhigh', 'invoice'=>'infobox-commande', 'knowledgemanagement'=>'infobox-contrat rotate90', 'loan'=>'infobox-bank_account', 'payment'=>'infobox-bank_account', 'payment_vat'=>'infobox-bank_account', 'poll'=>'infobox-adherent', 'pos'=>'infobox-bank_account', 'project'=>'infobox-project', 'projecttask'=>'infobox-project', @@ -5727,8 +5740,8 @@ function vatrate($rate, $addpercent = false, $info_bits = 0, $usestarfornpr = 0, * @param integer $form Type of format, HTML or not (not by default) * @param Translate|string $outlangs Object langs for output. '' use default lang. 'none' use international separators. * @param int $trunc 1=Truncate if there is more decimals than MAIN_MAX_DECIMALS_SHOWN (default), 0=Does not truncate. Deprecated because amount are rounded (to unit or total amount accurancy) before beeing inserted into database or after a computation, so this parameter should be useless. - * @param int $rounding MINIMUM number of decimal to show. 0=no change, -1=we use min($conf->global->MAIN_MAX_DECIMALS_UNIT,$conf->global->MAIN_MAX_DECIMALS_TOT) - * @param int|string $forcerounding Force the MAXIMUM of decimal to forcerounding decimal (-1=no change, 'MU' or 'MT' or numeric to round to MU or MT or to a given number of decimal) + * @param int $rounding MINIMUM number of decimal to show: 0=no change, -1=we use min($conf->global->MAIN_MAX_DECIMALS_UNIT,$conf->global->MAIN_MAX_DECIMALS_TOT) + * @param int|string $forcerounding MAXIMUM number of decimal to forcerounding decimal: -1=no change, 'MU' or 'MT' or numeric to round to MU or MT or to a given number of decimal * @param string $currency_code To add currency symbol (''=add nothing, 'auto'=Use default currency, 'XXX'=add currency symbols for XXX currency) * @return string String with formated amount * @@ -5743,7 +5756,7 @@ function price($amount, $form = 0, $outlangs = '', $trunc = 1, $rounding = -1, $ $amount = 0; // To have a numeric value if amount not defined or = '' } $amount = (is_numeric($amount) ? $amount : 0); // Check if amount is numeric, for example, an error occured when amount value = o (letter) instead 0 (number) - if ($rounding < 0) { + if ($rounding == -1) { $rounding = min($conf->global->MAIN_MAX_DECIMALS_UNIT, $conf->global->MAIN_MAX_DECIMALS_TOT); } $nbdecimal = $rounding; @@ -7564,7 +7577,7 @@ function dol_textishtml($msg, $option = 0) return true; } elseif (preg_match('/<\/textarea/i', $msg)) { return true; - } elseif (preg_match('/<(b|em|i|u)>/i', $msg)) { + } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) { return true; } elseif (preg_match('/
/i', $msg)) { + } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) { return true; } elseif (preg_match('//i', $msg)) { return true; @@ -7642,16 +7655,17 @@ function dol_concatdesc($text1, $text2, $forxml = false, $invert = false) * @param int $onlykey 1=Do not calculate some heavy values of keys (performance enhancement when we need only the keys), 2=Values are trunc and html sanitized (to use for help tooltip) * @param array $exclude Array of family keys we want to exclude. For example array('system', 'mycompany', 'object', 'objectamount', 'date', 'user', ...) * @param Object $object Object for keys on object + * @param array $include Array of family keys we want to include. For example array('system', 'mycompany', 'object', 'objectamount', 'date', 'user', ...) * @return array Array of substitutions * @see setSubstitFromObject() */ -function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $object = null) +function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $object = null, $include = null) { global $db, $conf, $mysoc, $user, $extrafields; $substitutionarray = array(); - if (empty($exclude) || !in_array('user', $exclude)) { + if ((empty($exclude) || !in_array('user', $exclude)) && (empty($include) || in_array('user', $include))) { // Add SIGNATURE into substitutionarray first, so, when we will make the substitution, // this will include signature content first and then replace var found into content of signature //var_dump($onlykey); @@ -7680,7 +7694,7 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, )); } } - if ((empty($exclude) || !in_array('mycompany', $exclude)) && is_object($mysoc)) { + if ((empty($exclude) || !in_array('mycompany', $exclude)) && is_object($mysoc) && (empty($include) || in_array('mycompany', $include))) { $substitutionarray = array_merge($substitutionarray, array( '__MYCOMPANY_NAME__' => $mysoc->name, '__MYCOMPANY_EMAIL__' => $mysoc->email, @@ -7704,7 +7718,7 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, )); } - if (($onlykey || is_object($object)) && (empty($exclude) || !in_array('object', $exclude))) { + if (($onlykey || is_object($object)) && (empty($exclude) || !in_array('object', $exclude)) && (empty($include) || in_array('object', $include))) { if ($onlykey) { $substitutionarray['__ID__'] = '__ID__'; $substitutionarray['__REF__'] = '__REF__'; @@ -7738,7 +7752,7 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = '__THIRDPARTY_NOTE_PUBLIC__'; $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = '__THIRDPARTY_NOTE_PRIVATE__'; } - if (isModEnabled('adherent') && (!is_object($object) || $object->element == 'adherent')) { + if (isModEnabled('adherent') && (!is_object($object) || $object->element == 'adherent') && (empty($exclude) || !in_array('member', $exclude)) && (empty($include) || in_array('member', $include))) { $substitutionarray['__MEMBER_ID__'] = '__MEMBER_ID__'; $substitutionarray['__MEMBER_CIVILITY__'] = '__MEMBER_CIVILITY__'; $substitutionarray['__MEMBER_FIRSTNAME__'] = '__MEMBER_FIRSTNAME__'; @@ -7748,7 +7762,7 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $substitutionarray['__MEMBER_NOTE_PRIVATE__'] = '__MEMBER_NOTE_PRIVATE__';*/ } // add variables subtitutions ticket - if (isModEnabled('ticket') && (!is_object($object) || $object->element == 'ticket')) { + if (isModEnabled('ticket') && (!is_object($object) || $object->element == 'ticket') && (empty($exclude) || !in_array('ticket', $exclude)) && (empty($include) || in_array('ticket', $include))) { $substitutionarray['__TICKET_TRACKID__'] = '__TICKET_TRACKID__'; $substitutionarray['__TICKET_SUBJECT__'] = '__TICKET_SUBJECT__'; $substitutionarray['__TICKET_TYPE__'] = '__TICKET_TYPE__'; @@ -7760,28 +7774,28 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $substitutionarray['__TICKET_USER_ASSIGN__'] = '__TICKET_USER_ASSIGN__'; } - if (isModEnabled('recruitment') && (!is_object($object) || $object->element == 'recruitmentcandidature')) { + if (isModEnabled('recruitment') && (!is_object($object) || $object->element == 'recruitmentcandidature') && (empty($exclude) || !in_array('recruitment', $exclude)) && (empty($include) || in_array('recruitment', $include))) { $substitutionarray['__CANDIDATE_FULLNAME__'] = '__CANDIDATE_FULLNAME__'; $substitutionarray['__CANDIDATE_FIRSTNAME__'] = '__CANDIDATE_FIRSTNAME__'; $substitutionarray['__CANDIDATE_LASTNAME__'] = '__CANDIDATE_LASTNAME__'; } - if (isModEnabled('project')) { // Most objects + if (isModEnabled('project') && (empty($exclude) || !in_array('project', $exclude)) && (empty($include) || in_array('project', $include))) { // Most objects $substitutionarray['__PROJECT_ID__'] = '__PROJECT_ID__'; $substitutionarray['__PROJECT_REF__'] = '__PROJECT_REF__'; $substitutionarray['__PROJECT_NAME__'] = '__PROJECT_NAME__'; /*$substitutionarray['__PROJECT_NOTE_PUBLIC__'] = '__PROJECT_NOTE_PUBLIC__'; $substitutionarray['__PROJECT_NOTE_PRIVATE__'] = '__PROJECT_NOTE_PRIVATE__';*/ } - if (isModEnabled('contrat') && (!is_object($object) || $object->element == 'contract')) { + if (isModEnabled('contrat') && (!is_object($object) || $object->element == 'contract') && (empty($exclude) || !in_array('contract', $exclude)) && (empty($include) || in_array('contract', $include))) { $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = 'Highest date planned for a service start'; $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = 'Highest date and hour planned for service start'; $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = 'Lowest data for planned expiration of service'; $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = 'Lowest date and hour for planned expiration of service'; } - if (isModEnabled("propal") && (!is_object($object) || $object->element == 'propal')) { + if (isModEnabled("propal") && (!is_object($object) || $object->element == 'propal') && (empty($exclude) || !in_array('propal', $exclude)) && (empty($include) || in_array('propal', $include))) { $substitutionarray['__ONLINE_SIGN_URL__'] = 'ToOfferALinkForOnlineSignature'; } - if (isModEnabled("ficheinter") && (!is_object($object) || $object->element == 'fichinter')) { + if (isModEnabled("ficheinter") && (!is_object($object) || $object->element == 'fichinter') && (empty($exclude) || !in_array('intervention', $exclude)) && (empty($include) || in_array('intervention', $include))) { $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = 'ToOfferALinkForOnlineSignature'; } $substitutionarray['__ONLINE_PAYMENT_URL__'] = 'UrlToPayOnlineIfApplicable'; @@ -8035,6 +8049,10 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, } if (is_object($object) && $object->element == 'member') { $typeforonlinepayment = 'member'; + $amounttouse = 0; + if (!empty($object->last_subscription_amount)) { + $amounttouse = $object->last_subscription_amount; + } } if (is_object($object) && $object->element == 'contrat') { $typeforonlinepayment = 'contract'; @@ -8042,7 +8060,8 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, if (is_object($object) && $object->element == 'fichinter') { $typeforonlinepayment = 'ficheinter'; } - $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $substitutionarray['__REF__']); + + $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $substitutionarray['__REF__'], $amounttouse); $paymenturl = $url; } @@ -8050,14 +8069,6 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = ($paymenturl ?str_replace('\n', "\n", $outputlangs->trans("PredefinedMailContentLink", $paymenturl)) : ''); $substitutionarray['__ONLINE_PAYMENT_URL__'] = $paymenturl; - if (is_object($object) && $object->element == 'propal') { - require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php'; - $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'proposal', $object->ref); - } - if (is_object($object) && $object->element == 'fichinter') { - require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php'; - $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = getOnlineSignatureUrl(0, 'fichinter', $object->ref); - } if (!empty($conf->global->PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'propal') { $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = $object->getLastMainDocLink($object->element); } else { @@ -8091,6 +8102,8 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, if (is_object($object) && $object->element == 'propal') { $substitutionarray['__URL_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/comm/propal/card.php?id=".$object->id; + require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php'; + $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'proposal', $object->ref); } if (is_object($object) && $object->element == 'commande') { $substitutionarray['__URL_ORDER__'] = DOL_MAIN_URL_ROOT."/commande/card.php?id=".$object->id; @@ -8100,9 +8113,13 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, } if (is_object($object) && $object->element == 'contrat') { $substitutionarray['__URL_CONTRACT__'] = DOL_MAIN_URL_ROOT."/contrat/card.php?id=".$object->id; + require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php'; + $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'contract', $object->ref); } if (is_object($object) && $object->element == 'fichinter') { $substitutionarray['__URL_FICHINTER__'] = DOL_MAIN_URL_ROOT."/fichinter/card.php?id=".$object->id; + require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php'; + $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = getOnlineSignatureUrl(0, 'fichinter', $object->ref); } if (is_object($object) && $object->element == 'supplier_proposal') { $substitutionarray['__URL_SUPPLIER_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/supplier_proposal/card.php?id=".$object->id; @@ -8119,7 +8136,7 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, } } } - if (empty($exclude) || !in_array('objectamount', $exclude)) { + if ((empty($exclude) || !in_array('objectamount', $exclude)) && (empty($include) || in_array('objectamount', $include))) { include_once DOL_DOCUMENT_ROOT.'/core/lib/functionsnumtoword.lib.php'; $substitutionarray['__DATE_YMD__'] = is_object($object) ? (isset($object->date) ? dol_print_date($object->date, 'day', 0, $outputlangs) : null) : ''; @@ -8175,7 +8192,7 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, } //var_dump($substitutionarray['__AMOUNT_FORMATED__']); - if (empty($exclude) || !in_array('date', $exclude)) { + if ((empty($exclude) || !in_array('date', $exclude)) && (empty($include) || in_array('date', $include))) { include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; $now = dol_now(); @@ -8212,7 +8229,7 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, if (isModEnabled('multicompany')) { $substitutionarray = array_merge($substitutionarray, array('__ENTITY_ID__' => $conf->entity)); } - if (empty($exclude) || !in_array('system', $exclude)) { + if ((empty($exclude) || !in_array('system', $exclude)) && (empty($include) || in_array('user', $include))) { $substitutionarray['__DOL_MAIN_URL_ROOT__'] = DOL_MAIN_URL_ROOT; $substitutionarray['__(AnyTranslationKey)__'] = $outputlangs->trans('TranslationOfKey'); $substitutionarray['__(AnyTranslationKey|langfile)__'] = $outputlangs->trans('TranslationOfKey').' (load also language file before)'; @@ -11193,10 +11210,13 @@ function dolGetButtonTitle($label, $helpText = '', $iconClass = 'fa fa-file', $u /** * Get an array with properties of an element. - * Called by fetchObjectByElement. * - * @param string $element_type Element type (Value of $object->element). Example: 'action', 'facture', 'project_task' or 'object@mymodule'... + * @param string $element_type Element type (Value of $object->element). Example: + * 'action', 'facture', 'project_task', + * 'myobject@mymodule' or + * 'myobject_mysubobject' (where mymodule = myobject, like 'project_task') * @return array (module, classpath, element, subelement, classfile, classname) + * @see fetchObjectByElement() */ function getElementProperties($element_type) { @@ -11204,102 +11224,150 @@ function getElementProperties($element_type) $classfile = $classname = $classpath = ''; - // Parse element/subelement (ex: project_task) + // Parse element/subelement $module = $element_type; $element = $element_type; $subelement = $element_type; - // If we ask an resource form external module (instead of default path) - if (preg_match('/^([^@]+)@([^@]+)$/i', $element_type, $regs)) { + // If we ask a resource form external module (instead of default path) + if (preg_match('/^([^@]+)@([^@]+)$/i', $element_type, $regs)) { // 'myobject@mymodule' $element = $subelement = $regs[1]; $module = $regs[2]; } - //print '
1. element : '.$element.' - module : '.$module .'
'; - if (preg_match('/^([^_]+)_([^_]+)/i', $element, $regs)) { + // If we ask a resource for a string with an element and a subelement + // Example 'project_task' + if (preg_match('/^([^_]+)_([^_]+)/i', $element, $regs)) { // 'myobject_mysubobject' with myobject=mymodule $module = $element = $regs[1]; $subelement = $regs[2]; } - // For compat + // For compat and To work with non standard path if ($element_type == "action") { $classpath = 'comm/action/class'; $subelement = 'Actioncomm'; $module = 'agenda'; - } - - // To work with non standard path - if ($element_type == 'facture' || $element_type == 'invoice') { + } elseif ($element_type == 'adherent_type') { + $classpath = 'adherents/class'; + $classfile = 'adherent_type'; + $module = 'adherent'; + $subelement = 'adherent_type'; + $classname = 'AdherentType'; + } elseif ($element_type == 'bank_account') { + $classpath = 'compta/bank/class'; + $module = 'banque'; + $classfile = 'account'; + $classname = 'Account'; + } elseif ($element_type == 'category') { + $classpath = 'categories/class'; + $module = 'categorie'; + $subelement = 'categorie'; + } elseif ($element_type == 'contact') { + $classpath = 'contact/class'; + $classfile = 'contact'; + $module = 'societe'; + $subelement = 'contact'; + } elseif ($element_type == 'stock') { + $classpath = 'product/stock/class'; + $classfile = 'entrepot'; + $classname = 'Entrepot'; + } elseif ($element_type == 'project') { + $classpath = 'projet/class'; + $module = 'projet'; + } elseif ($element_type == 'project_task') { + $classpath = 'projet/class'; + $module = 'projet'; + $subelement = 'task'; + } elseif ($element_type == 'facture' || $element_type == 'invoice') { $classpath = 'compta/facture/class'; $module = 'facture'; $subelement = 'facture'; - } - if ($element_type == 'commande' || $element_type == 'order') { + } elseif ($element_type == 'commande' || $element_type == 'order') { $classpath = 'commande/class'; $module = 'commande'; $subelement = 'commande'; - } - if ($element_type == 'propal') { + } elseif ($element_type == 'propal') { $classpath = 'comm/propal/class'; - } - if ($element_type == 'supplier_proposal') { + } elseif ($element_type == 'shipping') { + $classpath = 'expedition/class'; + $classfile = 'expedition'; + $classname = 'Expedition'; + $module = 'expedition'; + } elseif ($element_type == 'supplier_proposal') { $classpath = 'supplier_proposal/class'; - } - if ($element_type == 'shipping') { + $module = 'supplier_proposal'; + $element = 'supplierproposal'; + $classfile = 'supplier_proposal'; + $subelement = 'supplierproposal'; + } elseif ($element_type == 'shipping') { $classpath = 'expedition/class'; $subelement = 'expedition'; $module = 'expedition_bon'; - } - if ($element_type == 'delivery') { + } elseif ($element_type == 'delivery') { $classpath = 'delivery/class'; $subelement = 'delivery'; $module = 'delivery_note'; - } - if ($element_type == 'contract') { + } elseif ($element_type == 'contract') { $classpath = 'contrat/class'; $module = 'contrat'; $subelement = 'contrat'; - } - if ($element_type == 'member') { + } elseif ($element_type == 'member') { $classpath = 'adherents/class'; $module = 'adherent'; $subelement = 'adherent'; - } - if ($element_type == 'cabinetmed_cons') { + } elseif ($element_type == 'cabinetmed_cons') { $classpath = 'cabinetmed/class'; $module = 'cabinetmed'; $subelement = 'cabinetmedcons'; - } - if ($element_type == 'fichinter') { + } elseif ($element_type == 'fichinter') { $classpath = 'fichinter/class'; $module = 'ficheinter'; $subelement = 'fichinter'; - } - if ($element_type == 'dolresource' || $element_type == 'resource') { + } elseif ($element_type == 'dolresource' || $element_type == 'resource') { $classpath = 'resource/class'; $module = 'resource'; $subelement = 'dolresource'; - } - if ($element_type == 'propaldet') { + } elseif ($element_type == 'propaldet') { $classpath = 'comm/propal/class'; $module = 'propal'; $subelement = 'propaleligne'; - } - if ($element_type == 'order_supplier') { + } elseif ($element_type == 'opensurvey_sondage') { + $classpath = 'opensurvey/class'; + $module = 'opensurvey'; + $subelement = 'opensurveysondage'; + } elseif ($element_type == 'order_supplier') { $classpath = 'fourn/class'; $module = 'fournisseur'; - $subelement = 'commandefournisseur'; $classfile = 'fournisseur.commande'; - } - if ($element_type == 'invoice_supplier') { + $element = 'commande'; + $subelement = ''; + $classname = 'CommandeFournisseur'; + } elseif ($element_type == 'invoice_supplier') { $classpath = 'fourn/class'; $module = 'fournisseur'; - $subelement = 'facturefournisseur'; $classfile = 'fournisseur.facture'; - } - if ($element_type == "service") { + $element = 'facture'; + $subelement = ''; + $classname = 'FactureFournisseur'; + } elseif ($element_type == "service") { $classpath = 'product/class'; $subelement = 'product'; + } elseif ($element_type == 'salary') { + $classpath = 'salaries/class'; + $module = 'salaries'; + } elseif ($element_type == 'productlot') { + $module = 'productbatch'; + $classpath = 'product/stock/class'; + $classfile = 'productlot'; + $classname = 'Productlot'; + $element = 'productlot'; + $subelement = ''; + } elseif ($element_type == 'websitepage') { + $classpath = 'website/class'; + $classfile = 'websitepage'; + $classname = 'Websitepage'; + $module = 'website'; + $subelement = 'websitepage'; } if (empty($classfile)) { @@ -11328,25 +11396,39 @@ function getElementProperties($element_type) * Inclusion of classes is automatic * * @param int $element_id Element id - * @param string $element_type Element type + * @param string $element_type Element type ('module' or 'myobject@mymodule' or 'mymodule_myobject') * @param string $element_ref Element ref (Use this or element_id but not both) - * @return int|object object || 0 || -1 if error + * @return int|object object || 0 || <0 if error */ function fetchObjectByElement($element_id, $element_type, $element_ref = '') { - global $conf, $db; + global $db; + + $ret = 0; $element_prop = getElementProperties($element_type); - if (is_array($element_prop) && $conf->{$element_prop['module']}->enabled) { + //var_dump($element_prop); + + if (is_array($element_prop) && isModEnabled($element_prop['module'])) { dol_include_once('/'.$element_prop['classpath'].'/'.$element_prop['classfile'].'.class.php'); - $objecttmp = new $element_prop['classname']($db); - $ret = $objecttmp->fetch($element_id, $element_ref); - if ($ret >= 0) { - return $objecttmp; + if (class_exists($element_prop['classname'])) { + $classname = $element_prop['classname']; + $objecttmp = new $classname($db); + $ret = $objecttmp->fetch($element_id, $element_ref); + if ($ret >= 0) { + if (empty($objecttmp->module)) { + $objecttmp->module = $element_prop['module']; + } + + return $objecttmp; + } + } else { + return -1; } } - return 0; + + return $ret; } /** @@ -11368,6 +11450,7 @@ function isAFileWithExecutableContent($filename) * Return the value of token currently saved into session with name 'newtoken'. * This token must be send by any POST as it will be used by next page for comparison with value in session. * + * @since Dolibarr v10.0.7 * @return string */ function newToken() @@ -11379,6 +11462,7 @@ function newToken() * Return the value of token currently saved into session with name 'token'. * For ajax call, you must use this token as a parameter of the call into the js calling script (the called ajax php page must also set constant NOTOKENRENEWAL). * + * @since Dolibarr v10.0.7 * @return string */ function currentToken() diff --git a/htdocs/core/lib/functions2.lib.php b/htdocs/core/lib/functions2.lib.php index 188b30116d7..ce639624f1a 100644 --- a/htdocs/core/lib/functions2.lib.php +++ b/htdocs/core/lib/functions2.lib.php @@ -1314,8 +1314,8 @@ function get_next_value($db, $mask, $table, $field, $where = '', $objsoc = '', $ if (empty($counter)) { $counter = $maskoffset; } elseif (preg_match('/[^0-9]/i', $counter)) { - $counter = 0; dol_syslog("Error, the last counter found is '".$counter."' so is not a numeric value. We will restart to 1.", LOG_ERR); + $counter = 0; } elseif ($counter < $maskoffset && empty($conf->global->MAIN_NUMBERING_OFFSET_ONLY_FOR_FIRST)) { $counter = $maskoffset; } @@ -1936,14 +1936,14 @@ function getListOfModels($db, $type, $maxfilenamelength = 0) $sql .= " ORDER BY description DESC"; dol_syslog('/core/lib/function2.lib.php::getListOfModels', LOG_DEBUG); - $resql = $db->query($sql); - if ($resql) { - $num = $db->num_rows($resql); + $resql_models = $db->query($sql); + if ($resql_models) { + $num = $db->num_rows($resql_models); $i = 0; while ($i < $num) { $found = 1; - $obj = $db->fetch_object($resql); + $obj = $db->fetch_object($resql_models); // If this generation module needs to scan a directory, then description field is filled // with the constant that contains list of directories to scan (COMPANY_ADDON_PDF_ODT_PATH, ...). diff --git a/htdocs/core/lib/modulebuilder.lib.php b/htdocs/core/lib/modulebuilder.lib.php index 9d937d67627..2eb0aed6c07 100644 --- a/htdocs/core/lib/modulebuilder.lib.php +++ b/htdocs/core/lib/modulebuilder.lib.php @@ -638,3 +638,125 @@ function deletePropsFromDoc($file, $objectname) $new_contents = preg_replace($search, '', $str); file_put_contents($file, $new_contents); } + +/** + * Search a string and return all lines needed from file + * @param string $file file for searching + * @param string $start start line if exist + * @param string $end end line if exist + * @return string return the content needed + */ +function getFromFile($file, $start, $end) +{ + $i = 1; + $keys = array(); + $lines = file($file); + // Search for start and end lines + foreach ($lines as $i => $line) { + if (strpos($line, $start) !== false) { + // Copy lines until the end on array + while (($line = $lines[++$i]) !== false) { + if (strpos($line, $end) !== false) { + break; + } + $keys[] = $line; + } + break; + } + } + $content = implode("", $keys); + return $content; +} + +/** + * Write all permissions of each object in AsciiDoc format + * @param string $file path of the class + * @param string $destfile file where write table of permissions + * @return int 1 if OK, -1 if KO + */ +function writePermsInAsciiDoc($file, $destfile) +{ + global $langs; + //search and get all permssion in stirng + $start = '/* BEGIN MODULEBUILDER PERMISSIONS */'; + $end = '/* END MODULEBUILDER PERMISSIONS */'; + $content = getFromFile($file, $start, $end); + if (empty($content)) { + return -1; + } + //prepare table + $string = "[options='header',grid=rows,width=60%,caption=Organisation]\n"; + $string .= "|===\n"; + // header for table + $header = array($langs->trans('Objects'),$langs->trans('Permission')); + foreach ($header as $h) { + $string .= "|".$h; + } + $string .= "\n"; + //content table + $array = explode(";", $content); + $indexIgnored = 15; + $permissions = array_slice($array, $indexIgnored, null, true); + // delete occurrences "$r++" and ID + $permissions = str_replace('$r++', 1, $permissions); + + $permsN = array(); + foreach ($permissions as $i => $element) { + if ($element == 1) { + unset($permissions[$i]); + } + if (str_contains($element, '$this->numero')) { + unset($permissions[$i]); + } + if (str_contains($element, '$this->rights[$r][5]')) { + unset($permissions[$i]); + } + } + // cleaning the string on each element + foreach ($permissions as $key => $element) { + $element = str_replace(" '", '', $element); + $element = trim($element, "'"); + $permsN[] = substr($element, strpos($element, "=")+1); + } + array_pop($permsN); + + // Group permissions by Object and add it to string + $temp_array = []; + $final_array = []; + $countRights = count($permsN); + for ($i = 0; $i < $countRights ; $i++) { + // Add current element to temporary array + $temp_array[] = $permsN[$i]; + // add them to the final array and empty the temporary array + if (count($temp_array) == 2) { + $final_array[] = $temp_array; + $temp_array = []; + } + } + // add it to the final array + if (count($temp_array) > 0) { + $final_array[] = $temp_array; + } + + $result = array(); + foreach ($final_array as $subarray) { + // found object + $key = $subarray[1]; + // add sub array to object + $result[$key][] = $subarray; + } + foreach ($result as $i => $pems) { + $string .= "|*".$i."*|"; + foreach ($pems as $tab) { + $string .= $tab[0]." , "; + } + $string .= "\n"; + } + // end table + $string .= "\n|===\n"; + $write = dolReplaceInFile($destfile, array('__DATA_PERMISSIONS__'=> $string)); + if ($write<0) { + return -1; + } + return 1; +} diff --git a/htdocs/core/lib/payments.lib.php b/htdocs/core/lib/payments.lib.php index 93c7a17de2f..ef89c65bdf1 100644 --- a/htdocs/core/lib/payments.lib.php +++ b/htdocs/core/lib/payments.lib.php @@ -417,109 +417,3 @@ function getOnlinePaymentUrl($mode, $type, $ref = '', $amount = '9.99', $freetag return $out; } - - - -/** - * Show footer of company in HTML pages - * - * @param Societe $fromcompany Third party - * @param Translate $langs Output language - * @param int $addformmessage Add the payment form message - * @param string $suffix Suffix to use on constants - * @param Object $object Object related to payment - * @return void - */ -function htmlPrintOnlinePaymentFooter($fromcompany, $langs, $addformmessage = 0, $suffix = '', $object = null) -{ - global $conf; - - $reg = array(); - - // Juridical status - $line1 = ""; - if ($fromcompany->forme_juridique_code) { - $line1 .= ($line1 ? " - " : "").getFormeJuridiqueLabel($fromcompany->forme_juridique_code); - } - // Capital - if ($fromcompany->capital) { - $line1 .= ($line1 ? " - " : "").$langs->transnoentities("CapitalOf", $fromcompany->capital)." ".$langs->transnoentities("Currency".$conf->currency); - } - // Prof Id 1 - if ($fromcompany->idprof1 && ($fromcompany->country_code != 'FR' || !$fromcompany->idprof2)) { - $field = $langs->transcountrynoentities("ProfId1", $fromcompany->country_code); - if (preg_match('/\((.*)\)/i', $field, $reg)) { - $field = $reg[1]; - } - $line1 .= ($line1 ? " - " : "").$field.": ".$fromcompany->idprof1; - } - // Prof Id 2 - if ($fromcompany->idprof2) { - $field = $langs->transcountrynoentities("ProfId2", $fromcompany->country_code); - if (preg_match('/\((.*)\)/i', $field, $reg)) { - $field = $reg[1]; - } - $line1 .= ($line1 ? " - " : "").$field.": ".$fromcompany->idprof2; - } - - // Second line of company infos - $line2 = ""; - // Prof Id 3 - if ($fromcompany->idprof3) { - $field = $langs->transcountrynoentities("ProfId3", $fromcompany->country_code); - if (preg_match('/\((.*)\)/i', $field, $reg)) { - $field = $reg[1]; - } - $line2 .= ($line2 ? " - " : "").$field.": ".$fromcompany->idprof3; - } - // Prof Id 4 - if ($fromcompany->idprof4) { - $field = $langs->transcountrynoentities("ProfId4", $fromcompany->country_code); - if (preg_match('/\((.*)\)/i', $field, $reg)) { - $field = $reg[1]; - } - $line2 .= ($line2 ? " - " : "").$field.": ".$fromcompany->idprof4; - } - // IntraCommunautary VAT - if ($fromcompany->tva_intra != '') { - $line2 .= ($line2 ? " - " : "").$langs->transnoentities("VATIntraShort").": ".$fromcompany->tva_intra; - } - - print ''."\n"; - - print '
'."\n"; - print '
'; - if ($addformmessage) { - print ''; - print '
'; - - $parammessageform = 'ONLINE_PAYMENT_MESSAGE_FORM_'.$suffix; - if (!empty($conf->global->$parammessageform)) { - print $langs->transnoentities($conf->global->$parammessageform); - } elseif (!empty($conf->global->ONLINE_PAYMENT_MESSAGE_FORM)) { - print $langs->transnoentities($conf->global->ONLINE_PAYMENT_MESSAGE_FORM); - } - - // Add other message if VAT exists - if (!empty($object->total_vat) || !empty($object->total_tva)) { - $parammessageform = 'ONLINE_PAYMENT_MESSAGE_FORMIFVAT_'.$suffix; - if (!empty($conf->global->$parammessageform)) { - print $langs->transnoentities($conf->global->$parammessageform); - } elseif (!empty($conf->global->ONLINE_PAYMENT_MESSAGE_FORMIFVAT)) { - print $langs->transnoentities($conf->global->ONLINE_PAYMENT_MESSAGE_FORMIFVAT); - } - } - } - - print '

'."\n"; - print $fromcompany->name.'
'; - print $line1; - if (strlen($line1.$line2) > 50) { - print '
'; - } else { - print ' - '; - } - print $line2; - print '
'; - print '
'."\n"; -} diff --git a/htdocs/core/lib/pdf.lib.php b/htdocs/core/lib/pdf.lib.php index 468c4d82a9b..03e816a63f9 100644 --- a/htdocs/core/lib/pdf.lib.php +++ b/htdocs/core/lib/pdf.lib.php @@ -744,12 +744,13 @@ function pdf_pagehead(&$pdf, $outputlangs, $page_height) * @param Translate $outputlangs Output language * @param array $exclude Array of family keys we want to exclude. For example array('mycompany', 'object', 'date', 'user', ...) * @param Object $object Object - * @param int $onlykey 1=Do not calculate some heavy values of keys (performance enhancement when we need only the keys), 2=Values are truncated and html sanitized (to use for help tooltip) + * @param int $onlykey 1=Do not calculate some heavy values of keys (performance enhancement when we need only the keys), 2=Values are truncated and html sanitized (to use for help tooltip) + * @param array $include Array of family keys we want to include. For example array('system', 'mycompany', 'object', 'objectamount', 'date', 'user', ...) * @return array Array of substitutions */ -function pdf_getSubstitutionArray($outputlangs, $exclude = null, $object = null, $onlykey = 0) +function pdf_getSubstitutionArray($outputlangs, $exclude = null, $object = null, $onlykey = 0, $include = null) { - $substitutionarray = getCommonSubstitutionArray($outputlangs, $onlykey, $exclude, $object); + $substitutionarray = getCommonSubstitutionArray($outputlangs, $onlykey, $exclude, $object, $include); $substitutionarray['__FROM_NAME__'] = '__FROM_NAME__'; $substitutionarray['__FROM_EMAIL__'] = '__FROM_EMAIL__'; return $substitutionarray; @@ -1666,7 +1667,7 @@ function pdf_getlinedesc($object, $i, $outputlangs, $hideref = 0, $hidedesc = 0, // Show information for lot if (!empty($dbatch)) { // $object is a shipment. - //var_dump($object->lines[$i]->details_entrepot); // array from llx_expeditiondet (we can have seral lines for one fk_origin_line) + //var_dump($object->lines[$i]->details_entrepot); // array from llx_expeditiondet (we can have several lines for one fk_origin_line) //var_dump($object->lines[$i]->detail_batch); // array from llx_expeditiondet_batch (each line with a lot is linked to llx_expeditiondet) include_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php'; diff --git a/htdocs/core/lib/project.lib.php b/htdocs/core/lib/project.lib.php index 2a38906e4de..9baccc8e9fc 100644 --- a/htdocs/core/lib/project.lib.php +++ b/htdocs/core/lib/project.lib.php @@ -290,7 +290,7 @@ function project_prepare_head(Project $project, $moreparam = '') } else { require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php'; - $upload_dir = $conf->project->dir_output."/".dol_sanitizeFileName($project->ref); + $upload_dir = $conf->project->multidir_output[$project->entity]."/".dol_sanitizeFileName($project->ref); $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$')); $nbLinks = Link::count($db, $project->element, $project->id); $totalAttached = $nbFiles + $nbLinks; @@ -418,7 +418,7 @@ function task_prepare_head($object) } $head[$h][0] = DOL_URL_ROOT.'/projet/tasks/document.php?id='.$object->id.(GETPOST('withproject') ? '&withproject=1' : ''); - $filesdir = $conf->project->dir_output."/".dol_sanitizeFileName($object->project->ref).'/'.dol_sanitizeFileName($object->ref); + $filesdir = $conf->project->multidir_output[$object->entity]."/".dol_sanitizeFileName($object->project->ref).'/'.dol_sanitizeFileName($object->ref); include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; include_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php'; $nbFiles = count(dol_dir_list($filesdir, 'files', 0, '', '(\.meta|_preview.*\.png)$')); diff --git a/htdocs/core/lib/security.lib.php b/htdocs/core/lib/security.lib.php index 1f7b9404a7c..3c9ca5e34d9 100644 --- a/htdocs/core/lib/security.lib.php +++ b/htdocs/core/lib/security.lib.php @@ -270,9 +270,9 @@ function dol_verifyHash($chain, $hash, $type = '0') if ($type == '0' && !empty($conf->global->MAIN_SECURITY_HASH_ALGO) && $conf->global->MAIN_SECURITY_HASH_ALGO == 'password_hash' && function_exists('password_verify')) { if (! empty($hash[0]) && $hash[0] == '$') { return password_verify($chain, $hash); - } elseif (strlen($hash) == 32) { + } elseif (dol_strlen($hash) == 32) { return dol_verifyHash($chain, $hash, '3'); // md5 - } elseif (strlen($hash) == 40) { + } elseif (dol_strlen($hash) == 40) { return dol_verifyHash($chain, $hash, '2'); // sha1md5 } @@ -332,7 +332,7 @@ function dolGetLdapPasswordHash($password, $type = 'md5') * This method check permission on module then call checkUserAccessToObject() for permission on object (according to entity and socid of user). * * @param User $user User to check - * @param string $features Features to check (it must be module $object->element. Can be a 'or' check with 'levela|levelb'. + * @param string $features Features to check (it must be module name or $object->element. Can be a 'or' check with 'levela|levelb'. * Examples: 'societe', 'contact', 'produit&service', 'produit|service', ...) * This is used to check permission $user->rights->features->... * @param int|string|object $object Object or Object ID or list of Object ID if we want to check a particular record (optional) is linked to a owned thirdparty (optional). @@ -340,7 +340,7 @@ function dolGetLdapPasswordHash($password, $type = 'md5') * @param string $feature2 Feature to check, second level of permission (optional). Can be a 'or' check with 'sublevela|sublevelb'. * This is used to check permission $user->rights->features->feature2... * @param string $dbt_keyfield Field name for socid foreign key if not fk_soc. Not used if objectid is null (optional). Can use '' if NA. - * @param string $dbt_select Field name for select if not "rowid". Not used if objectid is null (optional) + * @param string $dbt_select Field rowid name, for select into tableandshare if not "rowid". Not used if objectid is null (optional) * @param int $isdraft 1=The object with id=$objectid is a draft * @param int $mode Mode (0=default, 1=return without dieing) * @return int If mode = 0 (default): Always 1, die process if not allowed. If mode = 1: Return 0 if access not allowed. @@ -351,6 +351,7 @@ function restrictedArea(User $user, $features, $object = 0, $tableandshare = '', global $db, $conf; global $hookmanager; + // Define $objectid if (is_object($object)) { $objectid = $object->id; } else { @@ -363,12 +364,17 @@ function restrictedArea(User $user, $features, $object = 0, $tableandshare = '', //dol_syslog("functions.lib:restrictedArea $feature, $objectid, $dbtablename, $feature2, $dbt_socfield, $dbt_select, $isdraft"); //print "user_id=".$user->id.", features=".$features.", feature2=".$feature2.", objectid=".$objectid; //print ", dbtablename=".$tableandshare.", dbt_socfield=".$dbt_keyfield.", dbt_select=".$dbt_select; - //print ", perm: ".$features."->".$feature2."=".($user->rights->$features->$feature2->lire)."
"; + //print ", perm: ".$features."->".$feature2."=".($user->hasRight($features, $feature2, 'lire'))."
"; $parentfortableentity = ''; // Fix syntax of $features param $originalfeatures = $features; + if ($features == 'agenda') { + $tableandshare = 'actioncomm&societe'; + $feature2 = 'myactions|allactions'; + $dbt_select = 'id'; + } if ($features == 'facturerec') { $features = 'facture'; } @@ -382,9 +388,7 @@ function restrictedArea(User $user, $features, $object = 0, $tableandshare = '', $features = 'adherent'; $feature2 = 'cotisation'; } - if ($features == 'websitepage') { - $features = 'website'; - $tableandshare = 'website_page'; + if ($features == 'website' && is_object($object) && $object->element == 'websitepage') { $parentfortableentity = 'fk_website@website'; } if ($features == 'project') { @@ -393,6 +397,19 @@ function restrictedArea(User $user, $features, $object = 0, $tableandshare = '', if ($features == 'product') { $features = 'produit'; } + if ($features == 'productbatch') { + $features = 'produit'; + } + if ($features == 'fournisseur') { // When vendor invoice and pruchase order are into module 'fournisseur' + $features = 'fournisseur'; + if ($object->element == 'invoice_supplier') { + $feature2 = 'facture'; + } elseif ($object->element == 'order_supplier') { + $feature2 = 'commande'; + } + } + + //print $features.' - '.$tableandshare.' - '.$feature2.' - '.$dbt_select."\n"; // Get more permissions checks from hooks $parameters = array('features'=>$features, 'originalfeatures'=>$originalfeatures, 'objectid'=>$objectid, 'dbt_select'=>$dbt_select, 'idtype'=>$dbt_select, 'isdraft'=>$isdraft); @@ -485,7 +502,7 @@ function restrictedArea(User $user, $features, $object = 0, $tableandshare = '', $readok = 0; $nbko++; } - } elseif (!empty($feature2)) { // This is for permissions on 2 levels + } elseif (!empty($feature2)) { // This is for permissions on 2 levels (module->object->read) $tmpreadok = 1; foreach ($feature2 as $subfeature) { if ($subfeature == 'user' && $user->id == $objectid) { @@ -504,7 +521,7 @@ function restrictedArea(User $user, $features, $object = 0, $tableandshare = '', $readok = 0; // All tests are ko (we manage here the and, the or will be managed later using $nbko). $nbko++; } - } elseif (!empty($feature) && ($feature != 'user' && $feature != 'usergroup')) { // This is permissions on 1 level + } elseif (!empty($feature) && ($feature != 'user' && $feature != 'usergroup')) { // This is permissions on 1 level (module->read) if (empty($user->rights->$feature->lire) && empty($user->rights->$feature->read) && empty($user->rights->$feature->run)) { @@ -531,7 +548,7 @@ function restrictedArea(User $user, $features, $object = 0, $tableandshare = '', // Check write permission from module (we need to know write permission to create but also to delete drafts record or to upload files) $createok = 1; $nbko = 0; - $wemustcheckpermissionforcreate = (GETPOST('sendit', 'alpha') || GETPOST('linkit', 'alpha') || in_array(GETPOST('action', 'aZ09'), array('create', 'update', 'add_element_resource', 'confirm_delete_linked_resource')) || GETPOST('roworder', 'alpha', 2)); + $wemustcheckpermissionforcreate = (GETPOST('sendit', 'alpha') || GETPOST('linkit', 'alpha') || in_array(GETPOST('action', 'aZ09'), array('create', 'update', 'set', 'upload', 'add_element_resource', 'confirm_delete_linked_resource')) || GETPOST('roworder', 'alpha', 2)); $wemustcheckpermissionfordeletedraft = ((GETPOST("action", "aZ09") == 'confirm_delete' && GETPOST("confirm", "aZ09") == 'yes') || GETPOST("action", "aZ09") == 'delete'); if ($wemustcheckpermissionforcreate || $wemustcheckpermissionfordeletedraft) { @@ -576,7 +593,7 @@ function restrictedArea(User $user, $features, $object = 0, $tableandshare = '', $createok = 0; $nbko++; } - } elseif (!empty($feature2)) { // This is for permissions on one level + } elseif (!empty($feature2)) { // This is for permissions on 2 levels (module->object->write) foreach ($feature2 as $subfeature) { if ($subfeature == 'user' && $user->id == $objectid && $user->rights->user->self->creer) { continue; // User can edit its own card @@ -599,7 +616,7 @@ function restrictedArea(User $user, $features, $object = 0, $tableandshare = '', break; } } - } elseif (!empty($feature)) { // This is for permissions on 2 levels ('creer' or 'write') + } elseif (!empty($feature)) { // This is for permissions on 1 levels (module->write) //print '
feature='.$feature.' creer='.$user->rights->$feature->creer.' write='.$user->rights->$feature->write; exit; if (empty($user->rights->$feature->creer) && empty($user->rights->$feature->write) @@ -1114,6 +1131,7 @@ function httponly_accessforbidden($message = 1, $http_response_code = 403, $stri function accessforbidden($message = '', $printheader = 1, $printfooter = 1, $showonlymessage = 0, $params = null) { global $conf, $db, $user, $langs, $hookmanager; + global $action, $object; if (!is_object($langs)) { include_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php'; @@ -1139,12 +1157,13 @@ function accessforbidden($message = '', $printheader = 1, $printfooter = 1, $sho print '
'; print '
'; if (empty($showonlymessage)) { - global $action, $object; if (empty($hookmanager)) { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; $hookmanager = new HookManager($db); // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context $hookmanager->initHooks(array('main')); } + $parameters = array('message'=>$message, 'params'=>$params); $reshook = $hookmanager->executeHooks('getAccessForbiddenMessage', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks print $hookmanager->resPrint; diff --git a/htdocs/core/lib/website.lib.php b/htdocs/core/lib/website.lib.php index 6f3ac2cdf0f..52b9afab8a7 100644 --- a/htdocs/core/lib/website.lib.php +++ b/htdocs/core/lib/website.lib.php @@ -35,8 +35,10 @@ function dolStripPhpCode($str, $replacewith = '') $newstr = ''; - //split on each opening tag - $parts = explode('holiday->enabled', __HANDLER__, 'left', 5000__+MAX_llx_menu__, 'hrm', 'hrm', 15__+MAX_llx_menu__, '/holiday/list.php?mainmenu=hrm&leftmenu=hrm', 'CPTitreMenu', 0, 'holiday', '$user->rights->holiday->read', '', 0, 1, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->holiday->enabled', __HANDLER__, 'left', 5001__+MAX_llx_menu__, 'hrm', '', 5000__+MAX_llx_menu__, '/holiday/card.php?mainmenu=hrm&action=create', 'New', 1, 'holiday', '$user->rights->holiday->write', '', 0, 1, __ENTITY__); -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->holiday->enabled', __HANDLER__, 'left', 5001__+MAX_llx_menu__, 'hrm', '', 5000__+MAX_llx_menu__, '/holiday/card_group.php?mainmenu=hrm&action=create', 'NewHolidayForGroup', 1, 'holiday', '$user->rights->holiday->write', '', 0, 1, __ENTITY__); -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->holiday->enabled', __HANDLER__, 'left', 5002__+MAX_llx_menu__, 'hrm', '', 5000__+MAX_llx_menu__, '/holiday/list.php?mainmenu=hrm&leftmenu=hrm', 'List', 1, 'holiday', '$user->rights->holiday->read', '', 0, 1, __ENTITY__); -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->holiday->enabled', __HANDLER__, 'left', 5003__+MAX_llx_menu__, 'hrm', '', 5002__+MAX_llx_menu__, '/holiday/list.php?mainmenu=hrm&search_statut=2&leftmenu=hrm', 'ListToApprove', 2, 'trips', '$user->rights->holiday->read', '', 0, 1, __ENTITY__); -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->holiday->enabled', __HANDLER__, 'left', 5004__+MAX_llx_menu__, 'hrm', '', 5000__+MAX_llx_menu__, '/holiday/define_holiday.php?mainmenu=hrm', 'MenuConfCP', 1, 'holiday', '$user->rights->holiday->define_holiday', '', 0, 2, __ENTITY__); -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->holiday->enabled', __HANDLER__, 'left', 5005__+MAX_llx_menu__, 'hrm', '', 5000__+MAX_llx_menu__, '/holiday/view_log.php?mainmenu=hrm', 'MenuLogCP', 1, 'holiday', '$user->rights->holiday->define_holiday', '', 0, 3, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->holiday->enabled', __HANDLER__, 'left', 5002__+MAX_llx_menu__, 'hrm', '', 5000__+MAX_llx_menu__, '/holiday/card_group.php?mainmenu=hrm&action=create', 'NewHolidayForGroup', 1, 'holiday', '$user->rights->holiday->write', '', 0, 1, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->holiday->enabled', __HANDLER__, 'left', 5003__+MAX_llx_menu__, 'hrm', '', 5000__+MAX_llx_menu__, '/holiday/list.php?mainmenu=hrm&leftmenu=hrm', 'List', 1, 'holiday', '$user->rights->holiday->read', '', 0, 1, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->holiday->enabled', __HANDLER__, 'left', 5004__+MAX_llx_menu__, 'hrm', '', 5002__+MAX_llx_menu__, '/holiday/list.php?mainmenu=hrm&search_statut=2&leftmenu=hrm', 'ListToApprove', 2, 'trips', '$user->rights->holiday->read', '', 0, 1, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->holiday->enabled', __HANDLER__, 'left', 5005__+MAX_llx_menu__, 'hrm', '', 5000__+MAX_llx_menu__, '/holiday/define_holiday.php?mainmenu=hrm', 'MenuConfCP', 1, 'holiday', '$user->rights->holiday->define_holiday', '', 0, 2, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->holiday->enabled', __HANDLER__, 'left', 5006__+MAX_llx_menu__, 'hrm', '', 5000__+MAX_llx_menu__, '/holiday/view_log.php?mainmenu=hrm', 'MenuLogCP', 1, 'holiday', '$user->rights->holiday->define_holiday', '', 0, 3, __ENTITY__); -- HRM - Trips and expenses (old module) insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->deplacement->enabled', __HANDLER__, 'left', 2100__+MAX_llx_menu__, 'accountancy', 'tripsandexpenses', 15__+MAX_llx_menu__, '/compta/deplacement/index.php?mainmenu=accountancy&leftmenu=tripsandexpenses', 'TripsAndExpenses', 0, 'trips', '$user->rights->deplacement->lire', '', 0, 5, __ENTITY__); diff --git a/htdocs/core/modules/DolibarrModules.class.php b/htdocs/core/modules/DolibarrModules.class.php index 6c43c945b65..62dbd494082 100644 --- a/htdocs/core/modules/DolibarrModules.class.php +++ b/htdocs/core/modules/DolibarrModules.class.php @@ -1986,7 +1986,7 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it public function insert_menus() { // phpcs:enable - global $user; + global $conf, $user; if (!is_array($this->menu) || empty($this->menu)) { return 0; @@ -1998,6 +1998,9 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it $err = 0; + // Common module + $entity = ((!empty($this->always_enabled) || !empty($this->core_enabled)) ? 0 : $conf->entity); + $this->db->begin(); foreach ($this->menu as $key => $value) { @@ -2049,6 +2052,7 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it $menu->user = $this->menu[$key]['user']; $menu->enabled = isset($this->menu[$key]['enabled']) ? $this->menu[$key]['enabled'] : 0; $menu->position = $this->menu[$key]['position']; + $menu->entity = $entity; if (!$err) { $result = $menu->create($user); // Save menu entry into table llx_menu @@ -2092,7 +2096,7 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it $sql = "DELETE FROM ".MAIN_DB_PREFIX."menu"; $sql .= " WHERE module = '".$this->db->escape($module)."'"; - $sql .= " AND entity = ".$conf->entity; + $sql .= " AND entity IN (0, ".$conf->entity.")"; dol_syslog(get_class($this)."::delete_menus", LOG_DEBUG); $resql = $this->db->query($sql); diff --git a/htdocs/core/modules/expedition/doc/pdf_espadon.modules.php b/htdocs/core/modules/expedition/doc/pdf_espadon.modules.php index 34699a6e608..f6c648f2ff0 100644 --- a/htdocs/core/modules/expedition/doc/pdf_espadon.modules.php +++ b/htdocs/core/modules/expedition/doc/pdf_espadon.modules.php @@ -368,11 +368,14 @@ class pdf_espadon extends ModelePdfExpedition if (!empty($notetoshow) || !empty($object->tracking_number)) { $tab_top -= 2; + $tab_topbeforetrackingnumber = $tab_top; // Tracking number if (!empty($object->tracking_number)) { + $height_trackingnumber = 4; + $pdf->SetFont('', 'B', $default_font_size - 2); - $pdf->writeHTMLCell(60, 4, $this->posxdesc - 1, $tab_top - 1, $outputlangs->transnoentities("TrackingNumber") . " : " . $object->tracking_number, 0, 1, false, true, 'L'); + $pdf->writeHTMLCell(60, $height_trackingnumber, $this->posxdesc - 1, $tab_top - 1, $outputlangs->transnoentities("TrackingNumber") . " : " . $object->tracking_number, 0, 1, false, true, 'L'); $tab_top_alt = $pdf->GetY(); $object->getUrlTrackingStatus($object->tracking_number); @@ -390,19 +393,20 @@ class pdf_espadon extends ModelePdfExpedition $label .= " : "; $label .= $object->tracking_url; } - $pdf->SetFont('', 'B', $default_font_size - 2); - $pdf->writeHTMLCell(60, 4, $this->posxdesc - 1, $tab_top_alt, $label, 0, 1, false, true, 'L'); - $tab_top = $pdf->GetY(); + $height_trackingnumber += 4; + $pdf->SetFont('', 'B', $default_font_size - 2); + $pdf->writeHTMLCell(60, $height_trackingnumber, $this->posxdesc - 1, $tab_top_alt, $label, 0, 1, false, true, 'L'); } } + $tab_top = $pdf->GetY(); } // Notes $pagenb = $pdf->getPage(); - if (!empty($notetoshow)) { - $tab_top -= 2; + if (!empty($notetoshow) || !empty($object->tracking_number)) { + $tab_top -= 1; $tab_width = $this->page_largeur - $this->marge_gauche - $this->marge_droite; $pageposbeforenote = $pagenb; @@ -465,11 +469,21 @@ class pdf_espadon extends ModelePdfExpedition $pdf->SetDrawColor(128, 128, 128); // Draw note frame if ($i > $pageposbeforenote) { - $height_note = $this->page_hauteur - ($tab_top_newpage + $heightforfooter); - $pdf->Rect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 1); + if (empty($height_trackingnumber)) { + $height_note = $this->page_hauteur - ($tab_top_newpage + $heightforfooter); + } else { + $height_note = $this->page_hauteur - ($tab_top_newpage + $heightforfooter) + $height_trackingnumber + 1; + $tab_top_newpage = $tab_topbeforetrackingnumber; + } + $pdf->Rect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 2); } else { - $height_note = $this->page_hauteur - ($tab_top + $heightforfooter); - $pdf->Rect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 1); + if (empty($height_trackingnumber)) { + $height_note = $this->page_hauteur - ($tab_top + $heightforfooter); + } else { + $height_note = $this->page_hauteur - ($tab_top + $heightforfooter)+ $height_trackingnumber + 1; + $tab_top = $tab_topbeforetrackingnumber; + } + $pdf->Rect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 2); } // Add footer @@ -489,8 +503,13 @@ class pdf_espadon extends ModelePdfExpedition { $pdf->commitTransaction(); $posyafter = $pdf->GetY(); - $height_note = $posyafter - $tab_top; - $pdf->Rect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 1); + if (empty($height_trackingnumber)) { + $height_note = $posyafter - $tab_top + 1; + } else { + $height_note = $posyafter - $tab_top + $height_trackingnumber + 1; + $tab_top = $tab_topbeforetrackingnumber; + } + $pdf->Rect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 2); if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + 20))) { diff --git a/htdocs/core/modules/export/export_excel2007.modules.php b/htdocs/core/modules/export/export_excel2007.modules.php index fba0dfa1c4a..ea7480cf15c 100644 --- a/htdocs/core/modules/export/export_excel2007.modules.php +++ b/htdocs/core/modules/export/export_excel2007.modules.php @@ -92,7 +92,7 @@ class ExportExcel2007 extends ModeleExports if (empty($this->disabled)) { require_once PHPEXCELNEW_PATH.'Spreadsheet.php'; $this->label_lib = 'PhpSpreadSheet'; - $this->version_lib = '1.6.0'; // No way to get info from library + $this->version_lib = '1.12.0'; // No way to get info from library } $this->row = 0; @@ -464,6 +464,7 @@ class ExportExcel2007 extends ModeleExports return ''; } + $letter = ''; while ($c != 0) { $p = ($c - 1) % 26; $c = intval(($c - $p) / 26); diff --git a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php index 174648dfa8c..50b22f1b439 100644 --- a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php @@ -1876,7 +1876,8 @@ class pdf_crabe extends ModelePDFFactures $title = $outputlangs->transnoentities("InvoiceProForma"); } if ($this->situationinvoice) { - $title = $outputlangs->transnoentities("PDFInvoiceSituation"); + $langs->loadLangs(array("other")); + $title = $outputlangs->transnoentities("PDFInvoiceSituation") . " " . $outputlangs->transnoentities("NumberingShort") . $object->situation_counter . " -"; } if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) { $title .= ' - '; @@ -1919,11 +1920,11 @@ class pdf_crabe extends ModelePDFFactures $posy += 3; $pdf->SetFont('', '', $default_font_size - 2); - if ($object->ref_client) { + if ($object->ref_customer) { $posy += 4; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefCustomer")." : ".$outputlangs->convToOutputCharset($object->ref_client), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefCustomer")." : ".$outputlangs->convToOutputCharset($object->ref_customer), '', 'R'); } if (!empty($conf->global->PDF_SHOW_PROJECT_TITLE)) { diff --git a/htdocs/core/modules/facture/doc/pdf_sponge.modules.php b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php index 312115bb0c1..cbdb1608beb 100644 --- a/htdocs/core/modules/facture/doc/pdf_sponge.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php @@ -2126,7 +2126,8 @@ class pdf_sponge extends ModelePDFFactures $title = $outputlangs->transnoentities("InvoiceProForma"); } if ($this->situationinvoice) { - $title = $outputlangs->transnoentities("PDFInvoiceSituation"); + $langs->loadLangs(array("other")); + $title = $outputlangs->transnoentities("PDFInvoiceSituation") . " " . $outputlangs->transnoentities("NumberingShort") . $object->situation_counter . " -"; } if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) { $title .= ' - '; @@ -2169,11 +2170,11 @@ class pdf_sponge extends ModelePDFFactures $posy += 3; $pdf->SetFont('', '', $default_font_size - 2); - if ($object->ref_client) { + if ($object->ref_customer) { $posy += 4; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefCustomer")." : ".dol_trunc($outputlangs->convToOutputCharset($object->ref_client), 65), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefCustomer")." : ".dol_trunc($outputlangs->convToOutputCharset($object->ref_customer), 65), '', 'R'); } if (!empty($conf->global->PDF_SHOW_PROJECT_TITLE)) { diff --git a/htdocs/core/modules/import/import_csv.modules.php b/htdocs/core/modules/import/import_csv.modules.php index 1213cc4cf16..8ad5ef94b2f 100644 --- a/htdocs/core/modules/import/import_csv.modules.php +++ b/htdocs/core/modules/import/import_csv.modules.php @@ -96,6 +96,8 @@ class ImportCsv extends ModeleImports public function __construct($db, $datatoimport) { global $conf, $langs; + + parent::__construct(); $this->db = $db; $this->separator = (GETPOST('separator') ?GETPOST('separator') : (empty($conf->global->IMPORT_CSV_SEPARATOR_TO_USE) ? ',' : $conf->global->IMPORT_CSV_SEPARATOR_TO_USE)); @@ -649,7 +651,7 @@ class ImportCsv extends ModeleImports break; } $classinstance = new $class($this->db); - $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $listfields, ($key - 1))); + $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $arrayfield, ($key - 1))); $newval = $res; // We get new value computed. } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'numeric') { $newval = price2num($newval); @@ -809,7 +811,7 @@ class ImportCsv extends ModeleImports break; } $classinstance = new $class($this->db); - $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $listfields, ($key - 1))); + $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $arrayfield, ($key - 1))); $fieldArr = explode('.', $fieldname); if (count($fieldArr) > 0) { $fieldname = $fieldArr[1]; @@ -870,6 +872,10 @@ class ImportCsv extends ModeleImports $filters[] = $col.' = '.$data[$key]; } } + if (!empty($tablewithentity_cache[$tablename])) { + $where[] = "entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")"; + $filters[] = "entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")"; + } $sqlSelect .= " WHERE ".implode(' AND ', $where); $resql = $this->db->query($sqlSelect); @@ -906,6 +912,10 @@ class ImportCsv extends ModeleImports } $sqlSelect .= " WHERE ".$keyfield." = ".((int) $lastinsertid); + if (!empty($tablewithentity_cache[$tablename])) { + $sqlSelect .= " AND entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")"; + } + $resql = $this->db->query($sqlSelect); if ($resql) { $res = $this->db->fetch_object($resql); @@ -951,6 +961,10 @@ class ImportCsv extends ModeleImports $sqlend = " WHERE " . implode(' AND ', $where); } + if (!empty($tablewithentity_cache[$tablename])) { + $sqlend .= " AND entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")"; + } + $sql = $sqlstart.$sqlend; // Run update request diff --git a/htdocs/core/modules/import/import_xlsx.modules.php b/htdocs/core/modules/import/import_xlsx.modules.php index c7f6df31d03..4ced5a7dff4 100644 --- a/htdocs/core/modules/import/import_xlsx.modules.php +++ b/htdocs/core/modules/import/import_xlsx.modules.php @@ -106,6 +106,8 @@ class ImportXlsx extends ModeleImports public function __construct($db, $datatoimport) { global $conf, $langs; + + parent::__construct(); $this->db = $db; // this is used as an extension from the example file code, so we have to put xlsx here !!! @@ -694,7 +696,7 @@ class ImportXlsx extends ModeleImports break; } $classinstance = new $class($this->db); - $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $listfields, $key)); + $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $arrayfield, $key)); $newval = $res; // We get new value computed. } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'numeric') { $newval = price2num($newval); @@ -853,7 +855,7 @@ class ImportXlsx extends ModeleImports break; } $classinstance = new $class($this->db); - $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $listfields, $key)); + $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $arrayfield, $key)); $fieldArr = explode('.', $fieldname); if (count($fieldArr) > 0) { $fieldname = $fieldArr[1]; @@ -916,6 +918,10 @@ class ImportXlsx extends ModeleImports $filters[] = $col.' = '.$data[$key]; } } + if (!empty($tablewithentity_cache[$tablename])) { + $where[] = "entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")"; + $filters[] = "entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")"; + } $sqlSelect .= " WHERE " . implode(' AND ', $where); $resql = $this->db->query($sqlSelect); @@ -953,6 +959,10 @@ class ImportXlsx extends ModeleImports } $sqlSelect .= " WHERE ".$keyfield." = ".((int) $lastinsertid); + if (!empty($tablewithentity_cache[$tablename])) { + $sqlSelect .= " AND entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")"; + } + $resql = $this->db->query($sqlSelect); if ($resql) { $res = $this->db->fetch_object($resql); @@ -998,6 +1008,10 @@ class ImportXlsx extends ModeleImports $sqlend = " WHERE " . implode(' AND ', $where); } + if (!empty($tablewithentity_cache[$tablename])) { + $sqlend .= " AND entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")"; + } + $sql = $sqlstart . $sqlend; // Run update request diff --git a/htdocs/core/modules/import/modules_import.php b/htdocs/core/modules/import/modules_import.php index fa4a5ad3692..5fe408f6dd5 100644 --- a/htdocs/core/modules/import/modules_import.php +++ b/htdocs/core/modules/import/modules_import.php @@ -75,14 +75,53 @@ class ModeleImports public $libversion = array(); + /** + * @var array Element mapping from table name + */ + public static $mapTableToElement = array( + 'actioncomm' => 'agenda', + 'adherent' => 'member', + 'adherent_type' => 'member_type', + //'bank_account' => 'bank_account', + 'categorie' => 'category', + //'commande' => 'commande', + //'commande_fournisseur' => 'commande_fournisseur', + 'contrat' => 'contract', + 'entrepot' => 'stock', + //'expensereport' => 'expensereport', + 'facture' => 'invoice', + //'facture_fourn' => 'facture_fourn', + 'fichinter' => 'intervention', + //'holiday' => 'holiday', + //'product' => 'product', + 'product_price' => 'productprice', + 'product_fournisseur_price' => 'productsupplierprice', + 'projet' => 'project', + //'propal' => 'propal', + //'societe' => 'societe', + 'socpeople' => 'contact', + //'supplier_proposal' => 'supplier_proposal', + //'ticket' => 'ticket', + ); /** * Constructor */ public function __construct() { - } + global $hookmanager; + if (is_object($hookmanager)) { + $hookmanager->initHooks(array('import')); + $parameters = array(); + $reshook = $hookmanager->executeHooks('constructModeleImports', $parameters, $this); + if ($reshook >= 0 && !empty($hookmanager->resArray)) { + foreach ($hookmanager->resArray as $mapList) { + self::$mapTableToElement[$mapList['table']] = $mapList['element']; + } + } + } + } /** * getDriverId @@ -267,4 +306,22 @@ class ModeleImports { return $this->libversion[$key]; } + + /** + * Get element from table name with prefix + * + * @param string $tableNameWithPrefix Table name with prefix + * @return string Element name or table element as default + */ + public function getElementFromTableWithPrefix($tableNameWithPrefix) + { + $tableElement = preg_replace('/^'.preg_quote($this->db->prefix(), '/').'/', '', $tableNameWithPrefix); + $element = $tableElement; + + if (isset(self::$mapTableToElement[$tableElement])) { + $element = self::$mapTableToElement[$tableElement]; + } + + return $element; + } } diff --git a/htdocs/core/modules/modEventOrganization.class.php b/htdocs/core/modules/modEventOrganization.class.php index f037f26176c..1bec1c5c67e 100644 --- a/htdocs/core/modules/modEventOrganization.class.php +++ b/htdocs/core/modules/modEventOrganization.class.php @@ -375,6 +375,11 @@ class modEventOrganization extends DolibarrModules include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; $formmail = new FormMail($this->db); + include_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php'; + if (!is_object($user)) { + $user = new User($this->db); // To avoid error during migration + } + $template = $formmail->getEMailTemplate($this->db, 'conferenceorbooth', $user, $langs, 0, 1, '(EventOrganizationEmailAskConf)'); if ($template->id > 0) { dolibarr_set_const($this->db, 'EVENTORGANIZATION_TEMPLATE_EMAIL_ASK_CONF', $template->id, 'chaine', 0, '', $conf->entity); diff --git a/htdocs/core/modules/modFacture.class.php b/htdocs/core/modules/modFacture.class.php index e3d39ea5848..64fca2dde60 100644 --- a/htdocs/core/modules/modFacture.class.php +++ b/htdocs/core/modules/modFacture.class.php @@ -135,7 +135,7 @@ class modFacture extends DolibarrModules 'objectname'=>'Facture', 'method'=>'sendEmailsRemindersOnInvoiceDueDate', 'parameters'=>"10,all,EmailTemplateCode", - 'comment'=>'Send an emails when the unpaid invoices reach a due date + n days = today. First param is the offset n of days, second parameter is "all" or a payment mode code, last parameter is the code of email template to use (an email template with EmailTemplateCode must exists. The version in the language of the thirdparty will be used in priority to update the PDF of the sent invoice).', + 'comment'=>'Send an emails when we reach the due date - n days of an invoice. First param is n, the number of days before due date to send the remind, second parameter is "all" or a payment mode code, last parameter is the code of email template to use (an email template with the EmailTemplateCode must exists. The version of the email template in the language of the thirdparty will be used in priority. Language of the thirdparty will be also used to update the PDF of the sent invoice).', 'frequency'=>1, 'unitfrequency'=>3600 * 24, 'priority'=>50, diff --git a/htdocs/core/modules/modFournisseur.class.php b/htdocs/core/modules/modFournisseur.class.php index b6286c35162..27c15bda16f 100644 --- a/htdocs/core/modules/modFournisseur.class.php +++ b/htdocs/core/modules/modFournisseur.class.php @@ -41,7 +41,7 @@ class modFournisseur extends DolibarrModules */ public function __construct($db) { - global $conf, $user; + global $conf, $langs, $user; $this->db = $db; $this->numero = 40; @@ -309,6 +309,8 @@ class modFournisseur extends DolibarrModules //-------- $r = 0; + $langs->loadLangs(array("suppliers", "multicurrency")); + $r++; $this->export_code[$r] = $this->rights_class.'_'.$r; $this->export_label[$r] = 'Vendor invoices and lines of invoices'; diff --git a/htdocs/core/modules/modProduct.class.php b/htdocs/core/modules/modProduct.class.php index 96fdb779b0b..a6fc98ffc08 100644 --- a/htdocs/core/modules/modProduct.class.php +++ b/htdocs/core/modules/modProduct.class.php @@ -517,7 +517,7 @@ class modProduct extends DolibarrModules 'p.price_base_type' => "PriceBaseType", //price base: with-tax (TTC) or without (HT) tax. Displays accordingly in Product card 'p.tva_tx' => 'VATRate', 'p.datec' => 'DateCreation', - 'p.cost_price' => "CostPrice", + 'p.cost_price' => "CostPrice" ); $this->import_convertvalue_array[$r] = array( @@ -748,6 +748,33 @@ class modProduct extends DolibarrModules $this->import_updatekeys_array[$r] = array_merge($this->import_updatekeys_array[$r], array('p.barcode'=>'BarCode')); //only show/allow barcode as update key if Barcode module enabled } + if (!empty($conf->global->STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE)) { + // Import products limit and desired stock by product and warehouse + $r++; + $this->import_code[$r] = $this->rights_class.'_stock_by_warehouse'; + $this->import_label[$r] = "ProductStockWarehouse"; // Translation key + $this->import_icon[$r] = $this->picto; + $this->import_entities_array[$r] = array(); // We define here only fields that use another icon that the one defined into import_icon + $this->import_tables_array[$r] = array('pwp'=>MAIN_DB_PREFIX.'product_warehouse_properties'); + $this->import_fields_array[$r] = array('pwp.fk_product'=>"Product*", + 'pwp.fk_entrepot'=>"Warehouse*", 'pwp.seuil_stock_alerte'=>"StockLimit", + 'pwp.desiredstock'=>"DesiredStock"); + $this->import_regex_array[$r] = array( + 'pwp.fk_product' => 'rowid@'.MAIN_DB_PREFIX.'product', + 'pwp.fk_entrepot' => 'rowid@'.MAIN_DB_PREFIX.'entrepot', + ); + $this->import_convertvalue_array[$r] = array( + 'pwp.fk_product'=>array('rule'=>'fetchidfromref', 'classfile'=>'/product/class/product.class.php', 'class'=>'Product', 'method'=>'fetch', 'element'=>'Product') + ,'pwp.fk_entrepot'=>array('rule'=>'fetchidfromref', 'classfile'=>'/product/stock/class/entrepot.class.php', 'class'=>'Entrepot', 'method'=>'fetch', 'element'=>'Entrepot') + ); + $this->import_examplevalues_array[$r] = array('pwp.fk_product'=>"ref:PRODUCT_REF or id:123456", + 'pwp.fk_entrepot'=>"ref:WAREHOUSE_REF or id:123456", + 'pwp.seuil_stock_alerte'=>"100", + 'pwp.desiredstock'=>"110" + ); + $this->import_updatekeys_array[$r] = array('pwp.fk_product'=>'Product', 'pwp.fk_entrepot'=>'Warehouse'); + } + if ((isModEnabled("fournisseur") && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) || isModEnabled("supplier_order") || isModEnabled("supplier_invoice")) { // Import suppliers prices (note: this code is duplicated in module Service) $r++; @@ -764,8 +791,9 @@ class modProduct extends DolibarrModules 'sp.quantity' => "QtyMin*", 'sp.tva_tx' => 'VATRate', 'sp.default_vat_code' => 'VATCode', - 'sp.delivery_time_days' => 'DeliveryDelay', - 'sp.supplier_reputation' => 'SupplierReputation' + 'sp.delivery_time_days' => 'NbDaysToDelivery', + 'sp.supplier_reputation' => 'SupplierReputation', + 'sp.status' => 'Status' ); if (is_object($mysoc) && $usenpr) { $this->import_fields_array[$r] = array_merge($this->import_fields_array[$r], array('sp.recuperableonly'=>'VATNPR')); @@ -827,7 +855,8 @@ class modProduct extends DolibarrModules 'sp.remise_percent'=>'0', 'sp.default_vat_code' => '', 'sp.delivery_time_days' => '5', - 'sp.supplier_reputation' => 'FAVORITE / NOTTHGOOD / DONOTORDER' + 'sp.supplier_reputation' => 'FAVORITE / NOTTHGOOD / DONOTORDER', + 'sp.status' => '1' ); if (is_object($mysoc) && $usenpr) { $this->import_examplevalues_array[$r] = array_merge($this->import_examplevalues_array[$r], array('sp.recuperableonly'=>'')); diff --git a/htdocs/core/modules/modService.class.php b/htdocs/core/modules/modService.class.php index a316c746acb..b4a6d2f6025 100644 --- a/htdocs/core/modules/modService.class.php +++ b/htdocs/core/modules/modService.class.php @@ -722,7 +722,7 @@ class modService extends DolibarrModules 'sp.quantity' => "QtyMin*", 'sp.tva_tx' => 'VATRate', 'sp.default_vat_code' => 'VATCode', - 'sp.delivery_time_days' => 'DeliveryDelay', + 'sp.delivery_time_days' => 'NbDaysToDelivery', 'sp.supplier_reputation' => 'SupplierReputation' ); if (is_object($mysoc) && $usenpr) { diff --git a/htdocs/core/modules/modSupplierProposal.class.php b/htdocs/core/modules/modSupplierProposal.class.php index c775744c6e7..674ba46601a 100644 --- a/htdocs/core/modules/modSupplierProposal.class.php +++ b/htdocs/core/modules/modSupplierProposal.class.php @@ -36,7 +36,6 @@ include_once DOL_DOCUMENT_ROOT.'/core/modules/DolibarrModules.class.php'; */ class modSupplierProposal extends DolibarrModules { - /** * Constructor. Define names, constants, directories, boxes, permissions * diff --git a/htdocs/core/modules/modWebServices.class.php b/htdocs/core/modules/modWebServices.class.php index 6f2e8e21c3e..2e03c6759ee 100644 --- a/htdocs/core/modules/modWebServices.class.php +++ b/htdocs/core/modules/modWebServices.class.php @@ -45,8 +45,8 @@ class modWebServices extends DolibarrModules // Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module) $this->name = preg_replace('/^mod/i', '', get_class($this)); $this->description = "Enable the Dolibarr web services server"; - // Possible values for version are: 'development', 'experimental', 'dolibarr' or version - $this->version = 'dolibarr'; + // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated', 'experimental_deprecated' or a version string like 'x.y.z' + $this->version = 'dolibarr_deprecated'; // Key used in llx_const table to save module status enabled/disabled (where MYMODULE is value of property name of module in uppercase) $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); // Name of image file used for this module. diff --git a/htdocs/core/modules/modWebhook.class.php b/htdocs/core/modules/modWebhook.class.php index c8ddea7dc06..e9f3e7f5baa 100644 --- a/htdocs/core/modules/modWebhook.class.php +++ b/htdocs/core/modules/modWebhook.class.php @@ -260,17 +260,17 @@ class modWebhook extends DolibarrModules // Add here entries to declare new permissions /* BEGIN MODULEBUILDER PERMISSIONS */ $this->rights[$r][0] = $this->numero . sprintf("%02d", $r + 1); // Permission id (must not be already used) - $this->rights[$r][1] = 'Read objects of Webhook'; // Permission label + $this->rights[$r][1] = 'Read Webhooks'; // Permission label $this->rights[$r][4] = 'webhook_target'; $this->rights[$r][5] = 'read'; // In php code, permission will be checked by test if ($user->rights->webhook->webhook_target->read) $r++; $this->rights[$r][0] = $this->numero . sprintf("%02d", $r + 1); // Permission id (must not be already used) - $this->rights[$r][1] = 'Create/Update objects of Webhook'; // Permission label + $this->rights[$r][1] = 'Create/Update Webhooks'; // Permission label $this->rights[$r][4] = 'webhook_target'; $this->rights[$r][5] = 'write'; // In php code, permission will be checked by test if ($user->rights->webhook->webhook_target->write) $r++; $this->rights[$r][0] = $this->numero . sprintf("%02d", $r + 1); // Permission id (must not be already used) - $this->rights[$r][1] = 'Delete objects of Webhook'; // Permission label + $this->rights[$r][1] = 'Delete Webhooks'; // Permission label $this->rights[$r][4] = 'webhook_target'; $this->rights[$r][5] = 'delete'; // In php code, permission will be checked by test if ($user->rights->webhook->webhook_target->delete) $r++; diff --git a/htdocs/core/modules/printing/printgcp.modules.php b/htdocs/core/modules/printing/printgcp.modules.php index c1b6ba6c86e..d62dbd94ab2 100644 --- a/htdocs/core/modules/printing/printgcp.modules.php +++ b/htdocs/core/modules/printing/printgcp.modules.php @@ -121,7 +121,7 @@ class printing_printgcp extends PrintingDriver $this->google_id = getDolGlobalString('OAUTH_GOOGLE_ID'); $this->google_secret = getDolGlobalString('OAUTH_GOOGLE_SECRET'); // Token storage - $storage = new DoliStorage($this->db, $this->conf, $keyforprovider); + $storage = new DoliStorage($this->db, $conf, $keyforprovider); //$storage->clearToken($this->OAUTH_SERVICENAME_GOOGLE); // Setup the credentials for the requests $credentials = new Credentials( @@ -255,12 +255,13 @@ class printing_printgcp extends PrintingDriver */ public function getlistAvailablePrinters() { + global $conf; $ret = array(); $keyforprovider = ''; // @FIXME // Token storage - $storage = new DoliStorage($this->db, $this->conf, $keyforprovider); + $storage = new DoliStorage($this->db, $conf, $keyforprovider); // Setup the credentials for the requests $credentials = new Credentials( $this->google_id, @@ -377,6 +378,7 @@ class printing_printgcp extends PrintingDriver */ public function sendPrintToPrinter($printerid, $printjobtitle, $filepath, $contenttype) { + global $conf; // Check if printer id if (empty($printerid)) { return array('status' =>0, 'errorcode' =>'', 'errormessage'=>'No provided printer ID'); @@ -401,7 +403,7 @@ class printing_printgcp extends PrintingDriver $keyforprovider = ''; // @FIXME // Dolibarr Token storage - $storage = new DoliStorage($this->db, $this->conf, $keyforprovider); + $storage = new DoliStorage($this->db, $conf, $keyforprovider); // Setup the credentials for the requests $credentials = new Credentials( $this->google_id, @@ -453,7 +455,7 @@ class printing_printgcp extends PrintingDriver $keyforprovider = ''; // @FIXME // Token storage - $storage = new DoliStorage($this->db, $this->conf, $keyforprovider); + $storage = new DoliStorage($this->db, $conf, $keyforprovider); // Setup the credentials for the requests $credentials = new Credentials( $this->google_id, diff --git a/htdocs/core/modules/project/doc/pdf_baleine.modules.php b/htdocs/core/modules/project/doc/pdf_baleine.modules.php index 2bfd73757c9..06f6e400b75 100644 --- a/htdocs/core/modules/project/doc/pdf_baleine.modules.php +++ b/htdocs/core/modules/project/doc/pdf_baleine.modules.php @@ -195,11 +195,11 @@ class pdf_baleine extends ModelePDFProjects // Load traductions files required by page $outputlangs->loadLangs(array("main", "dict", "companies", "projects")); - if ($conf->project->dir_output) { + if ($conf->project->multidir_output[$object->entity]) { //$nblines = count($object->lines); // This is set later with array of tasks $objectref = dol_sanitizeFileName($object->ref); - $dir = $conf->project->dir_output; + $dir = $conf->project->multidir_output[$object->entity]; if (!preg_match('/specimen/i', $objectref)) { $dir .= "/".$objectref; } diff --git a/htdocs/core/modules/project/doc/pdf_beluga.modules.php b/htdocs/core/modules/project/doc/pdf_beluga.modules.php index c1365fde536..ba175dc7c52 100644 --- a/htdocs/core/modules/project/doc/pdf_beluga.modules.php +++ b/htdocs/core/modules/project/doc/pdf_beluga.modules.php @@ -242,11 +242,11 @@ class pdf_beluga extends ModelePDFProjects // Load traductions files required by page $outputlangs->loadLangs(array("main", "dict", "companies", "projects")); - if ($conf->project->dir_output) { + if ($conf->project->multidir_output[$object->entity]) { //$nblines = count($object->lines); // This is set later with array of tasks $objectref = dol_sanitizeFileName($object->ref); - $dir = $conf->project->dir_output; + $dir = $conf->project->multidir_output[$object->entity]; if (!preg_match('/specimen/i', $objectref)) { $dir .= "/".$objectref; } diff --git a/htdocs/core/modules/project/doc/pdf_timespent.modules.php b/htdocs/core/modules/project/doc/pdf_timespent.modules.php index c5aa80d5748..31a8127f733 100644 --- a/htdocs/core/modules/project/doc/pdf_timespent.modules.php +++ b/htdocs/core/modules/project/doc/pdf_timespent.modules.php @@ -195,11 +195,11 @@ class pdf_timespent extends ModelePDFProjects // Load traductions files required by page $outputlangs->loadLangs(array("main", "dict", "companies", "projects")); - if ($conf->project->dir_output) { + if ($conf->project->multidir_output[$object->entity]) { //$nblines = count($object->lines); // This is set later with array of tasks $objectref = dol_sanitizeFileName($object->ref); - $dir = $conf->project->dir_output; + $dir = $conf->project->multidir_output[$object->entity]; if (!preg_match('/specimen/i', $objectref)) { $dir .= "/".$objectref; } diff --git a/htdocs/core/modules/syslog/mod_syslog_file.php b/htdocs/core/modules/syslog/mod_syslog_file.php index 73ebc0d1d90..116e49487f9 100644 --- a/htdocs/core/modules/syslog/mod_syslog_file.php +++ b/htdocs/core/modules/syslog/mod_syslog_file.php @@ -125,7 +125,7 @@ class mod_syslog_file extends LogHandler implements LogHandlerInterface } } - return $suffixinfilename ?preg_replace('/\.log$/i', $suffixinfilename.'.log', $tmp) : $tmp; + return $suffixinfilename ? preg_replace('/\.log$/i', $suffixinfilename.'.log', $tmp) : $tmp; } /** diff --git a/htdocs/core/tpl/admin_extrafields_add.tpl.php b/htdocs/core/tpl/admin_extrafields_add.tpl.php index 00dec927f9e..5404f831a65 100644 --- a/htdocs/core/tpl/admin_extrafields_add.tpl.php +++ b/htdocs/core/tpl/admin_extrafields_add.tpl.php @@ -209,7 +209,7 @@ $listofexamplesforlink = 'Societe:societe/class/societe.class.php
Contact:con textwithpicto($langs->trans("DisplayOnPdf"), $langs->trans("DisplayOnPdfDesc")); ?> -trans("Totalizable"); ?>> +trans("Totalizable"); ?>> textwithpicto($langs->trans("CssOnEdit"), $langs->trans("HelpCssOnEditDesc")); ?> @@ -220,7 +220,7 @@ $listofexamplesforlink = 'Societe:societe/class/societe.class.php
Contact:con textwithpicto($langs->trans("HelpOnTooltip"), $langs->trans("HelpOnTooltipDesc")); ?> - trans("AllEntities"); ?>> + trans("AllEntities"); ?>> diff --git a/htdocs/core/tpl/bloc_showhide.tpl.php b/htdocs/core/tpl/bloc_showhide.tpl.php index ee67fa6b74a..047e09a1e93 100644 --- a/htdocs/core/tpl/bloc_showhide.tpl.php +++ b/htdocs/core/tpl/bloc_showhide.tpl.php @@ -52,9 +52,9 @@ print ' $("#hide-'.$blocname.'").show();'."\n"; print '});'."\n"; print 'function setShowHide(status) {'."\n"; -print ' var id = '.$object->id.";\n"; -print " var element = '".$object->element."';\n"; -print " var htmlelement = '".$blocname."';\n"; +print ' var id = '.((int) $object->id).";\n"; +print " var element = '".dol_escape_js($object->element)."';\n"; +print " var htmlelement = '".dol_escape_js($blocname)."';\n"; print ' var type = "showhide";'."\n"; print ' $.get("'.dol_buildpath('/core/ajax/extraparams.php', 1); print '?id="+id+"&element="+element+"&htmlelement="+htmlelement+"&type="+type+"&value="+status);'."\n"; diff --git a/htdocs/core/tpl/extrafields_list_search_input.tpl.php b/htdocs/core/tpl/extrafields_list_search_input.tpl.php index f57101b81e6..3f90715cbea 100644 --- a/htdocs/core/tpl/extrafields_list_search_input.tpl.php +++ b/htdocs/core/tpl/extrafields_list_search_input.tpl.php @@ -47,7 +47,7 @@ if (!empty($extrafieldsobjectkey)) { // $extrafieldsobject is the $object->table if (in_array($typeofextrafield, array('link', 'sellist', 'text', 'html'))) { $morecss = 'maxwidth200'; } - echo $extrafields->showInputField($key, (empty($search_array_options[$search_options_pattern.$tmpkey]) ? '' : $search_array_options[$search_options_pattern.$tmpkey]), '', '', $search_options_pattern, $morecss, 0, $extrafieldsobjectkey, 1); + echo $extrafields->showInputField($key, (!isset($search_array_options[$search_options_pattern.$tmpkey]) ? '' : $search_array_options[$search_options_pattern.$tmpkey]), '', '', $search_options_pattern, $morecss, 0, $extrafieldsobjectkey, 1); } print ''; } diff --git a/htdocs/core/tpl/extrafields_view.tpl.php b/htdocs/core/tpl/extrafields_view.tpl.php index ec7578e0aa4..38b99fc5736 100644 --- a/htdocs/core/tpl/extrafields_view.tpl.php +++ b/htdocs/core/tpl/extrafields_view.tpl.php @@ -212,7 +212,7 @@ if (empty($reshook) && isset($extrafields->attributes[$object->table_element]['l $html_id = !empty($object->id) ? $object->element.'_extras_'.$tmpkeyextra.'_'.$object->id : ''; - print ''; + print ''; // Convert date into timestamp format if (in_array($extrafields->attributes[$object->table_element]['type'][$tmpkeyextra], array('date'))) { diff --git a/htdocs/core/tpl/filemanager.tpl.php b/htdocs/core/tpl/filemanager.tpl.php index da73f5cd4b6..01bad2e8f44 100644 --- a/htdocs/core/tpl/filemanager.tpl.php +++ b/htdocs/core/tpl/filemanager.tpl.php @@ -92,7 +92,7 @@ if ($module == 'ecm') { print '
'; } if ($permtoadd && GETPOSTISSET('website')) { // If on file manager to manage medias of a web site - print 'ref.'" class="inline-block valignmiddle toolbarbutton paddingtop" title="'.dol_escape_htmltag($langs->trans("GenerateImgWebp")).'">'; + print 'ref).'" class="inline-block valignmiddle toolbarbutton paddingtop" title="'.dol_escape_htmltag($langs->trans("GenerateImgWebp")).'">'; print img_picto('', 'images', '', false, 0, 0, '', 'size15x flip marginrightonly'); print ''; } elseif ($permtoadd && $module == 'ecm') { // If on file manager medias in ecm @@ -205,7 +205,10 @@ if ($action == 'confirmconvertimgwebp') { if ($module == 'medias') { $formquestion['website']=array('type'=>'hidden', 'value'=>$website->ref, 'name'=>'website'); } - print $form->formconfirm($_SERVER["PHP_SELF"], empty($file) ? $langs->trans('ConfirmImgWebpCreation') : $langs->trans('ConfirmChosenImgWebpCreation'), empty($file) ? $langs->trans('ConfirmGenerateImgWebp') : $langs->trans('ConfirmGenerateChosenImgWebp'), 'convertimgwebp', $formquestion, "yes", 1); + $param = ''; + if (!empty($sortfield)) $param .= '&sortfield='.urlencode($sortfield); + if (!empty($sortorder)) $param .= '&sortorder='.urlencode($sortorder); + print $form->formconfirm($_SERVER["PHP_SELF"].($param ? '?'.$param : ''), empty($file) ? $langs->trans('ConfirmImgWebpCreation') : $langs->trans('ConfirmChosenImgWebpCreation'), empty($file) ? $langs->trans('ConfirmGenerateImgWebp') : $langs->trans('ConfirmGenerateChosenImgWebp'), 'convertimgwebp', $formquestion, "yes", 1); $action = 'file_manager'; } diff --git a/htdocs/core/tpl/passwordforgotten.tpl.php b/htdocs/core/tpl/passwordforgotten.tpl.php index 05731dbb408..deec94ee004 100644 --- a/htdocs/core/tpl/passwordforgotten.tpl.php +++ b/htdocs/core/tpl/passwordforgotten.tpl.php @@ -238,21 +238,23 @@ if (!empty($morelogincontent)) { -'; } } else { + print ''; } ?> -

diff --git a/htdocs/core/tpl/passwordreset.tpl.php b/htdocs/core/tpl/passwordreset.tpl.php index ea79ec98180..e3202ff511f 100644 --- a/htdocs/core/tpl/passwordreset.tpl.php +++ b/htdocs/core/tpl/passwordreset.tpl.php @@ -118,7 +118,7 @@ if ($setnewpassword && $username && $passworduidhash) { ?> - + global->MAIN_LOGIN_BACKGROUND) ? '' : ' style="background-size: cover; background-position: center center; background-attachment: fixed; background-repeat: no-repeat; background-image: url(\''.DOL_URL_ROOT.'/viewimage.php?cache=1&noalt=1&modulepart=mycompany&file='.urlencode('logos/'.$conf->global->MAIN_LOGIN_BACKGROUND).'\')"'; ?>> @@ -279,21 +279,23 @@ if (!empty($morelogincontent)) { -'; } } else { + print ''; } ?> -

diff --git a/htdocs/core/website.inc.php b/htdocs/core/website.inc.php index 769f8edd8a4..4d067f992d6 100644 --- a/htdocs/core/website.inc.php +++ b/htdocs/core/website.inc.php @@ -122,6 +122,7 @@ if (!defined('USEDOLIBARRSERVER') && !defined('USEDOLIBARREDITOR')) { $contentsecuritypolicy = getDolGlobalString('WEBSITE_MAIN_SECURITY_FORCECSPRO'); if (!is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; $hookmanager = new HookManager($db); } $hookmanager->initHooks(array("main")); @@ -154,6 +155,7 @@ if (!defined('USEDOLIBARRSERVER') && !defined('USEDOLIBARREDITOR')) { $contentsecuritypolicy = getDolGlobalString('WEBSITE_MAIN_SECURITY_FORCECSP'); if (!is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; $hookmanager = new HookManager($db); } $hookmanager->initHooks(array("main")); diff --git a/htdocs/cron/class/cronjob.class.php b/htdocs/cron/class/cronjob.class.php index b12a2b909cf..7e288f265ba 100644 --- a/htdocs/cron/class/cronjob.class.php +++ b/htdocs/cron/class/cronjob.class.php @@ -741,7 +741,7 @@ class Cronjob extends CommonObject // Check parameters // Put here code to add a control on parameters values - if (dol_strlen($this->datenextrun) == 0) { + if (dol_strlen($this->datenextrun) == 0 && $this->status == self::STATUS_ENABLED) { $this->errors[] = $langs->trans('CronFieldMandatory', $langs->transnoentitiesnoconv('CronDtNextLaunch')); $error++; } @@ -995,17 +995,28 @@ class Cronjob extends CommonObject if (isset($this->status)) { $label .= ' '.$this->getLibStatut(5); } - $label .= '
'.$langs->trans('Ref').': '.$this->ref; + $label .= '
'.$langs->trans('Ref').': '.dol_escape_htmltag($this->ref); $label .= '
'.$langs->trans('Title').': '.$langs->trans($this->label); if ($this->label != $langs->trans($this->label)) { $label .= ' ('.$this->label.')'; } + if (!empty($this->params)) { + $label .= '
'.$langs->trans('Parameters').': '.dol_escape_htmltag($this->params); + } + $label .= '
'; + if (!empty($this->datestart)) { $label .= '
'.$langs->trans('CronDtStart').': '.dol_print_date($this->datestart, 'dayhour', 'tzuserrel'); } if (!empty($this->dateend)) { $label .= '
'.$langs->trans('CronDtEnd').': '.dol_print_date($this->dateend, 'dayhour', 'tzuserrel'); } + if (!empty($this->datelastrun)) { + $label .= '
'.$langs->trans('CronDtLastLaunch').': '.dol_print_date($this->datelastrun, 'dayhour', 'tzuserrel'); + } + if (!empty($this->datenextrun)) { + $label .= '
'.$langs->trans('CronDtNextLaunch').': '.dol_print_date($this->datenextrun, 'dayhour', 'tzuserrel'); + } $url = DOL_URL_ROOT.'/cron/card.php?id='.$this->id; diff --git a/htdocs/cron/list.php b/htdocs/cron/list.php index aaccb39e68e..fd3f705b7aa 100644 --- a/htdocs/cron/list.php +++ b/htdocs/cron/list.php @@ -509,6 +509,9 @@ if ($num > 0) { $object->datestart = $db->jdate($obj->datestart); $object->dateend = $db->jdate($obj->dateend); $object->module_name = $obj->module_name; + $object->params = $obj->params; + $object->datelastrun = $db->jdate($obj->datelastrun); + $object->datenextrun = $db->jdate($obj->datenextrun); $datelastrun = $db->jdate($obj->datelastrun); $datelastresult = $db->jdate($obj->datelastresult); diff --git a/htdocs/datapolicy/class/datapolicy.class.php b/htdocs/datapolicy/class/datapolicy.class.php index 7bbe8d7c1a6..e83730c89e2 100644 --- a/htdocs/datapolicy/class/datapolicy.class.php +++ b/htdocs/datapolicy/class/datapolicy.class.php @@ -44,7 +44,7 @@ class DataPolicy /** * getAllContactNotInformed * - * @return number + * @return integer */ public function getAllContactNotInformed() { @@ -75,12 +75,14 @@ class DataPolicy $this->error = $this->db->error(); return -1; } + + return 1; } /** * getAllCompaniesNotInformed * - * @return number + * @return integer */ public function getAllCompaniesNotInformed() { @@ -110,12 +112,14 @@ class DataPolicy $this->error = $this->db->error(); return -1; } + + return 1; } /** * getAllAdherentsNotInformed * - * @return number + * @return integer */ public function getAllAdherentsNotInformed() { @@ -145,6 +149,8 @@ class DataPolicy $this->error = $this->db->error(); return -1; } + + return 1; } /** diff --git a/htdocs/delivery/class/delivery.class.php b/htdocs/delivery/class/delivery.class.php index 61309a1cfae..bf8f68b3bbf 100644 --- a/htdocs/delivery/class/delivery.class.php +++ b/htdocs/delivery/class/delivery.class.php @@ -775,10 +775,11 @@ class Delivery extends CommonObject $dataparams = ''; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { $classfortooltip = 'classforajaxtooltip'; - $dataparams = ' data-params='.json_encode($params); - // $label = $langs->trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); $url = DOL_URL_ROOT.'/delivery/card.php?id='.$this->id; @@ -794,7 +795,9 @@ class Delivery extends CommonObject } //} - $linkstart = ''; + $linkstart = ''; $linkend = ''; if ($withpicto) { diff --git a/htdocs/don/class/paymentdonation.class.php b/htdocs/don/class/paymentdonation.class.php index 1aceca10c16..1769033df28 100644 --- a/htdocs/don/class/paymentdonation.class.php +++ b/htdocs/don/class/paymentdonation.class.php @@ -134,7 +134,7 @@ class PaymentDonation extends CommonObject $now = dol_now(); // Validate parameters - if (!$this->datepaid) { + if (!$this->datep) { $this->error = 'ErrorBadValueForParameterCreatePaymentDonation'; return -1; } @@ -193,7 +193,7 @@ class PaymentDonation extends CommonObject $sql .= " fk_typepayment, num_payment, note, ext_payment_id, ext_payment_site,"; $sql .= " fk_user_creat, fk_bank)"; $sql .= " VALUES (".((int) $this->chid).", '".$this->db->idate($now)."',"; - $sql .= " '".$this->db->idate($this->datepaid)."',"; + $sql .= " '".$this->db->idate($this->datep)."',"; $sql .= " ".((float) price2num($totalamount)).","; $sql .= " ".((int) $this->paymenttype).", '".$this->db->escape($this->num_payment)."', '".$this->db->escape($this->note_public)."', "; $sql .= " ".($this->ext_payment_id ? "'".$this->db->escape($this->ext_payment_id)."'" : "null").", ".($this->ext_payment_site ? "'".$this->db->escape($this->ext_payment_site)."'" : "null").","; @@ -588,10 +588,9 @@ class PaymentDonation extends CommonObject if ($mode == 'payment_donation') { $amount = $total; } - // Insert payment into llx_bank $bank_line_id = $acc->addline( - $this->datepaid, + $this->datep, $this->paymenttype, // Payment mode id or code ("CHQ or VIR for example") $label, $amount, diff --git a/htdocs/emailcollector/class/emailcollector.class.php b/htdocs/emailcollector/class/emailcollector.class.php index 108d0460193..4c4aaab84af 100644 --- a/htdocs/emailcollector/class/emailcollector.class.php +++ b/htdocs/emailcollector/class/emailcollector.class.php @@ -948,13 +948,13 @@ class EmailCollector extends CommonObject if (preg_match('/'.$regexstring.'/'.$regexoptions, $sourcestring, $regforval)) { // Overwrite param $tmpproperty $valueextracted = isset($regforval[count($regforval) - 1]) ?trim($regforval[count($regforval) - 1]) : null; - if (strtolower($sourcefield) == 'header') { + if (strtolower($sourcefield) == 'header') { // extract from HEADER if (preg_match('/^options_/', $tmpproperty)) { $object->array_options[preg_replace('/^options_/', '', $tmpproperty)] = $this->decodeSMTPSubject($valueextracted); } else { $object->$tmpproperty = $this->decodeSMTPSubject($valueextracted); } - } else { + } else { // extract from BODY if (preg_match('/^options_/', $tmpproperty)) { $object->array_options[preg_replace('/^options_/', '', $tmpproperty)] = $this->decodeSMTPSubject($valueextracted); } else { @@ -1509,7 +1509,7 @@ class EmailCollector extends CommonObject $emailto = $this->decodeSMTPSubject($overview[0]->to); - $operationslog .= '
Process email '.dol_escape_htmltag($iforemailloop)." - References: ".dol_escape_htmltag($headers['References'])." - Subject: ".dol_escape_htmltag($headers['Subject']); + $operationslog .= '
** Process email '.dol_escape_htmltag($iforemailloop)." - References: ".dol_escape_htmltag($headers['References'])." - Subject: ".dol_escape_htmltag($headers['Subject']); dol_syslog("** Process email ".$iforemailloop." References: ".$headers['References']." Subject: ".$headers['Subject']); @@ -1697,8 +1697,12 @@ class EmailCollector extends CommonObject //print $messagetext; //exit; + $fromstring = ''; + $replytostring = ''; + if (!empty($conf->global->MAIN_IMAP_USE_PHPIMAP)) { $fromstring = $overview['from']; + //$replytostring = empty($overview['reply-to']) ? '' : $overview['reply-to']; $sender = $overview['sender']; $to = $overview['to']; @@ -1709,6 +1713,7 @@ class EmailCollector extends CommonObject $subject = $overview['subject']; } else { $fromstring = $overview[0]->from; + //$replytostring = empty($overview[0]->replyto) ? '' : $overview[0]->replyto; $sender = $overview[0]->sender; $to = $overview[0]->to; @@ -1729,6 +1734,13 @@ class EmailCollector extends CommonObject $from = $fromstring; $fromtext = ''; } + if (preg_match('/^(.*)<(.*)>$/', $replytostring, $reg)) { + $replyto = $reg[2]; + $replytotext = $reg[1]; + } else { + $replyto = $replytostring; + $replytotext = ''; + } $fk_element_id = 0; $fk_element_type = ''; @@ -2025,6 +2037,7 @@ class EmailCollector extends CommonObject $idtouseforthirdparty = ''; $nametouseforthirdparty = ''; $emailtouseforthirdparty = ''; + $namealiastouseforthirdparty = ''; // $actionparam = 'param=SET:aaa' or 'param=EXTRACT:BODY:....' $arrayvaluetouse = dolExplodeIntoArray($actionparam, ';', '='); @@ -2057,23 +2070,30 @@ class EmailCollector extends CommonObject if ($propertytooverwrite == 'id') { $idtouseforthirdparty = isset($regforval[count($regforval) - 1]) ? trim($regforval[count($regforval) - 1]) : null; - $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtolower($sourcefield).' -> Found idtouseforthirdparty='.dol_escape_htmltag($idtouseforthirdparty); + $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found idtouseforthirdparty='.dol_escape_htmltag($idtouseforthirdparty); } elseif ($propertytooverwrite == 'email') { $emailtouseforthirdparty = isset($regforval[count($regforval) - 1]) ? trim($regforval[count($regforval) - 1]) : null; - $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtolower($sourcefield).' -> Found propertytooverwrite='.dol_escape_htmltag($propertytooverwrite); - } else { + $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found emailtouseforthirdparty='.dol_escape_htmltag($emailtouseforthirdparty); + } elseif ($propertytooverwrite == 'name') { $nametouseforthirdparty = isset($regforval[count($regforval) - 1]) ? trim($regforval[count($regforval) - 1]) : null; - $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtolower($sourcefield).' -> Found nametouseforthirdparty='.dol_escape_htmltag($nametouseforthirdparty); + $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found nametouseforthirdparty='.dol_escape_htmltag($nametouseforthirdparty); + } elseif ($propertytooverwrite == 'name_alias') { + $nametouseforthirdparty = isset($regforval[count($regforval) - 1]) ? trim($regforval[count($regforval) - 1]) : null; + + $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found namealiastouseforthirdparty='.dol_escape_htmltag($namealiastouseforthirdparty); + } else { + $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> We discard this, not used to search existing thirdparty'; } } else { // Regex not found $idtouseforthirdparty = null; $nametouseforthirdparty = null; $emailtouseforthirdparty = null; + $namealiastouseforthirdparty = null; - $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtolower($sourcefield).' -> Not found'; + $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Not found'; } //var_dump($object->$tmpproperty);exit; } else { @@ -2085,6 +2105,7 @@ class EmailCollector extends CommonObject } elseif (preg_match('/^(SET|SETIFEMPTY):(.*)$/', $valueforproperty, $reg)) { //if (preg_match('/^options_/', $tmpproperty)) $object->array_options[preg_replace('/^options_/', '', $tmpproperty)] = $reg[1]; //else $object->$tmpproperty = $reg[1]; + // Example: id=SETIFEMPTY:123 if ($propertytooverwrite == 'id') { $idtouseforthirdparty = $reg[2]; @@ -2093,10 +2114,14 @@ class EmailCollector extends CommonObject $emailtouseforthirdparty = $reg[2]; $operationslog .= '
We set property emailtouseforthrdparty='.dol_escape_htmltag($emailtouseforthirdparty); - } else { + } elseif ($propertytooverwrite == 'name') { $nametouseforthirdparty = $reg[2]; $operationslog .= '
We set property nametouseforthirdparty='.dol_escape_htmltag($nametouseforthirdparty); + } elseif ($propertytooverwrite == 'name_alias') { + $namealiastouseforthirdparty = $reg[2]; + + $operationslog .= '
We set property namealiastouseforthirdparty='.dol_escape_htmltag($namealiastouseforthirdparty); } } else { $errorforactions++; @@ -2106,8 +2131,8 @@ class EmailCollector extends CommonObject } } - if (!$errorforactions && ($idtouseforthirdparty || $emailtouseforthirdparty || $nametouseforthirdparty)) { - $result = $thirdpartystatic->fetch($idtouseforthirdparty, $nametouseforthirdparty, '', '', '', '', '', '', '', '', $emailtouseforthirdparty); + if (!$errorforactions && ($idtouseforthirdparty || $emailtouseforthirdparty || $nametouseforthirdparty || $namealiastouseforthirdparty)) { + $result = $thirdpartystatic->fetch($idtouseforthirdparty, $nametouseforthirdparty, '', '', '', '', '', '', '', '', $emailtouseforthirdparty, $namealiastouseforthirdparty); if ($result < 0) { $errorforactions++; $this->error = 'Error when getting thirdparty with name '.$nametouseforthirdparty.' (may be 2 record exists with same name ?)'; @@ -2115,21 +2140,25 @@ class EmailCollector extends CommonObject break; } elseif ($result == 0) { if ($operation['type'] == 'loadthirdparty') { - dol_syslog("Third party with id=".$idtouseforthirdparty." email=".$emailtouseforthirdparty." name=".$nametouseforthirdparty." was not found"); + dol_syslog("Third party with id=".$idtouseforthirdparty." email=".$emailtouseforthirdparty." name=".$nametouseforthirdparty." name_alias=".$namealiastouseforthirdparty." was not found"); $errorforactions++; $langs->load("errors"); - $this->error = $langs->trans('ErrorFailedToLoadThirdParty', $idtouseforthirdparty, $emailtouseforthirdparty, $nametouseforthirdparty); + $this->error = $langs->trans('ErrorFailedToLoadThirdParty', $idtouseforthirdparty, $emailtouseforthirdparty, $nametouseforthirdparty, $namealiastouseforthirdparty); $this->errors[] = $this->error; } elseif ($operation['type'] == 'loadandcreatethirdparty') { - dol_syslog("Third party with id=".$idtouseforthirdparty." email=".$emailtouseforthirdparty." name=".$nametouseforthirdparty." was not found. We try to create it."); + dol_syslog("Third party with id=".$idtouseforthirdparty." email=".$emailtouseforthirdparty." name=".$nametouseforthirdparty." name_alias=".$namealiastouseforthirdparty." was not found. We try to create it."); // Create thirdparty $thirdpartystatic->name = $nametouseforthirdparty; - if ($fromtext != $nametouseforthirdparty) { - $thirdpartystatic->name_alias = $fromtext; + if (!empty($namealiastouseforthirdparty)) { + if ($namealiastouseforthirdparty != $nametouseforthirdparty) { + $thirdpartystatic->name_alias = $namealiastouseforthirdparty; + } + } else { + $thirdpartystatic->name_alias = (empty($replytostring) ? (empty($fromtext) ? '': $fromtext) : $replytostring); } - $thirdpartystatic->email = ($emailtouseforthirdparty ? $emailtouseforthirdparty : $from); + $thirdpartystatic->email = (empty($emailtouseforthirdparty) ? (empty($replyto) ? (empty($from) ? '' : $from) : $replyto) : $emailtouseforthirdparty); // Overwrite values with values extracted from source email $errorforthisaction = $this->overwritePropertiesOfObject($thirdpartystatic, $operation['actionparam'], $messagetext, $subject, $header, $operationslog); @@ -2861,7 +2890,7 @@ class EmailCollector extends CommonObject $result = $candidaturetocreate->create($user); if ($result <= 0) { $errorforactions++; - $this->error = 'Failed to create ticket: '.join(', ', $candidaturetocreate->errors); + $this->error = 'Failed to create candidature: '.join(', ', $candidaturetocreate->errors); $this->errors = $candidaturetocreate->errors; } diff --git a/htdocs/eventorganization/conferenceorbooth_list.php b/htdocs/eventorganization/conferenceorbooth_list.php index 5892cda191b..258c47f12fc 100644 --- a/htdocs/eventorganization/conferenceorbooth_list.php +++ b/htdocs/eventorganization/conferenceorbooth_list.php @@ -403,7 +403,7 @@ if ($projectid > 0) { // Description print ''.$langs->trans("Description").''; - print nl2br($project->description); + print dol_htmlentitiesbr($project->description); print ''; // Categories @@ -933,7 +933,7 @@ while ($i < $imaxinloop) { if (!empty($arrayfields['t.'.$key]['checked'])) { print '$key)) { print ' title="'.dol_escape_htmltag($object->$key).'"'; } print '>'; diff --git a/htdocs/eventorganization/conferenceorboothattendee_list.php b/htdocs/eventorganization/conferenceorboothattendee_list.php index 8f55a4e558c..1582da86987 100644 --- a/htdocs/eventorganization/conferenceorboothattendee_list.php +++ b/htdocs/eventorganization/conferenceorboothattendee_list.php @@ -41,11 +41,8 @@ if (isModEnabled('categorie')) { global $dolibarr_main_url_root; -// for other modules -//dol_include_once('/othermodule/class/otherobject.class.php'); - // Load translation files required by the page -$langs->loadLangs(array("eventorganization", "other", "projects")); +$langs->loadLangs(array("eventorganization", "other", "projects", "bills")); // Get Paramters $action = GETPOST('action', 'aZ09') ?GETPOST('action', 'aZ09') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ... diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php index a9d11ca1eac..dcc50eff7dc 100644 --- a/htdocs/expedition/card.php +++ b/htdocs/expedition/card.php @@ -614,6 +614,7 @@ if (empty($reshook)) { $num_prod = count($lines); for ($i = 0; $i < $num_prod; $i++) { if ($lines[$i]->id == $line_id) { // we have found line to update + $update_done = false; $line = new ExpeditionLigne($db); $line->fk_expedition = $object->id; @@ -654,6 +655,8 @@ if (empty($reshook)) { if ($line->update($user) < 0) { setEventMessages($line->error, $line->errors, 'errors'); $error++; + } else { + $update_done=true; } } else { setEventMessages($lotStock->error, $lotStock->errors, 'errors'); @@ -696,6 +699,8 @@ if (empty($reshook)) { if ($line->update($user) < 0) { setEventMessages($line->error, $line->errors, 'errors'); $error++; + } else { + $update_done=true; } } else { setEventMessages($line->error, $line->errors, 'errors'); @@ -713,6 +718,8 @@ if (empty($reshook)) { if ($object->create_line_batch($line, $line->array_options) < 0) { setEventMessages($object->error, $object->errors, 'errors'); $error++; + } else { + $update_done=true; } } } else { @@ -750,6 +757,8 @@ if (empty($reshook)) { if ($line->update($user) < 0) { setEventMessages($line->error, $line->errors, 'errors'); $error++; + } else { + $update_done=true; } } unset($_POST[$stockLocation]); @@ -764,6 +773,8 @@ if (empty($reshook)) { if ($line->update($user) < 0) { setEventMessages($line->error, $line->errors, 'errors'); $error++; + } else { + $update_done=true; } unset($_POST[$qty]); } @@ -776,10 +787,17 @@ if (empty($reshook)) { if ($line->update($user) < 0) { setEventMessages($line->error, $line->errors, 'errors'); $error++; + } else { + $update_done=true; } unset($_POST[$qty]); } } + + if (empty($update_done)) { + $line->id = $lines[$i]->id; + $line->insertExtraFields(); + } } } diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index 7b1c8ae6df7..8f024665a77 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -754,77 +754,8 @@ class Expedition extends CommonObject // If stock increment is done on sending (recommanded choice) if (!$error && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT)) { - require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; - - $langs->load("agenda"); - - // Loop on each product line to add a stock movement - $sql = "SELECT cd.fk_product, cd.subprice,"; - $sql .= " ed.rowid, ed.qty, ed.fk_entrepot,"; - $sql .= " edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock"; - $sql .= " FROM ".MAIN_DB_PREFIX."commandedet as cd,"; - $sql .= " ".MAIN_DB_PREFIX."expeditiondet as ed"; - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."expeditiondet_batch as edb on edb.fk_expeditiondet = ed.rowid"; - $sql .= " WHERE ed.fk_expedition = ".((int) $this->id); - $sql .= " AND cd.rowid = ed.fk_origin_line"; - - dol_syslog(get_class($this)."::valid select details", LOG_DEBUG); - $resql = $this->db->query($sql); - if ($resql) { - $cpt = $this->db->num_rows($resql); - for ($i = 0; $i < $cpt; $i++) { - $obj = $this->db->fetch_object($resql); - if (empty($obj->edbrowid)) { - $qty = $obj->qty; - } else { - $qty = $obj->edbqty; - } - - if ($qty == 0 || ($qty < 0 && !getDolGlobalInt('SHIPMENT_ALLOW_NEGATIVE_QTY'))) { - continue; - } - dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid); - - //var_dump($this->lines[$i]); - $mouvS = new MouvementStock($this->db); - - $mouvS->setOrigin($this->element, $this->id); - - if (empty($obj->edbrowid)) { - // line without batch detail - - // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record. - $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentValidatedInDolibarr", $numref), '', '', '', '', 0, '', 1); - - if ($result < 0) { - $error++; - $this->error = $mouvS->error; - $this->errors = array_merge($this->errors, $mouvS->errors); - break; - } - } else { - // line with batch detail - - // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record. - // Note: ->fk_origin_stock = id into table llx_product_batch (may be renamed into llx_product_stock_batch in another version) - $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentValidatedInDolibarr", $numref), '', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock, '', 1); - if ($result < 0) { - $error++; - $this->error = $mouvS->error; - $this->errors = array_merge($this->errors, $mouvS->errors); - break; - } - } - } - - // If some stock lines are now 0, we can remove entry into llx_product_stock, but only if there is no child lines into llx_product_batch (detail of batch, because we can imagine - // having a lot1/qty=X and lot2/qty=-X, so 0 but we must not loose repartition of different lot. - $sql = "DELETE FROM ".MAIN_DB_PREFIX."product_stock WHERE reel = 0 AND rowid NOT IN (SELECT fk_product_stock FROM ".MAIN_DB_PREFIX."product_batch as pb)"; - $resql = $this->db->query($sql); - // We do not test error, it can fails if there is child in batch details - } else { - $this->db->rollback(); - $this->error = $this->db->error(); + $result = $this->manageStockMvtOnEvt($user); + if ($result < 0) { return -2; } } @@ -1834,7 +1765,8 @@ class Expedition extends CommonObject { global $conf, $langs; - $langs->load('shipping'); + $langs->load('sendings'); + $nofetch = !empty($params['nofetch']); $datas = array(); @@ -1844,6 +1776,13 @@ class Expedition extends CommonObject } $datas['ref'] = '
'.$langs->trans('Ref').': '.$this->ref; $datas['refcustomer'] = '
'.$langs->trans('RefCustomer').': '.($this->ref_customer ? $this->ref_customer : $this->ref_client); + if (!$nofetch) { + $langs->load('companies'); + if (empty($this->thirdparty)) { + $this->fetch_thirdparty(); + } + $datas['customer'] = '
'.$langs->trans('Customer').': '.$this->thirdparty->getNomUrl(1, '', 0, 1); + } return $datas; } @@ -1874,10 +1813,11 @@ class Expedition extends CommonObject $dataparams = ''; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { $classfortooltip = 'classforajaxtooltip'; - $dataparams = ' data-params='.json_encode($params); - // $label = $langs->trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); $url = DOL_URL_ROOT.'/expedition/card.php?id='.$this->id; @@ -1902,8 +1842,8 @@ class Expedition extends CommonObject $label = $langs->trans("Shipment"); $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; } - $linkclose .= $dataparams.' title="'.dol_escape_htmltag($label, 1).'"'; - $linkclose .= ' class="'.$classfortooltip.'"'; + $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"'); + $linkclose .= $dataparams.' class="'.$classfortooltip.'"'; } $linkstart = 'global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) { - require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; - - $langs->load("agenda"); - - // Loop on each product line to add a stock movement - // TODO possibilite d'expedier a partir d'une propale ou autre origine ? - $sql = "SELECT cd.fk_product, cd.subprice,"; - $sql .= " ed.rowid, ed.qty, ed.fk_entrepot,"; - $sql .= " e.ref,"; - $sql .= " edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock"; - $sql .= " FROM ".MAIN_DB_PREFIX."commandedet as cd,"; - $sql .= " ".MAIN_DB_PREFIX."expeditiondet as ed"; - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."expeditiondet_batch as edb on edb.fk_expeditiondet = ed.rowid"; - $sql .= " INNER JOIN ".MAIN_DB_PREFIX."expedition as e ON ed.fk_expedition = e.rowid"; - $sql .= " WHERE ed.fk_expedition = ".((int) $this->id); - $sql .= " AND cd.rowid = ed.fk_origin_line"; - - dol_syslog(get_class($this)."::valid select details", LOG_DEBUG); - $resql = $this->db->query($sql); - if ($resql) { - $cpt = $this->db->num_rows($resql); - for ($i = 0; $i < $cpt; $i++) { - $obj = $this->db->fetch_object($resql); - if (empty($obj->edbrowid)) { - $qty = $obj->qty; - } else { - $qty = $obj->edbqty; - } - if ($qty <= 0) { - continue; - } - dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid); - - $mouvS = new MouvementStock($this->db); - $mouvS->origin = &$this; - $mouvS->setOrigin($this->element, $this->id); - - if (empty($obj->edbrowid)) { - // line without batch detail - - // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record - $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentClassifyClosedInDolibarr", $obj->ref)); - if ($result < 0) { - $this->error = $mouvS->error; - $this->errors = $mouvS->errors; - $error++; - break; - } - } else { - // line with batch detail - - // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record - $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentClassifyClosedInDolibarr", $obj->ref), '', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock); - if ($result < 0) { - $this->error = $mouvS->error; - $this->errors = $mouvS->errors; - $error++; - break; - } - } - } - } else { - $this->error = $this->db->lasterror(); + $result = $this->manageStockMvtOnEvt($user); + if ($result<0) { $error++; } } @@ -2309,6 +2188,95 @@ class Expedition extends CommonObject } } + /** + * Manage Stock MVt onb Close or valid Shipment + * @param User $user Object user that modify + * @return int <0 if ko, >0 if ok + * @throws Exception + * + */ + private function manageStockMvtOnEvt($user) + { + global $langs; + + $error=0; + + require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php'; + + $langs->load("agenda"); + + // Loop on each product line to add a stock movement + $sql = "SELECT cd.fk_product, cd.subprice,"; + $sql .= " ed.rowid, ed.qty, ed.fk_entrepot,"; + $sql .= " e.ref,"; + $sql .= " edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock"; + $sql .= " ,cd.rowid as cdid, ed.rowid as edid"; + $sql .= " FROM " . MAIN_DB_PREFIX . "commandedet as cd,"; + $sql .= " " . MAIN_DB_PREFIX . "expeditiondet as ed"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "expeditiondet_batch as edb on edb.fk_expeditiondet = ed.rowid"; + $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "expedition as e ON ed.fk_expedition = e.rowid"; + $sql .= " WHERE ed.fk_expedition = " . ((int) $this->id); + $sql .= " AND cd.rowid = ed.fk_origin_line"; + + dol_syslog(get_class($this) . "::valid select details", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + $cpt = $this->db->num_rows($resql); + for ($i = 0; $i < $cpt; $i++) { + $obj = $this->db->fetch_object($resql); + if (empty($obj->edbrowid)) { + $qty = $obj->qty; + } else { + $qty = $obj->edbqty; + } + if ($qty <= 0 || ($qty < 0 && !getDolGlobalInt('SHIPMENT_ALLOW_NEGATIVE_QTY'))) { + continue; + } + dol_syslog(get_class($this) . "::valid movement index " . $i . " ed.rowid=" . $obj->rowid . " edb.rowid=" . $obj->edbrowid); + + $mouvS = new MouvementStock($this->db); + $mouvS->origin = &$this; + $mouvS->setOrigin($this->element, $this->id, $obj->cdid, $obj->edid); + + if (empty($obj->edbrowid)) { + // line without batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record + $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentClassifyClosedInDolibarr", $obj->ref)); + if ($result < 0) { + $this->error = $mouvS->error; + $this->errors = $mouvS->errors; + $error++; + break; + } + } else { + // line with batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record + $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentClassifyClosedInDolibarr", $obj->ref), '', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock); + if ($result < 0) { + $this->error = $mouvS->error; + $this->errors = $mouvS->errors; + $error++; + break; + } + } + + // If some stock lines are now 0, we can remove entry into llx_product_stock, but only if there is no child lines into llx_product_batch (detail of batch, because we can imagine + // having a lot1/qty=X and lot2/qty=-X, so 0 but we must not loose repartition of different lot. + $sql = "DELETE FROM ".MAIN_DB_PREFIX."product_stock WHERE reel = 0 AND rowid NOT IN (SELECT fk_product_stock FROM ".MAIN_DB_PREFIX."product_batch as pb)"; + $resql = $this->db->query($sql); + // We do not test error, it can fails if there is child in batch details + } + } else { + $this->error = $this->db->lasterror(); + $this->errors[] = $this->db->lasterror(); + $error ++; + } + + return $error; + } + /** * Classify the shipping as invoiced (used when WORKFLOW_BILL_ON_SHIPMENT is on) * diff --git a/htdocs/expedition/index.php b/htdocs/expedition/index.php index a644aeedbad..6cae17a835c 100644 --- a/htdocs/expedition/index.php +++ b/htdocs/expedition/index.php @@ -31,6 +31,7 @@ require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php'; $hookmanager = new HookManager($db); + $socid = GETPOST('socid', 'int'); // Initialize technical object to manage hooks. Note that conf->hooks_modules contains array diff --git a/htdocs/expedition/stats/index.php b/htdocs/expedition/stats/index.php index 9213e2ca849..c14d8c6d3b2 100644 --- a/htdocs/expedition/stats/index.php +++ b/htdocs/expedition/stats/index.php @@ -65,7 +65,7 @@ llxHeader(); print load_fiche_titre($langs->trans("StatisticsOfSendings"), '', 'dolly'); - +$dir = (!empty($conf->expedition->multidir_temp[$conf->entity]) ? $conf->expedition->multidir_temp[$conf->entity] : $conf->service->multidir_temp[$conf->entity]); dol_mkdir($dir); $stats = new ExpeditionStats($db, $socid, '', ($userid > 0 ? $userid : 0)); @@ -84,6 +84,7 @@ if (empty($user->rights->societe->client->voir) || $user->socid) { $px1 = new DolGraph(); $mesg = $px1->isGraphKo(); +$fileurlnb = ''; if (!$mesg) { $px1->SetData($data); $i = $startyear; $legend = array(); diff --git a/htdocs/expensereport/class/expensereport.class.php b/htdocs/expensereport/class/expensereport.class.php index ebbc83302d5..3cf5d8a5003 100644 --- a/htdocs/expensereport/class/expensereport.class.php +++ b/htdocs/expensereport/class/expensereport.class.php @@ -1767,10 +1767,11 @@ class ExpenseReport extends CommonObject $dataparams = ''; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { $classfortooltip = 'classforajaxtooltip'; - $dataparams = " data-params='".json_encode($params)."'"; - // $label = $langs->trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); if ($option != 'nolink') { // Add param to save lastsearch_values or not @@ -1794,8 +1795,8 @@ class ExpenseReport extends CommonObject $label = $langs->trans("ShowExpenseReport"); $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; } - $linkclose .= $dataparams.' title="'.dol_escape_htmltag($label, 1).'"'; - $linkclose .= ' class="'.$classfortooltip.'"'; + $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"'); + $linkclose .= $dataparams.' class="'.$classfortooltip.'"'; } $linkstart = 'datepaid) { + if (!$this->datep) { $this->error = 'ErrorBadValueForParameterCreatePaymentExpenseReport'; return -1; } @@ -170,7 +169,7 @@ class PaymentExpenseReport extends CommonObject $sql = "INSERT INTO ".MAIN_DB_PREFIX."payment_expensereport (fk_expensereport, datec, datep, amount,"; $sql .= " fk_typepayment, num_payment, note, fk_user_creat, fk_bank)"; $sql .= " VALUES ($this->fk_expensereport, '".$this->db->idate($now)."',"; - $sql .= " '".$this->db->idate($this->datepaid)."',"; + $sql .= " '".$this->db->idate($this->datep)."',"; $sql .= " ".price2num($totalamount).","; $sql .= " ".((int) $this->fk_typepayment).", '".$this->db->escape($this->num_payment)."', '".$this->db->escape($this->note_public)."', ".((int) $user->id).","; $sql .= " 0)"; // fk_bank is ID of transaction into ll_bank @@ -531,7 +530,7 @@ class PaymentExpenseReport extends CommonObject // Insert payment into llx_bank $bank_line_id = $acc->addline( - $this->datepaid, + $this->datep, $this->fk_typepayment, // Payment mode id or code ("CHQ or VIR for example") $label, -$amount, diff --git a/htdocs/expensereport/payment/payment.php b/htdocs/expensereport/payment/payment.php index 6456bf80d7f..20b49b1533c 100644 --- a/htdocs/expensereport/payment/payment.php +++ b/htdocs/expensereport/payment/payment.php @@ -107,8 +107,8 @@ if ($action == 'add_payment') { // Create a line of payments $payment = new PaymentExpenseReport($db); $payment->fk_expensereport = $expensereport->id; - $payment->datepaid = $datepaid; - $payment->amounts = $amounts; // Tableau de montant + $payment->datep = $datepaid; + $payment->amounts = $amounts; // Tableau de montant $payment->total = $total; $payment->fk_typepayment = GETPOST("fk_typepayment", 'int'); $payment->num_payment = GETPOST("num_payment", 'alphanothtml'); diff --git a/htdocs/exports/export.php b/htdocs/exports/export.php index f35ae3a3121..1afd41c6027 100644 --- a/htdocs/exports/export.php +++ b/htdocs/exports/export.php @@ -1180,7 +1180,8 @@ if ($step == 5 && $datatoexport) { print '
'; // List of available export formats - $htmltabloflibs = ''; + $htmltabloflibs = '
'; + $htmltabloflibs .= '
'; $htmltabloflibs .= ''; $htmltabloflibs .= ''; $htmltabloflibs .= ''; @@ -1204,7 +1205,7 @@ if ($step == 5 && $datatoexport) { $htmltabloflibs .= ''; $htmltabloflibs .= ''."\n"; } - $htmltabloflibs .= '
'.$langs->trans("AvailableFormats").''.$langs->trans("LibraryUsed").''.$objmodelexport->getLibVersionForKey($key).'
'; + $htmltabloflibs .= '
'; print ''.$form->textwithpicto($langs->trans("NowClickToGenerateToBuildExportFile"), $htmltabloflibs, 1, 'help', '', 0, 2, 'helphonformat').''; //print $htmltabloflibs; diff --git a/htdocs/fichinter/card.php b/htdocs/fichinter/card.php index 31ae0ccaf65..a4244195bfa 100644 --- a/htdocs/fichinter/card.php +++ b/htdocs/fichinter/card.php @@ -607,7 +607,7 @@ if (empty($reshook)) { // Extrafields $extrafields->fetch_name_optionals_label($object->table_element_line); $array_options = $extrafields->getOptionalsFromPost($object->table_element_line); - $objectline->array_options = $array_options; + $objectline->array_options = array_merge($objectline->array_options, $array_options); $result = $objectline->update($user); if ($result < 0) { diff --git a/htdocs/fichinter/class/fichinter.class.php b/htdocs/fichinter/class/fichinter.class.php index 45a78d2914d..2456c71e985 100644 --- a/htdocs/fichinter/class/fichinter.class.php +++ b/htdocs/fichinter/class/fichinter.class.php @@ -815,10 +815,11 @@ class Fichinter extends CommonObject $dataparams = ''; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { $classfortooltip = 'classforajaxtooltip'; - $dataparams = " data-params='".json_encode($params)."'"; - // $label = $langs->trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); $url = DOL_URL_ROOT.'/fichinter/card.php?id='.$this->id; @@ -839,8 +840,8 @@ class Fichinter extends CommonObject $label = $langs->trans("ShowIntervention"); $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; } - $linkclose .= $dataparams.' title="'.dol_escape_htmltag($label, 1).'"'; - $linkclose .= ' class="'.$classfortooltip.'"'; + $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"'); + $linkclose .= $dataparams.' class="'.$classfortooltip.'"'; } $linkstart = '
db->query($sql); - if ($result) { - $objp = $this->db->fetch_object($result); + $resql = $this->db->query($sql); + if ($resql) { + $objp = $this->db->fetch_object($resql); $this->rowid = $objp->rowid; - $this->id = $objp->rowid; + $this->id = $objp->rowid; $this->fk_fichinter = $objp->fk_fichinter; $this->date = $this->db->jdate($objp->date); $this->datei = $this->db->jdate($objp->date); // For backward compatibility @@ -1606,7 +1608,10 @@ class FichinterLigne extends CommonObjectLine $this->duration = $objp->duree; $this->rang = $objp->rang; - $this->db->free($result); + $this->db->free($resql); + + $this->fetch_optionals(); + return 1; } else { $this->error = $this->db->error().' sql='.$sql; @@ -1623,8 +1628,6 @@ class FichinterLigne extends CommonObjectLine */ public function insert($user, $notrigger = 0) { - global $langs, $conf; - $error = 0; dol_syslog("FichinterLigne::insert rang=".$this->rang); @@ -1714,8 +1717,6 @@ class FichinterLigne extends CommonObjectLine */ public function update($user, $notrigger = 0) { - global $langs, $conf; - $error = 0; if (empty($this->date) && !empty($this->datei)) { // For backward compatibility diff --git a/htdocs/fourn/ajax/getSupplierPrices.php b/htdocs/fourn/ajax/getSupplierPrices.php index 66001ccc5a6..c08ed49dd83 100644 --- a/htdocs/fourn/ajax/getSupplierPrices.php +++ b/htdocs/fourn/ajax/getSupplierPrices.php @@ -67,6 +67,9 @@ if ($idprod > 0) { $productSupplierArray = $producttmp->list_product_fournisseur_price($idprod, $sorttouse); // We list all price per supplier, and then firstly with the lower quantity. So we can choose first one with enough quantity into list. if (is_array($productSupplierArray)) { foreach ($productSupplierArray as $productSupplier) { + if (getDolGlobalInt("DISABLE_BAD_REPUTATION_PRODUCT_PRICE") && $productSupplier->supplier_reputation == "DONOTORDER") + continue; + $price = $productSupplier->fourn_price * (1 - $productSupplier->fourn_remise_percent / 100); $unitprice = $productSupplier->fourn_unitprice * (1 - $productSupplier->fourn_remise_percent / 100); diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 1e3f74389d5..e3f8e3c5f81 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -260,25 +260,25 @@ class CommandeFournisseur extends CommonOrder 'ref_ext' =>array('type'=>'varchar(255)', 'label'=>'Ref ext', 'enabled'=>1, 'visible'=>0, 'position'=>35), 'ref_supplier' =>array('type'=>'varchar(255)', 'label'=>'RefOrderSupplierShort', 'enabled'=>1, 'visible'=>1, 'position'=>40, 'searchall'=>1), 'fk_projet' =>array('type'=>'integer:Project:projet/class/project.class.php:1:(fk_statut:=:1)', 'label'=>'Project', 'enabled'=>"isModEnabled('project')", 'visible'=>-1, 'position'=>45), - 'date_valid' =>array('type'=>'datetime', 'label'=>'DateValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>60), - 'date_approve' =>array('type'=>'datetime', 'label'=>'DateApprove', 'enabled'=>1, 'visible'=>-1, 'position'=>62), - 'date_approve2' =>array('type'=>'datetime', 'label'=>'DateApprove2', 'enabled'=>1, 'visible'=>3, 'position'=>64), + 'date_valid' =>array('type'=>'datetime', 'label'=>'DateValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>710), + 'date_approve' =>array('type'=>'datetime', 'label'=>'DateApprove', 'enabled'=>1, 'visible'=>-1, 'position'=>720), + 'date_approve2' =>array('type'=>'datetime', 'label'=>'DateApprove2', 'enabled'=>1, 'visible'=>3, 'position'=>725), 'date_commande' =>array('type'=>'date', 'label'=>'OrderDateShort', 'enabled'=>1, 'visible'=>1, 'position'=>70), 'date_livraison' =>array('type'=>'datetime', 'label'=>'DeliveryDate', 'enabled'=>'empty($conf->global->ORDER_DISABLE_DELIVERY_DATE)', 'visible'=>1, 'position'=>74), - 'fk_user_author' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>3, 'position'=>75), + 'fk_user_author' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>3, 'position'=>41), 'fk_user_modif' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>3, 'notnull'=>-1, 'position'=>80), - 'fk_user_valid' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserValidation', 'enabled'=>1, 'visible'=>3, 'position'=>85), - 'fk_user_approve' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserApproval', 'enabled'=>1, 'visible'=>3, 'position'=>90), - 'fk_user_approve2' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserApproval2', 'enabled'=>1, 'visible'=>3, 'position'=>95), + 'fk_user_valid' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserValidation', 'enabled'=>1, 'visible'=>3, 'position'=>711), + 'fk_user_approve' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserApproval', 'enabled'=>1, 'visible'=>3, 'position'=>721), + 'fk_user_approve2' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserApproval2', 'enabled'=>1, 'visible'=>3, 'position'=>726), 'source' =>array('type'=>'smallint(6)', 'label'=>'Source', 'enabled'=>1, 'visible'=>3, 'notnull'=>1, 'position'=>100), - 'billed' =>array('type'=>'smallint(6)', 'label'=>'Billed', 'enabled'=>1, 'visible'=>1, 'position'=>110), - 'total_tva' =>array('type'=>'double(24,8)', 'label'=>'Tva', 'enabled'=>1, 'visible'=>1, 'position'=>130, 'isameasure'=>1), - 'localtax1' =>array('type'=>'double(24,8)', 'label'=>'Localtax1', 'enabled'=>1, 'visible'=>3, 'position'=>135, 'isameasure'=>1), - 'localtax2' =>array('type'=>'double(24,8)', 'label'=>'Localtax2', 'enabled'=>1, 'visible'=>3, 'position'=>140, 'isameasure'=>1), - 'total_ht' =>array('type'=>'double(24,8)', 'label'=>'TotalHT', 'enabled'=>1, 'visible'=>1, 'position'=>145, 'isameasure'=>1), - 'total_ttc' =>array('type'=>'double(24,8)', 'label'=>'TotalTTC', 'enabled'=>1, 'visible'=>-1, 'position'=>150, 'isameasure'=>1), - 'note_public' =>array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>155, 'searchall'=>1), - 'note_private' =>array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>160, 'searchall'=>1), + 'billed' =>array('type'=>'smallint(6)', 'label'=>'Billed', 'enabled'=>1, 'visible'=>1, 'position'=>710), + 'total_ht' =>array('type'=>'double(24,8)', 'label'=>'AmountHT', 'enabled'=>1, 'visible'=>1, 'position'=>130, 'isameasure'=>1), + 'total_tva' =>array('type'=>'double(24,8)', 'label'=>'AmountVAT', 'enabled'=>1, 'visible'=>1, 'position'=>135, 'isameasure'=>1), + 'localtax1' =>array('type'=>'double(24,8)', 'label'=>'LT1', 'enabled'=>1, 'visible'=>3, 'position'=>140, 'isameasure'=>1), + 'localtax2' =>array('type'=>'double(24,8)', 'label'=>'LT2', 'enabled'=>1, 'visible'=>3, 'position'=>145, 'isameasure'=>1), + 'total_ttc' =>array('type'=>'double(24,8)', 'label'=>'AmountTTC', 'enabled'=>1, 'visible'=>-1, 'position'=>150, 'isameasure'=>1), + 'note_public' =>array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>750, 'searchall'=>1), + 'note_private' =>array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>760, 'searchall'=>1), 'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'ModelPDF', 'enabled'=>1, 'visible'=>0, 'position'=>165), 'fk_input_method' =>array('type'=>'integer', 'label'=>'OrderMode', 'enabled'=>1, 'visible'=>3, 'position'=>170), 'fk_cond_reglement' =>array('type'=>'integer', 'label'=>'PaymentTerm', 'enabled'=>1, 'visible'=>3, 'position'=>175), @@ -294,7 +294,7 @@ class CommandeFournisseur extends CommonOrder 'multicurrency_total_tva' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyAmountVAT', 'enabled'=>'isModEnabled("multicurrency")', 'visible'=>-1, 'position'=>235), 'multicurrency_total_ttc' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyAmountTTC', 'enabled'=>'isModEnabled("multicurrency")', 'visible'=>-1, 'position'=>240), 'date_creation' =>array('type'=>'datetime', 'label'=>'Date creation', 'enabled'=>1, 'visible'=>-1, 'position'=>500), - 'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>'isModEnabled("societe")', 'visible'=>1, 'notnull'=>1, 'position'=>46), + 'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>'isModEnabled("societe")', 'visible'=>1, 'notnull'=>1, 'position'=>50), 'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>0, 'notnull'=>1, 'position'=>1000, 'index'=>1), 'tms'=>array('type'=>'datetime', 'label'=>"DateModificationShort", 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>501), 'last_main_doc' =>array('type'=>'varchar(255)', 'label'=>'LastMainDoc', 'enabled'=>1, 'visible'=>0, 'position'=>700), @@ -873,6 +873,8 @@ class CommandeFournisseur extends CommonOrder $langs->loadLangs(['bills', 'orders']); $datas = []; + $nofetch = !empty($params['nofetch']); + if ($user->hasRight("fournisseur", "commande", "read")) { $datas['picto'] = ''.$langs->trans("SupplierOrder").''; if (isset($this->statut)) { @@ -884,6 +886,13 @@ class CommandeFournisseur extends CommonOrder if (!empty($this->ref_supplier)) { $datas['refsupplier'] = '
'.$langs->trans('RefSupplier').': '.$this->ref_supplier; } + if (!$nofetch) { + $langs->load('companies'); + if (empty($this->thirdparty)) { + $this->fetch_thirdparty(); + } + $datas['supplier'] = '
'.$langs->trans('Supplier').': '.$this->thirdparty->getNomUrl(1, '', 0, 1); + } if (!empty($this->total_ht)) { $datas['totalht'] = '
'.$langs->trans('AmountHT').': '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency); } @@ -922,17 +931,18 @@ class CommandeFournisseur extends CommonOrder 'id' => $this->id, 'objecttype' => $this->element, 'option' => $option, + 'nofetch' => 1 ]; $classfortooltip = 'classfortooltip'; $dataparams = ''; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { $classfortooltip = 'classforajaxtooltip'; - $dataparams = " data-params='".json_encode($params)."'"; - // $label = $langs->trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); - $url = DOL_URL_ROOT.'/fourn/commande/card.php?id='.$this->id; if ($option !== 'nolink') { @@ -952,8 +962,8 @@ class CommandeFournisseur extends CommonOrder $label = $langs->trans("ShowOrder"); $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; } - $linkclose .= $dataparams.' title="'.dol_escape_htmltag($label, 1).'"'; - $linkclose .= ' class="'.$classfortooltip.'"'; + $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"'); + $linkclose .= $dataparams.' class="'.$classfortooltip.'"'; } $linkstart = '
trans('Loading'); + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); - $ref = $this->ref; if (empty($ref)) { $ref = $this->id; @@ -2846,8 +2846,8 @@ class FactureFournisseur extends CommonInvoice $label = $langs->trans("ShowSupplierInvoice"); $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; } - $linkclose .= $dataparams.' title="'.dol_escape_htmltag($label, 1).'"'; - $linkclose .= ' class="'.$classfortooltip.'"'; + $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"'); + $linkclose .= $dataparams.' class="'.$classfortooltip.'"'; } $linkstart = 'getNomUrl(1) : $this->ref).''; $return .= ''; - if (property_exists($this, 'socid')) { - $return .= ' | '.$this->socid.''; + if (!empty($arraydata['thirdparty'])) { + $return .= '
'.$arraydata['thirdparty'].''; } - if (property_exists($this, 'date_echeance') && property_exists($this, 'date')) { - if (!empty($this->date_echeance)) { - $return .= '
'.dol_print_date($this->date_echeance).''; - } else { - $return .= '
'.dol_print_date($this->date).''; - } + if (property_exists($this, 'date')) { + $return .= '
'.dol_print_date($this->date, 'day').''; } if (property_exists($this, 'total_ht')) { - $return .= '
'.$langs->trans("AmountHT").' : '.price($this->total_ht).''; + $return .= '   '.price($this->total_ht); + $return .= ' '.$langs->trans("HT"); + $return .= ''; } if (method_exists($this, 'getLibStatut')) { $alreadypaid = (empty($arraydata['alreadypaid']) ? 0 : $arraydata['alreadypaid']); diff --git a/htdocs/fourn/class/fournisseur.product.class.php b/htdocs/fourn/class/fournisseur.product.class.php index f31d6a38e7e..743d8d7b33c 100644 --- a/htdocs/fourn/class/fournisseur.product.class.php +++ b/htdocs/fourn/class/fournisseur.product.class.php @@ -135,6 +135,9 @@ class ProductFournisseur extends Product public $packaging; + const STATUS_OPEN = 1; + const STATUS_CANCELED = 0; + /** * Constructor @@ -685,7 +688,7 @@ class ProductFournisseur extends Product $sql .= " pfp.rowid as product_fourn_pri_id, pfp.entity, pfp.ref_fourn, pfp.desc_fourn, pfp.fk_product as product_fourn_id, pfp.fk_supplier_price_expression,"; $sql .= " pfp.price, pfp.quantity, pfp.unitprice, pfp.remise_percent, pfp.remise, pfp.tva_tx, pfp.fk_availability, pfp.charges, pfp.info_bits, pfp.delivery_time_days, pfp.supplier_reputation,"; $sql .= " pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code, pfp.datec, pfp.tms,"; - $sql .= " pfp.barcode, pfp.fk_barcode_type, pfp.packaging"; + $sql .= " pfp.barcode, pfp.fk_barcode_type, pfp.packaging, pfp.status as pfstatus"; $sql .= " FROM ".MAIN_DB_PREFIX."product_fournisseur_price as pfp, ".MAIN_DB_PREFIX."product as p, ".MAIN_DB_PREFIX."societe as s"; $sql .= " WHERE pfp.entity IN (".getEntity('productsupplierprice').")"; $sql .= " AND pfp.fk_soc = s.rowid AND pfp.fk_product = p.rowid"; @@ -742,6 +745,7 @@ class ProductFournisseur extends Product $prodfourn->fourn_multicurrency_code = $record["multicurrency_code"]; $prodfourn->packaging = $record["packaging"]; + $prodfourn->status = $record["pfstatus"]; if (isModEnabled('barcode')) { $prodfourn->supplier_barcode = $record["barcode"]; @@ -1249,7 +1253,7 @@ class ProductFournisseur extends Product $label .= $this->displayPriceProductFournisseurLog($logPrices); } - $url = dol_buildpath('/product/fournisseurs.php', 1).'?id='.$this->id.'&action=add_price&token='.newToken().'&socid='.$this->fourn_id.'&rowid='.$this->product_fourn_price_id; + $url = DOL_URL_ROOT.'/product/fournisseurs.php?id='.((int) $this->id).'&action=create_price&token='.newToken().'&socid='.((int) $this->fourn_id).'&rowid='.((int) $this->product_fourn_price_id); if ($option != 'nolink') { // Add param to save lastsearch_values or not @@ -1302,6 +1306,46 @@ class ProductFournisseur extends Product return $result; } + /** + * Return the label of the status + * + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @param int $type Type of product + * @return string Label of status + */ + public function getLibStatut($mode = 0, $type = 0) // must be compatible with getLibStatut of inherited Product + { + return $this->LibStatut($this->status, $mode); + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return the status + * + * @param int $status Id status + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @param int $type Type of product + * @return string Label of status + */ + public function LibStatut($status, $mode = 0, $type = 0) + { + // phpcs:enable + if (empty($this->labelStatus) || empty($this->labelStatusShort)) { + global $langs; + //$langs->load("mymodule@mymodule"); + $this->labelStatus[self::STATUS_OPEN] = $langs->transnoentitiesnoconv('Enabled'); + $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled'); + } + + $statusType = 'status4'; + //if ($status == self::STATUS_VALIDATED) $statusType = 'status1'; + if ($status == self::STATUS_CANCELED) { + $statusType = 'status6'; + } + + return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode); + } + /** * Private function to log price history * diff --git a/htdocs/fourn/class/paiementfourn.class.php b/htdocs/fourn/class/paiementfourn.class.php index 21dae0e85b2..b587922b71d 100644 --- a/htdocs/fourn/class/paiementfourn.class.php +++ b/htdocs/fourn/class/paiementfourn.class.php @@ -7,6 +7,7 @@ * Copyright (C) 2014 Marcos García * Copyright (C) 2018 Nicolas ZABOURI * Copyright (C) 2018 Frédéric France + * Copyright (C) 2023 Joachim Kueter * * 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 @@ -341,7 +342,18 @@ class PaiementFourn extends Paiement } } } else { - dol_syslog("Remain to pay for invoice ".$facid." not null. We do nothing."); + // hook to have an option to automatically close a closable invoice with less payment than the total amount (e.g. agreed cash discount terms) + global $hookmanager; + $hookmanager->initHooks(array('payment_supplierdao')); + $parameters = array('facid' => $facid, 'invoice' => $invoice, 'remaintopay' => $remaintopay); + $action = 'CLOSEPAIDSUPPLIERINVOICE'; + $reshook = $hookmanager->executeHooks('createPayment', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook < 0) { + $this->error = $hookmanager->error; + $error++; + } elseif ($reshook == 0) { + dol_syslog("Remain to pay for invoice " . $facid . " not null. We do nothing more."); + } } } @@ -350,6 +362,7 @@ class PaiementFourn extends Paiement $newlang = ''; $outputlangs = $langs; if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) { + $invoice->fetch_thirdparty(); $newlang = $invoice->thirdparty->default_lang; } if (!empty($newlang)) { diff --git a/htdocs/fourn/commande/dispatch.php b/htdocs/fourn/commande/dispatch.php index f5a983ac5bb..50508f171df 100644 --- a/htdocs/fourn/commande/dispatch.php +++ b/htdocs/fourn/commande/dispatch.php @@ -486,6 +486,7 @@ if ($action == 'updateline' && $permissiontoreceive) { } } + /* * View */ @@ -616,6 +617,10 @@ if ($id > 0 || !empty($ref)) { print '
'.$langs->trans("OrderStatusNotReadyToDispatch").''; } + + print '
'; + + if ($object->statut == CommandeFournisseur::STATUS_ORDERSENT || $object->statut == CommandeFournisseur::STATUS_RECEIVED_PARTIALLY || $object->statut == CommandeFournisseur::STATUS_RECEIVED_COMPLETELY) { @@ -731,7 +736,7 @@ if ($id > 0 || !empty($ref)) { print ''.$langs->trans("QtyOrdered").''; print ''.$langs->trans("QtyDispatchedShort").''; print ' '.$langs->trans("QtyToDispatchShort"); - print '
'.$langs->trans("Reset").''; + print '
'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').$langs->trans("Reset").''; print ''; if (!empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) { @@ -1069,6 +1074,7 @@ if ($id > 0 || !empty($ref)) { $dispatchBt = empty($conf->reception->enabled) ? $langs->trans("Receive") : $langs->trans("CreateReception"); print '
'; + print ''; print 'array('label'=>"AliasNameShort", 'position'=>47, 'checked'=>0), - 's.town'=>array('label'=>"Town", 'enabled'=>1, 'position'=>47, 'checked'=>1), - 's.zip'=>array('label'=>"Zip", 'enabled'=>1, 'position'=>47, 'checked'=>1), - 'state.nom'=>array('label'=>"StateShort", 'enabled'=>1, 'position'=>48), - 'country.code_iso'=>array('label'=>"Country", 'enabled'=>1, 'position'=>49), - 'typent.code'=>array('label'=>"ThirdPartyType", 'enabled'=>$checkedtypetiers, 'position'=>50), - 'u.login'=>array('label'=>"AuthorRequest", 'enabled'=>1, 'position'=>51), - 'cf.note_public'=>array('label'=>'NotePublic', 'checked'=>0, 'enabled'=>(!getDolGlobalInt('MAIN_LIST_HIDE_PUBLIC_NOTES')), 'position'=>100), - 'cf.note_private'=>array('label'=>'NotePrivate', 'checked'=>0, 'enabled'=>(!getDolGlobalInt('MAIN_LIST_HIDE_PRIVATE_NOTES')), 'position'=>110), + 'u.login'=>array('label'=>"AuthorRequest", 'enabled'=>1, 'position'=>41), + 's.name_alias'=>array('label'=>"AliasNameShort", 'position'=>51, 'checked'=>0), + 's.town'=>array('label'=>"Town", 'enabled'=>1, 'position'=>55, 'checked'=>1), + 's.zip'=>array('label'=>"Zip", 'enabled'=>1, 'position'=>56, 'checked'=>1), + 'state.nom'=>array('label'=>"StateShort", 'enabled'=>1, 'position'=>57), + 'country.code_iso'=>array('label'=>"Country", 'enabled'=>1, 'position'=>58), + 'typent.code'=>array('label'=>"ThirdPartyType", 'enabled'=>$checkedtypetiers, 'position'=>59), + 'cf.total_localtax1'=>array('label'=>$langs->transcountry("AmountLT1", $mysoc->country_code), 'checked'=>0, 'enabled'=>($mysoc->localtax1_assuj == "1"), 'position'=>140), + 'cf.total_localtax2'=>array('label'=>$langs->transcountry("AmountLT2", $mysoc->country_code), 'checked'=>0, 'enabled'=>($mysoc->localtax2_assuj == "1"), 'position'=>145), + 'cf.note_public'=>array('label'=>'NotePublic', 'checked'=>0, 'enabled'=>(!getDolGlobalInt('MAIN_LIST_HIDE_PUBLIC_NOTES')), 'position'=>750), + 'cf.note_private'=>array('label'=>'NotePrivate', 'checked'=>0, 'enabled'=>(!getDolGlobalInt('MAIN_LIST_HIDE_PRIVATE_NOTES')), 'position'=>760), ); foreach ($object->fields as $key => $val) { // If $val['visible']==0, then we never show the field @@ -766,6 +768,7 @@ $sql .= ' s.rowid as socid, s.nom as name, s.name_alias as alias, s.town, s.zip, $sql .= " typent.code as typent_code,"; $sql .= " state.code_departement as state_code, state.nom as state_name,"; $sql .= " cf.rowid, cf.ref, cf.ref_supplier, cf.fk_statut, cf.billed, cf.total_ht, cf.total_tva, cf.total_ttc, cf.fk_user_author, cf.date_commande as date_commande, cf.date_livraison as date_livraison,cf.date_valid, cf.date_approve,"; +$sql .= ' cf.localtax1 as total_localtax1, cf.localtax2 as total_localtax2,'; $sql .= ' cf.fk_multicurrency, cf.multicurrency_code, cf.multicurrency_tx, cf.multicurrency_total_ht, cf.multicurrency_total_tva, cf.multicurrency_total_ttc,'; $sql .= ' cf.date_creation as date_creation, cf.tms as date_update,'; $sql .= ' cf.note_public, cf.note_private,'; @@ -1774,7 +1777,7 @@ if ($resql) { $totalarray['nbfield']++; } } - //alias + // Alias if (!empty($arrayfields['s.name_alias']['checked'])) { print ''; print $obj->alias; diff --git a/htdocs/fourn/facture/card.php b/htdocs/fourn/facture/card.php index 5408b8f980a..054ae69e3ad 100644 --- a/htdocs/fourn/facture/card.php +++ b/htdocs/fourn/facture/card.php @@ -2800,7 +2800,7 @@ if ($action == 'create') { $head = facturefourn_prepare_head($object); $titre = $langs->trans('SupplierInvoice'); - print dol_get_fiche_head($head, 'card', $titre, -1, 'supplier_invoice'); + print dol_get_fiche_head($head, 'card', $titre, -1, 'supplier_invoice', 0, '', '', 0, '', 1); $formconfirm = ''; diff --git a/htdocs/fourn/facture/list.php b/htdocs/fourn/facture/list.php index 5302d5de3b2..878cca686e8 100644 --- a/htdocs/fourn/facture/list.php +++ b/htdocs/fourn/facture/list.php @@ -1513,7 +1513,7 @@ while ($i < $imaxinloop) { } } - $arraydata = array('alreadypaid' => $paiement); + $arraydata = array('alreadypaid' => $paiement, 'thirdparty' => $thirdparty->getNomUrl(1, '', 12)); print $facturestatic->getKanbanView('', $arraydata); if ($i == ($imaxinloop - 1)) { print '
'; diff --git a/htdocs/fourn/js/lib_dispatch.js.php b/htdocs/fourn/js/lib_dispatch.js.php index 01af2ee5d91..ff822543ddb 100644 --- a/htdocs/fourn/js/lib_dispatch.js.php +++ b/htdocs/fourn/js/lib_dispatch.js.php @@ -93,8 +93,8 @@ function addDispatchLine(index, type, mode) } console.log("qtyDispatched="+qtyDispatched+" qtyOrdered="+qtyOrdered); - if (qtyOrdered <= 1) { - window.alert("Quantity can't be split"); + if (qtyDispatched >= qtyOrdered || qtyOrdered <= 1) { + window.alert("Remain quantity to dispatch is too low to be split"); } else if (qtyDispatched < qtyOrdered) { //replace tr suffix nbr $row.html($row.html().replace(/_0_/g,"_"+nbrTrs+"_")); diff --git a/htdocs/holiday/card.php b/htdocs/holiday/card.php index 3e800760606..d8a25d06842 100644 --- a/htdocs/holiday/card.php +++ b/htdocs/holiday/card.php @@ -1003,27 +1003,6 @@ if ((empty($id) && empty($ref)) || $action == 'create' || $action == 'add') { print ''."\n"; print ''."\n"; - if (empty($conf->global->HOLIDAY_HIDE_BALANCE)) { - print dol_get_fiche_head('', '', '', -1); - - $out = ''; - $nb_holiday = 0; - $typeleaves = $object->getTypes(1, 1); - foreach ($typeleaves as $key => $val) { - $nb_type = $object->getCPforUser($user->id, $val['rowid']); - $nb_holiday += $nb_type; - - $out .= ' - '.($langs->trans($val['code']) != $val['code'] ? $langs->trans($val['code']) : $val['label']).': '.($nb_type ? price2num($nb_type) : 0).'
'; - //$out .= ' - '.$val['label'].': '.($nb_type ?price2num($nb_type) : 0).'
'; - } - print $langs->trans('SoldeCPUser', round($nb_holiday, 5)).'
'; - print $out; - - print dol_get_fiche_end(); - } elseif (!is_numeric($conf->global->HOLIDAY_HIDE_BALANCE)) { - print $langs->trans($conf->global->HOLIDAY_HIDE_BALANCE).'
'; - } - print dol_get_fiche_head(); //print ''.$langs->trans('DelayToRequestCP',$object->getConfCP('delayForRequest')).'

'; @@ -1033,14 +1012,57 @@ if ((empty($id) && empty($ref)) || $action == 'create' || $action == 'add') { // User for leave request print ''; - print ''.$langs->trans("User").''; - print ''; + print ''.$langs->trans("User").''; + print '
'; if ($cancreate && !$cancreateall) { - print img_picto('', 'user').$form->select_dolusers(($fuserid ? $fuserid : $user->id), 'fuserid', 0, '', 0, 'hierarchyme', '', '0,'.$conf->entity, 0, 0, $morefilter, 0, '', 'minwidth200 maxwidth500'); + print img_picto('', 'user').$form->select_dolusers(($fuserid ? $fuserid : $user->id), 'fuserid', 0, '', 0, 'hierarchyme', '', '0,'.$conf->entity, 0, 0, $morefilter, 0, '', 'minwidth200 maxwidth500 inline-block'); //print ''; } else { - print img_picto('', 'user').$form->select_dolusers($fuserid ? $fuserid : $user->id, 'fuserid', 0, '', 0, '', '', '0,'.$conf->entity, 0, 0, $morefilter, 0, '', 'minwidth200 maxwidth500'); + print img_picto('', 'user').$form->select_dolusers($fuserid ? $fuserid : $user->id, 'fuserid', 0, '', 0, '', '', '0,'.$conf->entity, 0, 0, $morefilter, 0, '', 'minwidth200 maxwidth500 inline-block'); } + print '
'; + + if (empty($conf->global->HOLIDAY_HIDE_BALANCE)) { + print '
'; + + $out = ''; + $nb_holiday = 0; + $typeleaves = $object->getTypes(1, 1); + foreach ($typeleaves as $key => $val) { + $nb_type = $object->getCPforUser(($fuserid ? $fuserid : $user->id), $val['rowid']); + $nb_holiday += $nb_type; + + $out .= ' - '.($langs->trans($val['code']) != $val['code'] ? $langs->trans($val['code']) : $val['label']).': '.($nb_type ? price2num($nb_type) : 0).'
'; + //$out .= ' - '.$val['label'].': '.($nb_type ?price2num($nb_type) : 0).'
'; + } + print '     '; + + $htmltooltip = $langs->trans("Detail").'
'; + $htmltooltip .= $out; + + print $form->textwithtooltip($langs->trans('SoldeCPUser', round($nb_holiday, 5)).' '.img_picto('', 'help'), $htmltooltip); + + print '
'; + if (!empty($conf->use_javascript_ajax)) { + print ''; + } + } elseif (!is_numeric($conf->global->HOLIDAY_HIDE_BALANCE)) { + print '
'; + print $langs->trans($conf->global->HOLIDAY_HIDE_BALANCE); + print '
'; + } + print ''; print ''; diff --git a/htdocs/holiday/class/holiday.class.php b/htdocs/holiday/class/holiday.class.php index f3c7130e7f8..507d784092a 100644 --- a/htdocs/holiday/class/holiday.class.php +++ b/htdocs/holiday/class/holiday.class.php @@ -1363,9 +1363,11 @@ class Holiday extends CommonObject $dataparams = ''; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { $classfortooltip = 'classforajaxtooltip'; - $dataparams = " data-params='".json_encode($params)."'"; + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); } - $label = implode($this->getTooltipContentArray($params)); $url = DOL_URL_ROOT.'/holiday/card.php?id='.$this->id; @@ -1380,7 +1382,9 @@ class Holiday extends CommonObject $url .= '&save_lastsearch_values=1'; } //} - $linkstart = ''; + $linkstart = ''; $linkend = ''; $result .= $linkstart; diff --git a/htdocs/hrm/index.php b/htdocs/hrm/index.php index 4fabcaa3840..b8ea9116418 100644 --- a/htdocs/hrm/index.php +++ b/htdocs/hrm/index.php @@ -54,6 +54,7 @@ if (isModEnabled('holiday')) { // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context $hookmanager = new HookManager($db); + $hookmanager->initHooks('hrmindex'); // Load translation files required by the page diff --git a/htdocs/hrm/job_list.php b/htdocs/hrm/job_list.php index dad366d14f1..3616c696d54 100644 --- a/htdocs/hrm/job_list.php +++ b/htdocs/hrm/job_list.php @@ -650,8 +650,8 @@ while ($i < $imaxinloop) { //if (in_array($key, array('fk_soc', 'fk_user', 'fk_warehouse'))) $cssforfield = 'tdoverflowmax100'; if (!empty($arrayfields['t.'.$key]['checked'])) { - print '$key)) { print ' title="'.dol_escape_htmltag($object->$key).'"'; } print '>'; diff --git a/htdocs/hrm/position_list.php b/htdocs/hrm/position_list.php index 4644382416e..3f605a84d4a 100644 --- a/htdocs/hrm/position_list.php +++ b/htdocs/hrm/position_list.php @@ -678,8 +678,8 @@ while ($i < $imaxinloop) { //if (in_array($key, array('fk_soc', 'fk_user', 'fk_warehouse'))) $cssforfield = 'tdoverflowmax100'; if (!empty($arrayfields['t.'.$key]['checked'])) { - print '$key)) { print ' title="'.dol_escape_htmltag($object->$key).'"'; } print '>'; diff --git a/htdocs/hrm/skill_list.php b/htdocs/hrm/skill_list.php index 07084815b13..b11af391ae2 100644 --- a/htdocs/hrm/skill_list.php +++ b/htdocs/hrm/skill_list.php @@ -673,7 +673,7 @@ while ($i < $imaxinloop) { if (!empty($arrayfields['t.'.$key]['checked'])) { print '$key)) { print ' title="'.dol_escape_htmltag($object->$key).'"'; } print '>'; diff --git a/htdocs/imports/import.php b/htdocs/imports/import.php index d46bfb2605c..963581e1350 100644 --- a/htdocs/imports/import.php +++ b/htdocs/imports/import.php @@ -1082,9 +1082,9 @@ if ($step == 4 && $datatoimport) { $valforsourcefieldnb[$lefti] = $key; $lefti++; - if ($lefti > count($fieldstarget)) { + /*if ($lefti > count($fieldstarget)) { break; // Other fields are in the not imported area - } + }*/ } //var_dump($valforsourcefieldnb); @@ -1138,9 +1138,9 @@ if ($step == 4 && $datatoimport) { print ''; foreach ($fieldssource as $code => $line) { // $fieldssource is an array code=column num, line=content on first line for column in source file. - if ($i == $minpos) { + /*if ($i == $minpos) { break; - } + }*/ print ''; $entity = (!empty($objimport->array_import_entities[0][$code]) ? $objimport->array_import_entities[0][$code] : $objimport->array_import_icon[0]); diff --git a/htdocs/includes/OAuth/Common/Storage/DoliStorage.php b/htdocs/includes/OAuth/Common/Storage/DoliStorage.php index e9cfb8d5dcc..61a4e53061a 100644 --- a/htdocs/includes/OAuth/Common/Storage/DoliStorage.php +++ b/htdocs/includes/OAuth/Common/Storage/DoliStorage.php @@ -238,8 +238,16 @@ class DoliStorage implements TokenStorageInterface */ public function clearAllTokens() { - // TODO - $this->conf->remove($this->key); + // TODO Remove token using a loop on each $service + /* + $servicepluskeyforprovider = $service; + if (!empty($this->keyforprovider)) { + // We clean the keyforprovider after the - to be sure it is not present + $servicepluskeyforprovider = preg_replace('/\-'.preg_quote($this->keyforprovider, '/').'$/', '', $servicepluskeyforprovider); + // Now we add the keyforprovider + $servicepluskeyforprovider .= '-'.$this->keyforprovider; + } + */ // allow chaining return $this; @@ -334,7 +342,6 @@ class DoliStorage implements TokenStorageInterface { // TODO // get previously saved tokens - //$states = $this->conf->get($this->stateKey); if (is_array($this->states) && array_key_exists($service, $this->states)) { unset($this->states[$service]); @@ -353,7 +360,6 @@ class DoliStorage implements TokenStorageInterface public function clearAllAuthorizationStates() { // TODO - //$this->conf->remove($this->stateKey); // allow chaining return $this; diff --git a/htdocs/includes/jquery/js/jquery.js b/htdocs/includes/jquery/js/jquery.js index fc6c299b73e..7f35c11bdf3 100644 --- a/htdocs/includes/jquery/js/jquery.js +++ b/htdocs/includes/jquery/js/jquery.js @@ -1,5 +1,5 @@ /*! - * jQuery JavaScript Library v3.6.0 + * jQuery JavaScript Library v3.6.4 * https://jquery.com/ * * Includes Sizzle.js @@ -9,7 +9,7 @@ * Released under the MIT license * https://jquery.org/license * - * Date: 2021-03-02T17:08Z + * Date: 2023-03-08T15:28Z */ ( function( global, factory ) { @@ -23,7 +23,7 @@ // (such as Node.js), expose a factory as module.exports. // This accentuates the need for the creation of a real `window`. // e.g. var jQuery = require("jquery")(window); - // See ticket #14549 for more info. + // See ticket trac-14549 for more info. module.exports = global.document ? factory( global, true ) : function( w ) { @@ -151,7 +151,7 @@ function toType( obj ) { var - version = "3.6.0", + version = "3.6.4", // Define a local copy of jQuery jQuery = function( selector, context ) { @@ -522,14 +522,14 @@ function isArrayLike( obj ) { } var Sizzle = /*! - * Sizzle CSS Selector Engine v2.3.6 + * Sizzle CSS Selector Engine v2.3.10 * https://sizzlejs.com/ * * Copyright JS Foundation and other contributors * Released under the MIT license * https://js.foundation/ * - * Date: 2021-02-16 + * Date: 2023-02-14 */ ( function( window ) { var i, @@ -633,7 +633,7 @@ var i, whitespace + "+$", "g" ), rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + rleadingCombinator = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), rdescend = new RegExp( whitespace + "|>" ), @@ -850,7 +850,7 @@ function Sizzle( selector, context, results, seed ) { // as such selectors are not recognized by querySelectorAll. // Thanks to Andrew Dupont for this technique. if ( nodeType === 1 && - ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + ( rdescend.test( selector ) || rleadingCombinator.test( selector ) ) ) { // Expand context for sibling selectors newContext = rsibling.test( selector ) && testContext( context.parentNode ) || @@ -1174,6 +1174,24 @@ setDocument = Sizzle.setDocument = function( node ) { !el.querySelectorAll( ":scope fieldset div" ).length; } ); + // Support: Chrome 105 - 110+, Safari 15.4 - 16.3+ + // Make sure the the `:has()` argument is parsed unforgivingly. + // We include `*` in the test to detect buggy implementations that are + // _selectively_ forgiving (specifically when the list includes at least + // one valid selector). + // Note that we treat complete lack of support for `:has()` as if it were + // spec-compliant support, which is fine because use of `:has()` in such + // environments will fail in the qSA path and fall back to jQuery traversal + // anyway. + support.cssHas = assert( function() { + try { + document.querySelector( ":has(*,:jqfake)" ); + return false; + } catch ( e ) { + return true; + } + } ); + /* Attributes ---------------------------------------------------------------------- */ @@ -1440,6 +1458,17 @@ setDocument = Sizzle.setDocument = function( node ) { } ); } + if ( !support.cssHas ) { + + // Support: Chrome 105 - 110+, Safari 15.4 - 16.3+ + // Our regular `try-catch` mechanism fails to detect natively-unsupported + // pseudo-classes inside `:has()` (such as `:has(:contains("Foo"))`) + // in browsers that parse the `:has()` argument as a forgiving selector list. + // https://drafts.csswg.org/selectors/#relational now requires the argument + // to be parsed unforgivingly, but browsers have not yet fully adjusted. + rbuggyQSA.push( ":has" ); + } + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); @@ -1452,7 +1481,14 @@ setDocument = Sizzle.setDocument = function( node ) { // As in, an element does not contain itself contains = hasCompare || rnative.test( docElem.contains ) ? function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, + + // Support: IE <9 only + // IE doesn't have `contains` on `document` so we need to check for + // `documentElement` presence. + // We need to fall back to `a` when `documentElement` is missing + // as `ownerDocument` of elements within `