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

This commit is contained in:
ldestailleur 2025-07-22 13:00:31 +02:00
commit b710c85b07
12 changed files with 181 additions and 68 deletions

View file

@ -85,9 +85,6 @@ before_install:
if [ "$TRAVIS_PHP_VERSION" = '7.1' ]; then
sudo apt install unzip apache2 php7.1 php7.1-cli php7.1-curl php7.1-mysql php7.1-pgsql php7.1-gd php7.1-imap php7.1-intl php7.1-ldap php7.1-xml php7.1-mbstring php7.1-xml php7.1-zip libapache2-mod-php7.1
fi
if [ "$TRAVIS_PHP_VERSION" = '7.1' ]; then
sudo apt install unzip apache2 php7.1 php7.1-cli php7.1-curl php7.1-mysql php7.1-pgsql php7.1-gd php7.1-imap php7.1-intl php7.1-ldap php7.1-xml php7.1-mbstring php7.1-xml php7.1-zip libapache2-mod-php7.1
fi
if [ "$TRAVIS_PHP_VERSION" = '8.1' ]; then
sudo apt install unzip apache2 php8.1 php8.1-cli php8.1-curl php8.1-mysql php8.1-pgsql php8.1-gd php8.1-imap php8.1-intl php8.1-ldap php8.1-xml php8.1-mbstring php8.1-xml php8.1-zip libapache2-mod-php8.1
fi

109
ChangeLog
View file

@ -161,6 +161,115 @@ The following changes may create regressions for some external modules, but were
* Debug v22 - Invert option TICKET_DO_NOT_INCLUDE_LINK_TO_CUSTOMER (that add link to backoffice interface link when it should remain private)
into TICKET_INCLUDE_LINK_TO_PUBLIC_INTERFACE_IN_MESSAGE. It also avoid often emails marked as SPAM due to suspicious link.
***** ChangeLog for 21.0.2 compared to 21.0.1 *****
FIX: 21.0: $height and $width can be ints, but also 'auto' (#34636)
FIX: #33030 (#34460)
FIX: #33727 Sec
FIX: #33774 #34214
FIX: #33854
FIX: #34313 Accountancy - Export with sources no longer works (#34324)
FIX: (#34448)
FIX: #34541 (#34597)
FIX: #34564 (#34590)
FIX: #34591 FIX: #34692
FIX: #34618 (#34621)
FIX: #34654
FIX: accountancy: bad filter on custom account groups (#34205)
FIX: accountancy balance: keep subtotals when sorting (#34001)
FIX: accountancy closure: if subledger_label is not found, PHP8.2 throws an error. (#34736)
FIX: accountancy: create new french PCG25-DEV accounting system in upgrade (#34036)
FIX: accountancy expensereport journal: php 8.1 warning (#34457)
FIX: accountancy fec export: remove dol_print_date warning (#34363)
FIX: accountancy general ledger: last total not shown if last account group shown has only one entry (#34251)
FIX: accountancy lettering: php8.1 warning (#34469)
FIX: Accountancy - Problem with constant ACCOUNTANCY_COMBO_FOR_AUX (#34414)
FIX: accountancy sales/purchases journal: sql error logged when no invoice in journal (#34339)
FIX: accountancy: warning when account not found in plan (#34030)
FIX: a comment without after a comma create a sql error (#33752)
FIX: Add others allowed tags (table, tr, td) for the prices history table displayed in the link url of the supplier product in supplier product prices list (#34532)
FIX: add payment to bank (#34263)
FIX: allow double colon and string obfuscation in dol eval for computed extra fields (#34015)
FIX: API expense report line comments (v18+) (#34297)
FIX: Approver must be able to approve even if user not in hierarchy.
FIX: asset depreciation: division by zero (#34218)
FIX: asset depreciation: php warnings (#34219)
FIX: avoid sql error when a comment is after without comma (#33758)
FIX: Backport fix of substitution of thirdparty info in notification
FIX: backport of replaceement of thirdparty information on notification
FIX: bad value for company ref crashes canvas feature (#34331)
FIX: bank payment rejection on SEPA (backport commit 100a657) (#33838)
FIX: BankTransfer information in line.php (#34425)
FIX: BankTransfer link in list.php (#34513)
FIX: BankTransfer link in rejets.php (#34424)
FIX: Bug filters (#34546)
FIX: Can set default value of the nature of member
FIX: Can set the default value of nature of thirdparty
FIX: cash control report: php warning (#34358)
FIX: common fields: php warning with select input field (#34495)
FIX: constant PAYMENTBYBANKTRANSFER_ADDDAYS was never saved (#33799)
FIX: creating acredit note from the remain to pay was always 0
FIX: DetecHTML on upload file from filemanager fails due to need to lock
FIX: Disallow special char in name of oauth entries
FIX: do not add a filter on status when doing a global search on project
FIX: Do not allow to force amount for online payment of order
FIX: do not forget extrafields for BOM in export lines (#34020)
FIX: Edition of target of menu entries
FIX: element must be visible to set focus on select input when using default values (#34406)
FIX: email collector: php 8 warning (#34496)
FIX: encoding issues with underscores in mb_convert_encoding functionality (#34411)
FIX: ensure dir exists before trying to move something in it (#34211)
FIX: event info tab: php 8.1 warning (#34458)
FIX: expense report card: mail notifications not sent (#34556)
FIX: expensereport payment list: php warning (#34453)
FIX: expensereport: php warning when generating pdf with multilangs (#34492)
FIX: files lib: multiple php 8.1 warnings (#34462)
FIX: filter agenda on user and resource SQL error (#34580)
FIX: HTML broken by the trunc.
FIX: html title when using custom value
FIX: if filter is set on export for Duree type filed, then there is SQL error (#34616)
FIX: interventions: sql error when signed_status not set (#34515)
FIX: js warning (Backport commit 84d982c) (#34555)
FIX: local taxes text in object line view mode (#34103)
FIX: local taxes text in PDF (#34343)
FIX: mandatory extrafelds on lines are not checked (#34228)
FIX: manufacturing orders: php 8.1 warnings on agenda tab (#34475)
FIX: mass assignment of sale representative
FIX: Missing ol in no escape tags (#34261)
FIX: modification de dates de pièces comptables sur plusieurs entités différentes (#34226)
FIX: oauth: php 8 warnings (#34027)
FIX: online propal sign: double header with logo when custom logo set (#34504)
FIX: Order error translation (#33834)
FIX: page of bom when only bom module is on
FIX: partial result on timespent list (#33855)
FIX: pgsql: boolean fields correctly defined in creation but not in migration (#34215)
FIX: pgsql: case sensitivity in select queries (#34028)
FIX: pgsql: error when creating sequences in migration scripts (#34021)
FIX: PHP 8 Error 500 (#34545)
FIX: prelevement order list: handle case of use by banktransfer module (#33801)
FIX: pre-send mail mass action: keep __EMAIL__ substitution (#34522)
FIX: prevent log warning with online signature url (#34361)
FIX: Product batch series - Title, help url et picto (#34560)
FIX: product multiprices: fatal error on vat update on php 8.2 (#34444)
FIX: product suplier tab: last modif date column was wrongly dependent of module barcode (#34170)
FIX: product translation: redirect after successful action (#34403)
FIX: projects: go back to edit view after cloning (#34221)
FIX: receptions: crash from api because of classes not found (#34523)
FIX: Remove useless amp; after & (#34288)
FIX: select supplier when creating object from project (#33766)
FIX: social contribution payment: correct error reporting (#34002)
FIX: stock control condition in reception delete (#33952)
FIX: Tmparray string not array (#34287)
FIX: Too heavy sql query (#34371)
FIX: try to fix v18 github action workflow (#34439)
FIX: Various payment - List - Can't see payment with subledger account (#34101)
FIX: warehouse list: broken status filter (#33667)
FIX: warnings when printing start/end date on line tpl (#34359)
FIX: wrong multicompany filter (#34714)
FIX: ws detection
***** ChangeLog for 21.0.1 compared to 21.0.0 *****
FIX: #33360

View file

@ -214,19 +214,6 @@ print '<input class="flat right width50" name="MAIN_SECURITY_MAX_NUMBER_FAILED_A
print '</td>';
print '</tr>';
/*
if (empty($conf->global->MAIN_APPLICATION_TITLE)) {
$conf->global->MAIN_APPLICATION_TITLE = "";
}
print '<tr class="oddeven">';
print '<td>'.$langs->trans("MAIN_APPLICATION_TITLE").'</td><td class="right">';
print '</td>';
print '<td class="nowrap">';
print '<input class="flat" name="MAIN_APPLICATION_TITLE" type="text" size="20" value="'.dol_escape_htmltag($conf->global->MAIN_APPLICATION_TITLE).'"> ';
print '</td>';
print '</tr>';
*/
print '</table>';
print $form->buttonsSaveCancel("Modify", '');

View file

@ -1829,9 +1829,12 @@ class Commande extends CommonOrder
$this->line_order(true, 'DESC');
} elseif ($ranktouse > 0 && $ranktouse <= count($this->lines)) {
// Update all rank of all other lines starting from the same $ranktouse
$linecount = count($this->lines);
for ($ii = $ranktouse; $ii <= $linecount; $ii++) {
$this->updateRangOfLine($this->lines[$ii - 1]->id, $ii + 1);
foreach ($this->lines as $tmpline) {
if ($tmpline->rang >= $ranktouse) {
if (!empty($tmpline->id)) {
$this->updateRangOfLine($tmpline->id, $tmpline->rang + 1);
}
}
}
}

View file

@ -175,6 +175,7 @@ class Facture extends CommonInvoice
* @var int id of source invoice if replacement invoice or credit note
*/
public $fk_facture_source;
public $linked_objects = array();
/**
@ -1295,6 +1296,7 @@ class Facture extends CommonInvoice
$object->fk_user_author = $user->id;
$object->fk_user_valid = null;
$object->fk_facture_source = 0;
$object->fk_fac_rec_source = 0;
$object->date_creation = '';
$object->date_modification = '';
$object->date_validation = '';

View file

@ -662,10 +662,12 @@ class Notify
//$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
// Define some vars
$application = 'Dolibarr';
if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
$application = getDolGlobalString('MAIN_APPLICATION_TITLE');
$application = constant('DOL_APPLICATION_TITLE');
$applicationcustom = getDolGlobalString('MAIN_APPLICATION_TITLE');
if ($applicationcustom) {
$application = (preg_match('/^\+/', $applicationcustom) ? $application : '').$applicationcustom;
}
$from = getDolGlobalString('NOTIFICATION_EMAIL_FROM');
$object_type = '';
$link = '';

View file

@ -165,7 +165,7 @@ $arrayoftype = array(
'order' => array('langs' => 'orders', 'label' => 'Orders', 'picto' => 'order', 'ObjectClassName' => 'Commande', 'enabled' => isModEnabled('order'), 'ClassPath' => "/commande/class/commande.class.php"),
'orderdet' => array('langs' => 'orders', 'label' => 'SaleOrderLines', 'picto' => 'order', 'ObjectClassName' => 'OrderLine', 'enabled' => isModEnabled('order'), 'ClassPath' => "/commande/class/orderline.class.php"),
'invoice' => array('langs' => 'facture', 'label' => 'Invoices', 'picto' => 'bill', 'ObjectClassName' => 'Facture', 'enabled' => isModEnabled('invoice'), 'ClassPath' => "/compta/facture/class/facture.class.php"),
'invoice_template' => array('label' => 'PredefinedInvoices', 'picto' => 'bill', 'ObjectClassName' => 'FactureRec', 'enabled' => isModEnabled('invoice'), 'ClassPath' => "/compta/class/facturerec.class.php", 'langs' => 'bills'),
'invoice_template' => array('label' => 'PredefinedInvoices', 'picto' => 'bill', 'ObjectClassName' => 'FactureRec', 'enabled' => isModEnabled('invoice'), 'ClassPath' => "/compta/facture/class/facture-rec.class.php", 'langs' => 'bills'),
'contract' => array('langs' => 'contracts', 'label' => 'Contracts', 'picto' => 'contract', 'ObjectClassName' => 'Contrat', 'enabled' => isModEnabled('contract'), 'ClassPath' => "/contrat/class/contrat.class.php", 'langs' => 'contracts'),
'contractdet' => array('langs' => 'contracts', 'label' => 'ContractLines', 'picto' => 'contract', 'ObjectClassName' => 'ContratLigne', 'enabled' => isModEnabled('contract'), 'ClassPath' => "/contrat/class/contrat.class.php", 'langs' => 'contracts'),
'bom' => array('label' => 'BOM', 'picto' => 'bom', 'ObjectClassName' => 'Bom', 'enabled' => isModEnabled('bom')),
@ -357,6 +357,7 @@ if (!empty($object->element_for_permission)) {
$features .= (empty($object->module) ? '' : '@'.$object->module);
}
// Security check
restrictedArea($user, $features, 0, '');

View file

@ -152,8 +152,14 @@ if (!function_exists('dol_loginfunction')) {
// Title
$appli = constant('DOL_APPLICATION_TITLE');
$title = $appli.(getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') ? '' : ' '.constant('DOL_VERSION'));
if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
$title = getDolGlobalString('MAIN_APPLICATION_TITLE');
$customapplication = getDolGlobalString('MAIN_APPLICATION_TITLE');
if ($customapplication) {
if (preg_match('/^\+/', $customapplication)) {
$title .= $customapplication;
} else {
$title = $customapplication;
}
}
$titletruedolibarrversion = constant('DOL_VERSION'); // $title used by login template after the @ to inform of true Dolibarr version

View file

@ -148,12 +148,20 @@ $arrayofjs = array(
'/core/js/dst.js'.(empty($conf->dol_use_jmobile) ? '' : '?version='.urlencode(DOL_VERSION))
);
// We display application title instead Login term
if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
$titleofloginpage = getDolGlobalString('MAIN_APPLICATION_TITLE');
// We display application title
$application = constant('DOL_APPLICATION_TITLE');
$applicationcustom = getDolGlobalString('MAIN_APPLICATION_TITLE');
if ($applicationcustom) {
$application = (preg_match('/^\+/', $applicationcustom) ? $application : '').$applicationcustom;
}
// We define login title
if ($applicationcustom) {
$titleofloginpage = $langs->trans('Login').' '.$application;
} else {
$titleofloginpage = $langs->trans('Login');
}
// Title of HTML page must have pattern ' @ (?:Doli[a-zA-Z]+ |)(\\d+)\\.(\\d+)\\.([^\\s]+)' to be detected as THE login page by webviews.
$titleofloginpage .= ' @ '.$titletruedolibarrversion; // $titletruedolibarrversion is defined by dol_loginfunction in security2.lib.php. We must keep the @, some tools use it to know it is login page and find true dolibarr version.
$disablenofollow = 1;
@ -256,12 +264,12 @@ if (!getDolGlobalString('ADD_UNSPLASH_LOGIN_BACKGROUND')) {
<!-- Title with version -->
<div class="login_table_title center" tabindex="-1" title="<?php echo dol_escape_htmltag($title); ?>">
<div class="login_table_title center" tabindex="-1" title="<?php echo dolPrintHTMLForAttribute($title); ?>">
<?php
if ($disablenofollow) {
echo '<a class="login_table_title" tabindex="-1" href="https://www.dolibarr.org" target="_blank" rel="noopener noreferrer external">';
}
echo dol_escape_htmltag($title);
echo dolPrintHTML($title);
if ($disablenofollow) {
echo '</a>';
}

View file

@ -94,12 +94,17 @@ if (!isset($form) || !is_object($form)) {
$form = new Form($db);
}
// Title
$title = $langs->trans("HomeArea").' - Dolibarr '.DOL_VERSION;
if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
$title = $langs->trans("HomeArea").' - ' . getDolGlobalString('MAIN_APPLICATION_TITLE');
$appli = constant('DOL_APPLICATION_TITLE');
$applicustom = getDolGlobalString('MAIN_APPLICATION_TITLE');
if ($applicustom) {
$appli = (preg_match('/^\+/', $applicustom) ? $appli : '').$applicustom;
} else {
$appli .= " ".DOL_VERSION;
}
// Title
$title = $langs->trans("HomeArea").' - '.$appli;
llxHeader('', $title);

View file

@ -1653,8 +1653,9 @@ function top_htmlhead($head, $title = '', $disablejs = 0, $disablehead = 0, $arr
// Displays title
$appli = constant('DOL_APPLICATION_TITLE');
if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
$appli = getDolGlobalString('MAIN_APPLICATION_TITLE');
$applicustom = getDolGlobalString('MAIN_APPLICATION_TITLE');
if ($applicustom) {
$appli = (preg_match('/^\+/', $applicustom) ? $appli : '').$applicustom;
}
print '<title>';
@ -2058,15 +2059,9 @@ function top_menu($head, $title = '', $target = '', $disablejs = 0, $disablehead
// Define link to login card
$appli = constant('DOL_APPLICATION_TITLE');
if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
$appli = getDolGlobalString('MAIN_APPLICATION_TITLE');
if (preg_match('/\d\.\d/', $appli)) {
if (!preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) {
$appli .= " (".DOL_VERSION.")"; // If new title contains a version that is different than core
}
} else {
$appli .= " ".DOL_VERSION;
}
$applicustom = getDolGlobalString('MAIN_APPLICATION_TITLE');
if ($applicustom) {
$appli = (preg_match('/^\+/', $applicustom) ? $appli : '').$applicustom;
} else {
$appli .= " ".DOL_VERSION;
}
@ -2457,15 +2452,9 @@ function top_menu_user($hideloginname = 0, $urllogout = '')
// Define version to show
$appli = constant('DOL_APPLICATION_TITLE');
if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
$appli = getDolGlobalString('MAIN_APPLICATION_TITLE');
if (preg_match('/\d\.\d/', $appli)) {
if (!preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) {
$appli .= " (".DOL_VERSION.")"; // If new title contains a version that is different than core
}
} else {
$appli .= " ".DOL_VERSION;
}
$applicustom = getDolGlobalString('MAIN_APPLICATION_TITLE');
if ($applicustom) {
$appli = (preg_match('/^\+/', $applicustom) ? $appli : '').$applicustom;
} else {
$appli .= " ".DOL_VERSION;
}
@ -3326,19 +3315,18 @@ function left_menu($menu_array_before, $helppagename = '', $notused = '', $menu_
}
$appli = constant('DOL_APPLICATION_TITLE');
if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
$appli = getDolGlobalString('MAIN_APPLICATION_TITLE');
$doliurl = '';
if (preg_match('/\d\.\d/', $appli)) {
if (!preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) {
$appli .= " (".DOL_VERSION.")"; // If new title contains a version that is different than core
}
} else {
$appli .= " ".DOL_VERSION;
}
$applicustom = getDolGlobalString('MAIN_APPLICATION_TITLE');
if ($applicustom) {
$appli = (preg_match('/^\+/', $applicustom) ? $appli : '').$applicustom;
} else {
$appli .= " ".DOL_VERSION;
}
// Clean doliurl if we use a custom application name
if ($applicustom) {
$doliurl = '';
}
print '<div id="blockvmenuhelpapp" class="blockvmenuhelp">';
if ($doliurl) {
print '<a class="help" target="_blank" rel="noopener noreferrer" href="'.$doliurl.'">';

View file

@ -190,12 +190,17 @@ if (empty($reshook)) {
$dol_url_root = DOL_URL_ROOT;
// Title
$title = 'Dolibarr '.DOL_VERSION;
if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
$title = getDolGlobalString('MAIN_APPLICATION_TITLE');
$appli = constant('DOL_APPLICATION_TITLE');
$applicustom = getDolGlobalString('MAIN_APPLICATION_TITLE');
if ($applicustom) {
$appli = (preg_match('/^\+/', $applicustom) ? $appli : '').$applicustom;
} else {
$appli .= " ".DOL_VERSION;
}
// Title
$title = $appli; // $title is used in .tpl file
// Select templates dir
$template_dir = '';
if (!empty($conf->modules_parts['tpl'])) { // Using this feature slow down application