diff --git a/ChangeLog b/ChangeLog index c301ac59b58..82805bb0b74 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,7 +12,7 @@ NEW: Minimal PHP version is now PHP 7.0 instead of PHP 5.6 NEW: #21780 Add pid field to Cronjob class and store PID on job execution NEW: #19680 Add option PRODUCT_ALLOW_EXTERNAL_DOWNLOAD to automatically have uploaded files shared publicly by a link NEW: #20650 can move the checkbox column on left (experimental option) -NEW: #21000 Added columns 'alias_name' on poject, supplier invoice, supplier order, supplier proposals and taks list +NEW: #21000 Added columns 'alias_name' on project, supplier invoice, supplier order, supplier proposals and task list NEW: #21395 Added option for dark theme mode in display - color and theme NEW: #21397 added option to auto define barcode numbers for third-parties in barcode module setup NEW: #21399 @@ -22,11 +22,11 @@ NEW: #22048 Added notes to productlot module NEW: #22298 Bank - Add salaries & vat in the tab of planned entries of a bank account NEW: #22328 NEW: #22424 -NEW: #22500 member module set up made easier +NEW: #22500 member module set up made easier NEW: #22527 projects and thirdparties can be viewed as conversation ("Message" view), like events/agenda. NEW: #22546 can now set user supervisors using mass action in htdocs/user NEW: #22594 can chose if VAT ID is unique or not for third parties -NEW: #22622 all partneships displayed on tab partnership of a thirdparty and member +NEW: #22622 all partnerships displayed on tab partnership of a thirdparty and member NEW: #22676 massaction for updating product prices NEW: #22735 Massaction to affect users on projects NEW: #25594 can chose if VAT ID is unique or not for third parties @@ -66,7 +66,7 @@ NEW: Add option FICHINTER_ALLOW_EXTERNAL_DOWNLOAD NEW: Add option --force on CLI cron_run_jobs.php NEW: Add option "Show price on the generated documents for receptions" NEW: Add performance index (name for company and contact) and llx_bank_url(url_id) -NEW: Add picto property on sub-module for paswword generation +NEW: Add picto property on sub-module for password generation NEW: Add price to product box in TakePOS NEW: add redirect on action confirm addconsumedline and addproduceline NEW: Add a new advanced permission "read price" @@ -85,7 +85,7 @@ NEW: Can enter the unit price including the vat NEW: Can invoice task time per different services NEW: Can join several files by default on email form NEW: Can send an email on scheduled job error -NEW: Can set a commercial discount by entereing amount including VAT +NEW: Can set a commercial discount by entering amount including VAT NEW: Can set a monthly frequency (or multiple) in cron tasks. NEW: Can set start and end dates and comment on button "Activate all services" NEW: can sort and preselected best supplier price @@ -133,7 +133,7 @@ NEW: Option PRODUIT_DESC_IN_FORM accept (desktop only or +smartphone) NEW: Page for mass stock transfer can be used with no source stock NEW: parent company column and filter in invoice and order list NEW: Add show "Sales rep" option for PDF -NEW: Picto for shared link is clicable +NEW: Picto for shared link is clickable NEW: possibility to select scopes with checkbox for Oauth tokens NEW: private and public note on user, thirdparty and contact list NEW: product categories filter on inventory list @@ -147,7 +147,7 @@ NEW: Saved token of OAUTH module are now encrypted into llx_oauth_token NEW: Save one click to select on delivery ack, on emails. NEW: scheduled job to send unpaid invoice reminder can now use the cc and bcc from email template NEW: set thirdparty type with company modify trigger -NEW: Show also shceduled task never finished in scheduled task widget +NEW: Show also scheduled task never finished in scheduled task widget NEW: show badge with number of extrafields in setup NEW: show category tree in sellist and chkbxlst for common object NEW: Show picto and color into combo for selection of tags @@ -165,7 +165,10 @@ NEW: Update ActionComm type_code on email message ticket NEW: VAT - Admin - Add information on deadline day for submission of VAT declaration NEW: expand/collapse permissions on user permission page NEW: Show delivery mode on PDF for proposals +NEW: Add the target to select attendees of event for emailings + Modules +NEW: Experimental module Asset For developers or integrators: ------------------------------ diff --git a/build/debian/source/options b/build/debian/source/options new file mode 100644 index 00000000000..4918d029b84 --- /dev/null +++ b/build/debian/source/options @@ -0,0 +1,3 @@ +# Use bzip2 instead of gzip +compression = "bzip2" +compression-level = 9 diff --git a/build/generate_filelist_xml.php b/build/generate_filelist_xml.php index 3d72ebe6739..b122f9b0305 100755 --- a/build/generate_filelist_xml.php +++ b/build/generate_filelist_xml.php @@ -55,14 +55,24 @@ if (empty($argv[1])) { $i=0; +$result=array(); while ($i < $argc) { if (!empty($argv[$i])) { - parse_str($argv[$i]); // set all params $release, $includecustom, $includeconstant, $buildzip ... + parse_str($argv[$i], $result); // set all params $release, $includecustom, $includeconstant, $buildzip ... } - if (preg_match('/includeconstant=/', $argv[$i])) { - $tmp=explode(':', $includeconstant, 3); // $includeconstant has been set with previous parse_str() + if (!empty($result["release"])) { + $release = $result["release"]; + } + if (!empty($result["includecustom"])) { + $includecustom = $result["includecustom"]; + } + if (!empty($result["includeconstant"])) { + $includeconstants[$i] = $result["includeconstant"]; + } + if (preg_match('/includeconstant=/', strval($argv[$i]))) { + $tmp=explode(':', $result['includeconstant'], 3); // $includeconstant has been set with previous parse_str() if (count($tmp) != 3) { - print "Error: Bad parameter includeconstant=".$includeconstant."\n"; + print "Error: Bad parameter includeconstant=".$result['includeconstant'] ."\n"; exit -1; } $includeconstants[$tmp[0]][$tmp[1]] = $tmp[2]; @@ -71,7 +81,7 @@ while ($i < $argc) { } if (empty($release)) { - print "Error: Missing release paramater\n"; + print "Error: Missing release parameter\n"; print "Usage: ".$script_file." release=autostable|auto[-mybuild]|x.y.z[-mybuild] [includecustom=1] [includeconstant=CC:MY_CONF_NAME:value]\n"; exit -1; } diff --git a/dev/dolibarr_changes.txt b/dev/dolibarr_changes.txt index cbfecbbc19f..461db52f959 100644 --- a/dev/dolibarr_changes.txt +++ b/dev/dolibarr_changes.txt @@ -283,6 +283,9 @@ RESTLER: elseif (count($value) && isset($value[0]) && is_numeric($value[0])) +* Add CommentParser.php line 406 & 407 to remove a warning on api request in php 8.1 + empty($value[0]) ? null : + empty($value[1]) ? null : +With swagger 2 provided into /explorer: ---------------------------------------- diff --git a/htdocs/accountancy/bookkeeping/balance.php b/htdocs/accountancy/bookkeeping/balance.php index d2b1aaa3348..01d89f1168d 100644 --- a/htdocs/accountancy/bookkeeping/balance.php +++ b/htdocs/accountancy/bookkeeping/balance.php @@ -239,10 +239,17 @@ if ($action != 'export_csv') { print ''; print ''; + $parameters = array(); $reshook = $hookmanager->executeHooks('addMoreActionsButtonsList', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } + + $button = empty($hookmanager->resPrint) ? '' : $hookmanager->resPrint; + if (empty($reshook)) { - $button = 'global->ACCOUNTING_EXPORT_FORMAT.')" />'; + $button .= 'global->ACCOUNTING_EXPORT_FORMAT.')" />'; print ''."\n"; } - print dol_get_fiche_head('', ''); + print dol_get_fiche_head(''); print ''; @@ -692,13 +694,8 @@ if ($action == 'create') { } -/* ************************************************************************** */ -/* */ -/* View mode */ -/* */ -/* ************************************************************************** */ - -if ($id) { +// View mode +if ($id > 0) { $head = salaries_prepare_head($object); $formconfirm = ''; @@ -794,34 +791,26 @@ if ($id) { $morehtmlref .= ''; } + $usercancreate = $permissiontoadd; + // Project if (isModEnabled('project')) { - $morehtmlref .= '
'.$langs->trans('Project').' '; - if ($user->rights->salaries->write) { + $langs->load("projects"); + $morehtmlref .= '
'; + if ($usercancreate) { + $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(-1, $object->fk_project, 'projectid', 0, 0, 1, 0, 1, 0, 0, '', 1, 0, 'maxwidth500'); - $morehtmlref .= ''; - $morehtmlref .= ''; - } else { - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + $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, ($action == 'classify' ? 1 : 0), 0, 1, ''); } else { if (!empty($object->fk_project)) { $proj = new Project($db); $proj->fetch($object->fk_project); - $morehtmlref .= ' : '.$proj->getNomUrl(1); + $morehtmlref .= $proj->getNomUrl(1); if ($proj->title) { - $morehtmlref .= ' - '.$proj->title; + $morehtmlref .= ' - '.dol_escape_htmltag($proj->title).''; } - } else { - $morehtmlref .= ''; } } } diff --git a/htdocs/salaries/document.php b/htdocs/salaries/document.php index 163042dbeb8..2ce7b2e2745 100644 --- a/htdocs/salaries/document.php +++ b/htdocs/salaries/document.php @@ -78,7 +78,9 @@ $childids = $user->getAllChildIds(1); // fetch optionals attributes and labels $extrafields->fetch_name_optionals_label($object->table_element); -$object = new Salary($db); +// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +$hookmanager->initHooks(array('salarydoc', 'globalcard')); + if ($id > 0 || !empty($ref)) { $object->fetch($id, $ref); @@ -105,7 +107,9 @@ if ($user->socid) { } restrictedArea($user, 'salaries', $object->id, 'salary', ''); +$permissiontoread = $user->rights->salaries->read; $permissiontoadd = $user->rights->salaries->write; // Used by the include of actions_addupdatedelete.inc.php and actions_linkedfiles +$permissiontodelete = $user->rights->salaries->delete || ($permissiontoadd && isset($object->status) && $object->status == $object::STATUS_DRAFT); /* @@ -176,34 +180,26 @@ if ($object->id) { $morehtmlref .= '
'.$langs->trans('Employee').' : '.$userstatic->getNomUrl(-1); + $usercancreate = $permissiontoadd; + // Project if (isModEnabled('project')) { - $morehtmlref .= '
'.$langs->trans('Project').' '; - if ($user->rights->salaries->write) { + $langs->load("projects"); + $morehtmlref .= '
'; + if ($usercancreate) { + $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(-1, $object->fk_project, 'projectid', 0, 0, 1, 0, 1, 0, 0, '', 1, 0, 'maxwidth500'); - $morehtmlref .= ''; - $morehtmlref .= ''; - } else { - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, -1, $object->fk_project, 'none', 0, 0, 0, 1); + $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, ($action == 'classify' ? 1 : 0), 0, 1, ''); } else { if (!empty($object->fk_project)) { $proj = new Project($db); $proj->fetch($object->fk_project); - $morehtmlref .= ' : '.$proj->getNomUrl(1); + $morehtmlref .= $proj->getNomUrl(1); if ($proj->title) { - $morehtmlref .= ' - '.$proj->title; + $morehtmlref .= ' - '.dol_escape_htmltag($proj->title).''; } - } else { - $morehtmlref .= ''; } } } diff --git a/htdocs/salaries/info.php b/htdocs/salaries/info.php index e16493ddc91..1085b1175cf 100644 --- a/htdocs/salaries/info.php +++ b/htdocs/salaries/info.php @@ -58,6 +58,9 @@ $childids = $user->getAllChildIds(1); // fetch optionals attributes and labels $extrafields->fetch_name_optionals_label($object->table_element); +// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +$hookmanager->initHooks(array('salaryinfo', 'globalcard')); + $object = new Salary($db); if ($id > 0 || !empty($ref)) { $object->fetch($id, $ref); @@ -77,6 +80,10 @@ if ($id > 0 || !empty($ref)) { restrictedArea($user, 'salaries', $object->id, 'salary', ''); +$permissiontoread = $user->rights->salaries->read; +$permissiontoadd = $user->rights->salaries->write; // Used by the include of actions_addupdatedelete.inc.php and actions_linkedfiles +$permissiontodelete = $user->rights->salaries->delete || ($permissiontoadd && isset($object->status) && $object->status == $object::STATUS_DRAFT); + /* * Actions @@ -107,7 +114,6 @@ $title = $langs->trans('Salary')." - ".$langs->trans('Info'); $help_url = ""; llxHeader("", $title, $help_url); -$object = new Salary($db); $object->fetch($id); $object->info($id); @@ -139,34 +145,26 @@ if ($action != 'editlabel') { $morehtmlref .= '
'.$langs->trans('Employee').' : '.$userstatic->getNomUrl(-1); +$usercancreate = $permissiontoadd; + // Project if (isModEnabled('project')) { - $morehtmlref .= '
'.$langs->trans('Project').' '; - if ($user->rights->salaries->write) { + $langs->load("projects"); + $morehtmlref .= '
'; + if ($usercancreate) { + $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(-1, $object->fk_project, 'projectid', 0, 0, 1, 0, 1, 0, 0, '', 1, 0, 'maxwidth500'); - $morehtmlref .= ''; - $morehtmlref .= ''; - } else { - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + $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, ($action == 'classify' ? 1 : 0), 0, 1, ''); } else { if (!empty($object->fk_project)) { $proj = new Project($db); $proj->fetch($object->fk_project); - $morehtmlref .= ' : '.$proj->getNomUrl(1); + $morehtmlref .= $proj->getNomUrl(1); if ($proj->title) { - $morehtmlref .= ' - '.$proj->title; + $morehtmlref .= ' - '.dol_escape_htmltag($proj->title).''; } - } else { - $morehtmlref .= ''; } } } @@ -180,7 +178,7 @@ print '
'; print '
'; -print '
\n"; + try { + if ($stripeacc) { + $list = \Stripe\Charge::all($option, array("stripe_account" => $stripeacc)); + } else { + $list = \Stripe\Charge::all($option); + } + + $num = count($list->data); + + + //if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage); + if ($limit > 0 && $limit != $conf->liste_limit) { + $param .= '&limit='.urlencode($limit); + } + $param .= '&starting_after_'.($page + 1).'='.$list->data[($limit - 1)]->id; + //$param.='&ending_before_'.($page+1).'='.$list->data[($limit-1)]->id; + } catch (Exception $e) { + print ''; + } + //print $list; $i = 0; - foreach ($list->data as $charge) { - if ($i >= $limit) { - break; - } + if (!empty($list)) { + foreach ($list->data as $charge) { + if ($i >= $limit) { + break; + } - if ($charge->refunded == '1') { - $status = img_picto($langs->trans("refunded"), 'statut6'); - } elseif ($charge->paid == '1') { - $status = img_picto($langs->trans((string) $charge->status), 'statut4'); - } else { - $label = $langs->trans("Message").": ".$charge->failure_message."
"; - $label .= $langs->trans("Network").": ".$charge->outcome->network_status."
"; - $label .= $langs->trans("Status").": ".$langs->trans((string) $charge->outcome->seller_message); - $status = $form->textwithpicto(img_picto($langs->trans((string) $charge->status), 'statut8'), $label, -1); - } + if ($charge->refunded == '1') { + $status = img_picto($langs->trans("refunded"), 'statut6'); + } elseif ($charge->paid == '1') { + $status = img_picto($langs->trans((string) $charge->status), 'statut4'); + } else { + $label = $langs->trans("Message").": ".$charge->failure_message."
"; + $label .= $langs->trans("Network").": ".$charge->outcome->network_status."
"; + $label .= $langs->trans("Status").": ".$langs->trans((string) $charge->outcome->seller_message); + $status = $form->textwithpicto(img_picto($langs->trans((string) $charge->status), 'statut8'), $label, -1); + } - if (isset($charge->payment_method_details->type) && $charge->payment_method_details->type == 'card') { - $type = $langs->trans("card"); - } elseif (isset($charge->source->type) && $charge->source->type == 'card') { - $type = $langs->trans("card"); - } elseif (isset($charge->payment_method_details->type) && $charge->payment_method_details->type == 'three_d_secure') { - $type = $langs->trans("card3DS"); - } elseif (isset($charge->payment_method_details->type) && $charge->payment_method_details->type == 'sepa_debit') { - $type = $langs->trans("sepadebit"); - } elseif (isset($charge->payment_method_details->type) && $charge->payment_method_details->type == 'ideal') { - $type = $langs->trans("iDEAL"); - } + if (isset($charge->payment_method_details->type) && $charge->payment_method_details->type == 'card') { + $type = $langs->trans("card"); + } elseif (isset($charge->source->type) && $charge->source->type == 'card') { + $type = $langs->trans("card"); + } elseif (isset($charge->payment_method_details->type) && $charge->payment_method_details->type == 'three_d_secure') { + $type = $langs->trans("card3DS"); + } elseif (isset($charge->payment_method_details->type) && $charge->payment_method_details->type == 'sepa_debit') { + $type = $langs->trans("sepadebit"); + } elseif (isset($charge->payment_method_details->type) && $charge->payment_method_details->type == 'ideal') { + $type = $langs->trans("iDEAL"); + } - // Why this ? - /*if (!empty($charge->payment_intent)) { - if (empty($stripeacc)) { // If the Stripe connect account not set, we use common API usage - $charge = \Stripe\PaymentIntent::retrieve($charge->payment_intent); - } else { - $charge = \Stripe\PaymentIntent::retrieve($charge->payment_intent, array("stripe_account" => $stripeacc)); - } - }*/ + // Why this ? + /*if (!empty($charge->payment_intent)) { + if (empty($stripeacc)) { // If the Stripe connect account not set, we use common API usage + $charge = \Stripe\PaymentIntent::retrieve($charge->payment_intent); + } else { + $charge = \Stripe\PaymentIntent::retrieve($charge->payment_intent, array("stripe_account" => $stripeacc)); + } + }*/ - // The metadata FULLTAG is defined by the online payment page - $FULLTAG = $charge->metadata->FULLTAG; + // The metadata FULLTAG is defined by the online payment page + $FULLTAG = $charge->metadata->FULLTAG; - // Save into $tmparray all metadata - $tmparray = dolExplodeIntoArray($FULLTAG, '.', '='); - // Load origin object according to metadata - if (!empty($tmparray['CUS']) && $tmparray['CUS'] > 0) { - $societestatic->fetch($tmparray['CUS']); - } elseif (!empty($charge->metadata->dol_thirdparty_id) && $charge->metadata->dol_thirdparty_id > 0) { - $societestatic->fetch($charge->metadata->dol_thirdparty_id); - } else { - $societestatic->id = 0; - } - if (!empty($tmparray['MEM']) && $tmparray['MEM'] > 0) { - $memberstatic->fetch($tmparray['MEM']); - } else { - $memberstatic->id = 0; - } + // Save into $tmparray all metadata + $tmparray = dolExplodeIntoArray($FULLTAG, '.', '='); + // Load origin object according to metadata + if (!empty($tmparray['CUS']) && $tmparray['CUS'] > 0) { + $societestatic->fetch($tmparray['CUS']); + } elseif (!empty($charge->metadata->dol_thirdparty_id) && $charge->metadata->dol_thirdparty_id > 0) { + $societestatic->fetch($charge->metadata->dol_thirdparty_id); + } else { + $societestatic->id = 0; + } + if (!empty($tmparray['MEM']) && $tmparray['MEM'] > 0) { + $memberstatic->fetch($tmparray['MEM']); + } else { + $memberstatic->id = 0; + } - print ''; + print ''; - if (!empty($stripeacc)) { - $connect = $stripeacc.'/'; - } else { - $connect = ''; - } + if (!empty($stripeacc)) { + $connect = $stripeacc.'/'; + } else { + $connect = ''; + } - // Ref - $url = 'https://dashboard.stripe.com/'.$connect.'test/payments/'.$charge->id; - if ($servicestatus) { - $url = 'https://dashboard.stripe.com/'.$connect.'payments/'.$charge->id; - } - print "\n"; + // Ref + $url = 'https://dashboard.stripe.com/'.$connect.'test/payments/'.$charge->id; + if ($servicestatus) { + $url = 'https://dashboard.stripe.com/'.$connect.'payments/'.$charge->id; + } + print "\n"; - // Stripe customer - print "\n"; + // Stripe customer + print "\n"; - // Link - print "\n"; + // Link + print "\n"; - // Origin - print "\n"; + + // Date payment + print '\n"; + // Type + print ''; + // Amount + print '"; + // Status + print '\n"; + + print "\n"; + + $i++; } - print "\n"; - - // Date payment - print '\n"; - // Type - print ''; - // Amount - print '"; - // Status - print '\n"; - - print "\n"; - - $i++; } print '
'; +print '
'; dol_print_object_info($object); print '
'; diff --git a/htdocs/societe/class/api_thirdparties.class.php b/htdocs/societe/class/api_thirdparties.class.php index 3901db79cc4..f68122bdfff 100644 --- a/htdocs/societe/class/api_thirdparties.class.php +++ b/htdocs/societe/class/api_thirdparties.class.php @@ -1154,7 +1154,7 @@ class Thirdparties extends DolibarrApi */ public function getCompanyBankAccount($id) { - if (!DolibarrApiAccess::$user->rights->facture->lire) { + if (!DolibarrApiAccess::$user->rights->societe->lire) { throw new RestException(401); } if (empty($id)) { diff --git a/htdocs/societe/class/companybankaccount.class.php b/htdocs/societe/class/companybankaccount.class.php index c3ecbe31ccd..d81a360e7d2 100644 --- a/htdocs/societe/class/companybankaccount.class.php +++ b/htdocs/societe/class/companybankaccount.class.php @@ -242,8 +242,7 @@ class CompanyBankAccount extends Account $sql .= " FROM ".MAIN_DB_PREFIX."societe_rib"; if ($id) { $sql .= " WHERE rowid = ".((int) $id); - } - if ($socid) { + } elseif ($socid > 0) { $sql .= " WHERE fk_soc = ".((int) $socid); if ($default > -1) { $sql .= " AND default_rib = ".((int) $default); diff --git a/htdocs/societe/list.php b/htdocs/societe/list.php index f5fcc56b49d..6da7fcf3779 100644 --- a/htdocs/societe/list.php +++ b/htdocs/societe/list.php @@ -488,6 +488,9 @@ if (!empty($extrafields->attributes[$object->table_element]['label'])) { $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object, $action); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; + +$sqlfields = $sql; // $sql fields to remove for count total + $sql .= " FROM ".MAIN_DB_PREFIX."societe as s"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s2 ON s.parent = s2.rowid"; if (!empty($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { @@ -723,14 +726,9 @@ $sql .= $hookmanager->resPrint; // Count total nb of records with no order and no limits $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { - /*$resql = $db->query($sql); - if ($resql) { - $nbtotalofrecords = $db->num_rows($resql); - } else { - dol_print_error($db); - }*/ /* The fast and low memory method to get and count full list converts the sql into a sql count */ - $sqlforcount = preg_replace('/^SELECT[a-zA-Z0-9\._\s\(\),=<>\:\-\']+\sFROM/Ui', 'SELECT COUNT(*) as nbtotalofrecords FROM', $sql); + $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); + $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); $resql = $db->query($sqlforcount); if ($resql) { $objforcount = $db->fetch_object($resql); diff --git a/htdocs/stripe/charge.php b/htdocs/stripe/charge.php index f598275177e..0aee0c11e30 100644 --- a/htdocs/stripe/charge.php +++ b/htdocs/stripe/charge.php @@ -87,38 +87,18 @@ if (!$rowid) { $option = array('limit' => $limit + 1); $num = 0; + $param = ''; + $totalnboflines = ''; + $moreforfilter = ''; + $list = null; if (GETPOSTISSET('starting_after_'.$page)) { $option['starting_after'] = GETPOST('starting_after_'.$page, 'alphanohtml'); } - - try { - if ($stripeacc) { - $list = \Stripe\Charge::all($option, array("stripe_account" => $stripeacc)); - } else { - $list = \Stripe\Charge::all($option); - } - - $num = count($list->data); - - $totalnboflines = ''; - - $param = ''; - //if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage); - if ($limit > 0 && $limit != $conf->liste_limit) { - $param .= '&limit='.urlencode($limit); - } - $param .= '&starting_after_'.($page + 1).'='.$list->data[($limit - 1)]->id; - //$param.='&ending_before_'.($page+1).'='.$list->data[($limit-1)]->id; - - $moreforfilter = ''; - } catch (Exception $e) { - print $e->getMessage(); - } - print '
'; if ($optioncss != '') { print ''; } + print ''; print ''; print ''; @@ -145,146 +125,168 @@ if (!$rowid) { print_liste_field_titre("Status", $_SERVER["PHP_SELF"], "", "", "", '', '', '', 'right '); print "
'.$e->getMessage().'
"; - print "".img_picto($langs->trans('ShowInStripe'), 'globe')." ".$charge->id.""; - if ($charge->payment_intent) { - print '
'.$charge->payment_intent.''; - } - print "
"; + print "".img_picto($langs->trans('ShowInStripe'), 'globe')." ".$charge->id.""; + if ($charge->payment_intent) { + print '
'.$charge->payment_intent.''; + } + print "
"; - if (isModEnabled('stripe') && !empty($stripeacc)) { - $connect = $stripeacc.'/'; - } - $url = 'https://dashboard.stripe.com/'.$connect.'test/customers/'.$charge->customer; - if ($servicestatus) { - $url = 'https://dashboard.stripe.com/'.$connect.'customers/'.$charge->customer; - } - if (!empty($charge->customer)) { - print ''.img_picto($langs->trans('ShowInStripe'), 'globe').' '.$charge->customer.''; - } - print ""; + if (isModEnabled('stripe') && !empty($stripeacc)) { + $connect = $stripeacc.'/'; + } + $url = 'https://dashboard.stripe.com/'.$connect.'test/customers/'.$charge->customer; + if ($servicestatus) { + $url = 'https://dashboard.stripe.com/'.$connect.'customers/'.$charge->customer; + } + if (!empty($charge->customer)) { + print ''.img_picto($langs->trans('ShowInStripe'), 'globe').' '.$charge->customer.''; + } + print ""; - if ($societestatic->id > 0) { - print $societestatic->getNomUrl(1); - } elseif ($memberstatic->id > 0) { - print $memberstatic->getNomUrl(1); - } - print ""; + if ($societestatic->id > 0) { + print $societestatic->getNomUrl(1); + } elseif ($memberstatic->id > 0) { + print $memberstatic->getNomUrl(1); + } + print ""; - if ($charge->metadata->dol_type == "order" || $charge->metadata->dol_type == "commande") { - $object = new Commande($db); - $object->fetch($charge->metadata->dol_id); - if ($object->id > 0) { - print "".img_picto('', 'order')." ".$object->ref.""; + // Origin + print ""; + if ($charge->metadata->dol_type == "order" || $charge->metadata->dol_type == "commande") { + $object = new Commande($db); + $object->fetch($charge->metadata->dol_id); + if ($object->id > 0) { + print "".img_picto('', 'order')." ".$object->ref.""; + } else { + print $FULLTAG; + } + } elseif ($charge->metadata->dol_type == "invoice" || $charge->metadata->dol_type == "facture") { + $object = new Facture($db); + $object->fetch($charge->metadata->dol_id); + if ($object->id > 0) { + print "".img_picto('', 'bill')." ".$object->ref.""; + } else { + print $FULLTAG; + } } else { print $FULLTAG; } - } elseif ($charge->metadata->dol_type == "invoice" || $charge->metadata->dol_type == "facture") { - $object = new Facture($db); - $object->fetch($charge->metadata->dol_id); - if ($object->id > 0) { - print "".img_picto('', 'bill')." ".$object->ref.""; - } else { - print $FULLTAG; - } - } else { - print $FULLTAG; + print "'.dol_print_date($charge->created, 'dayhour')."'; + print $type; + print ''.price(($charge->amount - $charge->amount_refunded) / 100, 0, '', 1, - 1, - 1, strtoupper($charge->currency))."'; + print $status; + print "
'.dol_print_date($charge->created, 'dayhour')."'; - print $type; - print ''.price(($charge->amount - $charge->amount_refunded) / 100, 0, '', 1, - 1, - 1, strtoupper($charge->currency))."'; - print $status; - print "
'; diff --git a/htdocs/supplier_proposal/card.php b/htdocs/supplier_proposal/card.php index 66f69a25ff9..71d9668dc92 100644 --- a/htdocs/supplier_proposal/card.php +++ b/htdocs/supplier_proposal/card.php @@ -972,7 +972,7 @@ if (empty($reshook)) { } $ttc = price2num(GETPOST('price_ttc'), '', 2); - $ht = $ttc / (1 + ($vatratecleaned / 100)); + $ht = (float) $ttc / (1 + ((float) $vatratecleaned / 100)); $price_base_type = 'HT'; } @@ -1879,7 +1879,7 @@ if ($action == 'create') { // Show object lines $result = $object->getLinesArray(); - print ' + print ' diff --git a/htdocs/takepos/css/pos.css.php b/htdocs/takepos/css/pos.css.php index 6f72fa6e7f2..88482b4dcba 100644 --- a/htdocs/takepos/css/pos.css.php +++ b/htdocs/takepos/css/pos.css.php @@ -337,7 +337,8 @@ div.paymentbordline width: 100%; height: 100%; margin: 0 auto; - overflow: visible; + overflow-x: hidden; + overfloy-y: scroll; box-sizing: border-box; } @@ -364,6 +365,7 @@ div.paymentbordline margin: 0 auto; width: 100%; height: 55%; + overflow: hidden; } .div1{ @@ -714,9 +716,12 @@ div#moreinfo, div#infowarehouse { } button.actionbutton { - min-height: 60px; + display: inline-flex; + align-items: center; + justify-content: center; padding-left: 4px; padding-right: 4px; + min-height: 30px; } } @@ -940,17 +945,19 @@ div#moreinfo, div#infowarehouse { } } -.arrows { - display: none; - position: absolute; - justify-content: space-between; - width: 100%; -} - .indicator { background: #00000042; padding: 15px 5px; cursor: pointer; + position:absolute; +} + +.indicator.left { + left:0; +} + +.indicator.right { + right:0; } .indicator:hover { @@ -1041,4 +1048,4 @@ html { .topnav.overflow .arrows { display: flex; -} \ No newline at end of file +} diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index 6f246a0ce96..ce4c6760aab 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -1395,6 +1395,12 @@ select.flat.selectlimit { overflow: hidden; height: auto !important; } +.tenlinesmax { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 10; + overflow: hidden; +} .tablelistofcalendars { margin-top: 25px !important; diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index 2324da32c43..71c45545961 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -1514,6 +1514,12 @@ select.flat.selectlimit { overflow: hidden; height: auto !important; } +.tenlinesmax { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 10; + overflow: hidden; +} .tablelistofcalendars { margin-top: 25px !important; diff --git a/htdocs/ticket/class/actions_ticket.class.php b/htdocs/ticket/class/actions_ticket.class.php index c5e267fddf6..6ad204965bc 100644 --- a/htdocs/ticket/class/actions_ticket.class.php +++ b/htdocs/ticket/class/actions_ticket.class.php @@ -206,9 +206,9 @@ class ActionsTicket print ''; print ''; - if (!empty($user->rights->ticket->manage) && $action == 'edit_message_init') { + if ($user->hasRight('ticket', 'manage') && $action == 'edit_message_init') { // MESSAGE - $msg = GETPOST('message_initial', 'alpha') ? GETPOST('message_initial', 'alpha') : $object->message; + $msg = GETPOSTISSET('message_initial') ? GETPOST('message_initial', 'restricthtml') : $object->message; include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; $uselocalbrowser = true; $ckeditorenabledforticket = $conf->global->FCKEDITOR_ENABLE_TICKET; @@ -218,7 +218,7 @@ class ActionsTicket // Deal with format differences (text / HTML) if (dol_textishtml($object->message)) { print '
'; - print $object->message; + print dol_htmlwithnojs($object->message); print '
'; /*print '
'; print $langs->trans("More").'...'; diff --git a/htdocs/ticket/class/ticket.class.php b/htdocs/ticket/class/ticket.class.php index 440950628d1..2aacffefcd1 100644 --- a/htdocs/ticket/class/ticket.class.php +++ b/htdocs/ticket/class/ticket.class.php @@ -1612,13 +1612,13 @@ class Ticket extends CommonObject // Insert entry into agenda with code 'TICKET_MSG' include_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php'; $actioncomm = new ActionComm($this->db); - $actioncomm->type_code = 'AC_OTH'; + $actioncomm->type_code = 'AC_OTH_AUTO'; // This is not an entry that must appears into manual calendar but only into CRM calendar $actioncomm->code = 'TICKET_MSG'; if ($this->private) { $actioncomm->code = 'TICKET_MSG_PRIVATE'; } if ($send_email) { - $actioncomm->type_code = 'AC_EMAIL'; + $actioncomm->code .= '_SENTBYMAIL'; } $actioncomm->socid = $this->socid; $actioncomm->label = $this->subject; @@ -1691,7 +1691,7 @@ class Ticket extends CommonObject $this->cache_msgs_ticket[$i]['datec'] = $this->db->jdate($obj->datec); $this->cache_msgs_ticket[$i]['subject'] = $obj->label; $this->cache_msgs_ticket[$i]['message'] = $obj->message; - $this->cache_msgs_ticket[$i]['private'] = ($obj->code == 'TICKET_MSG_PRIVATE' ? 1 : 0); + $this->cache_msgs_ticket[$i]['private'] = (preg_match('/^TICKET_MSG_PRIVATE/', $obj->code) ? 1 : 0); $i++; } return $num; diff --git a/htdocs/ticket/list.php b/htdocs/ticket/list.php index 8430598a308..4c4dce5a428 100644 --- a/htdocs/ticket/list.php +++ b/htdocs/ticket/list.php @@ -353,6 +353,9 @@ $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook $sql .= preg_replace('/^,/', '', $hookmanager->resPrint); $sql = preg_replace('/,\s*$/', '', $sql); + +$sqlfields = $sql; // $sql fields to remove for count total + $sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t"; if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (t.rowid = ef.fk_object)"; @@ -458,11 +461,17 @@ $sql .= $hookmanager->resPrint; $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { /* The fast and low memory method to get and count full list converts the sql into a sql count */ - $sqlforcount = preg_replace('/^SELECT[a-zA-Z0-9\._\s\(\),=<>\:\-\']+\sFROM/Ui', 'SELECT COUNT(*) as nbtotalofrecords FROM', $sql); + $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); + $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); $resql = $db->query($sqlforcount); - $objforcount = $db->fetch_object($resql); - $nbtotalofrecords = $objforcount->nbtotalofrecords; - if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 + if ($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 $page = 0; $offset = 0; } diff --git a/htdocs/user/card.php b/htdocs/user/card.php index 7fc268568c8..2325ab7ab53 100644 --- a/htdocs/user/card.php +++ b/htdocs/user/card.php @@ -537,6 +537,9 @@ if (empty($reshook)) { $sql .= " SET fk_socpeople=".((int) $contactid); if (!empty($contact->socid)) { $sql .= ", fk_soc=".((int) $contact->socid); + } elseif ($socid > 0) { + $sql .= ", fk_soc = null"; + setEventMessages($langs->trans("WarningUserDifferentContactSocid"), '', 'warnings'); // Add message if post socid != $contact->socid } $sql .= " WHERE rowid = ".((int) $object->id); } elseif ($socid > 0) { diff --git a/htdocs/user/list.php b/htdocs/user/list.php index d472ae3e9f4..8610113f0da 100644 --- a/htdocs/user/list.php +++ b/htdocs/user/list.php @@ -373,6 +373,9 @@ $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook $sql .= preg_replace('/^,/', '', $hookmanager->resPrint); $sql = preg_replace('/,\s*$/', '', $sql); + +$sqlfields = $sql; // $sql fields to remove for count total + $sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as u"; if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (u.rowid = ef.fk_object)"; @@ -481,21 +484,9 @@ $sql .= $hookmanager->resPrint; // Count total nb of records $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { - /* This old and fast method to get and count full list returns all record so use a high amount of memory. - $resql = $db->query($sql); - $nbtotalofrecords = $db->num_rows($resql); - */ - /* The slow method does not consume memory on mysql (not tested on pgsql) */ - /*$resql = $db->query($sql, 0, 'auto', 1); - while ($db->fetch_object($resql)) { - if (empty($nbtotalofrecords)) { - $nbtotalofrecords = 1; // We can't make +1 because init value is '' - } else { - $nbtotalofrecords++; - } - }*/ /* The fast and low memory method to get and count full list converts the sql into a sql count */ - $sqlforcount = preg_replace('/^SELECT[a-zA-Z0-9\._\s\(\),=<>\:\-\']+\sFROM/Ui', 'SELECT COUNT(*) as nbtotalofrecords FROM', $sql); + $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); + $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); $resql = $db->query($sqlforcount); if ($resql) { $objforcount = $db->fetch_object($resql); @@ -504,7 +495,7 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { dol_print_error($db); } - if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 + if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0 $page = 0; $offset = 0; } diff --git a/htdocs/website/index.php b/htdocs/website/index.php index 98b5ac49795..3593ddbcd95 100644 --- a/htdocs/website/index.php +++ b/htdocs/website/index.php @@ -572,7 +572,23 @@ if ($massaction == 'delcategory' && GETPOST('confirmmassaction', 'alpha') && $us if ($massaction == 'replace' && GETPOST('confirmmassaction', 'alpha') && $usercanedit) { $replacestring = GETPOST('replacestring', 'none'); - if (empty($user->rights->website->writephp)) { + $dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT); + $allowimportsite = true; + if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) { + $allowimportsite = false; + } + + if (!$allowimportsite) { + // Blocked by installmodules.lock + if (getDolGlobalString('MAIN_MESSAGE_INSTALL_MODULES_DISABLED_CONTACT_US')) { + // Show clean corporate message + $message = $langs->trans('InstallModuleFromWebHasBeenDisabledContactUs'); + } else { + // Show technical generic message + $message = $langs->trans("InstallModuleFromWebHasBeenDisabledByFile", $dolibarrdataroot.'/installmodules.lock'); + } + setEventMessages($message, null, 'errors'); + } elseif (empty($user->rights->website->writephp)) { setEventMessages("NotAllowedToAddDynamicContent", null, 'errors'); } elseif (!$replacestring) { setEventMessages("ErrorReplaceStringEmpty", null, 'errors'); @@ -2377,76 +2393,93 @@ if ($action == 'regeneratesite' && $usercanedit) { // Import site if ($action == 'importsiteconfirm' && $usercanedit) { - if (empty($_FILES) && !GETPOSTISSET('templateuserfile')) { - setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("File")), null, 'errors'); - $action = 'importsite'; - } else { - if (!empty($_FILES) || GETPOSTISSET('templateuserfile')) { - // Check symlink to medias and restore it if ko. Recreate also dir of website if not found. - $pathtomedias = DOL_DATA_ROOT.'/medias'; - $pathtomediasinwebsite = $pathofwebsite.'/medias'; - if (!is_link(dol_osencode($pathtomediasinwebsite))) { - dol_syslog("Create symlink for ".$pathtomedias." into name ".$pathtomediasinwebsite); - dol_mkdir(dirname($pathtomediasinwebsite)); // To be sure dir for website exists - $result = symlink($pathtomedias, $pathtomediasinwebsite); - if (!$result) { - setEventMessages($langs->trans("ErrorFieldToCreateSymLinkToMedias", $pathtomediasinwebsite, $pathtomedias), null, 'errors'); - $action = 'importsite'; - } - } + $dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT); + $allowimportsite = true; + if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) { + $allowimportsite = false; + } - $fileofzip = ''; - if (GETPOSTISSET('templateuserfile')) { - $fileofzip = DOL_DATA_ROOT.'/doctemplates/websites/'.GETPOST('templateuserfile', 'alpha'); - } elseif (!empty($_FILES)) { - if (is_array($_FILES['userfile']['tmp_name'])) { - $userfiles = $_FILES['userfile']['tmp_name']; - } else { - $userfiles = array($_FILES['userfile']['tmp_name']); + if ($allowimportsite) { + if (empty($_FILES) && !GETPOSTISSET('templateuserfile')) { + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("File")), null, 'errors'); + $action = 'importsite'; + } else { + if (!empty($_FILES) || GETPOSTISSET('templateuserfile')) { + // Check symlink to medias and restore it if ko. Recreate also dir of website if not found. + $pathtomedias = DOL_DATA_ROOT.'/medias'; + $pathtomediasinwebsite = $pathofwebsite.'/medias'; + if (!is_link(dol_osencode($pathtomediasinwebsite))) { + dol_syslog("Create symlink for ".$pathtomedias." into name ".$pathtomediasinwebsite); + dol_mkdir(dirname($pathtomediasinwebsite)); // To be sure dir for website exists + $result = symlink($pathtomedias, $pathtomediasinwebsite); + if (!$result) { + setEventMessages($langs->trans("ErrorFieldToCreateSymLinkToMedias", $pathtomediasinwebsite, $pathtomedias), null, 'errors'); + $action = 'importsite'; + } } - foreach ($userfiles as $key => $userfile) { - if (empty($_FILES['userfile']['tmp_name'][$key])) { - $error++; - if ($_FILES['userfile']['error'][$key] == 1 || $_FILES['userfile']['error'][$key] == 2) { - setEventMessages($langs->trans('ErrorFileSizeTooLarge'), null, 'errors'); - $action = 'importsite'; - } else { - setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("File")), null, 'errors'); - $action = 'importsite'; + $fileofzip = ''; + if (GETPOSTISSET('templateuserfile')) { + $fileofzip = DOL_DATA_ROOT.'/doctemplates/websites/'.GETPOST('templateuserfile', 'alpha'); + } elseif (!empty($_FILES)) { + if (is_array($_FILES['userfile']['tmp_name'])) { + $userfiles = $_FILES['userfile']['tmp_name']; + } else { + $userfiles = array($_FILES['userfile']['tmp_name']); + } + + foreach ($userfiles as $key => $userfile) { + if (empty($_FILES['userfile']['tmp_name'][$key])) { + $error++; + if ($_FILES['userfile']['error'][$key] == 1 || $_FILES['userfile']['error'][$key] == 2) { + setEventMessages($langs->trans('ErrorFileSizeTooLarge'), null, 'errors'); + $action = 'importsite'; + } else { + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("File")), null, 'errors'); + $action = 'importsite'; + } + } + } + + if (!$error) { + $upload_dir = $conf->website->dir_temp; + $result = dol_add_file_process($upload_dir, 1, -1, 'userfile', ''); + } + + // Get name of file (take last one if several name provided) + $fileofzip = $upload_dir.'/unknown'; + foreach ($_FILES as $key => $ifile) { + foreach ($ifile['name'] as $key2 => $ifile2) { + $fileofzip = $upload_dir.'/'.$ifile2; } } } if (!$error) { - $upload_dir = $conf->website->dir_temp; - $result = dol_add_file_process($upload_dir, 1, -1, 'userfile', ''); - } + $result = $object->importWebSite($fileofzip); - // Get name of file (take last one if several name provided) - $fileofzip = $upload_dir.'/unknown'; - foreach ($_FILES as $key => $ifile) { - foreach ($ifile['name'] as $key2 => $ifile2) { - $fileofzip = $upload_dir.'/'.$ifile2; + if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + $action = 'importsite'; + } else { + // Force mode dynamic on + dolibarr_set_const($db, 'WEBSITE_SUBCONTAINERSINLINE', 1, 'chaine', 0, '', $conf->entity); + + header("Location: ".$_SERVER["PHP_SELF"].'?website='.$object->ref); + exit(); } } } - - if (!$error) { - $result = $object->importWebSite($fileofzip); - - if ($result < 0) { - setEventMessages($object->error, $object->errors, 'errors'); - $action = 'importsite'; - } else { - // Force mode dynamic on - dolibarr_set_const($db, 'WEBSITE_SUBCONTAINERSINLINE', 1, 'chaine', 0, '', $conf->entity); - - header("Location: ".$_SERVER["PHP_SELF"].'?website='.$object->ref); - exit(); - } - } } + } else { + if (getDolGlobalString('MAIN_MESSAGE_INSTALL_MODULES_DISABLED_CONTACT_US')) { + // Show clean corporate message + $message = $langs->trans('InstallModuleFromWebHasBeenDisabledContactUs'); + } else { + // Show technical generic message + $message = $langs->trans("InstallModuleFromWebHasBeenDisabledByFile", $dolibarrdataroot.'/installmodules.lock'); + } + setEventMessages($message, null, 'errors'); } } @@ -3847,16 +3880,33 @@ if ($action == 'importsite') { print ''.$langs->trans("ZipOfWebsitePackageToImport").'

'; - $maxfilesizearray = getMaxFileSizeArray(); - $maxmin = $maxfilesizearray['maxmin']; - if ($maxmin > 0) { - print ''; // MAX_FILE_SIZE must precede the field type=file - } - print ''; - print ''; - print ''; - print '


'; + $dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT); + $allowimportsite = true; + if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) { + $allowimportsite = false; + } + + if ($allowimportsite) { + $maxfilesizearray = getMaxFileSizeArray(); + $maxmin = $maxfilesizearray['maxmin']; + if ($maxmin > 0) { + print ''; // MAX_FILE_SIZE must precede the field type=file + } + print ''; + print ''; + print ''; + print '


'; + } else { + if (getDolGlobalString('MAIN_MESSAGE_INSTALL_MODULES_DISABLED_CONTACT_US')) { + // Show clean corporate message + $message = $langs->trans('InstallModuleFromWebHasBeenDisabledContactUs'); + } else { + // Show technical generic message + $message = $langs->trans("InstallModuleFromWebHasBeenDisabledByFile", $dolibarrdataroot.'/installmodules.lock'); + } + print info_admin($message).'

'; + } print ''.$langs->trans("ZipOfWebsitePackageToLoad").'

'; diff --git a/scripts/cron/cron_run_jobs.php b/scripts/cron/cron_run_jobs.php index 630ae8c9948..c7a9d19fb5c 100755 --- a/scripts/cron/cron_run_jobs.php +++ b/scripts/cron/cron_run_jobs.php @@ -189,25 +189,17 @@ if ($result < 0) { exit(-1); } -$qualifiedjobs = array(); -foreach ($object->lines as $val) { - if (!verifCond($val->test)) { - continue; - } - $qualifiedjobs[] = $val; -} - // TODO Duplicate code. This sequence of code must be shared with code into public/cron/cron_run_jobs.php php page. -$nbofjobs = count($qualifiedjobs); +$nbofjobs = count($object->lines); $nbofjobslaunchedok = 0; $nbofjobslaunchedko = 0; -if (is_array($qualifiedjobs) && (count($qualifiedjobs) > 0)) { +if (is_array($object->lines) && (count($object->lines) > 0)) { $savconf = dol_clone($conf); // Loop over job - foreach ($qualifiedjobs as $line) { + foreach ($object->lines as $line) { dol_syslog("cron_run_jobs.php cronjobid: ".$line->id." priority=".$line->priority." entity=".$line->entity." label=".$line->label, LOG_DEBUG); echo "cron_run_jobs.php cronjobid: ".$line->id." priority=".$line->priority." entity=".$line->entity." label=".$line->label; @@ -249,6 +241,10 @@ if (is_array($qualifiedjobs) && (count($qualifiedjobs) > 0)) { } } + if (!verifCond($line->test)) { + continue; + } + //If date_next_jobs is less of current date, execute the program, and store the execution time of the next execution in database if ($forcequalified || (($line->datenextrun < $now) && (empty($line->datestart) || $line->datestart <= $now) && (empty($line->dateend) || $line->dateend >= $now))) { echo " - qualified"; diff --git a/test/phpunit/SecurityTest.php b/test/phpunit/SecurityTest.php index cadf8a7504f..cd4c3600b4c 100644 --- a/test/phpunit/SecurityTest.php +++ b/test/phpunit/SecurityTest.php @@ -537,16 +537,19 @@ class SecurityTest extends PHPUnit\Framework\TestCase print __METHOD__." result=".$result."\n"; $this->assertEquals("Text with ' encoded with the numeric html entity converted into text entity ' (like when submited by CKEditor)", $result, 'Test 14'); - $result=GETPOST("param15", 'restricthtml'); // src=>0xbeefed + $result=GETPOST("param15", 'restricthtml'); // param15 = src=>0xbeefed that is a dangerous string print __METHOD__." result=".$result."\n"; $this->assertEquals("0xbeefed", $result, 'Test 15'); // The GETPOST return a harmull string - // Test with restricthtml + MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES to test disabling of bad atrributes + // Test with restricthtml + MAIN_RESTRICTHTML_ONLY_VALID_HTML to test disabling of bad atrributes $conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML = 1; - $result=GETPOST("param15", 'restricthtml'); + + $result=GETPOST("param15", 'restricthtml'); // param15 = src=>0xbeefed that is a dangerous string print __METHOD__." result=".$result."\n"; $this->assertEquals('InvalidHTMLString', $result, 'Test 15b'); + //$this->assertEquals(' src=>0xbeefed', $result, 'Test 15b'); + unset($conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML); @@ -555,7 +558,7 @@ class SecurityTest extends PHPUnit\Framework\TestCase $result=GETPOST("param15", 'restricthtml'); print __METHOD__." result=".$result."\n"; - $this->assertEquals('0xbeefed', $result, 'Test 15b'); + $this->assertEquals('0xbeefed', $result, 'Test 15c'); $result=GETPOST('param16', 'restricthtml'); print __METHOD__." result=".$result."\n"; @@ -836,6 +839,36 @@ class SecurityTest extends PHPUnit\Framework\TestCase $this->assertEquals('google.com', $result, 'Test on dol_sanitizeUrl C'); } + /** + * testDolSanitizeEmail + * + * @return void + */ + public function testDolSanitizeEmail() + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $test = 'aaa@mycompany.com , bbb@mycompany.com '; + $result=dol_sanitizeEmail($test); + $this->assertEquals($test, $result, 'Test on dol_sanitizeEmail A'); + + $test = "aaa@mycompany.com ,\nbbb@mycompany.com "; + $result=dol_sanitizeEmail($test); + $this->assertEquals('aaa@mycompany.com ,bbb@mycompany.com ', $result, 'Test on dol_sanitizeEmail B'); + + $test = 'aaa@mycompany.com ,\nbbb@mycompany.com '; + $result=dol_sanitizeEmail($test); + $this->assertEquals('aaa@mycompany.com ,nbbb@mycompany.com ', $result, 'Test on dol_sanitizeEmail C'); + + $test = 'aaa@mycompany.com , "bcc:bbb"@mycompany.com '; + $result=dol_sanitizeEmail($test); + $this->assertEquals('aaa@mycompany.com , bccbbb@mycompany.com ', $result, 'Test on dol_sanitizeEmail D'); + } + /** * testDolSanitizeFileName *