Merge branch '17.0' of git@github.com:Dolibarr/dolibarr.git into develop

This commit is contained in:
Laurent Destailleur 2023-04-04 19:40:05 +02:00
commit 220d404d62
23 changed files with 183 additions and 91 deletions

View File

@ -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 *****

View File

@ -684,18 +684,18 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
print '</table>';
print '</div>';
print '<div class="clearboth"></div><br>';
print '<div class="clearboth"></div><br><br>';
// Operations
print '<div class="div-table-responsive">';
print '<table id="tablelines" class="noborder margintable noshadow">';
print '<div class="div-table-responsive-no-min">';
print '<table id="tablelines" class="noborder noshadow">';
print '<tr class="liste_titre nodrag nodrop">';
print '<td>'.img_picto('', 'technic', 'class="pictofixedwidth"').$form->textwithpicto($langs->trans("EmailcollectorOperations"), $langs->trans("EmailcollectorOperationsDesc")).'</td><td></td><td></td><td></td>';
print '</tr>';
$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'
);

View File

@ -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

View File

@ -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)$'));

View File

@ -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))) {

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -238,21 +238,23 @@ if (!empty($morelogincontent)) {
</form>
<div class="center login_main_home divpasswordmessagedesc paddingtopbottom<?php echo empty($conf->global->MAIN_LOGIN_BACKGROUND) ? '' : ' backgroundsemitransparent boxshadow'; ?>" style="max-width: 70%">
<?php
if ($mode == 'dolibarr' || !$disabled) {
if ($action != 'validatenewpassword' && empty($message)) {
print '<div class="center login_main_home divpasswordmessagedesc paddingtopbottom'.(empty($conf->global->MAIN_LOGIN_BACKGROUND) ? '' : ' backgroundsemitransparent boxshadow').'" style="max-width: 70%">';
print '<span class="passwordmessagedesc opacitymedium">';
print $langs->trans('SendNewPasswordDesc');
print '</span>';
print '</div>';
}
} else {
print '<div class="center login_main_home divpasswordmessagedesc paddingtopbottom'.(empty($conf->global->MAIN_LOGIN_BACKGROUND) ? '' : ' backgroundsemitransparent boxshadow').'" style="max-width: 70%">';
print '<div class="warning center">';
print $langs->trans('AuthenticationDoesNotAllowSendNewPassword', $mode);
print '</div>';
print '</div>';
}
?>
</div>
<br>

View File

@ -118,7 +118,7 @@ if ($setnewpassword && $username && $passworduidhash) {
?>
<!-- BEGIN PHP TEMPLATE PASSWORDFORGOTTEN.TPL.PHP -->
<!-- BEGIN PHP TEMPLATE PASSWORDRESET.TPL.PHP -->
<body class="body bodylogin"<?php print empty($conf->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)) {
</form>
<div class="center login_main_home divpasswordmessagedesc paddingtopbottom<?php echo empty($conf->global->MAIN_LOGIN_BACKGROUND) ? '' : ' backgroundsemitransparent boxshadow'; ?>" style="max-width: 70%">
<?php
if ($mode == 'dolibarr' || !$disabled) {
if (empty($message)) {
print '<div class="center login_main_home divpasswordmessagedesc paddingtopbottom'.(empty($conf->global->MAIN_LOGIN_BACKGROUND) ? '' : ' backgroundsemitransparent boxshadow').'" style="max-width: 70%">';
print '<span class="passwordmessagedesc opacitymedium">';
print $langs->trans('EnterNewPasswordHere');
print '</span>';
print '</div>';
}
} else {
print '<div class="center login_main_home divpasswordmessagedesc paddingtopbottom'.(empty($conf->global->MAIN_LOGIN_BACKGROUND) ? '' : ' backgroundsemitransparent boxshadow').'" style="max-width: 70%">';
print '<div class="warning center">';
print $langs->trans('AuthenticationDoesNotAllowSendNewPassword', $mode);
print '</div>';
print '</div>';
}
?>
</div>
<br>

View File

@ -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 .= '<br>Process email '.dol_escape_htmltag($iforemailloop)." - References: ".dol_escape_htmltag($headers['References'])." - Subject: ".dol_escape_htmltag($headers['Subject']);
$operationslog .= '<br>** 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 .= '<br>Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtolower($sourcefield).' -> Found idtouseforthirdparty='.dol_escape_htmltag($idtouseforthirdparty);
$operationslog .= '<br>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 .= '<br>Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtolower($sourcefield).' -> Found propertytooverwrite='.dol_escape_htmltag($propertytooverwrite);
} else {
$operationslog .= '<br>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 .= '<br>Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtolower($sourcefield).' -> Found nametouseforthirdparty='.dol_escape_htmltag($nametouseforthirdparty);
$operationslog .= '<br>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 .= '<br>Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found namealiastouseforthirdparty='.dol_escape_htmltag($namealiastouseforthirdparty);
} else {
$operationslog .= '<br>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 .= '<br>Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtolower($sourcefield).' -> Not found';
$operationslog .= '<br>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 .= '<br>We set property emailtouseforthrdparty='.dol_escape_htmltag($emailtouseforthirdparty);
} else {
} elseif ($propertytooverwrite == 'name') {
$nametouseforthirdparty = $reg[2];
$operationslog .= '<br>We set property nametouseforthirdparty='.dol_escape_htmltag($nametouseforthirdparty);
} elseif ($propertytooverwrite == 'name_alias') {
$namealiastouseforthirdparty = $reg[2];
$operationslog .= '<br>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);

View File

@ -403,7 +403,7 @@ if ($projectid > 0) {
// Description
print '<tr><td class="titlefield tdtop">'.$langs->trans("Description").'</td><td class="valuefield">';
print nl2br($project->description);
print dol_htmlentitiesbr($project->description);
print '</td></tr>';
// Categories

View File

@ -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();
}
}
}

View File

@ -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.<br>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:<br>'email=HEADER:^From:(.*);name=EXTRACT:BODY:Name:\\s([^\\s]*);client=SET:2;'<br>
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.<br>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:<br>'email=HEADER:^From:(.*);name=EXTRACT:BODY:Name:\\s([^\\s]*);client=SET:2;'<br>
EndPointFor=End point for %s : %s
DeleteEmailCollector=Delete email collector
ConfirmDeleteEmailCollector=Are you sure you want to delete this email collector?

View File

@ -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 = '<div class="refidno">';
// Title
$morehtmlref .= dol_escape_htmltag($object->title);
// Thirdparty
$morehtmlref .= '<br>';
// 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 '<div class="fichehalfleft">';
print '<div class="underbanner clearboth"></div>';
print '<table class="border tableforfield" width="100%">';
print '<table class="border tableforfield centpercent">';
// 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 '</td></tr>';
// Opportunity Weighted Amount
/*
print '<tr><td>'.$langs->trans('OpportunityWeightedAmount').'</td><td>';
if (strcmp($object->opp_amount, '') && strcmp($object->opp_percent, '')) {
print '<span class="amount">'.price($object->opp_amount * $object->opp_percent / 100, 0, $langs, 1, 0, -1, $conf->currency).'</span>';
}
print '</td></tr>';
*/
}
// 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 '</div><div class="fichehalfright">';
@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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&oacute;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 = '<div class="refidno">';
// Title
$morehtmlref .= $object->title;
$morehtmlref .= dol_escape_htmltag($object->title);
$morehtmlref .= '<br>';
// Thirdparty
if (!empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
$morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1, 'project');
$morehtmlref .= $object->thirdparty->getNomUrl(1, 'project');
}
$morehtmlref .= '</div>';
@ -365,26 +364,25 @@ if ($id > 0 || !empty($ref)) {
}
print '</td></tr>';
if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES) && $object->opp_status) {
if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES) && !empty($object->usage_opportunity)) {
// Opportunity status
print '<tr><td>'.$langs->trans("OpportunityStatus").'</td><td>';
$code = dol_getIdFromCode($db, $object->opp_status, 'c_lead_status', 'rowid', 'code');
if ($code) {
print $langs->trans("OppStatus".$code);
}
print '</td></tr>';
// Opportunity percent
print '<tr><td>'.$langs->trans("OpportunityProbability").'</td><td>';
print ' <span title="'.$langs->trans("OpportunityProbability").'"> / ';
if (strcmp($object->opp_percent, '')) {
print price($object->opp_percent, '', $langs, 1, 0).' %';
print price($object->opp_percent, 0, $langs, 1, 0).' %';
}
print '</td></tr>';
print '</span></td></tr>';
// Opportunity Amount
print '<tr><td>'.$langs->trans("OpportunityAmount").'</td><td>';
if (strcmp($object->opp_amount, '')) {
print '<span class="amount">'.price($object->opp_amount, '', $langs, 0, 0, 0, $conf->currency).'</span>';
print '<span class="amount">'.price($object->opp_amount, 0, $langs, 1, 0, -1, $conf->currency).'</span>';
if (strcmp($object->opp_percent, '')) {
print ' &nbsp; &nbsp; &nbsp; <span title="'.dol_escape_htmltag($langs->trans('OpportunityWeightedAmount')).'"><span class="opacitymedium">'.$langs->trans("Weighted").'</span>: <span class="amount">'.price($object->opp_amount * $object->opp_percent / 100, 0, $langs, 1, 0, -1, $conf->currency).'</span></span>';
}
@ -395,7 +393,7 @@ if ($id > 0 || !empty($ref)) {
// Budget
print '<tr><td>'.$langs->trans("Budget").'</td><td>';
if (!is_null($object->budget_amount) && strcmp($object->budget_amount, '')) {
print '<span class="amount">'.price($object->budget_amount, '', $langs, 0, 0, 0, $conf->currency).'</span>';
print '<span class="amount">'.price($object->budget_amount, 0, $langs, 1, 0, 0, $conf->currency).'</span>';
}
print '</td></tr>';
@ -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 ' <span class="opacitymedium">-</span> ';
print ($end ? $end : '?');
if ($object->hasDelay()) {
print img_warning("Late");
@ -425,7 +423,7 @@ if ($id > 0 || !empty($ref)) {
// Description
print '<td class="titlefield tdtop">'.$langs->trans("Description").'</td><td>';
print nl2br($object->description);
print dol_htmlentitiesbr($object->description);
print '</td></tr>';
// Categories

View File

@ -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');

View File

@ -341,7 +341,7 @@ print '<table class="border tableforfield centpercent">';
// Description
print '<td class="titlefield tdtop">'.$langs->trans("Description").'</td><td>';
print nl2br($object->description);
print dol_htmlentitiesbr($object->description);
print '</td></tr>';
// Categories

View File

@ -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 '<td class="titlefield tdtop">'.$langs->trans("Description").'</td><td>';
print nl2br($object->description);
print dol_htmlentitiesbr($object->description);
print '</td></tr>';
// Categories

View File

@ -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';

View File

@ -1051,7 +1051,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser
// Description
print '<td class="titlefield tdtop">'.$langs->trans("Description").'</td><td>';
print nl2br($projectstatic->description);
print dol_htmlentitiesbr($projectstatic->description);
print '</td></tr>';
// Categories