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 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.
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 size for VCF files and virtualcard qrcode

View File

@@ -91,8 +91,8 @@ function printDropdownBookmarksList()
$newbtn = '';
if ($user->hasRight('bookmark', 'creer')) {
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);
//$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);
$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>';
}

View File

@@ -1526,15 +1526,15 @@ class Categorie extends CommonObject
}
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>';
$w[] = $link.(($addpicto && $i == 1) ? img_object('', 'category', 'class="paddingright"') : '').$cat->label.$linkend;
} elseif ($url == 'none') {
$link = '<span class="'.$forced_color.'">';
$link = '<span class="'.($i < count($way) ? 'small ': '').$forced_color.'">';
$linkend = '</span>';
$w[] = $link.(($addpicto && $i == 1) ? img_object('', 'category', 'class="paddingright"') : '').$cat->label.$linkend;
} 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));

View File

@@ -6941,7 +6941,7 @@ class Form
* Else, default proposed VAT==0. End of rule.
* @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<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
*/
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);
if ($num > 0) {
// Define vat rate to pre-select (if defaulttx not forced and so is -1 or '')
if (($defaulttx < 0 || dol_strlen($defaulttx) == 0) && is_object($societe_vendeuse)) {
// Define the vat rate to pre-select (if defaulttx not forced so is -1 or '')
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->country_code = $mysoc->country_code;
$defaulttx = get_default_tva($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
$defaultnpr = get_default_npr($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(is_object($societe_vendeuse) ? $societe_vendeuse : $tmpthirdparty, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
if (preg_match('/\((.*)\)/', $defaulttx, $reg)) {
$defaultcode = $reg[1];
@@ -9600,7 +9602,7 @@ class Form
*
* @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 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
* @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.
$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';
$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)) {
setEventMessages($langs->trans("ErrorFileIsAnInfectedPDFWithJSInside"), null, 'errors');
} else {
setEventMessages($langs->trans("ErrorFileIsInfectedWithAVirus"), null, 'errors');
setEventMessages($langs->trans("ErrorFileIsInfectedWithAVirus").'<br>'.dolGetFirstLineOfText($resupload), null, 'errors');
}
} else { // Known error
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 $dolibarr_main_url_root, $dolibarr_main_data_root;
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';
$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;
@@ -1573,9 +1573,15 @@ function getAllImages($object, $objectpage, $urltograb, &$tmp, &$action, $modify
dol_mkdir(dirname($filetosave));
$fp = fopen($filetosave, "w");
fwrite($fp, $tmpgeturl['content']);
fclose($fp);
dolChmod($filetosave);
if ($fp) {
fwrite($fp, $tmpgeturl['content']);
fclose($fp);
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 .= "require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.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 .= "try {\n";
$tplcontent .= "// END PHP ?>\n";
@@ -375,6 +378,9 @@ function dolSavePageContent($filetpl, Website $object, WebsitePage $objectpage,
$tplcontent .= "} // Not already loaded\n";
$tplcontent .= "require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.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 .= $objectpage->content;

View File

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

View File

@@ -1,11 +1,9 @@
<?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) 2023 Benjamin Falière <benjamin.faliere@altairis.fr>
* Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
* 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
* 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>';
$url_public_ticket = getDolGlobalString('TICKET_URL_PUBLIC_INTERFACE', dol_buildpath('/public/ticket/', 2)).'view.php?track_id='.$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('TicketEmailPleaseDoNotReplyToThisEmail').'</p>';
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('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').'>';

View File

@@ -474,10 +474,15 @@ if (empty($reshook)) {
setEventMessages($mesg, null, 'mesgs');
} else {
$langs->load("other");
if ($mailfile->error) {
if (!empty($mailfile->error) || !empty($mailfile->errors)) {
$mesg = '';
$mesg .= $langs->trans('ErrorFailedToSendMail', $emailFrom, $emailTo);
$mesg .= '<br>'.$mailfile->error;
$mesg .= $langs->transnoentities('ErrorFailedToSendMail', dol_escape_htmltag($emailFrom), dol_escape_htmltag($emailTo));
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');
} else {
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>';
} elseif ($id > 0 || $ref) {
} elseif ($object->id > 0) {
$userauthor = null;
$result = $object->fetch($id, $ref);
@@ -2608,12 +2613,12 @@ if ($action == 'create') {
// Select VAT
print '<td class="right inputvat">';
$defaultvat = -1;
$defaultvat = '';
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
$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>';
// 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
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.
TicketEmailPleaseDoNotReplyToThisEmailNoInterface=Please do not reply directly to this email!
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.
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
TicketLogClosedBy=Ticket %s clôt par %s
TicketLogReopen=Ticket %s ré-ouvert
# Public pages
TicketSystem=Gestionnaire de tickets
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
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.
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.
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