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

develop
This commit is contained in:
ldestailleur
2025-03-02 15:29:14 +01:00
12 changed files with 59 additions and 32 deletions

View File

@@ -164,6 +164,8 @@ NEW: vat rate with department in dict (#31628) (#31627)
NEW: When we export data of unlaterable log, we add an unalterable line in logs NEW: When we export data of unlaterable log, we add an unalterable line in logs
NEW Add option THEME_STICKY_TOPMENU = 'scrollleftmenu_after_mainpage' (or 'disabled') NEW Add option THEME_STICKY_TOPMENU = 'scrollleftmenu_after_mainpage' (or 'disabled')
NEW value for FICHINTER_DISABLE_DETAILS. If FICHINTER_DISABLE_DETAILS is set to '2' details are disabled only on intervention list. NEW value for FICHINTER_DISABLE_DETAILS. If FICHINTER_DISABLE_DETAILS is set to '2' details are disabled only on intervention list.
SEC: security avoid RCE using -'- sequence to pass --checkpoint-action parameter in tar command.
SEC: FIX Security path transversal with modulepart=medias (viewimage.php and download.php)
PERF: Reduce nb of requests into num_public_holiday PERF: Reduce nb of requests into num_public_holiday
PERF: Reduce size for VCF files and virtualcard qrcode PERF: Reduce size for VCF files and virtualcard qrcode

View File

@@ -91,8 +91,8 @@ function printDropdownBookmarksList()
$newbtn = ''; $newbtn = '';
if ($user->hasRight('bookmark', 'creer')) { if ($user->hasRight('bookmark', 'creer')) {
if (!preg_match('/bookmarks\/card.php/', $_SERVER['PHP_SELF'])) { if (!preg_match('/bookmarks\/card.php/', $_SERVER['PHP_SELF'])) {
//$urltoadd=DOL_URL_ROOT.'/bookmarks/card.php?action=create&urlsource='.urlencode($url).'&url='.urlencode($url); //$urltoadd=DOL_URL_ROOT.'/bookmarks/card.php?action=create&url='.urlencode($url); // With & the GETPOST('url') will fail.
$urltoadd = DOL_URL_ROOT.'/bookmarks/card.php?action=create&url='.urlencode($url); $urltoadd = DOL_URL_ROOT.'/bookmarks/card.php?action=create&url='.urlencode($url);
$newbtn .= '<a class="top-menu-dropdown-link" title="'.$langs->trans('AddThisPageToBookmarks').'" href="'.dol_escape_htmltag($urltoadd).'" >'; $newbtn .= '<a class="top-menu-dropdown-link" title="'.$langs->trans('AddThisPageToBookmarks').'" href="'.dol_escape_htmltag($urltoadd).'" >';
$newbtn .= img_picto('', 'add', '', 0, 0, 0, '', 'pictofixedwidth paddingright').dol_escape_htmltag($langs->trans('AddThisPageToBookmarks')).'</a>'; $newbtn .= img_picto('', 'add', '', 0, 0, 0, '', 'pictofixedwidth paddingright').dol_escape_htmltag($langs->trans('AddThisPageToBookmarks')).'</a>';
} }

View File

@@ -1526,15 +1526,15 @@ class Categorie extends CommonObject
} }
if ($url == '') { if ($url == '') {
$link = '<a href="'.DOL_URL_ROOT.'/categories/viewcat.php?id='.$cat->id.'&type='.$cat->type.'" class="'.($i < count($way) ? 'small ': '').$forced_color.'">'; $link = '<a href="'.DOL_URL_ROOT.'/categories/viewcat.php?id='.((int) $cat->id).'&type='.urlencode($cat->type).'" class="'.($i < count($way) ? 'small ': '').$forced_color.'">';
$linkend = '</a>'; $linkend = '</a>';
$w[] = $link.(($addpicto && $i == 1) ? img_object('', 'category', 'class="paddingright"') : '').$cat->label.$linkend; $w[] = $link.(($addpicto && $i == 1) ? img_object('', 'category', 'class="paddingright"') : '').$cat->label.$linkend;
} elseif ($url == 'none') { } elseif ($url == 'none') {
$link = '<span class="'.$forced_color.'">'; $link = '<span class="'.($i < count($way) ? 'small ': '').$forced_color.'">';
$linkend = '</span>'; $linkend = '</span>';
$w[] = $link.(($addpicto && $i == 1) ? img_object('', 'category', 'class="paddingright"') : '').$cat->label.$linkend; $w[] = $link.(($addpicto && $i == 1) ? img_object('', 'category', 'class="paddingright"') : '').$cat->label.$linkend;
} else { } else {
$w[] = '<a class="'.$forced_color.'" href="'.DOL_URL_ROOT.'/'.$url.'?catid='.$cat->id.'">'.($addpicto ? img_object('', 'category') : '').$cat->label.'</a>'; $w[] = '<a class="'.($i < count($way) ? 'small ': '').$forced_color.'" href="'.DOL_URL_ROOT.'/'.$url.'?catid='.((int) $cat->id).'">'.($addpicto ? img_object('', 'category') : '').$cat->label.'</a>';
} }
} }
$newcategwithpath = preg_replace('/colortoreplace/', $forced_color, implode('<span class="inline-block valignmiddle paddingleft paddingright '.$forced_color.'">'.$sep.'</span>', $w)); $newcategwithpath = preg_replace('/colortoreplace/', $forced_color, implode('<span class="inline-block valignmiddle paddingleft paddingright '.$forced_color.'">'.$sep.'</span>', $w));

View File

@@ -6941,7 +6941,7 @@ class Form
* Else, default proposed VAT==0. End of rule. * Else, default proposed VAT==0. End of rule.
* @param bool $options_only Return HTML options lines only (for ajax treatment) * @param bool $options_only Return HTML options lines only (for ajax treatment)
* @param int<-1,1> $mode 0=Use vat rate as key in combo list, 1=Add VAT code after vat rate into key, -1=Use id of vat line as key * @param int<-1,1> $mode 0=Use vat rate as key in combo list, 1=Add VAT code after vat rate into key, -1=Use id of vat line as key
* @param int<0,2> $type_vat 0=All type, 1=VAT rate sale, 2=VAT rate purchase * @param int<0,2> $type_vat 0=All types, 1=VAT rate for sales, 2=VAT rate for purchases
* @return string * @return string
*/ */
public function load_tva($htmlname = 'tauxtva', $selectedrate = '', $societe_vendeuse = null, $societe_acheteuse = null, $idprod = 0, $info_bits = 0, $type = '', $options_only = false, $mode = 0, $type_vat = 0) public function load_tva($htmlname = 'tauxtva', $selectedrate = '', $societe_vendeuse = null, $societe_acheteuse = null, $idprod = 0, $info_bits = 0, $type = '', $options_only = false, $mode = 0, $type_vat = 0)
@@ -7056,12 +7056,14 @@ class Form
$num = count($arrayofvatrates); $num = count($arrayofvatrates);
if ($num > 0) { if ($num > 0) {
// Define vat rate to pre-select (if defaulttx not forced and so is -1 or '') // Define the vat rate to pre-select (if defaulttx not forced so is -1 or '')
if (($defaulttx < 0 || dol_strlen($defaulttx) == 0) && is_object($societe_vendeuse)) { if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
// Define a default thirdparty to use if the seller or buyer is not defined
$tmpthirdparty = new Societe($this->db); $tmpthirdparty = new Societe($this->db);
$tmpthirdparty->country_code = $mysoc->country_code;
$defaulttx = get_default_tva($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod); $defaulttx = get_default_tva(is_object($societe_vendeuse) ? $societe_vendeuse : $tmpthirdparty, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
$defaultnpr = get_default_npr($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod); $defaultnpr = get_default_npr(is_object($societe_vendeuse) ? $societe_vendeuse : $tmpthirdparty, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
if (preg_match('/\((.*)\)/', $defaulttx, $reg)) { if (preg_match('/\((.*)\)/', $defaulttx, $reg)) {
$defaultcode = $reg[1]; $defaultcode = $reg[1];
@@ -9600,7 +9602,7 @@ class Form
* *
* @param int $id Id of object * @param int $id Id of object
* @param string $type Type of category ('member', 'customer', 'supplier', 'product', 'contact'). Old mode (0, 1, 2, ...) is deprecated. * @param string $type Type of category ('member', 'customer', 'supplier', 'product', 'contact'). Old mode (0, 1, 2, ...) is deprecated.
* @param int<0,1> $rendermode 0=Default, use multiselect. 1=Emulate multiselect (recommended) * @param int<0,1> $rendermode 0=Default, use multiselect (deprecated). 1=Emulate multiselect (recommended)
* @param int<0,1> $nolink 1=Do not add html links * @param int<0,1> $nolink 1=Do not add html links
* @return string String with categories * @return string String with categories
*/ */

View File

@@ -2004,7 +2004,7 @@ function dol_add_file_process($upload_dir, $allowoverwrite = 0, $updatesessionor
// Move file from temp directory to final directory. A .noexe may also be appended on file name. // Move file from temp directory to final directory. A .noexe may also be appended on file name.
$resupload = dol_move_uploaded_file($TFile['tmp_name'][$i], $destfull, $allowoverwrite, 0, $TFile['error'][$i], 0, $varfiles, $upload_dir); $resupload = dol_move_uploaded_file($TFile['tmp_name'][$i], $destfull, $allowoverwrite, 0, $TFile['error'][$i], 0, $varfiles, $upload_dir);
if (is_numeric($resupload) && $resupload > 0) { // $resupload can be 'ErrorFileAlreadyExists' if (is_numeric($resupload) && $resupload > 0) { // $resupload can be 'ErrorFileAlreadyExists', 'ErrorFileIsInfectedWithAVirus...'
include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php'; include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
$tmparraysize = getDefaultImageSizes(); $tmparraysize = getDefaultImageSizes();
@@ -2068,7 +2068,7 @@ function dol_add_file_process($upload_dir, $allowoverwrite = 0, $updatesessionor
if (preg_match('/File is a PDF with javascript inside/', $resupload)) { if (preg_match('/File is a PDF with javascript inside/', $resupload)) {
setEventMessages($langs->trans("ErrorFileIsAnInfectedPDFWithJSInside"), null, 'errors'); setEventMessages($langs->trans("ErrorFileIsAnInfectedPDFWithJSInside"), null, 'errors');
} else { } else {
setEventMessages($langs->trans("ErrorFileIsInfectedWithAVirus"), null, 'errors'); setEventMessages($langs->trans("ErrorFileIsInfectedWithAVirus").'<br>'.dolGetFirstLineOfText($resupload), null, 'errors');
} }
} else { // Known error } else { // Known error
setEventMessages($langs->trans($resupload), null, 'errors'); setEventMessages($langs->trans($resupload), null, 'errors');

View File

@@ -286,12 +286,12 @@ function dolWebsiteOutput($content, $contenttype = 'html', $containerid = 0)
global $db, $langs, $conf, $user; global $db, $langs, $conf, $user;
global $dolibarr_main_url_root, $dolibarr_main_data_root; global $dolibarr_main_url_root, $dolibarr_main_data_root;
global $website; global $website;
global $includehtmlcontentopened; global $includehtmlcontentopened; // $includehtmlcontentopened is the level of includes (start at 0 for main page, 1 for first level include, ...)
'@phan-var-force Website $website'; '@phan-var-force Website $website';
$nbrep = 0; $nbrep = 0;
dol_syslog("dolWebsiteOutput start - contenttype=".$contenttype." containerid=".$containerid." USEDOLIBARREDITOR=".(defined('USEDOLIBARREDITOR') ? '1' : '')." USEDOLIBARRSERVER=".(defined('USEDOLIBARRSERVER') ? '1' : '').' includehtmlcontentopened='.$includehtmlcontentopened); dol_syslog("dolWebsiteOutput start - contenttype=".$contenttype." containerid=".$containerid.(defined('USEDOLIBARREDITOR') ? ' USEDOLIBARREDITOR=1' : '').(defined('USEDOLIBARRSERVER') ? ' USEDOLIBARRSERVER=1' : '').' includehtmlcontentopened='.$includehtmlcontentopened);
//print $containerid.' '.$content; //print $containerid.' '.$content;
@@ -1573,9 +1573,15 @@ function getAllImages($object, $objectpage, $urltograb, &$tmp, &$action, $modify
dol_mkdir(dirname($filetosave)); dol_mkdir(dirname($filetosave));
$fp = fopen($filetosave, "w"); $fp = fopen($filetosave, "w");
if ($fp) {
fwrite($fp, $tmpgeturl['content']); fwrite($fp, $tmpgeturl['content']);
fclose($fp); fclose($fp);
dolChmod($filetosave); dolChmod($filetosave);
} else {
$error++;
setEventMessages('Error failed to open file '.$filetosave.' for writing', null, 'errors');
$action = 'create';
}
} }
} }
} }

View File

@@ -186,6 +186,9 @@ function dolSavePageContent($filetpl, Website $object, WebsitePage $objectpage,
$tplcontent .= "} // Not already loaded\n"; $tplcontent .= "} // Not already loaded\n";
$tplcontent .= "require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';\n"; $tplcontent .= "require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';\n";
$tplcontent .= "require_once DOL_DOCUMENT_ROOT.'/core/website.inc.php';\n"; $tplcontent .= "require_once DOL_DOCUMENT_ROOT.'/core/website.inc.php';\n";
if (in_array($objectpage->type_container, array('page', 'blogpost'))) {
$tplcontent .= 'dol_syslog("--- Prepare content of page '.((int) $objectpage->id).' - '.$objectpage->pageurl.'");'."\n";
}
$tplcontent .= "ob_start();\n"; $tplcontent .= "ob_start();\n";
$tplcontent .= "try {\n"; $tplcontent .= "try {\n";
$tplcontent .= "// END PHP ?>\n"; $tplcontent .= "// END PHP ?>\n";
@@ -375,6 +378,9 @@ function dolSavePageContent($filetpl, Website $object, WebsitePage $objectpage,
$tplcontent .= "} // Not already loaded\n"; $tplcontent .= "} // Not already loaded\n";
$tplcontent .= "require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';\n"; $tplcontent .= "require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';\n";
$tplcontent .= "require_once DOL_DOCUMENT_ROOT.'/core/website.inc.php';\n"; $tplcontent .= "require_once DOL_DOCUMENT_ROOT.'/core/website.inc.php';\n";
if (in_array($objectpage->type_container, array('page', 'blogpost'))) {
$tplcontent .= 'dol_syslog("--- Prepare content of page '.((int) $objectpage->id).' - '.$objectpage->pageurl.'");'."\n";
}
$tplcontent .= "// END PHP ?>\n"; $tplcontent .= "// END PHP ?>\n";
$tplcontent .= $objectpage->content; $tplcontent .= $objectpage->content;

View File

@@ -92,6 +92,7 @@ class mod_member_simple extends ModeleNumRefMembers
$sql = "SELECT MAX(CAST(ref AS SIGNED)) as max"; $sql = "SELECT MAX(CAST(ref AS SIGNED)) as max";
$sql .= " FROM ".MAIN_DB_PREFIX."adherent"; $sql .= " FROM ".MAIN_DB_PREFIX."adherent";
$sql .= " WHERE entity = ".$conf->entity; $sql .= " WHERE entity = ".$conf->entity;
$resql = $db->query($sql); $resql = $db->query($sql);
if ($resql) { if ($resql) {
$row = $db->fetch_row($resql); $row = $db->fetch_row($resql);
@@ -125,6 +126,7 @@ class mod_member_simple extends ModeleNumRefMembers
$sql = "SELECT MAX(CAST(ref AS SIGNED)) as max"; $sql = "SELECT MAX(CAST(ref AS SIGNED)) as max";
$sql .= " FROM ".MAIN_DB_PREFIX."adherent"; $sql .= " FROM ".MAIN_DB_PREFIX."adherent";
$sql .= " WHERE entity = ".(int) $conf->entity; $sql .= " WHERE entity = ".(int) $conf->entity;
$sql .= " AND ref <> '(PROV)'";
$resql = $db->query($sql); $resql = $db->query($sql);
if ($resql) { if ($resql) {

View File

@@ -1,11 +1,9 @@
<?php <?php
/* Copyright (C) 2014-2016 Jean-François Ferry <hello@librethic.io>
/*
* Copyright (C) 2014-2016 Jean-François Ferry <hello@librethic.io>
* Copyright (C) 2016 Christophe Battarel <christophe@altairis.fr> * Copyright (C) 2016 Christophe Battarel <christophe@altairis.fr>
* Copyright (C) 2023 Benjamin Falière <benjamin.faliere@altairis.fr>
* Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com> * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2025 Frédéric France <frederic.france@free.fr> * Copyright (C) 2025 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2023-2025 Benjamin Falière <benjamin@faliere.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -502,10 +500,13 @@ class InterfaceTicketEmail extends DolibarrTriggers
} }
$message_customer .= '<p>'.$langs->trans('Message').' : <br><br>'.$message.'</p><br>'; $message_customer .= '<p>'.$langs->trans('Message').' : <br><br>'.$message.'</p><br>';
$url_public_ticket = getDolGlobalString('TICKET_URL_PUBLIC_INTERFACE', dol_buildpath('/public/ticket/', 2)).'view.php?track_id='.$object->track_id; if (getDolGlobalInt('TICKET_ENABLE_PUBLIC_INTERFACE')) {
$url_public_ticket = getDolGlobalString('TICKET_URL_PUBLIC_INTERFACE', dol_buildpath('/public/ticket/', 2)).'view.php?track_id='.((int) $object->track_id);
$message_customer .= '<p>'.$langs->trans($see_ticket).' : <a href="'.$url_public_ticket.'">'.$url_public_ticket.'</a></p>'; $message_customer .= '<p>'.$langs->trans($see_ticket).' : <a href="'.$url_public_ticket.'">'.$url_public_ticket.'</a></p>';
$message_customer .= '<p>'.$langs->trans('TicketEmailPleaseDoNotReplyToThisEmail').'</p>'; $message_customer .= '<p>'.$langs->trans('TicketEmailPleaseDoNotReplyToThisEmail').'</p>';
} else {
$message_customer .= '<p>'.$langs->trans('TicketEmailPleaseDoNotReplyToThisEmailNoInterface').'</p>';
}
$from = (getDolGlobalString('MAIN_INFO_SOCIETE_NOM') ? getDolGlobalString('MAIN_INFO_SOCIETE_NOM') . ' ' : '').'<' . getDolGlobalString('TICKET_NOTIFICATION_EMAIL_FROM').'>'; $from = (getDolGlobalString('MAIN_INFO_SOCIETE_NOM') ? getDolGlobalString('MAIN_INFO_SOCIETE_NOM') . ' ' : '').'<' . getDolGlobalString('TICKET_NOTIFICATION_EMAIL_FROM').'>';

View File

@@ -474,10 +474,15 @@ if (empty($reshook)) {
setEventMessages($mesg, null, 'mesgs'); setEventMessages($mesg, null, 'mesgs');
} else { } else {
$langs->load("other"); $langs->load("other");
if ($mailfile->error) { if (!empty($mailfile->error) || !empty($mailfile->errors)) {
$mesg = ''; $mesg = '';
$mesg .= $langs->trans('ErrorFailedToSendMail', $emailFrom, $emailTo); $mesg .= $langs->transnoentities('ErrorFailedToSendMail', dol_escape_htmltag($emailFrom), dol_escape_htmltag($emailTo));
$mesg .= '<br>'.$mailfile->error; if (!empty($mailfile->error)) {
$mesg .= '<br>' . $mailfile->error;
}
if (!empty($mailfile->errors) && is_array($mailfile->errors)) {
$mesg .= '<br>' . implode('<br>', $mailfile->errors);
}
setEventMessages($mesg, null, 'errors'); setEventMessages($mesg, null, 'errors');
} else { } else {
setEventMessages('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', null, 'warnings'); setEventMessages('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', null, 'warnings');
@@ -1553,7 +1558,7 @@ if ($action == 'create') {
print $form->buttonsSaveCancel("AddTrip"); print $form->buttonsSaveCancel("AddTrip");
print '</form>'; print '</form>';
} elseif ($id > 0 || $ref) { } elseif ($object->id > 0) {
$userauthor = null; $userauthor = null;
$result = $object->fetch($id, $ref); $result = $object->fetch($id, $ref);
@@ -2608,12 +2613,12 @@ if ($action == 'create') {
// Select VAT // Select VAT
print '<td class="right inputvat">'; print '<td class="right inputvat">';
$defaultvat = -1; $defaultvat = '';
if (getDolGlobalString('EXPENSEREPORT_NO_DEFAULT_VAT')) { if (getDolGlobalString('EXPENSEREPORT_NO_DEFAULT_VAT')) {
// If option to have no default VAT on expense report is on, we force MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS // If option to have no default VAT on expense report is on, we force MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS
$conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS = 'none'; $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS = 'none';
} }
print $form->load_tva('vatrate', (!empty($vatrate) ? $vatrate : $defaultvat), $mysoc, null, 0, 0, '', false, 1); print $form->load_tva('vatrate', (!empty($vatrate) ? $vatrate : $defaultvat), null, null, 0, 0, '', false, 1);
print '</td>'; print '</td>';
// Unit price net // Unit price net

View File

@@ -285,6 +285,7 @@ TicketNewEmailBodyInfosTrackUrl=You can view the progress of the ticket by click
TicketNewEmailBodyInfosTrackUrlCustomer=You can view the progress of the ticket in the public ticket portal by clicking the following link TicketNewEmailBodyInfosTrackUrlCustomer=You can view the progress of the ticket in the public ticket portal by clicking the following link
TicketCloseEmailBodyInfosTrackUrlCustomer=You can consult the history of this ticket by clicking the following link TicketCloseEmailBodyInfosTrackUrlCustomer=You can consult the history of this ticket by clicking the following link
TicketEmailPleaseDoNotReplyToThisEmail=Please do not reply directly to this email! Use the link to reply into the interface. TicketEmailPleaseDoNotReplyToThisEmail=Please do not reply directly to this email! Use the link to reply into the interface.
TicketEmailPleaseDoNotReplyToThisEmailNoInterface=Please do not reply directly to this email!
TicketPublicInfoCreateTicket=This form allows you to record a support ticket in our management system. TicketPublicInfoCreateTicket=This form allows you to record a support ticket in our management system.
TicketPublicPleaseBeAccuratelyDescribe=Please accurately describe your request. Provide the most information possible to allow us to correctly identify your request. TicketPublicPleaseBeAccuratelyDescribe=Please accurately describe your request. Provide the most information possible to allow us to correctly identify your request.
TicketPublicMsgViewLogIn=Please enter ticket tracking ID TicketPublicMsgViewLogIn=Please enter ticket tracking ID

View File

@@ -265,6 +265,7 @@ TicketLogAssignedTo=Ticket %s assigné à %s
TicketLogPropertyChanged=Ticket %s modifié: classification de %s à %s TicketLogPropertyChanged=Ticket %s modifié: classification de %s à %s
TicketLogClosedBy=Ticket %s clôt par %s TicketLogClosedBy=Ticket %s clôt par %s
TicketLogReopen=Ticket %s ré-ouvert TicketLogReopen=Ticket %s ré-ouvert
# Public pages # Public pages
TicketSystem=Gestionnaire de tickets TicketSystem=Gestionnaire de tickets
ShowListTicketWithTrackId=Afficher la liste des tickets à partir de l'ID de suivi ShowListTicketWithTrackId=Afficher la liste des tickets à partir de l'ID de suivi
@@ -283,6 +284,7 @@ TicketNewEmailBodyInfosTrackUrl=Vous pouvez voir la progression du ticket en cli
TicketNewEmailBodyInfosTrackUrlCustomer=Vous pouvez visualiser la progression du ticket dans l'interface publique en cliquant sur le lien suivant TicketNewEmailBodyInfosTrackUrlCustomer=Vous pouvez visualiser la progression du ticket dans l'interface publique en cliquant sur le lien suivant
TicketCloseEmailBodyInfosTrackUrlCustomer=Vous pouvez consulter l'historique de ce ticket en cliquant sur le lien suivant TicketCloseEmailBodyInfosTrackUrlCustomer=Vous pouvez consulter l'historique de ce ticket en cliquant sur le lien suivant
TicketEmailPleaseDoNotReplyToThisEmail=Merci de ne pas répondre directement à ce courriel ! Utilisez le lien pour répondre via l'interface. TicketEmailPleaseDoNotReplyToThisEmail=Merci de ne pas répondre directement à ce courriel ! Utilisez le lien pour répondre via l'interface.
TicketEmailPleaseDoNotReplyToThisEmailNoInterface=Merci de ne pas répondre directement à ce courriel !
TicketPublicInfoCreateTicket=Ce formulaire vous permet d'enregistrer un ticket dans notre système de gestion. TicketPublicInfoCreateTicket=Ce formulaire vous permet d'enregistrer un ticket dans notre système de gestion.
TicketPublicPleaseBeAccuratelyDescribe=Veuillez décrire précisément votre question. Fournissez le plus d'informations possible pour nous permettre d'identifier correctement votre demande. TicketPublicPleaseBeAccuratelyDescribe=Veuillez décrire précisément votre question. Fournissez le plus d'informations possible pour nous permettre d'identifier correctement votre demande.
TicketPublicMsgViewLogIn=Merci d'entrer le code de suivi du ticket TicketPublicMsgViewLogIn=Merci d'entrer le code de suivi du ticket