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

This commit is contained in:
Laurent Destailleur
2025-12-01 11:43:22 +01:00
48 changed files with 470 additions and 421 deletions

View File

@@ -5,7 +5,7 @@ This file contains some policies about the security reports on Dolibarr ERP CRM
## Supported Versions for security reports
Security report are valid only on current stable version (see https://dolibarr.org web site to get current stable version) or on development version (branch "develop" on https://github.com/Dolibarr/dolibarr).
Security report are valid only on any current stable version for the last 5 major versions (see https://dolibarr.org web site to get current stable version) or on development version (branch "develop" on https://github.com/Dolibarr/dolibarr).
## Reporting a Vulnerability

View File

@@ -1038,18 +1038,6 @@ parameters:
count: 1
path: ../../../htdocs/admin/website.php
-
message: '#^Parameter \#1 \$array of function dol_sort_array contains unresolvable type\.$#'
identifier: argument.unresolvableType
count: 1
path: ../../../htdocs/admin/workflow.php
-
message: '#^Return type of call to function dol_sort_array contains unresolvable type\.$#'
identifier: function.unresolvableReturnType
count: 1
path: ../../../htdocs/admin/workflow.php
-
message: '#^Loose comparison using \=\= between ''edit'' and ''edit'' will always evaluate to true\.$#'
identifier: equal.alwaysTrue
@@ -1590,30 +1578,6 @@ parameters:
count: 1
path: ../../../htdocs/categories/categorie_list.php
-
message: '#^Method Categorie\:\:get_full_arbo\(\) should return \-1\|array\<int, array\{rowid\: int, id\: int, fk_parent\: int, label\: string, description\: string, color\: string, position\: string, visible\: int, \.\.\.\}\> but returns array\<array\{rowid\: mixed, id\: mixed, fk_parent\: mixed, label\: mixed, description\: mixed, color\: mixed, position\: mixed, visible\: mixed, \.\.\.\}\>\.$#'
identifier: return.type
count: 1
path: ../../../htdocs/categories/class/categorie.class.php
-
message: '#^Parameter \#1 \$array of function dol_sort_array contains unresolvable type\.$#'
identifier: argument.unresolvableType
count: 1
path: ../../../htdocs/categories/class/categorie.class.php
-
message: '#^Property Categorie\:\:\$cats \(array\<int, array\{rowid\: int, id\: int, fk_parent\: int, label\: string, description\: string, color\: string, position\: string, visible\: int, \.\.\.\}\>\) does not accept array\<array\{rowid\: mixed, id\: mixed, fk_parent\: mixed, label\: mixed, description\: mixed, color\: mixed, position\: mixed, visible\: mixed, \.\.\.\}\>\.$#'
identifier: assign.propertyType
count: 2
path: ../../../htdocs/categories/class/categorie.class.php
-
message: '#^Return type of call to function dol_sort_array contains unresolvable type\.$#'
identifier: function.unresolvableReturnType
count: 1
path: ../../../htdocs/categories/class/categorie.class.php
-
message: '#^If condition is always true\.$#'
identifier: if.alwaysTrue
@@ -5646,12 +5610,6 @@ parameters:
count: 2
path: ../../../htdocs/core/class/html.form.class.php
-
message: '#^Parameter \#1 \$array of function dol_sort_array contains unresolvable type\.$#'
identifier: argument.unresolvableType
count: 3
path: ../../../htdocs/core/class/html.form.class.php
-
message: '#^Parameter \#15 \$excludeids of method Form\:\:select_company\(\) expects array\<string\>, array\<int\> given\.$#'
identifier: argument.type
@@ -5676,54 +5634,6 @@ parameters:
count: 1
path: ../../../htdocs/core/class/html.form.class.php
-
message: '#^Property Form\:\:\$cache_conditions_paiements has no type specified\.$#'
identifier: missingType.property
count: 1
path: ../../../htdocs/core/class/html.form.class.php
-
message: '#^Property Form\:\:\$cache_demand_reason has no type specified\.$#'
identifier: missingType.property
count: 1
path: ../../../htdocs/core/class/html.form.class.php
-
message: '#^Property Form\:\:\$cache_invoice_subtype has no type specified\.$#'
identifier: missingType.property
count: 1
path: ../../../htdocs/core/class/html.form.class.php
-
message: '#^Property Form\:\:\$cache_transport_mode has no type specified\.$#'
identifier: missingType.property
count: 1
path: ../../../htdocs/core/class/html.form.class.php
-
message: '#^Property Form\:\:\$cache_types_fees has no type specified\.$#'
identifier: missingType.property
count: 1
path: ../../../htdocs/core/class/html.form.class.php
-
message: '#^Property Form\:\:\$cache_types_paiements has no type specified\.$#'
identifier: missingType.property
count: 1
path: ../../../htdocs/core/class/html.form.class.php
-
message: '#^Property Form\:\:\$cache_vatrates has no type specified\.$#'
identifier: missingType.property
count: 1
path: ../../../htdocs/core/class/html.form.class.php
-
message: '#^Return type of call to function dol_sort_array contains unresolvable type\.$#'
identifier: function.unresolvableReturnType
count: 3
path: ../../../htdocs/core/class/html.form.class.php
-
message: '#^Right side of && is always true\.$#'
identifier: booleanAnd.rightAlwaysTrue
@@ -5760,24 +5670,12 @@ parameters:
count: 1
path: ../../../htdocs/core/class/html.formcompany.class.php
-
message: '#^Parameter \#1 \$array of function dol_sort_array contains unresolvable type\.$#'
identifier: argument.unresolvableType
count: 1
path: ../../../htdocs/core/class/html.formcompany.class.php
-
message: '#^Parameter \#3 \$selected of method Form\:\:multiselectarray\(\) expects array\<string\>, array\<array\<string, int\>\|int\> given\.$#'
identifier: argument.type
count: 1
path: ../../../htdocs/core/class/html.formcompany.class.php
-
message: '#^Return type of call to function dol_sort_array contains unresolvable type\.$#'
identifier: function.unresolvableReturnType
count: 1
path: ../../../htdocs/core/class/html.formcompany.class.php
-
message: '#^Variable \$idprof might not be defined\.$#'
identifier: variable.undefined
@@ -10794,18 +10692,6 @@ parameters:
count: 1
path: ../../../htdocs/main.inc.php
-
message: '#^Parameter \#1 \$array of function dol_sort_array contains unresolvable type\.$#'
identifier: argument.unresolvableType
count: 1
path: ../../../htdocs/margin/agentMargins.php
-
message: '#^Return type of call to function dol_sort_array contains unresolvable type\.$#'
identifier: function.unresolvableReturnType
count: 1
path: ../../../htdocs/margin/agentMargins.php
-
message: '#^Ternary operator condition is always false\.$#'
identifier: ternary.alwaysFalse
@@ -14064,18 +13950,6 @@ parameters:
count: 1
path: ../../../htdocs/reception/card.php
-
message: '#^Loose comparison using \=\= between ''''\|''CommandeFournisseur'' and ''commande'' will always evaluate to false\.$#'
identifier: equal.alwaysFalse
count: 2
path: ../../../htdocs/reception/card.php
-
message: '#^Loose comparison using \=\= between ''''\|''CommandeFournisseur'' and ''propal'' will always evaluate to false\.$#'
identifier: equal.alwaysFalse
count: 2
path: ../../../htdocs/reception/card.php
-
message: '#^Negated boolean expression is always true\.$#'
identifier: booleanNot.alwaysTrue
@@ -14088,12 +13962,6 @@ parameters:
count: 1
path: ../../../htdocs/reception/card.php
-
message: '#^Result of && is always false\.$#'
identifier: booleanAnd.alwaysFalse
count: 8
path: ../../../htdocs/reception/card.php
-
message: '#^Variable \$extrafields in empty\(\) always exists and is not falsy\.$#'
identifier: empty.variable
@@ -14244,24 +14112,6 @@ parameters:
count: 2
path: ../../../htdocs/reception/contact.php
-
message: '#^Loose comparison using \=\= between ''''\|''CommandeFournisseur'' and ''commande'' will always evaluate to false\.$#'
identifier: equal.alwaysFalse
count: 1
path: ../../../htdocs/reception/dispatch.php
-
message: '#^Loose comparison using \=\= between ''''\|''CommandeFournisseur'' and ''propal'' will always evaluate to false\.$#'
identifier: equal.alwaysFalse
count: 1
path: ../../../htdocs/reception/dispatch.php
-
message: '#^Result of && is always false\.$#'
identifier: booleanAnd.alwaysFalse
count: 4
path: ../../../htdocs/reception/dispatch.php
-
message: '#^Variable \$objectsrc might not be defined\.$#'
identifier: variable.undefined
@@ -15666,12 +15516,6 @@ parameters:
count: 3
path: ../../../htdocs/user/class/user.class.php
-
message: '#^Parameter \#1 \$array of function dol_sort_array contains unresolvable type\.$#'
identifier: argument.unresolvableType
count: 1
path: ../../../htdocs/user/class/user.class.php
-
message: '#^Property User\:\:\$rights \(stdClass\) in empty\(\) is not falsy\.$#'
identifier: empty.property
@@ -15726,12 +15570,6 @@ parameters:
count: 4
path: ../../../htdocs/user/class/user.class.php
-
message: '#^Return type of call to function dol_sort_array contains unresolvable type\.$#'
identifier: function.unresolvableReturnType
count: 1
path: ../../../htdocs/user/class/user.class.php
-
message: '#^Variable \$whereforadd in empty\(\) always exists and is not falsy\.$#'
identifier: empty.variable
@@ -16116,12 +15954,6 @@ parameters:
count: 1
path: ../../../htdocs/webhook/triggerhistory_list.php
-
message: '#^Loose comparison using \=\= between ''auto'' and ''auto'' will always evaluate to true\.$#'
identifier: equal.alwaysTrue
count: 1
path: ../../../htdocs/webportal/class/context.class.php
-
message: '#^Result of && is always false\.$#'
identifier: booleanAnd.alwaysFalse
@@ -16134,24 +15966,6 @@ parameters:
count: 1
path: ../../../htdocs/webportal/class/html.formcardwebportal.class.php
-
message: '#^Comparison operation "\<\=" between int\<2, max\> and 1 is always false\.$#'
identifier: smallerOrEqual.alwaysFalse
count: 1
path: ../../../htdocs/webportal/class/html.formlistwebportal.class.php
-
message: '#^Offset ''total'' on \*NEVER\* in isset\(\) always exists and is not nullable\.$#'
identifier: isset.offset
count: 1
path: ../../../htdocs/webportal/class/html.formlistwebportal.class.php
-
message: '#^Result of && is always false\.$#'
identifier: booleanAnd.alwaysFalse
count: 1
path: ../../../htdocs/webportal/class/html.formlistwebportal.class.php
-
message: '#^Call to function is_array\(\) with list\<string\> will always evaluate to true\.$#'
identifier: function.alreadyNarrowedType

View File

@@ -1,20 +1,22 @@
<?php
/* Copyright (C) 2025 MDW <mdeweerd@users.noreply.github.com>
*/
/* PHP 7.0 */
$finder = (new PhpCsFixer\Finder())
->in(__DIR__)
->exclude([
'core/includes',
'custom',
'documents',
'doctemplates',
'vendor',
'install/doctemplates',
'htdocs/custom',
'htdocs/includes',
'htdocs/install/doctemplates',
])
->notPath('vendor');
->in(__DIR__)
->exclude([
'core/includes',
'custom',
'documents',
'doctemplates',
'vendor',
'install/doctemplates',
'htdocs/custom',
'htdocs/includes',
'htdocs/install/doctemplates',
])
->notPath('vendor');
/* PHP 7.4+ */
@@ -43,8 +45,11 @@ return (new PhpCsFixer\Config())
// So we use target PHP70 for the moment.
'@PHP70Migration' => true,
//'@PHP71Migration' => true,
// Avoid adding public to const (incompatible with PHP 7.0):
'visibility_required' => ['elements'=>['property', 'method']],
// Avoid adding public to const (incompatible with PHP 7.0):
'visibility_required' => ['elements' => ['property', 'method']],
// Replace deprecated 'visibility_required'
'modifier_keywords' => ['elements' => ['property', 'method']],
//'strict_param' => true,
//'array_syntax' => ['syntax' => 'short'],
@@ -59,5 +64,4 @@ return (new PhpCsFixer\Config())
->setIndent("\t")
// All files MUST use the Unix LF line ending only
// https://www.php-fig.org/psr/psr-12/#22-files
->setLineEnding("\n")
;
->setLineEnding("\n");

View File

@@ -145,8 +145,6 @@ Barcode
BarcodeDesc
BarcodeStickersMask
BillOfMaterialsLine
BlockLogNeedAmountsValue
BlockLogNeedElement
BlockedLogAuthorityNeededToStoreYouFingerprintsInNonAlterableRemote
BlockedLogAuthorityUrl
BlockedLogSetup

View File

@@ -851,7 +851,7 @@ if ($action == 'create') {
print '<tr>';
print '<td class="titlefield">' . $langs->trans("DateExport") . '</td>';
print '<td>';
print $object->date_export ? img_picto($langs->trans("TransactionExportDesc"), 'fa-file-export', 'class="pictofixedwidth"').dol_print_date($object->date_export, 'dayhour') : '&nbsp;';
print $object->date_export ? img_picto($langs->trans("TransactionExportDesc"), 'fa-file-export', 'class="pictofixedwidth opacitymedium"').dol_print_date($object->date_export, 'dayhour') : '&nbsp;';
print '</td>';
print '</tr>';
@@ -859,7 +859,7 @@ if ($action == 'create') {
print '<tr>';
print '<td class="titlefield">' . $langs->trans("DateValidation") . '</td>';
print '<td>';
print $object->date_validation ? img_picto($langs->trans("TransactionBlockedLockedDesc"), 'fa-lock', 'class="pictofixedwidth"').dol_print_date($object->date_validation, 'dayhour') : '&nbsp;';
print $object->date_validation ? img_picto($langs->trans("TransactionBlockedLockedDesc"), 'fa-lock', 'class="pictofixedwidth opacitymedium"').dol_print_date($object->date_validation, 'dayhour') : '&nbsp;';
print '</td>';
print '</tr>';

View File

@@ -1272,6 +1272,12 @@ while ($i < min($num, $limit)) {
$object->piece_num = $line->piece_num;
$object->ref = $line->ref;
print $object->getNomUrl(1, '', 0, '', 1);
if (!empty($line->date_export)) {
print img_picto($langs->trans("DateExport").": ".dol_print_date($line->date_export, 'dayhour')." (".$langs->trans("TransactionExportDesc").")", 'fa-file-export', 'class="paddingleft pictofixedwidth opacitymedium"');
}
if (!empty($line->date_validation)) {
print img_picto($langs->trans("DateValidation").": ".dol_print_date($line->date_validation, 'dayhour')." (".$langs->trans("TransactionBlockedLockedDesc").")", 'fa-lock', 'class="paddingleft pictofixedwidth opacitymedium"');
}
print '</td>';
if (!$i) {
$totalarray['nbfield']++;

View File

@@ -1421,10 +1421,10 @@ while ($i < min($num, $limit)) {
$object->ref = $line->ref;
print $object->getNomUrl(1, '', 0, '', 1);
if (!empty($line->date_export)) {
print img_picto($langs->trans("DateExport").": ".dol_print_date($line->date_export, 'dayhour')." (".$langs->trans("TransactionExportDesc").")", 'fa-file-export', 'class="paddingleft pictofixedwidth"');
print img_picto($langs->trans("DateExport").": ".dol_print_date($line->date_export, 'dayhour')." (".$langs->trans("TransactionExportDesc").")", 'fa-file-export', 'class="paddingleft pictofixedwidth opacitymedium"');
}
if (!empty($line->date_validation)) {
print img_picto($langs->trans("DateValidation").": ".dol_print_date($line->date_validation, 'dayhour')." (".$langs->trans("TransactionBlockedLockedDesc").")", 'fa-lock', 'class="paddingleft pictofixedwidth"');
print img_picto($langs->trans("DateValidation").": ".dol_print_date($line->date_validation, 'dayhour')." (".$langs->trans("TransactionBlockedLockedDesc").")", 'fa-lock', 'class="paddingleft pictofixedwidth opacitymedium"');
}
print '</td>';
if (!$i) {

View File

@@ -524,9 +524,6 @@ if (empty($reshook)) {
}
// Rename some POST variables into a generic name
if ($field == 'fk_user' && !(GETPOSTINT('fk_user') > 0)) {
$_POST['fk_user'] = '';
}
if ($field == 'topic') {
$_POST['topic'] = GETPOST('topic-'.$rowid);
}
@@ -548,7 +545,7 @@ if (empty($reshook)) {
}
$sql .= $field."=";
if (GETPOST($keycode) == '' || (!in_array($keycode, array('langcode', 'position', 'private', 'defaultfortype')) && !GETPOST($keycode))) {
if ((GETPOST($keycode) == '' && in_array($keycode, array('langcode'))) || (!in_array($keycode, array('langcode', 'position', 'private', 'defaultfortype')) && !GETPOST($keycode))) {
$sql .= "null"; // langcode,... must be '' if not defined so the unique key that include lang will work
} elseif (GETPOST($keycode) == '0' && $keycode == 'langcode') {
$sql .= "''"; // langcode must be '' if not defined so the unique key that include lang will work
@@ -560,7 +557,9 @@ if (empty($reshook)) {
}
} elseif ($keycode == 'content') {
$sql .= "'".$db->escape(GETPOST($keycode, 'restricthtml'))."'";
} elseif (in_array($keycode, array('joinfiles', 'defaultfortype', 'private', 'position'))) {
} elseif ($keycode == 'position') {
$sql .= (GETPOSTINT($keycode) > 0 ? GETPOSTINT($keycode) : 1);
} elseif (in_array($keycode, array('joinfiles', 'defaultfortype', 'private'))) {
$sql .= GETPOSTINT($keycode);
} else {
$sql .= "'".$db->escape(GETPOST($keycode, 'alphanohtml'))."'";
@@ -572,10 +571,10 @@ if (empty($reshook)) {
if (!$user->admin) { // A non admin user can only edit its own template
$sql .= " AND fk_user = ".((int) $user->id);
}
//print $sql;exit;
dol_syslog("actionmodify", LOG_DEBUG);
//print $sql;
//print $sql; exit;
$resql = $db->query($sql);
if (!$resql) {
$error++;
@@ -731,7 +730,6 @@ $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters,
$param .= $hookmanager->resPrint;
$linkback = '';
$titlepicto = 'title_setup';
@@ -1164,7 +1162,8 @@ if ($num) {
if ($obj) {
if (($action == 'edit' || $action == 'preview') && ($rowid == (!empty($obj->rowid) ? $obj->rowid : $obj->code))) {
print '<tr class="nohover oddeven" id="rowid-'.$obj->rowid.'">';
// TODO Move this 2 lines into a popup
print '<tr class="nohover oddeven noborderbottom" id="rowid-'.$obj->rowid.'" name="'.(!empty($obj->rowid) ? $obj->rowid : $obj->code).'">';
$tmpaction = 'edit';
if ($action == 'edit') {
@@ -1180,16 +1179,6 @@ if ($num) {
$colspan = 0;
print '<tr><td colspan="12">';
print '<input type="hidden" name="page" value="'.$page.'">';
print '<input type="hidden" name="rowid" value="'.$rowid.'">';
print '<div name="'.(!empty($obj->rowid) ? $obj->rowid : $obj->code).'"></div>';
if ($action == 'edit') {
print '<input type="submit" class="button buttongen button-save" name="actionmodify" value="'.$langs->trans("Save").'">';
}
print '<input type="submit" class="button buttongen button-cancel" name="actioncancel" value="'.$langs->trans("Cancel").'">';
print '</td></tr>';
// Action column
if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print '<td class="center">';
@@ -1203,20 +1192,16 @@ if ($num) {
// Action column
if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print '<td class="center">';
print '<input type="hidden" name="page" value="'.$page.'">';
print '<input type="hidden" name="rowid" value="'.$rowid.'">';
if ($action == 'edit') {
print '<input type="submit" class="button buttongen button-save" name="actionmodify" value="'.$langs->trans("Modify").'">';
}
print '<div name="'.(!empty($obj->rowid) ? $obj->rowid : $obj->code).'"></div>';
print '<input type="submit" class="button buttongen button-cancel" name="actioncancel" value="'.$langs->trans("Cancel").'">';
print '</td>';
$colspan++;
}
print "</tr>\n";
print '<tr class="oddeven nohover" id="tr-aaa-'.$rowid.'">';
print '<td colspan="'.$colspan.'" class="" style="padding-left: 20px; padding-right: 20px;">';
if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print '<td class="center"></td>';
}
print '<td colspan="'.($colspan - 1).'" class="" style="padding-left: 20px; padding-right: 20px;">';
$fieldsforcontent = array('topic', 'email_from','joinfiles', 'content');
if (getDolGlobalString('MAIN_EMAIL_TEMPLATES_FOR_OBJECT_LINES')) {
@@ -1259,7 +1244,7 @@ if ($num) {
if (!getDolGlobalString('FCKEDITOR_ENABLE_MAIL')) {
$okforextended = false;
}
$doleditor = new DolEditor($tmpfieldlist.'-'.$rowid, (!empty($obj->{$tmpfieldlist}) ? $obj->{$tmpfieldlist} : ''), '', 500, 'dolibarr_mailings', 'In', false, $acceptlocallinktomedia, $okforextended, ROWS_6, '90%', ($action != 'edit' ? 1 : 0));
$doleditor = new DolEditor($tmpfieldlist.'-'.$rowid, (!empty($obj->{$tmpfieldlist}) ? $obj->{$tmpfieldlist} : ''), '', 450, 'dolibarr_mailings', 'In', false, $acceptlocallinktomedia, $okforextended, ROWS_6, '80%', ($action != 'edit' ? 1 : 0));
print $doleditor->Create(1);
}
if ($tmpfieldlist == 'content_lines') {
@@ -1269,16 +1254,27 @@ if ($num) {
if (!getDolGlobalString('FCKEDITOR_ENABLE_MAIL')) {
$okforextended = false;
}
$doleditor = new DolEditor($tmpfieldlist.'-'.$rowid, (!empty($obj->{$tmpfieldlist}) ? $obj->{$tmpfieldlist} : ''), '', 140, 'dolibarr_mailings', 'In', false, $acceptlocallinktomedia, $okforextended, ROWS_6, '90%');
$doleditor = new DolEditor($tmpfieldlist.'-'.$rowid, (!empty($obj->{$tmpfieldlist}) ? $obj->{$tmpfieldlist} : ''), '', 140, 'dolibarr_mailings', 'In', false, $acceptlocallinktomedia, $okforextended, ROWS_6, '80%');
print $doleditor->Create(1);
}
print '</div>';
}
}
print '</div>';
print '<center><input type="hidden" name="page" value="'.$page.'">';
print '<input type="hidden" name="rowid" value="'.$rowid.'">';
if ($action == 'edit') {
print '<input type="submit" class="button buttongen button-save" name="actionmodify" value="'.$langs->trans("Save").'">';
}
print '<input type="submit" class="button buttongen button-cancel" name="actioncancel" value="'.$langs->trans("Cancel").'">';
print '</center>';
print '</td>';
print "</tr>\n";
if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print '<td class="center"></td>';
}
print '</tr>';
$nbqualified++;
} else {
@@ -1509,7 +1505,7 @@ function fieldList($fieldlist, $obj = null, $tabname = '', $context = '')
} elseif ($value == 'fk_user') {
print '<td>';
if ($user->admin && $context != 'preview') {
print $form->select_dolusers(GETPOSTISSET('fk_user') ? GETPOSTINT('fk_user') : (empty($obj->$value) ? '' : $obj->$value), 'fk_user', 1, array(), 0, ($user->admin ? '' : 'hierarchyme'), array(), '0', 0, 0, '', 0, '', 'minwidth75 maxwidth100');
print $form->select_dolusers(GETPOSTISSET('fk_user') ? GETPOSTINT('fk_user') : (empty($obj->$value) ? '' : $obj->$value), 'fk_user', $langs->trans("Owner"), array(), 0, ($user->admin ? '' : 'hierarchyme'), array(), '0', 0, 0, '', 0, '', 'minwidth75 maxwidth100');
} else {
if ($context == 'add') { // I am not admin and we show the add form
print $user->getNomUrl(-1); // Me
@@ -1536,7 +1532,7 @@ function fieldList($fieldlist, $obj = null, $tabname = '', $context = '')
if ($context == 'edit') {
$selectedlang = $obj->lang;
}
print $formadmin->select_language($selectedlang, 'langcode', 0, array(), 1, 0, 0, 'maxwidth100');
print $formadmin->select_language($selectedlang, 'langcode', 0, array(), $langs->trans("Language"), 0, 0, 'maxwidth100');
} else {
if (!empty($obj->lang)) {
print $obj->lang.' - '.$langs->trans('Language_'.$obj->lang);

View File

@@ -28,8 +28,6 @@
// Load Dolibarr environment
require '../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
/**
* @var Conf $conf
* @var DoliDB $db
@@ -37,6 +35,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
* @var Translate $langs
* @var User $user
*/
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
if (!$user->admin) {
accessforbidden();
@@ -332,7 +331,7 @@ print '</td></tr>';
if (!empty($conf->loghandlers['mod_syslog_file']) && isModEnabled('cron')) {
print '<tr class="oddeven"><td>'.$langs->trans("SyslogFileNumberOfSaves").'</td>';
print '<td colspan="2"><input class="width50" type="number" name="file_saves" placeholder="14" min="0" step="1" value="'.getDolGlobalString('SYSLOG_FILE_SAVES').'" />';
print ' &nbsp; (<a href="'.dol_buildpath('/cron/list.php', 1).'?search_label=CompressSyslogs&status=-1">'.$langs->trans('ConfigureCleaningCronjobToSetFrequencyOfSaves').'</a>)</td></tr>';
print ' &nbsp; <a href="'.dol_buildpath('/cron/list.php', 1).'?search_label=CompressSyslogs&status=-1">'.$langs->trans('ConfigureCleaningCronjobToSetFrequencyOfSaves').'</a></td></tr>';
}
print '</table>';

View File

@@ -3,7 +3,7 @@
* Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
* Copyright (C) 2005-2021 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
*
* This program is free software; you can redistribute it and/or modify
@@ -65,9 +65,11 @@ if (preg_match('/del(.*)/', $action, $reg)) {
}
}
// List of workflow we can enable
clearstatcache();
/** @var array<string,array{family:string,position:int,enabled:bool,picto?:string,warning?:string,deprecated?:int<0,1>,reloadpage?:int<0,1>}> $workflowcodes */
$workflowcodes = array(
// Automatic creation
'WORKFLOW_PROPAL_AUTOCREATE_ORDER' => array(
@@ -227,6 +229,7 @@ $workflowcodes = array(
if (!empty($conf->modules_parts['workflow']) && is_array($conf->modules_parts['workflow'])) {
foreach ($conf->modules_parts['workflow'] as $workflow) {
/** @var array<string,array{family:string,position:int,enabled:bool,picto?:string,warning?:string,deprecated?:int<0,1>,reloadpage?:int<0,1>}> $workflow */
$workflowcodes = array_merge($workflowcodes, $workflow);
}
}

View File

@@ -169,7 +169,7 @@ if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x'
include DOL_DOCUMENT_ROOT.'/core/actions_linkedfiles.inc.php';
if (GETPOST('action') == 'upload' && $user->hasRight('blockedlog', 'read')) { // read is read/upload for blockedlog
if (GETPOST('action') == 'export' && $user->hasRight('blockedlog', 'read')) { // read is read/export for blockedlog
$error = 0;
$previoushash = '';
@@ -184,16 +184,20 @@ if (GETPOST('action') == 'upload' && $user->hasRight('blockedlog', 'read')) { /
$error++;
}
$dates = dol_get_first_day(GETPOSTINT('yeartoexport'), GETPOSTINT('monthtoexport') ? GETPOSTINT('monthtoexport') : 1);
$datee = dol_get_last_day(GETPOSTINT('yeartoexport'), GETPOSTINT('monthtoexport') ? GETPOSTINT('monthtoexport') : 12);
if ($datee >= dol_now()) {
setEventMessages($langs->trans("ErrorPeriodMustBePastToAllowExport"), null, "errors");
$error++;
}
if (!$error) {
// Get the ID of the first line qualified
$sql = "SELECT rowid,date_creation,tms,user_fullname,action,amounts,element,fk_object,date_object,ref_object,signature,fk_user,object_data";
$sql .= " FROM ".MAIN_DB_PREFIX."blockedlog";
$sql .= " WHERE entity = ".((int) $conf->entity);
if (GETPOSTINT('monthtoexport') > 0 || GETPOSTINT('yeartoexport') > 0) {
$dates = dol_get_first_day(GETPOSTINT('yeartoexport'), GETPOSTINT('monthtoexport') ? GETPOSTINT('monthtoexport') : 1);
$datee = dol_get_last_day(GETPOSTINT('yeartoexport'), GETPOSTINT('monthtoexport') ? GETPOSTINT('monthtoexport') : 12);
$sql .= " AND date_creation BETWEEN '".$db->idate($dates)."' AND '".$db->idate($datee)."'";
}
$sql .= " AND date_creation BETWEEN '".$db->idate($dates)."' AND '".$db->idate($datee)."'";
$sql .= " ORDER BY rowid ASC"; // Required so we get the first one
$sql .= $db->plimit(1);
@@ -518,7 +522,7 @@ if ($action == 'deletefile') {
print '<form method="POST" id="exportArchives" action="'.$_SERVER["PHP_SELF"].'?output=file">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="upload">';
print '<input type="hidden" name="action" value="export">';
print '<div class="right">';

View File

@@ -990,19 +990,29 @@ class BlockedLog
// Check parameters/properties
if (!isset($this->amounts)) { // amount can be 0 for some events (like when module is disabled)
$this->error = $langs->trans("BlockLogNeedAmountsValue");
$langs->load("errors");
$this->error = $langs->trans("ErrorBlockLogNeedAmountsValue");
dol_syslog($this->error, LOG_WARNING);
return -1;
}
if (empty($this->element)) {
$this->error = $langs->trans("BlockLogNeedElement");
$langs->load("errors");
$this->error = $langs->trans("ErrorBlockLogNeedElement");
dol_syslog($this->error, LOG_WARNING);
return -2;
}
if (empty($this->object_data)) {
$langs->load("errors");
$this->error = $langs->trans("ErrorBlockLogNeedObject");
dol_syslog($this->error, LOG_WARNING);
return -2;
}
if (empty($this->action)) {
$this->error = $langs->trans("BadParameterWhenCallingCreateOfBlockedLog");
$langs->load("errors");
$this->error = $langs->trans("ErrorBadParameterWhenCallingCreateOfBlockedLog");
dol_syslog($this->error, LOG_WARNING);
return -3;
}

View File

@@ -1342,19 +1342,23 @@ class Categorie extends CommonObject
$nbcateg = $this->db->num_rows($resql);
while ($obj = $this->db->fetch_object($resql)) {
$this->cats[$obj->rowid]['rowid'] = $obj->rowid;
$this->cats[$obj->rowid]['id'] = $obj->rowid;
$this->cats[$obj->rowid]['fk_parent'] = $obj->fk_parent;
$this->cats[$obj->rowid]['label'] = !empty($obj->label_trans) ? $obj->label_trans : $obj->label;
$this->cats[$obj->rowid]['description'] = !empty($obj->description_trans) ? $obj->description_trans : $obj->description;
$this->cats[$obj->rowid]['color'] = $obj->color;
$this->cats[$obj->rowid]['position'] = $obj->position;
$this->cats[$obj->rowid]['visible'] = $obj->visible;
$this->cats[$obj->rowid]['ref_ext'] = $obj->ref_ext;
$this->cats[$obj->rowid]['picto'] = 'category';
// fields are filled with buildPathFromId later
$this->cats[$obj->rowid]['fullpath'] = '';
$this->cats[$obj->rowid]['fulllabel'] = '';
$this->cats[(int) $obj->rowid]
= array(
'rowid' => (int) $obj->rowid,
'id' => (int) $obj->rowid,
'fk_parent' => (int) $obj->fk_parent,
'label' => !empty($obj->label_trans) ? (string) $obj->label_trans : (string) $obj->label,
'description' => !empty($obj->description_trans) ? (string) $obj->description_trans : (string) $obj->description,
'color' => (string) $obj->color,
'position' => (string) $obj->position,
'visible' => (int) $obj->visible,
'ref_ext' => (string) $obj->ref_ext,
'picto' => 'category',
// fields are filled with buildPathFromId later
'fullpath' => '',
'fulllabel' => '',
'level' => null,
);
$i++;
}
} else {

View File

@@ -100,11 +100,6 @@ $cancel = GETPOST('cancel', 'alpha');
$backtopage = GETPOST('backtopage', 'alpha'); // if not set, a default page will be used
$backtopageforcancel = GETPOST('backtopageforcancel', 'alpha'); // if not set, $backtopage will be used
$lineid = GETPOSTINT('lineid');
$userid = GETPOSTINT('userid');
$search_ref = GETPOST('sf_ref', 'alpha') ? GETPOST('sf_ref', 'alpha') : GETPOST('search_ref', 'alpha');
$search_societe = GETPOST('search_societe', 'alpha');
$search_montant_ht = GETPOST('search_montant_ht', 'alpha');
$search_montant_ttc = GETPOST('search_montant_ttc', 'alpha');
$origin = GETPOST('origin', 'alpha');
$originid = (GETPOSTINT('originid') ? GETPOSTINT('originid') : GETPOSTINT('origin_id')); // For backward compatibility
$fac_rec = GETPOSTINT('fac_rec');
@@ -123,8 +118,6 @@ $hideref = (GETPOSTINT('hideref') ? GETPOSTINT('hideref') : (getDolGlobalString(
// Number of lines for predefined product/service choices
$NBLINES = 4;
$usehm = getDolGlobalInt('MAIN_USE_HOURMIN_IN_DATE_RANGE');
$object = new Facture($db);
$extrafields = new ExtraFields($db);
@@ -1274,7 +1267,7 @@ if (empty($reshook)) {
$sourceinvoice = GETPOSTINT('fac_avoir');
if (!($sourceinvoice > 0) && !getDolGlobalString('INVOICE_CREDIT_NOTE_STANDALONE')) {
$error++;
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("CorrectInvoice")), null, 'errors');
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("InvoiceAvoirAskCombo")), null, 'errors');
$action = 'create';
}
@@ -4309,7 +4302,7 @@ if ($action == 'create') {
});
</script>';
$text = '<label>'.$tmp.$langs->transnoentities("InvoiceAvoirAsk").'</label> ';
$text .= '<select class="flat valignmiddle" name="fac_avoir" id="fac_avoir"';
$text .= '<select class="flat valignmiddle minwidth200" name="fac_avoir" id="fac_avoir"';
if (!$optionsav || $invoice_predefined->id > 0) {
$text .= ' disabled';
}
@@ -4325,9 +4318,10 @@ if ($action == 'create') {
print $desc;
print '<div id="credit_note_options" class="clearboth paddingtop marginbottomonly">';
print '<div class="marginleftlarge"><input type="checkbox" name="invoiceAvoirWithLines" id="invoiceAvoirWithLines" value="1" onclick="$(\'#credit_note_options input[type=checkbox]\').not(this).prop(\'checked\', false);" '.(GETPOSTINT('invoiceAvoirWithLines') > 0 ? 'checked' : '').' /> <label for="invoiceAvoirWithLines" class="small">'.$langs->trans('invoiceAvoirWithLines')."</label></div>";
//print '<br>';
print '<div class="marginleftlarge"><input type="checkbox" name="invoiceAvoirWithPaymentRestAmount" id="invoiceAvoirWithPaymentRestAmount" value="1" onclick="$(\'#credit_note_options input[type=checkbox]\').not(this).prop(\'checked\', false);" '.(GETPOSTINT('invoiceAvoirWithPaymentRestAmount') > 0 ? 'checked' : '').' /> <label for="invoiceAvoirWithPaymentRestAmount" class="small">'.$langs->trans('invoiceAvoirWithPaymentRestAmount')."</label></div>";
print '<div class="marginleftlargeondesktop"><input type="checkbox" name="invoiceAvoirWithLines" id="invoiceAvoirWithLines" value="1" onclick="$(\'#credit_note_options input[type=checkbox]\').not(this).prop(\'checked\', false);" '.(GETPOSTINT('invoiceAvoirWithLines') > 0 ? 'checked' : '').' /> <label for="invoiceAvoirWithLines" class="small">'.$langs->trans('invoiceAvoirWithLines')."</label></div>";
print '<div class="marginleftlargeondesktop"><input type="checkbox" name="invoiceAvoirWithPaymentRestAmount" id="invoiceAvoirWithPaymentRestAmount" value="1" onclick="$(\'#credit_note_options input[type=checkbox]\').not(this).prop(\'checked\', false);" '.(GETPOSTINT('invoiceAvoirWithPaymentRestAmount') > 0 ? 'checked' : '').' /> <label for="invoiceAvoirWithPaymentRestAmount" class="small">'.$langs->trans('invoiceAvoirWithPaymentRestAmount')."</label></div>";
// Adding a checkbox: "Automatically consume the credit note to close the corrected invoice" is better to be into
// the confirm popup when we validate the credit note
print '</div>';
print '</div></div>'."\n";

View File

@@ -1,6 +1,6 @@
<?php
/* Copyright (C) 2014-2016 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2014-2024 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2014-2025 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -65,6 +65,7 @@ if ($action == 'print_file' && $user->hasRight('printing', 'read')) {
$subdir = '';
$module = GETPOST('printer', 'alpha');
// TODO make conversion in printing module
switch ($module) {
case 'livraison':
$subdir = 'receipt';
@@ -74,7 +75,7 @@ if ($action == 'print_file' && $user->hasRight('printing', 'read')) {
$subdir = 'sending';
break;
case 'commande_fournisseur':
$module = 'fournisseur';
$module = 'commande_fournisseur';
$subdir = 'commande';
break;
}

View File

@@ -1000,6 +1000,7 @@ class Form
$langs->load("dict");
$out = '';
/** @var array<int,array{rowid:int,code_iso:string,code_iso3:string,label:string,favorite:string,eec:string}> $countryArray */
$countryArray = array();
$favorite = array();
$label = array();
@@ -1020,12 +1021,15 @@ class Form
while ($i < $num) {
$obj = $this->db->fetch_object($resql);
$countryArray[$i]['rowid'] = $obj->rowid;
$countryArray[$i]['code_iso'] = $obj->code_iso;
$countryArray[$i]['code_iso3'] = $obj->code_iso3;
$countryArray[$i]['label'] = ($obj->code_iso && $langs->transnoentitiesnoconv("Country" . $obj->code_iso) != "Country" . $obj->code_iso ? $langs->transnoentitiesnoconv("Country" . $obj->code_iso) : ($obj->label != '-' ? $obj->label : ''));
$countryArray[$i]['favorite'] = $obj->favorite;
$countryArray[$i]['eec'] = $obj->eec;
$countryArray[$i]
= array(
'rowid' => (int) $obj->rowid,
'code_iso' => (string) $obj->code_iso,
'code_iso3' => (string) $obj->code_iso3,
'label' => (string) ($obj->code_iso && $langs->transnoentitiesnoconv("Country" . $obj->code_iso) != "Country" . $obj->code_iso ? $langs->transnoentitiesnoconv("Country" . $obj->code_iso) : ($obj->label != '-' ? $obj->label : '')),
'favorite' => (string) $obj->favorite,
'eec' => (string) $obj->eec,
);
$favorite[$i] = $obj->favorite;
$label[$i] = dol_string_unaccent($countryArray[$i]['label']);
$i++;
@@ -2107,7 +2111,7 @@ class Form
dol_syslog(get_class($this) . "::select_remises", LOG_DEBUG);
$resql = $this->db->query($sql);
if ($resql) {
print '<select id="select_' . $htmlname . '" class="flat maxwidthonsmartphone" name="' . $htmlname . '">';
print '<select id="select_' . $htmlname . '" class="flat maxwidth200onsmartphone" name="' . $htmlname . '">';
$num = $this->db->num_rows($resql);
$qualifiedlines = $num;
@@ -4749,12 +4753,13 @@ class Form
if ($resql) {
$num = $this->db->num_rows($resql);
$i = 0;
/** @var array<int,array{id:int,code:string,label:string}> */
$tmparray = array();
while ($i < $num) {
$obj = $this->db->fetch_object($resql);
// Si traduction existe, on l'utilise, sinon on prend le libelle par default
$label = ($obj->label != '-' ? $obj->label : '');
$label = ($obj->label != '-' ? (string) $obj->label : '');
if ($langs->trans("DemandReasonType" . $obj->code) != "DemandReasonType" . $obj->code) {
$label = $langs->trans("DemandReasonType" . $obj->code); // So translation key DemandReasonTypeSRC_XXX will work
}
@@ -4762,9 +4767,12 @@ class Form
$label = $langs->trans($obj->code); // So translation key SRC_XXX will work
}
$tmparray[$obj->rowid]['id'] = (int) $obj->rowid;
$tmparray[$obj->rowid]['code'] = $obj->code;
$tmparray[$obj->rowid]['label'] = $label;
$tmparray[(int) $obj->rowid]
= array(
'id' => (int) $obj->rowid,
'code' => (string) $obj->code,
'label' => $label,
);
$i++;
}
@@ -5226,10 +5234,13 @@ class Form
// If traduction exist, we use it else we take the default label
$label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
$this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
$this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
$this->cache_transport_mode[$obj->rowid]['label'] = $label;
$this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
$this->cache_transport_mode[(int) $obj->rowid]
= array(
'rowid' => (int) $obj->rowid,
'code' => (string) $obj->code,
'label' => (string) $label,
'active' => (int) $obj->active,
);
$i++;
}
@@ -6844,10 +6855,10 @@ class Form
* Show form with transport mode
*
* @param string $page Page
* @param string $selected Id mode pre-select
* @param int|'' $selected Id mode pre-select
* @param string $htmlname Name of select html field
* @param int $active Active or not, -1 = all
* @param int $addempty 1=Add empty entry
* @param int<-1,1> $active Active or not, -1 = all
* @param int<0,1> $addempty 1=Add empty entry
* @return void
*/
public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)

View File

@@ -582,6 +582,7 @@ class FormCompany extends Form
if ($num) {
$i = 0;
$country = '';
/** @var array<int,array{code:int,label:string,label_sort:string,country_code:string,country:string}> $arraydata */
$arraydata = array();
while ($i < $num) {
$obj = $this->db->fetch_object($resql);
@@ -589,7 +590,7 @@ class FormCompany extends Form
if ($obj->code) { // We exclude empty line, we will add it later
$labelcountry = (($langs->trans("Country" . $obj->country_code) != "Country" . $obj->country_code) ? $langs->trans("Country" . $obj->country_code) : $obj->country);
$labeljs = (($langs->trans("JuridicalStatus" . $obj->code) != "JuridicalStatus" . $obj->code) ? $langs->trans("JuridicalStatus" . $obj->code) : ($obj->label != '-' ? $obj->label : '')); // $obj->label is already in output charset (converted by database driver)
$arraydata[$obj->code] = array('code' => $obj->code, 'label' => $labeljs, 'label_sort' => $labelcountry . '_' . $labeljs, 'country_code' => $obj->country_code, 'country' => $labelcountry);
$arraydata[(int) $obj->code] = array('code' => (int) $obj->code, 'label' => $labeljs, 'label_sort' => $labelcountry . '_' . $labeljs, 'country_code' => (string) $obj->country_code, 'country' => $labelcountry);
}
$i++;
}

View File

@@ -507,8 +507,32 @@ class FormFile
}
$printer = 0;
$supportedmoduleparts = [
'company',
'member',
'product',
'stock',
'ficheinter',
'user',
'project',
'contract',
'facture',
'supplier_proposal',
'propal',
'proposal',
'order',
'commande',
'expedition',
'commande_fournisseur',
'facture_fournisseur',
'expensereport',
'delivery',
'ticket',
'bom',
'mrp:mo',
];
// The direct print feature is implemented only for such elements
if (in_array($modulepart, array('contract', 'facture', 'supplier_proposal', 'propal', 'proposal', 'order', 'commande', 'expedition', 'commande_fournisseur', 'expensereport', 'delivery', 'ticket'))) {
if (in_array($modulepart, $supportedmoduleparts)) {
$printer = ($user->hasRight('printing', 'read') && isModEnabled('printing'));
}

View File

@@ -5691,7 +5691,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $srco
'accounting_account' => 'infobox-bank_account',
'accountline' => 'infobox-bank_account',
'accountancy' => 'infobox-bank_account',
'admin'=> 'opacitymedium',
'admin' => 'opacitymedium',
'asset' => 'infobox-bank_account',
'bank_account' => 'infobox-bank_account',
'bill' => 'infobox-commande',
@@ -8445,7 +8445,8 @@ function get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer,
}
// If the (seller country = buyer country) then the default VAT = VAT of the product sold. End of rule.
if (empty($vatrule) && (($seller_country_code == $buyer_country_code)
if (empty($vatrule) && (
($seller_country_code == $buyer_country_code)
|| (in_array($seller_country_code, array('FR', 'MC')) && in_array($buyer_country_code, array('FR', 'MC')))
|| (in_array($seller_country_code, array('MQ', 'GP')) && in_array($buyer_country_code, array('MQ', 'GP'))) // We should be able to manage the case of MQ, GP, ... with a deicated vat rate at previous step.
)) { // Warning ->country_code not always defined
@@ -8517,7 +8518,8 @@ function get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer,
// Allow an external module to bypass the calculation of prices
$parameters = array('vatvalue' => $vatvalue, 'vatrule' => $vatrule);
$tmpobject = null; $tmpaction = '';
$tmpobject = null;
$tmpaction = '';
// @phan-suppress-next-line PhanPluginConstantVariableNull
$reshook = $hookmanager->executeHooks('get_default_tva', $parameters, $tmpobject, $tmpaction); // @phan-suppress-current-line PhanPluginConstantVariableNull
if ($reshook > 0 && !empty($hookmanager->resArray['vatvalue'])) {

View File

@@ -139,16 +139,16 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it
*/
public $rights_class;
public const URL_FOR_BLACKLISTED_MODULES = 'https://ping.dolibarr.org/modules-blacklist.txt';
const URL_FOR_BLACKLISTED_MODULES = 'https://ping.dolibarr.org/modules-blacklist.txt';
public const KEY_ID = 0;
public const KEY_LABEL = 1;
public const KEY_TYPE = 2; // deprecated
public const KEY_DEFAULT = 3;
public const KEY_FIRST_LEVEL = 4;
public const KEY_SECOND_LEVEL = 5;
public const KEY_MODULE = 6;
public const KEY_ENABLED = 7;
const KEY_ID = 0;
const KEY_LABEL = 1;
const KEY_TYPE = 2; // deprecated
const KEY_DEFAULT = 3;
const KEY_FIRST_LEVEL = 4;
const KEY_SECOND_LEVEL = 5;
const KEY_MODULE = 6;
const KEY_ENABLED = 7;
/**
* @var array<array{commentgroup?:string,mainmenu:string,leftmenu:string,langs:string,enabled:int|string,target:string,titre:string,user:int,fk_menu:string,fk_parent:string,url:string,position:int,positionfull:int|string,perms:string,type:string}>|int<1,1> Module menu entries (1 means the menu entries are not declared into module descriptor but are hardcoded into menu manager)

View File

@@ -1,6 +1,6 @@
<?php
/*
* Copyright (C) 2014-2024 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2014-2025 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -47,7 +47,6 @@ class PrintingDriver
*/
public $errors = array();
/**
* @var string Name
*/

View File

@@ -244,7 +244,6 @@ class printing_printipp extends PrintingDriver
*/
public function getlistAvailablePrinters()
{
global $conf, $db;
include_once DOL_DOCUMENT_ROOT.'/includes/printipp/CupsPrintIPP.php';
$ipp = new CupsPrintIPP();
$ipp->setLog(DOL_DATA_ROOT.'/dolibarr_printipp.log', 'file', 3); // logging very verbose
@@ -254,7 +253,12 @@ class printing_printipp extends PrintingDriver
if (!empty($this->user)) {
$ipp->setAuthentication($this->user, $this->password);
}
$ipp->getPrinters();
try {
$ipp->getPrinters();
} catch (Exception $e) {
setEventMessage($e->getMessage(), 'errors');
}
return $ipp->available_printers;
}

View File

@@ -69,6 +69,7 @@ class InterfaceWebhookTriggers extends DolibarrTriggers
*/
public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
{
global $dolibarr_main_db_pass;
if (!isModEnabled('webhook')) {
return 0; // If module is not enabled, we do nothing
}
@@ -93,6 +94,9 @@ class InterfaceWebhookTriggers extends DolibarrTriggers
return 0;
}
// Create new instance of db for webhook history save
$dbhistory = getDoliDBInstance($conf->db->type, $conf->db->host, (string) $conf->db->user, $dolibarr_main_db_pass, $conf->db->name, (int) $conf->db->port);
$sendmanualtriggers = (!empty($object->context['sendmanualtriggers']) ? $object->context['sendmanualtriggers'] : "");
foreach ($target_url as $key => $tmpobject) {
// Set list of all triggers for this targetinto $actionarray
@@ -146,7 +150,8 @@ class InterfaceWebhookTriggers extends DolibarrTriggers
}*/
}
$triggerhistory = new TriggerHistory($this->db);
$dbhistory->begin();
$triggerhistory = new TriggerHistory($dbhistory);
$triggerhistory->trigger_code = $action;
$triggerhistory->trigger_data = $jsonstr;
$triggerhistory->fk_target = $tmpobject->id;
@@ -157,10 +162,14 @@ class InterfaceWebhookTriggers extends DolibarrTriggers
if (!$resql) {
$errors++;
$this->errors = array_merge($this->errors, $triggerhistory->errors);
$dbhistory->rollback();
} else {
$dbhistory->commit();
}
}
}
$dbhistory->close();
dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id." -> nbPost=".$nbPosts);
if (!empty($errors)) {

View File

@@ -1395,17 +1395,17 @@ class EmailCollector extends CommonObject
array_push($criteria, array($not."CC" => $rule['rulevalue']));
}
if ($rule['type'] == 'subject') {
if (strpos($rule['rulevalue'], '!') === 0) {
if ($not) {
//array_push($criteria, array("NOT SUBJECT" => $rule['rulevalue']));
$searchfilterexcludesubjectarray[] = preg_replace('/^!/', '', $rule['rulevalue']);
$searchfilterexcludesubjectarray[] = $rule['rulevalue'];
} else {
array_push($criteria, array("SUBJECT" => $rule['rulevalue']));
}
}
if ($rule['type'] == 'body') {
if (strpos($rule['rulevalue'], '!') === 0) {
if ($not) {
//array_push($criteria, array("NOT BODY" => $rule['rulevalue']));
$searchfilterexcludebodyarray[] = preg_replace('/^!/', '', $rule['rulevalue']);
$searchfilterexcludebodyarray[] = $rule['rulevalue'];
} else {
array_push($criteria, array("BODY" => $rule['rulevalue']));
}

View File

@@ -294,7 +294,16 @@ if (empty($reshook)) {
if ($action == 'add' && $permissiontoadd) {
$db->begin();
if (GETPOSTINT('socid') < 1) {
if ($origin && $origin_id > 0) {
// We will loop on each line of the original document to complete the shipping object with various info and quantity to deliver
$classname = ucfirst($origin);
$objectsrc = new $classname($db);
'@phan-var-force Facture|Commande $objectsrc';
$objectsrc->fetch($origin_id);
$object->socid = $objectsrc->socid;
}
if (GETPOSTINT('socid') < 1 && $object->socid < 1) {
$error++;
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ThirdParty")), null, 'errors');
$action = 'create';
@@ -1418,7 +1427,7 @@ $product_static = new Product($db);
$shipment_static = new Expedition($db);
$warehousestatic = new Entrepot($db);
if ($action == 'create' && !getDolGlobalString('SHIPMENT_STANDALONE')) {
if (!$origin && $action == 'create' && !getDolGlobalString('SHIPMENT_STANDALONE')) {
print load_fiche_titre($langs->trans("CreateShipment"), '', 'dolly');
print '<br>' .$langs->trans("ShipmentCreationIsDoneFromOrder");
@@ -2257,7 +2266,7 @@ if ($action == 'create' && $usercancreate) {
}
} else {
// ship from multiple locations
if (isModEnabled('productbatch') || !$product->hasbatch()) {
if (!isModEnabled('productbatch') || !$product->hasbatch()) {
print '<!-- Case warehouse not already known and product does not need lot -->';
print '<td></td><td></td>';
if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
@@ -2464,6 +2473,7 @@ if ($action == 'create' && $usercancreate) {
print '<!-- Show details of lot -->';
print '<input name="batchl' . $indiceAsked . '_' . $subj . '" type="hidden" value="' . $dbatch->id . '">';
print '<input name="entl' . $indiceAsked . '_'.$subj.'" type="hidden" value="' . $tmpwarehouseObject->id . '">';
//print '|'.$line->fk_product.'|'.$dbatch->batch.'|<br>';
print $langs->trans("Batch") . ': ';

View File

@@ -66,14 +66,14 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
// Load translation files required by the page
$langs->loadLangs(array('bills', 'companies', 'interventions', 'stocks'));
$id = GETPOSTINT('id');
$ref = GETPOST('ref', 'alpha');
$id = GETPOSTINT('id');
$ref = GETPOST('ref', 'alpha');
$ref_client = GETPOST('ref_client', 'alpha');
$socid = GETPOSTINT('socid');
$contratid = GETPOSTINT('contratid');
$action = GETPOST('action', 'alpha');
$cancel = GETPOST('cancel', 'alpha');
$confirm = GETPOST('confirm', 'alpha');
$action = GETPOST('action', 'alpha');
$cancel = GETPOST('cancel', 'alpha');
$confirm = GETPOST('confirm', 'alpha');
$backtopage = GETPOST('backtopage', 'alpha');
$mesg = GETPOST('msg', 'alpha');

View File

@@ -394,4 +394,7 @@ CREATE TABLE llx_expensereport_det_extrafields
ALTER TABLE llx_blockedlog ADD INDEX idx_ref_object (ref_object);
ALTER TABLE llx_blockedlog ADD CONSTRAINT fk_linktoref FOREIGN KEY (linktoref) REFERENCES llx_blockedlog(ref_object);
ALTER TABLE llx_fichinterdet ADD COLUMN special_code integer DEFAULT 0 AFTER fk_parent_line;
ALTER TABLE llx_fichinterdet ADD COLUMN product_type integer DEFAULT 0 AFTER special_code;
-- end of migration

View File

@@ -22,6 +22,8 @@ create table llx_fichinterdet
rowid integer AUTO_INCREMENT PRIMARY KEY,
fk_fichinter integer,
fk_parent_line integer NULL,
special_code integer DEFAULT 0, -- code for special lines (may be 1=transport, 2=ecotax, 3=option, moduleid=...)
product_type integer DEFAULT 0,
date datetime, -- date de la ligne d'intervention
description text, -- description de la ligne d'intervention
duree integer, -- duree de la ligne d'intervention

View File

@@ -683,6 +683,7 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
'MAIN_MODULE_BLOCKEDLOG' => 'noboxes',
'MAIN_MODULE_DON' => 'newboxdefonly',
'MAIN_MODULE_ECM' => 'newboxdefonly',
'MAIN_MODULE_EVENTORGANIZATION' => 'newboxdefonly',
'MAIN_MODULE_EXPENSEREPORT' => 'newboxdefonly',
'MAIN_MODULE_FACTURE' => 'newboxdefonly',
'MAIN_MODULE_FOURNISSEUR' => 'newboxdefonly',
@@ -4567,8 +4568,8 @@ function migrate_productlot_path()
}
if ($dir) {
$lot->id = $obj->rowid;
$lot->ref = $obj->id; // No ref for the moment
$lot->id = (int) $obj->rowid;
$lot->ref = (string) $obj->rowid; // No ref for the moment
$lot->batch = $obj->batch;
$lot->entity = $obj->entity;
$lot->fk_product = $obj->fk_product;

View File

@@ -30,7 +30,7 @@ InvoiceReplacementShort=Replacement
InvoiceReplacementAsk=Replacement invoice for invoice
InvoiceReplacementDesc=<b>Replacement invoice</b> is used to completely replace an invoice with no payment already received.<br><br>Note: Only invoices with no payment on it can be replaced. If the invoice you replace is not yet closed, it will be automatically closed to 'abandoned'.
InvoiceAvoir=Credit note
InvoiceAvoirAsk=Credit note
InvoiceAvoirAsk=Credit note from
InvoiceAvoirAskCombo=Invoice to correct
InvoiceAvoirDesc=The <b>credit note</b> is a negative invoice used to correct the fact that an invoice shows an amount that differs from the amount actually paid (eg the customer paid too much by mistake, or will not pay the complete amount since some products were returned).
invoiceAvoirWithLines=Create Credit Note with lines from the origin invoice

View File

@@ -49,6 +49,7 @@ TotalTTCIfInvoiceSeeCompleteDataForDetail=Amount of event. Total including tax i
TypeOfEvent=Type of event
TotalForAction=Total for event %s
SecretKey=Secret key
ErrorPeriodMustBePastToAllowExport=Export into archives is allowed only if period is completely past
## logTypes
logBILL_DELETE=Customer invoice logically deleted

View File

@@ -369,6 +369,10 @@ ErrorPaymentAmountMustNotBeNull=Error, payment amount must be defined and not ze
ErrorOneLineContainsADisactivatedProduct=Error, at least one product is not or no more on sale or for purchase
ErrorCalendarIsNotYetOpenOrHasBeenClosed=This calendar is not yet open or has been closed
ErrorFieldClassNotFoundForClassName=The class "%s" managing the field type "%s" is not found.
ErrorBlockLogNeedAmountsValue=The unalterbale log object needs amounts values to be set
ErrorBlockLogNeedElement=The unalterbale log object needs element type to be set
ErrorBlockLogNeedObject=The unalterbale log object needs object to be set
ErrorBadParameterWhenCallingCreateOfBlockedLog=Bad parameter when calling create of blocked log
# Warnings
WarningParamUploadMaxFileSizeHigherThanPostMaxSize=Your PHP parameter upload_max_filesize (%s) is higher than PHP parameter post_max_size (%s). This is not a consistent setup.

View File

@@ -280,23 +280,24 @@ if ($result) {
print "</tr>\n";
if ($num > 0) {
/** @var array<int,array{name:string,htmlname:string,selling_price:float,buying_price:float,marge:float}> $group_list */
$group_list = array();
while ($objp = $db->fetch_object($result)) {
if ($agentid > 0) {
$group_id = $objp->socid;
$group_id = (int) $objp->socid;
} else {
$group_id = $objp->agent;
$group_id = (int) $objp->agent;
}
if (!isset($group_list[$group_id])) {
if ($agentid > 0) {
$group_name = $objp->name;
$group_name = (string) $objp->name;
$companystatic->id = $objp->socid;
$companystatic->name = $objp->name;
$companystatic->client = $objp->client;
$group_htmlname = $companystatic->getNomUrl(1, 'customer');
} else {
$group_name = $objp->lastname;
$group_name = (string) $objp->lastname;
$userstatic->fetch($objp->agent);
$group_htmlname = $userstatic->getFullName($langs, 0, 0, 0);
}
@@ -317,15 +318,15 @@ if ($result) {
} else {
if ($obj_seller = $db->fetch_object($resql_seller)) {
if ($obj_seller->nb > 0) {
$seller_nb = $obj_seller->nb;
$seller_nb = (int) $obj_seller->nb;
}
}
}
}
$group_list[$group_id]['selling_price'] += $objp->selling_price / $seller_nb;
$group_list[$group_id]['buying_price'] += $objp->buying_price / $seller_nb;
$group_list[$group_id]['marge'] += $objp->marge / $seller_nb;
$group_list[$group_id]['selling_price'] += (float) $objp->selling_price / $seller_nb;
$group_list[$group_id]['buying_price'] += (float) $objp->buying_price / $seller_nb;
$group_list[$group_id]['marge'] += (float) $objp->marge / $seller_nb;
}
// sort group array by sortfield

View File

@@ -1,6 +1,7 @@
<?php
/* Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
* Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2024 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
@@ -144,61 +145,61 @@ if (getDolGlobalInt('MAIN_FEATURES_LEVEL') >= 2) {
}
print '<tr class="oddeven">';
print '<td>'.$langs->trans("UseSpecificEditorName").'</td>';
print '<td><label for="MODULEBUILDER_SPECIFIC_EDITOR_NAME" class="block">'.$langs->trans("UseSpecificEditorName").'</label></td>';
print '<td>';
print '<input type="text" name="MODULEBUILDER_SPECIFIC_EDITOR_NAME" value="'.getDolGlobalString('MODULEBUILDER_SPECIFIC_EDITOR_NAME').'">';
print '<input id="MODULEBUILDER_SPECIFIC_EDITOR_NAME" type="text" name="MODULEBUILDER_SPECIFIC_EDITOR_NAME" value="'.getDolGlobalString('MODULEBUILDER_SPECIFIC_EDITOR_NAME').'">';
print '</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("UseSpecificEditorURL").'</td>';
print '<td><label for="MODULEBUILDER_SPECIFIC_EDITOR_URL" class="block">'.$langs->trans("UseSpecificEditorURL").'</label></td>';
print '<td>';
print '<input type="text" name="MODULEBUILDER_SPECIFIC_EDITOR_URL" value="'.getDolGlobalString('MODULEBUILDER_SPECIFIC_EDITOR_URL').'">';
print '<input id="MODULEBUILDER_SPECIFIC_EDITOR_URL" type="text" name="MODULEBUILDER_SPECIFIC_EDITOR_URL" value="'.getDolGlobalString('MODULEBUILDER_SPECIFIC_EDITOR_URL').'">';
print '</td>';
print '</tr>';
if (getDolGlobalInt('MAIN_FEATURES_LEVEL') >= 2) {
print '<tr class="oddeven">';
print '<td>'.$langs->trans("UseSpecificFamily").'</td>';
print '<td><label for="MODULEBUILDER_SPECIFIC_FAMILY" class="block">'.$langs->trans("UseSpecificFamily").'</label></td>';
print '<td>';
print '<input type="text" name="MODULEBUILDER_SPECIFIC_FAMILY" value="'.getDolGlobalString('MODULEBUILDER_SPECIFIC_FAMILY').'">';
print '<input id="MODULEBUILDER_SPECIFIC_FAMILY" type="text" name="MODULEBUILDER_SPECIFIC_FAMILY" value="'.getDolGlobalString('MODULEBUILDER_SPECIFIC_FAMILY').'">';
print '</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("UseSpecificAuthor").'</td>';
print '<td><label for="MODULEBUILDER_SPECIFIC_AUTHOR" class="block">'.$langs->trans("UseSpecificAuthor").'</label></td>';
print '<td>';
print '<input type="text" name="MODULEBUILDER_SPECIFIC_AUTHOR" value="'.getDolGlobalString('MODULEBUILDER_SPECIFIC_AUTHOR').'">';
print '<input id="MODULEBUILDER_SPECIFIC_AUTHOR" type="text" name="MODULEBUILDER_SPECIFIC_AUTHOR" value="'.getDolGlobalString('MODULEBUILDER_SPECIFIC_AUTHOR').'">';
print '</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("UseSpecificVersion").'</td>';
print '<td><label for="MODULEBUILDER_SPECIFIC_VERSION" class="block">'.$langs->trans("UseSpecificVersion").'</label></td>';
print '<td>';
print '<input type="text" name="MODULEBUILDER_SPECIFIC_VERSION" value="'.getDolGlobalString('MODULEBUILDER_SPECIFIC_VERSION').'">';
print '<input id="MODULEBUILDER_SPECIFIC_VERSION" type="text" name="MODULEBUILDER_SPECIFIC_VERSION" value="'.getDolGlobalString('MODULEBUILDER_SPECIFIC_VERSION').'">';
print '</td>';
print '</tr>';
}
print '<tr class="oddeven">';
print '<td>'.$langs->trans("UseSpecificReadme").'</td>';
print '<td><label for="MODULEBUILDER_SPECIFIC_README" class="block">'.$langs->trans("UseSpecificReadme").'</label></td>';
print '<td>';
print '<textarea class="centpercent" rows="20" name="MODULEBUILDER_SPECIFIC_README">'.getDolGlobalString('MODULEBUILDER_SPECIFIC_README').'</textarea>';
print '<textarea id="MODULEBUILDER_SPECIFIC_README" class="centpercent" rows="20" name="MODULEBUILDER_SPECIFIC_README">'.getDolGlobalString('MODULEBUILDER_SPECIFIC_README').'</textarea>';
print '</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("AsciiToHtmlConverter").'</td>';
print '<td><label for="MODULEBUILDER_ASCIIDOCTOR" class="block">'.$langs->trans("AsciiToHtmlConverter").'</label></td>';
print '<td>';
print '<input type="text" name="MODULEBUILDER_ASCIIDOCTOR" value="'.getDolGlobalString('MODULEBUILDER_ASCIIDOCTOR').'">';
print '<input id="MODULEBUILDER_ASCIIDOCTOR" type="text" name="MODULEBUILDER_ASCIIDOCTOR" value="'.getDolGlobalString('MODULEBUILDER_ASCIIDOCTOR').'">';
print ' '.$langs->trans("Example").': asciidoc, asciidoctor';
print '</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("AsciiToPdfConverter").'</td>';
print '<td><label for="MODULEBUILDER_ASCIIDOCTORPDF" class="block">'.$langs->trans("AsciiToPdfConverter").'</label></td>';
print '<td>';
print '<input type="text" name="MODULEBUILDER_ASCIIDOCTORPDF" value="'.getDolGlobalString('MODULEBUILDER_ASCIIDOCTORPDF').'">';
print '<input id="MODULEBUILDER_ASCIIDOCTORPDF" type="text" name="MODULEBUILDER_ASCIIDOCTORPDF" value="'.getDolGlobalString('MODULEBUILDER_ASCIIDOCTORPDF').'">';
print ' '.$langs->trans("Example").': asciidoctor-pdf';
print '</td>';
print '</tr>';

View File

@@ -1342,6 +1342,9 @@ if (empty($reshook)) {
}
}
// Actions when printing a doc from card
include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
// Actions to send emails
$triggersendname = 'PRODUCT_SENTBYMAIL';
$paramname = 'id';

View File

@@ -284,6 +284,8 @@ if (empty($reshook)) {
$action = '';
}
// Actions when printing a doc from card
include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
// Actions to build doc
$upload_dir = $conf->stock->dir_output;

View File

@@ -614,6 +614,9 @@ if (empty($reshook)) {
}
}
// Actions when printing a doc from card
include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
// Actions to send emails
$triggersendname = 'PROJECT_SENTBYMAIL';
$paramname = 'id';

View File

@@ -945,6 +945,9 @@ if (empty($reshook)) {
$upload_dir = !empty($conf->societe->multidir_output[$object->entity ?? $conf->entity]) ? $conf->societe->multidir_output[$object->entity ?? $conf->entity] : $conf->societe->dir_output;
$permissiontoadd = $user->hasRight('societe', 'creer');
include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
// Actions when printing a doc from card
include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
}
@@ -1094,12 +1097,12 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($canvasdisplayactio
}
}
$object->phone = GETPOST('phone', 'alpha');
$object->phone_mobile = (string) GETPOST("phone_mobile", 'alpha');
$object->fax = GETPOST('fax', 'alpha');
$object->email = GETPOST('email', 'email');
$object->url = GETPOST('url', 'url');
$object->capital = GETPOST('capital'); // can be null or 0 or a float value
$object->phone = GETPOST('phone', 'alpha');
$object->phone_mobile = (string) GETPOST("phone_mobile", 'alpha');
$object->fax = GETPOST('fax', 'alpha');
$object->email = GETPOST('email', 'email');
$object->url = GETPOST('url', 'url');
$object->capital = GETPOST('capital'); // can be null or 0 or a float value
$paymentTermId = GETPOSTINT('cond_reglement_id'); // can be set by default values on create page and not already in get or post variables
if (empty($paymentTermId) && !GETPOSTISSET('cond_reglement_id')) {
$paymentTermId = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID');
@@ -1109,28 +1112,28 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($canvasdisplayactio
if (empty($paymentTypeId) && !GETPOSTISSET('mode_reglement_id')) {
$paymentTypeId = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID');
}
$object->mode_reglement_id = $paymentTypeId;
$object->barcode = GETPOST('barcode', 'alphanohtml');
$object->idprof1 = GETPOST('idprof1', 'alphanohtml');
$object->idprof2 = GETPOST('idprof2', 'alphanohtml');
$object->idprof3 = GETPOST('idprof3', 'alphanohtml');
$object->idprof4 = GETPOST('idprof4', 'alphanohtml');
$object->idprof5 = GETPOST('idprof5', 'alphanohtml');
$object->idprof6 = GETPOST('idprof6', 'alphanohtml');
$object->mode_reglement_id = $paymentTypeId;
$object->barcode = GETPOST('barcode', 'alphanohtml');
$object->idprof1 = GETPOST('idprof1', 'alphanohtml');
$object->idprof2 = GETPOST('idprof2', 'alphanohtml');
$object->idprof3 = GETPOST('idprof3', 'alphanohtml');
$object->idprof4 = GETPOST('idprof4', 'alphanohtml');
$object->idprof5 = GETPOST('idprof5', 'alphanohtml');
$object->idprof6 = GETPOST('idprof6', 'alphanohtml');
$object->typent_id = GETPOSTINT('typent_id');
$object->effectif_id = GETPOSTINT('effectif_id');
$object->civility_id = GETPOST('civility_id', 'alpha');
$object->effectif_id = GETPOSTINT('effectif_id');
$object->civility_id = GETPOST('civility_id', 'alpha');
$object->tva_assuj = GETPOSTINT('assujtva_value');
$object->vat_reverse_charge = GETPOST('vat_reverse_charge') == 'on' ? 1 : 0;
$object->status = GETPOSTINT('status');
//Local Taxes
$object->localtax1_assuj = GETPOSTINT('localtax1assuj_value');
$object->localtax2_assuj = GETPOSTINT('localtax2assuj_value');
$object->localtax1_assuj = GETPOSTINT('localtax1assuj_value');
$object->localtax2_assuj = GETPOSTINT('localtax2assuj_value');
$object->localtax1_value = GETPOST('lt1', 'alpha');
$object->localtax2_value = GETPOST('lt2', 'alpha');
$object->localtax1_value = GETPOST('lt1', 'alpha');
$object->localtax2_value = GETPOST('lt2', 'alpha');
$object->tva_intra = GETPOST('tva_intra', 'alphanohtml');
@@ -1147,7 +1150,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($canvasdisplayactio
}
}
if (GETPOSTISSET('accountancy_code_buy')) {
$accountancy_code_buy = GETPOST('accountancy_code_buy', 'alpha');
$accountancy_code_buy = GETPOST('accountancy_code_buy', 'alpha');
if (empty($accountancy_code_buy) || $accountancy_code_buy == '-1') {
$object->accountancy_code_buy = '';
@@ -1159,7 +1162,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($canvasdisplayactio
$object->logo = (isset($_FILES['photo']) ? dol_sanitizeFileName($_FILES['photo']['name']) : '');
// Company logo management
$dir = $conf->societe->multidir_output[$conf->entity]."/".$object->id."/logos";
$dir = $conf->societe->multidir_output[$conf->entity]."/".$object->id."/logos";
$file_OK = (isset($_FILES['photo']) ? is_uploaded_file($_FILES['photo']['tmp_name']) : false);
if ($file_OK) {
if (image_format_supported($_FILES['photo']['name'])) {

View File

@@ -1094,6 +1094,7 @@ class Thirdparties extends DolibarrApi
* @since 7.0.0 Initial implementation
*
* @param int $id ID of the third party
* @param string $mode 'customer' or 'supplier'
* @param string $filter Filter exceptional discount. "none" will return every discount, "available" returns unapplied discounts, "used" returns applied discounts {@choice none,available,used}
* @param string $sortfield Sort field
* @param string $sortorder Sort order
@@ -1109,7 +1110,7 @@ class Thirdparties extends DolibarrApi
* @throws RestException 404
* @throws RestException 503
*/
public function getFixedAmountDiscounts($id, $filter = "none", $sortfield = "f.type", $sortorder = 'ASC')
public function getFixedAmountDiscounts($id, $mode = 'customer', $filter = "none", $sortfield = "f.type", $sortorder = 'ASC')
{
$obj_ret = array();
@@ -1130,15 +1131,27 @@ class Thirdparties extends DolibarrApi
throw new RestException(404, 'Thirdparty not found');
}
$sql = "SELECT f.ref, f.type as factype, re.fk_facture_source, re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc, re.description, re.fk_facture, re.fk_facture_line";
$sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re, ".MAIN_DB_PREFIX."facture as f";
$sql .= " WHERE f.rowid = re.fk_facture_source AND re.fk_soc = ".((int) $id);
if ($filter == "available") {
$sql .= " AND re.fk_facture IS NULL AND re.fk_facture_line IS NULL";
}
if ($filter == "used") {
$sql .= " AND (re.fk_facture IS NOT NULL OR re.fk_facture_line IS NOT NULL)";
$sql = '';
if ($mode === 'customer') {
$sql = "SELECT f.ref, f.type as factype, re.fk_facture_source, re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc, re.description, re.fk_facture, re.fk_facture_line";
$sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re, ".MAIN_DB_PREFIX."facture as f";
$sql .= " WHERE f.rowid = re.fk_facture_source AND re.fk_soc = ".((int) $id);
if ($filter == "available") {
$sql .= " AND re.fk_facture IS NULL AND re.fk_facture_line IS NULL";
}
if ($filter == "used") {
$sql .= " AND (re.fk_facture IS NOT NULL OR re.fk_facture_line IS NOT NULL)";
}
} elseif ($mode === 'supplier') {
$sql = "SELECT f.ref, f.type as factype, re.fk_invoice_supplier_source, re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc, re.description, re.fk_invoice_supplier, re.fk_invoice_supplier_line";
$sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re, ".MAIN_DB_PREFIX."facture_fourn as f";
$sql .= " WHERE f.rowid = re.fk_invoice_supplier_source AND re.fk_soc = ".((int) $id);
if ($filter == "available") {
$sql .= " AND re.fk_invoice_supplier IS NULL AND re.fk_invoice_supplier_line IS NULL";
}
if ($filter == "used") {
$sql .= " AND (re.fk_invoice_supplier IS NOT NULL OR re.fk_invoice_supplier_line IS NOT NULL)";
}
}
$sql .= $this->db->order($sortfield, $sortorder);

View File

@@ -29,12 +29,6 @@
// Load Dolibarr environment
require "../main.inc.php";
require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.class.php';
/**
* @var Conf $conf
* @var DoliDB $db
@@ -42,6 +36,10 @@ require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.class.php';
* @var Translate $langs
* @var User $user
*/
require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.class.php';
// Load translation files required by the page
$langs->loadLangs(array("companies", "bills", "orders", "suppliers", "propal", "interventions", "contracts", "products"));
@@ -508,7 +506,7 @@ if ($sql_select) {
// Filters
print '<tr class="liste_titre">';
print '<th class="liste_titre">';
print '<input class="flat" type="text" name="sref" size="8" value="'.$sref.'">';
print '<input class="flat width75" type="text" name="sref" value="'.$sref.'">';
print '</th>';
print '<th class="liste_titre nowrap center valignmiddle">'; // date
print $formother->select_month($month ? (string) $month : '-1', 'month', 1, 0, 'valignmiddle');
@@ -573,7 +571,7 @@ if ($sql_select) {
}
print '<tr class="oddeven">';
print '<td class="nobordernopadding nowrap" width="100">';
print '<td class="nobordernopadding nowraponall">';
print $documentstatic->getNomUrl(1);
print '</td>';
print '<td class="center" width="80">'.dol_print_date($db->jdate($objp->dateprint), 'day').'</td>';

View File

@@ -1241,6 +1241,9 @@ td.wordbreak img, td.wordbreakimp img {
.marginleftlarge {
margin-<?php print $left; ?>: 20px !important;
}
.marginleftlargeondesktop {
margin-<?php print $left; ?>: 20px;
}
.paddinglarge {
padding: 6px !important;
}
@@ -2280,6 +2283,10 @@ datalist {
font-size: <?php print is_numeric($fontsize) ? ((int) $fontsize + 3).'px' : $fontsize; ?> !important;
}
.marginleftlargeondesktop {
margin-<?php print $left; ?>: 0;
}
div#login_left, div#login_right {
min-width: 150px !important;
max-width: 240px !important;
@@ -4434,7 +4441,7 @@ td.border, div.tagtable div div.border {
.nobordertop, .nobordertop tr:first-of-type td {
border-top: none !important;
}
.noborderbottom, .noborderbottom tr:last-of-type td {
.noborderbottom, tr.noborderbottom td, .noborderbottom tr:last-of-type td {
border-bottom: none !important;
}
.bordertop {

View File

@@ -1397,6 +1397,9 @@ td.wordbreak img, td.wordbreakimp img {
.marginleftlarge {
margin-<?php print $left; ?>: 20px !important;
}
.marginleftlargeondesktop {
margin-<?php print $left; ?>: 20px;
}
.paddinglarge {
padding: 6px !important;
}
@@ -1587,8 +1590,12 @@ span.fa.fa-plus-circle.paddingleft {
margin-left: 1px;
}
.listofinvoicetype {
height: 28px;
min-height: 1.8em;
vertical-align: middle;
padding-top: 7px;
padding-bottom: 1px;
display: flex;
align-items: center;
}
.divsocialnetwork:not(:last-child) {
padding-<?php print $right; ?>: 20px;
@@ -2395,6 +2402,10 @@ select.widthcentpercentminusxx, span.widthcentpercentminusxx:not(.select2-select
font-size: <?php print is_numeric($fontsize) ? ($fontsize).'px' : $fontsize; ?> !important;
}
.marginleftlargeondesktop {
margin-<?php print $left; ?>: 0;
}
.login_vertical_align {
padding-left: 0;
}
@@ -2436,7 +2447,7 @@ select.widthcentpercentminusxx, span.widthcentpercentminusxx:not(.select2-select
height: 40px !important;
}
div.tabBar .listofinvoicetype table tr, div.tabBar .listofinvoicetype table tr td {
height: 28px !important;
height: 2.2em !important;
}
div.tabs div.tab a.tab {
@@ -4478,7 +4489,7 @@ td.border, div.tagtable div div.border {
.nobordertop, .nobordertop tr:first-of-type td {
border-top: none !important;
}
.noborderbottom, .noborderbottom tr:last-of-type td {
.noborderbottom, tr.noborderbottom td, .noborderbottom tr:last-of-type td {
border-bottom: none !important;
}
.bordertop {

View File

@@ -688,6 +688,8 @@ if (empty($reshook)) {
$action = 'view';
}
// Actions when printing a doc from card
include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
$permissiondellink = $user->hasRight('ticket', 'write');
include DOL_DOCUMENT_ROOT . '/core/actions_dellink.inc.php'; // Must be 'include', not 'include_once'

View File

@@ -879,6 +879,9 @@ if (empty($reshook)) {
// Actions to build doc
$upload_dir = $conf->user->dir_output;
include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
// Actions when printing a doc from card
include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
}

View File

@@ -372,7 +372,7 @@ class User extends CommonObject
public $lastsearch_values; // To store last saved search criteria for user
/**
* @var array<int,User>|array<int,array{rowid:int,id:int,fk_user:int,fk_soc:int,firstname:string,lastname:string,login:string,statut:int,entity:int,email:string,gender:string|int<-1,-1>,admin:int<0,1>,photo:string,fullpath:string,fullname:string,level:int}> Array of User (filled from fetchAll) or Array with hierarchy of user information (filled with get_full_tree()
* @var array<int,User>|array<int,array{rowid:int,id:int,fk_user:int,fk_soc:int,firstname:string,lastname:string,login:string,statut:int,entity:int,email:string,gender:string|int<-1,-1>,admin:int<0,1>,photo:string,fullpath:string,fullname:string,level:int}> Array of User (filled from fetchAll) or Array with hierarchy of user information (filled with get_full_tree())
*/
public $users = array();
/**
@@ -3923,23 +3923,26 @@ class User extends CommonObject
if ($resql) {
$i = 0;
while ($obj = $this->db->fetch_object($resql)) {
$this->users[$obj->rowid]['rowid'] = $obj->rowid;
$this->users[$obj->rowid]['id'] = $obj->rowid;
$this->users[$obj->rowid]['fk_user'] = $obj->fk_user;
$this->users[$obj->rowid]['fk_soc'] = $obj->fk_soc;
$this->users[$obj->rowid]['firstname'] = $obj->firstname;
$this->users[$obj->rowid]['lastname'] = $obj->lastname;
$this->users[$obj->rowid]['login'] = $obj->login;
$this->users[$obj->rowid]['statut'] = $obj->statut;
$this->users[$obj->rowid]['entity'] = $obj->entity;
$this->users[$obj->rowid]['email'] = $obj->email;
$this->users[$obj->rowid]['gender'] = $obj->gender;
$this->users[$obj->rowid]['admin'] = $obj->admin;
$this->users[$obj->rowid]['photo'] = $obj->photo;
// fields are filled with build_path_from_id_user
$this->users[$obj->rowid]['fullpath'] = '';
$this->users[$obj->rowid]['fullname'] = '';
$this->users[$obj->rowid]['level'] = 0;
$this->users[(int) $obj->rowid]
= array(
'rowid' => (int) $obj->rowid,
'id' => (int) $obj->rowid,
'fk_user' => (int) $obj->fk_user,
'fk_soc' => (int) $obj->fk_soc,
'firstname' => (string) $obj->firstname,
'lastname' => (string) $obj->lastname,
'login' => (string) $obj->login,
'statut' => (int) $obj->statut,
'entity' => (int) $obj->entity,
'email' => (string) $obj->email,
'gender' => (string) $obj->gender,
'admin' => (int) $obj->admin,
'photo' => (string) $obj->photo,
// fields are filled with build_path_from_id_user
'fullpath' => '',
'fullname' => '',
'level' => 0,
);
$i++;
}
} else {

View File

@@ -309,6 +309,13 @@ function analyseVarsForSqlAndScriptsInjection(&$var, $type, $stopcode = 1)
}
}
// Prevent the use of method TRACE
if ($_SERVER["REQUEST_METHOD"] == "TRACE") {
print 'Access refused with request method TRACE';
http_response_code(405);
exit();
}
// Sanity check on URL
if (!defined('NOSCANPHPSELFFORINJECTION') && !empty($_SERVER["PHP_SELF"])) {
$morevaltochecklikepost = array($_SERVER["PHP_SELF"]);

View File

@@ -253,6 +253,9 @@ class AllTests
require_once dirname(__FILE__).'/AssetModelTest.php';
$suite->addTestSuite('AssetModelTest');
require_once dirname(__FILE__).'/BlockedLogAndLNETest.php';
$suite->addTestSuite('BlockedLogAndLNETest');
// Rest
require_once dirname(__FILE__).'/RestAPIUserTest.php';
$suite->addTestSuite('RestAPIUserTest');

View File

@@ -0,0 +1,85 @@
<?php
/* Copyright (C) 2007-2017 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2023 Alexandre Janniaux <alexandre.janniaux@gmail.com>
* Copyright (C) ---Put here your own copyright and developer email---
* Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* \file test/unit/BlockedLogAndLNETest.php
* \ingroup core
* \brief PHPUnit test for the BlockedLog and LNE class.
*/
global $conf,$user,$langs,$db;
//define('TEST_DB_FORCE_TYPE','mysql'); // This is to force using mysql driver
//require_once 'PHPUnit/Autoload.php';
require_once dirname(__FILE__).'/../../htdocs/master.inc.php';
require_once dirname(__FILE__).'/../../htdocs/compta/facture/class/facture.class.php';
require_once dirname(__FILE__).'/../../htdocs/blockedlog/class/blockedlog.class.php';
require_once dirname(__FILE__).'/CommonClassTest.class.php';
if (empty($user->id)) {
print "Load permissions for admin user nb 1\n";
$user->fetch(1);
$user->loadRights();
}
$conf->global->MAIN_DISABLE_ALL_MAILS = 1;
$langs->load("main");
/**
* Class for PHPUnit tests
*
* @backupGlobals disabled
* @backupStaticAttributes enabled
* @remarks backupGlobals must be disabled to have db,conf,user and lang not erased.
*/
class BlockedLogAndLNETest extends CommonClassTest
{
/**
* testBlockedLogAndLNETest
*
* @return int
*/
public function testBlockedLogAndLNETest()
{
global $conf,$user,$langs,$db;
$conf = $this->savconf;
$user = $this->savuser;
$langs = $this->savlangs;
$db = $this->savdb;
$localobject = new BlockedLog($db);
$localobject->action = 'TEST';
$element = new Facture($db);
$element->initAsSpecimen();
$localobject->element = $element->element;
$localobject->object_data = $element;
$result = $localobject->create($user);
print __METHOD__." result=".$result."\n";
$this->assertLessThan($result, 0);
return $result;
}
// TODO Add more tests
}