diff --git a/ChangeLog b/ChangeLog index 900dff4a9ab..ce8c34636f6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24,7 +24,56 @@ Following changes may create regressions for some external modules, but were nec ***** 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 ***** 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/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index c65d9e551ea..d0c2d9998b4 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -2976,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; @@ -2988,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 @@ -3001,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 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/modules/expedition/doc/pdf_espadon.modules.php b/htdocs/core/modules/expedition/doc/pdf_espadon.modules.php index d95d9912c2b..f6c648f2ff0 100644 --- a/htdocs/core/modules/expedition/doc/pdf_espadon.modules.php +++ b/htdocs/core/modules/expedition/doc/pdf_espadon.modules.php @@ -394,20 +394,19 @@ class pdf_espadon extends ModelePdfExpedition $label .= $object->tracking_url; } - $height_trackingnumber += 6; + $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(); } } + $tab_top = $pdf->GetY(); } // Notes $pagenb = $pdf->getPage(); if (!empty($notetoshow) || !empty($object->tracking_number)) { - $tab_top -= 2; + $tab_top -= 1; $tab_width = $this->page_largeur - $this->marge_gauche - $this->marge_droite; $pageposbeforenote = $pagenb; @@ -476,7 +475,7 @@ class pdf_espadon extends ModelePdfExpedition $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 + 1); + $pdf->Rect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 2); } else { if (empty($height_trackingnumber)) { $height_note = $this->page_hauteur - ($tab_top + $heightforfooter); @@ -484,7 +483,7 @@ class pdf_espadon extends ModelePdfExpedition $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 + 1); + $pdf->Rect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 2); } // Add footer @@ -510,7 +509,7 @@ class pdf_espadon extends ModelePdfExpedition $height_note = $posyafter - $tab_top + $height_trackingnumber + 1; $tab_top = $tab_topbeforetrackingnumber; } - $pdf->Rect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 1); + $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/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/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)) { -
global->MAIN_LOGIN_BACKGROUND) ? '' : ' backgroundsemitransparent boxshadow').'" style="max-width: 70%">'; print ''; print $langs->trans('SendNewPasswordDesc'); print ''; + print '
'; } } else { + print '
'; print '
'; print $langs->trans('AuthenticationDoesNotAllowSendNewPassword', $mode); print '
'; + 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)) { -
global->MAIN_LOGIN_BACKGROUND) ? '' : ' backgroundsemitransparent boxshadow').'" style="max-width: 70%">'; print ''; print $langs->trans('EnterNewPasswordHere'); print ''; + print '
'; } } else { + print '
'; print '
'; print $langs->trans('AuthenticationDoesNotAllowSendNewPassword', $mode); print '
'; + print '
'; } ?> -
diff --git a/htdocs/emailcollector/class/emailcollector.class.php b/htdocs/emailcollector/class/emailcollector.class.php index ffd1dfc3d50..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); diff --git a/htdocs/eventorganization/conferenceorbooth_list.php b/htdocs/eventorganization/conferenceorbooth_list.php index 17b0bc2e570..258c47f12fc 100644 --- a/htdocs/eventorganization/conferenceorbooth_list.php +++ b/htdocs/eventorganization/conferenceorbooth_list.php @@ -403,7 +403,7 @@ if ($projectid > 0) { // Description print ''; // Categories 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/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 484e207e347..9fb7a487118 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -2199,7 +2199,7 @@ LargerThan=Larger than IfTrackingIDFoundEventWillBeLinked=Note that If a tracking ID of an object is found into email, or if the email is an answer of an email aready collected and linked to an object, the created event will be automatically linked to the known related object. WithGMailYouCanCreateADedicatedPassword=With a GMail account, if you enabled the 2 steps validation, it is recommanded to create a dedicated second password for the application instead of using your own account passsword from https://myaccount.google.com/. EmailCollectorTargetDir=It may be a desired behaviour to move the email into another tag/directory when it was processed successfully. Just set name of directory here to use this feature (Do NOT use special characters in name). Note that you must also use a read/write login account. -EmailCollectorLoadThirdPartyHelp=You can use this action to use the email content to find and load an existing thirdparty in your database. The found (or created) thirdparty will be used for following actions that need it.
For example, if you want to create a thirdparty with a name extracted from a string 'Name: name to find' present into the body, use the sender email as email, you can set the parameter field like this:
'email=HEADER:^From:(.*);name=EXTRACT:BODY:Name:\\s([^\\s]*);client=SET:2;'
+EmailCollectorLoadThirdPartyHelp=You can use this action to use the email content to find and load an existing thirdparty in your database (search will be done on the defined property among 'id','name','name_alias','email'). The found (or created) thirdparty will be used for following actions that need it.
For example, if you want to create a thirdparty with a name extracted from a string 'Name: name to find' present into the body, use the sender email as email, you can set the parameter field like this:
'email=HEADER:^From:(.*);name=EXTRACT:BODY:Name:\\s([^\\s]*);client=SET:2;'
EndPointFor=End point for %s : %s DeleteEmailCollector=Delete email collector ConfirmDeleteEmailCollector=Are you sure you want to delete this email collector? diff --git a/htdocs/projet/card.php b/htdocs/projet/card.php index bc31f211a63..42833785c09 100644 --- a/htdocs/projet/card.php +++ b/htdocs/projet/card.php @@ -420,7 +420,7 @@ if (empty($reshook)) { require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; $langs->load("other"); - $upload_dir = $conf->project->dir_output; + $upload_dir = $conf->project->multidir_output[$object->entity]; $file = $upload_dir.'/'.GETPOST('file'); $ret = dol_delete_file($file, 0, 0, 0, $object); if ($ret) { @@ -1219,8 +1219,8 @@ if ($action == 'create' && $user->rights->projet->creer) { $morehtmlref = '
'; // Title $morehtmlref .= dol_escape_htmltag($object->title); - // Thirdparty $morehtmlref .= '
'; + // Thirdparty if (!empty($object->thirdparty->id) && $object->thirdparty->id > 0) { $morehtmlref .= $object->thirdparty->getNomUrl(1, 'project'); } @@ -1238,7 +1238,7 @@ if ($action == 'create' && $user->rights->projet->creer) { print '
'; print '
'; - print '
'.img_picto('', 'technic', 'class="pictofixedwidth"').$form->textwithpicto($langs->trans("EmailcollectorOperations"), $langs->trans("EmailcollectorOperationsDesc")).'
'.$langs->trans("Description").''; - print nl2br($project->description); + print dol_htmlentitiesbr($project->description); print '
'; + print '
'; // Usage if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES) || empty($conf->global->PROJECT_HIDE_TASKS) || isModEnabled('eventorganization')) { @@ -1308,15 +1308,6 @@ if ($action == 'create' && $user->rights->projet->creer) { } } print ''; - - // Opportunity Weighted Amount - /* - print ''; - */ } // Budget @@ -1605,12 +1596,12 @@ if ($action == 'create' && $user->rights->projet->creer) { * Generated documents */ $filename = dol_sanitizeFileName($object->ref); - $filedir = $conf->project->dir_output."/".dol_sanitizeFileName($object->ref); + $filedir = $conf->project->multidir_output[$object->entity]."/".dol_sanitizeFileName($object->ref); $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id; $genallowed = ($user->rights->projet->lire && $userAccess > 0); $delallowed = ($user->rights->projet->creer && $userWrite > 0); - print $formfile->showdocuments('project', $filename, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf); + print $formfile->showdocuments('project', $filename, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 0, 0, '', '', '', '', '', $object); print '
'; @@ -1629,7 +1620,7 @@ if ($action == 'create' && $user->rights->projet->creer) { // Presend form $modelmail = 'project'; $defaulttopic = 'SendProjectRef'; - $diroutput = $conf->project->dir_output; + $diroutput = $conf->project->multidir_output[$object->entity]; $autocopy = 'MAIN_MAIL_AUTOCOPY_PROJECT_TO'; // used to know the automatic BCC to add $trackid = 'proj'.$object->id; diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index b3c0c142f7a..9f00d4ce3c0 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -1422,6 +1422,7 @@ class Project extends CommonObject // Initialise parameters $this->id = 0; $this->ref = 'SPECIMEN'; + $this->entity = $conf->entity; $this->specimen = 1; $this->socid = 1; $this->date_c = $now; diff --git a/htdocs/projet/class/task.class.php b/htdocs/projet/class/task.class.php index b8821fbd486..fe00eb671d9 100644 --- a/htdocs/projet/class/task.class.php +++ b/htdocs/projet/class/task.class.php @@ -203,7 +203,7 @@ class Task extends CommonObjectLine $sql .= ", progress"; $sql .= ", budget_amount"; $sql .= ") VALUES ("; - $sql .= ((int) $conf->entity); + $sql .= (!empty($this->entity) ? (int) $this->entity : (int) $conf->entity); $sql .= ", ".((int) $this->fk_project); $sql .= ", ".(!empty($this->ref) ? "'".$this->db->escape($this->ref)."'" : 'null'); $sql .= ", ".((int) $this->fk_task_parent); @@ -279,6 +279,7 @@ class Task extends CommonObjectLine $sql = "SELECT"; $sql .= " t.rowid,"; $sql .= " t.ref,"; + $sql .= " t.entity,"; $sql .= " t.fk_projet as fk_project,"; $sql .= " t.fk_task_parent,"; $sql .= " t.label,"; @@ -323,6 +324,7 @@ class Task extends CommonObjectLine $this->id = $obj->rowid; $this->ref = $obj->ref; + $this->entity = $obj->entity; $this->fk_project = $obj->fk_project; $this->fk_task_parent = $obj->fk_task_parent; $this->label = $obj->label; diff --git a/htdocs/projet/contact.php b/htdocs/projet/contact.php index 43fdb1a3ca2..b0fece54827 100644 --- a/htdocs/projet/contact.php +++ b/htdocs/projet/contact.php @@ -247,6 +247,10 @@ if (empty($reshook)) { * View */ +$form = new Form($db); +$contactstatic = new Contact($db); +$userstatic = new User($db); + $title = $langs->trans('ProjectContact').' - '.$object->ref.' '.$object->name; if (!empty($conf->global->MAIN_HTML_TITLE) && preg_match('/projectnameonly/', $conf->global->MAIN_HTML_TITLE) && $object->name) { $title = $object->ref.' '.$object->name.' - '.$langs->trans('ProjectContact'); @@ -256,18 +260,12 @@ $help_url = 'EN:Module_Projects|FR:Module_Projets|ES:Módulo_Proyectos|DE: llxHeader('', $title, $help_url); -$form = new Form($db); -$contactstatic = new Contact($db); -$userstatic = new User($db); -/* *************************************************************************** */ -/* */ -/* Edition and view mode */ -/* */ -/* *************************************************************************** */ - if ($id > 0 || !empty($ref)) { + /* + * View + */ if (!empty($conf->global->PROJECT_ALLOW_COMMENT_ON_PROJECT) && method_exists($object, 'fetchComments') && empty($object->comments)) { $object->fetchComments(); } @@ -300,10 +298,11 @@ if ($id > 0 || !empty($ref)) { $morehtmlref = '
'; // Title - $morehtmlref .= $object->title; + $morehtmlref .= dol_escape_htmltag($object->title); + $morehtmlref .= '
'; // Thirdparty if (!empty($object->thirdparty->id) && $object->thirdparty->id > 0) { - $morehtmlref .= '
'.$object->thirdparty->getNomUrl(1, 'project'); + $morehtmlref .= $object->thirdparty->getNomUrl(1, 'project'); } $morehtmlref .= '
'; @@ -365,26 +364,25 @@ if ($id > 0 || !empty($ref)) { } print ''; - if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES) && $object->opp_status) { + if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES) && !empty($object->usage_opportunity)) { // Opportunity status print '
'; // Opportunity percent - print ''; + print ''; // Opportunity Amount print ''; @@ -404,7 +402,7 @@ if ($id > 0 || !empty($ref)) { $start = dol_print_date($object->date_start, 'day'); print ($start ? $start : '?'); $end = dol_print_date($object->date_end, 'day'); - print ' - '; + print ' - '; print ($end ? $end : '?'); if ($object->hasDelay()) { print img_warning("Late"); @@ -425,7 +423,7 @@ if ($id > 0 || !empty($ref)) { // Description print ''; // Categories diff --git a/htdocs/projet/document.php b/htdocs/projet/document.php index bb50bf0def6..4e7620476c4 100644 --- a/htdocs/projet/document.php +++ b/htdocs/projet/document.php @@ -50,7 +50,7 @@ if (!empty($conf->global->PROJECT_ALLOW_COMMENT_ON_PROJECT) && method_exists($ob } if ($id > 0 || !empty($ref)) { - $upload_dir = $conf->project->dir_output."/".dol_sanitizeFileName($object->ref); + $upload_dir = $conf->project->multidir_output[$object->entity]."/".dol_sanitizeFileName($object->ref); } // Get parameters @@ -110,7 +110,7 @@ llxHeader('', $title, $help_url); $form = new Form($db); if ($object->id > 0) { - $upload_dir = $conf->project->dir_output.'/'.dol_sanitizeFileName($object->ref); + $upload_dir = $conf->project->multidir_output[$object->entity].'/'.dol_sanitizeFileName($object->ref); // To verify role of users //$userAccess = $object->restrictedProjectArea($user,'read'); diff --git a/htdocs/projet/element.php b/htdocs/projet/element.php index 3dcbbbbcddf..a737ffce640 100644 --- a/htdocs/projet/element.php +++ b/htdocs/projet/element.php @@ -341,7 +341,7 @@ print '
'.$langs->trans('OpportunityWeightedAmount').''; - if (strcmp($object->opp_amount, '') && strcmp($object->opp_percent, '')) { - print ''.price($object->opp_amount * $object->opp_percent / 100, 0, $langs, 1, 0, -1, $conf->currency).''; - } - print '
'.$langs->trans("OpportunityStatus").''; $code = dol_getIdFromCode($db, $object->opp_status, 'c_lead_status', 'rowid', 'code'); if ($code) { print $langs->trans("OppStatus".$code); } - print '
'.$langs->trans("OpportunityProbability").''; + print ' / '; if (strcmp($object->opp_percent, '')) { - print price($object->opp_percent, '', $langs, 1, 0).' %'; + print price($object->opp_percent, 0, $langs, 1, 0).' %'; } - print '
'.$langs->trans("OpportunityAmount").''; if (strcmp($object->opp_amount, '')) { - print ''.price($object->opp_amount, '', $langs, 0, 0, 0, $conf->currency).''; + print ''.price($object->opp_amount, 0, $langs, 1, 0, -1, $conf->currency).''; if (strcmp($object->opp_percent, '')) { print '       '.$langs->trans("Weighted").': '.price($object->opp_amount * $object->opp_percent / 100, 0, $langs, 1, 0, -1, $conf->currency).''; } @@ -395,7 +393,7 @@ if ($id > 0 || !empty($ref)) { // Budget print '
'.$langs->trans("Budget").''; if (!is_null($object->budget_amount) && strcmp($object->budget_amount, '')) { - print ''.price($object->budget_amount, '', $langs, 0, 0, 0, $conf->currency).''; + print ''.price($object->budget_amount, 0, $langs, 1, 0, 0, $conf->currency).''; } print '
'.$langs->trans("Description").''; - print nl2br($object->description); + print dol_htmlentitiesbr($object->description); print '
'; // Description print ''; // Categories diff --git a/htdocs/projet/tasks.php b/htdocs/projet/tasks.php index 9e448b6cf45..f0f98e3df6c 100644 --- a/htdocs/projet/tasks.php +++ b/htdocs/projet/tasks.php @@ -344,6 +344,7 @@ if ($action == 'createtask' && $user->rights->projet->creer) { $task = new Task($db); $task->fk_project = $projectid; + $task->entity = $object->entity; // Task have the same entity of project $task->ref = $taskref; $task->label = $label; $task->description = $description; @@ -668,7 +669,7 @@ if ($id > 0 || !empty($ref)) { // Description print ''; // Categories diff --git a/htdocs/projet/tasks/document.php b/htdocs/projet/tasks/document.php index 6a62e973a62..b8c6fd863c5 100644 --- a/htdocs/projet/tasks/document.php +++ b/htdocs/projet/tasks/document.php @@ -111,7 +111,7 @@ if ($id > 0 || !empty($ref)) { $object->project = clone $projectstatic; - $upload_dir = $conf->project->dir_output.'/'.dol_sanitizeFileName($projectstatic->ref).'/'.dol_sanitizeFileName($object->ref); + $upload_dir = $conf->project->multidir_output[$projectstatic->entity].'/'.dol_sanitizeFileName($projectstatic->ref).'/'.dol_sanitizeFileName($object->ref); } include DOL_DOCUMENT_ROOT.'/core/actions_linkedfiles.inc.php'; diff --git a/htdocs/projet/tasks/time.php b/htdocs/projet/tasks/time.php index fe7d2a093fd..12eb7c573ce 100644 --- a/htdocs/projet/tasks/time.php +++ b/htdocs/projet/tasks/time.php @@ -1051,7 +1051,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser // Description print ''; // Categories
'.$langs->trans("Description").''; -print nl2br($object->description); +print dol_htmlentitiesbr($object->description); print '
'.$langs->trans("Description").''; - print nl2br($object->description); + print dol_htmlentitiesbr($object->description); print '
'.$langs->trans("Description").''; - print nl2br($projectstatic->description); + print dol_htmlentitiesbr($projectstatic->description); print '