Merge branch 'develop' into fix/PhanTypePossiblyInvalidDimOffset

This commit is contained in:
Laurent Destailleur 2024-03-21 12:53:59 +01:00 committed by GitHub
commit 60c626dbe4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 374 additions and 288 deletions

View file

@ -106,7 +106,7 @@ jobs:
ls -l ~/.cache/pre-commit/
- name: Convert Raw Log to Annotations
uses: mdeweerd/logToCheckStyle@2024.3.2
uses: mdeweerd/logToCheckStyle@v2024.3.4
if: ${{ failure() }}
with:
in: ${{ env.RAW_LOG }}

View file

@ -150,7 +150,7 @@ jobs:
for /f "tokens=2 delims==" %%A in ('doskey /m:err') do EXIT /B %%A
- name: Convert Raw Log to Annotations
uses: mdeweerd/logToCheckStyle@2024.3.2
uses: mdeweerd/logToCheckStyle@v2024.3.4
if: ${{ failure() }}
with:
in: ${{ env.PHPUNIT_LOG }}

View file

@ -104,7 +104,7 @@ FIX: #yogosha21416
For users:
----------
NEW: Compatibility with PHP 8.2
NEW: Compatibility with PHP 8.2 (warning must be disabled)
NEW: Module Workstation (used to enhance the module BOM and Manufacturing Order) is now stable
NEW: Add a CLI tool to regenerate all documents
NEW: Add a confirmation popup when deleting extrafields

View file

@ -10,25 +10,20 @@
return [
// # Issue statistics:
// PhanParamSignatureMismatch : 25+ occurrences
// PhanTypeMismatchReturnNullable : 20+ occurrences
// PhanPluginSuspiciousParamPosition : 15+ occurrences
// PhanUndeclaredConstant : 15+ occurrences
// PhanPluginDuplicateExpressionBinaryOp : 10+ occurrences
// PhanTypeArraySuspiciousNull : 10+ occurrences
// PhanTypeMismatchReturn : 10+ occurrences
// PhanTypeMismatchReturn : 8 occurrences
// PhanRedefineFunctionInternal : 6 occurrences
// PhanTypeArraySuspiciousNull : 6 occurrences
// PhanParamTooMany : 4 occurrences
// PhanTypeMismatchPropertyProbablyReal : 2 occurrences
// PhanTypeMismatchReturnNullable : 3 occurrences
// PhanAccessMethodProtected : 1 occurrence
// PhanAccessPropertyStaticAsNonStatic : 1 occurrence
// PhanNoopStringLiteral : 1 occurrence
// PhanPluginAlwaysReturnFunction : 1 occurrence
// Currently, file_suppressions and directory_suppressions are the only supported suppressions
'file_suppressions' => [
'htdocs/adherents/class/adherent.class.php' => ['PhanTypeMismatchReturnNullable'],
'htdocs/adherents/class/adherentstats.class.php' => ['PhanTypeMismatchReturnNullable'],
'htdocs/adherents/stats/geo.php' => ['PhanTypeArraySuspiciousNull'],
'htdocs/adherents/type.php' => ['PhanPluginDuplicateExpressionBinaryOp'],
'htdocs/admin/receiptprinter.php' => ['PhanRedefineFunctionInternal'],
'htdocs/api/class/api_documents.class.php' => ['PhanPluginDuplicateExpressionBinaryOp'],
@ -36,10 +31,7 @@ return [
'htdocs/categories/class/api_categories.class.php' => ['PhanAccessMethodProtected'],
'htdocs/categories/viewcat.php' => ['PhanPluginDuplicateExpressionBinaryOp'],
'htdocs/collab/index.php' => ['PhanParamTooMany'],
'htdocs/comm/action/class/actioncomm.class.php' => ['PhanTypeMismatchReturnNullable'],
'htdocs/comm/action/index.php' => ['PhanTypeArraySuspiciousNull'],
'htdocs/comm/mailing/card.php' => ['PhanPluginSuspiciousParamPosition'],
'htdocs/comm/propal/class/api_proposals.class.php' => ['PhanTypeMismatchReturnNullable'],
'htdocs/compta/cashcontrol/cashcontrol_card.php' => ['PhanPluginDuplicateExpressionBinaryOp'],
'htdocs/compta/prelevement/class/bonprelevement.class.php' => ['PhanParamTooMany'],
'htdocs/compta/prelevement/create.php' => ['PhanPluginSuspiciousParamPosition'],
@ -47,24 +39,15 @@ return [
'htdocs/core/class/commonobject.class.php' => ['PhanTypeMismatchReturnNullable'],
'htdocs/core/class/extrafields.class.php' => ['PhanTypeMismatchReturnNullable'],
'htdocs/core/class/html.form.class.php' => ['PhanPluginSuspiciousParamPosition'],
'htdocs/core/class/html.formprojet.class.php' => ['PhanTypeMismatchReturnNullable'],
'htdocs/core/class/smtps.class.php' => ['PhanTypeMismatchReturnNullable'],
'htdocs/core/class/stats.class.php' => ['PhanTypeMismatchReturnNullable'],
'htdocs/core/db/mysqli.class.php' => ['PhanParamSignatureMismatch'],
'htdocs/core/db/pgsql.class.php' => ['PhanParamSignatureMismatch'],
'htdocs/core/db/sqlite3.class.php' => ['PhanParamSignatureMismatch', 'PhanTypeMismatchReturnNullable'],
'htdocs/core/get_info.php' => ['PhanPluginSuspiciousParamPosition'],
'htdocs/core/lib/date.lib.php' => ['PhanTypeMismatchReturnNullable'],
'htdocs/core/lib/files.lib.php' => ['PhanPluginDuplicateExpressionBinaryOp'],
'htdocs/core/lib/functions.lib.php' => ['PhanParamTooMany', 'PhanPluginAlwaysReturnFunction', 'PhanRedefineFunctionInternal'],
'htdocs/core/lib/functions2.lib.php' => ['PhanTypeMismatchReturnNullable'],
'htdocs/core/lib/pdf.lib.php' => ['PhanTypeMismatchReturnNullable'],
'htdocs/core/lib/functions.lib.php' => ['PhanParamTooMany', 'PhanRedefineFunctionInternal'],
'htdocs/core/lib/price.lib.php' => ['PhanPluginSuspiciousParamPosition'],
'htdocs/core/lib/website.lib.php' => ['PhanTypeMismatchReturnNullable'],
'htdocs/core/modules/DolibarrModules.class.php' => ['PhanTypeMismatchReturnNullable'],
'htdocs/core/modules/movement/doc/pdf_standard.modules.php' => ['PhanPluginDuplicateExpressionBinaryOp'],
'htdocs/core/modules/mrp/doc/pdf_vinci.modules.php' => ['PhanTypeArraySuspiciousNull'],
'htdocs/core/modules/societe/modules_societe.class.php' => ['PhanTypeMismatchReturn'],
'htdocs/core/modules/syslog/mod_syslog_file.php' => ['PhanParamSignatureMismatch'],
'htdocs/core/modules/syslog/mod_syslog_syslog.php' => ['PhanParamSignatureMismatch'],
'htdocs/don/class/don.class.php' => ['PhanParamTooMany'],
@ -76,17 +59,12 @@ return [
'htdocs/mrp/class/mo.class.php' => ['PhanParamSignatureMismatch'],
'htdocs/product/admin/product_tools.php' => ['PhanNoopStringLiteral'],
'htdocs/product/class/product.class.php' => ['PhanTypeMismatchReturn'],
'htdocs/projet/class/project.class.php' => ['PhanTypeMismatchReturnNullable'],
'htdocs/projet/class/projectstats.class.php' => ['PhanTypeMismatchReturnNullable'],
'htdocs/projet/class/task.class.php' => ['PhanTypeMismatchReturnNullable'],
'htdocs/projet/tasks/list.php' => ['PhanTypeArraySuspiciousNull'],
'htdocs/public/payment/paymentok.php' => ['PhanPluginSuspiciousParamPosition'],
'htdocs/societe/class/companybankaccount.class.php' => ['PhanParamSignatureMismatch'],
'htdocs/stripe/admin/stripe.php' => ['PhanDeprecatedFunction'],
'htdocs/stripe/class/actions_stripe.class.php' => ['PhanPluginSuspiciousParamPosition'],
'htdocs/takepos/invoice.php' => ['PhanPluginSuspiciousParamPosition'],
'htdocs/variants/class/ProductCombination.class.php' => ['PhanPluginSuspiciousParamPosition'],
'htdocs/website/class/website.class.php' => ['PhanTypeMismatchReturnNullable'],
'internal' => ['PhanUndeclaredConstant'],
],
// 'directory_suppressions' => ['src/directory_name' => ['PhanIssueName1', 'PhanIssueName2']] can be manually added if needed.

View file

@ -40,6 +40,7 @@ Reservation
ACCOUNTING_ACCOUNT_CUSTOMER
ACCOUNTING_ACCOUNT_CUSTOMER_Desc
ACCOUNTING_ACCOUNT_CUSTOMER_RETAINED_WARRANTY
ACCOUNTING_ACCOUNT_EXPENSEREPORT
ACCOUNTING_ACCOUNT_SUPPLIER
ACCOUNTING_ACCOUNT_SUPPLIER_Desc
ACCOUNTING_ACCOUNT_SUSPENSE

View file

@ -560,12 +560,13 @@ class Adherent extends CommonObject
* Return translated label by the nature of a adherent (physical or moral)
*
* @param string $morphy Nature of the adherent (physical or moral)
* @param int $addbadge Add badge (1=Full label, 2=First letters only)
* @param int<0,2> $addbadge Add badge (1=Full label, 2=First letters only)
* @return string Label
*/
public function getmorphylib($morphy = '', $addbadge = 0)
{
global $langs;
$s = '';
// Clean var
if (!$morphy) {
@ -573,7 +574,6 @@ class Adherent extends CommonObject
}
if ($addbadge) {
$s = '';
$labeltoshowm = $langs->trans("Moral");
$labeltoshowp = $langs->trans("Physical");
if ($morphy == 'phy') {

View file

@ -3,6 +3,7 @@
* Copyright (c) 2005-2011 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2005-2009 Regis Houssin <regis.houssin@inodbox.com>
* Copyright (C) 2023 Waël Almoman <info@almoman.com>
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.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
@ -168,15 +169,15 @@ class AdherentStats extends Stats
/**
* Return count of member by status group by adh type, total and average
*
* @param int $numberYears Number of years to scan (0 = all)
* @return array Array with total of draft, pending, uptodate, expired, resiliated for each member type
* @param int $numberYears Number of years to scan (0 = all)
* @return array<string,array{label:string,members_draft:int,members_pending:0,members_uptodate:int,members_expired:int,members_excluded:int,members_resiliated:int,all?:float|int,total_adhtag:float|int}> Array with total of draft, pending, uptodate, expired, resiliated for each member type
*/
public function countMembersByTypeAndStatus($numberYears = 0)
{
global $user;
$now = dol_now();
$endYear = date('Y');
$endYear = (int) date('Y');
$startYear = $endYear - $numberYears;
$sql = "SELECT t.rowid as fk_adherent_type, t.libelle as label";
@ -224,7 +225,7 @@ class AdherentStats extends Stats
'members_resiliated' => (int) $objp->members_resiliated
);
$totalrow = 0;
foreach ($MembersCountArray[$objp->fk_adherent_type] as $key=>$nb) {
foreach ($MembersCountArray[$objp->fk_adherent_type] as $key => $nb) {
if ($key != 'label') {
$totalrow += $nb;
$totalstatus[$key] += $nb;
@ -244,16 +245,17 @@ class AdherentStats extends Stats
/**
* Return count of member by status group by adh type, total and average
*
* @param int $numberYears Number of years to scan (0 = all)
* @return array Array with total of draft, pending, uptodate, expired, resiliated for each member tag
* @param int $numberYears Number of years to scan (0 = all)
* @return array<string,array{label:string,members_draft:int,members_pending:0,members_uptodate:int,members_expired:int,members_excluded:int,members_resiliated:int,all?:float|int,total_adhtag:float|int}> Array with total of draft, pending, uptodate, expired, resiliated for each member tag
*/
public function countMembersByTagAndStatus($numberYears = 0)
{
global $user;
$now = dol_now();
$endYear = date('Y');
$endYear = (int) date('Y');
$startYear = $endYear - $numberYears;
$MembersCountArray = [];
$sql = "SELECT c.rowid as fk_categorie, c.label as label";
$sql .= ", COUNT(".$this->db->ifsql("d.statut = ".Adherent::STATUS_DRAFT, "'members_draft'", 'NULL').") as members_draft";
@ -282,7 +284,6 @@ class AdherentStats extends Stats
if ($result) {
$num = $this->db->num_rows($result);
$i = 0;
$MembersCountArray = [];
$totalstatus = array(
'label' => 'Total',
'members_draft' => 0,
@ -304,7 +305,7 @@ class AdherentStats extends Stats
'members_resiliated' => (int) $objp->members_resiliated
);
$totalrow = 0;
foreach ($MembersCountArray[$objp->fk_categorie] as $key=>$nb) {
foreach ($MembersCountArray[$objp->fk_categorie] as $key => $nb) {
if ($key != 'label') {
$totalrow += $nb;
$totalstatus[$key] += $nb;

View file

@ -1393,7 +1393,7 @@ class ActionComm extends CommonObject
*
* @param User $user Object user
* @param int $load_state_board Load indicator array this->nb
* @return WorkboardResponse|int Return integer <0 if KO, WorkboardResponse if OK
* @return WorkboardResponse|int<-1,1> Return integer <0 if KO, WorkboardResponse if OK
*/
public function load_board($user, $load_state_board = 0)
{
@ -1462,7 +1462,7 @@ class ActionComm extends CommonObject
}
$this->db->free($resql);
if (empty($load_state_board)) {
if (empty($load_state_board) && $response instanceof WorkboardResponse) {
return $response;
} else {
return 1;

View file

@ -4,6 +4,7 @@
* Copyright (C) 2020 Thibault FOUCART <support@ptibogxiv.net>
* Copyright (C) 2022 ATM Consulting <contact@atm-consulting.fr>
* Copyright (C) 2022 OpenDSI <support@open-dsi.fr>
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.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
@ -410,6 +411,7 @@ class Proposals extends DolibarrApi
}
$errors = [];
$updateRes = 0;
$this->db->begin();
foreach ($request_data as $TData) {

View file

@ -7269,7 +7269,7 @@ abstract class CommonObject
if (!preg_match('/search_/', $keyprefix)) { // If keyprefix is search_ or search_options_, we must just use a simple text field
require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
$doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, false, ROWS_5, '90%');
$out = $doleditor->Create(1, '', true, '', '', '', $morecss);
$out = (string) $doleditor->Create(1, '', true, '', '', '', $morecss);
} else {
$out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
}
@ -7277,7 +7277,7 @@ abstract class CommonObject
if (!preg_match('/search_/', $keyprefix)) { // If keyprefix is search_ or search_options_, we must just use a simple text field
require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
$doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, isModEnabled('fckeditor') && $conf->global->FCKEDITOR_ENABLE_SOCIETE, ROWS_5, '90%');
$out = $doleditor->Create(1, '', true, '', '', $moreparam, $morecss);
$out = (string) $doleditor->Create(1, '', true, '', '', $moreparam, $morecss);
} else {
$out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
}

View file

@ -3,6 +3,7 @@
* Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
* Copyright (C) 2018 Charlene Benke <charlie@patas-monkey.com>
* Copyright (C) 2024 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
* it under the terms of the GNU General Public License as published by
@ -686,7 +687,7 @@ class FormProjets extends Form
* @param string $morecss Add more css
* @param int $noadmininfo 0=Add admin info, 1=Disable admin info
* @param int $addcombojs 1=Add a js combo
* @return int|string The HTML select list of element or '' if nothing or -1 if KO
* @return int<-1,-1>|string The HTML select list of element or '' if nothing or -1 if KO
*/
public function selectOpportunityStatus($htmlname, $preselected = '-1', $showempty = 1, $useshortlabel = 0, $showallnone = 0, $showpercent = 0, $morecss = '', $noadmininfo = 0, $addcombojs = 0)
{
@ -701,6 +702,7 @@ class FormProjets extends Form
if ($resql) {
$num = $this->db->num_rows($resql);
$i = 0;
$sellist = '';
if ($num > 0) {
$sellist = '<select class="flat oppstatus' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '">';
if ($showempty) {
@ -841,7 +843,7 @@ class FormProjets extends Form
// Use select2 selector
if (!empty($conf->use_javascript_ajax)) {
include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
$comboenhancement = ajax_combobox($htmlNameInvoice, array(array('method'=>'getLines', 'url'=>dol_buildpath('/core/ajax/ajaxinvoiceline.php', 1), 'htmlname'=>$htmlNameInvoiceLine)), 0, 0);
$comboenhancement = ajax_combobox($htmlNameInvoice, array(array('method' => 'getLines', 'url' => dol_buildpath('/core/ajax/ajaxinvoiceline.php', 1), 'htmlname' => $htmlNameInvoiceLine)), 0, 0);
$out .= $comboenhancement;
$morecss = 'minwidth200imp maxwidth500';
}
@ -957,9 +959,9 @@ class FormProjets extends Form
$out .= $langs->trans("OppStatus".$code);
// Opportunity percent
$out.= ' / <span title="'.$langs->trans("OpportunityProbability").'"> ';
$out.= price($percent_value, 0, $langs, 1, 0).' %';
$out.= '</span>';
$out .= ' / <span title="'.$langs->trans("OpportunityProbability").'"> ';
$out .= price($percent_value, 0, $langs, 1, 0).' %';
$out .= '</span>';
} else {
$out .= "&nbsp;";
}

View file

@ -1686,6 +1686,8 @@ class SMTPs
}
$content .= "--".$this->_getBoundary('mixed').'--'."\r\n";
} else {
die("Sorry, no content");
}
return $content;

View file

@ -3,6 +3,7 @@
* Copyright (c) 2008-2013 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2012 Regis Houssin <regis.houssin@inodbox.com>
* Copyright (C) 2012 Marcos García <marcosgdf@gmail.com>
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.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
@ -75,21 +76,21 @@ abstract class Stats
public $month;
/**
* @param int $year number
* @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month
* @return array array of values by month
* @param int $year number
* @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month
* @return array<int<0,11>,array{0:int<1,12>,1:int}> Array of nb each month
*/
abstract protected function getNbByMonth($year, $format = 0);
/**
* Return nb of elements by month for several years
*
* @param int $endyear Start year
* @param int $startyear End year
* @param int $cachedelay Delay we accept for cache file (0=No read, no save of cache, -1=No read but save)
* @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month
* @param int $startmonth month of the fiscal year start min 1 max 12 ; if 1 = january
* @return array Array of values
* @param int $endyear Start year
* @param int $startyear End year
* @param int $cachedelay Delay we accept for cache file (0=No read, no save of cache, -1=No read but save)
* @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month
* @param int $startmonth month of the fiscal year start min 1 max 12 ; if 1 = january
* @return array<int<0,11>,array{0:int<1,12>,1:int}> Array of values
*/
public function getNbByMonthWithPrevYear($endyear, $startyear, $cachedelay = 0, $format = 0, $startmonth = 1)
{
@ -99,7 +100,8 @@ abstract class Stats
return array();
}
$datay = array();
$data = array(); // This is the return value
$datay = array(); // This is a work value
// Search into cache
if (!empty($cachedelay)) {
@ -127,6 +129,7 @@ abstract class Stats
if ($foundintocache) { // Cache file found and is not too old
dol_syslog(get_class($this).'::'.__FUNCTION__." read data from cache file ".$newpathofdestfile." ".$filedate.".");
$data = json_decode(file_get_contents($newpathofdestfile), true);
'@phan-var-force array<int<0,11>,array{0:int<1,12>,1:int}> $data';
} else {
$year = $startyear;
$sm = $startmonth - 1;
@ -138,19 +141,18 @@ abstract class Stats
$year++;
}
$data = array();
for ($i = 0; $i < 12; $i++) {
$data[$i][] = $datay[$endyear][($i + $sm) % 12][0];
$year = $startyear;
while ($year <= $endyear) {
// floor(($i + $sm) / 12)) is 0 if we are after the month start $sm and same year, become 1 when we reach january of next year
$data[$i][] = $datay[$year - (1 - floor(($i + $sm) / 12)) + ($sm == 0 ? 1 : 0)][($i + $sm) % 12][1];
$data[$i][] = $datay[$year - (1 - (int) floor(($i + $sm) / 12)) + ($sm == 0 ? 1 : 0)][($i + $sm) % 12][1];
$year++;
}
}
}
// Save cache file
if (empty($foundintocache) && ($cachedelay > 0 || $cachedelay == -1)) {
dol_syslog(get_class($this).'::'.__FUNCTION__." save cache file ".$newpathofdestfile." onto disk.");
@ -170,9 +172,9 @@ abstract class Stats
}
/**
* @param int $year year number
* @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month
* @return array array of values by month
* @param int $year year number
* @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month
* @return array<int<0,11>,array{0:int<1,12>,1:int|float}> Array of values by month
*/
abstract protected function getAmountByMonth($year, $format = 0);
@ -187,7 +189,7 @@ abstract class Stats
* @param int $cachedelay Delay we accept for cache file (0=No read, no save of cache, -1=No read but save)
* @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month
* @param int $startmonth month of the fiscal year start min 1 max 12 ; if 1 = january
* @return array Array of values
* @return array<int<0,11>,array<string|int|float>> Array of values
*/
public function getAmountByMonthWithPrevYear($endyear, $startyear, $cachedelay = 0, $format = 0, $startmonth = 1)
{
@ -198,6 +200,7 @@ abstract class Stats
}
$datay = array();
$data = array(); // Return value
// Search into cache
if (!empty($cachedelay)) {
@ -237,7 +240,6 @@ abstract class Stats
$year++;
}
$data = array();
// $data = array('xval'=>array(0=>xlabel,1=>yval1,2=>yval2...),...)
for ($i = 0; $i < 12; $i++) {
$data[$i][] = isset($datay[$endyear][($i + $sm) % 12]['label']) ? $datay[$endyear][($i + $sm) % 12]['label'] : $datay[$endyear][($i + $sm) % 12][0]; // set label
@ -271,17 +273,17 @@ abstract class Stats
}
/**
* @param int $year year number
* @return array array of values
* @param int $year year number
* @return array<int<0,11>,array{0:int<1,12>,1:int|float}> Array of values
*/
abstract protected function getAverageByMonth($year);
/**
* Return average of entity by month for several years
* Return average of entity by month for several years
*
* @param int $endyear Start year
* @param int $startyear End year
* @return array Array of values
* @param int $endyear Start year
* @param int $startyear End year
* @return array<array<int|float>> Array of values
*/
public function getAverageByMonthWithPrevYear($endyear, $startyear)
{
@ -290,6 +292,7 @@ abstract class Stats
}
$datay = array();
$data = array();
$year = $startyear;
while ($year <= $endyear) {
@ -297,8 +300,6 @@ abstract class Stats
$year++;
}
$data = array();
for ($i = 0; $i < 12; $i++) {
$data[$i][] = $datay[$endyear][$i][0];
$year = $startyear;
@ -312,12 +313,12 @@ abstract class Stats
}
/**
* Return count, and sum of products
* Return count, and sum of products
*
* @param int $year Year
* @param int $cachedelay Delay we accept for cache file (0=No read, no save of cache, -1=No read but save)
* @param int $limit Limit
* @return array Array of values
* @param int $year Year
* @param int $cachedelay Delay we accept for cache file (0=No read, no save of cache, -1=No read but save)
* @param int $limit Limit
* @return array<int<0,11>,array{0:int<1,12>,1:int|float}> Array of values
*/
public function getAllByProductEntry($year, $cachedelay = 0, $limit = 10)
{
@ -325,7 +326,7 @@ abstract class Stats
$data = array();
// Search into cache
// Search in cache
if (!empty($cachedelay)) {
include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php';
@ -352,6 +353,7 @@ abstract class Stats
if ($foundintocache) { // Cache file found and is not too old
dol_syslog(get_class($this).'::'.__FUNCTION__." read data from cache file ".$newpathofdestfile." ".$filedate.".");
$data = json_decode(file_get_contents($newpathofdestfile), true);
'@phan-var-force array<int<0,11>,array{0:int<1,12>,1:int|float}> $data'; // Phan can't decode json_decode's return value
} else {
// This method is defined in parent object only, not into abstract, so we disable phpstan warning
/** @phpstan-ignore-next-line */
@ -465,13 +467,13 @@ abstract class Stats
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
/**
* Renvoie le nombre de documents par mois pour une annee donnee
* Return number of documents per month for a given year
* Renvoie le nombre de documents par mois pour une annee donnee
* Return number of documents per month for a given year
*
* @param int $year Year
* @param string $sql SQL
* @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month
* @return array Array of nb each month
* @param int $year Year
* @param string $sql SQL
* @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month
* @return array<int<0,11>,array{0:int<1,12>,1:int}> Array of nb each month
*/
protected function _getNbByMonth($year, $sql, $format = 0)
{
@ -523,12 +525,12 @@ abstract class Stats
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
/**
* Return the amount per month for a given year
* Return the amount per month for a given year
*
* @param int $year Year
* @param string $sql SQL
* @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month
* @return array
* @param int $year Year
* @param string $sql SQL
* @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month
* @return array<int<0,11>,array{0:int<1,12>,1:int|float}> Array of nb each month
*/
protected function _getAmountByMonth($year, $sql, $format = 0)
{
@ -580,13 +582,12 @@ abstract class Stats
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
/**
* Renvoie le montant moyen par mois pour une annee donnee
* Return the amount average par month for a given year
*
* @param int $year Year
* @param string $sql SQL
* @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month
* @return array
* @return array<int<0,11>,array{0:int<1,12>,1:int|float}> Array of average each month
*/
protected function _getAverageByMonth($year, $sql, $format = 0)
{
@ -643,7 +644,7 @@ abstract class Stats
*
* @param string $sql SQL
* @param int $limit Limit
* @return array
* @return array<int<0,11>,array{0:int<1,12>,1:int|float}> Array of total of product refs each month
*/
protected function _getAllByProduct($sql, $limit = 10)
{
@ -682,7 +683,7 @@ abstract class Stats
/**
* Returns the summed amounts per year for a given number of past years ending now
* @param string $sql SQL
* @return array
* @return array<int,array{0:int,1:int}> Array of sum of amounts
*/
protected function _getAmountByYear($sql)
{
@ -693,7 +694,6 @@ abstract class Stats
$i = 0;
while ($i < $num) {
$row = $this->db->fetch_row($resql);
$j = (int) $row[0];
$result[] = [
0 => (int) $row[0],
1 => (int) $row[1],

View file

@ -825,55 +825,66 @@ class DoliDBMysqli extends DoliDB
public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null)
{
// phpcs:enable
// FIXME: $fulltext_keys parameter is unused
// @TODO: $fulltext_keys parameter is unused
if (empty($type)) {
$type = 'InnoDB';
}
$pk = '';
$sqluq = $sqlk = array();
// cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
// ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
$sql = "CREATE TABLE ".$table."(";
// Keys found into the array $fields: type,value,attribute,null,default,extra
// ex. : $fields['rowid'] = array(
// 'type'=>'int' or 'integer',
// 'value'=>'11',
// 'null'=>'not null',
// 'extra'=> 'auto_increment'
// );
$sql = "CREATE TABLE ".$this->sanitize($table)."(";
$i = 0;
$sqlfields = array();
foreach ($fields as $field_name => $field_desc) {
$sqlfields[$i] = $field_name." ";
$sqlfields[$i] .= $field_desc['type'];
if (preg_match("/^[^\s]/i", $field_desc['value'])) {
$sqlfields[$i] .= "(".$field_desc['value'].")";
$sqlfields[$i] = $this->sanitize($field_name)." ";
$sqlfields[$i] .= $this->sanitize($field_desc['type']);
if (!is_null($field_desc['value']) && $field_desc['value'] !== '') {
$sqlfields[$i] .= "(".$this->sanitize($field_desc['value']).")";
}
if (preg_match("/^[^\s]/i", $field_desc['attribute'])) {
$sqlfields[$i] .= " ".$field_desc['attribute'];
if (!is_null($field_desc['attribute']) && $field_desc['attribute'] !== '') {
$sqlfields[$i] .= " ".$this->sanitize($field_desc['attribute']);
}
if (preg_match("/^[^\s]/i", $field_desc['default'])) {
if ((preg_match("/null/i", $field_desc['default'])) || (preg_match("/CURRENT_TIMESTAMP/i", $field_desc['default']))) {
$sqlfields[$i] .= " default ".$field_desc['default'];
if (!is_null($field_desc['default']) && $field_desc['default'] !== '') {
if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) {
$sqlfields[$i] .= " DEFAULT ".((float) $field_desc['default']);
} elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP') {
$sqlfields[$i] .= " DEFAULT ".$this->sanitize($field_desc['default']);
} else {
$sqlfields[$i] .= " default '".$this->escape($field_desc['default'])."'";
$sqlfields[$i] .= " DEFAULT '".$this->escape($field_desc['default'])."'";
}
}
if (preg_match("/^[^\s]/i", $field_desc['null'])) {
$sqlfields[$i] .= " ".$field_desc['null'];
if (!is_null($field_desc['null']) && $field_desc['null'] !== '') {
$sqlfields[$i] .= " ".$this->sanitize($field_desc['null'], 0, 0, 1);
}
if (preg_match("/^[^\s]/i", $field_desc['extra'])) {
$sqlfields[$i] .= " ".$field_desc['extra'];
if (!is_null($field_desc['extra']) && $field_desc['extra'] !== '') {
$sqlfields[$i] .= " ".$this->sanitize($field_desc['extra'], 0, 0, 1);
}
$i++;
}
if ($primary_key != "") {
$pk = "primary key(".$primary_key.")";
$pk = "PRIMARY KEY(".$this->sanitize($primary_key).")";
}
if (is_array($unique_keys)) {
$i = 0;
foreach ($unique_keys as $key => $value) {
$sqluq[$i] = "UNIQUE KEY '".$key."' ('".$this->escape($value)."')";
$sqluq[$i] = "UNIQUE KEY '".$this->sanitize($key)."' ('".$this->escape($value)."')";
$i++;
}
}
if (is_array($keys)) {
$i = 0;
foreach ($keys as $key => $value) {
$sqlk[$i] = "KEY ".$key." (".$value.")";
$sqlk[$i] = "KEY ".$this->sanitize($key)." (".$value.")";
$i++;
}
}
@ -887,7 +898,8 @@ class DoliDBMysqli extends DoliDB
if (is_array($keys)) {
$sql .= ",".implode(',', $sqlk);
}
$sql .= ") engine=".$type;
$sql .= ")";
$sql .= " engine=".$this->sanitize($type);
if (!$this->query($sql)) {
return -1;
@ -908,7 +920,7 @@ class DoliDBMysqli extends DoliDB
// phpcs:enable
$tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
$sql = "DROP TABLE ".$tmptable;
$sql = "DROP TABLE ".$this->sanitize($tmptable);
if (!$this->query($sql)) {
return -1;
@ -928,7 +940,7 @@ class DoliDBMysqli extends DoliDB
public function DDLDescTable($table, $field = "")
{
// phpcs:enable
$sql = "DESC ".$table." ".$field;
$sql = "DESC ".$this->sanitize($table)." ".$this->sanitize($field);
dol_syslog(get_class($this)."::DDLDescTable ".$sql, LOG_DEBUG);
$this->_results = $this->query($sql);
@ -950,30 +962,32 @@ class DoliDBMysqli extends DoliDB
// phpcs:enable
// cles recherchees dans le tableau des descriptions (field_desc) : type,value,attribute,null,default,extra
// ex. : $field_desc = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
$sql = "ALTER TABLE ".$table." ADD ".$field_name." ";
$sql .= $field_desc['type'];
if (preg_match("/^[^\s]/i", $field_desc['value'])) {
if (!in_array($field_desc['type'], array('date', 'datetime')) && $field_desc['value']) {
$sql .= "(".$field_desc['value'].")";
$sql = "ALTER TABLE ".$this->sanitize($table)." ADD ".$this->sanitize($field_name)." ";
$sql .= $this->sanitize($field_desc['type']);
if (isset($field_desc['value']) && preg_match("/^[^\s]/i", $field_desc['value'])) {
if (!in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'date', 'datetime')) && $field_desc['value']) {
$sql .= "(".$this->sanitize($field_desc['value']).")";
}
}
if (isset($field_desc['attribute']) && preg_match("/^[^\s]/i", $field_desc['attribute'])) {
$sql .= " ".$field_desc['attribute'];
$sql .= " ".$this->sanitize($field_desc['attribute']);
}
if (isset($field_desc['null']) && preg_match("/^[^\s]/i", $field_desc['null'])) {
$sql .= " ".$field_desc['null'];
}
if (isset($field_desc['default']) && preg_match("/^[^\s]/i", $field_desc['default'])) {
if (preg_match("/null/i", $field_desc['default'])) {
$sql .= " default ".$field_desc['default'];
if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) {
$sql .= " DEFAULT ".((float) $field_desc['default']);
} elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP') {
$sql .= " DEFAULT ".$this->sanitize($field_desc['default']);
} else {
$sql .= " default '".$this->escape($field_desc['default'])."'";
$sql .= " DEFAULT '".$this->escape($field_desc['default'])."'";
}
}
if (isset($field_desc['extra']) && preg_match("/^[^\s]/i", $field_desc['extra'])) {
$sql .= " ".$field_desc['extra'];
$sql .= " ".$this->escape($field_desc['extra'], 0, 0, 1);
}
$sql .= " ".$field_position;
$sql .= " ".$this->escape($field_position, 0, 0, 1);
dol_syslog(get_class($this)."::DDLAddField ".$sql, LOG_DEBUG);
if ($this->query($sql)) {
@ -994,18 +1008,18 @@ class DoliDBMysqli extends DoliDB
public function DDLUpdateField($table, $field_name, $field_desc)
{
// phpcs:enable
$sql = "ALTER TABLE ".$table;
$sql .= " MODIFY COLUMN ".$field_name." ".$field_desc['type'];
$sql = "ALTER TABLE ".$this->sanitize($table);
$sql .= " MODIFY COLUMN ".$this->sanitize($field_name)." ".$this->sanitize($field_desc['type']);
if (in_array($field_desc['type'], array('double', 'tinyint', 'int', 'varchar')) && $field_desc['value']) {
$sql .= "(".$field_desc['value'].")";
$sql .= "(".$this->sanitize($field_desc['value']).")";
}
if ($field_desc['null'] == 'not null' || $field_desc['null'] == 'NOT NULL') {
// We will try to change format of column to NOT NULL. To be sure the ALTER works, we try to update fields that are NULL
if ($field_desc['type'] == 'varchar' || $field_desc['type'] == 'text') {
$sqlbis = "UPDATE ".$table." SET ".$field_name." = '".$this->escape(isset($field_desc['default']) ? $field_desc['default'] : '')."' WHERE ".$field_name." IS NULL";
$sqlbis = "UPDATE ".$this->sanitize($table)." SET ".$this->sanitize($field_name)." = '".$this->escape(isset($field_desc['default']) ? $field_desc['default'] : '')."' WHERE ".$this->sanitize($field_name)." IS NULL";
$this->query($sqlbis);
} elseif ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') {
$sqlbis = "UPDATE ".$table." SET ".$field_name." = ".((int) $this->escape(isset($field_desc['default']) ? $field_desc['default'] : 0))." WHERE ".$field_name." IS NULL";
} elseif (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) {
$sqlbis = "UPDATE ".$this->sanitize($table)." SET ".$this->sanitize($field_name)." = ".((float) $this->escape(isset($field_desc['default']) ? $field_desc['default'] : 0))." WHERE ".$this->sanitize($field_name)." IS NULL";
$this->query($sqlbis);
}
@ -1013,8 +1027,8 @@ class DoliDBMysqli extends DoliDB
}
if (isset($field_desc['default']) && $field_desc['default'] != '') {
if ($field_desc['type'] == 'double' || $field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') {
$sql .= " DEFAULT ".$this->escape($field_desc['default']);
if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) {
$sql .= " DEFAULT ".((float) $field_desc['default']);
} elseif ($field_desc['type'] != 'text') {
$sql .= " DEFAULT '".$this->escape($field_desc['default'])."'"; // Default not supported on text fields
}
@ -1041,7 +1055,7 @@ class DoliDBMysqli extends DoliDB
// phpcs:enable
$tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i', '', $field_name);
$sql = "ALTER TABLE ".$table." DROP COLUMN `".$tmp_field_name."`";
$sql = "ALTER TABLE ".$this->sanitize($table)." DROP COLUMN `".$this->sanitize($tmp_field_name)."`";
if ($this->query($sql)) {
return 1;
}

View file

@ -1068,51 +1068,63 @@ class DoliDBPgsql extends DoliDB
public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null)
{
// phpcs:enable
// FIXME: $fulltext_keys parameter is unused
// @TODO: $fulltext_keys parameter is unused
$sqlfields = array();
$sqlk = array();
$sqluq = array();
// cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
// ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
$sql = "create table ".$table."(";
// Keys found into the array $fields: type,value,attribute,null,default,extra
// ex. : $fields['rowid'] = array(
// 'type'=>'int' or 'integer',
// 'value'=>'11',
// 'null'=>'not null',
// 'extra'=> 'auto_increment'
// );
$sql = "CREATE TABLE ".$this->sanitize($table)."(";
$i = 0;
$sqlfields = array();
foreach ($fields as $field_name => $field_desc) {
$sqlfields[$i] = $field_name." ";
$sqlfields[$i] .= $field_desc['type'];
if (preg_match("/^[^\s]/i", $field_desc['value'])) {
$sqlfields[$i] .= "(".$field_desc['value'].")";
} elseif (preg_match("/^[^\s]/i", $field_desc['attribute'])) {
$sqlfields[$i] .= " ".$field_desc['attribute'];
} elseif (preg_match("/^[^\s]/i", $field_desc['default'])) {
if (preg_match("/null/i", $field_desc['default'])) {
$sqlfields[$i] .= " default ".$field_desc['default'];
$sqlfields[$i] = $this->sanitize($field_name)." ";
$sqlfields[$i] .= $this->sanitize($field_desc['type']);
if (!is_null($field_desc['value']) && $field_desc['value'] !== '') {
$sqlfields[$i] .= "(".$this->sanitize($field_desc['value']).")";
}
if (!is_null($field_desc['attribute']) && $field_desc['attribute'] !== '') {
$sqlfields[$i] .= " ".$this->sanitize($field_desc['attribute']);
}
if (!is_null($field_desc['default']) && $field_desc['default'] !== '') {
if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) {
$sqlfields[$i] .= " DEFAULT ".((float) $field_desc['default']);
} elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP') {
$sqlfields[$i] .= " DEFAULT ".$this->sanitize($field_desc['default']);
} else {
$sqlfields[$i] .= " default '".$this->escape($field_desc['default'])."'";
$sqlfields[$i] .= " DEFAULT '".$this->escape($field_desc['default'])."'";
}
} elseif (preg_match("/^[^\s]/i", $field_desc['null'])) {
$sqlfields[$i] .= " ".$field_desc['null'];
} elseif (preg_match("/^[^\s]/i", $field_desc['extra'])) {
$sqlfields[$i] .= " ".$field_desc['extra'];
}
if (!is_null($field_desc['null']) && $field_desc['null'] !== '') {
$sqlfields[$i] .= " ".$this->sanitize($field_desc['null'], 0, 0, 1);
}
if (!is_null($field_desc['extra']) && $field_desc['extra'] !== '') {
$sqlfields[$i] .= " ".$this->sanitize($field_desc['extra']);
}
$i++;
}
if ($primary_key != "") {
$pk = "primary key(".$primary_key.")";
$pk = "PRIMARY KEY(".$this->sanitize($primary_key).")";
}
if (is_array($unique_keys)) {
$i = 0;
foreach ($unique_keys as $key => $value) {
$sqluq[$i] = "UNIQUE KEY '".$key."' ('".$this->escape($value)."')";
$sqluq[$i] = "UNIQUE KEY '".$this->sanitize($key)."' ('".$this->escape($value)."')";
$i++;
}
}
if (is_array($keys)) {
$i = 0;
foreach ($keys as $key => $value) {
$sqlk[$i] = "KEY ".$key." (".$value.")";
$sqlk[$i] = "KEY ".$this->sanitize($key)." (".$value.")";
$i++;
}
}
@ -1120,15 +1132,15 @@ class DoliDBPgsql extends DoliDB
if ($primary_key != "") {
$sql .= ",".$pk;
}
if (is_array($unique_keys)) {
if ($unique_keys != "") {
$sql .= ",".implode(',', $sqluq);
}
if (is_array($keys)) {
$sql .= ",".implode(',', $sqlk);
}
$sql .= ") type=".$type;
$sql .= ")";
//$sql .= " engine=".$this->sanitize($type);
dol_syslog($sql, LOG_DEBUG);
if (!$this->query($sql)) {
return -1;
} else {
@ -1148,7 +1160,7 @@ class DoliDBPgsql extends DoliDB
// phpcs:enable
$tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
$sql = "DROP TABLE ".$tmptable;
$sql = "DROP TABLE ".$this->sanitize($tmptable);
if (!$this->query($sql)) {
return -1;
@ -1157,31 +1169,6 @@ class DoliDBPgsql extends DoliDB
}
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Create a user to connect to database
*
* @param string $dolibarr_main_db_host Ip server
* @param string $dolibarr_main_db_user Name of user to create
* @param string $dolibarr_main_db_pass Password of user to create
* @param string $dolibarr_main_db_name Database name where user must be granted
* @return int Return integer <0 if KO, >=0 if OK
*/
public function DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name)
{
// phpcs:enable
// Note: using ' on user does not works with pgsql
$sql = "CREATE USER ".$this->escape($dolibarr_main_db_user)." with password '".$this->escape($dolibarr_main_db_pass)."'";
dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
$resql = $this->query($sql);
if (!$resql) {
return -1;
}
return 1;
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Return a pointer of line with description of a table or field
@ -1219,30 +1206,32 @@ class DoliDBPgsql extends DoliDB
// phpcs:enable
// cles recherchees dans le tableau des descriptions (field_desc) : type,value,attribute,null,default,extra
// ex. : $field_desc = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
$sql = "ALTER TABLE ".$table." ADD ".$field_name." ";
$sql .= $field_desc['type'];
if (preg_match("/^[^\s]/i", $field_desc['value'])) {
if (!in_array($field_desc['type'], array('smallint', 'int', 'date', 'datetime')) && $field_desc['value']) {
$sql .= "(".$field_desc['value'].")";
$sql = "ALTER TABLE ".$this->sanitize($table)." ADD ".$this->sanitize($field_name)." ";
$sql .= $this->sanitize($field_desc['type']);
if (isset($field_desc['value']) && preg_match("/^[^\s]/i", $field_desc['value'])) {
if (!in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'date', 'datetime')) && $field_desc['value']) {
$sql .= "(".$this->sanitize($field_desc['value']).")";
}
}
if (preg_match("/^[^\s]/i", $field_desc['attribute'])) {
$sql .= " ".$field_desc['attribute'];
if (isset($field_desc['attribute']) && preg_match("/^[^\s]/i", $field_desc['attribute'])) {
$sql .= " ".$this->sanitize($field_desc['attribute']);
}
if (preg_match("/^[^\s]/i", $field_desc['null'])) {
if (isset($field_desc['null']) && preg_match("/^[^\s]/i", $field_desc['null'])) {
$sql .= " ".$field_desc['null'];
}
if (preg_match("/^[^\s]/i", $field_desc['default'])) {
if (preg_match("/null/i", $field_desc['default'])) {
$sql .= " default ".$field_desc['default'];
if (isset($field_desc['default']) && preg_match("/^[^\s]/i", $field_desc['default'])) {
if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) {
$sql .= " DEFAULT ".((float) $field_desc['default']);
} elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP') {
$sql .= " DEFAULT ".$this->sanitize($field_desc['default']);
} else {
$sql .= " default '".$this->escape($field_desc['default'])."'";
$sql .= " DEFAULT '".$this->escape($field_desc['default'])."'";
}
}
if (preg_match("/^[^\s]/i", $field_desc['extra'])) {
$sql .= " ".$field_desc['extra'];
if (isset($field_desc['extra']) && preg_match("/^[^\s]/i", $field_desc['extra'])) {
$sql .= " ".$this->escape($field_desc['extra'], 0, 0, 1);
}
$sql .= " ".$field_position;
$sql .= " ".$this->escape($field_position, 0, 0, 1);
dol_syslog($sql, LOG_DEBUG);
if (!$this -> query($sql)) {
@ -1263,30 +1252,30 @@ class DoliDBPgsql extends DoliDB
public function DDLUpdateField($table, $field_name, $field_desc)
{
// phpcs:enable
$sql = "ALTER TABLE ".$table;
$sql .= " ALTER COLUMN ".$this->escape($field_name)." TYPE ".$field_desc['type'];
$sql = "ALTER TABLE ".$this->sanitize($table);
$sql .= " ALTER COLUMN ".$this->sanitize($field_name)." TYPE ".$this->sanitize($field_desc['type']);
if (preg_match("/^[^\s]/i", $field_desc['value'])) {
if (!in_array($field_desc['type'], array('smallint', 'int', 'date', 'datetime')) && $field_desc['value']) {
$sql .= "(".$field_desc['value'].")";
$sql .= "(".$this->sanitize($field_desc['value']).")";
}
}
if ($field_desc['null'] == 'not null' || $field_desc['null'] == 'NOT NULL') {
// We will try to change format of column to NOT NULL. To be sure the ALTER works, we try to update fields that are NULL
if ($field_desc['type'] == 'varchar' || $field_desc['type'] == 'text') {
$sqlbis = "UPDATE ".$table." SET ".$this->escape($field_name)." = '".$this->escape(isset($field_desc['default']) ? $field_desc['default'] : '')."' WHERE ".$this->escape($field_name)." IS NULL";
$sqlbis = "UPDATE ".$this->sanitize($table)." SET ".$this->escape($field_name)." = '".$this->escape(isset($field_desc['default']) ? $field_desc['default'] : '')."' WHERE ".$this->escape($field_name)." IS NULL";
$this->query($sqlbis);
} elseif ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') {
$sqlbis = "UPDATE ".$table." SET ".$this->escape($field_name)." = ".((int) $this->escape(isset($field_desc['default']) ? $field_desc['default'] : 0))." WHERE ".$this->escape($field_name)." IS NULL";
} elseif (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) {
$sqlbis = "UPDATE ".$this->sanitize($table)." SET ".$this->escape($field_name)." = ".((float) $this->escape(isset($field_desc['default']) ? $field_desc['default'] : 0))." WHERE ".$this->escape($field_name)." IS NULL";
$this->query($sqlbis);
}
}
if (isset($field_desc['default']) && $field_desc['default'] != '') {
if ($field_desc['type'] == 'double' || $field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') {
$sql .= " DEFAULT ".$this->escape($field_desc['default']);
} elseif ($field_desc['type'] != 'text') {
$sql .= " DEFAULT '".$this->escape($field_desc['default'])."'"; // Default not supported on text fields
if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) {
$sql .= ", ALTER COLUMN ".$this->sanitize($field_name)." SET DEFAULT ".((float) $field_desc['default']);
} elseif ($field_desc['type'] != 'text') { // Default not supported on text fields ?
$sql .= ", ALTER COLUMN ".$this->sanitize($field_name)." SET DEFAULT '".$this->escape($field_desc['default'])."'";
}
}
@ -1310,7 +1299,7 @@ class DoliDBPgsql extends DoliDB
// phpcs:enable
$tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i', '', $field_name);
$sql = "ALTER TABLE ".$table." DROP COLUMN ".$tmp_field_name;
$sql = "ALTER TABLE ".$this->sanitize($table)." DROP COLUMN ".$this->sanitize($tmp_field_name);
if (!$this->query($sql)) {
$this->error = $this->lasterror();
return -1;
@ -1318,6 +1307,31 @@ class DoliDBPgsql extends DoliDB
return 1;
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Create a user to connect to database
*
* @param string $dolibarr_main_db_host Ip server
* @param string $dolibarr_main_db_user Name of user to create
* @param string $dolibarr_main_db_pass Password of user to create
* @param string $dolibarr_main_db_name Database name where user must be granted
* @return int Return integer <0 if KO, >=0 if OK
*/
public function DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name)
{
// phpcs:enable
// Note: using ' on user does not works with pgsql
$sql = "CREATE USER ".$this->sanitize($dolibarr_main_db_user)." with password '".$this->escape($dolibarr_main_db_pass)."'";
dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
$resql = $this->query($sql);
if (!$resql) {
return -1;
}
return 1;
}
/**
* Return charset used to store data in database
*

View file

@ -389,14 +389,14 @@ class DoliDBSqlite3 extends DoliDB
}
/**
* Execute a SQL request and return the resultset
* Execute a SQL request and return the resultset
*
* @param string $query SQL query string
* @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollbock to savepoint if error (this allow to have some request with errors inside global transactions).
* @param string $query SQL query string
* @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollbock to savepoint if error (this allow to have some request with errors inside global transactions).
* Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints.
* @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...)
* @param int $result_mode Result mode (not used with sqlite)
* @return bool|SQLite3Result Resultset of answer
* @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...)
* @param int $result_mode Result mode (not used with sqlite)
* @return bool|SQLite3Result|null Resultset of answer
*/
public function query($query, $usesavepoint = 0, $type = 'auto', $result_mode = 0)
{
@ -970,51 +970,63 @@ class DoliDBSqlite3 extends DoliDB
public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null)
{
// phpcs:enable
// FIXME: $fulltext_keys parameter is unused
// @TODO: $fulltext_keys parameter is unused
$sqlfields = array();
$sqlk = array();
$sqluq = array();
// cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
// ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
$sql = "create table ".$table."(";
// Keys found into the array $fields: type,value,attribute,null,default,extra
// ex. : $fields['rowid'] = array(
// 'type'=>'int' or 'integer',
// 'value'=>'11',
// 'null'=>'not null',
// 'extra'=> 'auto_increment'
// );
$sql = "CREATE TABLE ".$this->sanitize($table)."(";
$i = 0;
$sqlfields = array();
foreach ($fields as $field_name => $field_desc) {
$sqlfields[$i] = $field_name." ";
$sqlfields[$i] .= $field_desc['type'];
if (preg_match("/^[^\s]/i", $field_desc['value'])) {
$sqlfields[$i] .= "(".$field_desc['value'].")";
} elseif (preg_match("/^[^\s]/i", $field_desc['attribute'])) {
$sqlfields[$i] .= " ".$field_desc['attribute'];
} elseif (preg_match("/^[^\s]/i", $field_desc['default'])) {
if (preg_match("/null/i", $field_desc['default'])) {
$sqlfields[$i] .= " default ".$field_desc['default'];
$sqlfields[$i] = $this->sanitize($field_name)." ";
$sqlfields[$i] .= $this->sanitize($field_desc['type']);
if (!is_null($field_desc['value']) && $field_desc['value'] !== '') {
$sqlfields[$i] .= "(".$this->sanitize($field_desc['value']).")";
}
if (!is_null($field_desc['attribute']) && $field_desc['attribute'] !== '') {
$sqlfields[$i] .= " ".$this->sanitize($field_desc['attribute']);
}
if (!is_null($field_desc['default']) && $field_desc['default'] !== '') {
if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) {
$sqlfields[$i] .= " DEFAULT ".((float) $field_desc['default']);
} elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP') {
$sqlfields[$i] .= " DEFAULT ".$this->sanitize($field_desc['default']);
} else {
$sqlfields[$i] .= " default '".$this->escape($field_desc['default'])."'";
$sqlfields[$i] .= " DEFAULT '".$this->escape($field_desc['default'])."'";
}
} elseif (preg_match("/^[^\s]/i", $field_desc['null'])) {
$sqlfields[$i] .= " ".$field_desc['null'];
} elseif (preg_match("/^[^\s]/i", $field_desc['extra'])) {
$sqlfields[$i] .= " ".$field_desc['extra'];
}
if (!is_null($field_desc['null']) && $field_desc['null'] !== '') {
$sqlfields[$i] .= " ".$this->sanitize($field_desc['null'], 0, 0, 1);
}
if (!is_null($field_desc['extra']) && $field_desc['extra'] !== '') {
$sqlfields[$i] .= " ".$this->sanitize($field_desc['extra']);
}
$i++;
}
if ($primary_key != "") {
$pk = "primary key(".$primary_key.")";
$pk = "PRIMARY KEY(".$this->sanitize($primary_key).")";
}
if (is_array($unique_keys)) {
$i = 0;
foreach ($unique_keys as $key => $value) {
$sqluq[$i] = "UNIQUE KEY '".$key."' ('".$this->escape($value)."')";
$sqluq[$i] = "UNIQUE KEY '".$this->sanitize($key)."' ('".$this->escape($value)."')";
$i++;
}
}
if (is_array($keys)) {
$i = 0;
foreach ($keys as $key => $value) {
$sqlk[$i] = "KEY ".$key." (".$value.")";
$sqlk[$i] = "KEY ".$this->sanitize($key)." (".$value.")";
$i++;
}
}
@ -1022,19 +1034,20 @@ class DoliDBSqlite3 extends DoliDB
if ($primary_key != "") {
$sql .= ",".$pk;
}
if (is_array($unique_keys)) {
if ($unique_keys != "") {
$sql .= ",".implode(',', $sqluq);
}
if (is_array($keys)) {
$sql .= ",".implode(',', $sqlk);
}
$sql .= ") type=".$type;
$sql .= ")";
//$sql .= " engine=".$this->sanitize($type);
dol_syslog($sql, LOG_DEBUG);
if (!$this -> query($sql)) {
if (!$this->query($sql)) {
return -1;
} else {
return 1;
}
return 1;
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
@ -1105,16 +1118,18 @@ class DoliDBSqlite3 extends DoliDB
$sql .= " ".$field_desc['null'];
}
if (preg_match("/^[^\s]/i", $field_desc['default'])) {
if (preg_match("/null/i", $field_desc['default'])) {
$sql .= " default ".$field_desc['default'];
if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) {
$sql .= " DEFAULT ".((float) $field_desc['default']);
} elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP') {
$sql .= " DEFAULT ".$this->sanitize($field_desc['default']);
} else {
$sql .= " default '".$this->escape($field_desc['default'])."'";
$sql .= " DEFAULT '".$this->escape($field_desc['default'])."'";
}
}
if (preg_match("/^[^\s]/i", $field_desc['extra'])) {
$sql .= " ".$field_desc['extra'];
if (isset($field_desc['extra']) && preg_match("/^[^\s]/i", $field_desc['extra'])) {
$sql .= " ".$this->escape($field_desc['extra'], 0, 0, 1);
}
$sql .= " ".$field_position;
$sql .= " ".$this->escape($field_position, 0, 0, 1);
dol_syslog(get_class($this)."::DDLAddField ".$sql, LOG_DEBUG);
if (!$this->query($sql)) {
@ -1135,10 +1150,10 @@ class DoliDBSqlite3 extends DoliDB
public function DDLUpdateField($table, $field_name, $field_desc)
{
// phpcs:enable
$sql = "ALTER TABLE ".$table;
$sql .= " MODIFY COLUMN ".$field_name." ".$field_desc['type'];
$sql = "ALTER TABLE ".$this->sanitize($table);
$sql .= " MODIFY COLUMN ".$this->sanitize(($field_name)." ".$this->sanitize($field_desc['type']);
if ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int' || $field_desc['type'] == 'varchar') {
$sql .= "(".$field_desc['value'].")";
$sql .= "(".$this->sanitize($field_desc['value']).")";
}
dol_syslog(get_class($this)."::DDLUpdateField ".$sql, LOG_DEBUG);
@ -1161,7 +1176,7 @@ class DoliDBSqlite3 extends DoliDB
// phpcs:enable
$tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i', '', $field_name);
$sql = "ALTER TABLE ".$table." DROP COLUMN `".$tmp_field_name."`";
$sql = "ALTER TABLE ".$this->sanitize($table)." DROP COLUMN `".$this->sanitize($tmp_field_name)."`";
if (!$this->query($sql)) {
$this->error = $this->lasterror();
return -1;

View file

@ -1005,7 +1005,7 @@ function num_public_holiday($timestampStart, $timestampEnd, $country_code = '',
* @param int $timestampEnd Timestamp end UTC
* @param int $lastday Last day is included, 0: no, 1:yes
* @return int Number of days
* @seealso num_public_holiday(), num_open_day()
* @see also num_public_holiday(), num_open_day()
*/
function num_between_day($timestampStart, $timestampEnd, $lastday = 0)
{
@ -1016,6 +1016,8 @@ function num_between_day($timestampStart, $timestampEnd, $lastday = 0)
$bit = 1;
}
$nbjours = (int) floor(($timestampEnd - $timestampStart) / (60 * 60 * 24)) + 1 - $bit;
} else {
$nbjours = 0;
}
//print ($timestampEnd - $timestampStart) - $lastday;
return $nbjours;

View file

@ -1424,6 +1424,9 @@ function get_next_value($db, $mask, $table, $field, $where = '', $objsoc = '', $
$maskuser_maskafter = $maskuser_value;
$numFinal = str_replace($maskuser_maskbefore, $maskuser_maskafter, $numFinal);
}
} else {
$numFinal = "ErrorBadMode";
dol_syslog("functions2::get_next_value ErrorBadMode '$mode'", LOG_ERR);
}
dol_syslog("functions2::get_next_value return ".$numFinal, LOG_DEBUG);

View file

@ -1288,12 +1288,12 @@ function createNewDictionnary($modulename, $file, $namedic, $dictionnaires = nul
}
$columns = array(
'rowid' => array('type' => 'integer(11)'),
'code' => array('type' => 'varchar(255) NOT NULL'),
'label' => array('type' => 'varchar(255) NOT NULL'),
'position' => array('type' => 'integer(11) NULL'),
'use_default' => array('type' => 'varchar(255) DEFAULT 1'),
'active' => array('type' => 'integer')
'rowid' => array('type' => 'integer', 'value' => 11, 'extra' => 'AUTO_INCREMENT PRIMARY KEY'),
'code' => array('type' => 'varchar', 'value' => 255, 'null'=>'NOT NULL'),
'label' => array('type' => 'varchar', 'value' => 255, 'null'=>'NOT NULL'),
'position' => array('type' => 'integer', 'value' => 11, 'null'=>'NULL'),
'use_default' => array('type' => 'varchar', 'value' => 11, 'default'=>'1'),
'active' => array('type' => 'integer', 'value' => 3)
);
@ -1309,13 +1309,13 @@ function createNewDictionnary($modulename, $file, $namedic, $dictionnaires = nul
}
}
// check if tablename exist in Database and create it if not
$query = "SHOW TABLES LIKE '" . MAIN_DB_PREFIX.strtolower($namedic) . "'";
$query = "SHOW TABLES LIKE '" . $db->sanitize(MAIN_DB_PREFIX.strtolower($namedic)) . "'";
$checkTable = $db->query($query);
if ($checkTable && $db->num_rows($checkTable) > 0) {
setEventMessages($langs->trans("ErrorTableExist", $namedic), null, 'errors');
return;
} else {
$_results = $db->DDLCreateTable(MAIN_DB_PREFIX.strtolower($namedic), $columns, $primaryKey, "InnoDB");
$_results = $db->DDLCreateTable(MAIN_DB_PREFIX.strtolower($namedic), $columns, $primaryKey, "");
if ($_results < 0) {
dol_print_error($db);
$langs->load("errors");

View file

@ -1018,6 +1018,7 @@ function pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_
$outputlangs->load("dict");
$line = '';
$reg = array();
$marginwithfooter = 0; // Return value
$dims = $pdf->getPageDimensions();
@ -1356,9 +1357,9 @@ function pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_
if (getDolGlobalString('PDF_USE_GETALIASNBPAGE_FOR_TOTAL')) {
// $pagination = $pdf->getAliasNumPage().' / '.$pdf->getAliasNbPages(); // works with $pdf->Cell
$pagination = $pdf->PageNo().' / '.$pdf->getAliasNbPages(); // seems to not works with all fonts like ru_UK
$pagination = $pdf->PageNo().' / '.$pdf->getAliasNbPages(); // seems to not work with all fonts like ru_UK
} else {
$pagination = $pdf->PageNo().' / '.$pdf->getNumPages(); // seems to always work even with $pdf->Cell. But some users has reported wrong nb (no way to reproduce)
$pagination = $pdf->PageNo().' / '.$pdf->getNumPages(); // seems to always work even with $pdf->Cell. But some users have reported wrong nb (no way to reproduce)
}
$pdf->MultiCell(18, 2, $pagination, 0, 'R', 0);

View file

@ -837,6 +837,8 @@ function getStructuredData($type, $data = array())
}
}'."\n";
$ret .= '</script>'."\n";
} else {
$ret = '';
}
return $ret;
}

View file

@ -806,6 +806,8 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it
} else {
$content = nl2br($content);
}
} else {
$content = '';
}
return $content;
@ -1124,7 +1126,7 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it
*
* @param string $reldir Relative directory where to scan files. Example: '/install/mysql/' or '/module/sql/'
* @param string $onlywithsuffix Only with the defined suffix
* @return int Return integer <=0 if KO, >0 if OK
* @return int<0,1> Return integer <=0 if KO, >0 if OK
*/
protected function _load_tables($reldir, $onlywithsuffix = '')
{
@ -1133,6 +1135,7 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it
$error = 0;
$dirfound = 0;
$ok = 1;
if (empty($reldir)) {
return 1;
@ -1140,9 +1143,8 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it
include_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
$ok = 1;
foreach ($conf->file->dol_document_root as $dirroot) {
if ($ok) {
if ($ok == 1) {
$dirsql = $dirroot.$reldir;
$ok = 0;
@ -1293,7 +1295,7 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it
}
if (!$dirfound) {
dol_syslog("A module ask to load sql files into ".$reldir." but this directory was not found.", LOG_WARNING);
dol_syslog("A module wants to load sql files from ".$reldir." but this directory was not found.", LOG_WARNING);
}
return $ok;
}

View file

@ -243,7 +243,7 @@ class doc_generic_invoice_odt extends ModelePDFFactures
$object->fetch_thirdparty();
$dir = $conf->facture->dir_output;
$dir = empty($conf->facture->multidir_output[$object->entity]) ? $conf->facture->dir_output : $conf->facture->multidir_output[$object->entity];
$objectref = dol_sanitizeFileName($object->ref);
if (!preg_match('/specimen/i', $objectref)) {
$dir .= "/".$objectref;

View file

@ -255,13 +255,14 @@ abstract class ModeleAccountancyCode extends CommonNumRefGenerator
* @param DoliDB $db Database handler
* @param Societe $societe Third party object
* @param string $type 'customer' or 'supplier'
* @return int >=0 if OK, <0 if KO
* @return int<-1,1> >=0 if success, -1 if failure
*/
public function get_code($db, $societe, $type = '')
{
// phpcs:enable
global $langs;
return $langs->trans("NotAvailable");
dol_syslog(get_class($this)."::get_code".$langs->trans("NotAvailable"), LOG_ERR);
return -1;
}
}

View file

@ -1898,13 +1898,13 @@ class Product extends CommonObject
while ($obj = $this->db->fetch_object($result)) {
//print 'lang='.$obj->lang.' current='.$current_lang.'<br>';
if ($obj->lang == $current_lang) { // si on a les traduct. dans la langue courante on les charge en infos principales.
$this->label = $obj->label;
$this->label = $obj->label;
$this->description = $obj->description;
$this->other = $obj->other;
$this->other = $obj->other;
}
$this->multilangs["$obj->lang"]["label"] = $obj->label;
$this->multilangs["$obj->lang"]["description"] = $obj->description;
$this->multilangs["$obj->lang"]["other"] = $obj->other;
$this->multilangs[(string) $obj->lang]["label"] = $obj->label;
$this->multilangs[(string) $obj->lang]["description"] = $obj->description;
$this->multilangs[(string) $obj->lang]["other"] = $obj->other;
}
return 1;
} else {

View file

@ -1697,6 +1697,7 @@ class Project extends CommonObject
global $langs, $conf;
$error = 0;
$clone_project_id = 0; // For static toolcheck
dol_syslog("createFromClone clone_contact=".json_encode($clone_contact)." clone_task=".json_encode($clone_task)." clone_project_file=".json_encode($clone_project_file)." clone_note=".json_encode($clone_note)." move_date=".json_encode($move_date), LOG_DEBUG);
@ -1900,7 +1901,7 @@ class Project extends CommonObject
unset($clone_project->context['createfromclone']);
if (!$error) {
if (!$error && $clone_project_id != 0) {
$this->db->commit();
return $clone_project_id;
} else {

View file

@ -1,6 +1,7 @@
<?php
/* Lead
* Copyright (C) 2014-2015 Florian HENRY <florian.henry@open-concept.pro>
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.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
@ -289,7 +290,7 @@ class ProjectStats extends Stats
* @param int $startyear End year
* @param int $cachedelay Delay we accept for cache file (0=No read, no save of cache, -1=No read but save)
* @param int $wonlostfilter Add a filter on status won/lost
* @return array|int Array of values or <0 if error
* @return array|int<-1,-1> Array of values or <0 if error
*/
public function getWeightedAmountByMonthWithPrevYear($endyear, $startyear, $cachedelay = 0, $wonlostfilter = 1)
{
@ -328,6 +329,7 @@ class ProjectStats extends Stats
if ($foundintocache) { // Cache file found and is not too old
dol_syslog(get_class($this).'::'.__FUNCTION__." read data from cache file ".$newpathofdestfile." ".$filedate.".");
$data = json_decode(file_get_contents($newpathofdestfile), true);
'@phan-var-force array $data'; // Phan can not interpret json_decode
} else {
$year = $startyear;
while ($year <= $endyear) {
@ -438,6 +440,7 @@ class ProjectStats extends Stats
if ($foundintocache) { // Cache file found and is not too old
dol_syslog(get_class($this).'::'.__FUNCTION__." read data from cache file ".$newpathofdestfile." ".$filedate.".");
$data = json_decode(file_get_contents($newpathofdestfile), true);
'@phan-var-force array $data'; // Phan can not interpret json_decode
} else {
$year = $startyear;
while ($year <= $endyear) {

View file

@ -2051,9 +2051,10 @@ class Task extends CommonObjectLine
$this->error = $clone_task->error;
$error++;
}
// End
if (!$error) {
if ($error) {
$clone_task_id = 0; // For static tool check
} else {
$clone_task_id = $clone_task->id;
$clone_task_ref = $clone_task->ref;

View file

@ -2152,7 +2152,7 @@ if ($action != 'dopayment') {
if (getDolGlobalString('PAYPAL_API_INTEGRAL_OR_PAYPALONLY') != 'integral') {
print '<div style="line-height: 1em">&nbsp;</div>';
}
print '<span class="fa fa-paypal"></span> <input class="" type="submit" id="dopayment_paypal" name="dopayment_paypal" value="'.$langs->trans("PaypalDoPayment").'">';
print '<span class="fab fa-paypal"></span> <input class="" type="submit" id="dopayment_paypal" name="dopayment_paypal" value="'.$langs->trans("PaypalDoPayment").'">';
if (getDolGlobalString('PAYPAL_API_INTEGRAL_OR_PAYPALONLY') == 'integral') {
print '<br>';
print '<span class="buttonpaymentsmall">'.$langs->trans("CreditOrDebitCard").'</span><span class="buttonpaymentsmall"> - </span>';

View file

@ -4,6 +4,7 @@
* Copyright (C) 2017 Saasprov <saasprov@gmail.com>
* Copyright (C) 2018-2022 Thibault FOUCART <support@ptibogxiv.net>
* Copyright (C) 2018 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.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
@ -256,6 +257,7 @@ if (empty($conf->stripeconnect->enabled)) {
}
}
$endpoint->url = $url;
// @phan-suppress-next-line PhanDeprecatedFunction
$endpoint->save();
if ($endpoint->status == 'enabled') {
@ -328,6 +330,7 @@ if (empty($conf->stripeconnect->enabled)) {
}
}
$endpoint->url = $url;
// @phan-suppress-next-line PhanDeprecatedFunction
$endpoint->save();
if ($endpoint->status == 'enabled') {
print '<a class="reposition" href="'.$_SERVER['PHP_SELF'].'?action=ipn&webhook='.$endpoint->id.'&status=0">';

View file

@ -1868,6 +1868,8 @@ class Website extends CommonObject
$numOfPageDest = $this->extractNumberFromFilename($fileNeeded['name']);
$differences = $this->showDifferences($destContent, $sourceContent, array($numOfPageDest,$numOfPageSource));
$differences['file_destination'] = $fileNeeded;
} else {
$differences = array();
}
return $differences;
}

View file

@ -48,6 +48,41 @@ $conf->global->MAIN_DISABLE_ALL_MAILS = 1;
*/
class DoliDBTest extends CommonClassTest
{
/**
* testDDLUpdateField
*
* @return int
*/
public function testDDLCreateTable()
{
global $conf,$user,$langs,$db;
$conf = $this->savconf;
$user = $this->savuser;
$langs = $this->savlangs;
$db = $this->savdb;
$namedic = MAIN_DB_PREFIX.'tmptesttabletoremove';
$res = $db->DDLDropTable($namedic);
$columns = array(
'rowid' => array('type' => 'integer', 'value' => 11, 'AUTO_INCREMENT PRIMARY KEY'),
'code' => array('type' => 'varchar', 'value' => 255, 'null'=>'NOT NULL'),
'label' => array('type' => 'varchar', 'value' => 255, 'null'=>'NOT NULL'),
'position' => array('type' => 'integer', 'value' => 11, 'null'=>'NULL'),
'use_default' => array('type' => 'varchar', 'value' => 11, 'default'=>'1'),
'active' => array('type' => 'integer', 'value' => 3)
);
$primaryKey = 'rowid';
print __METHOD__.' db->type = '.$db->type."\n";
$res = $db->DDLCreateTable($namedic, $columns, $primaryKey, "");
$this->assertEquals(1, $res);
print __METHOD__." result=".$res."\n";
}
/**
* testDDLUpdateField
*
@ -81,9 +116,10 @@ class DoliDBTest extends CommonClassTest
print __METHOD__." result=".$result."\n";
// TODO Use $savtype and $savnull instead of hard coded
$field_desc = array('type' => 'varchar', 'value' => '16', 'null' => 'NOT NULL');
$field_desc = array('type'=>'varchar', 'value'=>'16', 'null'=>'NOT NULL', 'default'=>'aaaabbbbccccdddd');
$result = $db->DDLUpdateField($db->prefix().'c_paper_format', 'code', $field_desc);
$this->assertEquals(1, $result);
print __METHOD__." result=".$result."\n";