diff --git a/dev/translation/ignore_translation_keys.lst b/dev/translation/ignore_translation_keys.lst index d85ac6636da..506c03fab85 100644 --- a/dev/translation/ignore_translation_keys.lst +++ b/dev/translation/ignore_translation_keys.lst @@ -676,7 +676,6 @@ RECUR RSS RateIndirect Re-Open -Rechercher ReconciledBy RecordNotFound RecruitmentJobPosition @@ -808,8 +807,6 @@ SupplierMissingRef Synchronize Syslog TLS/STARTTLS -TLSv1 -TLSv1.2 TYPE_ Tabs Tag diff --git a/htdocs/accountancy/admin/index.php b/htdocs/accountancy/admin/index.php index ce20d740c98..04acb1c0350 100644 --- a/htdocs/accountancy/admin/index.php +++ b/htdocs/accountancy/admin/index.php @@ -158,8 +158,8 @@ if ($action == 'updatemode') { $error = 0; $accounting_modes = array( - 'RECETTES-DEPENSES', - 'CREANCES-DETTES' + 'CREANCES-DETTES', + 'RECETTES-DEPENSES' ); $accounting_mode = GETPOST('accounting_mode', 'alpha'); diff --git a/htdocs/accountancy/class/bookkeeping.class.php b/htdocs/accountancy/class/bookkeeping.class.php index 42a2b14ec06..8ee2279fc2c 100644 --- a/htdocs/accountancy/class/bookkeeping.class.php +++ b/htdocs/accountancy/class/bookkeeping.class.php @@ -2,7 +2,7 @@ /* Copyright (C) 2014-2017 Olivier Geffroy * Copyright (C) 2015-2022 Alexandre Spangaro * Copyright (C) 2015-2020 Florian Henry - * Copyright (C) 2018-2024 Frédéric France + * Copyright (C) 2018-2025 Frédéric France * Copyright (C) 2024-2025 MDW * Copyright (C) 2024 Jose MARTINEZ * @@ -2617,7 +2617,7 @@ class BookKeeping extends CommonObject * @param string $thirdpartyname Thirdparty name * @param string $reference Reference of the element * @param string $labelaccount Label of the accounting account - * @param string $full 0=Default, 1=Keep label intact (no trunc so HTML content is not corrupted) + * @param int<0,1> $full 0=Default, 1=Keep label intact (no trunc so HTML content is not corrupted) * @return string Label of the operation */ public function accountingLabelForOperation($thirdpartyname, $reference, $labelaccount, $full = 0) diff --git a/htdocs/accountancy/journal/treasuryjournal.php b/htdocs/accountancy/journal/treasuryjournal.php index dec35a92c65..c3a1cf26cf9 100644 --- a/htdocs/accountancy/journal/treasuryjournal.php +++ b/htdocs/accountancy/journal/treasuryjournal.php @@ -7,7 +7,7 @@ * Copyright (C) 2013-2021 Alexandre Spangaro * Copyright (C) 2013-2014 Florian Henry * Copyright (C) 2013-2014 Olivier Geffroy - * Copyright (C) 2017-2018 Frédéric France + * Copyright (C) 2017-2025 Frédéric France * Copyright (C) 2018 Ferran Marcet * * This program is free software; you can redistribute it and/or modify @@ -42,6 +42,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php'; * @var Conf $conf * @var DoliDB $db * @var HookManager $hookmanager + * @var Societe $mysoc * @var Translate $langs * @var User $user */ @@ -1129,7 +1130,7 @@ $journal_label = $langs->transnoentitiesnoconv($accountingjournalstatic->label); $MAXNBERRORS = 5; // Write bookkeeping -if ($action == 'writebookkeeping' && $user->hasRight('accounting', 'bind', 'write')) { +if ($action == 'writebookkeeping' /* && $user->hasRight('accounting', 'bind', 'write') */) { // Test on permission already done foreach ($tabpay as $payment_id => $payment) { $accountInfos = $tabaccount[$payment["fk_bank_account"]]; @@ -1346,7 +1347,7 @@ if ($action == 'writebookkeeping' && $user->hasRight('accounting', 'bind', 'writ $param .= '&date_endmonth='.$date_endmonth; $param .= '&date_endyear='.$date_endyear; $param .= '&in_bookkeeping='.$in_bookkeeping; - header("Location: ".$_SERVER['PHP_SELF'].($param ? '?'.$param : '')); + header("Location: " . $_SERVER['PHP_SELF'] . '?' . $param); exit; } } diff --git a/htdocs/admin/modules.php b/htdocs/admin/modules.php index a80dc11596a..952ac0f902e 100644 --- a/htdocs/admin/modules.php +++ b/htdocs/admin/modules.php @@ -8,8 +8,8 @@ * Copyright (C) 2015 Jean-François Ferry * Copyright (C) 2015 Raphaël Doursenaud * Copyright (C) 2018 Nicolas ZABOURI - * Copyright (C) 2021-2024 Frédéric France - * Copyright (C) 2024 MDW + * Copyright (C) 2021-2025 Frédéric France + * Copyright (C) 2024 MDW * * 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 @@ -1347,7 +1347,7 @@ if ($mode == 'marketplace') {
- + ">trans('Reset') ?>   diff --git a/htdocs/ai/admin/custom_prompt.php b/htdocs/ai/admin/custom_prompt.php index f9ae1a1f941..803f718c5bd 100644 --- a/htdocs/ai/admin/custom_prompt.php +++ b/htdocs/ai/admin/custom_prompt.php @@ -1,7 +1,7 @@ * Copyright (C) 2022 Alice Adminson - * Copyright (C) 2024 Frédéric France + * Copyright (C) 2024-2025 Frédéric France * Coryright (C) 2024 Alexandre Spangaro * * This program is free software: you can redistribute it and/or modify @@ -54,6 +54,7 @@ $pre_prompt = GETPOST('prePrompt'); $post_prompt = GETPOST('postPrompt'); $blacklists = GETPOST('blacklists'); $test = GETPOST('test'); +$key = (string) GETPOST('key', 'alpha'); if (empty($action)) { $action = 'edit'; @@ -80,16 +81,16 @@ $aiservice = getDolGlobalString('AI_API_SERVICE', 'chatgpt'); // Setup conf for AI model $formSetup->formHiddenInputs['action'] = "updatefeaturemodel"; -foreach ($arrayofaifeatures as $key => $val) { - $newkey = $key; - if (preg_match('/^text/', $key)) { +foreach ($arrayofaifeatures as $featurekey => $feature) { + $newkey = $featurekey; + if (preg_match('/^text/', $featurekey)) { $newkey = 'textgeneration'; } - $item = $formSetup->newItem('AI_API_'.strtoupper($aiservice).'_MODEL_'.$val["function"]); // Name of constant must end with _KEY so it is encrypted when saved into database. + $item = $formSetup->newItem('AI_API_'.strtoupper($aiservice).'_MODEL_'.$feature["function"]); // Name of constant must end with _KEY so it is encrypted when saved into database. if ($arrayofai[$aiservice][$newkey] != 'na') { - $item->nameText = $langs->trans("AI_API_MODEL_".$val["function"]).' ('.$langs->trans("Default").' = '.$arrayofai[$aiservice][$newkey].')'; + $item->nameText = $langs->trans("AI_API_MODEL_".$feature["function"]).' ('.$langs->trans("Default").' = '.$arrayofai[$aiservice][$newkey].')'; } else { - $item->nameText = $langs->trans("AI_API_MODEL_".$val["function"]).' ('.$langs->trans("None").')'; + $item->nameText = $langs->trans("AI_API_MODEL_".$feature["function"]).' ('.$langs->trans("None").')'; } $item->cssClass = 'minwidth500 input'; } @@ -158,8 +159,6 @@ if ($action == 'update' && !$cancel && !$test) { // Update entry if ($action == 'updatePrompts' && !$test) { - $key = GETPOST('key', 'alpha'); - $blacklistArray = array_filter(array_map('trim', explode(',', $blacklists))); $currentConfigurations[$key] = [ @@ -187,8 +186,6 @@ if ($action == 'updatePrompts' && $test) { // Delete entry if ($action == 'confirm_deleteproperty' && GETPOST('confirm') == 'yes') { - $key = GETPOST('key', 'alpha'); - if (isset($currentConfigurations[$key])) { unset($currentConfigurations[$key]); @@ -276,10 +273,10 @@ if ($action == 'create') { // Combo list of AI features $out .= ''; $out .= ajax_combobox("functioncode"); @@ -290,8 +287,8 @@ if ($action == 'create') { var changedValue = $(this).val(); console.log(changedValue); var arrayplaceholder = {'; - foreach ($arrayofaifeatures as $key => $val) { - $out .= dol_escape_js($key).': \''.dol_escape_js(empty($val['placeholder']) ? '' : $val['placeholder']).'\','; + foreach ($arrayofaifeatures as $featurekey => $feature) { + $out .= dol_escape_js($featurekey).': \''.dol_escape_js(empty($feature['placeholder']) ? '' : $feature['placeholder']).'\','; } $out .= '} jQuery("#prePromptInput'.dol_escape_js($key).'").val(arrayplaceholder[changedValue]); @@ -350,22 +347,22 @@ if ($action == 'edit' || $action == 'create' || $action == 'deleteproperty') { $out = ''; if (!empty($currentConfigurations)) { - foreach ($currentConfigurations as $key => $config) { - if (!empty($key) && !preg_match('/^[a-z]+$/i', $key)) { // Ignore empty saved setup + foreach ($currentConfigurations as $confkey => $config) { + if (!empty($confkey) && !preg_match('/^[a-z]+$/i', $confkey)) { // Ignore empty saved setup continue; } $out .= '
'; $out .= ''; - $out .= ''; + $out .= ''; $out .= ''; $out .= ''; $out .= ''; $out .= ''; $out .= ''; - $out .= ''; $out .= ''; $out .= ''; @@ -377,7 +374,7 @@ if ($action == 'edit' || $action == 'create' || $action == 'deleteproperty') { $out .= ''.$langs->trans("Pre-Prompt").''; $out .= ''; $out .= ''; $out .= ''; @@ -386,14 +383,14 @@ if ($action == 'edit' || $action == 'create' || $action == 'deleteproperty') { $out .= ''.$langs->trans("Post-Prompt").''; $out .= ''; $out .= ''; $out .= ''; - $out .= ''; + $out .= ''; $out .= ''; $out .= ''; $out .= ''; @@ -405,10 +402,10 @@ if ($action == 'edit' || $action == 'create' || $action == 'deleteproperty') { $formmail = new FormMail($db); $formmail->withaiprompt = 'html'; // set format - $showlinktoai = $key; // 'textgenerationemail', 'textgenerationwebpage', 'imagegeneration', ... + $showlinktoai = $confkey; // 'textgenerationemail', 'textgenerationwebpage', 'imagegeneration', ... $showlinktoailabel = $langs->trans("ToTest"); - $htmlname = $key; - $onlyenhancements = $key; + $htmlname = $confkey; + $onlyenhancements = $confkey; // Fill $out include DOL_DOCUMENT_ROOT.'/core/tpl/formlayoutai.tpl.php'; @@ -421,7 +418,7 @@ if ($action == 'edit' || $action == 'create' || $action == 'deleteproperty') { $out .= ''; $out .= '
'.$arrayofaifeatures[$key]['picto'].' '.$langs->trans($arrayofaifeatures[$key]['label']); - $out .= ''.img_delete().''; + $out .= ''.$arrayofaifeatures[$confkey]['picto'].' '.$langs->trans($arrayofaifeatures[$confkey]['label']); + $out .= ''.img_delete().''; $out .= '
'; - $out .= ''; + $out .= ''; $out .= '
'; - $out .= ''; + $out .= ''; $out .= '
'.$form->textwithpicto($langs->trans("BlackListWords"), $langs->trans("BlackListWordsHelp")).''; - $out .= ''; + $out .= ''; $out .= '
'; - $out .= '
'; + $out .= '
'; $out .= '
'; diff --git a/htdocs/ai/lib/ai.lib.php b/htdocs/ai/lib/ai.lib.php index fc893dbabfc..07748b80cb2 100644 --- a/htdocs/ai/lib/ai.lib.php +++ b/htdocs/ai/lib/ai.lib.php @@ -1,6 +1,6 @@ - * Copyright (C) 2024 Frédéric France + * Copyright (C) 2024-2025 Frédéric France * Copyright (C) 2024 MDW * * This program is free software: you can redistribute it and/or modify @@ -36,13 +36,13 @@ function getListOfAIFeatures() global $langs; $arrayofaifeatures = array( - 'textgenerationemail' => array('label' => $langs->trans('TextGeneration').' ('.$langs->trans("EmailContent").')', 'picto' => '', 'status' => 'dolibarr', 'function' => 'TEXT', 'placeholder' => AI::AI_DEFAULT_PROMPT_FOR_EMAIL), - 'textgenerationwebpage' => array('label' => $langs->trans('TextGeneration').' ('.$langs->trans("WebsitePage").')', 'picto' => '', 'status' => 'dolibarr', 'function' => 'TEXT', 'placeholder' => AI::AI_DEFAULT_PROMPT_FOR_WEBPAGE), + 'textgenerationemail' => array('label' => $langs->trans('TextGeneration').' ('.$langs->trans("EmailContent").')', 'picto' => '', 'status' => 'dolibarr', 'function' => 'TEXT', 'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_EMAIL), + 'textgenerationwebpage' => array('label' => $langs->trans('TextGeneration').' ('.$langs->trans("WebsitePage").')', 'picto' => '', 'status' => 'dolibarr', 'function' => 'TEXT', 'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_WEBPAGE), 'textgeneration' => array('label' => $langs->trans('TextGeneration').' ('.$langs->trans("Other").')', 'picto' => '', 'status' => 'notused', 'function' => 'TEXT'), - 'texttranslation' => array('label' => $langs->trans('TextTranslation'), 'picto' => '', 'status'=>'dolibarr', 'function' => 'TEXT', 'placeholder' => AI::AI_DEFAULT_PROMPT_FOR_TEXT_TRANSLATION), - 'textsummarize' => array('label' => $langs->trans('TextSummarize'), 'picto' => '', 'status'=>'dolibarr', 'function' => 'TEXT', 'placeholder' => AI::AI_DEFAULT_PROMPT_FOR_TEXT_SUMMARIZE), - 'textrephrase' => array('label' => $langs->trans('TextRephraser'), 'picto' => '', 'status'=>'dolibarr', 'function' => 'TEXT', 'placeholder' => AI::AI_DEFAULT_PROMPT_FOR_TEXT_REPHRASER), + 'texttranslation' => array('label' => $langs->trans('TextTranslation'), 'picto' => '', 'status'=>'dolibarr', 'function' => 'TEXT', 'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_TEXT_TRANSLATION), + 'textsummarize' => array('label' => $langs->trans('TextSummarize'), 'picto' => '', 'status'=>'dolibarr', 'function' => 'TEXT', 'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_TEXT_SUMMARIZE), + 'textrephrase' => array('label' => $langs->trans('TextRephraser'), 'picto' => '', 'status'=>'dolibarr', 'function' => 'TEXT', 'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_TEXT_REPHRASER), 'imagegeneration' => array('label' => 'ImageGeneration', 'picto' => '', 'status' => 'notused', 'function' => 'IMAGE'), 'videogeneration' => array('label' => 'VideoGeneration', 'picto' => '', 'status' => 'notused', 'function' => 'VIDEO'), diff --git a/htdocs/comm/action/list.php b/htdocs/comm/action/list.php index 6d75d72d26e..416ba6b69cf 100644 --- a/htdocs/comm/action/list.php +++ b/htdocs/comm/action/list.php @@ -4,7 +4,7 @@ * Copyright (C) 2004-2016 Laurent Destailleur * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2017 Open-DSI - * Copyright (C) 2018-2024 Frédéric France + * Copyright (C) 2018-2025 Frédéric France * Copyright (C) 2020 Tobias Sekan * Copyright (C) 2024-2025 MDW * Copyright (C) 2024 Alexandre Spangaro @@ -499,9 +499,16 @@ if (!empty($actioncode)) { } else { if (is_array($actioncode)) { // Remove all -1 values - $actioncode = array_filter($actioncode, function ($value) { - return ((string) $value !== '-1'); - }); + $actioncode = array_filter( + $actioncode, + /** + * @param string $value + * @return bool + */ + function ($value) { + return ((string) $value !== '-1'); + } + ); if (count($actioncode)) { $sql .= " AND c.code IN (".$db->sanitize("'".implode("','", $actioncode)."'", 1).")"; } diff --git a/htdocs/comm/card.php b/htdocs/comm/card.php index 58f80f68070..209f3ba322c 100644 --- a/htdocs/comm/card.php +++ b/htdocs/comm/card.php @@ -375,7 +375,7 @@ if ($object->id > 0) { print ''; // Nature Prospect/Customer/Supplier - print ''; diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index d4b52424ed4..5079537629e 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -1450,7 +1450,7 @@ if (empty($reshook)) { } // Standard or deposit invoice, not from a Predefined template invoice - if ((GETPOST('type') == Facture::TYPE_STANDARD || GETPOST('type') == Facture::TYPE_DEPOSIT || GETPOST('type') == Facture::TYPE_PROFORMA || (GETPOST('type') == Facture::TYPE_SITUATION && !GETPOST('situations'))) && GETPOST('fac_rec') <= 0) { + if ((GETPOST('type') == Facture::TYPE_STANDARD || GETPOST('type') == Facture::TYPE_DEPOSIT || GETPOST('type') == Facture::TYPE_PROFORMA || (GETPOST('type') == Facture::TYPE_SITUATION && GETPOSTINT('situations') < 0)) && GETPOST('fac_rec') <= 0) { $typeamount = GETPOST('typedeposit', 'aZ09'); $valuestandardinvoice = price2num(str_replace('%', '', GETPOST('valuestandardinvoice', 'alpha')), 'MU'); $valuedeposit = price2num(str_replace('%', '', GETPOST('valuedeposit', 'alpha')), 'MU'); @@ -1991,7 +1991,7 @@ if (empty($reshook)) { } // Situation invoices - if (GETPOST('type') == Facture::TYPE_SITUATION && GETPOST('situations')) { + if (GETPOST('type') == Facture::TYPE_SITUATION && GETPOSTINT('situations') > 0) { if (empty($dateinvoice)) { $error++; $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")); diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index be4f13b3db7..fa291961362 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -5244,6 +5244,11 @@ class Facture extends CommonInvoice } $sql .= " ORDER BY f.ref"; + if (getDolGlobalInt('LIST_OF_QUALIFIED_INVOICES_LIMIT_DEFINED') > 0) { + $sql .= " DESC"; //order by + $sql .= " LIMIT " . getDolGlobalInt('LIST_OF_QUALIFIED_INVOICES_LIMIT_DEFINED'); + } + dol_syslog(get_class($this)."::list_qualified_avoir_invoices", LOG_DEBUG); $resql = $this->db->query($sql); if ($resql) { diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php index dc601a65eba..f9beed97340 100644 --- a/htdocs/compta/facture/list.php +++ b/htdocs/compta/facture/list.php @@ -614,13 +614,63 @@ if ($action == 'makepayment_confirm' && $user->hasRight('facture', 'paiement')) if (!empty($listofbills)) { $nbwithdrawrequestok = 0; foreach ($listofbills as $aBill) { - $db->begin(); - $result = $aBill->demande_prelevement($user, $aBill->resteapayer, 'direct-debit', 'facture'); - if ($result > 0) { - $db->commit(); - $nbwithdrawrequestok++; + // Note: The 2 following SQL requests are wrong but it works because we have one record into pfd for one record into pl and for into p for the same fk_facture_fourn. + // The table prelevement and prelevement_lignes and must be removed in future and merged into prelevement_demande + // Step 1: Move field fk_... of llx_prelevement into llx_prelevement_lignes + // Step 2: Move field fk_... + status into prelevement_demande. + $pending = 0; + // Get pending requests open with no transfer receipt yet + $sql = "SELECT SUM(pfd.amount) as amount"; + $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_demande as pfd"; + //if ($type == 'bank-transfer') { + //$sql .= " WHERE pfd.fk_facture_fourn = ".((int) $aBill->id); + //} else { + $sql .= " WHERE pfd.fk_facture = ".((int) $aBill->id); + //} + $sql .= " AND pfd.traite = 0"; + //$sql .= " AND pfd.type = 'ban'"; + $resql = $db->query($sql); + if ($resql) { + $obj = $db->fetch_object($resql); + if ($obj) { + $pending += (float) $obj->amount; + } } else { - $db->rollback(); + dol_print_error($db); + } + // Get pending request with a transfer receipt generated but not yet processed + $sqlPending = "SELECT SUM(pl.amount) as amount"; + $sqlPending .= " FROM ".$db->prefix()."prelevement_lignes as pl"; + $sqlPending .= " INNER JOIN ".$db->prefix()."prelevement as p ON p.fk_prelevement_lignes = pl.rowid"; + //if ($type == 'bank-transfer') { + //$sqlPending .= " WHERE p.fk_facture_fourn = ".((int) $aBill->id); + //} else { + $sqlPending .= " WHERE p.fk_facture = ".((int) $aBill->id); + //} + $sqlPending .= " AND (pl.statut IS NULL OR pl.statut = 0)"; + $resPending = $db->query($sqlPending); + if ($resPending) { + if ($objPending = $db->fetch_object($resPending)) { + $pending += (float) $objPending->amount; + } + } + $db->free($resPending); + + $requestAmount = $aBill->resteapayer - $pending; + + $db->begin(); + $result = $aBill->demande_prelevement($user, $requestAmount, 'direct-debit', 'facture'); + if ($requestAmount > 0) { + if ($result > 0) { + $db->commit(); + $nbwithdrawrequestok++; + } else { + $db->rollback(); + setEventMessages($aBill->error, $aBill->errors, 'errors'); + } + } else { + $aBill->error = 'WithdrawRequestErrorNilAmount'; + $aBill->errors[] = $aBill->error; setEventMessages($aBill->error, $aBill->errors, 'errors'); } } diff --git a/htdocs/compta/facture/prelevement.php b/htdocs/compta/facture/prelevement.php index 3c164359ec2..192e458cf26 100644 --- a/htdocs/compta/facture/prelevement.php +++ b/htdocs/compta/facture/prelevement.php @@ -1,5 +1,4 @@ * Copyright (C) 2004 Eric Seigne * Copyright (C) 2004-2016 Laurent Destailleur @@ -722,7 +721,49 @@ if ($object->id > 0) { // For which amount ? + // Note: The 2 following SQL requests are wrong but it works because we have one record into pfd for one record into pl and for into p for the same fk_facture_fourn. + // The table prelevement and prelevement_lignes and must be removed in future and merged into prelevement_demande + // Step 1: Move field fk_... of llx_prelevement into llx_prelevement_lignes + // Step 2: Move field fk_... + status into prelevement_demande. + $pending = 0; + // Get pending requests open with no transfer receipt yet + $sql = "SELECT SUM(pfd.amount) as amount"; + $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_demande as pfd"; + if ($type == 'bank-transfer') { + $sql .= " WHERE pfd.fk_facture_fourn = ".((int) $object->id); + } else { + $sql .= " WHERE pfd.fk_facture = ".((int) $object->id); + } + $sql .= " AND pfd.traite = 0"; + //$sql .= " AND pfd.type = 'ban'"; + $resql = $db->query($sql); + if ($resql) { + $obj = $db->fetch_object($resql); + if ($obj) { + $pending += (float) $obj->amount; + } + } else { + dol_print_error($db); + } + // Get pending request with a transfer receipt generated but not yet processed + $sqlPending = "SELECT SUM(pl.amount) as amount"; + $sqlPending .= " FROM ".$db->prefix()."prelevement_lignes as pl"; + $sqlPending .= " INNER JOIN ".$db->prefix()."prelevement as p ON p.fk_prelevement_lignes = pl.rowid"; + if ($type == 'bank-transfer') { + $sqlPending .= " WHERE p.fk_facture_fourn = ".((int) $object->id); + } else { + $sqlPending .= " WHERE p.fk_facture = ".((int) $object->id); + } + $sqlPending .= " AND (pl.statut IS NULL OR pl.statut = 0)"; + $resPending = $db->query($sqlPending); + if ($resPending) { + if ($objPending = $db->fetch_object($resPending)) { + $pending += (float) $objPending->amount; + } + } + $db->free($resPending); + /* $sql = "SELECT SUM(pfd.amount) as amount"; $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_demande as pfd"; if ($type == 'bank-transfer') { @@ -737,12 +778,12 @@ if ($object->id > 0) { if ($resql) { $obj = $db->fetch_object($resql); if ($obj) { - $pending = $obj->amount; + $pendingAmount = $obj->amount; } } else { dol_print_error($db); } - + */ /* * Buttons diff --git a/htdocs/core/class/html.formsetup.class.php b/htdocs/core/class/html.formsetup.class.php index a41b8a3cc42..f1e60578050 100644 --- a/htdocs/core/class/html.formsetup.class.php +++ b/htdocs/core/class/html.formsetup.class.php @@ -817,6 +817,8 @@ class FormSetupItem $val_const = GETPOST($this->confKey, 'restricthtml'); } elseif ($this->type == 'email') { $val_const = GETPOST($this->confKey, 'alphawithlgt'); + } elseif ($this->type == 'number') { + $val_const = GETPOSTINT($this->confKey); } else { $val_const = GETPOST($this->confKey, 'alphanohtml'); } @@ -1411,6 +1413,31 @@ class FormSetupItem return $this; } + /** + * Set type of input as number + * @param int $min minimum value for input number + * @param int $max maximum value for input number + * @param int $step legal number intervals + * + * @return self + */ + public function setAsNumber($min = null, $max = null, $step = null) + { + $this->type = 'number'; //for GETPOSTINT + $this->fieldAttr['type'] = 'number'; //generic thanks to generateAttributesStringFromArray + if (!is_null($min)) { + $this->fieldAttr['min'] = $min; + } + if (!is_null($max)) { + $this->fieldAttr['max'] = $max; + } + if (!is_null($step)) { + $this->fieldAttr['step'] = $step; + } + return $this; + } + + /** * Set type of input as string * diff --git a/htdocs/core/modules/commande/doc/pdf_einstein.modules.php b/htdocs/core/modules/commande/doc/pdf_einstein.modules.php index 765e3035aa5..cd4c68a5965 100644 --- a/htdocs/core/modules/commande/doc/pdf_einstein.modules.php +++ b/htdocs/core/modules/commande/doc/pdf_einstein.modules.php @@ -1602,7 +1602,7 @@ class pdf_einstein extends ModelePDFCommandes $companystatic = new Societe($this->db); $companystatic->fetch($object->contact->fk_soc); $carac_client_name_shipping = pdfBuildThirdpartyName($object->contact, $outputlangs); - $carac_client_shipping = pdf_build_address($outputlangs, $this->emetteur, $companystatic, $object->contact, ($usecontact ? 1 : 0), 'target', $object); + $carac_client_shipping = pdf_build_address($outputlangs, $this->emetteur, $companystatic, $object->contact, 1, 'target', $object); } else { $carac_client_name_shipping = pdfBuildThirdpartyName($object->thirdparty, $outputlangs); $carac_client_shipping = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'target', $object); diff --git a/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php b/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php index 7eb3cb951b4..993325c6f0b 100644 --- a/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php +++ b/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php @@ -1798,7 +1798,7 @@ class pdf_eratosthene extends ModelePDFCommandes $companystatic = new Societe($this->db); $companystatic->fetch($object->contact->fk_soc); $carac_client_name_shipping = pdfBuildThirdpartyName($object->contact, $outputlangs); - $carac_client_shipping = pdf_build_address($outputlangs, $this->emetteur, $companystatic, $object->contact, ($usecontact ? 1 : 0), 'target', $object); + $carac_client_shipping = pdf_build_address($outputlangs, $this->emetteur, $companystatic, $object->contact, 1, 'target', $object); } else { $carac_client_name_shipping = pdfBuildThirdpartyName($object->thirdparty, $outputlangs); $carac_client_shipping = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'target', $object); diff --git a/htdocs/core/tpl/login.tpl.php b/htdocs/core/tpl/login.tpl.php index 8d437a2803a..c2ef622e722 100644 --- a/htdocs/core/tpl/login.tpl.php +++ b/htdocs/core/tpl/login.tpl.php @@ -318,8 +318,10 @@ if ($disablenofollow) { if ($passwordInput.is('[type=password]')) { $passwordInput.attr('type', 'text'); + jQuery('#togglepassword .fa-eye').attr('class', 'fa fa-eye-slash'); } else { $passwordInput.attr('type', 'password'); + jQuery('#togglepassword .fa-eye-slash').attr('class', 'fa fa-eye'); } return false; // This prevents the click from reloading the page diff --git a/htdocs/fourn/facture/list.php b/htdocs/fourn/facture/list.php index 64deb435293..d746699db86 100644 --- a/htdocs/fourn/facture/list.php +++ b/htdocs/fourn/facture/list.php @@ -406,13 +406,62 @@ if (empty($reshook)) { if (!empty($listofbills)) { $nbwithdrawrequestok = 0; foreach ($listofbills as $aBill) { - $db->begin(); - $result = $aBill->demande_prelevement($user, $aBill->resteapayer, 'bank-transfer', 'supplier_invoice'); - if ($result > 0) { - $db->commit(); - $nbwithdrawrequestok++; + // Note: The 2 following SQL requests are wrong but it works because we have one record into pfd for one record into pl and for into p for the same fk_facture_fourn. + // The table prelevement and prelevement_lignes and must be removed in future and merged into prelevement_demande + // Step 1: Move field fk_... of llx_prelevement into llx_prelevement_lignes + // Step 2: Move field fk_... + status into prelevement_demande. + $pending = 0; + // Get pending requests open with no transfer receipt yet + $sql = "SELECT SUM(pfd.amount) as amount"; + $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_demande as pfd"; + //if ($type == 'bank-transfer') { + $sql .= " WHERE pfd.fk_facture_fourn = ".((int) $aBill->id); + //} else { + // $sql .= " WHERE pfd.fk_facture = ".((int) $aBill->id); + //} + $sql .= " AND pfd.traite = 0"; + //$sql .= " AND pfd.type = 'ban'"; + $resql = $db->query($sql); + if ($resql) { + $obj = $db->fetch_object($resql); + if ($obj) { + $pending += (float) $obj->amount; + } } else { - $db->rollback(); + dol_print_error($db); + } + // Get pending request with a transfer receipt generated but not yet processed + $sqlPending = "SELECT SUM(pl.amount) as amount"; + $sqlPending .= " FROM ".$db->prefix()."prelevement_lignes as pl"; + $sqlPending .= " INNER JOIN ".$db->prefix()."prelevement as p ON p.fk_prelevement_lignes = pl.rowid"; + //if ($type == 'bank-transfer') { + $sqlPending .= " WHERE p.fk_facture_fourn = ".((int) $aBill->id); + //} else { + // $sqlPending .= " WHERE p.fk_facture = ".((int) $aBill->id); + //} + $sqlPending .= " AND (pl.statut IS NULL OR pl.statut = 0)"; + $resPending = $db->query($sqlPending); + if ($resPending) { + if ($objPending = $db->fetch_object($resPending)) { + $pending += (float) $objPending->amount; + } + } + $db->free($resPending); + + $requestAmount = $aBill->resteapayer - $pending; + if ($requestAmount > 0) { + $db->begin(); + $result = $aBill->demande_prelevement($user, $requestAmount, 'bank-transfer', 'supplier_invoice'); + if ($result > 0) { + $db->commit(); + $nbwithdrawrequestok++; + } else { + $db->rollback(); + setEventMessages($aBill->error, $aBill->errors, 'errors'); + } + } else { + $aBill->error = 'WithdrawRequestErrorNilAmount'; + $aBill->errors[] = $aBill->error; setEventMessages($aBill->error, $aBill->errors, 'errors'); } } diff --git a/htdocs/install/mysql/tables/llx_prelevement_lignes.sql b/htdocs/install/mysql/tables/llx_prelevement_lignes.sql index f3de4f8f780..aac3140af1c 100644 --- a/htdocs/install/mysql/tables/llx_prelevement_lignes.sql +++ b/htdocs/install/mysql/tables/llx_prelevement_lignes.sql @@ -16,13 +16,15 @@ -- -- =================================================================== +-- TODO This tables is a duplicate with table llx_prelevement_demande. +-- TODO Move the field status into table llx_prelevement_demande and remove this table. create table llx_prelevement_lignes ( rowid integer AUTO_INCREMENT PRIMARY KEY, fk_prelevement_bons integer, fk_soc integer NOT NULL, fk_user integer NULL, - + statut smallint DEFAULT 0, client_nom varchar(255), diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index d7266f79c7d..64690a7e6c1 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -2667,6 +2667,6 @@ MULTICURRENCY_APP_ENDPOINT=API endpoint URL to get live multicurrencies from a s NoWebsite=No website UploadName=Upload MAIN_SECURITY_MAXFILESIZE_DOWNLOADED=Max size of downloaded files -ShowTopMenuURLIntoAFrame=Show the content into a frame +ShowTopMenuURLIntoAFrame=Include content of URL into a frame under the top menu SameWindow=Same window NewWindow=New window / New tab diff --git a/htdocs/langs/en_US/other.lang b/htdocs/langs/en_US/other.lang index fbb3dab2265..75b3461e42d 100644 --- a/htdocs/langs/en_US/other.lang +++ b/htdocs/langs/en_US/other.lang @@ -374,3 +374,5 @@ RephraseStyleProfessional=Professional style RephraseStyleHumouristic=Humouristic style TextRephraser=Text style rephraser AIEnhancements=AI Enhancements +TLSv1=TLSv1 +TLSv1.2=TLSv1.2 diff --git a/htdocs/waf.inc.php b/htdocs/waf.inc.php index 591534f16c6..dd556b8d864 100644 --- a/htdocs/waf.inc.php +++ b/htdocs/waf.inc.php @@ -1,5 +1,6 @@ + * Copyright (C) 2025 Frédéric France * * 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 @@ -244,7 +245,7 @@ function analyseVarsForSqlAndScriptsInjection(&$var, $type, $stopcode = 1) if (is_array($var)) { foreach ($var as $key => $value) { // Warning, $key may also be used for attacks // Exclude check for some variable keys - if ($type === 0 && defined('NOSCANPOSTFORINJECTION') && is_array(constant('NOSCANPOSTFORINJECTION')) && in_array($key, constant('NOSCANPOSTFORINJECTION'))) { + if ($type === 0 && defined('NOSCANPOSTFORINJECTION') && is_array(constant('NOSCANPOSTFORINJECTION')) && in_array($key, (array) constant('NOSCANPOSTFORINJECTION'))) { continue; } diff --git a/htdocs/website/index.php b/htdocs/website/index.php index db6eb464bd3..7c1e1f4df2d 100644 --- a/htdocs/website/index.php +++ b/htdocs/website/index.php @@ -331,7 +331,7 @@ $manifestjsoncontentdefault .= '{ $listofpages = array(); $algo = ''; -if (GETPOST('optiopagecontent')) { +if (GETPOST('optionpagecontent')) { $algo .= 'content'; } if (GETPOST('optionmeta')) { @@ -631,7 +631,7 @@ if ($massaction == 'replace' && GETPOST('confirmmassaction', 'alpha') && $userca if ($objectpage->pageurl) { dol_syslog("Replace string into page ".$objectpage->pageurl); - if (GETPOST('optiopagecontent', 'aZ09')) { + if (GETPOST('optionpagecontent', 'aZ09')) { $objectpage->content = str_replace($searchkey, $replacestring, $objectpage->content); } if (GETPOST('optionmeta', 'aZ09')) { @@ -5425,7 +5425,7 @@ if ($mode == 'replacesite' || $massaction == 'replace') { print $langs->trans("SearchReplaceInto"); print ''; print '
'; - print '
'; + print '
'; print '
'; print '
'; print '
'; @@ -5545,8 +5545,8 @@ if ($mode == 'replacesite' || $massaction == 'replace') { $param = 'mode=replacesite&website='.urlencode($website->ref); $param .= '&searchstring='.urlencode($searchkey); - if (GETPOST('optiopagecontent')) { - $param .= '&optiopagecontent=content'; + if (GETPOST('optionpagecontent')) { + $param .= '&optionpagecontent=content'; } if (GETPOST('optionmeta')) { $param .= '&optionmeta=meta'; @@ -5595,7 +5595,7 @@ if ($mode == 'replacesite' || $massaction == 'replace') { if (is_object($answerrecord) && get_class($answerrecord) == 'WebsitePage') { $param = '?mode=replacesite'; $param .= '&websiteid='.$website->id; - $param .= '&optiopagecontent='.GETPOST('optiopagecontent', 'aZ09'); + $param .= '&optionpagecontent='.GETPOST('optionpagecontent', 'aZ09'); $param .= '&optionmeta='.GETPOST('optionmeta', 'aZ09'); $param .= '&optionsitefiles='.GETPOST('optionsitefiles', 'aZ09'); $param .= '&optioncontainertype='.GETPOST('optioncontainertype', 'aZ09'); @@ -5740,7 +5740,7 @@ if ($mode == 'replacesite' || $massaction == 'replace') { '@phan-var-force array{type:string} $answerrecord'; $param = '?mode=replacesite'; $param .= '&websiteid='.$website->id; - $param .= '&optiopagecontent='.GETPOST('optiopagecontent', 'aZ09'); + $param .= '&optionpagecontent='.GETPOST('optionpagecontent', 'aZ09'); $param .= '&optionmeta='.GETPOST('optionmeta', 'aZ09'); $param .= '&optionsitefiles='.GETPOST('optionsitefiles', 'aZ09'); $param .= '&optioncontainertype='.GETPOST('optioncontainertype', 'aZ09');
'.$langs->trans('NatureOfThirdParty').''; + print '
'.$langs->trans('NatureOfThirdParty').''; print $object->getTypeUrl(1); print '