From 3697d7f2aa1f25a06a4758dc8e7cd2927d0edf8f Mon Sep 17 00:00:00 2001 From: Ferran Marcet Date: Mon, 7 Oct 2024 15:55:13 +0200 Subject: [PATCH 001/383] Fix: Grand total correction --- htdocs/core/tpl/list_print_total.tpl.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/core/tpl/list_print_total.tpl.php b/htdocs/core/tpl/list_print_total.tpl.php index 8900665eaeb..8990ce12984 100644 --- a/htdocs/core/tpl/list_print_total.tpl.php +++ b/htdocs/core/tpl/list_print_total.tpl.php @@ -64,7 +64,8 @@ if (isset($totalarray['pos'])) { while ($i < $totalarray['nbfield']) { $i++; if (!empty($totalarray['pos'][$i])) { - printTotalValCell($totalarray['type'][$i], $sumsarray[$totalarray['pos'][$i]]); + $fieldname = preg_replace('/[^a-z0-9]/', '', $totalarray['pos'][$i]); + printTotalValCell($totalarray['type'][$i], $sumsarray[$fieldname]); } else { if ($i == 1) { print ''; From 786905a6c8b341e9d52ec356fce9aab0bec35b63 Mon Sep 17 00:00:00 2001 From: Ferran Marcet Date: Thu, 10 Oct 2024 09:16:32 +0200 Subject: [PATCH 002/383] Fix: Does not filter correctly by project contacts --- htdocs/core/lib/company.lib.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/lib/company.lib.php b/htdocs/core/lib/company.lib.php index 411fe6d0663..9a1ea12d88f 100644 --- a/htdocs/core/lib/company.lib.php +++ b/htdocs/core/lib/company.lib.php @@ -10,7 +10,7 @@ * Copyright (C) 2015-2024 Frédéric France * Copyright (C) 2015 Raphaël Doursenaud * Copyright (C) 2017 Rui Strecht - * Copyright (C) 2018 Ferran Marcet + * Copyright (C) 2018-2024 Ferran Marcet * Copyright (C) 2024 MDW * * This program is free software; you can redistribute it and/or modify @@ -1026,7 +1026,7 @@ function show_projects($conf, $langs, $db, $object, $backtopage = '', $nocreatel $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_type_contact as tc on ec.fk_c_type_contact = tc.rowid"; $sql .= " WHERE sc.fk_soc = ".((int) $object->id); $sql .= " AND p.entity IN (".getEntity('project').")"; - $sql .= " AND tc.element = 'project'"; + $sql .= " AND tc.element = 'project' AND tc.source = 'external'"; $sql .= " ORDER BY p.dateo DESC"; $result = $db->query($sql); From 4354165955958eb031f06bf5ba19bd70f704d941 Mon Sep 17 00:00:00 2001 From: Ferran Marcet Date: Wed, 13 Nov 2024 10:31:47 +0100 Subject: [PATCH 003/383] Fix: Closed invoices are not considered as issued --- .../interface_20_modWorkflow_WorkflowManager.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php b/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php index a816a83a428..5f291b9e5bd 100644 --- a/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php +++ b/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php @@ -2,7 +2,7 @@ /* Copyright (C) 2010 Regis Houssin * Copyright (C) 2011-2017 Laurent Destailleur * Copyright (C) 2014 Marcos García - * Copyright (C) 2022 Ferran Marcet + * Copyright (C) 2022-2024 Ferran Marcet * Copyright (C) 2023 Alexandre Janniaux * Copyright (C) 2024 MDW * @@ -248,7 +248,7 @@ class InterfaceWorkflowManager extends DolibarrTriggers $totalHTInvoices = 0; $areAllInvoicesValidated = true; foreach ($orderLinked->linkedObjects['facture'] as $key => $invoice) { - if ($invoice->statut == Facture::STATUS_VALIDATED || $object->id == $invoice->id) { + if ($invoice->statut == Facture::STATUS_VALIDATED || $invoice->statut == Facture::STATUS_CLOSED || $object->id == $invoice->id) { $totalHTInvoices += (float) $invoice->total_ht; } else { $areAllInvoicesValidated = false; From 343873c82f1aa8936a31e677209f48f777bb3d26 Mon Sep 17 00:00:00 2001 From: David Beniamine Date: Thu, 7 Nov 2024 23:42:03 +0100 Subject: [PATCH 004/383] Once payment is complet, a click on a product should start a new sale --- htdocs/takepos/index.php | 5 +++++ htdocs/takepos/pay.php | 1 + 2 files changed, 6 insertions(+) diff --git a/htdocs/takepos/index.php b/htdocs/takepos/index.php index a92bc4cac53..c9fb88f2ed0 100644 --- a/htdocs/takepos/index.php +++ b/htdocs/takepos/index.php @@ -527,6 +527,10 @@ function MoreProducts(moreorless) { function ClickProduct(position, qty = 1) { console.log("ClickProduct at position"+position); + if ($('#invoiceid').val() == "") { + invoiceid = $('#invoiceid').val(); + Refresh(); + } $('#proimg'+position).animate({opacity: '0.5'}, 1); $('#proimg'+position).animate({opacity: '1'}, 100); if ($('#prodiv'+position).data('iscat')==1){ @@ -1015,6 +1019,7 @@ function ModalBox(ModalID) function DirectPayment(){ console.log("DirectPayment"); $("#poslines").load("invoice.php?place="+place+"&action=valid&token=&pay=LIQ", function() { + $('#invoiceid').val(""); }); } diff --git a/htdocs/takepos/pay.php b/htdocs/takepos/pay.php index d2ee2999100..492419e264d 100644 --- a/htdocs/takepos/pay.php +++ b/htdocs/takepos/pay.php @@ -352,6 +352,7 @@ if (!getDolGlobalInt("TAKEPOS_NUMPAD")) { parent.$("#poslines").load("invoice.php?place=&action=valid&token=&pay="+payment+"&amount="+amountpayed+"&excess="+excess+"&invoiceid="+invoiceid+"&accountid="+accountid, function() { if (amountpayed > || amountpayed == || amountpayed==0 ) { console.log("Close popup"); + parent.$('#invoiceid').val(""); parent.$.colorbox.close(); } else { From c86b50e3fc0ff807e78dbe68e51313d8350d60d4 Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Sat, 30 Nov 2024 14:24:13 +0100 Subject: [PATCH 005/383] The $empty param must follow same rules than other select component. --- htdocs/core/class/html.formticket.class.php | 42 +++++++++++---------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/htdocs/core/class/html.formticket.class.php b/htdocs/core/class/html.formticket.class.php index 8920b259489..0cbd3e55876 100644 --- a/htdocs/core/class/html.formticket.class.php +++ b/htdocs/core/class/html.formticket.class.php @@ -332,7 +332,7 @@ class FormTicket // Type of Ticket print ''; - $this->selectTypesTickets((GETPOST('type_code', 'alpha') ? GETPOST('type_code', 'alpha') : $this->type_code), 'type_code', '', 2, 1, 0, 0, 'minwidth200'); + $this->selectTypesTickets((GETPOST('type_code', 'alpha') ? GETPOST('type_code', 'alpha') : $this->type_code), 'type_code', '', 2, 'ifone', 0, 0, 'minwidth200'); print ''; // Group => Category @@ -342,12 +342,12 @@ class FormTicket $filter = 'public=1'; } $selected = (GETPOST('category_code') ? GETPOST('category_code') : $this->category_code); - $this->selectGroupTickets($selected, 'category_code', $filter, 2, 1, 0, 0, 'minwidth200'); + $this->selectGroupTickets($selected, 'category_code', $filter, 2, 'ifone', 0, 0, 'minwidth200'); print ''; // Severity => Priority print ''; - $this->selectSeveritiesTickets((GETPOST('severity_code') ? GETPOST('severity_code') : $this->severity_code), 'severity_code', '', 2, 1); + $this->selectSeveritiesTickets((GETPOST('severity_code') ? GETPOST('severity_code') : $this->severity_code), 'severity_code', '', 2, 'ifone'); print ''; if (!empty($conf->knowledgemanagement->enabled)) { @@ -690,8 +690,8 @@ class FormTicket * @param string|array $selected Id of preselected field or array of Ids * @param string $htmlname Nom de la zone select * @param string $filtertype To filter on field type in llx_c_ticket_type (array('code'=>xx,'label'=>zz)) - * @param int $format 0=id+libelle, 1=code+code, 2=code+libelle, 3=id+code - * @param int $empty 1=peut etre vide, 0 sinon + * @param int $format 0=id+label, 1=code+code, 2=code+label, 3=id+code + * @param int|string $empty 1 = can be empty or 'string' to show the string as the empty value, 0 = can't be empty, 'ifone' = can be empty but autoselected if there is one only * @param int $noadmininfo 0=Add admin info, 1=Disable admin info * @param int $maxlength Max length of label * @param string $morecss More CSS @@ -715,9 +715,9 @@ class FormTicket $ticketstat->loadCacheTypesTickets(); - print ''; + if ($empty) { + print ''; } if (is_array($ticketstat->cache_types_tickets) && count($ticketstat->cache_types_tickets)) { @@ -755,6 +755,8 @@ class FormTicket print ' selected="selected"'; } elseif ($arraytypes['use_default'] == "1" && empty($selected) && !$multiselect) { print ' selected="selected"'; + } elseif (count($ticketstat->cache_types_tickets) == 1 && (!$empty || $empty == 'ifone')) { // If only 1 choice, we autoselect it + print ' selected="selected"'; } print '>'; @@ -813,10 +815,10 @@ class FormTicket $ticketstat = new Ticket($this->db); $ticketstat->loadCacheCategoriesTickets($publicgroups ? 1 : -1); // get list of active ticket groups - if ($use_multilevel <= 0) { + if ($use_multilevel <= 0) { // Only one combo list to select the group of ticket (default) print ''; if ($empty) { - print ''; + print ''; } if (is_array($ticketstat->cache_severity_tickets) && count($ticketstat->cache_severity_tickets)) { @@ -1201,6 +1203,8 @@ class FormTicket print ' selected="selected"'; } elseif ($arrayseverities['use_default'] == "1" && empty($selected)) { print ' selected="selected"'; + } elseif (count($conf->cache['severity_tickets']) == 1 && (!$empty || $empty == 'ifone')) { // If only 1 choice, we autoselect it + print ' selected="selected"'; } print '>'; From e48e1e27d542787ca0d42f7fdc814214348f8edc Mon Sep 17 00:00:00 2001 From: tnegre Date: Fri, 6 Dec 2024 12:07:37 +0100 Subject: [PATCH 006/383] replace code from develop to match DLB18 variable name --- htdocs/core/class/html.formticket.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/html.formticket.class.php b/htdocs/core/class/html.formticket.class.php index 0cbd3e55876..9c3a3847a24 100644 --- a/htdocs/core/class/html.formticket.class.php +++ b/htdocs/core/class/html.formticket.class.php @@ -1203,7 +1203,7 @@ class FormTicket print ' selected="selected"'; } elseif ($arrayseverities['use_default'] == "1" && empty($selected)) { print ' selected="selected"'; - } elseif (count($conf->cache['severity_tickets']) == 1 && (!$empty || $empty == 'ifone')) { // If only 1 choice, we autoselect it + } elseif (count($ticketstat->cache_severity_tickets) == 1 && (!$empty || $empty == 'ifone')) { // If only 1 choice, we autoselect it print ' selected="selected"'; } From e8aaa51edcf65d9feacb7000ee6e657419670275 Mon Sep 17 00:00:00 2001 From: tnegre Date: Fri, 6 Dec 2024 14:06:54 +0100 Subject: [PATCH 007/383] set empty value for choice --- htdocs/ticket/list.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/ticket/list.php b/htdocs/ticket/list.php index 9e69271f09c..9f1f30a3e7f 100644 --- a/htdocs/ticket/list.php +++ b/htdocs/ticket/list.php @@ -856,11 +856,11 @@ foreach ($object->fields as $key => $val) { print ''; } elseif ($key == 'category_code') { print ''; - $formTicket->selectGroupTickets(dol_escape_htmltag(empty($search[$key]) ? '' : $search[$key]), 'search_'.$key, '', 2, 1, 1, 0, (!empty($val['css']) ? $val['css'] : 'maxwidth150')); + $formTicket->selectGroupTickets(dol_escape_htmltag(empty($search[$key]) ? '' : $search[$key]), 'search_'.$key, '', 2, ' ', 1, 0, (!empty($val['css']) ? $val['css'] : 'maxwidth150')); print ''; } elseif ($key == 'severity_code') { print ''; - $formTicket->selectSeveritiesTickets(dol_escape_htmltag(empty($search[$key]) ? '' : $search[$key]), 'search_'.$key, '', 2, 1, 1, 0, (!empty($val['css']) ? $val['css'] : 'maxwidth150')); + $formTicket->selectSeveritiesTickets(dol_escape_htmltag(empty($search[$key]) ? '' : $search[$key]), 'search_'.$key, '', 2, ' ', 1, 0, (!empty($val['css']) ? $val['css'] : 'maxwidth150')); print ''; } elseif ($key == 'fk_user_assign' || $key == 'fk_user_create') { print ''; From 86833633efb1098e2363e41e2047b4813b20405a Mon Sep 17 00:00:00 2001 From: tnegre Date: Wed, 18 Dec 2024 10:26:26 +0100 Subject: [PATCH 008/383] fix --- htdocs/core/class/html.formticket.class.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/core/class/html.formticket.class.php b/htdocs/core/class/html.formticket.class.php index 9c3a3847a24..4a140185432 100644 --- a/htdocs/core/class/html.formticket.class.php +++ b/htdocs/core/class/html.formticket.class.php @@ -863,9 +863,9 @@ class FormTicket print ' selected="selected"'; } elseif (isset($selected) && $selected == $id) { print ' selected="selected"'; - } elseif ($arraycategories['use_default'] == "1" && !$selected && !$empty) { + } elseif ($arraycategories['use_default'] == "1" && !$selected && (!$empty || $empty == 'ifone')) { print ' selected="selected"'; - } elseif (count($ticketstat->cache_category_tickets) == 1) { + } elseif (count($ticketstat->cache_category_tickets) == 1 && (!$empty || $empty == 'ifone')) { print ' selected="selected"'; } @@ -1201,7 +1201,7 @@ class FormTicket print ' selected="selected"'; } elseif (isset($selected) && $selected == $id) { print ' selected="selected"'; - } elseif ($arrayseverities['use_default'] == "1" && empty($selected)) { + } elseif ($arrayseverities['use_default'] == "1" && empty($selected) && (!$empty || $empty == 'ifone')) { print ' selected="selected"'; } elseif (count($ticketstat->cache_severity_tickets) == 1 && (!$empty || $empty == 'ifone')) { // If only 1 choice, we autoselect it print ' selected="selected"'; From fed049e93e2bccf66bed6416e04bf0fa46e49768 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20PASCAL?= Date: Tue, 24 Dec 2024 10:36:53 +0100 Subject: [PATCH 009/383] feat: add function to get public holidays list within period --- htdocs/core/lib/date.lib.php | 268 +++++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) diff --git a/htdocs/core/lib/date.lib.php b/htdocs/core/lib/date.lib.php index 1005cc70941..77fbf7944e2 100644 --- a/htdocs/core/lib/date.lib.php +++ b/htdocs/core/lib/date.lib.php @@ -1013,6 +1013,274 @@ function num_public_holiday($timestampStart, $timestampEnd, $country_code = '', return $nbFerie; } +/** + * Return the list of public holidays including Friday, Saturday and Sunday (or not) between 2 dates in timestamp. + * Dates must be UTC with hour, min, sec to 0. + * Called by function num_open_day() + * + * @param int $timestampStart Timestamp start (UTC with hour, min, sec = 0) + * @param int $timestampEnd Timestamp end (UTC with hour, min, sec = 0) + * @param string $country_code Country code + * @param int $lastday Last day is included, 0: no, 1:yes + * @param int $excludesaturday Exclude saturday as non working day (-1=use setup, 0=no, 1=yes) + * @param int $excludesunday Exclude sunday as non working day (-1=use setup, 0=no, 1=yes) + * @param int $excludefriday Exclude friday as non working day (-1=use setup, 0=no, 1=yes) + * @param int $excludemonday Exclude monday as non working day (-1=use setup, 0=no, 1=yes) + * @return int|array List of public holidays or error message string if error + * @see num_between_day(), num_open_day() + */ +function list_public_holiday($timestampStart, $timestampEnd, $country_code = '', $lastday = 0, $excludesaturday = -1, $excludesunday = -1, $excludefriday = -1, $excludemonday = -1) +{ + global $conf, $db, $mysoc; + + // Check to ensure we use correct parameters + if (($timestampEnd - $timestampStart) % 86400 != 0) { + return 'Error Dates must use same hours and must be GMT dates'; + } + + if (empty($country_code)) { + $country_code = $mysoc->country_code; + } + if ($excludemonday < 0) { + $excludemonday = getDolGlobalInt('MAIN_NON_WORKING_DAYS_INCLUDE_MONDAY', 0); + } + if ($excludefriday < 0) { + $excludefriday = getDolGlobalInt('MAIN_NON_WORKING_DAYS_INCLUDE_FRIDAY', 0); + } + if ($excludesaturday < 0) { + $excludesaturday = getDolGlobalInt('MAIN_NON_WORKING_DAYS_INCLUDE_SATURDAY', 1); + } + if ($excludesunday < 0) { + $excludesunday = getDolGlobalInt('MAIN_NON_WORKING_DAYS_INCLUDE_SUNDAY', 1); + } + + $country_id = dol_getIdFromCode($db, $country_code, 'c_country', 'code', 'rowid'); + + if (empty($conf->cache['arrayOfActivePublicHolidays_' . $country_id])) { + // Loop on public holiday defined into hrm_public_holiday for the day, month and year analyzed + $tmpArrayOfPublicHolidays = array(); + $sql = "SELECT id, code, entity, fk_country, dayrule, year, month, day, active"; + $sql .= " FROM " . MAIN_DB_PREFIX . "c_hrm_public_holiday"; + $sql .= " WHERE active = 1 and fk_country IN (0" . ($country_id > 0 ? ", " . $country_id : 0) . ")"; + $sql .= " AND entity IN (0," . getEntity('holiday') . ")"; + + $resql = $db->query($sql); + if ($resql) { + $num_rows = $db->num_rows($resql); + $i = 0; + while ($i < $num_rows) { + $obj = $db->fetch_object($resql); + $tmpArrayOfPublicHolidays[$obj->id] = array('dayrule' => $obj->dayrule, 'year' => $obj->year, 'month' => $obj->month, 'day' => $obj->day); + $i++; + } + } else { + dol_syslog($db->lasterror(), LOG_ERR); + return 'Error sql ' . $db->lasterror(); + } + + //var_dump($tmpArrayOfPublicHolidays); + $conf->cache['arrayOfActivePublicHolidays_' . $country_id] = $tmpArrayOfPublicHolidays; + } + + $arrayOfPublicHolidays = $conf->cache['arrayOfActivePublicHolidays_' . $country_id]; + $listFeries = []; + $i = 0; + while ((($lastday == 0 && $timestampStart < $timestampEnd) || ($lastday && $timestampStart <= $timestampEnd)) + && ($i < 50000)) { // Loop end when equals (Test on i is a security loop to avoid infinite loop) + $nonWorkingDay = false; + $ferie = false; + $specialdayrule = array(); + + $jour = (int) gmdate("d", $timestampStart); + $mois = (int) gmdate("m", $timestampStart); + $annee = (int) gmdate("Y", $timestampStart); + + // If we have to exclude Friday, Saturday and Sunday + if ($excludefriday || $excludesaturday || $excludesunday) { + $jour_julien = unixtojd($timestampStart); + $jour_semaine = jddayofweek($jour_julien, 0); + if ($excludefriday) { //Friday (5), Saturday (6) and Sunday (0) + if ($jour_semaine == 5) { + $nonWorkingDay = true; + } + } + if ($excludesaturday) { //Friday (5), Saturday (6) and Sunday (0) + if ($jour_semaine == 6) { + $nonWorkingDay = true; + } + } + if ($excludesunday) { //Friday (5), Saturday (6) and Sunday (0) + if ($jour_semaine == 0) { + $nonWorkingDay = true; + } + } + } + //print "ferie=".$nonWorkingDay."\n"; + + if (!$nonWorkingDay) { + //print "jour=".$jour." month=".$mois." year=".$annee." includesaturday=".$excludesaturday." includesunday=".$excludesunday."\n"; + foreach ($arrayOfPublicHolidays as $entrypublicholiday) { + if (!empty($entrypublicholiday['dayrule']) && $entrypublicholiday['dayrule'] != 'date') { // For example 'easter', '...' + $specialdayrule[$entrypublicholiday['dayrule']] = $entrypublicholiday['dayrule']; + } else { + $match = 1; + if (!empty($entrypublicholiday['year']) && $entrypublicholiday['year'] != $annee) { + $match = 0; + } + if ($entrypublicholiday['month'] != $mois) { + $match = 0; + } + if ($entrypublicholiday['day'] != $jour) { + $match = 0; + } + + if ($match) { + $ferie = true; + $listFeries[] = $timestampStart; + } + } + + $i++; + } + //var_dump($specialdayrule)."\n"; + //print "ferie=".$nonWorkingDay."\n"; + } + + if (!$nonWorkingDay && !$ferie) { + // Special dayrules + if (in_array('easter', $specialdayrule)) { + // Calculation for easter date + $date_paques = getGMTEasterDatetime($annee); + $jour_paques = gmdate("d", $date_paques); + $mois_paques = gmdate("m", $date_paques); + if ($jour_paques == $jour && $mois_paques == $mois) { + $ferie = true; + $listFeries[] = $timestampStart; + } + // Easter (sunday) + } + + if (in_array('eastermonday', $specialdayrule)) { + // Calculation for the monday of easter date + $date_paques = getGMTEasterDatetime($annee); + //print 'PPP'.$date_paques.' '.dol_print_date($date_paques, 'dayhour', 'gmt')." "; + $date_lundi_paques = $date_paques + (3600 * 24); + $jour_lundi_paques = gmdate("d", $date_lundi_paques); + $mois_lundi_paques = gmdate("m", $date_lundi_paques); + if ($jour_lundi_paques == $jour && $mois_lundi_paques == $mois) { + $ferie = true; + $listFeries[] = $timestampStart; + } + // Easter (monday) + //print 'annee='.$annee.' $jour='.$jour.' $mois='.$mois.' $jour_lundi_paques='.$jour_lundi_paques.' $mois_lundi_paques='.$mois_lundi_paques."\n"; + } + + //Good Friday + if (in_array('goodfriday', $specialdayrule)) { + // Pulls the date of Easter + $easter = getGMTEasterDatetime($annee); + + // Calculates the date of Good Friday based on Easter + $date_good_friday = $easter - (2 * 3600 * 24); + $dom_good_friday = gmdate("d", $date_good_friday); + $month_good_friday = gmdate("m", $date_good_friday); + + if ($dom_good_friday == $jour && $month_good_friday == $mois) { + $ferie = true; + $listFeries[] = $timestampStart; + } + } + + if (in_array('ascension', $specialdayrule)) { + // Calcul du jour de l'ascension (39 days after easter day) + $date_paques = getGMTEasterDatetime($annee); + $date_ascension = $date_paques + (3600 * 24 * 39); + $jour_ascension = gmdate("d", $date_ascension); + $mois_ascension = gmdate("m", $date_ascension); + if ($jour_ascension == $jour && $mois_ascension == $mois) { + $ferie = true; + $listFeries[] = $timestampStart; + } + // Ascension (thursday) + } + + if (in_array('pentecost', $specialdayrule)) { + // Calculation of "Pentecote" (49 days after easter day) + $date_paques = getGMTEasterDatetime($annee); + $date_pentecote = $date_paques + (3600 * 24 * 49); + $jour_pentecote = gmdate("d", $date_pentecote); + $mois_pentecote = gmdate("m", $date_pentecote); + if ($jour_pentecote == $jour && $mois_pentecote == $mois) { + $ferie = true; + $listFeries[] = $timestampStart; + } + // "Pentecote" (sunday) + } + + if (in_array('pentecotemonday', $specialdayrule)) { + // Calculation of "Pentecote" (49 days after easter day) + $date_paques = getGMTEasterDatetime($annee); + $date_pentecote = $date_paques + (3600 * 24 * 50); + $jour_pentecote = gmdate("d", $date_pentecote); + $mois_pentecote = gmdate("m", $date_pentecote); + if ($jour_pentecote == $jour && $mois_pentecote == $mois) { + $ferie = true; + $listFeries[] = $timestampStart; + } + // "Pentecote" (monday) + } + + if (in_array('viernessanto', $specialdayrule)) { + // Viernes Santo + $date_paques = getGMTEasterDatetime($annee); + $date_viernes = $date_paques - (3600 * 24 * 2); + $jour_viernes = gmdate("d", $date_viernes); + $mois_viernes = gmdate("m", $date_viernes); + if ($jour_viernes == $jour && $mois_viernes == $mois) { + $ferie = true; + $listFeries[] = $timestampStart; + } + //Viernes Santo + } + + if (in_array('fronleichnam', $specialdayrule)) { + // Fronleichnam (60 days after easter sunday) + $date_paques = getGMTEasterDatetime($annee); + $date_fronleichnam = $date_paques + (3600 * 24 * 60); + $jour_fronleichnam = gmdate("d", $date_fronleichnam); + $mois_fronleichnam = gmdate("m", $date_fronleichnam); + if ($jour_fronleichnam == $jour && $mois_fronleichnam == $mois) { + $ferie = true; + $listFeries[] = $timestampStart; + } + // Fronleichnam + } + + if (in_array('genevafast', $specialdayrule)) { + // Geneva fast in Switzerland (Thursday after the first sunday in September) + $date_1sunsept = strtotime('next thursday', strtotime('next sunday', mktime(0, 0, 0, 9, 1, $annee))); + $jour_1sunsept = date("d", $date_1sunsept); + $mois_1sunsept = date("m", $date_1sunsept); + if ($jour_1sunsept == $jour && $mois_1sunsept == $mois) { + $ferie = true; + $listFeries[] = $timestampStart; + } + // Geneva fast in Switzerland + } + } + //print "ferie=".$nonWorkingDay."\n"; + + // Increase number of days (on go up into loop) + $timestampStart = dol_time_plus_duree($timestampStart, 1, 'd'); + //var_dump($jour.' '.$mois.' '.$annee.' '.$timestampStart); + + $i++; + } + + //print "nbFerie=".$nbFerie."\n"; + return $listFeries; +} + /** * Function to return number of days between two dates (date must be UTC date !) * Example: 2012-01-01 2012-01-02 => 1 if lastday=0, 2 if lastday=1 From 39e509f3809ee47d40cefe2c7977b7b34bff53b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9?= Date: Tue, 24 Dec 2024 10:50:29 +0100 Subject: [PATCH 010/383] fix: list_public_holiday function return type --- htdocs/core/lib/date.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/date.lib.php b/htdocs/core/lib/date.lib.php index 77fbf7944e2..87ad6a3a213 100644 --- a/htdocs/core/lib/date.lib.php +++ b/htdocs/core/lib/date.lib.php @@ -1026,7 +1026,7 @@ function num_public_holiday($timestampStart, $timestampEnd, $country_code = '', * @param int $excludesunday Exclude sunday as non working day (-1=use setup, 0=no, 1=yes) * @param int $excludefriday Exclude friday as non working day (-1=use setup, 0=no, 1=yes) * @param int $excludemonday Exclude monday as non working day (-1=use setup, 0=no, 1=yes) - * @return int|array List of public holidays or error message string if error + * @return string|array List of public holidays or error message string if error * @see num_between_day(), num_open_day() */ function list_public_holiday($timestampStart, $timestampEnd, $country_code = '', $lastday = 0, $excludesaturday = -1, $excludesunday = -1, $excludefriday = -1, $excludemonday = -1) From 303b7423f350590e7046b5ef11de4c19964b2144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9?= Date: Tue, 24 Dec 2024 11:01:15 +0100 Subject: [PATCH 011/383] fix: update list_public_holiday return type --- htdocs/core/lib/date.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/date.lib.php b/htdocs/core/lib/date.lib.php index 87ad6a3a213..956a3f2d2a5 100644 --- a/htdocs/core/lib/date.lib.php +++ b/htdocs/core/lib/date.lib.php @@ -1026,7 +1026,7 @@ function num_public_holiday($timestampStart, $timestampEnd, $country_code = '', * @param int $excludesunday Exclude sunday as non working day (-1=use setup, 0=no, 1=yes) * @param int $excludefriday Exclude friday as non working day (-1=use setup, 0=no, 1=yes) * @param int $excludemonday Exclude monday as non working day (-1=use setup, 0=no, 1=yes) - * @return string|array List of public holidays or error message string if error + * @return string|int[] List of public holidays timestamps or error message string if error * @see num_between_day(), num_open_day() */ function list_public_holiday($timestampStart, $timestampEnd, $country_code = '', $lastday = 0, $excludesaturday = -1, $excludesunday = -1, $excludefriday = -1, $excludemonday = -1) From db47ce3bb129a1dde64bf3348b46a4e2073acb09 Mon Sep 17 00:00:00 2001 From: VESSILLER Date: Mon, 20 Jan 2025 11:33:24 +0100 Subject: [PATCH 012/383] FIX delete supplier order line when linked to customer order line --- htdocs/fourn/class/fournisseur.commande.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 020b551f99a..156ec3971ef 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -3894,7 +3894,7 @@ class CommandeFournisseurLigne extends CommonOrderLine return -1; } - $sql1 = 'UPDATE '.MAIN_DB_PREFIX."commandedet SET fk_commandefourndet = NULL WHERE rowid=".((int) $this->id); + $sql1 = 'UPDATE '.MAIN_DB_PREFIX."commandedet SET fk_commandefourndet = NULL WHERE fk_commandefourndet=".((int) $this->id); $resql = $this->db->query($sql1); if (!$resql) { $this->db->rollback(); From 426f4305b05c6696994a8ebce17b4c4b7d6b6ac2 Mon Sep 17 00:00:00 2001 From: VESSILLER Date: Mon, 20 Jan 2025 11:48:37 +0100 Subject: [PATCH 013/383] FIX delete supplier order when at least one line linked to customer order line --- htdocs/fourn/class/fournisseur.commande.class.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index b98f14aa074..60b6f98f0cf 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -2312,6 +2312,16 @@ class CommandeFournisseur extends CommonOrder $error++; } + if (!$error) { + $sql1 = 'UPDATE '.$this->db->prefix()."commandedet SET fk_commandefourndet = NULL WHERE fk_commandefourndet IN (SELECT rowid FROM ".$main." WHERE fk_commande = ".((int) $this->id).")"; + dol_syslog(__METHOD__." linked order lines", LOG_DEBUG); + if (!$this->db->query($sql1)) { + $error++; + $this->error = $this->db->lasterror(); + $this->errors[] = $this->db->lasterror(); + } + } + $sql = "DELETE FROM ".MAIN_DB_PREFIX."commande_fournisseurdet WHERE fk_commande =".((int) $this->id); dol_syslog(get_class($this)."::delete", LOG_DEBUG); if (!$this->db->query($sql)) { From 08a976fd8545ec7edfa17543fb099f74d6a84a9d Mon Sep 17 00:00:00 2001 From: VESSILLER Date: Mon, 20 Jan 2025 11:56:54 +0100 Subject: [PATCH 014/383] FIX delete supplier order when at least one line linked to customer order line --- htdocs/fourn/class/fournisseur.commande.class.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 156ec3971ef..8bd670525a1 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -2133,6 +2133,16 @@ class CommandeFournisseur extends CommonOrder $error++; } + if (!$error) { + $sql1 = "UPDATE ".MAIN_DB_PREFIX."commandedet SET fk_commandefourndet = NULL WHERE fk_commandefourndet IN (SELECT rowid FROM ".$main." WHERE fk_commande = ".((int) $this->id).")"; + dol_syslog(__METHOD__." linked order lines", LOG_DEBUG); + if (!$this->db->query($sql1)) { + $error++; + $this->error = $this->db->lasterror(); + $this->errors[] = $this->db->lasterror(); + } + } + $sql = "DELETE FROM ".MAIN_DB_PREFIX."commande_fournisseurdet WHERE fk_commande =".((int) $this->id); dol_syslog(get_class($this)."::delete", LOG_DEBUG); if (!$this->db->query($sql)) { From ad60a50d4de17dedcbf6244ff9082343148785d1 Mon Sep 17 00:00:00 2001 From: VESSILLER Date: Mon, 20 Jan 2025 11:58:58 +0100 Subject: [PATCH 015/383] Uniformize SQL concat char --- htdocs/fourn/class/fournisseur.commande.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 8bd670525a1..0e16160189e 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -3904,7 +3904,7 @@ class CommandeFournisseurLigne extends CommonOrderLine return -1; } - $sql1 = 'UPDATE '.MAIN_DB_PREFIX."commandedet SET fk_commandefourndet = NULL WHERE fk_commandefourndet=".((int) $this->id); + $sql1 = "UPDATE ".MAIN_DB_PREFIX."commandedet SET fk_commandefourndet = NULL WHERE fk_commandefourndet=".((int) $this->id); $resql = $this->db->query($sql1); if (!$resql) { $this->db->rollback(); From 7f2a253625148d02dc94a2513e2a8251020e8c3f Mon Sep 17 00:00:00 2001 From: VESSILLER Date: Mon, 20 Jan 2025 12:17:12 +0100 Subject: [PATCH 016/383] Uniformize SQL concat char --- htdocs/fourn/class/fournisseur.commande.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 60b6f98f0cf..6ad989bceb5 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -2313,7 +2313,7 @@ class CommandeFournisseur extends CommonOrder } if (!$error) { - $sql1 = 'UPDATE '.$this->db->prefix()."commandedet SET fk_commandefourndet = NULL WHERE fk_commandefourndet IN (SELECT rowid FROM ".$main." WHERE fk_commande = ".((int) $this->id).")"; + $sql1 = "UPDATE ".$this->db->prefix()."commandedet SET fk_commandefourndet = NULL WHERE fk_commandefourndet IN (SELECT rowid FROM ".$main." WHERE fk_commande = ".((int) $this->id).")"; dol_syslog(__METHOD__." linked order lines", LOG_DEBUG); if (!$this->db->query($sql1)) { $error++; @@ -4147,7 +4147,7 @@ class CommandeFournisseurLigne extends CommonOrderLine return -1; } - $sql1 = 'UPDATE '.MAIN_DB_PREFIX."commandedet SET fk_commandefourndet = NULL WHERE fk_commandefourndet=".((int) $this->id); + $sql1 = "UPDATE ".MAIN_DB_PREFIX."commandedet SET fk_commandefourndet = NULL WHERE fk_commandefourndet=".((int) $this->id); $resql = $this->db->query($sql1); if (!$resql) { $this->db->rollback(); From 1ca277faeff8819d40c0df8153c5ec7ec292226a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9lina=20JOUM?= Date: Mon, 20 Jan 2025 12:36:10 +0100 Subject: [PATCH 017/383] NEW: Use the packaging feature to round the quantities to some given multiples for the sale --- htdocs/product/admin/product.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/htdocs/product/admin/product.php b/htdocs/product/admin/product.php index d38409f9eaa..92f698ed976 100644 --- a/htdocs/product/admin/product.php +++ b/htdocs/product/admin/product.php @@ -169,6 +169,11 @@ if ($action == 'other') { $value = GETPOST('PRODUCT_USE_SUPPLIER_PACKAGING', 'alpha'); $res = dolibarr_set_const($db, "PRODUCT_USE_SUPPLIER_PACKAGING", $value, 'chaine', 0, '', $conf->entity); } + + if (GETPOSTISSET('PRODUCT_USE_CUSTOMER_PACKAGING')) { + $value = GETPOST('PRODUCT_USE_CUSTOMER_PACKAGING', 'alpha'); + $res = dolibarr_set_const($db, "PRODUCT_USE_CUSTOMER_PACKAGING", $value, 'chaine', 0, '', $conf->entity); + } } @@ -642,6 +647,17 @@ if (isModEnabled("supplier_order") || isModEnabled("supplier_invoice")) { print ''; } +// Use packaging during your sales +if (isModEnabled("order") || isModEnabled("invoice")) { + print ''; + print ''.$form->textwithpicto($langs->trans("UseProductCustomerPackaging"), $langs->trans("PackagingForThisProductSellDesc")).''; + print ''; + print ajax_constantonoff("PRODUCT_USE_CUSTOMER_PACKAGING", array(), $conf->entity, 0, 0, 0, 0); + //print $form->selectyesno("activate_useProdSupplierPackaging", (!empty($conf->global->PRODUCT_USE_CUSTOMER_PACKAGING) ? $conf->global->PRODUCT_USE_CUSTOMER_PACKAGING : 0), 1); + print ''; + print ''; +} + print ''; print ''; From a14a474a708c117906bd91f96f35dd7820ed7350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9lina=20JOUM?= Date: Mon, 20 Jan 2025 12:43:30 +0100 Subject: [PATCH 018/383] ADD: packaging to round the quantities to some given multiples for the sale prices --- htdocs/product/class/product.class.php | 13 ++++++++++++ htdocs/product/price.php | 28 ++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index fa3cc2b2d4e..d0b9dfd9738 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -1438,6 +1438,9 @@ class Product extends CommonObject $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra); $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export); + if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING') && !empty($this->packaging)) { + $this->packaging = $this->packaging; + } $this->db->begin(); @@ -1588,6 +1591,9 @@ class Product extends CommonObject $sql .= ", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression : 'NULL'); $sql .= ", fk_user_modif = ".($user->id > 0 ? $user->id : 'NULL'); $sql .= ", mandatory_period = ".($this->mandatory_period); + if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING') && !empty($this->packaging)) { + $sql .= ", packaging = ".($this->packaging); + } // stock field is not here because it is a denormalized value from product_stock. $sql .= " WHERE rowid = ".((int) $id); @@ -2888,6 +2894,9 @@ class Product extends CommonObject } else { $sql .= " ppe.accountancy_code_buy, ppe.accountancy_code_buy_intra, ppe.accountancy_code_buy_export, ppe.accountancy_code_sell, ppe.accountancy_code_sell_intra, ppe.accountancy_code_sell_export,"; } + if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { + $sql .= " p.packaging,"; + } // For MultiCompany // PMP per entity & Stocks Sharings stock_reel includes only stocks shared with this entity @@ -3067,6 +3076,10 @@ class Product extends CommonObject $this->mandatory_period = $obj->mandatory_period; + if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { + $this->packaging = $obj->packaging; + } + $this->db->free($resql); // fetch optionals attributes and labels diff --git a/htdocs/product/price.php b/htdocs/product/price.php index c0d130de0db..aba3ab981c7 100644 --- a/htdocs/product/price.php +++ b/htdocs/product/price.php @@ -283,6 +283,11 @@ if (empty($reshook)) { $psq = empty($newpsq) ? 0 : $newpsq; $maxpricesupplier = $object->min_recommended_price(); + // Packaging / Conditionnement + if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { + $packaging = GETPOST('packaging'); + } + if (isModEnabled('dynamicprices')) { $object->fk_price_expression = empty($eid) ? 0 : $eid; //0 discards expression @@ -481,6 +486,11 @@ if (empty($reshook)) { if (!$error) { $db->begin(); + // Packaging / Conditionnement + if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { + $object->packaging = $packaging; + } + foreach ($pricestoupdate as $key => $val) { $newprice = $val['price']; @@ -1421,6 +1431,13 @@ if (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUS } print ''; + // Packaging / Conditionnement + if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { + print ''.$form->textwithpicto($langs->trans("PackagingForThisProduct"), $langs->trans("PackagingForThisProductSellDesc")).''; + print $object->packaging; + print ''; + } + // Price Label print ''.$langs->trans("PriceLabel").''; print $object->price_label; @@ -1743,6 +1760,17 @@ if (($action == 'edit_price' || $action == 'edit_level_price') && $object->getRi print ''; print ''; + // Packaging / Conditionnement + if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { + print ''; + print $form->textwithpicto($langs->trans("PackagingForThisProduct"), $langs->trans("PackagingForThisProductSellDesc")); + print ''; + $packaging = $object->packaging; + print ''; + print ''; + print ''; + } + // Price Label print ''; print $langs->trans('PriceLabel'); From b7b0a29e42b7f502d94ffcabae8a7d2f6598b99a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9lina=20JOUM?= Date: Mon, 20 Jan 2025 12:50:09 +0100 Subject: [PATCH 019/383] ADD: packaging to round the quantities to some given multiples for the sales orders --- htdocs/commande/class/commande.class.php | 30 +++++++++++++++++++++++ htdocs/commande/class/orderline.class.php | 11 +++++++++ 2 files changed, 41 insertions(+) diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index 474c50a7ff7..55bc6ff71a1 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -1634,6 +1634,20 @@ class Commande extends CommonOrder $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc); + if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { + $product = new Product($this->db); + $result = $product->fetch($fk_product); + if ($qty < $product->packaging) { + $qty = $product->packaging; + } else { + if (!empty($product->packaging) && (fmod((float) $qty, $product->packaging) > 0.000001)) { + $coeff = intval((float) $qty / $product->packaging) + 1; + $qty = (float) $product->packaging * $coeff; + setEventMessages($langs->trans('QtyRecalculatedWithPackaging'), null, 'mesgs'); + } + } + } + // Clean vat code $reg = array(); $vat_src_code = ''; @@ -2192,6 +2206,10 @@ class Commande extends CommonOrder $line->volume = $objp->volume; $line->volume_units = $objp->volume_units; + if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { + $line->packaging = $objp->packaging; + } + $line->date_start = $this->db->jdate($objp->date_start); $line->date_end = $this->db->jdate($objp->date_end); @@ -3163,6 +3181,18 @@ class Commande extends CommonOrder $this->line->rang = $rangmax + 1; } + if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { + if ($qty < $this->line->packaging) { + $qty = $this->line->packaging; + } else { + if (!empty($this->line->packaging) && ($qty % $this->line->packaging) > 0) { + $coeff = intval($qty / $this->line->packaging) + 1; + $qty = $this->line->packaging * $coeff; + setEventMessage($langs->trans('QtyRecalculatedWithPackaging'), 'mesgs'); + } + } + } + $this->line->id = $rowid; $this->line->label = $label; $this->line->desc = $desc; diff --git a/htdocs/commande/class/orderline.class.php b/htdocs/commande/class/orderline.class.php index e16bde3054e..9db924777f5 100644 --- a/htdocs/commande/class/orderline.class.php +++ b/htdocs/commande/class/orderline.class.php @@ -145,6 +145,10 @@ class OrderLine extends CommonOrderLine */ public $skip_update_total; + /** + * @var float + */ + public $packaging; /** * Constructor @@ -171,6 +175,9 @@ class OrderLine extends CommonOrderLine $sql .= ' cd.fk_multicurrency, cd.multicurrency_code, cd.multicurrency_subprice, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc,'; $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc, p.tobatch as product_tobatch,'; $sql .= ' cd.date_start, cd.date_end, cd.vat_src_code'; + if (getDolGlobalInt('PRODUCT_USE_CUSTOMER_PACKAGING')) { + $sql .= ', p.packaging'; + } $sql .= ' FROM '.MAIN_DB_PREFIX.'commandedet as cd'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON cd.fk_product = p.rowid'; $sql .= ' WHERE cd.rowid = '.((int) $rowid); @@ -225,6 +232,10 @@ class OrderLine extends CommonOrderLine $this->product_tobatch = $objp->product_tobatch; $this->fk_unit = $objp->fk_unit; + if (getDolGlobalInt('PRODUCT_USE_CUSTOMER_PACKAGING')) { + $this->packaging = $objp->packaging; + } + $this->date_start = $this->db->jdate($objp->date_start); $this->date_end = $this->db->jdate($objp->date_end); From 02dea8d103a8edd96746b0cfb3a307e9ed2f61ba Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Mon, 20 Jan 2025 17:11:06 +0100 Subject: [PATCH 020/383] fix: allow list mass action update price when price mode is multiprice price --- htdocs/core/actions_massactions.inc.php | 42 ++++++++++++++++++------- htdocs/product/list.php | 5 ++- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php index 6e26ef0eca7..3f06f4f3e8c 100644 --- a/htdocs/core/actions_massactions.inc.php +++ b/htdocs/core/actions_massactions.inc.php @@ -1281,18 +1281,38 @@ if (!$error && ($action == 'updateprice' && $confirm == 'yes') && $permissiontoa $result = $object->fetch($toselectid); //var_dump($contcats);exit; if ($result > 0) { - if ($obj->price_base_type == 'TTC') { - $newprice = $object->price_ttc * (100 + $pricepercentage) / 100; - $minprice = $object->price_min_ttc; + if (getDolGlobalString('PRODUIT_MULTIPRICES')) { + for ($level = 1; $level <= getDolGlobalInt('PRODUIT_MULTIPRICES_LIMIT'); $level++) { + // Force the update of the price of the product using the new VAT + if ($object->price_base_type == 'TTC') { + $newprice = $object->multiprices_ttc[$level] * (100 + $pricepercentage) / 100; + $minprice = $object->multiprices_min_ttc[$level]; + } else { + $newprice = $object->multiprices[$level] * (100 + $pricepercentage) / 100; + $minprice = $object->multiprices_min[$level]; + } + $ret = $object->updatePrice($newprice, $object->price_base_type, $user, $object->tva_tx, $minprice, $level, $object->tva_npr, 0, 0, array(), $object->default_vat_code); + + if ($res > 0) { + $nbok++; + } else { + setEventMessages($object->error, $object->errors, 'errors'); + } + } } else { - $newprice = $object->price * (100 + $pricepercentage) / 100; - $minprice = $object->price_min; - } - $res = $object->updatePrice($newprice, $obj->price_base_type, $user, $object->tva_tx, $minprice, 0, $object->tva_npr, 0, 0, array(), $object->default_vat_code); - if ($res > 0) { - $nbok++; - } else { - setEventMessages($object->error, $object->errors, 'errors'); + if ($object->price_base_type == 'TTC') { + $newprice = $object->price_ttc * (100 + $pricepercentage) / 100; + $minprice = $object->price_min_ttc; + } else { + $newprice = $object->price * (100 + $pricepercentage) / 100; + $minprice = $object->price_min; + } + $res = $object->updatePrice($newprice, $object->price_base_type, $user, $object->tva_tx, $minprice, 0, $object->tva_npr, 0, 0, array(), $object->default_vat_code); + if ($res > 0) { + $nbok++; + } else { + setEventMessages($object->error, $object->errors, 'errors'); + } } } else { setEventMessages($object->error, $object->errors, 'errors'); diff --git a/htdocs/product/list.php b/htdocs/product/list.php index 4d817250cbe..cecce963be1 100644 --- a/htdocs/product/list.php +++ b/htdocs/product/list.php @@ -829,9 +829,8 @@ $arrayofmassactions = array( //'presend'=>img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail"), ); if ($user->hasRight($rightskey, 'creer')) { - if (getDolGlobalString('PRODUCT_PRICE_UNIQ') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES')) { - $arrayofmassactions['preupdateprice'] = img_picto('', 'edit', 'class="pictofixedwidth"').$langs->trans("UpdatePrice"); - } + $arrayofmassactions['preupdateprice'] = img_picto('', 'edit', 'class="pictofixedwidth"').$langs->trans("UpdatePrice"); + $arrayofmassactions['switchonsalestatus'] = img_picto('', 'stop-circle', 'class="pictofixedwidth"').$langs->trans("SwitchOnSaleStatus"); $arrayofmassactions['switchonpurchasestatus'] = img_picto('', 'stop-circle', 'class="pictofixedwidth"').$langs->trans("SwitchOnPurchaseStatus"); From e4078477c6c05d51caabeacfd8b5004bed0dffcb Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Mon, 20 Jan 2025 17:32:08 +0100 Subject: [PATCH 021/383] fix: allow list mass action update price when price mode is multiprice price --- htdocs/core/actions_massactions.inc.php | 3 +-- htdocs/core/tpl/massactions_pre.tpl.php | 7 ++++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php index 3f06f4f3e8c..e84c02a8c93 100644 --- a/htdocs/core/actions_massactions.inc.php +++ b/htdocs/core/actions_massactions.inc.php @@ -1291,8 +1291,7 @@ if (!$error && ($action == 'updateprice' && $confirm == 'yes') && $permissiontoa $newprice = $object->multiprices[$level] * (100 + $pricepercentage) / 100; $minprice = $object->multiprices_min[$level]; } - $ret = $object->updatePrice($newprice, $object->price_base_type, $user, $object->tva_tx, $minprice, $level, $object->tva_npr, 0, 0, array(), $object->default_vat_code); - + $res = $object->updatePrice($newprice, $object->price_base_type, $user, $object->tva_tx, $minprice, $level, $object->tva_npr, 0, 0, array(), $object->default_vat_code); if ($res > 0) { $nbok++; } else { diff --git a/htdocs/core/tpl/massactions_pre.tpl.php b/htdocs/core/tpl/massactions_pre.tpl.php index 3c321f10123..bdbcee257f5 100644 --- a/htdocs/core/tpl/massactions_pre.tpl.php +++ b/htdocs/core/tpl/massactions_pre.tpl.php @@ -112,7 +112,12 @@ if ($massaction == 'preupdateprice') { 'value' => $valuefield ); - print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmUpdatePrice"), $langs->trans("ConfirmUpdatePriceQuestion", count($toselect)), "updateprice", $formquestion, 1, 0, 200, 500, 1); + $descConfirmPreUpdatePrice=$langs->trans("ConfirmUpdatePriceQuestion", count($toselect)); + if (getDolGlobalString('PRODUIT_MULTIPRICES')) { + $descConfirmPreUpdatePrice=$langs->trans("ConfirmUpdatePriceQuestion", count($toselect)*getDolGlobalInt('PRODUIT_MULTIPRICES_LIMIT') .' ('.$langs->transnoentities('PricingRule').', '.$langs->transnoentities('MultiPricesNumPrices').')'); + } + + print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmUpdatePrice"), $descConfirmPreUpdatePrice, "updateprice", $formquestion, 1, 0, 200, 500, 1); } if ($massaction == 'presetsupervisor') { From 576e70c3ce95da7511ce3c13f6b501c7a56d3d4c Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Mon, 20 Jan 2025 22:32:30 +0100 Subject: [PATCH 022/383] FIX wrong update function parameter --- htdocs/fourn/class/api_supplier_invoices.class.php | 2 +- htdocs/ticket/class/api_tickets.class.php | 2 +- htdocs/zapier/class/api_zapier.class.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/fourn/class/api_supplier_invoices.class.php b/htdocs/fourn/class/api_supplier_invoices.class.php index 13dc0e8b094..1614552ee5c 100644 --- a/htdocs/fourn/class/api_supplier_invoices.class.php +++ b/htdocs/fourn/class/api_supplier_invoices.class.php @@ -272,7 +272,7 @@ class SupplierInvoices extends DolibarrApi $this->invoice->$field = $value; } - if ($this->invoice->update($id, DolibarrApiAccess::$user)) { + if ($this->invoice->update(DolibarrApiAccess::$user)) { return $this->get($id); } diff --git a/htdocs/ticket/class/api_tickets.class.php b/htdocs/ticket/class/api_tickets.class.php index 62f94b2491b..a40e54934a1 100644 --- a/htdocs/ticket/class/api_tickets.class.php +++ b/htdocs/ticket/class/api_tickets.class.php @@ -389,7 +389,7 @@ class Tickets extends DolibarrApi $this->ticket->$field = $value; } - if ($this->ticket->update($id, DolibarrApiAccess::$user)) { + if ($this->ticket->update(DolibarrApiAccess::$user)) { return $this->get($id); } diff --git a/htdocs/zapier/class/api_zapier.class.php b/htdocs/zapier/class/api_zapier.class.php index 5ff155aebf0..2ed4e984126 100644 --- a/htdocs/zapier/class/api_zapier.class.php +++ b/htdocs/zapier/class/api_zapier.class.php @@ -300,7 +300,7 @@ class Zapier extends DolibarrApi $this->hook->$field = $value; } - if ($this->hook->update($id, DolibarrApiAccess::$user) > 0) { + if ($this->hook->update(DolibarrApiAccess::$user) > 0) { return $this->get($id); } else { throw new RestException(500, $this->hook->error); From 3c2e6140a1fc3cd2a2fb6a9e9d31e2af2cb14682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9lina=20JOUM?= Date: Tue, 21 Jan 2025 09:43:00 +0100 Subject: [PATCH 023/383] ADD: packaging to round the quantities to some given multiples for the commercials proposals --- htdocs/comm/propal/class/propal.class.php | 26 +++++++++++++++++++ .../comm/propal/class/propaleligne.class.php | 11 ++++++++ 2 files changed, 37 insertions(+) diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index a78da69017f..cb3cd883abe 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -709,6 +709,20 @@ class Propal extends CommonObject $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc); + if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { + $product = new Product($this->db); + $result = $product->fetch($fk_product); + if ($qty < $product->packaging) { + $qty = $product->packaging; + } else { + if (!empty($product->packaging) && (fmod((float) $qty, $product->packaging) > 0.000001)) { + $coeff = intval((float) $qty / $product->packaging) + 1; + $qty = (float) $product->packaging * $coeff; + setEventMessages($langs->trans('QtyRecalculatedWithPackaging'), null, 'mesgs'); + } + } + } + // Clean vat code $reg = array(); $vat_src_code = ''; @@ -974,6 +988,18 @@ class Propal extends CommonObject $this->line->rang = $rangmax + 1; } + if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { + if ($qty < $this->line->packaging) { + $qty = $this->line->packaging; + } else { + if (!empty($this->line->packaging) && ($qty % $this->line->packaging) > 0) { + $coeff = intval($qty / $this->line->packaging) + 1; + $qty = $this->line->packaging * $coeff; + setEventMessage($langs->trans('QtyRecalculatedWithPackaging'), 'mesgs'); + } + } + } + $this->line->id = $rowid; $this->line->label = $label; $this->line->desc = $desc; diff --git a/htdocs/comm/propal/class/propaleligne.class.php b/htdocs/comm/propal/class/propaleligne.class.php index ea403b5b363..817b6866f64 100644 --- a/htdocs/comm/propal/class/propaleligne.class.php +++ b/htdocs/comm/propal/class/propaleligne.class.php @@ -343,6 +343,10 @@ class PropaleLigne extends CommonObjectLine */ public $multicurrency_total_ttc; + /** + * @var float + */ + public $packaging; /** * Class line Constructor @@ -370,6 +374,9 @@ class PropaleLigne extends CommonObjectLine $sql .= ' pd.fk_multicurrency, pd.multicurrency_code, pd.multicurrency_subprice, pd.multicurrency_total_ht, pd.multicurrency_total_tva, pd.multicurrency_total_ttc,'; $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc,'; $sql .= ' pd.date_start, pd.date_end, pd.product_type'; + if (getDolGlobalInt('PRODUCT_USE_CUSTOMER_PACKAGING')) { + $sql .= ', p.packaging'; + } $sql .= ' FROM '.MAIN_DB_PREFIX.'propaldet as pd'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON pd.fk_product = p.rowid'; $sql .= ' WHERE pd.rowid = '.((int) $rowid); @@ -418,6 +425,10 @@ class PropaleLigne extends CommonObjectLine $this->product_desc = $objp->product_desc; $this->fk_unit = $objp->fk_unit; + if (getDolGlobalInt('PRODUCT_USE_CUSTOMER_PACKAGING')) { + $this->packaging = $objp->packaging; + } + $this->date_start = $this->db->jdate($objp->date_start); $this->date_end = $this->db->jdate($objp->date_end); From 33d2969ab843fdb4330ff2f8d9e5c6816ee62409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9lina=20JOUM?= Date: Tue, 21 Jan 2025 09:56:43 +0100 Subject: [PATCH 024/383] ADD: packaging to round the quantities to some given multiples for the invoices --- htdocs/compta/facture/class/facture.class.php | 26 +++++++++++++++++++ .../facture/class/factureligne.class.php | 12 +++++++++ 2 files changed, 38 insertions(+) diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 179385b1aba..4964b9d9929 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -3994,6 +3994,20 @@ class Facture extends CommonInvoice $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc); + if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { + $product = new Product($this->db); + $result = $product->fetch($fk_product); + if ($qty < $product->packaging) { + $qty = $product->packaging; + } else { + if (!empty($product->packaging) && (fmod((float) $qty, $product->packaging) > 0.000001)) { + $coeff = intval((float) $qty / $product->packaging) + 1; + $qty = (float) $product->packaging * $coeff; + setEventMessages($langs->trans('QtyRecalculatedWithPackaging'), null, 'mesgs'); + } + } + } + // Clean vat code $reg = array(); $vat_src_code = ''; @@ -4298,6 +4312,18 @@ class Facture extends CommonInvoice $this->line->rang = $rangmax + 1; } + if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { + if ($qty < $this->line->packaging) { + $qty = $this->line->packaging; + } else { + if (!empty($this->line->packaging) && ($qty % $this->line->packaging) > 0) { + $coeff = intval($qty / $this->line->packaging) + 1; + $qty = $this->line->packaging * $coeff; + setEventMessage($langs->trans('QtyRecalculatedWithPackaging'), 'mesgs'); + } + } + } + $this->line->id = $rowid; $this->line->rowid = $rowid; $this->line->label = $label; diff --git a/htdocs/compta/facture/class/factureligne.class.php b/htdocs/compta/facture/class/factureligne.class.php index e4e2b1a3ae2..c96f07c056b 100644 --- a/htdocs/compta/facture/class/factureligne.class.php +++ b/htdocs/compta/facture/class/factureligne.class.php @@ -180,6 +180,11 @@ class FactureLigne extends CommonInvoiceLine */ public $fk_prev_id; + /** + * @var float + */ + public $packaging; + /** * Constructor @@ -211,6 +216,9 @@ class FactureLigne extends CommonInvoiceLine $sql .= ' fd.multicurrency_total_tva,'; $sql .= ' fd.multicurrency_total_ttc,'; $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc'; + if (getDolGlobalInt('PRODUCT_USE_CUSTOMER_PACKAGING')) { + $sql .= ', p.packaging'; + } $sql .= ' FROM '.MAIN_DB_PREFIX.'facturedet as fd'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON fd.fk_product = p.rowid'; $sql .= ' WHERE fd.rowid = '.((int) $rowid); @@ -277,6 +285,10 @@ class FactureLigne extends CommonInvoiceLine $this->multicurrency_total_tva = $objp->multicurrency_total_tva; $this->multicurrency_total_ttc = $objp->multicurrency_total_ttc; + if (getDolGlobalInt('PRODUCT_USE_CUSTOMER_PACKAGING')) { + $this->packaging = $objp->packaging; + } + $this->fetch_optionals(); $this->db->free($result); From 1569366feb7903dad163663b34f756d3a8ced09f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9lina=20JOUM?= Date: Tue, 21 Jan 2025 14:45:33 +0100 Subject: [PATCH 025/383] ADD: translations for option Use the packaging feature to round the quantities to some given multiples for the sale --- htdocs/langs/en_US/products.lang | 3 +++ htdocs/langs/fr_FR/products.lang | 3 +++ 2 files changed, 6 insertions(+) diff --git a/htdocs/langs/en_US/products.lang b/htdocs/langs/en_US/products.lang index ededc52cbfc..40769a0af05 100644 --- a/htdocs/langs/en_US/products.lang +++ b/htdocs/langs/en_US/products.lang @@ -345,6 +345,9 @@ ProductSupplierDescription=Vendor description for the product UseProductSupplierPackaging=Use the "packaging" feature to round the quantities to some given multiples (when adding/updating line in a vendor documents, recalculate quantities and purchase prices according to the higher multiple set on the purchase prices of a product) PackagingForThisProduct=Packaging of quantities PackagingForThisProductDesc=You will automatically purchase a multiple of this quantity. +UseProductCustomerPackaging=Use the "packaging" feature to round the quantities to some given multiples (when adding/updating line in a customer documents, recalculate quantities and sale prices according to the higher multiple set on the sale prices of a product) +PackagingForThisProductSell=Packaging of quantities (sale) +PackagingForThisProductSellDesc=You will automatically sell a multiple of this quantity. QtyRecalculatedWithPackaging=The quantity of the line were recalculated according to supplier packaging #Attributes diff --git a/htdocs/langs/fr_FR/products.lang b/htdocs/langs/fr_FR/products.lang index 2dd144775d4..73eb7584c2a 100644 --- a/htdocs/langs/fr_FR/products.lang +++ b/htdocs/langs/fr_FR/products.lang @@ -345,6 +345,9 @@ ProductSupplierDescription=Description du fournisseur du produit UseProductSupplierPackaging=Utilisez la fonction "conditionnement" pour arrondir les quantités à certains multiples donnés (lors de l'ajout/de la mise à jour d'une ligne, dans les documents d'un fournisseur, recalculez les quantités et les prix d'achat en fonction du multiple supérieur défini sur les prix d'achat d'un produit) PackagingForThisProduct=Conditionnement des quantités PackagingForThisProductDesc=Vous achèterez automatiquement un multiple de cette quantité. +UseProductCustomerPackaging=Utilisez la fonction "conditionnement" pour arrondir les quantités à certains multiples donnés (lors de l'ajout/de la mise à jour d'une ligne, dans les documents d'un client, recalculez les quantités et les prix de vente en fonction du multiple supérieur défini sur les prix de vente d'un produit) +PackagingForThisProductSell=Conditionnement des quantités (vente) +PackagingForThisProductSellDesc=Vous vendrez automatiquement un multiple de cette quantité. QtyRecalculatedWithPackaging=La quantité de la ligne a été recalculée en fonction de l'emballage du fournisseur #Attributes From 3230e83f2b5c5e34b157424f0c12e3321555f275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9lina=20JOUM?= Date: Tue, 21 Jan 2025 15:59:13 +0100 Subject: [PATCH 026/383] ADD: the packaging field to product import --- htdocs/core/modules/modProduct.class.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/htdocs/core/modules/modProduct.class.php b/htdocs/core/modules/modProduct.class.php index 7b87d30b1f4..01b77908a23 100644 --- a/htdocs/core/modules/modProduct.class.php +++ b/htdocs/core/modules/modProduct.class.php @@ -638,6 +638,12 @@ class modProduct extends DolibarrModules )); } + if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { + $this->import_fields_array[$r] = array_merge($this->import_fields_array[$r], array( + 'p.packaging' => 'PackagingForThisProductSell', + )); + } + if (isModEnabled("supplier_order") || isModEnabled("supplier_invoice") || isModEnabled('margin')) { $this->import_fields_array[$r] = array_merge($this->import_fields_array[$r], array('p.cost_price' => 'CostPrice')); } @@ -755,6 +761,13 @@ class modProduct extends DolibarrModules ) )); } + + if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { + $import_sample = array_merge($import_sample, array( + 'p.packaging' => "2", + )); + } + $this->import_examplevalues_array[$r] = array_merge($import_sample, $import_extrafield_sample); $this->import_updatekeys_array[$r] = array('p.ref' => 'Ref'); if (isModEnabled('barcode')) { From 8d0a4ac6d91b0f719135d86c46311094b4987ba9 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Wed, 22 Jan 2025 20:18:53 +0100 Subject: [PATCH 027/383] fix: allow list mass action update price when price mode is multiprice price --- htdocs/core/actions_massactions.inc.php | 1 - 1 file changed, 1 deletion(-) diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php index e84c02a8c93..fb45b57ac7a 100644 --- a/htdocs/core/actions_massactions.inc.php +++ b/htdocs/core/actions_massactions.inc.php @@ -1283,7 +1283,6 @@ if (!$error && ($action == 'updateprice' && $confirm == 'yes') && $permissiontoa if ($result > 0) { if (getDolGlobalString('PRODUIT_MULTIPRICES')) { for ($level = 1; $level <= getDolGlobalInt('PRODUIT_MULTIPRICES_LIMIT'); $level++) { - // Force the update of the price of the product using the new VAT if ($object->price_base_type == 'TTC') { $newprice = $object->multiprices_ttc[$level] * (100 + $pricepercentage) / 100; $minprice = $object->multiprices_min_ttc[$level]; From cbe15c7c71059ad25315533d60d52dc973e93bba Mon Sep 17 00:00:00 2001 From: Eric Seigne Date: Wed, 22 Jan 2025 23:53:16 +0100 Subject: [PATCH 028/383] missing hookmanager like others doc_generic*odt modules --- .../project/task/doc/doc_generic_task_odt.modules.php | 8 ++++++++ .../core/modules/societe/doc/doc_generic_odt.modules.php | 1 + .../mymodule/doc/doc_generic_myobject_odt.modules.php | 5 +++++ .../doc_generic_recruitmentjobposition_odt.modules.php | 5 +++++ 4 files changed, 19 insertions(+) diff --git a/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php b/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php index 51e53e21d3f..f2cb1eddb78 100644 --- a/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php +++ b/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php @@ -469,6 +469,14 @@ class doc_generic_task_odt extends ModelePDFTask return -1; } + // Add odtgeneration hook + if (!is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($this->db); + } + $hookmanager->initHooks(array('odtgeneration')); + global $action; + if (!is_object($outputlangs)) { $outputlangs = $langs; } diff --git a/htdocs/core/modules/societe/doc/doc_generic_odt.modules.php b/htdocs/core/modules/societe/doc/doc_generic_odt.modules.php index 374c44c7a25..49ce657fce7 100644 --- a/htdocs/core/modules/societe/doc/doc_generic_odt.modules.php +++ b/htdocs/core/modules/societe/doc/doc_generic_odt.modules.php @@ -216,6 +216,7 @@ class doc_generic_odt extends ModeleThirdPartyDoc $hookmanager = new HookManager($this->db); } $hookmanager->initHooks(array('odtgeneration')); + global $action; if (!is_object($outputlangs)) { $outputlangs = $langs; diff --git a/htdocs/modulebuilder/template/core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php b/htdocs/modulebuilder/template/core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php index e35fb604cec..680cf49de6b 100644 --- a/htdocs/modulebuilder/template/core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php +++ b/htdocs/modulebuilder/template/core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php @@ -233,7 +233,12 @@ class doc_generic_myobject_odt extends ModelePDFMyObject } // Add odtgeneration hook + if (!is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($this->db); + } $hookmanager->initHooks(array('odtgeneration')); + global $action; if (!is_object($outputlangs)) { $outputlangs = $langs; diff --git a/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php b/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php index da7640d708a..128293c9d85 100644 --- a/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php +++ b/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php @@ -221,7 +221,12 @@ class doc_generic_recruitmentjobposition_odt extends ModelePDFRecruitmentJobPosi } // Add odtgeneration hook + if (!is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($this->db); + } $hookmanager->initHooks(array('odtgeneration')); + global $action; if (!is_object($outputlangs)) { $outputlangs = $langs; From dc83dd7cbebc3983950244655688a5839bf120f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9=20Cendrier?= Date: Thu, 23 Jan 2025 10:02:59 +0100 Subject: [PATCH 029/383] FIX: trailing space --- htdocs/comm/propal/class/propaleligne.class.php | 2 +- htdocs/commande/class/orderline.class.php | 2 +- htdocs/compta/facture/class/factureligne.class.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/comm/propal/class/propaleligne.class.php b/htdocs/comm/propal/class/propaleligne.class.php index 817b6866f64..c300084d960 100644 --- a/htdocs/comm/propal/class/propaleligne.class.php +++ b/htdocs/comm/propal/class/propaleligne.class.php @@ -375,7 +375,7 @@ class PropaleLigne extends CommonObjectLine $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc,'; $sql .= ' pd.date_start, pd.date_end, pd.product_type'; if (getDolGlobalInt('PRODUCT_USE_CUSTOMER_PACKAGING')) { - $sql .= ', p.packaging'; + $sql .= ', p.packaging'; } $sql .= ' FROM '.MAIN_DB_PREFIX.'propaldet as pd'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON pd.fk_product = p.rowid'; diff --git a/htdocs/commande/class/orderline.class.php b/htdocs/commande/class/orderline.class.php index 9db924777f5..10519dd0cf2 100644 --- a/htdocs/commande/class/orderline.class.php +++ b/htdocs/commande/class/orderline.class.php @@ -176,7 +176,7 @@ class OrderLine extends CommonOrderLine $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc, p.tobatch as product_tobatch,'; $sql .= ' cd.date_start, cd.date_end, cd.vat_src_code'; if (getDolGlobalInt('PRODUCT_USE_CUSTOMER_PACKAGING')) { - $sql .= ', p.packaging'; + $sql .= ', p.packaging'; } $sql .= ' FROM '.MAIN_DB_PREFIX.'commandedet as cd'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON cd.fk_product = p.rowid'; diff --git a/htdocs/compta/facture/class/factureligne.class.php b/htdocs/compta/facture/class/factureligne.class.php index c96f07c056b..c397b5ddf00 100644 --- a/htdocs/compta/facture/class/factureligne.class.php +++ b/htdocs/compta/facture/class/factureligne.class.php @@ -217,7 +217,7 @@ class FactureLigne extends CommonInvoiceLine $sql .= ' fd.multicurrency_total_ttc,'; $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc'; if (getDolGlobalInt('PRODUCT_USE_CUSTOMER_PACKAGING')) { - $sql .= ', p.packaging'; + $sql .= ', p.packaging'; } $sql .= ' FROM '.MAIN_DB_PREFIX.'facturedet as fd'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON fd.fk_product = p.rowid'; From db97347497105c964ca4036ff71e794f58310839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9=20Cendrier?= Date: Thu, 23 Jan 2025 10:25:24 +0100 Subject: [PATCH 030/383] FIX: phan remarks --- htdocs/product/class/product.class.php | 4 ---- htdocs/product/price.php | 6 ++---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 49710e29d87..368a44ecd4a 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -1442,10 +1442,6 @@ class Product extends CommonObject $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra); $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export); - if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING') && !empty($this->packaging)) { - $this->packaging = $this->packaging; - } - $this->db->begin(); $result = 0; diff --git a/htdocs/product/price.php b/htdocs/product/price.php index aba3ab981c7..d8000817b9f 100644 --- a/htdocs/product/price.php +++ b/htdocs/product/price.php @@ -14,7 +14,7 @@ * Copyright (C) 2018-2025 Frédéric France * Copyright (C) 2018 Nicolas ZABOURI * Copyright (C) 2024 MDW - * Copyright (C) 2024 Mélina Joum + * Copyright (C) 2025 Mélina Joum * * 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 @@ -284,9 +284,7 @@ if (empty($reshook)) { $maxpricesupplier = $object->min_recommended_price(); // Packaging / Conditionnement - if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { - $packaging = GETPOST('packaging'); - } + $packaging = getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING') ? GETPOST('packaging') : null; if (isModEnabled('dynamicprices')) { $object->fk_price_expression = empty($eid) ? 0 : $eid; //0 discards expression From 2589febbae97cd9ff25722157648c7dd13e9615e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9=20Cendrier?= Date: Thu, 23 Jan 2025 10:34:59 +0100 Subject: [PATCH 031/383] FIX: property type --- htdocs/product/price.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/product/price.php b/htdocs/product/price.php index d8000817b9f..1984b661cab 100644 --- a/htdocs/product/price.php +++ b/htdocs/product/price.php @@ -486,7 +486,7 @@ if (empty($reshook)) { // Packaging / Conditionnement if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { - $object->packaging = $packaging; + $object->packaging = (double) $packaging; } foreach ($pricestoupdate as $key => $val) { From 75db8061027376a07093d3dac991406d00a91d8d Mon Sep 17 00:00:00 2001 From: ATM-Lucas Date: Fri, 24 Jan 2025 12:23:08 +0100 Subject: [PATCH 032/383] Adding sending mails on product --- htdocs/core/tpl/card_presend.tpl.php | 5 +++++ htdocs/product/card.php | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/htdocs/core/tpl/card_presend.tpl.php b/htdocs/core/tpl/card_presend.tpl.php index d29932c2c20..9a5a12be721 100644 --- a/htdocs/core/tpl/card_presend.tpl.php +++ b/htdocs/core/tpl/card_presend.tpl.php @@ -115,6 +115,11 @@ if ($action == 'presend') { } if ($forcebuilddoc) { // If there is no default value for supplier invoice, we do not generate file, even if modelpdf was set by a manual generation if ((!$file || !is_readable($file)) && method_exists($object, 'generateDocument')) { + + $hidedetails = $hidedetails?$hidedetails:''; + $hidedesc = $hidedetails?$hidedetails:''; + $hideref = $hidedetails?$hidedetails:''; + $result = $object->generateDocument(GETPOST('model') ? GETPOST('model') : $object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref); if ($result < 0) { dol_print_error($db, $object->error, $object->errors); diff --git a/htdocs/product/card.php b/htdocs/product/card.php index 5de9cda0342..bcbe53236c5 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -1295,6 +1295,14 @@ if (empty($reshook)) { setEventMessages($langs->trans("WarningSelectOneDocument"), null, 'warnings'); } } + + // Actions to send emails + $triggersendname = 'PRODUCT_SENTBYMAIL'; + $paramname = 'id'; + $autocopy = 'MAIN_MAIL_AUTOCOPY_PRODUCT_TO'; + $trackid = 'prod'.$object->id; + include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php'; + } @@ -3027,6 +3035,9 @@ if ($action != 'create' && $action != 'edit') { print dolGetButtonAction('', $langs->trans('Modify'), 'default', $_SERVER["PHP_SELF"].'?action=edit&token='.newToken().'&id='.$object->id, '', $usercancreate); } + //Send + print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=presend&mode=init&token=' . newToken() . '#formmailbeforetitle'); + if (!isset($hookmanager->resArray['no_button_copy']) || $hookmanager->resArray['no_button_copy'] != 1) { if (!empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile)) { $cloneProductUrl = ''; @@ -3198,6 +3209,15 @@ if ($action != 'create' && $action != 'edit' && $action != 'delete') { $somethingshown = $formactions->showactions($object, 'product', 0, 1, '', $MAXEVENT, '', $morehtmlcenter); // Show all action for product print ''; + + // Presend form + $modelmail = 'product_send'; // Modèle d'e-mail pour les produits + $defaulttopic = $object->label; // Sujet par défaut + $diroutput = $conf->product->multidir_output[$object->entity]; // Répertoire de sortie + $trackid = 'prod' . $object->id; // ID de suivi + + include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php'; + } // End of page From ba6f80c307be59843ee1354d16fe12ca4685e592 Mon Sep 17 00:00:00 2001 From: ATM-Lucas Date: Fri, 24 Jan 2025 12:24:43 +0100 Subject: [PATCH 033/383] comm --- htdocs/product/card.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/product/card.php b/htdocs/product/card.php index bcbe53236c5..1efadc81fbf 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -3211,10 +3211,10 @@ if ($action != 'create' && $action != 'edit' && $action != 'delete') { print ''; // Presend form - $modelmail = 'product_send'; // Modèle d'e-mail pour les produits - $defaulttopic = $object->label; // Sujet par défaut - $diroutput = $conf->product->multidir_output[$object->entity]; // Répertoire de sortie - $trackid = 'prod' . $object->id; // ID de suivi + $modelmail = 'product_send'; + $defaulttopic = $object->label; + $diroutput = $conf->product->multidir_output[$object->entity]; + $trackid = 'prod' . $object->id; include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php'; From e3856d0de5a11c137681d493a7075393ed42eafb Mon Sep 17 00:00:00 2001 From: ATM-Lucas Date: Fri, 24 Jan 2025 14:04:30 +0100 Subject: [PATCH 034/383] pre-commit error --- htdocs/core/tpl/card_presend.tpl.php | 1 - htdocs/product/card.php | 2 -- 2 files changed, 3 deletions(-) diff --git a/htdocs/core/tpl/card_presend.tpl.php b/htdocs/core/tpl/card_presend.tpl.php index 9a5a12be721..e0654d487ca 100644 --- a/htdocs/core/tpl/card_presend.tpl.php +++ b/htdocs/core/tpl/card_presend.tpl.php @@ -115,7 +115,6 @@ if ($action == 'presend') { } if ($forcebuilddoc) { // If there is no default value for supplier invoice, we do not generate file, even if modelpdf was set by a manual generation if ((!$file || !is_readable($file)) && method_exists($object, 'generateDocument')) { - $hidedetails = $hidedetails?$hidedetails:''; $hidedesc = $hidedetails?$hidedetails:''; $hideref = $hidedetails?$hidedetails:''; diff --git a/htdocs/product/card.php b/htdocs/product/card.php index 1efadc81fbf..2a0868bcaa3 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -1302,7 +1302,6 @@ if (empty($reshook)) { $autocopy = 'MAIN_MAIL_AUTOCOPY_PRODUCT_TO'; $trackid = 'prod'.$object->id; include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php'; - } @@ -3217,7 +3216,6 @@ if ($action != 'create' && $action != 'edit' && $action != 'delete') { $trackid = 'prod' . $object->id; include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php'; - } // End of page From 4afb100767382bdaf926da456c0c9899ab978695 Mon Sep 17 00:00:00 2001 From: ATM-Lucas Date: Fri, 24 Jan 2025 16:52:50 +0100 Subject: [PATCH 035/383] Adding model Mail --- htdocs/admin/mails_templates.php | 3 +++ htdocs/core/class/html.formmail.class.php | 3 ++- htdocs/product/card.php | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/htdocs/admin/mails_templates.php b/htdocs/admin/mails_templates.php index 6f79d58551a..d710306172c 100644 --- a/htdocs/admin/mails_templates.php +++ b/htdocs/admin/mails_templates.php @@ -252,6 +252,9 @@ if (isModEnabled('eventorganization') && $user->hasRight('eventorganization', 'r if (isModEnabled('partnership') && $user->hasRight('partnership', 'read')) { $elementList['partnership_send'] = img_picto('', 'partnership', 'class="pictofixedwidth"').dol_escape_htmltag($langs->trans('MailToPartnership')); } +if (isModEnabled('product') && !empty($user->rights->produit->lire)) { + $elementList['product_send'] = img_picto('', 'product', 'class="pictofixedwidth"').dol_escape_htmltag($langs->trans('Product')); +} $parameters = array('elementList' => $elementList); $reshook = $hookmanager->executeHooks('emailElementlist', $parameters); // Note that $action and $object may have been modified by some hooks diff --git a/htdocs/core/class/html.formmail.class.php b/htdocs/core/class/html.formmail.class.php index 3f09d2816f7..8964679bc7e 100644 --- a/htdocs/core/class/html.formmail.class.php +++ b/htdocs/core/class/html.formmail.class.php @@ -534,6 +534,7 @@ class FormMail extends Form $listofmimes = array(); $keytoavoidconflict = empty($this->trackid) ? '' : '-'.$this->trackid; // this->trackid must be defined + if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) { if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) { if (!empty($arraydefaultmessage->joinfiles) && !empty($this->param['fileinit']) && is_array($this->param['fileinit'])) { foreach ($this->param['fileinit'] as $path) { @@ -624,7 +625,7 @@ class FormMail extends Form } elseif (!empty($this->param['models']) && in_array($this->param['models'], array( 'propal_send', 'order_send', 'facture_send', 'shipping_send', 'fichinter_send', 'supplier_proposal_send', 'order_supplier_send', - 'invoice_supplier_send', 'thirdparty', 'contract', 'user', 'recruitmentcandidature_send', 'all' + 'invoice_supplier_send', 'thirdparty', 'contract', 'user', 'recruitmentcandidature_send', 'product_send', 'all' ))) { // If list of template is empty $out .= '
'."\n"; diff --git a/htdocs/product/card.php b/htdocs/product/card.php index 2a0868bcaa3..7c3588d0e08 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -3176,6 +3176,10 @@ if (getDolGlobalString('PRODUCT_ADD_FORM_ADD_TO') && $object->id && ($action == * Generated documents */ +if (GETPOST('modelselected')) { + $action = 'presend'; +} + if ($action != 'create' && $action != 'edit' && $action != 'delete') { print '
'; print ''; // ancre From 9c10d36b1b6f96c6327009110a2b707d688c56d0 Mon Sep 17 00:00:00 2001 From: ATM-Lucas Date: Fri, 24 Jan 2025 16:55:13 +0100 Subject: [PATCH 036/383] fault --- htdocs/core/class/html.formmail.class.php | 1152 ++++++++++----------- 1 file changed, 576 insertions(+), 576 deletions(-) diff --git a/htdocs/core/class/html.formmail.class.php b/htdocs/core/class/html.formmail.class.php index 8964679bc7e..a5881534518 100644 --- a/htdocs/core/class/html.formmail.class.php +++ b/htdocs/core/class/html.formmail.class.php @@ -473,7 +473,7 @@ class FormMail extends Form global $conf, $langs, $user, $hookmanager, $form; // Required to show preview wof mail attachments - require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; + require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php'; $formfile = new FormFile($this->db); if (!is_object($form)) { @@ -532,632 +532,632 @@ class FormMail extends Form $listofpaths = array(); $listofnames = array(); $listofmimes = array(); - $keytoavoidconflict = empty($this->trackid) ? '' : '-'.$this->trackid; // this->trackid must be defined + $keytoavoidconflict = empty($this->trackid) ? '' : '-' . $this->trackid; // this->trackid must be defined if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) { - if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) { - if (!empty($arraydefaultmessage->joinfiles) && !empty($this->param['fileinit']) && is_array($this->param['fileinit'])) { - foreach ($this->param['fileinit'] as $path) { - if (!empty($path)) { - $this->add_attached_files($path); + if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) { + if (!empty($arraydefaultmessage->joinfiles) && !empty($this->param['fileinit']) && is_array($this->param['fileinit'])) { + foreach ($this->param['fileinit'] as $path) { + if (!empty($path)) { + $this->add_attached_files($path); + } } } } - } - if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) { - $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]); - } - if (!empty($_SESSION["listofnames".$keytoavoidconflict])) { - $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]); - } - if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) { - $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]); - } - - - $out .= "\n".'
'."\n"; - if ($this->withform == 1) { - $out .= '
'."\n"; - - $out .= ''; - $out .= ''; - $out .= ''; - $out .= ''; - $out .= ''; - } - if (!empty($this->withfrom)) { - if (!empty($this->withfromreadonly)) { - $out .= ''; - $out .= ''; + if (!empty($_SESSION["listofpaths" . $keytoavoidconflict])) { + $listofpaths = explode(';', $_SESSION["listofpaths" . $keytoavoidconflict]); } - } - foreach ($this->param as $key => $value) { - if (is_array($value)) { - $out .= "\n"; - } else { - $out .= ''."\n"; + if (!empty($_SESSION["listofnames" . $keytoavoidconflict])) { + $listofnames = explode(';', $_SESSION["listofnames" . $keytoavoidconflict]); } - } - - $modelmail_array = array(); - if ($this->param['models'] != 'none') { - $result = $this->fetchAllEMailTemplate($this->param["models"], $user, $outputlangs); - if ($result < 0) { - setEventMessages($this->error, $this->errors, 'errors'); + if (!empty($_SESSION["listofmimes" . $keytoavoidconflict])) { + $listofmimes = explode(';', $_SESSION["listofmimes" . $keytoavoidconflict]); } - foreach ($this->lines_model as $line) { - $reg = array(); - if (preg_match('/\((.*)\)/', $line->label, $reg)) { - $labeltouse = $langs->trans($reg[1]); // langs->trans when label is __(xxx)__ + + $out .= "\n" . '
' . "\n"; + if ($this->withform == 1) { + $out .= '' . "\n"; + + $out .= ''; + $out .= ''; + $out .= ''; + $out .= ''; + $out .= ''; + } + if (!empty($this->withfrom)) { + if (!empty($this->withfromreadonly)) { + $out .= ''; + $out .= ''; + } + } + foreach ($this->param as $key => $value) { + if (is_array($value)) { + $out .= "\n"; } else { - $labeltouse = $line->label; - } - - // We escape the $labeltouse to store it into $modelmail_array. - $modelmail_array[$line->id] = dol_escape_htmltag($labeltouse); - if ($line->lang) { - $modelmail_array[$line->id] .= ' '.picto_from_langcode($line->lang); - } - if ($line->private) { - $modelmail_array[$line->id] .= ' - '.dol_escape_htmltag($langs->trans("Private")).''; + $out .= '' . "\n"; } } - } - // Zone to select email template - if (count($modelmail_array) > 0) { - $model_mail_selected_id = GETPOSTISSET('modelmailselected') ? GETPOSTINT('modelmailselected') : ($arraydefaultmessage->id > 0 ? $arraydefaultmessage->id : 0); + $modelmail_array = array(); + if ($this->param['models'] != 'none') { + $result = $this->fetchAllEMailTemplate($this->param["models"], $user, $outputlangs); + if ($result < 0) { + setEventMessages($this->error, $this->errors, 'errors'); + } - // If list of template is filled - $out .= '
'."\n"; - - $out .= $this->selectarray('modelmailselected', $modelmail_array, $model_mail_selected_id, $langs->trans('SelectMailModel'), 0, 0, '', 0, 0, 0, '', 'minwidth100', 1, '', 0, 1); - if ($user->admin) { - $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFrom", $langs->transnoentitiesnoconv('Setup').' - '.$langs->transnoentitiesnoconv('EMails')), 1); - } - - $out .= '   '; - $out .= ''; - $out .= '   '; - $out .= '
'; - } elseif (!empty($this->param['models']) && in_array($this->param['models'], array( - 'propal_send', 'order_send', 'facture_send', - 'shipping_send', 'fichinter_send', 'supplier_proposal_send', 'order_supplier_send', - 'invoice_supplier_send', 'thirdparty', 'contract', 'user', 'recruitmentcandidature_send', 'product_send', 'all' - ))) { - // If list of template is empty - $out .= '
'."\n"; - $out .= ''.$langs->trans('SelectMailModel').': '; - $out .= ''; // Do not put 'disabled' on 'option' tag, it is already on 'select' and it makes chrome crazy. - if ($user->admin) { - $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFrom", $langs->transnoentitiesnoconv('Setup').' - '.$langs->transnoentitiesnoconv('EMails')), 1); - } - $out .= '   '; - $out .= ''; - $out .= '   '; - $out .= '
'; - } else { - $out .= ''; - } - - - $out .= ''."\n"; - - // Substitution array/string - $helpforsubstitution = ''; - if (is_array($this->substit) && count($this->substit)) { - $helpforsubstitution .= $langs->trans('AvailableVariables').' :

'."\n"; - } - foreach ($this->substit as $key => $val) { - // Do not show deprecated variables into the tooltip help of substitution variables - if (in_array($key, array('__NEWREF__', '__REFCLIENT__', '__REFSUPPLIER__', '__SUPPLIER_ORDER_DATE_DELIVERY__', '__SUPPLIER_ORDER_DELAY_DELIVERY__'))) { - continue; - } - $helpforsubstitution .= $key.' -> '.$langs->trans(dol_string_nohtmltag(dolGetFirstLineOfText($val))).'
'; - } - if (is_array($this->substit) && count($this->substit)) { - $helpforsubstitution .= '
'; - } - - /* - if (!empty($this->withsubstit)) { // Unset or set ->withsubstit=0 to disable this. - $out .= '\n"; - }*/ - - // From - if (!empty($this->withfrom)) { - if (!empty($this->withfromreadonly)) { - $out .= '
'; - if (is_numeric($this->withsubstit)) { - $out .= $form->textwithpicto($langs->trans("EMailTestSubstitutionReplacedByGenericValues"), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltip'); // Old usage - } else { - $out .= $form->textwithpicto($langs->trans('AvailableVariables'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltip'); // New usage - } - $out .= "
'.$langs->trans("MailFrom").''; - - // $this->fromtype is the default value to use to select sender - if (!($this->fromtype === 'user' && $this->fromid > 0) - && !($this->fromtype === 'company') - && !($this->fromtype === 'robot') - && !preg_match('/user_aliases/', $this->fromtype) - && !preg_match('/global_aliases/', $this->fromtype) - && !preg_match('/senderprofile/', $this->fromtype) - ) { - // Use this->fromname and this->frommail or error if not defined - $out .= $this->fromname; - if ($this->frommail) { - $out .= ' <'.$this->frommail.'>'; + foreach ($this->lines_model as $line) { + $reg = array(); + if (preg_match('/\((.*)\)/', $line->label, $reg)) { + $labeltouse = $langs->trans($reg[1]); // langs->trans when label is __(xxx)__ } else { - if ($this->fromtype) { + $labeltouse = $line->label; + } + + // We escape the $labeltouse to store it into $modelmail_array. + $modelmail_array[$line->id] = dol_escape_htmltag($labeltouse); + if ($line->lang) { + $modelmail_array[$line->id] .= ' ' . picto_from_langcode($line->lang); + } + if ($line->private) { + $modelmail_array[$line->id] .= ' - ' . dol_escape_htmltag($langs->trans("Private")) . ''; + } + } + } + + // Zone to select email template + if (count($modelmail_array) > 0) { + $model_mail_selected_id = GETPOSTISSET('modelmailselected') ? GETPOSTINT('modelmailselected') : ($arraydefaultmessage->id > 0 ? $arraydefaultmessage->id : 0); + + // If list of template is filled + $out .= '
' . "\n"; + + $out .= $this->selectarray('modelmailselected', $modelmail_array, $model_mail_selected_id, $langs->trans('SelectMailModel'), 0, 0, '', 0, 0, 0, '', 'minwidth100', 1, '', 0, 1); + if ($user->admin) { + $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFrom", $langs->transnoentitiesnoconv('Setup') . ' - ' . $langs->transnoentitiesnoconv('EMails')), 1); + } + + $out .= '   '; + $out .= ''; + $out .= '   '; + $out .= '
'; + } elseif (!empty($this->param['models']) && in_array($this->param['models'], array( + 'propal_send', 'order_send', 'facture_send', + 'shipping_send', 'fichinter_send', 'supplier_proposal_send', 'order_supplier_send', + 'invoice_supplier_send', 'thirdparty', 'contract', 'user', 'recruitmentcandidature_send', 'product_send', 'all' + ))) { + // If list of template is empty + $out .= '
' . "\n"; + $out .= '' . $langs->trans('SelectMailModel') . ': '; + $out .= ''; // Do not put 'disabled' on 'option' tag, it is already on 'select' and it makes chrome crazy. + if ($user->admin) { + $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFrom", $langs->transnoentitiesnoconv('Setup') . ' - ' . $langs->transnoentitiesnoconv('EMails')), 1); + } + $out .= '   '; + $out .= ''; + $out .= '   '; + $out .= '
'; + } else { + $out .= ''; + } + + + $out .= '' . "\n"; + + // Substitution array/string + $helpforsubstitution = ''; + if (is_array($this->substit) && count($this->substit)) { + $helpforsubstitution .= $langs->trans('AvailableVariables') . ' :

' . "\n"; + } + foreach ($this->substit as $key => $val) { + // Do not show deprecated variables into the tooltip help of substitution variables + if (in_array($key, array('__NEWREF__', '__REFCLIENT__', '__REFSUPPLIER__', '__SUPPLIER_ORDER_DATE_DELIVERY__', '__SUPPLIER_ORDER_DELAY_DELIVERY__'))) { + continue; + } + $helpforsubstitution .= $key . ' -> ' . $langs->trans(dol_string_nohtmltag(dolGetFirstLineOfText($val))) . '
'; + } + if (is_array($this->substit) && count($this->substit)) { + $helpforsubstitution .= '
'; + } + + /* + if (!empty($this->withsubstit)) { // Unset or set ->withsubstit=0 to disable this. + $out .= '\n"; + }*/ + + // From + if (!empty($this->withfrom)) { + if (!empty($this->withfromreadonly)) { + $out .= '\n"; - } else { - $out .= '\n"; - } - } - - // To - if (!empty($this->withto) || is_array($this->withto)) { - $out .= $this->getHtmlForTo(); - } - - // To User - if (!empty($this->withtouser) && is_array($this->withtouser) && getDolGlobalString('MAIN_MAIL_ENABLED_USER_DEST_SELECT')) { - $out .= '\n"; - } - - // With option for one email per recipient - if (!empty($this->withoptiononeemailperrecipient)) { - if (abs($this->withoptiononeemailperrecipient) == 1) { - $out .= ''; - } else { - $out .= ''; - } - } - - // CC - if (!empty($this->withtocc) || is_array($this->withtocc)) { - $out .= $this->getHtmlForCc(); - } - - // To User cc - if (!empty($this->withtoccuser) && is_array($this->withtoccuser) && getDolGlobalString('MAIN_MAIL_ENABLED_USER_DEST_SELECT')) { - $out .= '\n"; - } - - // CCC - if (!empty($this->withtoccc) || is_array($this->withtoccc)) { - $out .= $this->getHtmlForWithCcc(); - } - - // Replyto - if (!empty($this->withreplyto)) { - if ($this->withreplytoreadonly) { - $out .= ''; - $out .= ''; - $out .= "\n"; - } - } - - // Errorsto - if (!empty($this->witherrorsto)) { - $out .= $this->getHtmlForWithErrorsTo(); - } - - // Ask delivery receipt - if (!empty($this->withdeliveryreceipt) && getDolGlobalInt('MAIN_EMAIL_SUPPORT_ACK')) { - $out .= $this->getHtmlForDeliveryreceipt(); - } - - // Topic - if (!empty($this->withtopic)) { - $out .= $this->getHtmlForTopic($arraydefaultmessage, $helpforsubstitution); - } - - // Attached files - if (!empty($this->withfile)) { - $out .= ''; - $out .= ''; - - $out .= '\n"; } else { - $out .= '
'; + $out .= '\n"; } } - if (is_numeric($this->withfile)) { - // TODO Trick to have param removedfile containing nb of file to delete. But this does not works without javascript - $out .= ''."\n"; - $out .= ''."\n"; - if (count($listofpaths)) { - foreach ($listofpaths as $key => $val) { - $relativepathtofile = substr($val, (strlen(DOL_DATA_ROOT) - strlen($val))); + // To + if (!empty($this->withto) || is_array($this->withto)) { + $out .= $this->getHtmlForTo(); + } - $entity = (isset($this->param['object_entity']) ? $this->param['object_entity'] : $conf->entity); - if ($entity > 1) { - $relativepathtofile = str_replace('/'.$entity.'/', '/', $relativepathtofile); + // To User + if (!empty($this->withtouser) && is_array($this->withtouser) && getDolGlobalString('MAIN_MAIL_ENABLED_USER_DEST_SELECT')) { + $out .= '\n"; + } + + // With option for one email per recipient + if (!empty($this->withoptiononeemailperrecipient)) { + if (abs($this->withoptiononeemailperrecipient) == 1) { + $out .= ''; + } else { + $out .= ''; + } + } + + // CC + if (!empty($this->withtocc) || is_array($this->withtocc)) { + $out .= $this->getHtmlForCc(); + } + + // To User cc + if (!empty($this->withtoccuser) && is_array($this->withtoccuser) && getDolGlobalString('MAIN_MAIL_ENABLED_USER_DEST_SELECT')) { + $out .= '\n"; + } + + // CCC + if (!empty($this->withtoccc) || is_array($this->withtoccc)) { + $out .= $this->getHtmlForWithCcc(); + } + + // Replyto + if (!empty($this->withreplyto)) { + if ($this->withreplytoreadonly) { + $out .= ''; + $out .= ''; + $out .= "\n"; + } + } + + // Errorsto + if (!empty($this->witherrorsto)) { + $out .= $this->getHtmlForWithErrorsTo(); + } + + // Ask delivery receipt + if (!empty($this->withdeliveryreceipt) && getDolGlobalInt('MAIN_EMAIL_SUPPORT_ACK')) { + $out .= $this->getHtmlForDeliveryreceipt(); + } + + // Topic + if (!empty($this->withtopic)) { + $out .= $this->getHtmlForTopic($arraydefaultmessage, $helpforsubstitution); + } + + // Attached files + if (!empty($this->withfile)) { + $out .= ''; + $out .= ''; + + $out .= '\n"; } - $out .= "\n"; - } - - // Message (+ Links to choose layout or ai prompt) - if (!empty($this->withbody)) { - $defaultmessage = GETPOST('message', 'restricthtml'); - if (!GETPOST('modelselected', 'alpha') || GETPOST('modelmailselected') != '-1') { - if ($arraydefaultmessage && $arraydefaultmessage->content) { - $defaultmessage = $arraydefaultmessage->content; - } elseif (!is_numeric($this->withbody)) { - $defaultmessage = $this->withbody; + // Message (+ Links to choose layout or ai prompt) + if (!empty($this->withbody)) { + $defaultmessage = GETPOST('message', 'restricthtml'); + if (!GETPOST('modelselected', 'alpha') || GETPOST('modelmailselected') != '-1') { + if ($arraydefaultmessage && $arraydefaultmessage->content) { + $defaultmessage = $arraydefaultmessage->content; + } elseif (!is_numeric($this->withbody)) { + $defaultmessage = $this->withbody; + } } - } - // Complete substitution array with the url to make online payment - $paymenturl = ''; - // Set the online payment url link into __ONLINE_PAYMENT_URL__ key - require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php'; - $validpaymentmethod = getValidOnlinePaymentMethods(''); - - if (empty($this->substit['__REF__'])) { // @phan-suppress-current-line PhanTypeMismatchProperty + // Complete substitution array with the url to make online payment $paymenturl = ''; - } else { - $langs->loadLangs(array('paypal', 'other')); - $typeforonlinepayment = 'free'; - if ($this->param["models"] == 'order' || $this->param["models"] == 'order_send') { - $typeforonlinepayment = 'order'; // TODO use detection on something else than template - } - if ($this->param["models"] == 'invoice' || $this->param["models"] == 'facture_send') { - $typeforonlinepayment = 'invoice'; // TODO use detection on something else than template - } - if ($this->param["models"] == 'member') { - $typeforonlinepayment = 'member'; // TODO use detection on something else than template - } - $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $this->substit['__REF__']); - $paymenturl = $url; - } + // Set the online payment url link into __ONLINE_PAYMENT_URL__ key + require_once DOL_DOCUMENT_ROOT . '/core/lib/payments.lib.php'; + $validpaymentmethod = getValidOnlinePaymentMethods(''); - if (count($validpaymentmethod) > 0 && $paymenturl) { - $langs->load('other'); - $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = str_replace('\n', "\n", $langs->transnoentities("PredefinedMailContentLink", $paymenturl)); - $this->substit['__ONLINE_PAYMENT_URL__'] = $paymenturl; - } elseif (count($validpaymentmethod) > 0) { - $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = '__ONLINE_PAYMENT_TEXT_AND_URL__'; - $this->substit['__ONLINE_PAYMENT_URL__'] = '__ONLINE_PAYMENT_URL__'; - } else { - $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = ''; - $this->substit['__ONLINE_PAYMENT_URL__'] = ''; - } - - $this->substit['__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__'] = ''; - - // Generate the string with the template for lines repeated and filled for each line - $lines = ''; - $defaultlines = $arraydefaultmessage->content_lines; - if (isset($defaultlines)) { - foreach ($this->substit_lines as $lineid => $substit_line) { - $lines .= make_substitutions($defaultlines, $substit_line)."\n"; - } - } - $this->substit['__LINES__'] = $lines; - - $defaultmessage = str_replace('\n', "\n", $defaultmessage); - - // Deal with format differences between message and some substitution variables (text / HTML) - $atleastonecomponentishtml = 0; - if (strpos($defaultmessage, '__USER_SIGNATURE__') !== false && dol_textishtml($this->substit['__USER_SIGNATURE__'])) { - $atleastonecomponentishtml++; - } - if (strpos($defaultmessage, '__SENDEREMAIL_SIGNATURE__') !== false && dol_textishtml($this->substit['__SENDEREMAIL_SIGNATURE__'])) { - $atleastonecomponentishtml++; - } - if (strpos($defaultmessage, '__ONLINE_PAYMENT_TEXT_AND_URL__') !== false && dol_textishtml($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'])) { - $atleastonecomponentishtml++; - } - if (strpos($defaultmessage, '__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__') !== false && dol_textishtml($this->substit['__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__'])) { - $atleastonecomponentishtml++; - } - if (dol_textishtml($defaultmessage)) { - $atleastonecomponentishtml++; - } - if ($atleastonecomponentishtml) { - if (!dol_textishtml($this->substit['__USER_SIGNATURE__'])) { - $this->substit['__USER_SIGNATURE__'] = dol_nl2br($this->substit['__USER_SIGNATURE__']); - } - if (!dol_textishtml($this->substit['__SENDEREMAIL_SIGNATURE__'])) { - $this->substit['__SENDEREMAIL_SIGNATURE__'] = dol_nl2br($this->substit['__SENDEREMAIL_SIGNATURE__']); - } - if (!dol_textishtml($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'])) { - $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = dol_nl2br($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__']); - } - if (!dol_textishtml($defaultmessage)) { - $defaultmessage = dol_nl2br($defaultmessage); - } - } - - if (GETPOSTISSET("message") && !GETPOST('modelselected')) { - $defaultmessage = GETPOST("message", "restricthtml"); - } else { - $defaultmessage = make_substitutions($defaultmessage, $this->substit); - // Clean first \n and br (to avoid empty line when CONTACTCIVNAME is empty) - $defaultmessage = preg_replace("/^(
)+/", "", $defaultmessage); - $defaultmessage = preg_replace("/^\n+/", "", $defaultmessage); - } - - $out .= ''; - $out .= ''; - $out .= ''; - $out .= ''; - - $out .= ''; - $out .= ''; + $out .= ''; + $out .= ''; + $out .= ''; + + $out .= ''; + $out .= '\n"; } - $out .= "\n"; - } - $out .= '
'; + if (is_numeric($this->withsubstit)) { + $out .= $form->textwithpicto($langs->trans("EMailTestSubstitutionReplacedByGenericValues"), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltip'); // Old usage + } else { + $out .= $form->textwithpicto($langs->trans('AvailableVariables'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltip'); // New usage + } + $out .= "
' . $langs->trans("MailFrom") . ''; + + // $this->fromtype is the default value to use to select sender + if (!($this->fromtype === 'user' && $this->fromid > 0) + && !($this->fromtype === 'company') + && !($this->fromtype === 'robot') + && !preg_match('/user_aliases/', $this->fromtype) + && !preg_match('/global_aliases/', $this->fromtype) + && !preg_match('/senderprofile/', $this->fromtype) + ) { + // Use this->fromname and this->frommail or error if not defined + $out .= $this->fromname; + if ($this->frommail) { + $out .= ' <' . $this->frommail . '>'; + } else { + if ($this->fromtype) { + $langs->load('errors'); + $out .= ' <' . $langs->trans('ErrorNoMailDefinedForThisUser') . '> '; + } + } + } else { + $liste = array(); + + // Add user email + if (empty($user->email)) { $langs->load('errors'); - $out .= ' <'.$langs->trans('ErrorNoMailDefinedForThisUser').'> '; + $s = $user->getFullName($langs) . ' <' . $langs->trans('ErrorNoMailDefinedForThisUser') . '>'; + } else { + $s = $user->getFullName($langs) . ' <' . $user->email . '>'; } - } - } else { - $liste = array(); + $liste['user'] = array('label' => $s, 'data-html' => $s); - // Add user email - if (empty($user->email)) { - $langs->load('errors'); - $s = $user->getFullName($langs).' <'.$langs->trans('ErrorNoMailDefinedForThisUser').'>'; - } else { - $s = $user->getFullName($langs).' <'.$user->email.'>'; - } - $liste['user'] = array('label' => $s, 'data-html' => $s); - - // Add also company main email - if (getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')) { - $s = (!getDolGlobalString('MAIN_INFO_SOCIETE_NOM') ? $conf->global->MAIN_INFO_SOCIETE_EMAIL : $conf->global->MAIN_INFO_SOCIETE_NOM).' <' . getDolGlobalString('MAIN_INFO_SOCIETE_MAIL').'>'; - $liste['company'] = array('label' => $s, 'data-html' => $s); - } - - // Add also email aliases if there is some - $listaliases = array( - 'user_aliases' => (empty($user->email_aliases) ? '' : $user->email_aliases), - 'global_aliases' => getDolGlobalString('MAIN_INFO_SOCIETE_MAIL_ALIASES'), - ); - - if (!empty($arraydefaultmessage->email_from)) { - $templatemailfrom = ' <'.$arraydefaultmessage->email_from.'>'; - $liste['from_template_'.GETPOST('modelmailselected')] = array('label' => $templatemailfrom, 'data-html' => $templatemailfrom); - } - - // Also add robot email - if (!empty($this->fromalsorobot)) { - if (getDolGlobalString('MAIN_MAIL_EMAIL_FROM') && getDolGlobalString('MAIN_MAIL_EMAIL_FROM') != getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')) { - $s = getDolGlobalString('MAIN_MAIL_EMAIL_FROM'); - if ($this->frommail) { - $s .= ' <' . getDolGlobalString('MAIN_MAIL_EMAIL_FROM').'>'; - } - $liste['main_from'] = array('label' => $s, 'data-html' => $s); + // Add also company main email + if (getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')) { + $s = (!getDolGlobalString('MAIN_INFO_SOCIETE_NOM') ? $conf->global->MAIN_INFO_SOCIETE_EMAIL : $conf->global->MAIN_INFO_SOCIETE_NOM) . ' <' . getDolGlobalString('MAIN_INFO_SOCIETE_MAIL') . '>'; + $liste['company'] = array('label' => $s, 'data-html' => $s); } - } - // Add also email aliases from the c_email_senderprofile table - $sql = "SELECT rowid, label, email FROM ".$this->db->prefix()."c_email_senderprofile"; - $sql .= " WHERE active = 1 AND (private = 0 OR private = ".((int) $user->id).")"; - $sql .= " ORDER BY position"; - $resql = $this->db->query($sql); - if ($resql) { - $num = $this->db->num_rows($resql); - $i = 0; - while ($i < $num) { - $obj = $this->db->fetch_object($resql); - if ($obj) { - $listaliases['senderprofile_'.$obj->rowid] = $obj->label.' <'.$obj->email.'>'; - } - $i++; + // Add also email aliases if there is some + $listaliases = array( + 'user_aliases' => (empty($user->email_aliases) ? '' : $user->email_aliases), + 'global_aliases' => getDolGlobalString('MAIN_INFO_SOCIETE_MAIL_ALIASES'), + ); + + if (!empty($arraydefaultmessage->email_from)) { + $templatemailfrom = ' <' . $arraydefaultmessage->email_from . '>'; + $liste['from_template_' . GETPOST('modelmailselected')] = array('label' => $templatemailfrom, 'data-html' => $templatemailfrom); } - } else { - dol_print_error($this->db); - } - foreach ($listaliases as $typealias => $listalias) { - $posalias = 0; - $listaliasarray = explode(',', $listalias); - foreach ($listaliasarray as $listaliasval) { - $posalias++; - $listaliasval = trim($listaliasval); - if ($listaliasval) { - $listaliasval = preg_replace('//', '>', $listaliasval); - if (!preg_match('/</', $listaliasval)) { - $listaliasval = '<'.$listaliasval.'>'; + // Also add robot email + if (!empty($this->fromalsorobot)) { + if (getDolGlobalString('MAIN_MAIL_EMAIL_FROM') && getDolGlobalString('MAIN_MAIL_EMAIL_FROM') != getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')) { + $s = getDolGlobalString('MAIN_MAIL_EMAIL_FROM'); + if ($this->frommail) { + $s .= ' <' . getDolGlobalString('MAIN_MAIL_EMAIL_FROM') . '>'; } - $liste[$typealias.'_'.$posalias] = array('label' => $listaliasval, 'data-html' => $listaliasval); + $liste['main_from'] = array('label' => $s, 'data-html' => $s); } } - } - // Using ajaxcombo here make the '' no more visible on list because is not a valid html tag, - // so we transform before each record into $liste to be printable with ajaxcombo by replacing <> into () - // $liste['senderprofile_0_0'] = array('label'=>'rrr', 'data-html'=>'rrr <aaaa>'); - foreach ($liste as $key => $val) { - if (!empty($liste[$key]['data-html'])) { - $liste[$key]['data-html'] = str_replace(array('<', '<', '>', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $liste[$key]['data-html']); - $liste[$key]['data-html'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('(', ')'), $liste[$key]['data-html']); + // Add also email aliases from the c_email_senderprofile table + $sql = "SELECT rowid, label, email FROM " . $this->db->prefix() . "c_email_senderprofile"; + $sql .= " WHERE active = 1 AND (private = 0 OR private = " . ((int)$user->id) . ")"; + $sql .= " ORDER BY position"; + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) { + $obj = $this->db->fetch_object($resql); + if ($obj) { + $listaliases['senderprofile_' . $obj->rowid] = $obj->label . ' <' . $obj->email . '>'; + } + $i++; + } + } else { + dol_print_error($this->db); } + + foreach ($listaliases as $typealias => $listalias) { + $posalias = 0; + $listaliasarray = explode(',', $listalias); + foreach ($listaliasarray as $listaliasval) { + $posalias++; + $listaliasval = trim($listaliasval); + if ($listaliasval) { + $listaliasval = preg_replace('//', '>', $listaliasval); + if (!preg_match('/</', $listaliasval)) { + $listaliasval = '<' . $listaliasval . '>'; + } + $liste[$typealias . '_' . $posalias] = array('label' => $listaliasval, 'data-html' => $listaliasval); + } + } + } + + // Using ajaxcombo here make the '' no more visible on list because is not a valid html tag, + // so we transform before each record into $liste to be printable with ajaxcombo by replacing <> into () + // $liste['senderprofile_0_0'] = array('label'=>'rrr', 'data-html'=>'rrr <aaaa>'); + foreach ($liste as $key => $val) { + if (!empty($liste[$key]['data-html'])) { + $liste[$key]['data-html'] = str_replace(array('<', '<', '>', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $liste[$key]['data-html']); + $liste[$key]['data-html'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('(', ')'), $liste[$key]['data-html']); + } + } + $out .= ' ' . $form->selectarray('fromtype', $liste, empty($arraydefaultmessage->email_from) ? $this->fromtype : 'from_template_' . GETPOST('modelmailselected'), 0, 0, 0, '', 0, 0, 0, '', 'fromforsendingprofile maxwidth200onsmartphone', 1, '', $disablebademails); } - $out .= ' '.$form->selectarray('fromtype', $liste, empty($arraydefaultmessage->email_from) ? $this->fromtype : 'from_template_'.GETPOST('modelmailselected'), 0, 0, 0, '', 0, 0, 0, '', 'fromforsendingprofile maxwidth200onsmartphone', 1, '', $disablebademails); - } - $out .= "
'.$langs->trans("MailFrom").""; - $out .= $langs->trans("Name").':'; - $out .= '    '; - $out .= $langs->trans("EMail").':<>'; - $out .= "
'; - $out .= $langs->trans("MailToUsers"); - $out .= ''; - - // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time - $tmparray = $this->withtouser; - foreach ($tmparray as $key => $val) { - $tmparray[$key] = dol_htmlentities($tmparray[$key], 0, 'UTF-8', true); - } - $withtoselected = GETPOST("receiveruser", 'array'); // Array of selected value - if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') { - $withtoselected = array_keys($tmparray); - } - $out .= $form->multiselectarray("receiveruser", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, ""); - $out .= "
'; - $out .= $langs->trans("GroupEmails"); - $out .= ''; - $out .= ' withoptiononeemailperrecipient > 0 ? ' checked="checked"' : '').'> '; - $out .= ''; - //$out .= ''; - //$out .= ' - '; - //$out .= $langs->trans("WarningIfYouCheckOneRecipientPerEmail"); - //$out .= ''; - if (getDolGlobalString('MASS_ACTION_EMAIL_ON_DIFFERENT_THIRPARTIES_ADD_CUSTOM_EMAIL')) { - if (!empty($this->withto) && !is_array($this->withto)) { - $out .= ' '.$langs->trans("or").' '; - } - } - $out .= '
'; - $out .= $langs->trans("MailToCCUsers"); - $out .= ''; - - // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time - $tmparray = $this->withtoccuser; - foreach ($tmparray as $key => $val) { - $tmparray[$key] = dol_htmlentities($tmparray[$key], 0, 'UTF-8', true); - } - $withtoselected = GETPOST("receiverccuser", 'array'); // Array of selected value - if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') { - $withtoselected = array_keys($tmparray); - } - $out .= $form->multiselectarray("receiverccuser", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, ""); - $out .= "
".$langs->trans("MailReply")."".$this->replytoname.($this->replytomail ? (" <".$this->replytomail.">") : ""); - $out .= "
'.$langs->trans("MailFile").''; - - if ($this->withmaindocfile) { - // withmaindocfile is set to 1 or -1 to show the checkbox (-1 = checked or 1 = not checked) - if (GETPOSTISSET('sendmail')) { - $this->withmaindocfile = (GETPOST('addmaindocfile', 'alpha') ? -1 : 1); - } elseif (is_object($arraydefaultmessage) && $arraydefaultmessage->id > 0) { - // If a template was selected, we use setup of template to define if join file checkbox is selected or not. - $this->withmaindocfile = ($arraydefaultmessage->joinfiles ? -1 : 1); - } - } - - if (!empty($this->withmaindocfile)) { - if ($this->withmaindocfile == 1) { - $out .= ''; - } elseif ($this->withmaindocfile == -1) { - $out .= ''; - } - if (getDolGlobalString('MAIL_MASS_ACTION_ADD_LAST_IF_MAIN_DOC_NOT_FOUND')) { - $out .= '
'; + $out .= "
' . $langs->trans("MailFrom") . ""; + $out .= $langs->trans("Name") . ':'; + $out .= '    '; + $out .= $langs->trans("EMail") . ':<>'; + $out .= "
'; + $out .= $langs->trans("MailToUsers"); + $out .= ''; + + // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time + $tmparray = $this->withtouser; + foreach ($tmparray as $key => $val) { + $tmparray[$key] = dol_htmlentities($tmparray[$key], 0, 'UTF-8', true); + } + $withtoselected = GETPOST("receiveruser", 'array'); // Array of selected value + if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') { + $withtoselected = array_keys($tmparray); + } + $out .= $form->multiselectarray("receiveruser", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, ""); + $out .= "
'; + $out .= $langs->trans("GroupEmails"); + $out .= ''; + $out .= ' withoptiononeemailperrecipient > 0 ? ' checked="checked"' : '') . '> '; + $out .= ''; + //$out .= ''; + //$out .= ' - '; + //$out .= $langs->trans("WarningIfYouCheckOneRecipientPerEmail"); + //$out .= ''; + if (getDolGlobalString('MASS_ACTION_EMAIL_ON_DIFFERENT_THIRPARTIES_ADD_CUSTOM_EMAIL')) { + if (!empty($this->withto) && !is_array($this->withto)) { + $out .= ' ' . $langs->trans("or") . ' '; } - // Try to extract data from full path - $formfile_params = array(); - preg_match('#^(/)(\w+)(/)(.+)$#', $relativepathtofile, $formfile_params); - - $out .= '
'; - // Preview of attachment - $out .= img_mime($listofnames[$key]).$listofnames[$key]; - - $out .= ' '.$formfile->showPreview(array(), $formfile_params[2], $formfile_params[4], 0, ($entity == 1 ? '' : 'entity='.((int) $entity))); - - if (!$this->withfilereadonly) { - $out .= ' '; - //$out.= ' '.img_delete($langs->trans("Remove"), 'id="removedfile_'.$key.'" name="removedfile_'.$key.'"', 'removedfile input-nobottom').''; - } - $out .= '
'; } - } /*elseif (empty($this->withmaindocfile)) { + $out .= '
'; + $out .= $langs->trans("MailToCCUsers"); + $out .= ''; + + // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time + $tmparray = $this->withtoccuser; + foreach ($tmparray as $key => $val) { + $tmparray[$key] = dol_htmlentities($tmparray[$key], 0, 'UTF-8', true); + } + $withtoselected = GETPOST("receiverccuser", 'array'); // Array of selected value + if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') { + $withtoselected = array_keys($tmparray); + } + $out .= $form->multiselectarray("receiverccuser", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, ""); + $out .= "
" . $langs->trans("MailReply") . "" . $this->replytoname . ($this->replytomail ? (" <" . $this->replytomail . ">") : ""); + $out .= "
' . $langs->trans("MailFile") . ''; + + if ($this->withmaindocfile) { + // withmaindocfile is set to 1 or -1 to show the checkbox (-1 = checked or 1 = not checked) + if (GETPOSTISSET('sendmail')) { + $this->withmaindocfile = (GETPOST('addmaindocfile', 'alpha') ? -1 : 1); + } elseif (is_object($arraydefaultmessage) && $arraydefaultmessage->id > 0) { + // If a template was selected, we use setup of template to define if join file checkbox is selected or not. + $this->withmaindocfile = ($arraydefaultmessage->joinfiles ? -1 : 1); + } + } + + if (!empty($this->withmaindocfile)) { + if ($this->withmaindocfile == 1) { + $out .= ''; + } elseif ($this->withmaindocfile == -1) { + $out .= ''; + } + if (getDolGlobalString('MAIL_MASS_ACTION_ADD_LAST_IF_MAIN_DOC_NOT_FOUND')) { + $out .= '
'; + } else { + $out .= '
'; + } + } + + if (is_numeric($this->withfile)) { + // TODO Trick to have param removedfile containing nb of file to delete. But this does not works without javascript + $out .= '' . "\n"; + $out .= '' . "\n"; + if (count($listofpaths)) { + foreach ($listofpaths as $key => $val) { + $relativepathtofile = substr($val, (strlen(DOL_DATA_ROOT) - strlen($val))); + + $entity = (isset($this->param['object_entity']) ? $this->param['object_entity'] : $conf->entity); + if ($entity > 1) { + $relativepathtofile = str_replace('/' . $entity . '/', '/', $relativepathtofile); + } + // Try to extract data from full path + $formfile_params = array(); + preg_match('#^(/)(\w+)(/)(.+)$#', $relativepathtofile, $formfile_params); + + $out .= '
'; + // Preview of attachment + $out .= img_mime($listofnames[$key]) . $listofnames[$key]; + + $out .= ' ' . $formfile->showPreview(array(), $formfile_params[2], $formfile_params[4], 0, ($entity == 1 ? '' : 'entity=' . ((int)$entity))); + + if (!$this->withfilereadonly) { + $out .= ' '; + //$out.= ' '.img_delete($langs->trans("Remove"), 'id="removedfile_'.$key.'" name="removedfile_'.$key.'"', 'removedfile input-nobottom').''; + } + $out .= '
'; + } + } /*elseif (empty($this->withmaindocfile)) { //$out .= ''.$langs->trans("NoAttachedFiles").'
'; }*/ - if ($this->withfile == 2) { - $maxfilesizearray = getMaxFileSizeArray(); - $maxmin = $maxfilesizearray['maxmin']; - if ($maxmin > 0) { - $out .= ''; // MAX_FILE_SIZE must precede the field type=file + if ($this->withfile == 2) { + $maxfilesizearray = getMaxFileSizeArray(); + $maxmin = $maxfilesizearray['maxmin']; + if ($maxmin > 0) { + $out .= ''; // MAX_FILE_SIZE must precede the field type=file + } + // Can add other files + if (!getDolGlobalString('FROM_MAIL_DONT_USE_INPUT_FILE_MULTIPLE')) { + $out .= ''; + } else { + $out .= ''; + } + $out .= ' '; + $out .= ''; } - // Can add other files - if (!getDolGlobalString('FROM_MAIL_DONT_USE_INPUT_FILE_MULTIPLE')) { - $out .= ''; - } else { - $out .= ''; - } - $out .= ' '; - $out .= ''; + } else { + $out .= $this->withfile; } - } else { - $out .= $this->withfile; + + $out .= "
'; - $out .= $form->textwithpicto($langs->trans('MailText'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltipfrombody'); - $out .= ''; - - $formmail = $this; - $showlinktolayout = ($formmail->withfckeditor && getDolGlobalInt('MAIN_EMAIL_USE_LAYOUT')) ? $formmail->withlayout : ''; - $showlinktolayoutlabel = $langs->trans("FillMessageWithALayout"); - $showlinktoai = ($formmail->withaiprompt && isModEnabled('ai')) ? 'textgenerationemail' : ''; - $showlinktoailabel = $langs->trans("FillMessageWithAIContent"); - $formatforouput = ''; - $htmlname = 'message'; - - // Fill $out - include DOL_DOCUMENT_ROOT.'/core/tpl/formlayoutai.tpl.php'; - - $out .= '
'; - if ($this->withbodyreadonly) { - $out .= nl2br($defaultmessage); - $out .= ''; - } else { - if (!isset($this->ckeditortoolbar)) { - $this->ckeditortoolbar = 'dolibarr_mailings'; + if (empty($this->substit['__REF__'])) { // @phan-suppress-current-line PhanTypeMismatchProperty + $paymenturl = ''; + } else { + $langs->loadLangs(array('paypal', 'other')); + $typeforonlinepayment = 'free'; + if ($this->param["models"] == 'order' || $this->param["models"] == 'order_send') { + $typeforonlinepayment = 'order'; // TODO use detection on something else than template + } + if ($this->param["models"] == 'invoice' || $this->param["models"] == 'facture_send') { + $typeforonlinepayment = 'invoice'; // TODO use detection on something else than template + } + if ($this->param["models"] == 'member') { + $typeforonlinepayment = 'member'; // TODO use detection on something else than template + } + $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $this->substit['__REF__']); + $paymenturl = $url; } - // Editor wysiwyg - require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; - if ($this->withfckeditor == -1) { - if (getDolGlobalString('FCKEDITOR_ENABLE_MAIL')) { - $this->withfckeditor = 1; - } else { - $this->withfckeditor = 0; + if (count($validpaymentmethod) > 0 && $paymenturl) { + $langs->load('other'); + $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = str_replace('\n', "\n", $langs->transnoentities("PredefinedMailContentLink", $paymenturl)); + $this->substit['__ONLINE_PAYMENT_URL__'] = $paymenturl; + } elseif (count($validpaymentmethod) > 0) { + $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = '__ONLINE_PAYMENT_TEXT_AND_URL__'; + $this->substit['__ONLINE_PAYMENT_URL__'] = '__ONLINE_PAYMENT_URL__'; + } else { + $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = ''; + $this->substit['__ONLINE_PAYMENT_URL__'] = ''; + } + + $this->substit['__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__'] = ''; + + // Generate the string with the template for lines repeated and filled for each line + $lines = ''; + $defaultlines = $arraydefaultmessage->content_lines; + if (isset($defaultlines)) { + foreach ($this->substit_lines as $lineid => $substit_line) { + $lines .= make_substitutions($defaultlines, $substit_line) . "\n"; + } + } + $this->substit['__LINES__'] = $lines; + + $defaultmessage = str_replace('\n', "\n", $defaultmessage); + + // Deal with format differences between message and some substitution variables (text / HTML) + $atleastonecomponentishtml = 0; + if (strpos($defaultmessage, '__USER_SIGNATURE__') !== false && dol_textishtml($this->substit['__USER_SIGNATURE__'])) { + $atleastonecomponentishtml++; + } + if (strpos($defaultmessage, '__SENDEREMAIL_SIGNATURE__') !== false && dol_textishtml($this->substit['__SENDEREMAIL_SIGNATURE__'])) { + $atleastonecomponentishtml++; + } + if (strpos($defaultmessage, '__ONLINE_PAYMENT_TEXT_AND_URL__') !== false && dol_textishtml($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'])) { + $atleastonecomponentishtml++; + } + if (strpos($defaultmessage, '__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__') !== false && dol_textishtml($this->substit['__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__'])) { + $atleastonecomponentishtml++; + } + if (dol_textishtml($defaultmessage)) { + $atleastonecomponentishtml++; + } + if ($atleastonecomponentishtml) { + if (!dol_textishtml($this->substit['__USER_SIGNATURE__'])) { + $this->substit['__USER_SIGNATURE__'] = dol_nl2br($this->substit['__USER_SIGNATURE__']); + } + if (!dol_textishtml($this->substit['__SENDEREMAIL_SIGNATURE__'])) { + $this->substit['__SENDEREMAIL_SIGNATURE__'] = dol_nl2br($this->substit['__SENDEREMAIL_SIGNATURE__']); + } + if (!dol_textishtml($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'])) { + $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = dol_nl2br($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__']); + } + if (!dol_textishtml($defaultmessage)) { + $defaultmessage = dol_nl2br($defaultmessage); } } - $doleditor = new DolEditor('message', $defaultmessage, '', 280, $this->ckeditortoolbar, 'In', true, true, $this->withfckeditor, 8, '95%'); - $out .= $doleditor->Create(1); + if (GETPOSTISSET("message") && !GETPOST('modelselected')) { + $defaultmessage = GETPOST("message", "restricthtml"); + } else { + $defaultmessage = make_substitutions($defaultmessage, $this->substit); + // Clean first \n and br (to avoid empty line when CONTACTCIVNAME is empty) + $defaultmessage = preg_replace("/^(
)+/", "", $defaultmessage); + $defaultmessage = preg_replace("/^\n+/", "", $defaultmessage); + } + + $out .= '
'; + $out .= $form->textwithpicto($langs->trans('MailText'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltipfrombody'); + $out .= ''; + + $formmail = $this; + $showlinktolayout = ($formmail->withfckeditor && getDolGlobalInt('MAIN_EMAIL_USE_LAYOUT')) ? $formmail->withlayout : ''; + $showlinktolayoutlabel = $langs->trans("FillMessageWithALayout"); + $showlinktoai = ($formmail->withaiprompt && isModEnabled('ai')) ? 'textgenerationemail' : ''; + $showlinktoailabel = $langs->trans("FillMessageWithAIContent"); + $formatforouput = ''; + $htmlname = 'message'; + + // Fill $out + include DOL_DOCUMENT_ROOT . '/core/tpl/formlayoutai.tpl.php'; + + $out .= '
'; + if ($this->withbodyreadonly) { + $out .= nl2br($defaultmessage); + $out .= ''; + } else { + if (!isset($this->ckeditortoolbar)) { + $this->ckeditortoolbar = 'dolibarr_mailings'; + } + + // Editor wysiwyg + require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php'; + if ($this->withfckeditor == -1) { + if (getDolGlobalString('FCKEDITOR_ENABLE_MAIL')) { + $this->withfckeditor = 1; + } else { + $this->withfckeditor = 0; + } + } + + $doleditor = new DolEditor('message', $defaultmessage, '', 280, $this->ckeditortoolbar, 'In', true, true, $this->withfckeditor, 8, '95%'); + $out .= $doleditor->Create(1); + } + $out .= "
'."\n"; + $out .= '
' . "\n"; - if ($this->withform == 1 || $this->withform == -1) { - $out .= '
'; - $out .= 'withfile == 2 && $conf->use_javascript_ajax) { - $out .= ' onClick="if (document.mailform.addedfile.value != \'\') { alert(\''.dol_escape_js($langs->trans("FileWasNotUploaded")).'\'); return false; } else { return true; }"'; + if ($this->withform == 1 || $this->withform == -1) { + $out .= '
'; + $out .= 'withfile == 2 && $conf->use_javascript_ajax) { + $out .= ' onClick="if (document.mailform.addedfile.value != \'\') { alert(\'' . dol_escape_js($langs->trans("FileWasNotUploaded")) . '\'); return false; } else { return true; }"'; + } + $out .= ' />'; + if ($this->withcancel) { + $out .= ''; + } + $out .= '
' . "\n"; } - $out .= ' />'; - if ($this->withcancel) { - $out .= ''; + + if ($this->withform == 1) { + $out .= '' . "\n"; } - $out .= '
'."\n"; - } - if ($this->withform == 1) { - $out .= ''."\n"; - } - - // Disable enter key if option MAIN_MAILFORM_DISABLE_ENTERKEY is set - if (getDolGlobalString('MAIN_MAILFORM_DISABLE_ENTERKEY')) { - $out .= ''; + $out .= ' })'; + $out .= ''; + } + + $out .= "\n"; + + return $out; } - - $out .= "\n"; - - return $out; } } - /** * get html For To * From 5a427209a99321a1e8605f4c280a16ad8d7f164f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 27 Jan 2025 04:57:09 +0100 Subject: [PATCH 037/383] Doc --- htdocs/core/lib/functions.lib.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 3a6cff28efc..c8050d8b679 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -2011,17 +2011,23 @@ function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapeta $tmpold = $tmp; if (preg_match('/<'.preg_quote($tagtoreplace, '/').'\s+([^>]+)>/', $tmp, $reg)) { + // We want to pprotect the attribute part ... in '' to avoid transformation by htmlentities() lafter $tmpattributes = str_ireplace(array('[', ']'), '_', $reg[1]); // We must never have [ ] inside the attribute string - $tmpattributes = str_ireplace('href="http:', '__HREFHTTPA', $tmpattributes); + $tmpattributes = str_ireplace('href="http:', '__HREFHTTPA', $tmpattributes); // TODO Try to remove this $tmpattributes = str_ireplace('href="https:', '__HREFHTTPSA', $tmpattributes); $tmpattributes = str_ireplace('src="http:', '__SRCHTTPIMG', $tmpattributes); $tmpattributes = str_ireplace('src="https:', '__SRCHTTPSIMG', $tmpattributes); $tmpattributes = str_ireplace('"', '__DOUBLEQUOTE', $tmpattributes); $tmpattributes = preg_replace('/[^a-z0-9_\/\?\;\s=&\.\-@:\.#\+]/i', '', $tmpattributes); //$tmpattributes = preg_replace("/float:\s*(left|right)/", "", $tmpattributes); // Disabled: we must not remove content + + // TODO Test the replacement by using a memory array for attributes to restore them + // TODO Test a tag like 'abc' $tmp = preg_replace('/<'.preg_quote($tagtoreplace, '/').'\s+'.preg_quote($reg[1], '/').'>/', '__BEGINTAGTOREPLACE'.$tagtoreplace.'['.$tmpattributes.']__', $tmp); } + // TODO This may be already in previous case ? Try to remove this. if (preg_match('/<'.preg_quote($tagtoreplace, '/').'\s+([^>]+)\s+\/>/', $tmp, $reg)) { + // We want to protect the attribute part ... in '' to avoid transformation by htmlentities() lafter $tmpattributes = str_ireplace(array('[', ']'), '_', $reg[1]); // We must not have [ ] inside the attribute string $tmpattributes = str_ireplace('"', '__DOUBLEQUOTE', $tmpattributes); $tmpattributes = preg_replace('/[^a-z0-9_\/\?\;\s=&\.\-@:\.#\+]/i', '', $tmpattributes); From 046d0511db5e5d392a35577839c677ecf6c5e912 Mon Sep 17 00:00:00 2001 From: Eric Seigne Date: Mon, 27 Jan 2025 08:40:13 +0100 Subject: [PATCH 038/383] add an info against booking.class.php > calendar.class.php --- ChangeLog | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2e13f51fa5b..bc39e16a356 100644 --- a/ChangeLog +++ b/ChangeLog @@ -518,7 +518,7 @@ NEW: Upgrade in module builder in menu section NEW: use account address in sepa mandate (#23642) NEW: VAT rate - Add entity NEW: When an user unset the batch management of products, transformation of each batch stock mouvement in global stock mouvement -NEW: PDF Generation for each Human Resource Evaluations. +NEW: PDF Generation for each Human Resource Evaluations. SEC: #25512 applicative anti bruteforce - security on too many login attempts (#25520) SEC: Add action confirm_... as sensitive to need a CSRF token @@ -592,7 +592,7 @@ The following changes may create regressions for some external modules, but were * The property ->user_creation to store ID of user of creation has been renamed into ->user_creation_id. * The property ->user_modification to store ID of user of modification has been renamed into ->user_modification_id. * The private array ->status_short, ->statuts and ->status_long are now array ->labelStatusShort and ->labelStatus everywhere. -* The duplicate property ->user_creat, ->date_creat, ->date_valid have been removed (use instead user_creation, date_creation, date_validation). +* The duplicate property ->user_creat, ->date_creat, ->date_valid have been removed (use instead user_creation, date_creation, date_validation). * The method get_substitutionarray_shipment_lines() has been removed. Use the generic get_substitutionarray_lines() instead. * The method ProductcustomerPrice->fetch_all_log() has been renamed into camel case ->fetchAllLog() * It was possible to use a variable $soc or $right inside a PHP code condition of some extrafields properties, this is no more true (this 2 variables are no more global variables). @@ -602,7 +602,7 @@ The following changes may create regressions for some external modules, but were * The delete() method of AdherentType, Contact, Delivery, MultiCurrency, CurrencyRate now need $user as first parameter. * A very high number of class properties (with old name in french) are now deprecated in favor of the property name in english. * The load of hook context productdao has been removed before calling loadvirtualstock. Modules must use the context of main parent page or 'all' for all cases. - +* booking.class.php was removed, please have a look at calendar.class.php ***** ChangeLog for 18.0.6 compared to 18.0.5 ***** FIX: 16.0 - parent company gets emptied when updating a third party from the card in edit mode (#28269) @@ -1009,7 +1009,7 @@ NEW: Accountancy - Quadratus export with attachments in accountancy export NEW: Accountancy - Can filter on a custom group of accounts. Perf or ledger list. NEW: Accountancy - Can select the export format during export of journals NEW: Accountancy - sort of column of custom group of account -NEW: Can upload a file with drag and drop on purchase invoice, vats, salaries and social contributions +NEW: Can upload a file with drag and drop on purchase invoice, vats, salaries and social contributions NEW: Authentication: #22740 add OpenID Connect impl NEW: Authentication: add experimental support for Google OAuth2 connexion NEW: Authentication: can now edit service name for OAuth token From 9554ea00a818977d6923b86e4347b9090fb857d0 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Mon, 27 Jan 2025 08:53:00 +0100 Subject: [PATCH 039/383] FIX can not delete files in task card --- htdocs/projet/tasks/task.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/htdocs/projet/tasks/task.php b/htdocs/projet/tasks/task.php index fbf8fdc1e45..264462594f2 100644 --- a/htdocs/projet/tasks/task.php +++ b/htdocs/projet/tasks/task.php @@ -72,7 +72,10 @@ if ($reshook < 0) { } if ($id > 0 || $ref) { - $object->fetch($id, $ref); + $ret = $object->fetch($id, $ref); + if ($ret > 0) { + $projectstatic->fetch($object->fk_project); + } } // Security check @@ -235,7 +238,7 @@ if ($action == 'remove_file' && $user->hasRight('projet', 'creer')) { require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; $langs->load("other"); - $upload_dir = $conf->project->dir_output; + $upload_dir = $conf->project->dir_output."/".dol_sanitizeFileName($projectstatic->ref)."/".dol_sanitizeFileName($object->ref); $file = $upload_dir.'/'.dol_sanitizeFileName(GETPOST('file')); $ret = dol_delete_file($file); @@ -254,7 +257,6 @@ $form = new Form($db); $formother = new FormOther($db); $formfile = new FormFile($db); $formproject = new FormProjets($db); -$result = $projectstatic->fetch($object->fk_project); $title = $object->ref; if (!empty($withproject)) { @@ -739,7 +741,7 @@ if ($id > 0 || !empty($ref)) { /* * Generated documents */ - $filename = dol_sanitizeFileName($projectstatic->ref)."/".dol_sanitizeFileName($object->ref); + $filename = ''; $filedir = $conf->project->dir_output."/".dol_sanitizeFileName($projectstatic->ref)."/".dol_sanitizeFileName($object->ref); $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id; $genallowed = ($user->hasRight('projet', 'lire')); From 5e88f9b415975e573c94ec6310a2e927aa681338 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Mon, 27 Jan 2025 09:48:29 +0100 Subject: [PATCH 040/383] FIX avoid php warnings --- htdocs/core/lib/project.lib.php | 1 + htdocs/projet/class/project.class.php | 3 +++ 2 files changed, 4 insertions(+) diff --git a/htdocs/core/lib/project.lib.php b/htdocs/core/lib/project.lib.php index 4776907192f..23ae5d8b032 100644 --- a/htdocs/core/lib/project.lib.php +++ b/htdocs/core/lib/project.lib.php @@ -2743,6 +2743,7 @@ function print_projecttasks_array($db, $form, $socid, $projectsListId, $mytasks } print ''; + $alttext = ''; if ($objp->opp_percent && $objp->opp_amount) { $opp_weighted_amount = $objp->opp_percent * $objp->opp_amount / 100; $alttext = $langs->trans("OpportunityWeightedAmount").' '.price($opp_weighted_amount, 0, '', 1, -1, 0, $conf->currency); diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index cf7cc5558a4..a7b99b90df0 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -2197,6 +2197,9 @@ class Project extends CommonObject $date = explode('-', $obj->element_date); $week_number = getWeekNumber($date[2], $date[1], $date[0]); } + if (!isset($this->monthWorkLoadPerTask[$week_number][$obj->fk_element])) { + $this->monthWorkLoadPerTask[$week_number][$obj->fk_element] = 0; + } '@phan-var-force int $week_number'; // Needed because phan considers it might be null if (empty($weekalreadyfound[$week_number])) { $this->monthWorkLoad[$week_number] = $obj->element_duration; From 25ab0e7f9b9d1e83ee68a5a61ee22baa2a297d0b Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Mon, 27 Jan 2025 10:03:02 +0100 Subject: [PATCH 041/383] FIX wrong type --- htdocs/projet/class/project.class.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index a7b99b90df0..a3bdd034b9d 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -2197,15 +2197,15 @@ class Project extends CommonObject $date = explode('-', $obj->element_date); $week_number = getWeekNumber($date[2], $date[1], $date[0]); } - if (!isset($this->monthWorkLoadPerTask[$week_number][$obj->fk_element])) { - $this->monthWorkLoadPerTask[$week_number][$obj->fk_element] = 0; - } '@phan-var-force int $week_number'; // Needed because phan considers it might be null if (empty($weekalreadyfound[$week_number])) { $this->monthWorkLoad[$week_number] = $obj->element_duration; $this->monthWorkLoadPerTask[$week_number][$obj->fk_element] = $obj->element_duration; } else { $this->monthWorkLoad[$week_number] += $obj->element_duration; + if (!isset($this->monthWorkLoadPerTask[$week_number][$obj->fk_element])) { + $this->monthWorkLoadPerTask[$week_number][$obj->fk_element] = array(); + } $this->monthWorkLoadPerTask[$week_number][$obj->fk_element] += $obj->element_duration; } $weekalreadyfound[$week_number] = 1; From 968f3dbaa1d0c734e64f9d5dc9a431d29fc5ec18 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Mon, 27 Jan 2025 10:04:35 +0100 Subject: [PATCH 042/383] FIX phpstan tu me soules ! --- htdocs/projet/class/project.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index a3bdd034b9d..a8f684acf22 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -2204,7 +2204,7 @@ class Project extends CommonObject } else { $this->monthWorkLoad[$week_number] += $obj->element_duration; if (!isset($this->monthWorkLoadPerTask[$week_number][$obj->fk_element])) { - $this->monthWorkLoadPerTask[$week_number][$obj->fk_element] = array(); + $this->monthWorkLoadPerTask[$week_number][$obj->fk_element] = 0; } $this->monthWorkLoadPerTask[$week_number][$obj->fk_element] += $obj->element_duration; } From c1058da4c5d2703cea4423bef97eb650ac72141d Mon Sep 17 00:00:00 2001 From: ATM-Lucas Date: Mon, 27 Jan 2025 10:15:56 +0100 Subject: [PATCH 043/383] Travis error --- htdocs/core/class/html.formmail.class.php | 1181 ++++++++++----------- 1 file changed, 589 insertions(+), 592 deletions(-) diff --git a/htdocs/core/class/html.formmail.class.php b/htdocs/core/class/html.formmail.class.php index a5881534518..21f064ba8ca 100644 --- a/htdocs/core/class/html.formmail.class.php +++ b/htdocs/core/class/html.formmail.class.php @@ -473,7 +473,7 @@ class FormMail extends Form global $conf, $langs, $user, $hookmanager, $form; // Required to show preview wof mail attachments - require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php'; + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; $formfile = new FormFile($this->db); if (!is_object($form)) { @@ -532,632 +532,631 @@ class FormMail extends Form $listofpaths = array(); $listofnames = array(); $listofmimes = array(); - $keytoavoidconflict = empty($this->trackid) ? '' : '-' . $this->trackid; // this->trackid must be defined + $keytoavoidconflict = empty($this->trackid) ? '' : '-'.$this->trackid; // this->trackid must be defined if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) { - if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) { - if (!empty($arraydefaultmessage->joinfiles) && !empty($this->param['fileinit']) && is_array($this->param['fileinit'])) { - foreach ($this->param['fileinit'] as $path) { - if (!empty($path)) { - $this->add_attached_files($path); - } + if (!empty($arraydefaultmessage->joinfiles) && !empty($this->param['fileinit']) && is_array($this->param['fileinit'])) { + foreach ($this->param['fileinit'] as $path) { + if (!empty($path)) { + $this->add_attached_files($path); } } } + } - if (!empty($_SESSION["listofpaths" . $keytoavoidconflict])) { - $listofpaths = explode(';', $_SESSION["listofpaths" . $keytoavoidconflict]); + if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) { + $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]); + } + if (!empty($_SESSION["listofnames".$keytoavoidconflict])) { + $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]); + } + if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) { + $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]); + } + + + $out .= "\n".'
'."\n"; + if ($this->withform == 1) { + $out .= '
'."\n"; + + $out .= ''; + $out .= ''; + $out .= ''; + $out .= ''; + $out .= ''; + } + if (!empty($this->withfrom)) { + if (!empty($this->withfromreadonly)) { + $out .= ''; + $out .= ''; } - if (!empty($_SESSION["listofnames" . $keytoavoidconflict])) { - $listofnames = explode(';', $_SESSION["listofnames" . $keytoavoidconflict]); - } - if (!empty($_SESSION["listofmimes" . $keytoavoidconflict])) { - $listofmimes = explode(';', $_SESSION["listofmimes" . $keytoavoidconflict]); - } - - - $out .= "\n" . '
' . "\n"; - if ($this->withform == 1) { - $out .= '' . "\n"; - - $out .= ''; - $out .= ''; - $out .= ''; - $out .= ''; - $out .= ''; - } - if (!empty($this->withfrom)) { - if (!empty($this->withfromreadonly)) { - $out .= ''; - $out .= ''; - } - } - foreach ($this->param as $key => $value) { - if (is_array($value)) { - $out .= "\n"; - } else { - $out .= '' . "\n"; - } - } - - $modelmail_array = array(); - if ($this->param['models'] != 'none') { - $result = $this->fetchAllEMailTemplate($this->param["models"], $user, $outputlangs); - if ($result < 0) { - setEventMessages($this->error, $this->errors, 'errors'); - } - - foreach ($this->lines_model as $line) { - $reg = array(); - if (preg_match('/\((.*)\)/', $line->label, $reg)) { - $labeltouse = $langs->trans($reg[1]); // langs->trans when label is __(xxx)__ - } else { - $labeltouse = $line->label; - } - - // We escape the $labeltouse to store it into $modelmail_array. - $modelmail_array[$line->id] = dol_escape_htmltag($labeltouse); - if ($line->lang) { - $modelmail_array[$line->id] .= ' ' . picto_from_langcode($line->lang); - } - if ($line->private) { - $modelmail_array[$line->id] .= ' - ' . dol_escape_htmltag($langs->trans("Private")) . ''; - } - } - } - - // Zone to select email template - if (count($modelmail_array) > 0) { - $model_mail_selected_id = GETPOSTISSET('modelmailselected') ? GETPOSTINT('modelmailselected') : ($arraydefaultmessage->id > 0 ? $arraydefaultmessage->id : 0); - - // If list of template is filled - $out .= '
' . "\n"; - - $out .= $this->selectarray('modelmailselected', $modelmail_array, $model_mail_selected_id, $langs->trans('SelectMailModel'), 0, 0, '', 0, 0, 0, '', 'minwidth100', 1, '', 0, 1); - if ($user->admin) { - $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFrom", $langs->transnoentitiesnoconv('Setup') . ' - ' . $langs->transnoentitiesnoconv('EMails')), 1); - } - - $out .= '   '; - $out .= ''; - $out .= '   '; - $out .= '
'; - } elseif (!empty($this->param['models']) && in_array($this->param['models'], array( - 'propal_send', 'order_send', 'facture_send', - 'shipping_send', 'fichinter_send', 'supplier_proposal_send', 'order_supplier_send', - 'invoice_supplier_send', 'thirdparty', 'contract', 'user', 'recruitmentcandidature_send', 'product_send', 'all' - ))) { - // If list of template is empty - $out .= '
' . "\n"; - $out .= '' . $langs->trans('SelectMailModel') . ': '; - $out .= ''; // Do not put 'disabled' on 'option' tag, it is already on 'select' and it makes chrome crazy. - if ($user->admin) { - $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFrom", $langs->transnoentitiesnoconv('Setup') . ' - ' . $langs->transnoentitiesnoconv('EMails')), 1); - } - $out .= '   '; - $out .= ''; - $out .= '   '; - $out .= '
'; + } + foreach ($this->param as $key => $value) { + if (is_array($value)) { + $out .= "\n"; } else { - $out .= ''; + $out .= ''."\n"; + } + } + + $modelmail_array = array(); + if ($this->param['models'] != 'none') { + $result = $this->fetchAllEMailTemplate($this->param["models"], $user, $outputlangs); + if ($result < 0) { + setEventMessages($this->error, $this->errors, 'errors'); } - - $out .= '' . "\n"; - - // Substitution array/string - $helpforsubstitution = ''; - if (is_array($this->substit) && count($this->substit)) { - $helpforsubstitution .= $langs->trans('AvailableVariables') . ' :

' . "\n"; - } - foreach ($this->substit as $key => $val) { - // Do not show deprecated variables into the tooltip help of substitution variables - if (in_array($key, array('__NEWREF__', '__REFCLIENT__', '__REFSUPPLIER__', '__SUPPLIER_ORDER_DATE_DELIVERY__', '__SUPPLIER_ORDER_DELAY_DELIVERY__'))) { - continue; - } - $helpforsubstitution .= $key . ' -> ' . $langs->trans(dol_string_nohtmltag(dolGetFirstLineOfText($val))) . '
'; - } - if (is_array($this->substit) && count($this->substit)) { - $helpforsubstitution .= '
'; - } - - /* - if (!empty($this->withsubstit)) { // Unset or set ->withsubstit=0 to disable this. - $out .= '\n"; - }*/ - // From - if (!empty($this->withfrom)) { - if (!empty($this->withfromreadonly)) { - $out .= '"; print '"; print '"; print ''; if (!$i) { diff --git a/htdocs/eventorganization/conferenceorboothattendee_card.php b/htdocs/eventorganization/conferenceorboothattendee_card.php index b7010dadaf5..041e671a8f0 100644 --- a/htdocs/eventorganization/conferenceorboothattendee_card.php +++ b/htdocs/eventorganization/conferenceorboothattendee_card.php @@ -1,7 +1,7 @@ * Copyright (C) 2024 Alexandre Spangaro - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) 2024 Frédéric France * * This program is free software; you can redistribute it and/or modify @@ -75,6 +75,8 @@ $diroutputmassaction = $conf->eventorganization->dir_output.'/temp/massgeneratio $hookmanager->initHooks(array('conferenceorboothattendeecard', 'globalcard')); // Note that conf->hooks_modules contains array +$confOrBooth = null; + if ($conf_or_booth_id > 0) { $confOrBooth = new ConferenceOrBooth($db); $result = $confOrBooth->fetch($id > 0 ? $id : $conf_or_booth_id); @@ -221,7 +223,7 @@ $help_url = 'EN:Module_Event_Organization'; llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-eventorganization page-attendee-card'); -$result = $projectstatic->fetch(empty($confOrBooth->fk_project) ? $fk_project : $confOrBooth->fk_project); +$result = $projectstatic->fetch(($confOrBooth === null || empty($confOrBooth->fk_project)) ? $fk_project : $confOrBooth->fk_project); if (getDolGlobalString('PROJECT_ALLOW_COMMENT_ON_PROJECT') && method_exists($projectstatic, 'fetchComments') && empty($projectstatic->comments)) { $projectstatic->fetchComments(); } @@ -357,7 +359,7 @@ if (!empty($withproject)) { $htmltext = $langs->trans("AllowUnknownPeopleSuggestConfHelp"); print $form->editfieldkey('AllowUnknownPeopleSuggestConf', 'accept_conference_suggestions', '', $projectstatic, 0, $typeofdata, '', 0, 0, 'projectid', $htmltext); print '"; print '"; print '"; print '"; print '"; print '"; print '"; print '"; - // Link to ICS for the event - print '"; + // Show message + $message = ''.$langs->trans('DownloadICSLink').img_picto('', 'download', 'class="paddingleft"').''; + print $message; + print ""; print ''; if (!$i) { diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php index 1b74583596c..a19523f9d7b 100644 --- a/htdocs/expedition/card.php +++ b/htdocs/expedition/card.php @@ -14,7 +14,7 @@ * Copyright (C) 2018-2024 Frédéric France * Copyright (C) 2020 Lenin Rivas * Copyright (C) 2022 Josep Lluís Amador - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 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 @@ -388,7 +388,7 @@ if (empty($reshook)) { } // Extrafields - $array_options[$i] = $extrafields->getOptionalsFromPost($object->table_element_line, $i); + $array_options[$i] = $extrafields->getOptionalsFromPost($object->table_element_line, (string) $i); // Unset extrafield if (isset($extrafields->attributes[$object->table_element_line]['label']) && is_array($extrafields->attributes[$object->table_element_line]['label'])) { // Get extra fields @@ -528,7 +528,7 @@ if (empty($reshook)) { } } elseif ($action == 'confirm_cancel' && $confirm == 'yes' && $user->hasRight('expedition', 'supprimer')) { $also_update_stock = (GETPOST('alsoUpdateStock', 'alpha') ? 1 : 0); - $result = $object->cancel(0, $also_update_stock); + $result = $object->cancel(0, (bool) $also_update_stock); if ($result > 0) { $result = $object->setStatut(-1); } else { @@ -536,7 +536,7 @@ if (empty($reshook)) { } } elseif ($action == 'confirm_delete' && $confirm == 'yes' && $user->hasRight('expedition', 'supprimer')) { $also_update_stock = (GETPOST('alsoUpdateStock', 'alpha') ? 1 : 0); - $result = $object->delete($user, 0, $also_update_stock); + $result = $object->delete($user, 0, (bool) $also_update_stock); if ($result > 0) { header("Location: ".DOL_URL_ROOT.'/expedition/index.php'); exit; @@ -1035,7 +1035,7 @@ if ($action == 'create') { print ''; print ''; print ''; @@ -1081,7 +1081,7 @@ if ($action == 'create') { print ''; @@ -1094,7 +1094,7 @@ if ($action == 'create') { print ' x '; print ' x '; print ' '; - $text = $formproduct->selectMeasuringUnits("size_units", "size", GETPOSTINT('size_units'), 0, 2); + $text = $formproduct->selectMeasuringUnits("size_units", "size", (string) GETPOSTINT('size_units'), 0, 2); $htmltext = $langs->trans("KeepEmptyForAutoCalculation"); print $form->textwithpicto($text, $htmltext); print ''; @@ -1277,7 +1277,7 @@ if ($action == 'create') { $text .= ' - '.(!empty($line->label) ? $line->label : $line->product_label); $description = ($showdescinproductdesc ? '' : dol_htmlentitiesbr($line->desc)); - print $form->textwithtooltip($text, $description, 3, 0, '', $i); + print $form->textwithtooltip($text, $description, 3, 0, '', (string) $i); // Show range print_date_range($db->jdate($line->date_start), $db->jdate($line->date_end)); @@ -1298,7 +1298,7 @@ if ($action == 'create') { if (!empty($line->label)) { $text .= ' '.$line->label.''; - print $form->textwithtooltip($text, $line->desc, 3, 0, '', $i); + print $form->textwithtooltip($text, $line->desc, 3, 0, '', (string) $i); } else { print $text.' '.nl2br($line->desc); } @@ -1856,7 +1856,7 @@ if ($action == 'create') { $expLine->array_options = array_merge($expLine->array_options, $srcLine->array_options); - print $expLine->showOptionals($extrafields, 'edit', array('style' => 'class="drag drop oddeven"', 'colspan' => $colspan), $indiceAsked, '', 1); + print $expLine->showOptionals($extrafields, 'edit', array('style' => 'class="drag drop oddeven"', 'colspan' => $colspan), (string) $indiceAsked, '', '1'); } } @@ -2003,7 +2003,7 @@ if ($action == 'create') { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $objectsrc->socid, $objectsrc->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $objectsrc->socid, (string) $objectsrc->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($objectsrc) && !empty($objectsrc->fk_project)) { $proj = new Project($db); @@ -2107,13 +2107,13 @@ if ($action == 'create') { print ''; print ''; print ''; - print $formproduct->selectMeasuringUnits("weight_units", "weight", $object->weight_units, 0, 2, 'maxwidth125 valignmiddle'); + print $formproduct->selectMeasuringUnits("weight_units", "weight", (string) $object->weight_units, 0, 2, 'maxwidth125 valignmiddle'); print ' '; print ' '; print ''; } else { print $object->trueWeight; - print ($object->trueWeight && $object->weight_units != '') ? ' '.measuringUnitString(0, "weight", $object->weight_units) : ''; + print ($object->trueWeight && $object->weight_units != '') ? ' '.measuringUnitString(0, "weight", (string) $object->weight_units) : ''; } // Calculated @@ -2228,7 +2228,7 @@ if ($action == 'create') { } else { if ($object->shipping_method_id > 0) { // Get code using getLabelFromKey - $code = $langs->getLabelFromKey($db, $object->shipping_method_id, 'c_shipment_mode', 'rowid', 'code'); + $code = $langs->getLabelFromKey($db, (string) $object->shipping_method_id, 'c_shipment_mode', 'rowid', 'code'); print $langs->trans("SendingMethod".strtoupper($code)); } } @@ -2462,7 +2462,7 @@ if ($action == 'create') { $text = $product_static->getNomUrl(1); $text .= ' - '.$label; $description = (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE') ? '' : dol_htmlentitiesbr($lines[$i]->description)); - print $form->textwithtooltip($text, $description, 3, 0, '', $i); + print $form->textwithtooltip($text, $description, 3, 0, '', (string) $i); print_date_range(!empty($lines[$i]->date_start) ? $lines[$i]->date_start : '', !empty($lines[$i]->date_end) ? $lines[$i]->date_end : ''); if (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE')) { print (!empty($lines[$i]->description) && $lines[$i]->description != $lines[$i]->product) ? '
'.dol_htmlentitiesbr($lines[$i]->description) : ''; @@ -2478,7 +2478,7 @@ if ($action == 'create') { if (!empty($lines[$i]->label)) { $text .= ' '.$lines[$i]->label.''; - print $form->textwithtooltip($text, $lines[$i]->description, 3, 0, '', $i); + print $form->textwithtooltip($text, $lines[$i]->description, 3, 0, '', (string) $i); } else { print $text.' '.nl2br($lines[$i]->description); } @@ -2489,7 +2489,7 @@ if ($action == 'create') { $unit_order = ''; if (getDolGlobalString('PRODUCT_USE_UNITS')) { - $unit_order = measuringUnitString($lines[$i]->fk_unit); + $unit_order = measuringUnitString((int) $lines[$i]->fk_unit); } // Qty ordered @@ -2529,7 +2529,7 @@ if ($action == 'create') { } } } - print $form->textwithpicto($qtyalreadysent, $htmltooltip, 1, 'info', '', 0, 3, 'tooltip'.$lines[$i]->id); + print $form->textwithpicto((string) $qtyalreadysent, $htmltooltip, 1, 'info', '', 0, 3, 'tooltip'.$lines[$i]->id); print ''; } @@ -2738,9 +2738,9 @@ if ($action == 'create') { // TODO Show all in same line by setting $display_type = 'line' if ($action == 'editline' && $line->id == $line_id) { - print $lines[$i]->showOptionals($extrafields, 'edit', array('colspan' => $colspan), !empty($indiceAsked) ? $indiceAsked : '', '', 0, 'card'); + print $lines[$i]->showOptionals($extrafields, 'edit', array('colspan' => $colspan), !empty($indiceAsked) ? $indiceAsked : '', '', '', 'card'); } else { - print $lines[$i]->showOptionals($extrafields, 'view', array('colspan' => $colspan), !empty($indiceAsked) ? $indiceAsked : '', '', 0, 'card'); + print $lines[$i]->showOptionals($extrafields, 'view', array('colspan' => $colspan), !empty($indiceAsked) ? $indiceAsked : '', '', '', 'card'); } } } diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index 61e50c14373..d3ecb5adad9 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -13,7 +13,7 @@ * Copyright (C) 2018 Nicolas ZABOURI * Copyright (C) 2018-2025 Frédéric France * Copyright (C) 2020 Lenin Rivas - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) 2024 William Mead * * This program is free software; you can redistribute it and/or modify @@ -306,7 +306,6 @@ class Expedition extends CommonObject * Closed status * -> parcel was received by customer / end of process * prev status : validated or shipment_in_progress - * */ const STATUS_CLOSED = 2; @@ -1476,10 +1475,10 @@ class Expedition extends CommonObject * Delete shipment. * Warning, do not delete a shipment if a delivery is linked to (with table llx_element_element) * - * @param User $user User making the deletion - * @param int $notrigger Disable triggers - * @param bool $also_update_stock true if the stock should be increased back (false by default) - * @return int >0 if OK, 0 if deletion done but failed to delete files, <0 if KO + * @param ?User $user User making the deletion + * @param int<0,1> $notrigger Disable triggers + * @param bool $also_update_stock true if the stock should be increased back (false by default) + * @return int >0 if OK, 0 if deletion done but failed to delete files, <0 if KO */ public function delete($user = null, $notrigger = 0, $also_update_stock = false) { @@ -2437,7 +2436,6 @@ class Expedition extends CommonObject * @param string $labelmovement Label of movement * @return int Return integer <0 if KO, >0 if OK * @throws Exception - * */ private function manageStockMvtOnEvt($user, $labelmovement = 'ShipmentClassifyClosedInDolibarr') { diff --git a/htdocs/expedition/contact.php b/htdocs/expedition/contact.php index 3818847e84e..534515a84f6 100644 --- a/htdocs/expedition/contact.php +++ b/htdocs/expedition/contact.php @@ -4,6 +4,7 @@ * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2023 Christian Foellmann * Copyright (C) 2024 Frédéric France + * Copyright (C) 2025 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 @@ -52,6 +53,7 @@ $id = GETPOSTINT('id'); $ref = GETPOST('ref', 'alpha'); $action = GETPOST('action', 'aZ09'); +$typeobject = null; $object = new Expedition($db); if ($id > 0 || !empty($ref)) { $object->fetch($id, $ref); @@ -85,7 +87,7 @@ $result = restrictedArea($user, 'expedition', $object->id, ''); * Actions */ -$parameters = array('id'=>$id); +$parameters = array('id' => $id); $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); if ($reshook < 0) { setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); @@ -172,7 +174,7 @@ if ($id > 0 || !empty($ref)) { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $objectsrc->socid, $objectsrc->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $objectsrc->socid, (string) $objectsrc->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($objectsrc) && !empty($objectsrc->fk_project)) { $proj = new Project($db); diff --git a/htdocs/expedition/dispatch.php b/htdocs/expedition/dispatch.php index e1340a8b0d7..67c30c5ff95 100644 --- a/htdocs/expedition/dispatch.php +++ b/htdocs/expedition/dispatch.php @@ -9,7 +9,7 @@ * Copyright (C) 2017-2022 Ferran Marcet * Copyright (C) 2018-2024 Frédéric France * Copyright (C) 2019-2020 Christophe Battarel - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 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 @@ -141,6 +141,7 @@ if ($action == 'updatelines' && $usercancreate) { $reg = array(); if (preg_match('/^product_.*([0-9]+)_([0-9]+)$/i', $key, $reg)) { $pos++; + $modebatch = null; if (preg_match('/^product_([0-9]+)_([0-9]+)$/i', $key, $reg)) { $modebatch = "barcode"; } elseif (preg_match('/^product_batch_([0-9]+)_([0-9]+)$/i', $key, $reg)) { // With batchmode enabled @@ -156,7 +157,7 @@ if ($action == 'updatelines' && $usercancreate) { $qty = "qty_".$reg[1].'_'.$reg[2]; $ent = "entrepot_".$reg[1].'_'.$reg[2]; $fk_commandedet = "fk_commandedet_".$reg[1].'_'.$reg[2]; - $idline = GETPOST("idline_".$reg[1].'_'.$reg[2]); + $idline = GETPOSTINT("idline_".$reg[1].'_'.$reg[2]); $warehouse_id = GETPOSTINT($ent); $prod_id = GETPOSTINT($prod); //$pu = "pu_".$reg[1].'_'.$reg[2]; // This is unit price including discount @@ -245,6 +246,7 @@ if ($action == 'updatelines' && $usercancreate) { $sqlsearchdet .= " AND batch = '".$db->escape($lot)."'"; $resqlsearchdet = $db->query($sqlsearchdet); + $objsearchdet = null; if ($resqlsearchdet) { $objsearchdet = $db->fetch_object($resqlsearchdet); } else { @@ -384,6 +386,7 @@ $warehouse_static = new Entrepot($db); $title = $object->ref." - ".$langs->trans('ShipmentDistribution'); $help_url = 'EN:Module_Shipments|FR:Module_Expéditions|ES:Módulo_Expediciones|DE:Modul_Lieferungen'; $morejs = array('/expedition/js/lib_dispatch.js.php'); +$typeobject = null; llxHeader('', $title, $help_url, '', 0, 0, $morejs, '', '', 'mod-expedition page-card_dispatch'); @@ -459,7 +462,7 @@ if ($object->id > 0 || !empty($object->ref)) { if ($action != 'classify' && $permissiontoadd) { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, (!getDolGlobalString('PROJECT_CAN_ALWAYS_LINK_TO_ALL_SUPPLIERS') ? $object->socid : -1), $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, (!getDolGlobalString('PROJECT_CAN_ALWAYS_LINK_TO_ALL_SUPPLIERS') ? $object->socid : -1), (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($objectsrc) && !empty($objectsrc->fk_project)) { $proj = new Project($db); @@ -546,6 +549,11 @@ if ($object->id > 0 || !empty($object->ref)) { $entrepot = new Entrepot($db); $listwarehouses = $entrepot->list_array(1); + $nbfreeproduct = 0; // Nb of lines of free products/services + $nbproduct = 0; // Nb of predefined product lines to dispatch (already done or not) if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is off (default) + // or nb of line that remain to dispatch if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is on. + + print '
'; @@ -683,10 +691,6 @@ if ($object->id > 0 || !empty($object->ref)) { print "\n"; } - $nbfreeproduct = 0; // Nb of lines of free products/services - $nbproduct = 0; // Nb of predefined product lines to dispatch (already done or not) if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is off (default) - // or nb of line that remain to dispatch if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is on. - $conf->cache['product'] = array(); // Loop on each line of origin order diff --git a/htdocs/expedition/document.php b/htdocs/expedition/document.php index f8b1cc3ad85..4dc74e52a72 100644 --- a/htdocs/expedition/document.php +++ b/htdocs/expedition/document.php @@ -6,6 +6,7 @@ * Copyright (C) 2013 Cédric Salvador * Copyright (C) 2017 Ferran Marcet * Copyright (C) 2024 Frédéric France + * Copyright (C) 2025 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 @@ -79,6 +80,7 @@ if ($id > 0 || !empty($ref)) { $object->fetch($id, $ref); $object->fetch_thirdparty(); + $typeobject = null; if (!empty($object->origin)) { $typeobject = $object->origin; $origin = $object->origin; @@ -159,7 +161,7 @@ if ($id > 0 || !empty($ref)) { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $objectsrc->socid, $objectsrc->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $objectsrc->socid, (string) $objectsrc->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($objectsrc->fk_project)) { $proj = new Project($db); diff --git a/htdocs/expedition/list.php b/htdocs/expedition/list.php index b45450396bc..03a6a11db5d 100644 --- a/htdocs/expedition/list.php +++ b/htdocs/expedition/list.php @@ -6,7 +6,7 @@ * Copyright (C) 2019 Nicolas ZABOURI * Copyright (C) 2020 Thibault FOUCART * Copyright (C) 2023 Christophe Battarel - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) 2024 Benjamin Falière * Copyright (C) 2024 Vincent Maury * Copyright (C) 2024 William Mead @@ -557,9 +557,6 @@ if (empty($reshook)) { if ($search_company) { $param .= "&search_company=".urlencode($search_company); } - if ($search_shipping_method_id) { - $param .= "&search_shipping_method_id=".urlencode($search_shipping_method_id); - } if ($search_tracking) { $param .= "&search_tracking=".urlencode($search_tracking); } @@ -1089,7 +1086,7 @@ if ($massaction == 'createbills') { print $langs->trans('DateInvoice'); print ''; print '
'; print ''; print ''; @@ -1106,7 +1103,7 @@ if ($massaction == 'createbills') { print ''; print ''; } // Town @@ -1353,7 +1350,7 @@ if (!empty($arrayfields['e.signed_status']['checked'])) { // Status billed if (!empty($arrayfields['e.billed']['checked'])) { print ''; } // Action column @@ -1649,7 +1646,7 @@ while ($i < $imaxinloop) { } if (!empty($arrayfields['e.fk_shipping_method']['checked'])) { // Get code using getLabelFromKey - $code = $langs->getLabelFromKey($db, $object->shipping_method_id, 'c_shipment_mode', 'rowid', 'code'); + $code = $langs->getLabelFromKey($db, (string) $object->shipping_method_id, 'c_shipment_mode', 'rowid', 'code'); print '
'; - if (is_numeric($this->withsubstit)) { - $out .= $form->textwithpicto($langs->trans("EMailTestSubstitutionReplacedByGenericValues"), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltip'); // Old usage + foreach ($this->lines_model as $line) { + $reg = array(); + if (preg_match('/\((.*)\)/', $line->label, $reg)) { + $labeltouse = $langs->trans($reg[1]); // langs->trans when label is __(xxx)__ } else { - $out .= $form->textwithpicto($langs->trans('AvailableVariables'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltip'); // New usage + $labeltouse = $line->label; } - $out .= "
' . $langs->trans("MailFrom") . ''; + // We escape the $labeltouse to store it into $modelmail_array. + $modelmail_array[$line->id] = dol_escape_htmltag($labeltouse); + if ($line->lang) { + $modelmail_array[$line->id] .= ' '.picto_from_langcode($line->lang); + } + if ($line->private) { + $modelmail_array[$line->id] .= ' - '.dol_escape_htmltag($langs->trans("Private")).''; + } + } + } - // $this->fromtype is the default value to use to select sender - if (!($this->fromtype === 'user' && $this->fromid > 0) - && !($this->fromtype === 'company') - && !($this->fromtype === 'robot') - && !preg_match('/user_aliases/', $this->fromtype) - && !preg_match('/global_aliases/', $this->fromtype) - && !preg_match('/senderprofile/', $this->fromtype) - ) { - // Use this->fromname and this->frommail or error if not defined - $out .= $this->fromname; - if ($this->frommail) { - $out .= ' <' . $this->frommail . '>'; - } else { - if ($this->fromtype) { - $langs->load('errors'); - $out .= ' <' . $langs->trans('ErrorNoMailDefinedForThisUser') . '> '; - } - } + // Zone to select email template + if (count($modelmail_array) > 0) { + $model_mail_selected_id = GETPOSTISSET('modelmailselected') ? GETPOSTINT('modelmailselected') : ($arraydefaultmessage->id > 0 ? $arraydefaultmessage->id : 0); + + // If list of template is filled + $out .= '
'."\n"; + + $out .= $this->selectarray('modelmailselected', $modelmail_array, $model_mail_selected_id, $langs->trans('SelectMailModel'), 0, 0, '', 0, 0, 0, '', 'minwidth100', 1, '', 0, 1); + if ($user->admin) { + $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFrom", $langs->transnoentitiesnoconv('Setup').' - '.$langs->transnoentitiesnoconv('EMails')), 1); + } + + $out .= '   '; + $out .= ''; + $out .= '   '; + $out .= '
'; + } elseif (!empty($this->param['models']) && in_array($this->param['models'], array( + 'propal_send', 'order_send', 'facture_send', + 'shipping_send', 'fichinter_send', 'supplier_proposal_send', 'order_supplier_send', + 'invoice_supplier_send', 'thirdparty', 'contract', 'user', 'recruitmentcandidature_send', 'all' + ))) { + // If list of template is empty + $out .= '
'."\n"; + $out .= ''.$langs->trans('SelectMailModel').': '; + $out .= ''; // Do not put 'disabled' on 'option' tag, it is already on 'select' and it makes chrome crazy. + if ($user->admin) { + $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFrom", $langs->transnoentitiesnoconv('Setup').' - '.$langs->transnoentitiesnoconv('EMails')), 1); + } + $out .= '   '; + $out .= ''; + $out .= '   '; + $out .= '
'; + } else { + $out .= ''; + } + + + $out .= ''."\n"; + + // Substitution array/string + $helpforsubstitution = ''; + if (is_array($this->substit) && count($this->substit)) { + $helpforsubstitution .= $langs->trans('AvailableVariables').' :

'."\n"; + } + foreach ($this->substit as $key => $val) { + // Do not show deprecated variables into the tooltip help of substitution variables + if (in_array($key, array('__NEWREF__', '__REFCLIENT__', '__REFSUPPLIER__', '__SUPPLIER_ORDER_DATE_DELIVERY__', '__SUPPLIER_ORDER_DELAY_DELIVERY__'))) { + continue; + } + $helpforsubstitution .= $key.' -> '.$langs->trans(dol_string_nohtmltag(dolGetFirstLineOfText($val))).'
'; + } + if (is_array($this->substit) && count($this->substit)) { + $helpforsubstitution .= '
'; + } + + /* + if (!empty($this->withsubstit)) { // Unset or set ->withsubstit=0 to disable this. + $out .= '\n"; + }*/ + + // From + if (!empty($this->withfrom)) { + if (!empty($this->withfromreadonly)) { + $out .= '\n"; } else { - $out .= '\n"; - } - } + $liste = array(); - // To - if (!empty($this->withto) || is_array($this->withto)) { - $out .= $this->getHtmlForTo(); - } - - // To User - if (!empty($this->withtouser) && is_array($this->withtouser) && getDolGlobalString('MAIN_MAIL_ENABLED_USER_DEST_SELECT')) { - $out .= '\n"; - } - - // With option for one email per recipient - if (!empty($this->withoptiononeemailperrecipient)) { - if (abs($this->withoptiononeemailperrecipient) == 1) { - $out .= ''; - } else { - $out .= ''; - } - } - - // CC - if (!empty($this->withtocc) || is_array($this->withtocc)) { - $out .= $this->getHtmlForCc(); - } - - // To User cc - if (!empty($this->withtoccuser) && is_array($this->withtoccuser) && getDolGlobalString('MAIN_MAIL_ENABLED_USER_DEST_SELECT')) { - $out .= '\n"; - } - - // CCC - if (!empty($this->withtoccc) || is_array($this->withtoccc)) { - $out .= $this->getHtmlForWithCcc(); - } - - // Replyto - if (!empty($this->withreplyto)) { - if ($this->withreplytoreadonly) { - $out .= ''; - $out .= ''; - $out .= "\n"; - } - } - - // Errorsto - if (!empty($this->witherrorsto)) { - $out .= $this->getHtmlForWithErrorsTo(); - } - - // Ask delivery receipt - if (!empty($this->withdeliveryreceipt) && getDolGlobalInt('MAIN_EMAIL_SUPPORT_ACK')) { - $out .= $this->getHtmlForDeliveryreceipt(); - } - - // Topic - if (!empty($this->withtopic)) { - $out .= $this->getHtmlForTopic($arraydefaultmessage, $helpforsubstitution); - } - - // Attached files - if (!empty($this->withfile)) { - $out .= ''; - $out .= ''; - - $out .= '\n"; + } else { + $out .= '\n"; + } + } - $entity = (isset($this->param['object_entity']) ? $this->param['object_entity'] : $conf->entity); - if ($entity > 1) { - $relativepathtofile = str_replace('/' . $entity . '/', '/', $relativepathtofile); - } - // Try to extract data from full path - $formfile_params = array(); - preg_match('#^(/)(\w+)(/)(.+)$#', $relativepathtofile, $formfile_params); + // To + if (!empty($this->withto) || is_array($this->withto)) { + $out .= $this->getHtmlForTo(); + } - $out .= '
'; - // Preview of attachment - $out .= img_mime($listofnames[$key]) . $listofnames[$key]; + // To User + if (!empty($this->withtouser) && is_array($this->withtouser) && getDolGlobalString('MAIN_MAIL_ENABLED_USER_DEST_SELECT')) { + $out .= '
\n"; + } - if (!$this->withfilereadonly) { - $out .= ' '; - //$out.= ' '.img_delete($langs->trans("Remove"), 'id="removedfile_'.$key.'" name="removedfile_'.$key.'"', 'removedfile input-nobottom').''; - } - $out .= '
'; + // With option for one email per recipient + if (!empty($this->withoptiononeemailperrecipient)) { + if (abs($this->withoptiononeemailperrecipient) == 1) { + $out .= ''; + } else { + $out .= ''; + } + } + + // CC + if (!empty($this->withtocc) || is_array($this->withtocc)) { + $out .= $this->getHtmlForCc(); + } + + // To User cc + if (!empty($this->withtoccuser) && is_array($this->withtoccuser) && getDolGlobalString('MAIN_MAIL_ENABLED_USER_DEST_SELECT')) { + $out .= '\n"; + } + + // CCC + if (!empty($this->withtoccc) || is_array($this->withtoccc)) { + $out .= $this->getHtmlForWithCcc(); + } + + // Replyto + if (!empty($this->withreplyto)) { + if ($this->withreplytoreadonly) { + $out .= ''; + $out .= ''; + $out .= "\n"; + } + } + + // Errorsto + if (!empty($this->witherrorsto)) { + $out .= $this->getHtmlForWithErrorsTo(); + } + + // Ask delivery receipt + if (!empty($this->withdeliveryreceipt) && getDolGlobalInt('MAIN_EMAIL_SUPPORT_ACK')) { + $out .= $this->getHtmlForDeliveryreceipt(); + } + + // Topic + if (!empty($this->withtopic)) { + $out .= $this->getHtmlForTopic($arraydefaultmessage, $helpforsubstitution); + } + + // Attached files + if (!empty($this->withfile)) { + $out .= ''; + $out .= ''; + + $out .= '\n"; + } else { + $out .= $this->withfile; } - // Message (+ Links to choose layout or ai prompt) - if (!empty($this->withbody)) { - $defaultmessage = GETPOST('message', 'restricthtml'); - if (!GETPOST('modelselected', 'alpha') || GETPOST('modelmailselected') != '-1') { - if ($arraydefaultmessage && $arraydefaultmessage->content) { - $defaultmessage = $arraydefaultmessage->content; - } elseif (!is_numeric($this->withbody)) { - $defaultmessage = $this->withbody; - } - } + $out .= "\n"; + } - // Complete substitution array with the url to make online payment + // Message (+ Links to choose layout or ai prompt) + if (!empty($this->withbody)) { + $defaultmessage = GETPOST('message', 'restricthtml'); + if (!GETPOST('modelselected', 'alpha') || GETPOST('modelmailselected') != '-1') { + if ($arraydefaultmessage && $arraydefaultmessage->content) { + $defaultmessage = $arraydefaultmessage->content; + } elseif (!is_numeric($this->withbody)) { + $defaultmessage = $this->withbody; + } + } + + // Complete substitution array with the url to make online payment + $paymenturl = ''; + // Set the online payment url link into __ONLINE_PAYMENT_URL__ key + require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php'; + $validpaymentmethod = getValidOnlinePaymentMethods(''); + + if (empty($this->substit['__REF__'])) { // @phan-suppress-current-line PhanTypeMismatchProperty $paymenturl = ''; - // Set the online payment url link into __ONLINE_PAYMENT_URL__ key - require_once DOL_DOCUMENT_ROOT . '/core/lib/payments.lib.php'; - $validpaymentmethod = getValidOnlinePaymentMethods(''); - - if (empty($this->substit['__REF__'])) { // @phan-suppress-current-line PhanTypeMismatchProperty - $paymenturl = ''; - } else { - $langs->loadLangs(array('paypal', 'other')); - $typeforonlinepayment = 'free'; - if ($this->param["models"] == 'order' || $this->param["models"] == 'order_send') { - $typeforonlinepayment = 'order'; // TODO use detection on something else than template - } - if ($this->param["models"] == 'invoice' || $this->param["models"] == 'facture_send') { - $typeforonlinepayment = 'invoice'; // TODO use detection on something else than template - } - if ($this->param["models"] == 'member') { - $typeforonlinepayment = 'member'; // TODO use detection on something else than template - } - $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $this->substit['__REF__']); - $paymenturl = $url; + } else { + $langs->loadLangs(array('paypal', 'other')); + $typeforonlinepayment = 'free'; + if ($this->param["models"] == 'order' || $this->param["models"] == 'order_send') { + $typeforonlinepayment = 'order'; // TODO use detection on something else than template } - - if (count($validpaymentmethod) > 0 && $paymenturl) { - $langs->load('other'); - $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = str_replace('\n', "\n", $langs->transnoentities("PredefinedMailContentLink", $paymenturl)); - $this->substit['__ONLINE_PAYMENT_URL__'] = $paymenturl; - } elseif (count($validpaymentmethod) > 0) { - $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = '__ONLINE_PAYMENT_TEXT_AND_URL__'; - $this->substit['__ONLINE_PAYMENT_URL__'] = '__ONLINE_PAYMENT_URL__'; - } else { - $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = ''; - $this->substit['__ONLINE_PAYMENT_URL__'] = ''; + if ($this->param["models"] == 'invoice' || $this->param["models"] == 'facture_send') { + $typeforonlinepayment = 'invoice'; // TODO use detection on something else than template } - - $this->substit['__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__'] = ''; - - // Generate the string with the template for lines repeated and filled for each line - $lines = ''; - $defaultlines = $arraydefaultmessage->content_lines; - if (isset($defaultlines)) { - foreach ($this->substit_lines as $lineid => $substit_line) { - $lines .= make_substitutions($defaultlines, $substit_line) . "\n"; - } + if ($this->param["models"] == 'member') { + $typeforonlinepayment = 'member'; // TODO use detection on something else than template } - $this->substit['__LINES__'] = $lines; - - $defaultmessage = str_replace('\n', "\n", $defaultmessage); - - // Deal with format differences between message and some substitution variables (text / HTML) - $atleastonecomponentishtml = 0; - if (strpos($defaultmessage, '__USER_SIGNATURE__') !== false && dol_textishtml($this->substit['__USER_SIGNATURE__'])) { - $atleastonecomponentishtml++; - } - if (strpos($defaultmessage, '__SENDEREMAIL_SIGNATURE__') !== false && dol_textishtml($this->substit['__SENDEREMAIL_SIGNATURE__'])) { - $atleastonecomponentishtml++; - } - if (strpos($defaultmessage, '__ONLINE_PAYMENT_TEXT_AND_URL__') !== false && dol_textishtml($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'])) { - $atleastonecomponentishtml++; - } - if (strpos($defaultmessage, '__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__') !== false && dol_textishtml($this->substit['__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__'])) { - $atleastonecomponentishtml++; - } - if (dol_textishtml($defaultmessage)) { - $atleastonecomponentishtml++; - } - if ($atleastonecomponentishtml) { - if (!dol_textishtml($this->substit['__USER_SIGNATURE__'])) { - $this->substit['__USER_SIGNATURE__'] = dol_nl2br($this->substit['__USER_SIGNATURE__']); - } - if (!dol_textishtml($this->substit['__SENDEREMAIL_SIGNATURE__'])) { - $this->substit['__SENDEREMAIL_SIGNATURE__'] = dol_nl2br($this->substit['__SENDEREMAIL_SIGNATURE__']); - } - if (!dol_textishtml($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'])) { - $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = dol_nl2br($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__']); - } - if (!dol_textishtml($defaultmessage)) { - $defaultmessage = dol_nl2br($defaultmessage); - } - } - - if (GETPOSTISSET("message") && !GETPOST('modelselected')) { - $defaultmessage = GETPOST("message", "restricthtml"); - } else { - $defaultmessage = make_substitutions($defaultmessage, $this->substit); - // Clean first \n and br (to avoid empty line when CONTACTCIVNAME is empty) - $defaultmessage = preg_replace("/^(
)+/", "", $defaultmessage); - $defaultmessage = preg_replace("/^\n+/", "", $defaultmessage); - } - - $out .= ''; - $out .= ''; - $out .= ''; - $out .= ''; - - $out .= ''; - $out .= '\n"; + $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $this->substit['__REF__']); + $paymenturl = $url; } - $out .= '
'; + if (is_numeric($this->withsubstit)) { + $out .= $form->textwithpicto($langs->trans("EMailTestSubstitutionReplacedByGenericValues"), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltip'); // Old usage + } else { + $out .= $form->textwithpicto($langs->trans('AvailableVariables'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltip'); // New usage + } + $out .= "
'.$langs->trans("MailFrom").''; + + // $this->fromtype is the default value to use to select sender + if (!($this->fromtype === 'user' && $this->fromid > 0) + && !($this->fromtype === 'company') + && !($this->fromtype === 'robot') + && !preg_match('/user_aliases/', $this->fromtype) + && !preg_match('/global_aliases/', $this->fromtype) + && !preg_match('/senderprofile/', $this->fromtype) + ) { + // Use this->fromname and this->frommail or error if not defined + $out .= $this->fromname; + if ($this->frommail) { + $out .= ' <'.$this->frommail.'>'; } else { - $liste = array(); - - // Add user email - if (empty($user->email)) { + if ($this->fromtype) { $langs->load('errors'); - $s = $user->getFullName($langs) . ' <' . $langs->trans('ErrorNoMailDefinedForThisUser') . '>'; - } else { - $s = $user->getFullName($langs) . ' <' . $user->email . '>'; + $out .= ' <'.$langs->trans('ErrorNoMailDefinedForThisUser').'> '; } - $liste['user'] = array('label' => $s, 'data-html' => $s); - - // Add also company main email - if (getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')) { - $s = (!getDolGlobalString('MAIN_INFO_SOCIETE_NOM') ? $conf->global->MAIN_INFO_SOCIETE_EMAIL : $conf->global->MAIN_INFO_SOCIETE_NOM) . ' <' . getDolGlobalString('MAIN_INFO_SOCIETE_MAIL') . '>'; - $liste['company'] = array('label' => $s, 'data-html' => $s); - } - - // Add also email aliases if there is some - $listaliases = array( - 'user_aliases' => (empty($user->email_aliases) ? '' : $user->email_aliases), - 'global_aliases' => getDolGlobalString('MAIN_INFO_SOCIETE_MAIL_ALIASES'), - ); - - if (!empty($arraydefaultmessage->email_from)) { - $templatemailfrom = ' <' . $arraydefaultmessage->email_from . '>'; - $liste['from_template_' . GETPOST('modelmailselected')] = array('label' => $templatemailfrom, 'data-html' => $templatemailfrom); - } - - // Also add robot email - if (!empty($this->fromalsorobot)) { - if (getDolGlobalString('MAIN_MAIL_EMAIL_FROM') && getDolGlobalString('MAIN_MAIL_EMAIL_FROM') != getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')) { - $s = getDolGlobalString('MAIN_MAIL_EMAIL_FROM'); - if ($this->frommail) { - $s .= ' <' . getDolGlobalString('MAIN_MAIL_EMAIL_FROM') . '>'; - } - $liste['main_from'] = array('label' => $s, 'data-html' => $s); - } - } - - // Add also email aliases from the c_email_senderprofile table - $sql = "SELECT rowid, label, email FROM " . $this->db->prefix() . "c_email_senderprofile"; - $sql .= " WHERE active = 1 AND (private = 0 OR private = " . ((int)$user->id) . ")"; - $sql .= " ORDER BY position"; - $resql = $this->db->query($sql); - if ($resql) { - $num = $this->db->num_rows($resql); - $i = 0; - while ($i < $num) { - $obj = $this->db->fetch_object($resql); - if ($obj) { - $listaliases['senderprofile_' . $obj->rowid] = $obj->label . ' <' . $obj->email . '>'; - } - $i++; - } - } else { - dol_print_error($this->db); - } - - foreach ($listaliases as $typealias => $listalias) { - $posalias = 0; - $listaliasarray = explode(',', $listalias); - foreach ($listaliasarray as $listaliasval) { - $posalias++; - $listaliasval = trim($listaliasval); - if ($listaliasval) { - $listaliasval = preg_replace('//', '>', $listaliasval); - if (!preg_match('/</', $listaliasval)) { - $listaliasval = '<' . $listaliasval . '>'; - } - $liste[$typealias . '_' . $posalias] = array('label' => $listaliasval, 'data-html' => $listaliasval); - } - } - } - - // Using ajaxcombo here make the '' no more visible on list because is not a valid html tag, - // so we transform before each record into $liste to be printable with ajaxcombo by replacing <> into () - // $liste['senderprofile_0_0'] = array('label'=>'rrr', 'data-html'=>'rrr <aaaa>'); - foreach ($liste as $key => $val) { - if (!empty($liste[$key]['data-html'])) { - $liste[$key]['data-html'] = str_replace(array('<', '<', '>', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $liste[$key]['data-html']); - $liste[$key]['data-html'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('(', ')'), $liste[$key]['data-html']); - } - } - $out .= ' ' . $form->selectarray('fromtype', $liste, empty($arraydefaultmessage->email_from) ? $this->fromtype : 'from_template_' . GETPOST('modelmailselected'), 0, 0, 0, '', 0, 0, 0, '', 'fromforsendingprofile maxwidth200onsmartphone', 1, '', $disablebademails); } - - $out .= "
' . $langs->trans("MailFrom") . ""; - $out .= $langs->trans("Name") . ':'; - $out .= '    '; - $out .= $langs->trans("EMail") . ':<>'; - $out .= "
'; - $out .= $langs->trans("MailToUsers"); - $out .= ''; - - // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time - $tmparray = $this->withtouser; - foreach ($tmparray as $key => $val) { - $tmparray[$key] = dol_htmlentities($tmparray[$key], 0, 'UTF-8', true); - } - $withtoselected = GETPOST("receiveruser", 'array'); // Array of selected value - if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') { - $withtoselected = array_keys($tmparray); - } - $out .= $form->multiselectarray("receiveruser", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, ""); - $out .= "
'; - $out .= $langs->trans("GroupEmails"); - $out .= ''; - $out .= ' withoptiononeemailperrecipient > 0 ? ' checked="checked"' : '') . '> '; - $out .= ''; - //$out .= ''; - //$out .= ' - '; - //$out .= $langs->trans("WarningIfYouCheckOneRecipientPerEmail"); - //$out .= ''; - if (getDolGlobalString('MASS_ACTION_EMAIL_ON_DIFFERENT_THIRPARTIES_ADD_CUSTOM_EMAIL')) { - if (!empty($this->withto) && !is_array($this->withto)) { - $out .= ' ' . $langs->trans("or") . ' '; - } - } - $out .= '
'; - $out .= $langs->trans("MailToCCUsers"); - $out .= ''; - - // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time - $tmparray = $this->withtoccuser; - foreach ($tmparray as $key => $val) { - $tmparray[$key] = dol_htmlentities($tmparray[$key], 0, 'UTF-8', true); - } - $withtoselected = GETPOST("receiverccuser", 'array'); // Array of selected value - if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') { - $withtoselected = array_keys($tmparray); - } - $out .= $form->multiselectarray("receiverccuser", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, ""); - $out .= "
" . $langs->trans("MailReply") . "" . $this->replytoname . ($this->replytomail ? (" <" . $this->replytomail . ">") : ""); - $out .= "
' . $langs->trans("MailFile") . ''; - - if ($this->withmaindocfile) { - // withmaindocfile is set to 1 or -1 to show the checkbox (-1 = checked or 1 = not checked) - if (GETPOSTISSET('sendmail')) { - $this->withmaindocfile = (GETPOST('addmaindocfile', 'alpha') ? -1 : 1); - } elseif (is_object($arraydefaultmessage) && $arraydefaultmessage->id > 0) { - // If a template was selected, we use setup of template to define if join file checkbox is selected or not. - $this->withmaindocfile = ($arraydefaultmessage->joinfiles ? -1 : 1); - } - } - - if (!empty($this->withmaindocfile)) { - if ($this->withmaindocfile == 1) { - $out .= ''; - } elseif ($this->withmaindocfile == -1) { - $out .= ''; - } - if (getDolGlobalString('MAIL_MASS_ACTION_ADD_LAST_IF_MAIN_DOC_NOT_FOUND')) { - $out .= '
'; + // Add user email + if (empty($user->email)) { + $langs->load('errors'); + $s = $user->getFullName($langs).' <'.$langs->trans('ErrorNoMailDefinedForThisUser').'>'; } else { - $out .= '
'; + $s = $user->getFullName($langs).' <'.$user->email.'>'; } + $liste['user'] = array('label' => $s, 'data-html' => $s); + + // Add also company main email + if (getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')) { + $s = (!getDolGlobalString('MAIN_INFO_SOCIETE_NOM') ? $conf->global->MAIN_INFO_SOCIETE_EMAIL : $conf->global->MAIN_INFO_SOCIETE_NOM).' <' . getDolGlobalString('MAIN_INFO_SOCIETE_MAIL').'>'; + $liste['company'] = array('label' => $s, 'data-html' => $s); + } + + // Add also email aliases if there is some + $listaliases = array( + 'user_aliases' => (empty($user->email_aliases) ? '' : $user->email_aliases), + 'global_aliases' => getDolGlobalString('MAIN_INFO_SOCIETE_MAIL_ALIASES'), + ); + + if (!empty($arraydefaultmessage->email_from)) { + $templatemailfrom = ' <'.$arraydefaultmessage->email_from.'>'; + $liste['from_template_'.GETPOST('modelmailselected')] = array('label' => $templatemailfrom, 'data-html' => $templatemailfrom); + } + + // Also add robot email + if (!empty($this->fromalsorobot)) { + if (getDolGlobalString('MAIN_MAIL_EMAIL_FROM') && getDolGlobalString('MAIN_MAIL_EMAIL_FROM') != getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')) { + $s = getDolGlobalString('MAIN_MAIL_EMAIL_FROM'); + if ($this->frommail) { + $s .= ' <' . getDolGlobalString('MAIN_MAIL_EMAIL_FROM').'>'; + } + $liste['main_from'] = array('label' => $s, 'data-html' => $s); + } + } + + // Add also email aliases from the c_email_senderprofile table + $sql = "SELECT rowid, label, email FROM ".$this->db->prefix()."c_email_senderprofile"; + $sql .= " WHERE active = 1 AND (private = 0 OR private = ".((int) $user->id).")"; + $sql .= " ORDER BY position"; + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) { + $obj = $this->db->fetch_object($resql); + if ($obj) { + $listaliases['senderprofile_'.$obj->rowid] = $obj->label.' <'.$obj->email.'>'; + } + $i++; + } + } else { + dol_print_error($this->db); + } + + foreach ($listaliases as $typealias => $listalias) { + $posalias = 0; + $listaliasarray = explode(',', $listalias); + foreach ($listaliasarray as $listaliasval) { + $posalias++; + $listaliasval = trim($listaliasval); + if ($listaliasval) { + $listaliasval = preg_replace('//', '>', $listaliasval); + if (!preg_match('/</', $listaliasval)) { + $listaliasval = '<'.$listaliasval.'>'; + } + $liste[$typealias.'_'.$posalias] = array('label' => $listaliasval, 'data-html' => $listaliasval); + } + } + } + + // Using ajaxcombo here make the '' no more visible on list because is not a valid html tag, + // so we transform before each record into $liste to be printable with ajaxcombo by replacing <> into () + // $liste['senderprofile_0_0'] = array('label'=>'rrr', 'data-html'=>'rrr <aaaa>'); + foreach ($liste as $key => $val) { + if (!empty($liste[$key]['data-html'])) { + $liste[$key]['data-html'] = str_replace(array('<', '<', '>', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $liste[$key]['data-html']); + $liste[$key]['data-html'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('(', ')'), $liste[$key]['data-html']); + } + } + $out .= ' '.$form->selectarray('fromtype', $liste, empty($arraydefaultmessage->email_from) ? $this->fromtype : 'from_template_'.GETPOST('modelmailselected'), 0, 0, 0, '', 0, 0, 0, '', 'fromforsendingprofile maxwidth200onsmartphone', 1, '', $disablebademails); } - if (is_numeric($this->withfile)) { - // TODO Trick to have param removedfile containing nb of file to delete. But this does not works without javascript - $out .= '' . "\n"; - $out .= '' . "\n"; - if (count($listofpaths)) { - foreach ($listofpaths as $key => $val) { - $relativepathtofile = substr($val, (strlen(DOL_DATA_ROOT) - strlen($val))); + $out .= "
'.$langs->trans("MailFrom").""; + $out .= $langs->trans("Name").':'; + $out .= '    '; + $out .= $langs->trans("EMail").':<>'; + $out .= "
'; + $out .= $langs->trans("MailToUsers"); + $out .= ''; - $out .= ' ' . $formfile->showPreview(array(), $formfile_params[2], $formfile_params[4], 0, ($entity == 1 ? '' : 'entity=' . ((int)$entity))); + // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time + $tmparray = $this->withtouser; + foreach ($tmparray as $key => $val) { + $tmparray[$key] = dol_htmlentities($tmparray[$key], 0, 'UTF-8', true); + } + $withtoselected = GETPOST("receiveruser", 'array'); // Array of selected value + if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') { + $withtoselected = array_keys($tmparray); + } + $out .= $form->multiselectarray("receiveruser", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, ""); + $out .= "
'; + $out .= $langs->trans("GroupEmails"); + $out .= ''; + $out .= ' withoptiononeemailperrecipient > 0 ? ' checked="checked"' : '').'> '; + $out .= ''; + //$out .= ''; + //$out .= ' - '; + //$out .= $langs->trans("WarningIfYouCheckOneRecipientPerEmail"); + //$out .= ''; + if (getDolGlobalString('MASS_ACTION_EMAIL_ON_DIFFERENT_THIRPARTIES_ADD_CUSTOM_EMAIL')) { + if (!empty($this->withto) && !is_array($this->withto)) { + $out .= ' '.$langs->trans("or").' '; + } + } + $out .= '
'; + $out .= $langs->trans("MailToCCUsers"); + $out .= ''; + + // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time + $tmparray = $this->withtoccuser; + foreach ($tmparray as $key => $val) { + $tmparray[$key] = dol_htmlentities($tmparray[$key], 0, 'UTF-8', true); + } + $withtoselected = GETPOST("receiverccuser", 'array'); // Array of selected value + if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') { + $withtoselected = array_keys($tmparray); + } + $out .= $form->multiselectarray("receiverccuser", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, ""); + $out .= "
".$langs->trans("MailReply")."".$this->replytoname.($this->replytomail ? (" <".$this->replytomail.">") : ""); + $out .= "
'.$langs->trans("MailFile").''; + + if ($this->withmaindocfile) { + // withmaindocfile is set to 1 or -1 to show the checkbox (-1 = checked or 1 = not checked) + if (GETPOSTISSET('sendmail')) { + $this->withmaindocfile = (GETPOST('addmaindocfile', 'alpha') ? -1 : 1); + } elseif (is_object($arraydefaultmessage) && $arraydefaultmessage->id > 0) { + // If a template was selected, we use setup of template to define if join file checkbox is selected or not. + $this->withmaindocfile = ($arraydefaultmessage->joinfiles ? -1 : 1); + } + } + + if (!empty($this->withmaindocfile)) { + if ($this->withmaindocfile == 1) { + $out .= ''; + } elseif ($this->withmaindocfile == -1) { + $out .= ''; + } + if (getDolGlobalString('MAIL_MASS_ACTION_ADD_LAST_IF_MAIN_DOC_NOT_FOUND')) { + $out .= '
'; + } else { + $out .= '
'; + } + } + + if (is_numeric($this->withfile)) { + // TODO Trick to have param removedfile containing nb of file to delete. But this does not works without javascript + $out .= ''."\n"; + $out .= ''."\n"; + if (count($listofpaths)) { + foreach ($listofpaths as $key => $val) { + $relativepathtofile = substr($val, (strlen(DOL_DATA_ROOT) - strlen($val))); + + $entity = (isset($this->param['object_entity']) ? $this->param['object_entity'] : $conf->entity); + if ($entity > 1) { + $relativepathtofile = str_replace('/'.$entity.'/', '/', $relativepathtofile); } - } /*elseif (empty($this->withmaindocfile)) { + // Try to extract data from full path + $formfile_params = array(); + preg_match('#^(/)(\w+)(/)(.+)$#', $relativepathtofile, $formfile_params); + + $out .= '
'; + // Preview of attachment + $out .= img_mime($listofnames[$key]).$listofnames[$key]; + + $out .= ' '.$formfile->showPreview(array(), $formfile_params[2], $formfile_params[4], 0, ($entity == 1 ? '' : 'entity='.((int) $entity))); + + if (!$this->withfilereadonly) { + $out .= ' '; + //$out.= ' '.img_delete($langs->trans("Remove"), 'id="removedfile_'.$key.'" name="removedfile_'.$key.'"', 'removedfile input-nobottom').''; + } + $out .= '
'; + } + } /*elseif (empty($this->withmaindocfile)) { //$out .= ''.$langs->trans("NoAttachedFiles").'
'; }*/ - if ($this->withfile == 2) { - $maxfilesizearray = getMaxFileSizeArray(); - $maxmin = $maxfilesizearray['maxmin']; - if ($maxmin > 0) { - $out .= ''; // MAX_FILE_SIZE must precede the field type=file - } - // Can add other files - if (!getDolGlobalString('FROM_MAIL_DONT_USE_INPUT_FILE_MULTIPLE')) { - $out .= ''; - } else { - $out .= ''; - } - $out .= ' '; - $out .= ''; + if ($this->withfile == 2) { + $maxfilesizearray = getMaxFileSizeArray(); + $maxmin = $maxfilesizearray['maxmin']; + if ($maxmin > 0) { + $out .= ''; // MAX_FILE_SIZE must precede the field type=file } - } else { - $out .= $this->withfile; + // Can add other files + if (!getDolGlobalString('FROM_MAIL_DONT_USE_INPUT_FILE_MULTIPLE')) { + $out .= ''; + } else { + $out .= ''; + } + $out .= ' '; + $out .= ''; } - - $out .= "
'; - $out .= $form->textwithpicto($langs->trans('MailText'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltipfrombody'); - $out .= ''; - - $formmail = $this; - $showlinktolayout = ($formmail->withfckeditor && getDolGlobalInt('MAIN_EMAIL_USE_LAYOUT')) ? $formmail->withlayout : ''; - $showlinktolayoutlabel = $langs->trans("FillMessageWithALayout"); - $showlinktoai = ($formmail->withaiprompt && isModEnabled('ai')) ? 'textgenerationemail' : ''; - $showlinktoailabel = $langs->trans("FillMessageWithAIContent"); - $formatforouput = ''; - $htmlname = 'message'; - - // Fill $out - include DOL_DOCUMENT_ROOT . '/core/tpl/formlayoutai.tpl.php'; - - $out .= '
'; - if ($this->withbodyreadonly) { - $out .= nl2br($defaultmessage); - $out .= ''; - } else { - if (!isset($this->ckeditortoolbar)) { - $this->ckeditortoolbar = 'dolibarr_mailings'; - } - - // Editor wysiwyg - require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php'; - if ($this->withfckeditor == -1) { - if (getDolGlobalString('FCKEDITOR_ENABLE_MAIL')) { - $this->withfckeditor = 1; - } else { - $this->withfckeditor = 0; - } - } - - $doleditor = new DolEditor('message', $defaultmessage, '', 280, $this->ckeditortoolbar, 'In', true, true, $this->withfckeditor, 8, '95%'); - $out .= $doleditor->Create(1); - } - $out .= "
' . "\n"; - - if ($this->withform == 1 || $this->withform == -1) { - $out .= '
'; - $out .= 'withfile == 2 && $conf->use_javascript_ajax) { - $out .= ' onClick="if (document.mailform.addedfile.value != \'\') { alert(\'' . dol_escape_js($langs->trans("FileWasNotUploaded")) . '\'); return false; } else { return true; }"'; - } - $out .= ' />'; - if ($this->withcancel) { - $out .= ''; - } - $out .= '
' . "\n"; + if (count($validpaymentmethod) > 0 && $paymenturl) { + $langs->load('other'); + $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = str_replace('\n', "\n", $langs->transnoentities("PredefinedMailContentLink", $paymenturl)); + $this->substit['__ONLINE_PAYMENT_URL__'] = $paymenturl; + } elseif (count($validpaymentmethod) > 0) { + $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = '__ONLINE_PAYMENT_TEXT_AND_URL__'; + $this->substit['__ONLINE_PAYMENT_URL__'] = '__ONLINE_PAYMENT_URL__'; + } else { + $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = ''; + $this->substit['__ONLINE_PAYMENT_URL__'] = ''; } - if ($this->withform == 1) { - $out .= '' . "\n"; + $this->substit['__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__'] = ''; + + // Generate the string with the template for lines repeated and filled for each line + $lines = ''; + $defaultlines = $arraydefaultmessage->content_lines; + if (isset($defaultlines)) { + foreach ($this->substit_lines as $lineid => $substit_line) { + $lines .= make_substitutions($defaultlines, $substit_line)."\n"; + } + } + $this->substit['__LINES__'] = $lines; + + $defaultmessage = str_replace('\n', "\n", $defaultmessage); + + // Deal with format differences between message and some substitution variables (text / HTML) + $atleastonecomponentishtml = 0; + if (strpos($defaultmessage, '__USER_SIGNATURE__') !== false && dol_textishtml($this->substit['__USER_SIGNATURE__'])) { + $atleastonecomponentishtml++; + } + if (strpos($defaultmessage, '__SENDEREMAIL_SIGNATURE__') !== false && dol_textishtml($this->substit['__SENDEREMAIL_SIGNATURE__'])) { + $atleastonecomponentishtml++; + } + if (strpos($defaultmessage, '__ONLINE_PAYMENT_TEXT_AND_URL__') !== false && dol_textishtml($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'])) { + $atleastonecomponentishtml++; + } + if (strpos($defaultmessage, '__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__') !== false && dol_textishtml($this->substit['__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__'])) { + $atleastonecomponentishtml++; + } + if (dol_textishtml($defaultmessage)) { + $atleastonecomponentishtml++; + } + if ($atleastonecomponentishtml) { + if (!dol_textishtml($this->substit['__USER_SIGNATURE__'])) { + $this->substit['__USER_SIGNATURE__'] = dol_nl2br($this->substit['__USER_SIGNATURE__']); + } + if (!dol_textishtml($this->substit['__SENDEREMAIL_SIGNATURE__'])) { + $this->substit['__SENDEREMAIL_SIGNATURE__'] = dol_nl2br($this->substit['__SENDEREMAIL_SIGNATURE__']); + } + if (!dol_textishtml($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'])) { + $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = dol_nl2br($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__']); + } + if (!dol_textishtml($defaultmessage)) { + $defaultmessage = dol_nl2br($defaultmessage); + } } - // Disable enter key if option MAIN_MAILFORM_DISABLE_ENTERKEY is set - if (getDolGlobalString('MAIN_MAILFORM_DISABLE_ENTERKEY')) { - $out .= ''; - } - - $out .= "\n"; - - return $out; + $out .= ' })'; + $out .= ''; } + + $out .= "\n"; + + return $out; } } + /** * get html For To * @@ -1694,7 +1693,7 @@ class FormMail extends Form // Use the multiselect array function to create the dropdown $out .= ''; $out .= ''."\n"; - // Add headers + + // Add HTML headers (must be before the Add of the common CSS and js). The common js may content javascript using jquery or a framework loaded by the HTML header. $tplcontent .= ''."\n"; $tplcontent .= ''."\n"; $tplcontent .= ''."\n"; $tplcontent .= preg_replace('/<\/?html>/ims', '', $objectpage->htmlheader)."\n"; + + // Add css + $tplcontent .= ''."\n"; + $tplcontent .= ''."\n"; + + // Add js + $tplcontent .= ''."\n"; + $tplcontent .= ''."\n"; $tplcontent .= ''."\n"; + // Page content $tplcontent .= ''."\n"; $tplcontent .= ''."\n"; $tplcontent .= $objectpage->content."\n"; From 579b0918df72c33a1b01c757166ac8b03258e57b Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Tue, 28 Jan 2025 20:08:04 +0100 Subject: [PATCH 135/383] Doc --- htdocs/core/lib/website2.lib.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/lib/website2.lib.php b/htdocs/core/lib/website2.lib.php index 0a6885fba3d..0f11bd01a63 100644 --- a/htdocs/core/lib/website2.lib.php +++ b/htdocs/core/lib/website2.lib.php @@ -306,11 +306,11 @@ function dolSavePageContent($filetpl, Website $object, WebsitePage $objectpage, $tplcontent .= preg_replace('/<\/?html>/ims', '', $objectpage->htmlheader)."\n"; // Add css - $tplcontent .= ''."\n"; + $tplcontent .= ''."\n"; $tplcontent .= ''."\n"; // Add js - $tplcontent .= ''."\n"; + $tplcontent .= ''."\n"; $tplcontent .= ''."\n"; $tplcontent .= ''."\n"; From 4a08b6cfcbdda5a31995ffc5f1a1d5b0a651c8a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20France?= Date: Tue, 28 Jan 2025 20:32:57 +0100 Subject: [PATCH 136/383] fix phpstan --- htdocs/fourn/class/fournisseur.commande.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 690866f52c3..3186e8d9e74 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -2128,7 +2128,7 @@ class CommandeFournisseur extends CommonOrder $prod->get_buyprice($fk_prod_fourn_price, $qty, $fk_product, 'none', (empty($this->fk_soc) ? $this->socid : $this->fk_soc)); if ($qty < $prod->packaging) { - $qty = $prod->packaging; + $qty = (float) $prod->packaging; } else { if (!empty($prod->packaging) && (fmod((float) $qty, (float) $prod->packaging) > 0.000001)) { $coeff = intval((float) $qty / $prod->packaging) + 1; From 612c26c2e023a7c15d3a953677326a3d9e5e9ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20France?= Date: Tue, 28 Jan 2025 20:35:25 +0100 Subject: [PATCH 137/383] fix phpstan --- htdocs/fourn/class/fournisseur.commande.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 3186e8d9e74..7b1500750d1 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -2211,8 +2211,9 @@ class CommandeFournisseur extends CommonOrder $this->line->total_localtax2 = (float) $total_localtax2; $this->line->total_ttc = (float) $total_ttc; $this->line->product_type = $type; - $this->line->special_code = (!empty($special_code) ? $special_code : 0); + $this->line->special_code = (!empty($special_code) ? $special_code : 0); $this->line->origin = $origin; + $this->line->origin_type = $origin; $this->line->origin_id = $origin_id; $this->line->fk_unit = $fk_unit; From 00249c9a90b6206cf7359507fd4163e674ac9cb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20France?= Date: Tue, 28 Jan 2025 20:46:05 +0100 Subject: [PATCH 138/383] fix phpstan --- .../class/fournisseur.commande.class.php | 55 ++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 7b1500750d1..700be6e45fc 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -553,16 +553,16 @@ class CommandeFournisseur extends CommonOrder $this->user_validation_id = $obj->user_validation_id; $this->user_approve_id = $obj->user_approve_id; $this->user_approve_id2 = $obj->user_approve_id2; - $this->total_ht = $obj->total_ht; - $this->total_tva = $obj->total_tva; - $this->total_localtax1 = $obj->localtax1; - $this->total_localtax2 = $obj->localtax2; - $this->total_ttc = $obj->total_ttc; + $this->total_ht = $obj->total_ht; + $this->total_tva = $obj->total_tva; + $this->total_localtax1 = $obj->localtax1; + $this->total_localtax2 = $obj->localtax2; + $this->total_ttc = $obj->total_ttc; $this->date_creation = $this->db->jdate($obj->date_creation); $this->date_valid = $this->db->jdate($obj->date_valid); - $this->date_approve = $this->db->jdate($obj->date_approve); - $this->date_approve2 = $this->db->jdate($obj->date_approve2); - $this->date_commande = $this->db->jdate($obj->date_commande); // date we make the order to supplier + $this->date_approve = $this->db->jdate($obj->date_approve); + $this->date_approve2 = $this->db->jdate($obj->date_approve2); + $this->date_commande = $this->db->jdate($obj->date_commande); // date we make the order to supplier if (isset($obj->date_commande)) { $this->date = $this->date_commande; } else { @@ -1372,9 +1372,11 @@ class CommandeFournisseur extends CommonOrder $this->ref = $this->newref; if ($movetoapprovestatus) { - $this->statut = self::STATUS_ACCEPTED; + $this->statut = self::STATUS_ACCEPTED; // deprecated + $this->status = self::STATUS_ACCEPTED; } else { - $this->statut = self::STATUS_VALIDATED; + $this->statut = self::STATUS_VALIDATED; // deprecated + $this->status = self::STATUS_VALIDATED; } if (empty($secondlevel)) { // standard or first level approval $this->date_approve = $now; @@ -1531,7 +1533,8 @@ class CommandeFournisseur extends CommonOrder dol_syslog(get_class($this)."::commande", LOG_DEBUG); if ($this->db->query($sql)) { - $this->statut = self::STATUS_ORDERSENT; + $this->statut = self::STATUS_ORDERSENT; // deprecated + $this->status = self::STATUS_ORDERSENT; $this->methode_commande_id = $methode; $this->date_commande = $date; $this->context = array('comments' => $comment); @@ -1827,7 +1830,7 @@ class CommandeFournisseur extends CommonOrder $sql .= " localtax2=".(isset($this->total_localtax2) ? $this->total_localtax2 : "null").","; $sql .= " total_ht=".(isset($this->total_ht) ? $this->total_ht : "null").","; $sql .= " total_ttc=".(isset($this->total_ttc) ? $this->total_ttc : "null").","; - $sql .= " fk_statut=".(isset($this->statut) ? $this->statut : "null").","; + $sql .= " fk_statut=".(isset($this->status) ? $this->status : "null").","; $sql .= " fk_user_author=".(isset($this->user_author_id) ? $this->user_author_id : "null").","; $sql .= " fk_user_valid=".(isset($this->user_validation_id) && $this->user_validation_id > 0 ? $this->user_validation_id : "null").","; $sql .= " fk_projet=".(isset($this->fk_project) ? $this->fk_project : "null").","; @@ -1923,7 +1926,8 @@ class CommandeFournisseur extends CommonOrder } $this->id = 0; - $this->statut = self::STATUS_DRAFT; + $this->statut = self::STATUS_DRAFT; // deprecated + $this->status = self::STATUS_DRAFT; // Clear fields $this->user_author_id = $user->id; @@ -2259,8 +2263,7 @@ class CommandeFournisseur extends CommonOrder return -1; } } else { - $this->error = $this->line->error; - $this->errors = $this->line->errors; + $this->setErrorsFromObject($this->line); dol_syslog(get_class($this)."::addline error=".$this->error, LOG_ERR); $this->db->rollback(); return -1; @@ -2313,7 +2316,7 @@ class CommandeFournisseur extends CommonOrder $inventorycode = dol_print_date(dol_now(), 'dayhourlog'); - if (($this->statut == self::STATUS_ORDERSENT || $this->statut == self::STATUS_RECEIVED_PARTIALLY || $this->statut == self::STATUS_RECEIVED_COMPLETELY)) { + if (($this->status == self::STATUS_ORDERSENT || $this->status == self::STATUS_RECEIVED_PARTIALLY || $this->status == self::STATUS_RECEIVED_COMPLETELY)) { $this->db->begin(); $sql = "INSERT INTO ".$this->db->prefix()."receptiondet_batch"; @@ -2387,7 +2390,7 @@ class CommandeFournisseur extends CommonOrder { global $user; - if ($this->statut == 0) { + if ($this->status == 0) { $line = new CommandeFournisseurLigne($this->db); if ($line->fetch($idline) <= 0) { @@ -2680,8 +2683,8 @@ class CommandeFournisseur extends CommonOrder $resql = $this->db->query($sql); if ($resql) { $result = 1; - $old_statut = $this->statut; - $this->statut = $statut; + $old_statut = $this->status; + $this->status = $statut; $this->context['actionmsg2'] = $comment; // Call trigger @@ -2694,7 +2697,7 @@ class CommandeFournisseur extends CommonOrder if (empty($error)) { $this->db->commit(); } else { - $this->statut = $old_statut; + $this->status = $old_statut; $this->db->rollback(); $this->error = $this->db->lasterror(); $result = -1; @@ -2932,7 +2935,7 @@ class CommandeFournisseur extends CommonOrder } if (!$error) { - $this->statut = $status; + $this->status = $status; $this->db->commit(); return 1; } else { @@ -2972,7 +2975,7 @@ class CommandeFournisseur extends CommonOrder $error = 0; - if ($this->statut == self::STATUS_DRAFT) { + if ($this->status == self::STATUS_DRAFT) { // Clean parameters if (empty($qty)) { $qty = 0; @@ -3193,7 +3196,7 @@ class CommandeFournisseur extends CommonOrder $this->multicurrency_tx = 1; $this->multicurrency_code = $conf->currency; - $this->statut = 0; + $this->statut = 0; // deprecated $this->status = 0; // Lines @@ -3536,7 +3539,7 @@ class CommandeFournisseur extends CommonOrder { global $conf; - if ($this->statut == self::STATUS_ORDERSENT || $this->statut == self::STATUS_RECEIVED_PARTIALLY) { + if ($this->status == self::STATUS_ORDERSENT || $this->status == self::STATUS_RECEIVED_PARTIALLY) { $now = dol_now(); if (!empty($this->delivery_date)) { $date_to_test = $this->delivery_date; @@ -3550,7 +3553,7 @@ class CommandeFournisseur extends CommonOrder $now = dol_now(); $date_to_test = $this->date_commande; - return ($this->statut > 0 && $this->statut < 5) && $date_to_test && $date_to_test < ($now - $conf->commande->fournisseur->warning_delay); + return ($this->status > 0 && $this->status < 5) && $date_to_test && $date_to_test < ($now - $conf->commande->fournisseur->warning_delay); } } @@ -3569,7 +3572,7 @@ class CommandeFournisseur extends CommonOrder $text = ''; - if ($this->statut == self::STATUS_ORDERSENT || $this->statut == self::STATUS_RECEIVED_PARTIALLY) { + if ($this->status == self::STATUS_ORDERSENT || $this->status == self::STATUS_RECEIVED_PARTIALLY) { if (!empty($this->delivery_date)) { $text = $langs->trans("DeliveryDate").' '.dol_print_date($this->delivery_date, 'day'); } else { From bb261ce017b220eb3f30fa17872083dc8929f2a3 Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Tue, 28 Jan 2025 21:12:55 +0100 Subject: [PATCH 139/383] Fix cache delay param --- htdocs/website/samples/wrapper.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/htdocs/website/samples/wrapper.php b/htdocs/website/samples/wrapper.php index eadc7c68a53..51c6c2500bb 100644 --- a/htdocs/website/samples/wrapper.php +++ b/htdocs/website/samples/wrapper.php @@ -129,10 +129,11 @@ if (GETPOSTISSET('type')) { $original_file = str_replace("../", "/", $original_file); // Cache or not -if (GETPOST("cache", 'aZ09') || image_format_supported($original_file) >= 0) { +$cachestring = GETPOST("cache", 'aZ09'); // May be 1, or an int, or a hash +if ($cachestring || image_format_supported($original_file) >= 0) { // Important: Following code is to avoid page request by browser and PHP CPU at // each Dolibarr page access. - header('Cache-Control: max-age=3600, public, must-revalidate'); + header('Cache-Control: max-age='.((is_numeric($cachestring) && (int) $cachestring > 1 && (int) $cachestring < 999999) ? $cachestring : '3600').', public, must-revalidate'); header('Pragma: cache'); // This is to avoid having Pragma: no-cache } From 64f1d966f13f77c920619518cbba7b14897219b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20France?= Date: Tue, 28 Jan 2025 21:33:32 +0100 Subject: [PATCH 140/383] fix phpstan --- htdocs/fourn/class/fournisseur.class.php | 9 +++++---- htdocs/fourn/class/fournisseur.commande.class.php | 7 ++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/htdocs/fourn/class/fournisseur.class.php b/htdocs/fourn/class/fournisseur.class.php index 2529bce86ec..20eb2ef661b 100644 --- a/htdocs/fourn/class/fournisseur.class.php +++ b/htdocs/fourn/class/fournisseur.class.php @@ -1,9 +1,10 @@ - * Copyright (C) 2006 Laurent Destailleur - * Copyright (C) 2005-2009 Regis Houssin - * Copyright (C) 2011 Juanjo Menent +/* Copyright (C) 2004-2007 Rodolphe Quiedeville + * Copyright (C) 2006 Laurent Destailleur + * Copyright (C) 2005-2009 Regis Houssin + * Copyright (C) 2011 Juanjo Menent * Copyright (C) 2024 MDW + * 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 diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 700be6e45fc..9ad00e00bc2 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -14,8 +14,8 @@ * Copyright (C) 2021 Josep Lluís Amador * Copyright (C) 2022 Gauthier VERDOL * Copyright (C) 2024 Solution Libre SAS - * Copyright (C) 2024 MDW - * Copyright (C) 2024 William Mead + * Copyright (C) 2024 MDW + * Copyright (C) 2024 William Mead * * 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 @@ -3358,7 +3358,8 @@ class CommandeFournisseur extends CommonOrder while ($obj = $this->db->fetch_object($resql)) { $commandestatic->delivery_date = $this->db->jdate($obj->delivery_date); $commandestatic->date_commande = $this->db->jdate($obj->date_commande); - $commandestatic->statut = $obj->fk_statut; + $commandestatic->statut = $obj->fk_statut; // deprecated + $commandestatic->status = $obj->fk_statut; $response->nbtodo++; $response->total += $obj->total_ht; From 656a63acdc7d51673b5f9af52cf4d6e8688fb77f Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Tue, 28 Jan 2025 22:07:11 +0100 Subject: [PATCH 141/383] Debug v21 --- htdocs/core/class/html.form.class.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 71031684d57..34623d573df 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -933,9 +933,10 @@ class Form * @param int<0,1> $addspecialentries 1=Add dedicated entries for group of countries (like 'European Economic Community', ...) * @param string[] $exclude_country_code Array of country code (iso2) to exclude * @param int<0,1> $hideflags Hide flags + * @param int<0,1> $forcecombo Force to load all values and output a standard combobox (with no beautification) * @return string HTML string with select */ - public function select_country($selected = '', $htmlname = 'country_id', $htmloption = '', $maxlength = 0, $morecss = 'minwidth300', $usecodeaskey = '', $showempty = 1, $disablefavorites = 0, $addspecialentries = 0, $exclude_country_code = array(), $hideflags = 0) + public function select_country($selected = '', $htmlname = 'country_id', $htmloption = '', $maxlength = 0, $morecss = 'minwidth300', $usecodeaskey = '', $showempty = 1, $disablefavorites = 0, $addspecialentries = 0, $exclude_country_code = array(), $hideflags = 0, $forcecombo = 0) { // phpcs:enable global $conf, $langs, $mysoc; @@ -1047,8 +1048,10 @@ class Form } // Make select dynamic - include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php'; - $out .= ajax_combobox('select' . $htmlname, array(), 0, 0, 'resolve'); + if (empty($forcecombo)) { + include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php'; + $out .= ajax_combobox('select' . $htmlname, array(), 0, 0, 'resolve'); + } return $out; } @@ -1076,7 +1079,7 @@ class Form $langs->load("dict"); $out = ''; - $moreattrib = ''; + //$moreattrib = ''; $incotermArray = array(); $sql = "SELECT rowid, code"; @@ -1129,7 +1132,7 @@ class Form if ($conf->use_javascript_ajax && empty($disableautocomplete)) { $out .= ajax_multiautocompleter('location_incoterms', array(), DOL_URL_ROOT . '/core/ajax/locationincoterms.php') . "\n"; - $moreattrib .= ' autocomplete="off"'; + //$moreattrib .= ' autocomplete="off"'; } $out .= '' . "\n"; From 995e0792e5872d075059b2aa3f5979512878ba42 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 29 Jan 2025 00:44:39 +0100 Subject: [PATCH 142/383] Fix escaping var --- htdocs/product/class/product.class.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 0a9b0206f54..0f368838f0f 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -1311,12 +1311,12 @@ class Product extends CommonObject $sql .= ", accountancy_code_sell_export= '" . $this->db->escape($this->accountancy_code_sell_export) . "'"; } $sql .= ", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (float) $this->desiredstock : "null"); - $sql .= ", cost_price = ".($this->cost_price != '' ? $this->db->escape($this->cost_price) : 'null'); + $sql .= ", cost_price = ".($this->cost_price != '' ? ((float) $this->cost_price) : 'null'); $sql .= ", fk_unit= ".(!$this->fk_unit ? 'NULL' : (int) $this->fk_unit); $sql .= ", price_autogen = ".(!$this->price_autogen ? 0 : 1); $sql .= ", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression : 'NULL'); - $sql .= ", fk_user_modif = ".($user->id > 0 ? $user->id : 'NULL'); - $sql .= ", mandatory_period = ".($this->mandatory_period); + $sql .= ", fk_user_modif = ".($user->id > 0 ? (int) $user->id : 'NULL'); + $sql .= ", mandatory_period = ".((int) $this->mandatory_period); // stock field is not here because it is a denormalized value from product_stock. $sql .= " WHERE rowid = ".((int) $id); From 1c7a3a0e73d0379a3d09f21c42beb57cc073b2ad Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 29 Jan 2025 01:38:11 +0100 Subject: [PATCH 143/383] More complete fix for #32839 --- htdocs/core/lib/functions.lib.php | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 27c1b697b5e..0a8cab279a9 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -1,5 +1,4 @@ * Copyright (C) 2003 Jean-Louis Bergamo * Copyright (C) 2004-2024 Laurent Destailleur @@ -2172,7 +2171,7 @@ function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapeta $tmp = str_ireplace('__DONOTDECODEAPOS', '&apos', $tmp); $tmp = str_ireplace('__DONOTDECODE39', ''', $tmp); - $tmp = str_ireplace(''', '__SIMPLEQUOTE', $tmp); // HTML 4 + $tmp = str_ireplace(''', '__SIMPLEQUOTE__', $tmp); // HTML 4 } if (!$keepb) { $tmp = strtr($tmp, array("" => '', '' => '', '' => '', '' => '')); @@ -2213,7 +2212,7 @@ function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapeta if (preg_match('/<'.preg_quote($tagtoreplace, '/').'(\s+)([^>]+)>/', $tmp, $reg)) { // We want to protect the attribute part ... in '' to avoid transformation by htmlentities() later $tmpattributes = str_ireplace(array('[', ']'), '_', $reg[2]); // We must never have [ ] inside the attribute string - $tmpattributes = str_ireplace('"', '__DOUBLEQUOTE', $tmpattributes); + $tmpattributes = str_ireplace('"', '__DOUBLEQUOTE__', $tmpattributes); $tmpattributes = preg_replace('/[^a-z0-9_%,\/\?\;\s=&\.\-@:\.#\+]/i', '', $tmpattributes); //$tmpattributes = preg_replace("/float:\s*(left|right)/", "", $tmpattributes); // Disabled: we must not remove content $tmp = str_replace('<'.$tagtoreplace.$reg[1].$reg[2].'>', '__BEGINTAGTOREPLACE'.$tagtoreplace.'['.$tmpattributes.']__', $tmp); @@ -2223,9 +2222,9 @@ function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapeta } while ($diff); } - $tmp = str_ireplace('"', '__DOUBLEQUOTE', $tmp); - $tmp = str_ireplace('<', '__LESSTAN', $tmp); - $tmp = str_ireplace('>', '__GREATERTHAN', $tmp); + $tmp = str_ireplace('"', '__DOUBLEQUOTENOSEMICOLON__', $tmp); + $tmp = str_ireplace('<', '__LESSTHAN__', $tmp); + $tmp = str_ireplace('>', '__GREATERTHAN__', $tmp); } // Warning: htmlentities encode HTML tags like & into & and more (but not < > "es; ' ' & that remains untouched). @@ -2243,12 +2242,14 @@ function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapeta $result = preg_replace('/__BEGINENDTAGTOREPLACE'.$tagtoreplace.'\[([^\]]*)\]__/', '<'.$tagtoreplace.' \1 />', $result); } - $result = str_ireplace('__DOUBLEQUOTE', '"', $result); - $result = str_ireplace('__LESSTAN', '<', $result); - $result = str_ireplace('__GREATERTHAN', '>', $result); + $result = str_ireplace('__DOUBLEQUOTE__', '"', $result); + + $result = str_ireplace('__DOUBLEQUOTENOSEMICOLON__', '"', $result); + $result = str_ireplace('__LESSTHAN__', '<', $result); + $result = str_ireplace('__GREATERTHAN__', '>', $result); } - $result = str_ireplace('__SIMPLEQUOTE', ''', $result); + $result = str_ireplace('__SIMPLEQUOTE__', ''', $result); //$result="\n\n\n".var_export($tmp, true)."\n\n\n".var_export($result, true); From 09a282bc38bdd95282fe56871813153430234e6a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 29 Jan 2025 01:38:11 +0100 Subject: [PATCH 144/383] More complete fix for #32839 --- htdocs/core/lib/functions.lib.php | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 41387eacc26..7ad4d1888ce 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -2169,7 +2169,7 @@ function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapeta $tmp = str_ireplace('__DONOTDECODEAPOS', '&apos', $tmp); $tmp = str_ireplace('__DONOTDECODE39', ''', $tmp); - $tmp = str_ireplace(''', '__SIMPLEQUOTE', $tmp); // HTML 4 + $tmp = str_ireplace(''', '__SIMPLEQUOTE__', $tmp); // HTML 4 } if (!$keepb) { $tmp = strtr($tmp, array("" => '', '' => '', '' => '', '' => '')); @@ -2210,7 +2210,7 @@ function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapeta if (preg_match('/<'.preg_quote($tagtoreplace, '/').'(\s+)([^>]+)>/', $tmp, $reg)) { // We want to protect the attribute part ... in '' to avoid transformation by htmlentities() later $tmpattributes = str_ireplace(array('[', ']'), '_', $reg[2]); // We must never have [ ] inside the attribute string - $tmpattributes = str_ireplace('"', '__DOUBLEQUOTE', $tmpattributes); + $tmpattributes = str_ireplace('"', '__DOUBLEQUOTE__', $tmpattributes); $tmpattributes = preg_replace('/[^a-z0-9_%,\/\?\;\s=&\.\-@:\.#\+]/i', '', $tmpattributes); //$tmpattributes = preg_replace("/float:\s*(left|right)/", "", $tmpattributes); // Disabled: we must not remove content $tmp = str_replace('<'.$tagtoreplace.$reg[1].$reg[2].'>', '__BEGINTAGTOREPLACE'.$tagtoreplace.'['.$tmpattributes.']__', $tmp); @@ -2220,9 +2220,9 @@ function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapeta } while ($diff); } - $tmp = str_ireplace('"', '__DOUBLEQUOTE', $tmp); - $tmp = str_ireplace('<', '__LESSTAN', $tmp); - $tmp = str_ireplace('>', '__GREATERTHAN', $tmp); + $tmp = str_ireplace('"', '__DOUBLEQUOTENOSEMICOLON__', $tmp); + $tmp = str_ireplace('<', '__LESSTHAN__', $tmp); + $tmp = str_ireplace('>', '__GREATERTHAN__', $tmp); } // Warning: htmlentities encode HTML tags like & into & and more (but not < > "es; ' ' & that remains untouched). @@ -2240,12 +2240,14 @@ function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapeta $result = preg_replace('/__BEGINENDTAGTOREPLACE'.$tagtoreplace.'\[([^\]]*)\]__/', '<'.$tagtoreplace.' \1 />', $result); } - $result = str_ireplace('__DOUBLEQUOTE', '"', $result); - $result = str_ireplace('__LESSTAN', '<', $result); - $result = str_ireplace('__GREATERTHAN', '>', $result); + $result = str_ireplace('__DOUBLEQUOTE__', '"', $result); + + $result = str_ireplace('__DOUBLEQUOTENOSEMICOLON__', '"', $result); + $result = str_ireplace('__LESSTHAN__', '<', $result); + $result = str_ireplace('__GREATERTHAN__', '>', $result); } - $result = str_ireplace('__SIMPLEQUOTE', ''', $result); + $result = str_ireplace('__SIMPLEQUOTE__', ''', $result); //$result="\n\n\n".var_export($tmp, true)."\n\n\n".var_export($result, true); From e5c385999d73490e1b0ab68477444178b2984f88 Mon Sep 17 00:00:00 2001 From: MDW Date: Sun, 19 Jan 2025 02:30:36 +0100 Subject: [PATCH 145/383] Qual: Fix multiple phan notices # Qual: Fix multiple phan notices Fix multiple phan notices --- htdocs/comm/propal/class/propal.class.php | 14 +++---- htdocs/commande/class/commande.class.php | 38 +++++++++--------- htdocs/compta/facture/class/facture.class.php | 7 ++-- htdocs/core/class/html.form.class.php | 38 +++++++++--------- htdocs/ecm/dir_card.php | 4 +- htdocs/ecm/index.php | 14 ++++--- .../conferenceorbooth_card.php | 10 ++--- .../conferenceorbooth_list.php | 7 ++-- .../conferenceorboothattendee_card.php | 18 +++++---- .../conferenceorboothattendee_list.php | 37 ++++++++--------- htdocs/expedition/card.php | 40 +++++++++---------- htdocs/expedition/class/expedition.class.php | 12 +++--- htdocs/expedition/contact.php | 6 ++- htdocs/expedition/dispatch.php | 18 +++++---- htdocs/expedition/document.php | 4 +- htdocs/expedition/list.php | 19 ++++----- htdocs/expedition/note.php | 4 +- htdocs/expedition/shipment.php | 33 +++++++-------- htdocs/expensereport/card.php | 35 ++++++++-------- 19 files changed, 187 insertions(+), 171 deletions(-) diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index eb81c4c084e..ecd6898734c 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -19,7 +19,7 @@ * Copyright (C) 2022 OpenDSI * Copyright (C) 2022 Gauthier VERDOL * Copyright (C) 2023 William Mead - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 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 @@ -146,23 +146,23 @@ class Propal extends CommonObject /** * @var int|'' - * @deprecated + * @deprecated Use $date_validation * @see $date_validation */ public $datev; /** - * @var integer|'' $date_validation; + * @var int|'' */ public $date_validation; /** - * @var integer|'' $date_signature; + * @var int|'' */ public $date_signature; /** - * @var User $user_signature + * @var User */ public $user_signature; @@ -715,7 +715,7 @@ class Propal extends CommonObject if ($qty < $product->packaging) { $qty = $product->packaging; } else { - if (!empty($product->packaging) && (fmod((float) $qty, $product->packaging) > 0.000001)) { + if (!empty($product->packaging) && (fmod((float) $qty, (float) $product->packaging) > 0.000001)) { $coeff = intval((float) $qty / $product->packaging) + 1; $qty = (float) $product->packaging * $coeff; setEventMessages($langs->trans('QtyRecalculatedWithPackaging'), null, 'mesgs'); @@ -772,7 +772,7 @@ class Propal extends CommonObject $this->line->fk_propal = $this->id; $this->line->label = $label; $this->line->desc = $desc; - $this->line->qty = $qty; + $this->line->qty = (float) $qty; $this->line->vat_src_code = $vat_src_code; $this->line->tva_tx = $txtva; diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index 71e03085f69..6c747d2602b 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -13,7 +13,7 @@ * Copyright (C) 2016-2022 Ferran Marcet * Copyright (C) 2021-2025 Frédéric France * Copyright (C) 2022 Gauthier VERDOL - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) 2024 William Mead * * This program is free software; you can redistribute it and/or modify @@ -1637,10 +1637,10 @@ class Commande extends CommonOrder if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { $product = new Product($this->db); $result = $product->fetch($fk_product); - if ($qty < $product->packaging) { + if ($qty < (float) $product->packaging) { $qty = $product->packaging; } else { - if (!empty($product->packaging) && (fmod((float) $qty, $product->packaging) > 0.000001)) { + if (!empty($product->packaging) && (fmod((float) $qty, (float) $product->packaging) > 0.000001)) { $coeff = intval((float) $qty / $product->packaging) + 1; $qty = (float) $product->packaging * $coeff; setEventMessages($langs->trans('QtyRecalculatedWithPackaging'), null, 'mesgs'); @@ -1703,7 +1703,7 @@ class Commande extends CommonOrder $this->line->fk_commande = $this->id; $this->line->label = $label; $this->line->desc = $desc; - $this->line->qty = $qty; + $this->line->qty = (float) $qty; $this->line->ref_ext = $ref_ext; $this->line->vat_src_code = $vat_src_code; @@ -1863,21 +1863,21 @@ class Commande extends CommonOrder $this->lines[] = $line; /** POUR AJOUTER AUTOMATIQUEMENT LES SOUSPRODUITS a LA COMMANDE - if (getDolGlobalString('PRODUIT_SOUSPRODUITS')) { - $prod = new Product($this->db); - $prod->fetch($idproduct); - $prod -> get_sousproduits_arbo(); - $prods_arbo = $prod->get_arbo_each_prod(); - if(count($prods_arbo) > 0) - { - foreach($prods_arbo as $key => $value) - { - // print "id : ".$value[1].' :qty: '.$value[0].'
'; - if not in lines { - $this->add_product($value[1], $value[0]); - } - } - } + * if (getDolGlobalString('PRODUIT_SOUSPRODUITS')) { + * $prod = new Product($this->db); + * $prod->fetch($idproduct); + * $prod -> get_sousproduits_arbo(); + * $prods_arbo = $prod->get_arbo_each_prod(); + * if(count($prods_arbo) > 0) + * { + * foreach($prods_arbo as $key => $value) + * { + * // print "id : ".$value[1].' :qty: '.$value[0].'
'; + * if not in lines { + * $this->add_product($value[1], $value[0]); + * } + * } + * } **/ } } diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 09dddafbbd5..88430241586 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -20,7 +20,7 @@ * Copyright (C) 2022 Sylvain Legrand * Copyright (C) 2023 Gauthier VERDOL * Copyright (C) 2023 Nick Fragoulis - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) 2024-2025 Frédéric France * * This program is free software; you can redistribute it and/or modify @@ -174,7 +174,6 @@ class Facture extends CommonInvoice public $resteapayer; /** - * * @var int<0,1> 1 if invoice paid COMPLETELY, 0 otherwise * @deprecated * Use statut and close_code) */ @@ -4002,10 +4001,10 @@ class Facture extends CommonInvoice if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { $product = new Product($this->db); $result = $product->fetch($fk_product); - if ($qty < $product->packaging) { + if ($qty < (float) $product->packaging) { $qty = $product->packaging; } else { - if (!empty($product->packaging) && (fmod((float) $qty, $product->packaging) > 0.000001)) { + if (!empty($product->packaging) && (fmod((float) $qty, (float) $product->packaging) > 0.000001)) { $coeff = intval((float) $qty / $product->packaging) + 1; $qty = (float) $product->packaging * $coeff; setEventMessages($langs->trans('QtyRecalculatedWithPackaging'), null, 'mesgs'); diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index e374296cf13..143cc1a07d9 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -107,9 +107,9 @@ class Form * @param object $object Object (on the page we show) * @param int<0,1> $perm Permission to allow button to edit parameter. Set it to 0 to have a not edited field. * @param string $typeofdata Type of data ('string' by default, 'email', 'amount:99', 'numeric:99', 'text' or 'textarea:rows:cols', 'datepicker' ('day' do not work, don't know why), 'dayhour' or 'datehourpicker' 'checkbox:ckeditor:dolibarr_zzz:width:height:savemethod:1:rows:cols', 'select;xxx[:class]'...) - * @param string $moreparam More param to add on a href URL. - * @param int $fieldrequired 1 if we want to show field as mandatory using the "fieldrequired" CSS. - * @param int<0,3> $notabletag 1=Do not output table tags but output a ':', 2=Do not output table tags and no ':', 3=Do not output table tags but output a ' ' + * @param string $moreparam More param to add on a href URL. + * @param int<0,1> $fieldrequired 1 if we want to show field as mandatory using the "fieldrequired" CSS. + * @param int<0,3> $notabletag 1=Do not output table tags but output a ':', 2=Do not output table tags and no ':', 3=Do not output table tags but output a ' ' * @param string $paramid Key of parameter for id ('id', 'socid') * @param string $help Tooltip help * @return string HTML edit field @@ -624,19 +624,19 @@ class Form * Show a text and picto with tooltip on text or picto. * Can be called by an instancied $form->textwithtooltip or by a static call Form::textwithtooltip * - * @param string $text Text to show - * @param string $htmltext HTML content of tooltip. Must be HTML/UTF8 encoded. - * @param int $tooltipon 1=tooltip on text, 2=tooltip on image, 3=tooltip on both - * @param int $direction -1=image is before, 0=no image, 1=image is after - * @param string $img Html code for image (use img_xxx() function to get it) - * @param string $extracss Add a CSS style to td tags - * @param int $notabs 0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span - * @param string $incbefore Include code before the text - * @param int $noencodehtmltext Do not encode into html entity the htmltext - * @param string $tooltiptrigger ''=Tooltip on hover, 'abc'=Tooltip on click (abc is a unique key) - * @param int $forcenowrap Force no wrap between text and picto (works with notabs=2 only) - * @return string Code html du tooltip (texte+picto) - * @see textwithpicto() Use textwithpicto() instead of textwithtooltip if you can. + * @param string $text Text to show + * @param string $htmltext HTML content of tooltip. Must be HTML/UTF8 encoded. + * @param int<0,3> $tooltipon 1=tooltip on text, 2=tooltip on image, 3=tooltip on both + * @param int<-1,1> $direction -1=image is before, 0=no image, 1=image is after + * @param string $img Html code for image (use img_xxx() function to get it) + * @param string $extracss Add a CSS style to td tags + * @param int<0,3> $notabs 0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span + * @param string $incbefore Include code before the text + * @param int<0,1> $noencodehtmltext Do not encode into html entity the htmltext + * @param string $tooltiptrigger ''=Tooltip on hover, 'abc'=Tooltip on click (abc is a unique key) + * @param int<0,1> $forcenowrap Force no wrap between text and picto (works with notabs=2 only) + * @return string Code html du tooltip (texte+picto) + * @see textwithpicto() Use textwithpicto() instead of textwithtooltip if you can. */ public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0) { @@ -5645,9 +5645,9 @@ class Form * @param string $title Title * @param string $question Question * @param string $action Action - * @param array}>|string|null $formquestion An array with complementary inputs to add into forms: array(array('label'=> ,'type'=> , 'size'=>, 'morecss'=>, 'moreattr'=>'autofocus' or 'style=...')) - * 'type' can be 'text', 'password', 'checkbox', 'radio', 'date', 'datetime', 'select', 'multiselect', 'morecss', - * 'other', 'onecolumn' or 'hidden'... + * @param array}>|string|null $formquestion An array with complementary inputs to add into forms: array(array('label'=> ,'type'=> , 'size'=>, 'morecss'=>, 'moreattr'=>'autofocus' or 'style=...')) + * 'type' can be 'text', 'password', 'checkbox', 'radio', 'date', 'datetime', 'select', 'multiselect', 'morecss', + * 'other', 'onecolumn' or 'hidden'... * @param int<0,1>|''|'no'|'yes'|'1'|'0' $selectedchoice '' or 'no', or 'yes' or '1', 1, '0' or 0 * @param int<0,2>|string $useajax 0=No, 1=Yes use Ajax to show the popup, 2=Yes and also submit page with &confirm=no if choice is No, 'xxx'=Yes and preoutput confirm box with div id=dialog-confirm-xxx * @param int|string $height Force height of box (0 = auto) diff --git a/htdocs/ecm/dir_card.php b/htdocs/ecm/dir_card.php index fcfff57f74a..cf7d8c159c9 100644 --- a/htdocs/ecm/dir_card.php +++ b/htdocs/ecm/dir_card.php @@ -1,6 +1,7 @@ * Copyright (C) 2024-2025 Frédéric France + * Copyright (C) 2025 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 @@ -85,7 +86,7 @@ $ecmdir = new EcmDirectory($db); if ($module == 'ecm') { // $section should be an int except if it is dir not yet created into EcmDirectory - $result = $ecmdir->fetch($section); + $result = preg_match('/^\d+$/', $section) ? $ecmdir->fetch((int) $section) : 0; if ($result > 0) { $relativepath = $ecmdir->getRelativePath(); $upload_dir = $conf->ecm->dir_output.'/'.$relativepath; @@ -199,6 +200,7 @@ if ($action == 'confirm_deletedir' && $confirm == 'yes' && $permissiontoupload) // Update dirname or description if ($action == 'update' && !GETPOST('cancel', 'alpha') && $permissiontoadd) { $error = 0; + $oldlabel = ''; if ($module == 'ecm') { $oldlabel = $ecmdir->label; diff --git a/htdocs/ecm/index.php b/htdocs/ecm/index.php index 0f3e5cd7c24..213d60c4a17 100644 --- a/htdocs/ecm/index.php +++ b/htdocs/ecm/index.php @@ -2,6 +2,7 @@ /* Copyright (C) 2008-2017 Laurent Destailleur * Copyright (C) 2008-2010 Regis Houssin * Copyright (C) 2024 Frédéric France + * Copyright (C) 2025 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 @@ -109,10 +110,11 @@ $permissiontodeletedir = $user->hasRight('ecm', 'setup'); //$backtopage = $_SERVER["PHP_SELF"].'?file_manager=1&website='.$websitekey.'&pageid='.$pageid; // used after a confirm_deletefile into actions_linkedfiles.inc.php //include DOL_DOCUMENT_ROOT.'/core/actions_linkedfiles.inc.php'; +$relativepath = ''; + // Upload file (code similar but different than actions_linkedfiles.inc.php) if (GETPOST("sendit", 'alphanohtml') && getDolGlobalString('MAIN_UPLOAD_DOC') && $permissiontocreate) { // Define relativepath and upload_dir - $relativepath = ''; if ($ecmdir->id) { $relativepath = $ecmdir->getRelativePath(); } else { @@ -277,11 +279,11 @@ if ($action == 'refreshmanual' && $permissiontoread) { //print $ecmdirtmp->cachenbofdoc."
\n";exit; $id = $ecmdirtmp->create($user); if ($id > 0) { - $newdirsql = array('id'=>$id, - 'id_mere'=>$ecmdirtmp->fk_parent, - 'label'=>$ecmdirtmp->label, - 'description'=>$ecmdirtmp->description, - 'fullrelativename'=>$relativepathmissing); + $newdirsql = array('id' => $id, + 'id_mere' => $ecmdirtmp->fk_parent, + 'label' => $ecmdirtmp->label, + 'description' => $ecmdirtmp->description, + 'fullrelativename' => $relativepathmissing); $sqltree[] = $newdirsql; // We complete fulltree for following loops //var_dump($sqltree); $adirwascreated = 1; diff --git a/htdocs/eventorganization/conferenceorbooth_card.php b/htdocs/eventorganization/conferenceorbooth_card.php index 69162c5fca8..ff6d66b04f3 100644 --- a/htdocs/eventorganization/conferenceorbooth_card.php +++ b/htdocs/eventorganization/conferenceorbooth_card.php @@ -3,7 +3,7 @@ * Copyright (C) 2021 Florian Henry * Copyright (C) 2024 Alexandre Spangaro * Copyright (C) 2024 Frédéric France - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 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 @@ -187,7 +187,7 @@ $help_url = 'EN:Module_Event_Organization'; llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-eventorganization page-card'); if ($action == 'create') { - $result = $projectstatic->fetch(GETPOST('fk_project')); + $result = $projectstatic->fetch(GETPOSTINT('fk_project')); } else { $result = $projectstatic->fetch($object->fk_project); } @@ -351,7 +351,7 @@ if (!empty($withproject)) { $htmltext = $langs->trans("AllowUnknownPeopleSuggestConfHelp"); print $form->editfieldkey('AllowUnknownPeopleSuggestConf', 'accept_conference_suggestions', '', $projectstatic, 0, $typeofdata, '', 0, 0, 'projectid', $htmltext); print '
'; - print $form->editfieldval('AllowUnknownPeopleSuggestConf', 'accept_conference_suggestions', '1', $projectstatic, 0, $typeofdata, '', null, 0, '', 0, '', 'projectid'); + print $form->editfieldval('AllowUnknownPeopleSuggestConf', 'accept_conference_suggestions', '1', $projectstatic, 0, $typeofdata, '', null, null, '', 0, '', 'projectid'); print "
'; @@ -359,7 +359,7 @@ if (!empty($withproject)) { $htmltext = $langs->trans("AllowUnknownPeopleSuggestBoothHelp"); print $form->editfieldkey('AllowUnknownPeopleSuggestBooth', 'accept_booth_suggestions', '', $projectstatic, 0, $typeofdata, '', 0, 0, 'projectid', $htmltext); print ''; - print $form->editfieldval('AllowUnknownPeopleSuggestBooth', 'accept_booth_suggestions', '1', $projectstatic, 0, $typeofdata, '', null, 0, '', 0, '', 'projectid'); + print $form->editfieldval('AllowUnknownPeopleSuggestBooth', 'accept_booth_suggestions', '1', $projectstatic, 0, $typeofdata, '', null, null, '', 0, '', 'projectid'); print "
'; @@ -377,7 +377,7 @@ if (!empty($withproject)) { print '
'; print $form->editfieldkey($form->textwithpicto($langs->trans('MaxNbOfAttendees'), ''), 'max_attendees', '', $projectstatic, $permissiontoadd, 'integer:3', '', 0, 0, 'projectid'); print ''; - print $form->editfieldval($form->textwithpicto($langs->trans('MaxNbOfAttendees'), ''), 'max_attendees', $projectstatic->max_attendees, $projectstatic, $permissiontoadd, 'integer:3', '', null, 0, '', 0, '', 'projectid'); + print $form->editfieldval($form->textwithpicto($langs->trans('MaxNbOfAttendees'), ''), 'max_attendees', $projectstatic->max_attendees, $projectstatic, $permissiontoadd, 'integer:3', '', null, null, '', 0, '', 'projectid'); print "
'.$langs->trans("EventOrganizationICSLink").''; diff --git a/htdocs/eventorganization/conferenceorbooth_list.php b/htdocs/eventorganization/conferenceorbooth_list.php index 46bb260a6be..dcaecaf7f4e 100644 --- a/htdocs/eventorganization/conferenceorbooth_list.php +++ b/htdocs/eventorganization/conferenceorbooth_list.php @@ -3,6 +3,7 @@ * Copyright (C) 2021 Florian Henry * Copyright (C) 2023-2024 Frédéric France * Copyright (C) 2024 Alexandre Spangaro + * Copyright (C) 2025 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 @@ -880,7 +881,7 @@ foreach ($object->fields as $key => $val) { } elseif ($key == 'lang') { require_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php'; $formadmin = new FormAdmin($db); - print $formadmin->select_language($search[$key], 'search_lang', 0, null, 1, 0, 0, 'minwidth100imp maxwidth125', 2); + print $formadmin->select_language($search[$key], 'search_lang', 0, array(), 1, 0, 0, 'minwidth100imp maxwidth125', 2); } else { print ''; } @@ -1032,7 +1033,7 @@ while ($i < $imaxinloop) { if (!empty($arrayfields['t.'.$key]['checked'])) { print '$key)) { - print ' title="'.dol_escape_htmltag($object->$key).'"'; + print ' title="'.dol_escape_htmltag((string) $object->$key).'"'; } print '>'; if ($key == 'status') { @@ -1040,7 +1041,7 @@ while ($i < $imaxinloop) { } elseif ($key == 'ref') { print $object->getNomUrl(1, 0, '', (($projectid > 0) ? 'withproject' : '')); } else { - print $object->showOutputField($val, $key, $object->$key, ''); + print $object->showOutputField($val, $key, (string) $object->$key, ''); } print ''; - print $form->editfieldval('AllowUnknownPeopleSuggestConf', 'accept_conference_suggestions', '1', $projectstatic, 0, $typeofdata, '', null, 0, '', 0, '', 'projectid'); + print $form->editfieldval('AllowUnknownPeopleSuggestConf', 'accept_conference_suggestions', '1', $projectstatic, 0, $typeofdata, '', null, null, '', 0, '', 'projectid'); print "
'; @@ -365,7 +367,7 @@ if (!empty($withproject)) { $htmltext = $langs->trans("AllowUnknownPeopleSuggestBoothHelp"); print $form->editfieldkey('AllowUnknownPeopleSuggestBooth', 'accept_booth_suggestions', '', $projectstatic, 0, $typeofdata, '', 0, 0, 'projectid', $htmltext); print ''; - print $form->editfieldval('AllowUnknownPeopleSuggestBooth', 'accept_booth_suggestions', '1', $projectstatic, 0, $typeofdata, '', null, 0, '', 0, '', 'projectid'); + print $form->editfieldval('AllowUnknownPeopleSuggestBooth', 'accept_booth_suggestions', '1', $projectstatic, 0, $typeofdata, '', null, null, '', 0, '', 'projectid'); print "
'; @@ -377,7 +379,7 @@ if (!empty($withproject)) { print '
'; print $form->editfieldkey($form->textwithpicto($langs->trans('PriceOfRegistration'), $langs->trans("PriceOfRegistrationHelp")), 'price_registration', '', $projectstatic, 0, 'amount', '', 0, 0, 'projectid'); print ''; - print $form->editfieldval($form->textwithpicto($langs->trans('PriceOfRegistration'), $langs->trans("PriceOfRegistrationHelp")), 'price_registration', $projectstatic->price_registration, $projectstatic, 0, 'amount', '', null, 0, '', 0, '', 'projectid'); + print $form->editfieldval($form->textwithpicto($langs->trans('PriceOfRegistration'), $langs->trans("PriceOfRegistrationHelp")), 'price_registration', $projectstatic->price_registration, $projectstatic, 0, 'amount', '', null, null, '', 0, '', 'projectid'); print "
'.$langs->trans("EventOrganizationICSLink").''; @@ -439,7 +441,7 @@ if (!empty($withproject)) { } // Part to create -if ($action == 'create') { +if ($action == 'create' && $confOrBooth !== null) { print load_fiche_titre($langs->trans("NewObject", $langs->transnoentitiesnoconv("ConferenceOrBoothAttendee")), '', 'object_'.$object->picto); @@ -484,7 +486,7 @@ if ($action == 'create') { } // Part to edit record -if (($id || $ref) && $action == 'edit') { +if (($id || $ref) && $action == 'edit' && $confOrBooth !== null) { print load_fiche_titre($langs->trans("ConferenceOrBoothAttendee"), '', 'object_'.$object->picto); print '
'; @@ -527,7 +529,7 @@ if (($id || $ref) && $action == 'edit') { } // Part to show record -if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) { +if ($confOrBooth !== null && $object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) { $object->fetch_optionals(); $moreparam = ''; diff --git a/htdocs/eventorganization/conferenceorboothattendee_list.php b/htdocs/eventorganization/conferenceorboothattendee_list.php index c5934e13ecd..3cabcb13528 100644 --- a/htdocs/eventorganization/conferenceorboothattendee_list.php +++ b/htdocs/eventorganization/conferenceorboothattendee_list.php @@ -3,6 +3,7 @@ * Copyright (C) 2021 Florian Henry * Copyright (C) 2024 Alexandre Spangaro * Copyright (C) 2024 Frédéric France + * Copyright (C) 2025 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 @@ -564,7 +565,7 @@ if ($projectstatic->id > 0 || $confOrBooth > 0) { $htmltext = $langs->trans("AllowUnknownPeopleSuggestConfHelp"); print $form->editfieldkey('AllowUnknownPeopleSuggestConf', 'accept_conference_suggestions', $projectstatic->accept_conference_suggestions ? 1 : 0, $projectstatic, 0, $typeofdata, '', 0, 0, 'projectid', $htmltext); print '
'; - print $form->editfieldval('AllowUnknownPeopleSuggestConf', 'accept_conference_suggestions', $projectstatic->accept_conference_suggestions ? 1 : 0, $projectstatic, 0, $typeofdata, '', null, 0, '', 0, '', 'projectid'); + print $form->editfieldval('AllowUnknownPeopleSuggestConf', 'accept_conference_suggestions', $projectstatic->accept_conference_suggestions ? 1 : 0, $projectstatic, 0, $typeofdata, '', null, null, '', 0, '', 'projectid'); print "
'; @@ -572,39 +573,39 @@ if ($projectstatic->id > 0 || $confOrBooth > 0) { $htmltext = $langs->trans("AllowUnknownPeopleSuggestBoothHelp"); print $form->editfieldkey('AllowUnknownPeopleSuggestBooth', 'accept_booth_suggestions', $projectstatic->accept_booth_suggestions ? 1 : 0, $projectstatic, 0, $typeofdata, '', 0, 0, 'projectid', $htmltext); print ''; - print $form->editfieldval('AllowUnknownPeopleSuggestBooth', 'accept_booth_suggestions', $projectstatic->accept_booth_suggestions ? 1 : 0, $projectstatic, 0, $typeofdata, '', null, 0, '', 0, '', 'projectid'); + print $form->editfieldval('AllowUnknownPeopleSuggestBooth', 'accept_booth_suggestions', $projectstatic->accept_booth_suggestions ? 1 : 0, $projectstatic, 0, $typeofdata, '', null, null, '', 0, '', 'projectid'); print "
'; print $form->editfieldkey($form->textwithpicto($langs->trans('PriceOfBooth'), $langs->trans("PriceOfBoothHelp")), 'price_booth', '', $projectstatic, 0, 'amount', '', 0, 0, 'projectid'); print ''; - print $form->editfieldval($form->textwithpicto($langs->trans('PriceOfBooth'), $langs->trans("PriceOfBoothHelp")), 'price_booth', $projectstatic->price_booth, $projectstatic, 0, 'amount', '', null, 0, '', 0, '', 'projectid'); + print $form->editfieldval($form->textwithpicto($langs->trans('PriceOfBooth'), $langs->trans("PriceOfBoothHelp")), 'price_booth', $projectstatic->price_booth, $projectstatic, 0, 'amount', '', null, null, '', 0, '', 'projectid'); print "
'; print $form->editfieldkey($form->textwithpicto($langs->trans('PriceOfRegistration'), $langs->trans("PriceOfRegistrationHelp")), 'price_registration', '', $projectstatic, 0, 'amount', '', 0, 0, 'projectid'); print ''; - print $form->editfieldval($form->textwithpicto($langs->trans('PriceOfRegistration'), $langs->trans("PriceOfRegistrationHelp")), 'price_registration', $projectstatic->price_registration, $projectstatic, 0, 'amount', '', null, 0, '', 0, '', 'projectid'); + print $form->editfieldval($form->textwithpicto($langs->trans('PriceOfRegistration'), $langs->trans("PriceOfRegistrationHelp")), 'price_registration', $projectstatic->price_registration, $projectstatic, 0, 'amount', '', null, null, '', 0, '', 'projectid'); print "
'; print $form->editfieldkey($form->textwithpicto($langs->trans('MaxNbOfAttendees'), ''), 'max_attendees', '', $projectstatic, $permissiontoadd, 'integer:3', '&withproject=1', 0, 0, 'projectid'); print ''; - print $form->editfieldval($form->textwithpicto($langs->trans('MaxNbOfAttendees'), ''), 'max_attendees', $projectstatic->max_attendees, $projectstatic, $permissiontoadd, 'integer:3', '', null, 0, '&withproject=1', 0, '', 'projectid'); + print $form->editfieldval($form->textwithpicto($langs->trans('MaxNbOfAttendees'), ''), 'max_attendees', $projectstatic->max_attendees, $projectstatic, $permissiontoadd, 'integer:3', '', null, null, '&withproject=1', 0, '', 'projectid'); print "
'.$langs->trans("EventOrganizationICSLinkProject").''; + // Link to ICS for the event + print '
'.$langs->trans("EventOrganizationICSLinkProject").''; // Define $urlwithroot - $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root)); - $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; + $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root)); + $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; - // Show message - $message = ''.$langs->trans('DownloadICSLink').img_picto('', 'download', 'class="paddingleft"').''; - print $message; - print "
'.$langs->trans("EventOrganizationICSLink").''; // Define $urlwithroot @@ -870,7 +871,7 @@ foreach ($object->fields as $key => $val) { } elseif ($key == 'lang') { require_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php'; $formadmin = new FormAdmin($db); - print $formadmin->select_language($search[$key], 'search_lang', 0, null, 1, 0, 0, 'minwidth100imp maxwidth125', 2); + print $formadmin->select_language($search[$key], 'search_lang', 0, array(), 1, 0, 0, 'minwidth100imp maxwidth125', 2); } else { print ''; } @@ -1021,7 +1022,7 @@ while ($i < $imaxinloop) { if (!empty($arrayfields['t.'.$key]['checked'])) { print '$key)) { - print ' title="'.dol_escape_htmltag($object->$key).'"'; + print ' title="'.dol_escape_htmltag((string) $object->$key).'"'; } print '>'; if ($key == 'status') { @@ -1033,7 +1034,7 @@ while ($i < $imaxinloop) { } print $object->getNomUrl(1, $optionLink); } else { - print $object->showOutputField($val, $key, $object->$key, ''); + print $object->showOutputField($val, $key, (string) $object->$key, ''); } print '
'.$langs->trans("Project").''; print img_picto('', 'project', 'class="pictofixedwidth"'); - $numprojet = $formproject->select_projects($soc->id, $projectid, 'projectid', 0); + $numprojet = $formproject->select_projects($soc->id, (string) $projectid, 'projectid', 0); print ' id).'">'; print '
'; print img_picto('', 'fa-balance-scale', 'class="pictofixedwidth"'); print ' '; - $text = $formproduct->selectMeasuringUnits("weight_units", "weight", GETPOSTINT('weight_units'), 0, 2); + $text = $formproduct->selectMeasuringUnits("weight_units", "weight", (string) GETPOSTINT('weight_units'), 0, 2); $htmltext = $langs->trans("KeepEmptyForAutoCalculation"); print $form->textwithpicto($text, $htmltext); print '
'; - print $form->selectDate('', '', '', '', '', '', 1, 1); + print $form->selectDate('', '', 0, 0, 0, '', 1, 1); print '
'; if (!empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_BILL)) { - print $form->selectyesno('validate_invoices', 0, 1, 1); + print $form->selectyesno('validate_invoices', 0, 1, true); $langs->load("errors"); print ' ('.$langs->trans("WarningAutoValNotPossibleWhenStockIsDecreasedOnInvoiceVal").')'; } else { @@ -1152,7 +1149,7 @@ if ($user->hasRight('user', 'user', 'lire')) { $moreforfilter .= '
'; $tmptitle = $langs->trans('LinkedToSpecificUsers'); $moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"'); - $moreforfilter .= $form->select_dolusers($search_user, 'search_user', $tmptitle, '', 0, '', '', 0, 0, 0, '', 0, '', 'maxwidth200'); + $moreforfilter .= $form->select_dolusers($search_user, 'search_user', $tmptitle, null, 0, '', '', '0', 0, 0, '', 0, '', 'maxwidth200'); $moreforfilter .= '
'; } // If the user can view prospects other than his' @@ -1190,7 +1187,7 @@ if (!empty($moreforfilter)) { } $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; -$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')); +$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')); // @phan-suppress-current-line PhanTypeMismatchArgument if ($massactionbutton) { $selectedfields .= $form->showCheckAddButtons('checkforselect', 1); // This also change content of $arrayfields } @@ -1223,7 +1220,7 @@ if (!empty($arrayfields['e.ref_customer']['checked'])) { // Thirdparty if (!empty($arrayfields['s.nom']['checked'])) { print '
'; - print ''; + print ''; print ''; - print $form->selectyesno('search_billed', $search_billed, 1, 0, 1); + print $form->selectyesno('search_billed', $search_billed, 1, false, 1); print ''; if ($object->shipping_method_id > 0) { print $langs->trans("SendingMethod".strtoupper($code)); diff --git a/htdocs/expedition/note.php b/htdocs/expedition/note.php index 862253ba2ce..f2186c1be04 100644 --- a/htdocs/expedition/note.php +++ b/htdocs/expedition/note.php @@ -4,6 +4,7 @@ * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2013 Florian Henry * Copyright (C) 2024 Frédéric France + * Copyright (C) 2025 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 @@ -54,6 +55,7 @@ if ($id > 0 || !empty($ref)) { $object->fetch($id, $ref); $object->fetch_thirdparty(); + $typeobject = null; if (!empty($object->origin)) { $typeobject = $object->origin; $origin = $object->origin; @@ -128,7 +130,7 @@ if ($id > 0 || !empty($ref)) { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $objectsrc->socid, $objectsrc->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $objectsrc->socid, (string) $objectsrc->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($objectsrc) && !empty($objectsrc->fk_project)) { $proj = new Project($db); diff --git a/htdocs/expedition/shipment.php b/htdocs/expedition/shipment.php index 89930ef944c..e7ecf387ec1 100644 --- a/htdocs/expedition/shipment.php +++ b/htdocs/expedition/shipment.php @@ -5,7 +5,7 @@ * Copyright (C) 2012-2015 Juanjo Menent * Copyright (C) 2018-2024 Frédéric France * Copyright (C) 2018-2022 Philippe Grand - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 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 @@ -146,7 +146,7 @@ if (empty($reshook)) { if ($action == 'setavailability' && $permissiontoadd) { $object->fetch($id); - $result = $object->availability(GETPOST('availability_id')); + $result = $object->availability(GETPOSTINT('availability_id')); if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); } @@ -154,7 +154,7 @@ if (empty($reshook)) { if ($action == 'setdemandreason' && $permissiontoadd) { $object->fetch($id); - $result = $object->demand_reason(GETPOST('demand_reason_id')); + $result = $object->demand_reason(GETPOSTINT('demand_reason_id')); if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); } @@ -301,7 +301,7 @@ if ($id > 0 || !empty($ref)) { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $objectsrc->socid, $objectsrc->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $objectsrc->socid, (string) $objectsrc->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($objectsrc) && !empty($objectsrc->fk_project)) { $proj = new Project($db); @@ -336,8 +336,8 @@ if ($id > 0 || !empty($ref)) { print '
'.$langs->trans('Discounts').''; - $absolute_discount = $soc->getAvailableDiscounts('', $filterabsolutediscount); - $absolute_creditnote = $soc->getAvailableDiscounts('', $filtercreditnote); + $absolute_discount = $soc->getAvailableDiscounts(null, $filterabsolutediscount); + $absolute_creditnote = $soc->getAvailableDiscounts(null, $filtercreditnote); $absolute_discount = price2num($absolute_discount, 'MT'); $absolute_creditnote = price2num($absolute_creditnote, 'MT'); @@ -396,9 +396,9 @@ if ($id > 0 || !empty($ref)) { print '
'; print ''; if ($action == 'editavailability') { - $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, $object->availability_id, 'availability_id', 1); + $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->availability_id, 'availability_id', 1); } else { - $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, $object->availability_id, 'none', 1); + $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->availability_id, 'none', 1); } print ''; @@ -413,9 +413,9 @@ if ($id > 0 || !empty($ref)) { print ''; print ''; if ($action == 'editshippingmethod') { - $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, $object->shipping_method_id, 'shipping_method_id', 1); + $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->shipping_method_id, 'shipping_method_id', 1); } else { - $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, $object->shipping_method_id, 'none'); + $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->shipping_method_id, 'none'); } print ''; print ''; @@ -453,9 +453,9 @@ if ($id > 0 || !empty($ref)) { print ''; print ''; if ($action == 'editdemandreason') { - $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, $object->demand_reason_id, 'demand_reason_id', 1); + $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->demand_reason_id, 'demand_reason_id', 1); } else { - $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, $object->demand_reason_id, 'none'); + $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->demand_reason_id, 'none'); } // Terms of payment @@ -620,6 +620,9 @@ if ($id > 0 || !empty($ref)) { $sql .= " WHERE cd.fk_commande = ".((int) $object->id); $sql .= " ORDER BY cd.rang, cd.rowid"; + $toBeShipped = array(); + $toBeShippedTotal = 0; + //print $sql; dol_syslog("shipment.php", LOG_DEBUG); $resql = $db->query($sql); @@ -643,8 +646,6 @@ if ($id > 0 || !empty($ref)) { print "\n"; print ''; - $toBeShipped = array(); - $toBeShippedTotal = 0; while ($i < $num) { $objp = $db->fetch_object($resql); @@ -733,7 +734,7 @@ if ($id > 0 || !empty($ref)) { $text .= ' - '.$label; $description = (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE') ? '' : dol_htmlentitiesbr($objp->description)).'
'; $description .= $product_static->show_photos('product', $conf->product->multidir_output[$product_static->entity], 1, 1, 0, 0, 0, 80); - print $form->textwithtooltip($text, $description, 3, '', '', $i); + print $form->textwithtooltip($text, $description, 3, '', 0, (string) $i); // Show range print_date_range($db->jdate($objp->date_start), $db->jdate($objp->date_end)); @@ -754,7 +755,7 @@ if ($id > 0 || !empty($ref)) { if (!empty($objp->label)) { $text .= ' '.$objp->label.''; - print $form->textwithtooltip($text, $objp->description, 3, '', '', $i); + print $form->textwithtooltip($text, $objp->description, 3, 0, '', (string) $i); } else { print $text.' '.nl2br($objp->description); } diff --git a/htdocs/expensereport/card.php b/htdocs/expensereport/card.php index e0cd273c028..d931c854afb 100644 --- a/htdocs/expensereport/card.php +++ b/htdocs/expensereport/card.php @@ -5,7 +5,7 @@ * Copyright (C) 2015-2023 Alexandre Spangaro * Copyright (C) 2017 Ferran Marcet * Copyright (C) 2018-2024 Frédéric France - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 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 @@ -234,6 +234,7 @@ if (empty($reshook)) { // Action clone object if ($action == 'confirm_clone' && $confirm == 'yes' && $permissiontoadd) { + // @phan-suppress-next-line PhanPluginBothLiteralsBinaryOp if (1 == 0 && !GETPOST('clone_content', 'alpha') && !GETPOST('clone_receivers', 'alpha')) { setEventMessages($langs->trans("NoCloneOptionsSpecified"), null, 'errors'); } else { @@ -1358,7 +1359,7 @@ if (empty($reshook)) { if (!$error) { // TODO Use update method of ExpenseReportLine - $result = $object->updateline($rowid, $type_fees_id, $projet_id, $vatrate, $comments, $qty, $value_unit, $date, $id, $fk_c_exp_tax_cat, $fk_ecm_files); + $result = $object->updateline($rowid, $type_fees_id, $projet_id, $vatrate, $comments, (float) $qty, (float) $value_unit, $date, $id, $fk_c_exp_tax_cat, $fk_ecm_files); if ($result >= 0) { if ($result > 0) { // Define output language @@ -1431,6 +1432,7 @@ $paymentexpensereportstatic = new PaymentExpenseReport($db); $bankaccountstatic = new Account($db); $ecmfilesstatic = new EcmFiles($db); $formexpensereport = new FormExpenseReport($db); +$remaintopay = 0; // Create if ($action == 'create') { @@ -1474,7 +1476,7 @@ if ($action == 'create') { if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('expensereport', 'writeall_advance')) { $include_users = array(); } - $s = $form->select_dolusers($defaultselectuser, "fk_user_author", 0, "", 0, $include_users, '', '0,'.$conf->entity); + $s = $form->select_dolusers($defaultselectuser, "fk_user_author", 0, null, 0, $include_users, '', '0,'.$conf->entity); print $s; print ''; print ''; @@ -1495,7 +1497,7 @@ if ($action == 'create') { if (GETPOSTINT('fk_user_validator') > 0) { $defaultselectuser = GETPOSTINT('fk_user_validator'); } - $s = $form->select_dolusers($defaultselectuser, "fk_user_validator", 1, "", ((empty($defaultselectuser) || !getDolGlobalString('EXPENSEREPORT_DEFAULT_VALIDATOR_UNCHANGEABLE')) ? 0 : 1), $include_users); + $s = $form->select_dolusers($defaultselectuser, "fk_user_validator", 1, null, ((empty($defaultselectuser) || !getDolGlobalString('EXPENSEREPORT_DEFAULT_VALIDATOR_UNCHANGEABLE')) ? 0 : 1), $include_users); print $form->textwithpicto($s, $langs->trans("AnyOtherInThisListCanValidate")); } print ''; @@ -1552,6 +1554,7 @@ if ($action == 'create') { print ''; } elseif ($id > 0 || $ref) { + $userauthor = null; $result = $object->fetch($id, $ref); if ($result > 0) { @@ -1624,7 +1627,7 @@ if ($action == 'create') { print ''; print ''.$langs->trans("ModePaiement").''; print ''; - $form->select_types_paiements($object->fk_c_paiement, 'fk_c_paiement'); + $form->select_types_paiements((string) $object->fk_c_paiement, 'fk_c_paiement'); print ''; print ''; } @@ -1634,7 +1637,7 @@ if ($action == 'create') { print ''.$langs->trans("VALIDATOR").''; // Approbator print ''; $include_users = $object->fetch_users_approver_expensereport(); - $s = $form->select_dolusers($object->fk_user_validator, "fk_user_validator", 1, "", 0, $include_users); + $s = $form->select_dolusers($object->fk_user_validator, "fk_user_validator", 1, null, 0, $include_users); print $form->textwithpicto($s, $langs->trans("AnyOtherInThisListCanValidate")); print ''; print ''; @@ -2225,7 +2228,7 @@ if ($action == 'create') { print ''.price($line->value_unit).''; - print ''.dol_escape_htmltag($line->qty).''; + print ''.dol_escape_htmltag((string) $line->qty).''; if ($action != 'editline') { print ''.price($line->total_ht).''; @@ -2400,7 +2403,7 @@ if ($action == 'create') { // Select project if (isModEnabled('project')) { print ''; - $formproject->select_projects(-1, $line->fk_project, 'fk_project', 0, 0, $projectRequired ? 0 : 1, 1, 0, 0, 0, '', 0, 0, 'maxwidth300'); + $formproject->select_projects(-1, (string) $line->fk_project, 'fk_project', 0, 0, $projectRequired ? 0 : 1, 1, 0, 0, 0, '', 0, 0, 'maxwidth300'); print ''; } @@ -2412,7 +2415,7 @@ if ($action == 'create') { if (getDolGlobalString('MAIN_USE_EXPENSE_IK')) { print ''; $params = array('fk_expense' => $object->id, 'fk_expense_det' => $line->id, 'date' => $line->date); - print $form->selectExpenseCategories($line->fk_c_exp_tax_cat, 'fk_c_exp_tax_cat', 1, array(), 'fk_c_type_fees', $userauthor->default_c_exp_tax_cat, $params); + print $form->selectExpenseCategories($line->fk_c_exp_tax_cat, 'fk_c_exp_tax_cat', 1, array(), 'fk_c_type_fees', (string) $userauthor->default_c_exp_tax_cat, $params); print ''; } @@ -2424,7 +2427,7 @@ if ($action == 'create') { // VAT $selectedvat = price2num($line->vatrate).(!empty($line->vat_src_code) ? ' ('.$line->vat_src_code.')' : ''); print ''; - print $form->load_tva('vatrate', (GETPOSTISSET("vatrate") ? GETPOST("vatrate") : $selectedvat), $mysoc, '', 0, 0, '', false, 1, 2); + print $form->load_tva('vatrate', (GETPOSTISSET("vatrate") ? GETPOST("vatrate") : $selectedvat), $mysoc, null, 0, 0, '', false, 1, 2); print ''; // Unit price @@ -2439,7 +2442,7 @@ if ($action == 'create') { // Quantity print ''; - print ''; // We must be able to enter decimal qty + print ''; // We must be able to enter decimal qty print ''; //print ''.$langs->trans('AmountHT').''; @@ -2455,7 +2458,7 @@ if ($action == 'create') { print ''; print ''; - print $form->buttonsSaveCancel('Save', 'Cancel', array(), 0, 'small'); + print $form->buttonsSaveCancel('Save', 'Cancel', array(), false, 'small'); print ''; print ''; @@ -2582,7 +2585,7 @@ if ($action == 'create') { // Select project if (isModEnabled('project')) { print ''; - $formproject->select_projects(-1, !empty($fk_project) ? $fk_project : 0, 'fk_project', 0, 0, $projectRequired ? 0 : 1, -1, 0, 0, 0, '', 0, 0, 'maxwidth300'); + $formproject->select_projects(-1, !empty($fk_project) ? (string) $fk_project : '0', 'fk_project', 0, 0, $projectRequired ? 0 : 1, -1, 0, 0, 0, '', 0, 0, 'maxwidth300'); print ''; } @@ -2610,7 +2613,7 @@ if ($action == 'create') { // If option to have no default VAT on expense report is on, we force MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS = 'none'; } - print $form->load_tva('vatrate', (!empty($vatrate) ? $vatrate : $defaultvat), $mysoc, '', 0, 0, '', false, 1); + print $form->load_tva('vatrate', (!empty($vatrate) ? $vatrate : $defaultvat), $mysoc, null, 0, 0, '', false, 1); print ''; // Unit price net @@ -2638,7 +2641,7 @@ if ($action == 'create') { } print ''; - print $form->buttonsSaveCancel("Add", '', '', 1, 'reposition'); + print $form->buttonsSaveCancel("Add", '', array(), true, 'reposition'); print ''; print ''; @@ -2938,7 +2941,7 @@ if ($action != 'presend') { // List of actions on element include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php'; $formactions = new FormActions($db); - $somethingshown = $formactions->showactions($object, 'expensereport', null); + $somethingshown = $formactions->showactions($object, 'expensereport', 0); print '
'; } From 0438db7747cbcfd8fca449e3908ba5316b32a4a5 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Wed, 29 Jan 2025 07:10:41 +0100 Subject: [PATCH 146/383] FIX wrong table name --- htdocs/accountancy/class/accountancycategory.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/accountancy/class/accountancycategory.class.php b/htdocs/accountancy/class/accountancycategory.class.php index 379e2b802e1..fbbdb35e7a8 100644 --- a/htdocs/accountancy/class/accountancycategory.class.php +++ b/htdocs/accountancy/class/accountancycategory.class.php @@ -439,7 +439,7 @@ class AccountancyCategory // extends CommonObject { global $conf; $sql = "SELECT t.rowid, t.account_number, t.label"; - $sql .= " FROM ".$this->db->prefix().$this->table_element." as t"; + $sql .= " FROM ".$this->db->prefix()."accounting_account as t"; $sql .= " WHERE t.fk_accounting_category = ".((int) $id); $sql .= " AND t.entity = ".$conf->entity; From c43f74687a6aa19318d09435db5c673d2300e9dc Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Wed, 29 Jan 2025 07:32:22 +0100 Subject: [PATCH 147/383] FIX #32843 --- htdocs/bom/bom_card.php | 2 +- htdocs/mrp/mo_card.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/bom/bom_card.php b/htdocs/bom/bom_card.php index c5456de0a21..0656d9d1e31 100644 --- a/htdocs/bom/bom_card.php +++ b/htdocs/bom/bom_card.php @@ -800,7 +800,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id; $genallowed = $user->hasRight('bom', 'read'); // If you can read, you can build the PDF to read content $delallowed = $user->hasRight('bom', 'write'); // If you can create/edit, you can remove a file on card - print $formfile->showdocuments('bom', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $langs->defaultlang); + print $formfile->showdocuments('bom', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $langs->defaultlang, '', $object); // Show links to link elements $linktoelem = $form->showLinkToObjectBlock($object, null, array('bom')); diff --git a/htdocs/mrp/mo_card.php b/htdocs/mrp/mo_card.php index 17f5aefcb62..7f1ccf1729e 100644 --- a/htdocs/mrp/mo_card.php +++ b/htdocs/mrp/mo_card.php @@ -853,7 +853,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id; $genallowed = $user->hasRight('mrp', 'read'); // If you can read, you can build the PDF to read content $delallowed = $user->hasRight("mrp", "creer"); // If you can create/edit, you can remove a file on card - print $formfile->showdocuments('mrp:mo', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $mysoc->default_lang); + print $formfile->showdocuments('mrp:mo', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $mysoc->default_lang, '', $object); // Show links to link elements $linktoelem = $form->showLinkToObjectBlock($object, null, array('mo')); From 510da33c338f3f6be53cb9ec90626bcb404aeab7 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Wed, 29 Jan 2025 08:35:55 +0100 Subject: [PATCH 148/383] FIX #32840 --- htdocs/categories/class/categorie.class.php | 35 ++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/htdocs/categories/class/categorie.class.php b/htdocs/categories/class/categorie.class.php index 330baf65469..b3721d1bee7 100644 --- a/htdocs/categories/class/categorie.class.php +++ b/htdocs/categories/class/categorie.class.php @@ -285,6 +285,38 @@ class Categorie extends CommonObject */ public $imgHeight; + /** + * 'type' if the field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password') + * Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)" + * 'label' the translation key. + * 'enabled' is a condition when the field must be managed (Example: 1 or 'getDolGlobalString("MY_SETUP_PARAM")' + * 'position' is the sort order of field. + * 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0). + * 'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing) + * 'noteditable' says if field is not editable (1 or 0) + * 'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created. + * 'index' if we want an index in database. + * 'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommended to name the field fk_...). + * 'searchall' is 1 if we want to search in this field when making a search from the quick search button. + * 'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8). + * 'css' is the CSS style to use on field. For example: 'maxwidth200' + * 'help' is a string visible as a tooltip on field + * 'showoncombobox' if value of the field must be visible into the label of the combobox that list record + * 'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code. + * 'arrayofkeyval' to set list of value if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel") + * 'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1. + * 'comment' is not used. You can store here any text of your choice. It is not used by application. + * + * Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor. + */ + + /** + * @var array|string,position:int,notnull?:int,visible:int,noteditable?:int,default?:string,index?:int,foreignkey?:string,searchall?:int,isameasure?:int,css?:string,csslist?:string,help?:string,showoncombobox?:int,disabled?:int,arrayofkeyval?:array,comment?:string}> Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. + */ + public $fields = array( + 'label' => array('type' => 'varchar(255)', 'label' => 'Label', 'enabled' => 1, 'visible' => 1, 'showoncombobox' => 1), + ); + /** * Constructor * @@ -1751,7 +1783,8 @@ class Categorie extends CommonObject } // Check contrast with background and correct text color - $forced_color = 'categtextwhite'; + //$forced_color = 'categtextwhite'; // TODO This css class hide the link + $forced_color = 'categtextblack'; if ($this->color) { if (colorIsLight($this->color)) { $forced_color = 'categtextblack'; From 3f1efcfb53a5d9bb58800aed0f3f27574d0fb3c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 29 Jan 2025 09:01:32 +0100 Subject: [PATCH 149/383] dict type contact --- htdocs/admin/dict.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php index c201ca97b73..d96d7ce0e4f 100644 --- a/htdocs/admin/dict.php +++ b/htdocs/admin/dict.php @@ -11,7 +11,7 @@ * Copyright (C) 2011-2024 Alexandre Spangaro * Copyright (C) 2015 Ferran Marcet * Copyright (C) 2016 Raphaël Doursenaud - * Copyright (C) 2019-2024 Frédéric France + * Copyright (C) 2019-2025 Frédéric France * Copyright (C) 2020-2022 Open-Dsi * Copyright (C) 2024 Charlene Benke * Copyright (C) 2024 MDW @@ -716,6 +716,7 @@ if ($id == DICT_TYPE_CONTACT) { 'project_task' => img_picto('', 'projecttask', 'class="pictofixedwidth"').$langs->trans('Task'), 'propal' => img_picto('', 'propal', 'class="pictofixedwidth"').$langs->trans('Proposal'), 'commande' => img_picto('', 'order', 'class="pictofixedwidth"').$langs->trans('Order'), + 'shipping' => img_picto('', 'dolly', 'class="pictofixedwidth"') . $langs->trans('Shipment'), 'facture' => img_picto('', 'bill', 'class="pictofixedwidth"').$langs->trans('Bill'), 'fichinter' => img_picto('', 'intervention', 'class="pictofixedwidth"').$langs->trans('InterventionCard'), 'contrat' => img_picto('', 'contract', 'class="pictofixedwidth"').$langs->trans('Contract'), From 40d8bea77e2133335de16b8336e66b074a96e205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 29 Jan 2025 09:14:13 +0100 Subject: [PATCH 150/383] dict type contact --- htdocs/commande/class/commande.class.php | 4 ++-- htdocs/install/mysql/migration/21.0.0-22.0.0.sql | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index 71e03085f69..ccce40846ce 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -1638,9 +1638,9 @@ class Commande extends CommonOrder $product = new Product($this->db); $result = $product->fetch($fk_product); if ($qty < $product->packaging) { - $qty = $product->packaging; + $qty = (float) $product->packaging; } else { - if (!empty($product->packaging) && (fmod((float) $qty, $product->packaging) > 0.000001)) { + if (!empty($product->packaging) && (fmod((float) $qty, (float) $product->packaging) > 0.000001)) { $coeff = intval((float) $qty / $product->packaging) + 1; $qty = (float) $product->packaging * $coeff; setEventMessages($langs->trans('QtyRecalculatedWithPackaging'), null, 'mesgs'); diff --git a/htdocs/install/mysql/migration/21.0.0-22.0.0.sql b/htdocs/install/mysql/migration/21.0.0-22.0.0.sql index 0837bdb61a8..0aef3f65cc8 100644 --- a/htdocs/install/mysql/migration/21.0.0-22.0.0.sql +++ b/htdocs/install/mysql/migration/21.0.0-22.0.0.sql @@ -42,6 +42,13 @@ ALTER TABLE llx_societe_account ADD UNIQUE INDEX uk_societe_account_login_websit -- V22 migration +-- fix element +UPDATE llx_c_type_contact set element='shipping' WHERE element='expedition'; +-- Shipment / Expedition +insert into llx_c_type_contact (element, source, code, libelle, active ) values ('shipping', 'internal', 'SALESREPFOLL', 'Responsable suivi de l''expédition', 1); +insert into llx_c_type_contact (element, source, code, libelle, active ) values ('shipping', 'external', 'CUSTOMER', 'Customer shipping contact', 1); +insert into llx_c_type_contact (element, source, code, libelle, active ) values ('shipping', 'external', 'SHIPPING', 'Loading facility', 1); +insert into llx_c_type_contact (element, source, code, libelle, active ) values ('shipping', 'external', 'DELIVERY', 'Delivery facility', 1); ALTER TABLE llx_holiday_config DROP INDEX idx_holiday_config; ALTER TABLE llx_holiday_config ADD COLUMN entity integer DEFAULT 1 NOT NULL AFTER rowid; @@ -49,4 +56,4 @@ ALTER TABLE llx_holiday_config ADD UNIQUE INDEX idx_holiday_config (entity, name ALTER TABLE llx_societe_account ADD COLUMN ip varchar(250); -ALTER TABLE llx_product ADD COLUMN packaging float(24,8) DEFAULT NULL; \ No newline at end of file +ALTER TABLE llx_product ADD COLUMN packaging float(24,8) DEFAULT NULL; From e7088d779415b158720aa3081ca01a44f30ec31c Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Wed, 29 Jan 2025 09:14:37 +0100 Subject: [PATCH 151/383] FIX add other fields --- htdocs/categories/class/categorie.class.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/htdocs/categories/class/categorie.class.php b/htdocs/categories/class/categorie.class.php index b3721d1bee7..305649da4e4 100644 --- a/htdocs/categories/class/categorie.class.php +++ b/htdocs/categories/class/categorie.class.php @@ -314,7 +314,9 @@ class Categorie extends CommonObject * @var array|string,position:int,notnull?:int,visible:int,noteditable?:int,default?:string,index?:int,foreignkey?:string,searchall?:int,isameasure?:int,css?:string,csslist?:string,help?:string,showoncombobox?:int,disabled?:int,arrayofkeyval?:array,comment?:string}> Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. */ public $fields = array( - 'label' => array('type' => 'varchar(255)', 'label' => 'Label', 'enabled' => 1, 'visible' => 1, 'showoncombobox' => 1), + 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'index' => 1, 'position' => 1, 'comment' => 'Id'), + 'entity' => array('type' => 'integer', 'label' => 'Entity', 'enabled' => 1, 'visible' => 0, 'default' => '1', 'notnull' => 1, 'index' => 1, 'position' => 5), + 'label' => array('type' => 'varchar(255)', 'label' => 'Label', 'enabled' => 1, 'visible' => 1, 'showoncombobox' => 1, 'position' => 15, 'csslist' => 'tdoverflowmax250'), ); /** From 262a07f5fa43a0a6418579d1eb42034583977471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 29 Jan 2025 09:25:23 +0100 Subject: [PATCH 152/383] dict type contact --- htdocs/compta/facture/class/facture.class.php | 4 ++-- htdocs/install/mysql/migration/21.0.0-22.0.0.sql | 9 +++++---- htdocs/langs/en_US/propal.lang | 2 +- htdocs/langs/en_US/sendings.lang | 6 ++++++ 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 09dddafbbd5..68a019043d5 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -4003,9 +4003,9 @@ class Facture extends CommonInvoice $product = new Product($this->db); $result = $product->fetch($fk_product); if ($qty < $product->packaging) { - $qty = $product->packaging; + $qty = (float) $product->packaging; } else { - if (!empty($product->packaging) && (fmod((float) $qty, $product->packaging) > 0.000001)) { + if (!empty($product->packaging) && (fmod((float) $qty, (float) $product->packaging) > 0.000001)) { $coeff = intval((float) $qty / $product->packaging) + 1; $qty = (float) $product->packaging * $coeff; setEventMessages($langs->trans('QtyRecalculatedWithPackaging'), null, 'mesgs'); diff --git a/htdocs/install/mysql/migration/21.0.0-22.0.0.sql b/htdocs/install/mysql/migration/21.0.0-22.0.0.sql index 0aef3f65cc8..4cf68ce85ad 100644 --- a/htdocs/install/mysql/migration/21.0.0-22.0.0.sql +++ b/htdocs/install/mysql/migration/21.0.0-22.0.0.sql @@ -45,10 +45,11 @@ ALTER TABLE llx_societe_account ADD UNIQUE INDEX uk_societe_account_login_websit -- fix element UPDATE llx_c_type_contact set element='shipping' WHERE element='expedition'; -- Shipment / Expedition -insert into llx_c_type_contact (element, source, code, libelle, active ) values ('shipping', 'internal', 'SALESREPFOLL', 'Responsable suivi de l''expédition', 1); -insert into llx_c_type_contact (element, source, code, libelle, active ) values ('shipping', 'external', 'CUSTOMER', 'Customer shipping contact', 1); -insert into llx_c_type_contact (element, source, code, libelle, active ) values ('shipping', 'external', 'SHIPPING', 'Loading facility', 1); -insert into llx_c_type_contact (element, source, code, libelle, active ) values ('shipping', 'external', 'DELIVERY', 'Delivery facility', 1); +INSERT INTO llx_c_type_contact (element, source, code, libelle, active ) VALUES ('shipping', 'internal', 'SALESREPFOLL', 'Representative following-up shipping', 1); +INSERT INTO llx_c_type_contact (element, source, code, libelle, active ) VALUES ('shipping', 'external', 'BILLING', 'Customer invoice contact', 1); +INSERT INTO llx_c_type_contact (element, source, code, libelle, active ) VALUES ('shipping', 'external', 'CUSTOMER', 'Customer shipping contact', 1); +INSERT INTO llx_c_type_contact (element, source, code, libelle, active ) VALUES ('shipping', 'external', 'SHIPPING', 'Loading facility', 1); +INSERT INTO llx_c_type_contact (element, source, code, libelle, active ) VALUES ('shipping', 'external', 'DELIVERY', 'Delivery facility', 1); ALTER TABLE llx_holiday_config DROP INDEX idx_holiday_config; ALTER TABLE llx_holiday_config ADD COLUMN entity integer DEFAULT 1 NOT NULL AFTER rowid; diff --git a/htdocs/langs/en_US/propal.lang b/htdocs/langs/en_US/propal.lang index 1b4f57d49c9..e08c7fbb26d 100644 --- a/htdocs/langs/en_US/propal.lang +++ b/htdocs/langs/en_US/propal.lang @@ -77,7 +77,7 @@ AvailabilityTypeAV_1W=1 week AvailabilityTypeAV_2W=2 weeks AvailabilityTypeAV_3W=3 weeks AvailabilityTypeAV_1M=1 month -##### Types ofe contacts ##### +##### Types of contacts ##### TypeContact_propal_internal_SALESREPFOLL=Representative following-up proposal TypeContact_propal_external_BILLING=Customer invoice contact TypeContact_propal_external_CUSTOMER=Customer contact following-up proposal diff --git a/htdocs/langs/en_US/sendings.lang b/htdocs/langs/en_US/sendings.lang index 95406dcc87e..fe9fdc20532 100644 --- a/htdocs/langs/en_US/sendings.lang +++ b/htdocs/langs/en_US/sendings.lang @@ -83,3 +83,9 @@ ShipmentDistribution=Shipment distribution ErrorTooManyCombinationBatchcode=No dispatch for line %s as too many combinations of warehouse, product, batch code was found (%s). ErrorNoCombinationBatchcode=Could not save the line %s as the combination of warehouse-product-lot/serial (%s, %s, %s) was not found in stock. ErrorTooMuchShipped=Quantity shipped should not be greater than quantity ordered for line %s +##### Types of contacts ##### +TypeContact_shipping_internal_SALESREPFOLL=Representative following-up shipping +TypeContact_shipping_external_BILLING=Customer invoice contact +TypeContact_shipping_external_CUSTOMER=Customer contact following-up shipping +TypeContact_shipping_external_SHIPPING=Customer contact for shipping +TypeContact_shipping_external_DELIVERY=Customer contact for delivery From 0eb75b7e4fc3004d3cccaf82953becfe10c124dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 29 Jan 2025 09:28:36 +0100 Subject: [PATCH 153/383] dict type contact --- htdocs/comm/propal/class/propal.class.php | 4 ++-- htdocs/install/mysql/data/llx_c_type_contact.sql | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index eb81c4c084e..070f9914417 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -713,9 +713,9 @@ class Propal extends CommonObject $product = new Product($this->db); $result = $product->fetch($fk_product); if ($qty < $product->packaging) { - $qty = $product->packaging; + $qty = (float) $product->packaging; } else { - if (!empty($product->packaging) && (fmod((float) $qty, $product->packaging) > 0.000001)) { + if (!empty($product->packaging) && (fmod((float) $qty, (float) $product->packaging) > 0.000001)) { $coeff = intval((float) $qty / $product->packaging) + 1; $qty = (float) $product->packaging * $coeff; setEventMessages($langs->trans('QtyRecalculatedWithPackaging'), null, 'mesgs'); diff --git a/htdocs/install/mysql/data/llx_c_type_contact.sql b/htdocs/install/mysql/data/llx_c_type_contact.sql index d7bbbf77cf2..6611bd3b5aa 100644 --- a/htdocs/install/mysql/data/llx_c_type_contact.sql +++ b/htdocs/install/mysql/data/llx_c_type_contact.sql @@ -74,7 +74,8 @@ insert into llx_c_type_contact (element, source, code, libelle, active ) values insert into llx_c_type_contact (element, source, code, libelle, active ) values ('commande', 'external', 'SHIPPING', 'Contact client livraison commande', 1); -- Shipment / Expedition -insert into llx_c_type_contact (element, source, code, libelle, active ) values ('shipping', 'internal', 'SALESREPFOLL', 'Responsable suivi de l''expédition', 1); +insert into llx_c_type_contact (element, source, code, libelle, active ) values ('shipping', 'internal', 'SALESREPFOLL', 'Representative following-up shipping', 1); +INSERT INTO llx_c_type_contact (element, source, code, libelle, active ) VALUES ('shipping', 'external', 'BILLING', 'Customer invoice contact', 1); insert into llx_c_type_contact (element, source, code, libelle, active ) values ('shipping', 'external', 'CUSTOMER', 'Customer shipping contact', 1); insert into llx_c_type_contact (element, source, code, libelle, active ) values ('shipping', 'external', 'SHIPPING', 'Loading facility', 1); insert into llx_c_type_contact (element, source, code, libelle, active ) values ('shipping', 'external', 'DELIVERY', 'Delivery facility', 1); From 7bd2bb6efc7071ee2f4f74d1663865df14c04b4d Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Wed, 29 Jan 2025 09:35:37 +0100 Subject: [PATCH 154/383] FIX DROP INDEX IF EXISTS is not possible ! --- htdocs/core/class/extrafields.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index 4cfb2fed5db..9b1f5921740 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -749,7 +749,7 @@ class ExtraFields $sql = "ALTER TABLE ".$this->db->prefix().$table." ADD UNIQUE INDEX uk_".$table."_".$this->db->sanitize($attrname)." (".$this->db->sanitize($attrname).")"; } else { dol_syslog(get_class($this).'::update_common', LOG_DEBUG); - $sql = "ALTER TABLE ".$this->db->prefix().$table." DROP INDEX IF EXISTS uk_".$table."_".$this->db->sanitize($attrname); + $sql = "ALTER TABLE ".$this->db->prefix().$table." DROP INDEX uk_".$table."_".$this->db->sanitize($attrname); } dol_syslog(get_class($this).'::update', LOG_DEBUG); $resql = $this->db->query($sql, 1, 'dml'); From f3dc94d3345867b732fcb17a712b043f931a0c44 Mon Sep 17 00:00:00 2001 From: Irvine Fleith Date: Wed, 29 Jan 2025 10:14:46 +0100 Subject: [PATCH 155/383] fix(services-list): added missing hook printFieldListSearchParam --- htdocs/contrat/services_list.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/htdocs/contrat/services_list.php b/htdocs/contrat/services_list.php index 0b3666a295e..70dc312c2be 100644 --- a/htdocs/contrat/services_list.php +++ b/htdocs/contrat/services_list.php @@ -442,6 +442,10 @@ if ($optioncss != '') { } // Add $param from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; +// Add $param from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object, $action); // Note that $action and $object may have been modified by hook +$param .= $hookmanager->resPrint; // List of mass actions available $arrayofmassactions = array( From 3c7327a457738acfe503bf4afad0675c8332ee68 Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Wed, 29 Jan 2025 12:35:27 +0100 Subject: [PATCH 156/383] Missing notes --- htdocs/core/modules/modProjet.class.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/htdocs/core/modules/modProjet.class.php b/htdocs/core/modules/modProjet.class.php index d58edcf7de2..bed2e414cc6 100644 --- a/htdocs/core/modules/modProjet.class.php +++ b/htdocs/core/modules/modProjet.class.php @@ -231,6 +231,7 @@ class modProjet extends DolibarrModules 'p.rowid'=>"Numeric", 'p.ref'=>"Text", 'p.title'=>"Text", 'p.usage_opportunity'=>'Boolean', 'p.usage_task'=>'Boolean', 'p.usage_bill_time'=>'Boolean', 'p.datec'=>"Date", 'p.dateo'=>"Date", 'p.datee'=>"Date", 'p.fk_statut'=>'Status', 'cls.code'=>"Text", 'p.opp_percent'=>'Numeric', 'p.opp_amount'=>'Numeric', 'p.description'=>"Text", 'p.entity'=>'Numeric', 'p.budget_amount'=>'Numeric', + 'p.note_public'=>'Text', 'p.note_private'=>'Text', 'pt.rowid'=>'Numeric', 'pt.ref'=>'Text', 'pt.label'=>'Text', 'pt.dateo'=>"Date", 'pt.datee'=>"Date", 'pt.duration_effective'=>"Duree", 'pt.planned_workload'=>"Numeric", 'pt.progress'=>"Numeric", 'pt.description'=>"Text", 'ptt.rowid'=>'Numeric', 'ptt.element_date'=>'Date', 'ptt.element_duration'=>"Duree", 'ptt.fk_user'=>"FormSelect:select_dolusers", 'ptt.note'=>"Text" ); @@ -243,7 +244,8 @@ class modProjet extends DolibarrModules 's.phone'=>'Phone', 's.email'=>'Email', 's.siren'=>'ProfId1', 's.siret'=>'ProfId2', 's.ape'=>'ProfId3', 's.idprof4'=>'ProfId4', 's.code_compta'=>'CustomerAccountancyCode', 's.code_compta_fournisseur'=>'SupplierAccountancyCode', 'p.rowid'=>"ProjectId", 'p.ref'=>"RefProject", 'p.title'=>'ProjectLabel', 'p.usage_opportunity'=>'ProjectFollowOpportunity', 'p.usage_task'=>'ProjectFollowTasks', 'p.usage_bill_time'=>'BillTime', - 'p.datec'=>"DateCreation", 'p.dateo'=>"DateStart", 'p.datee'=>"DateEnd", 'p.fk_statut'=>'ProjectStatus', 'cls.code'=>'OpportunityStatus', 'p.opp_percent'=>'OpportunityProbability', 'p.opp_amount'=>'OpportunityAmount', 'p.budget_amount'=>'Budget', 'p.description'=>"Description" + 'p.datec'=>"DateCreation", 'p.dateo'=>"DateStart", 'p.datee'=>"DateEnd", 'p.fk_statut'=>'ProjectStatus', 'cls.code'=>'OpportunityStatus', 'p.opp_percent'=>'OpportunityProbability', 'p.opp_amount'=>'OpportunityAmount', 'p.description'=>"Description", 'p.budget_amount'=>'Budget', + 'p.note_public'=>'NotePublic', 'p.note_private'=>'NotePrivate', ); // Add multicompany field if (getDolGlobalString('MULTICOMPANY_ENTITY_IN_EXPORT_IF_SHARED')) { From f94cfd0d60a80a5f8a2eab641c80330ef8abd489 Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Wed, 29 Jan 2025 13:29:44 +0100 Subject: [PATCH 157/383] Fix position --- htdocs/projet/card.php | 100 ++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/htdocs/projet/card.php b/htdocs/projet/card.php index 4fc99beac08..a62f4437fd6 100644 --- a/htdocs/projet/card.php +++ b/htdocs/projet/card.php @@ -812,31 +812,6 @@ if ($action == 'create' && $user->hasRight('projet', 'creer')) { print ''; } - // Visibility - print ''.$langs->trans("Visibility").''; - $array = array(); - if (!getDolGlobalString('PROJECT_DISABLE_PRIVATE_PROJECT')) { - $array[0] = $langs->trans("PrivateProject"); - } - if (!getDolGlobalString('PROJECT_DISABLE_PUBLIC_PROJECT')) { - $array[1] = $langs->trans("SharedProject"); - } - - if (count($array) > 0) { - print $form->selectarray('public', $array, GETPOSTINT('public') ? 1 : 0, 0, 0, 0, '', 0, 0, 0, '', '', 1); - } else { - print ''; - - if (GETPOSTINT('public') == 0) { - print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); - print $langs->trans("PrivateProject"); - } else { - print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); - print $langs->trans("SharedProject"); - } - } - print ''; - if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES')) { // Opportunity status print ''.$langs->trans("OpportunityStatus").''; @@ -901,6 +876,31 @@ if ($action == 'create' && $user->hasRight('projet', 'creer')) { print ""; } + // Visibility + print ''.$langs->trans("Visibility").''; + $array = array(); + if (!getDolGlobalString('PROJECT_DISABLE_PRIVATE_PROJECT')) { + $array[0] = $langs->trans("PrivateProject"); + } + if (!getDolGlobalString('PROJECT_DISABLE_PUBLIC_PROJECT')) { + $array[1] = $langs->trans("SharedProject"); + } + + if (count($array) > 0) { + print $form->selectarray('public', $array, GETPOSTINT('public') ? 1 : 0, 0, 0, 0, '', 0, 0, 0, '', '', 1); + } else { + print ''; + + if (GETPOSTINT('public') == 0) { + print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); + print $langs->trans("PrivateProject"); + } else { + print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); + print $langs->trans("SharedProject"); + } + } + print ''; + // Selection of Owner contact type print ''.$langs->trans("ProjectContactTypeManager").''; print ''; @@ -1210,31 +1210,6 @@ if ($action == 'create' && $user->hasRight('projet', 'creer')) { print ''; } - // Visibility - print ''.$langs->trans("Visibility").''; - $array = array(); - if (!getDolGlobalString('PROJECT_DISABLE_PRIVATE_PROJECT')) { - $array[0] = $langs->trans("PrivateProject"); - } - if (!getDolGlobalString('PROJECT_DISABLE_PUBLIC_PROJECT')) { - $array[1] = $langs->trans("SharedProject"); - } - - if (count($array) > 0) { - print $form->selectarray('public', $array, $object->public, 0, 0, 0, '', 0, 0, 0, '', '', 1); - } else { - print ''; - - if ($object->public == 0) { - print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); - print $langs->trans("PrivateProject"); - } else { - print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); - print $langs->trans("SharedProject"); - } - } - print ''; - if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES')) { $classfortr = ($object->usage_opportunity ? '' : ' hideobject'); // Opportunity status @@ -1322,6 +1297,31 @@ if ($action == 'create' && $user->hasRight('projet', 'creer')) { print ""; } + // Visibility + print ''.$langs->trans("Visibility").''; + $array = array(); + if (!getDolGlobalString('PROJECT_DISABLE_PRIVATE_PROJECT')) { + $array[0] = $langs->trans("PrivateProject"); + } + if (!getDolGlobalString('PROJECT_DISABLE_PUBLIC_PROJECT')) { + $array[1] = $langs->trans("SharedProject"); + } + + if (count($array) > 0) { + print $form->selectarray('public', $array, $object->public, 0, 0, 0, '', 0, 0, 0, '', '', 1); + } else { + print ''; + + if ($object->public == 0) { + print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); + print $langs->trans("PrivateProject"); + } else { + print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); + print $langs->trans("SharedProject"); + } + } + print ''; + // Other options $parameters = array(); $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook From a121e52d82f62fa4c323069eb362cda8181f6c1d Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Wed, 29 Jan 2025 13:29:44 +0100 Subject: [PATCH 158/383] Fix position --- htdocs/projet/card.php | 100 ++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/htdocs/projet/card.php b/htdocs/projet/card.php index 0eb947f56a6..6fdd27c568c 100644 --- a/htdocs/projet/card.php +++ b/htdocs/projet/card.php @@ -812,31 +812,6 @@ if ($action == 'create' && $user->hasRight('projet', 'creer')) { print ''; } - // Visibility - print ''.$langs->trans("Visibility").''; - $array = array(); - if (!getDolGlobalString('PROJECT_DISABLE_PRIVATE_PROJECT')) { - $array[0] = $langs->trans("PrivateProject"); - } - if (!getDolGlobalString('PROJECT_DISABLE_PUBLIC_PROJECT')) { - $array[1] = $langs->trans("SharedProject"); - } - - if (count($array) > 0) { - print $form->selectarray('public', $array, GETPOSTINT('public') ? 1 : 0, 0, 0, 0, '', 0, 0, 0, '', '', 1); - } else { - print ''; - - if (GETPOSTINT('public') == 0) { - print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); - print $langs->trans("PrivateProject"); - } else { - print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); - print $langs->trans("SharedProject"); - } - } - print ''; - if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES')) { // Opportunity status print ''.$langs->trans("OpportunityStatus").''; @@ -901,6 +876,31 @@ if ($action == 'create' && $user->hasRight('projet', 'creer')) { print ""; } + // Visibility + print ''.$langs->trans("Visibility").''; + $array = array(); + if (!getDolGlobalString('PROJECT_DISABLE_PRIVATE_PROJECT')) { + $array[0] = $langs->trans("PrivateProject"); + } + if (!getDolGlobalString('PROJECT_DISABLE_PUBLIC_PROJECT')) { + $array[1] = $langs->trans("SharedProject"); + } + + if (count($array) > 0) { + print $form->selectarray('public', $array, GETPOSTINT('public') ? 1 : 0, 0, 0, 0, '', 0, 0, 0, '', '', 1); + } else { + print ''; + + if (GETPOSTINT('public') == 0) { + print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); + print $langs->trans("PrivateProject"); + } else { + print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); + print $langs->trans("SharedProject"); + } + } + print ''; + // Selection of Owner contact type print ''.$langs->trans("ProjectContactTypeManager").''; print ''; @@ -1210,31 +1210,6 @@ if ($action == 'create' && $user->hasRight('projet', 'creer')) { print ''; } - // Visibility - print ''.$langs->trans("Visibility").''; - $array = array(); - if (!getDolGlobalString('PROJECT_DISABLE_PRIVATE_PROJECT')) { - $array[0] = $langs->trans("PrivateProject"); - } - if (!getDolGlobalString('PROJECT_DISABLE_PUBLIC_PROJECT')) { - $array[1] = $langs->trans("SharedProject"); - } - - if (count($array) > 0) { - print $form->selectarray('public', $array, $object->public, 0, 0, 0, '', 0, 0, 0, '', '', 1); - } else { - print ''; - - if ($object->public == 0) { - print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); - print $langs->trans("PrivateProject"); - } else { - print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); - print $langs->trans("SharedProject"); - } - } - print ''; - if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES')) { $classfortr = ($object->usage_opportunity ? '' : ' hideobject'); // Opportunity status @@ -1322,6 +1297,31 @@ if ($action == 'create' && $user->hasRight('projet', 'creer')) { print ""; } + // Visibility + print ''.$langs->trans("Visibility").''; + $array = array(); + if (!getDolGlobalString('PROJECT_DISABLE_PRIVATE_PROJECT')) { + $array[0] = $langs->trans("PrivateProject"); + } + if (!getDolGlobalString('PROJECT_DISABLE_PUBLIC_PROJECT')) { + $array[1] = $langs->trans("SharedProject"); + } + + if (count($array) > 0) { + print $form->selectarray('public', $array, $object->public, 0, 0, 0, '', 0, 0, 0, '', '', 1); + } else { + print ''; + + if ($object->public == 0) { + print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); + print $langs->trans("PrivateProject"); + } else { + print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); + print $langs->trans("SharedProject"); + } + } + print ''; + // Other options $parameters = array(); $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook From 9870069f44f25c6774134aa7dc4ba9099c368bea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 29 Jan 2025 13:56:46 +0100 Subject: [PATCH 159/383] more fields in liste_contacts --- htdocs/core/class/commonobject.class.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 3aa18de36e9..02cee9b9716 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -1500,14 +1500,14 @@ abstract class CommonObject $sql = "SELECT ec.rowid, ec.statut as statuslink, ec.fk_socpeople as id, ec.fk_c_type_contact"; // This field contains id of llx_socpeople or id of llx_user if ($source == 'internal') { - $sql .= ", '-1' as socid, t.statut as statuscontact, t.login, t.photo, t.gender"; + $sql .= ", '-1' as socid, t.statut as statuscontact, t.login, t.photo, t.gender, t.fk_country as country_id"; } if ($source == 'external' || $source == 'thirdparty') { - $sql .= ", t.fk_soc as socid, t.statut as statuscontact"; + $sql .= ", t.fk_soc as socid, t.statut as statuscontact, t.fk_pays as country_id"; } - $sql .= ", t.civility as civility, t.lastname as lastname, t.firstname, t.email"; + $sql .= ", t.civility as civility, t.lastname as lastname, t.firstname, t.email, t.address, t.zip, t.town"; if (empty($arrayoftcids)) { - $sql .= ", tc.source, tc.element, tc.code, tc.libelle as type_label"; + $sql .= ", tc.source, tc.element, tc.code, tc.libelle as type_label, co.label as country"; } $sql .= " FROM"; if (empty($arrayoftcids)) { @@ -1516,9 +1516,11 @@ abstract class CommonObject $sql .= " ".$this->db->prefix()."element_contact as ec"; if ($source == 'internal') { // internal contact (user) $sql .= " LEFT JOIN ".$this->db->prefix()."user as t on ec.fk_socpeople = t.rowid"; + $sql .= " LEFT JOIN ".$this->db->prefix()."c_country as co ON co.rowid = t.fk_country"; } if ($source == 'external' || $source == 'thirdparty') { // external contact (socpeople) $sql .= " LEFT JOIN ".$this->db->prefix()."socpeople as t on ec.fk_socpeople = t.rowid"; + $sql .= " LEFT JOIN ".$this->db->prefix()."c_country as co ON co.rowid = t.fk_pays"; } $sql .= " WHERE ec.element_id = ".((int) $this->id); if (empty($arrayoftcids)) { @@ -1566,6 +1568,11 @@ abstract class CommonObject 'lastname' => $obj->lastname, 'firstname' => $obj->firstname, 'email' => $obj->email, + 'address' => $obj->address, + 'zip' => $obj->zip, + 'town' => $obj->town, + 'country_id' => $obj->country_id, + 'country' => $obj->country, 'login' => (empty($obj->login) ? '' : $obj->login), 'photo' => (empty($obj->photo) ? '' : $obj->photo), 'gender' => (empty($obj->gender) ? '' : $obj->gender), From cad040a96d6953b80889d6336392f6cf5ef4f1fe Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Wed, 29 Jan 2025 14:08:48 +0100 Subject: [PATCH 160/383] Debug v21 - print of description --- htdocs/projet/card.php | 39 +++++++++++++++-------------- htdocs/projet/contact.php | 37 ++++++++++++++++------------ htdocs/projet/element.php | 37 ++++++++++++++++------------ htdocs/projet/tasks.php | 37 ++++++++++++++++------------ htdocs/projet/tasks/contact.php | 42 +++++++++++++++++++------------- htdocs/projet/tasks/document.php | 42 +++++++++++++++++++------------- htdocs/projet/tasks/note.php | 42 +++++++++++++++++++------------- htdocs/projet/tasks/task.php | 42 +++++++++++++++++++------------- htdocs/projet/tasks/time.php | 37 ++++++++++++++++------------ htdocs/theme/eldy/global.inc.php | 2 +- 10 files changed, 206 insertions(+), 151 deletions(-) diff --git a/htdocs/projet/card.php b/htdocs/projet/card.php index 6fdd27c568c..fea8f4ce90e 100644 --- a/htdocs/projet/card.php +++ b/htdocs/projet/card.php @@ -1409,17 +1409,6 @@ if ($action == 'create' && $user->hasRight('projet', 'creer')) { print ''; } - // Visibility - print ''.$langs->trans("Visibility").''; - if ($object->public) { - print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); - print $langs->trans('SharedProject'); - } else { - print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); - print $langs->trans('PrivateProject'); - } - print ''; - if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES') && !empty($object->usage_opportunity)) { // Opportunity status print ''.$langs->trans("OpportunityStatus"); @@ -1463,6 +1452,17 @@ if ($action == 'create' && $user->hasRight('projet', 'creer')) { } print ''; + // Visibility + print ''.$langs->trans("Visibility").''; + if ($object->public) { + print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); + print $langs->trans('SharedProject'); + } else { + print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); + print $langs->trans('PrivateProject'); + } + print ''; + // Other attributes $cols = 2; include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php'; @@ -1475,13 +1475,6 @@ if ($action == 'create' && $user->hasRight('projet', 'creer')) { print ''; - // Description - print ''; - // Categories if (isModEnabled('category')) { print '"; } + // Description + print ''; + if ($object->description) { + print ''; + } + print '
'.$langs->trans("Description").''; - print '
'; - print dolPrintHTML($object->description); - print '
'; - print '
'.$langs->trans("Categories").''; @@ -1489,6 +1482,16 @@ if ($action == 'create' && $user->hasRight('projet', 'creer')) { print "
'.$langs->trans("Description").'
'; + print '
'; + print dolPrintHTML($object->description); + print '
'; + print '
'; print '
'; diff --git a/htdocs/projet/contact.php b/htdocs/projet/contact.php index 4f2dde28a50..f04c1df9ae6 100644 --- a/htdocs/projet/contact.php +++ b/htdocs/projet/contact.php @@ -424,17 +424,6 @@ if ($id > 0 || !empty($ref)) { print ''; } - // Visibility - print ''.$langs->trans("Visibility").''; - if ($object->public) { - print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); - print $langs->trans('SharedProject'); - } else { - print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); - print $langs->trans('PrivateProject'); - } - print ''; - if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES') && !empty($object->usage_opportunity)) { // Opportunity status print ''.$langs->trans("OpportunityStatus").''; @@ -480,6 +469,17 @@ if ($id > 0 || !empty($ref)) { } print ''; + // Visibility + print ''.$langs->trans("Visibility").''; + if ($object->public) { + print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); + print $langs->trans('SharedProject'); + } else { + print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); + print $langs->trans('PrivateProject'); + } + print ''; + // Other attributes $cols = 2; include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php'; @@ -492,11 +492,6 @@ if ($id > 0 || !empty($ref)) { print ''; - // Description - print ''; - // Categories if (isModEnabled('category')) { print '"; } + // Description + print ''; + if ($object->description) { + print ''; + } + print '
'.$langs->trans("Description").''; - print dol_htmlentitiesbr($object->description); - print '
'.$langs->trans("Categories").''; @@ -504,6 +499,16 @@ if ($id > 0 || !empty($ref)) { print "
'.$langs->trans("Description").'
'; + print '
'; + print dolPrintHTML($object->description); + print '
'; + print '
'; print ''; diff --git a/htdocs/projet/element.php b/htdocs/projet/element.php index f4ffea34d18..80af93b7cd0 100644 --- a/htdocs/projet/element.php +++ b/htdocs/projet/element.php @@ -311,17 +311,6 @@ if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES') || !getDolGlobalString('PROJ print ''; } -// Visibility -print ''.$langs->trans("Visibility").''; -if ($object->public) { - print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); - print $langs->trans('SharedProject'); -} else { - print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); - print $langs->trans('PrivateProject'); -} -print ''; - if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES')) { // Opportunity status print ''.$langs->trans("OpportunityStatus").''; @@ -368,6 +357,17 @@ if ($object->hasDelay()) { } print ''; +// Visibility +print ''.$langs->trans("Visibility").''; +if ($object->public) { + print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); + print $langs->trans('SharedProject'); +} else { + print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); + print $langs->trans('PrivateProject'); +} +print ''; + // Other attributes $cols = 2; include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php'; @@ -380,11 +380,6 @@ print '
'; print ''; -// Description -print ''; - // Categories if (isModEnabled('category')) { print '"; } +// Description +print ''; +if ($object->description) { + print ''; +} + print '
'.$langs->trans("Description").''; -print dol_htmlentitiesbr($object->description); -print '
'.$langs->trans("Categories").''; @@ -392,6 +387,16 @@ if (isModEnabled('category')) { print "
'.$langs->trans("Description").'
'; + print '
'; + print dolPrintHTML($object->description); + print '
'; + print '
'; print ''; diff --git a/htdocs/projet/tasks.php b/htdocs/projet/tasks.php index 2dde9cf51ed..4cd188910ec 100644 --- a/htdocs/projet/tasks.php +++ b/htdocs/projet/tasks.php @@ -660,17 +660,6 @@ if ($id > 0 || !empty($ref)) { print ''; } - // Visibility - print ''.$langs->trans("Visibility").''; - if ($object->public) { - print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); - print $langs->trans('SharedProject'); - } else { - print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); - print $langs->trans('PrivateProject'); - } - print ''; - // Budget print ''.$langs->trans("Budget").''; if (!is_null($object->budget_amount) && strcmp($object->budget_amount, '')) { @@ -690,6 +679,17 @@ if ($id > 0 || !empty($ref)) { } print ''; + // Visibility + print ''.$langs->trans("Visibility").''; + if ($object->public) { + print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); + print $langs->trans('SharedProject'); + } else { + print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); + print $langs->trans('PrivateProject'); + } + print ''; + // Other attributes $cols = 2; include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php'; @@ -702,11 +702,6 @@ if ($id > 0 || !empty($ref)) { print ''; - // Description - print ''; - // Categories if (isModEnabled('category')) { print '"; } + // Description + print ''; + if ($object->description) { + print ''; + } + print '
'.$langs->trans("Description").''; - print dol_htmlentitiesbr($object->description); - print '
'.$langs->trans("Categories").''; @@ -714,6 +709,16 @@ if ($id > 0 || !empty($ref)) { print "
'.$langs->trans("Description").'
'; + print '
'; + print dolPrintHTML($object->description); + print '
'; + print '
'; print ''; diff --git a/htdocs/projet/tasks/contact.php b/htdocs/projet/tasks/contact.php index f829533062a..ef379748e77 100644 --- a/htdocs/projet/tasks/contact.php +++ b/htdocs/projet/tasks/contact.php @@ -255,17 +255,6 @@ if ($id > 0 || !empty($ref)) { print ''; } - // Visibility - print ''.$langs->trans("Visibility").''; - if ($projectstatic->public) { - print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); - print $langs->trans('SharedProject'); - } else { - print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); - print $langs->trans('PrivateProject'); - } - print ''; - // Budget print ''.$langs->trans("Budget").''; if (isset($projectstatic->budget_amount) && strcmp($projectstatic->budget_amount, '')) { @@ -285,9 +274,23 @@ if ($id > 0 || !empty($ref)) { } print ''; + // Visibility + print ''.$langs->trans("Visibility").''; + if ($projectstatic->public) { + print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); + print $langs->trans('SharedProject'); + } else { + print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); + print $langs->trans('PrivateProject'); + } + print ''; + // Other attributes $cols = 2; - //include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + $savobject = $object; + $object = $projectstatic; + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + $object = $savobject; print ''; @@ -297,11 +300,6 @@ if ($id > 0 || !empty($ref)) { print ''; - // Description - print ''; - // Categories if (isModEnabled('category')) { print '"; } + // Description + print ''; + if ($projectstatic->description) { + print ''; + } + print '
'.$langs->trans("Description").''; - print nl2br($projectstatic->description); - print '
'.$langs->trans("Categories").''; @@ -309,6 +307,16 @@ if ($id > 0 || !empty($ref)) { print "
'.$langs->trans("Description").'
'; + print '
'; + print dolPrintHTML($projectstatic->description); + print '
'; + print '
'; print ''; diff --git a/htdocs/projet/tasks/document.php b/htdocs/projet/tasks/document.php index 8f091a04a5e..a85d451efa8 100644 --- a/htdocs/projet/tasks/document.php +++ b/htdocs/projet/tasks/document.php @@ -212,17 +212,6 @@ if ($object->id > 0) { print ''; } - // Visibility - print ''.$langs->trans("Visibility").''; - if ($projectstatic->public) { - print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); - print $langs->trans('SharedProject'); - } else { - print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); - print $langs->trans('PrivateProject'); - } - print ''; - // Budget print ''.$langs->trans("Budget").''; if (isset($projectstatic->budget_amount) && strcmp($projectstatic->budget_amount, '')) { @@ -242,9 +231,23 @@ if ($object->id > 0) { } print ''; + // Visibility + print ''.$langs->trans("Visibility").''; + if ($projectstatic->public) { + print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); + print $langs->trans('SharedProject'); + } else { + print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); + print $langs->trans('PrivateProject'); + } + print ''; + // Other attributes $cols = 2; - //include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + $savobject = $object; + $object = $projectstatic; + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + $object = $savobject; print ''; @@ -254,11 +257,6 @@ if ($object->id > 0) { print ''; - // Description - print ''; - // Categories if (isModEnabled('category')) { print '"; } + // Description + print ''; + if ($projectstatic->description) { + print ''; + } + print '
'.$langs->trans("Description").''; - print nl2br($projectstatic->description); - print '
'.$langs->trans("Categories").''; @@ -266,6 +264,16 @@ if ($object->id > 0) { print "
'.$langs->trans("Description").'
'; + print '
'; + print dolPrintHTML($projectstatic->description); + print '
'; + print '
'; print ''; diff --git a/htdocs/projet/tasks/note.php b/htdocs/projet/tasks/note.php index 673c820368b..c938650cef5 100644 --- a/htdocs/projet/tasks/note.php +++ b/htdocs/projet/tasks/note.php @@ -202,17 +202,6 @@ if ($object->id > 0) { print ''; } - // Visibility - print ''.$langs->trans("Visibility").''; - if ($projectstatic->public) { - print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); - print $langs->trans('SharedProject'); - } else { - print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); - print $langs->trans('PrivateProject'); - } - print ''; - // Budget print ''.$langs->trans("Budget").''; if (isset($projectstatic->budget_amount) && strcmp($projectstatic->budget_amount, '')) { @@ -232,9 +221,23 @@ if ($object->id > 0) { } print ''; + // Visibility + print ''.$langs->trans("Visibility").''; + if ($projectstatic->public) { + print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); + print $langs->trans('SharedProject'); + } else { + print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); + print $langs->trans('PrivateProject'); + } + print ''; + // Other attributes $cols = 2; - //include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + $savobject = $object; + $object = $projectstatic; + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + $object = $savobject; print ''; @@ -244,11 +247,6 @@ if ($object->id > 0) { print ''; - // Description - print ''; - // Categories if (isModEnabled('category')) { print '"; } + // Description + print ''; + if ($projectstatic->description) { + print ''; + } + print '
'.$langs->trans("Description").''; - print nl2br($projectstatic->description); - print '
'.$langs->trans("Categories").''; @@ -256,6 +254,16 @@ if ($object->id > 0) { print "
'.$langs->trans("Description").'
'; + print '
'; + print dolPrintHTML($projectstatic->description); + print '
'; + print '
'; print ''; diff --git a/htdocs/projet/tasks/task.php b/htdocs/projet/tasks/task.php index 494e3f20774..8eaa2bb9062 100644 --- a/htdocs/projet/tasks/task.php +++ b/htdocs/projet/tasks/task.php @@ -361,17 +361,6 @@ if ($id > 0 || !empty($ref)) { print ''; } - // Visibility - print ''.$langs->trans("Visibility").''; - if ($projectstatic->public) { - print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); - print $langs->trans('SharedProject'); - } else { - print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); - print $langs->trans('PrivateProject'); - } - print ''; - // Budget print ''.$langs->trans("Budget").''; if (isset($projectstatic->budget_amount) && strcmp($projectstatic->budget_amount, '')) { @@ -391,9 +380,23 @@ if ($id > 0 || !empty($ref)) { } print ''; + // Visibility + print ''.$langs->trans("Visibility").''; + if ($projectstatic->public) { + print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); + print $langs->trans('SharedProject'); + } else { + print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); + print $langs->trans('PrivateProject'); + } + print ''; + // Other attributes $cols = 2; - //include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + $savobject = $object; + $object = $projectstatic; + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + $object = $savobject; print ''; @@ -404,11 +407,6 @@ if ($id > 0 || !empty($ref)) { print ''; - // Description - print ''; - // Categories if (isModEnabled('category')) { print '"; } + // Description + print ''; + if ($projectstatic->description) { + print ''; + } + print '
'.$langs->trans("Description").''; - print nl2br($projectstatic->description); - print '
'.$langs->trans("Categories").''; @@ -416,6 +414,16 @@ if ($id > 0 || !empty($ref)) { print "
'.$langs->trans("Description").'
'; + print '
'; + print dolPrintHTML($projectstatic->description); + print '
'; + print '
'; print ''; diff --git a/htdocs/projet/tasks/time.php b/htdocs/projet/tasks/time.php index e72ccc48706..568cf922cd5 100644 --- a/htdocs/projet/tasks/time.php +++ b/htdocs/projet/tasks/time.php @@ -1002,17 +1002,6 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser print ''; } - // Visibility - print '' . $langs->trans("Visibility") . ''; - if ($projectstatic->public) { - print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); - print $langs->trans('SharedProject'); - } else { - print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); - print $langs->trans('PrivateProject'); - } - print ''; - // Budget print '' . $langs->trans("Budget") . ''; if (!is_null($projectstatic->budget_amount) && strcmp($projectstatic->budget_amount, '')) { @@ -1032,6 +1021,17 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser } print ''; + // Visibility + print '' . $langs->trans("Visibility") . ''; + if ($projectstatic->public) { + print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); + print $langs->trans('SharedProject'); + } else { + print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); + print $langs->trans('PrivateProject'); + } + print ''; + // Other attributes $cols = 2; $savobject = $object; @@ -1047,11 +1047,6 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser print ''; - // Description - print ''; - // Categories if (isModEnabled('category')) { print '"; } + // Description + print ''; + if ($projectstatic->description) { + print ''; + } + print '
'.$langs->trans("Description").''; - print dol_htmlentitiesbr($projectstatic->description); - print '
' . $langs->trans("Categories") . ''; @@ -1059,6 +1054,16 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser print "
'.$langs->trans("Description").'
'; + print '
'; + print dolPrintHTML($projectstatic->description); + print '
'; + print '
'; print ''; diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index d94ade62111..46f5c1ddf45 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -2313,7 +2313,7 @@ datalist { .linkobject { cursor: pointer; } -table.tableforfield tr:not(.liste_titre)>td:first-of-type, tr.trforfield:not(.liste_titre)>td:first-of-type, div.tableforfield div.tagtr:not(.liste_titre)>div.tagtd:first-of-type { +table.tableforfield tr:not(.liste_titre)>td:first-of-type:not(.nottitleforfield), tr.trforfield:not(.liste_titre)>td:first-of-type, div.tableforfield div.tagtr:not(.liste_titre)>div.tagtd:first-of-type { color: var(--tableforfieldcolor); } From 710b5d3405c75ac6922821efc34d49380d7d2fa8 Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Wed, 29 Jan 2025 14:15:08 +0100 Subject: [PATCH 161/383] Debug v21 --- .../conferenceorbooth_list.php | 37 +++++++++++-------- .../conferenceorboothattendee_list.php | 37 +++++++++++-------- htdocs/projet/element.php | 2 +- 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/htdocs/eventorganization/conferenceorbooth_list.php b/htdocs/eventorganization/conferenceorbooth_list.php index 46bb260a6be..020aecc753f 100644 --- a/htdocs/eventorganization/conferenceorbooth_list.php +++ b/htdocs/eventorganization/conferenceorbooth_list.php @@ -385,17 +385,6 @@ if ($projectid > 0) { print ''; } - // Visibility - print ''.$langs->trans("Visibility").''; - if ($project->public == 0) { - print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); - print $langs->trans("PrivateProject"); - } else { - print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); - print $langs->trans("SharedProject"); - } - print ''; - // Budget print ''.$langs->trans("Budget").''; if (strcmp($project->budget_amount, '')) { @@ -432,6 +421,17 @@ if ($projectid > 0) { print $project->location; print ''; + // Visibility + print ''.$langs->trans("Visibility").''; + if ($project->public == 0) { + print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); + print $langs->trans("PrivateProject"); + } else { + print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); + print $langs->trans("SharedProject"); + } + print ''; + // Other attributes $cols = 2; $objectconf = $object; @@ -447,11 +447,6 @@ if ($projectid > 0) { print ''; - // Description - print ''; - // Categories if (isModEnabled('category')) { print '"; } + // Description + print ''; + if ($project->description) { + print ''; + } + print ''; } - // Visibility - print ''; - // Budget print ''; + // Visibility + print ''; + // Location event print '
'.$langs->trans("Description").''; - print dol_htmlentitiesbr($project->description); - print '
'.$langs->trans("Categories").''; @@ -459,6 +454,16 @@ if ($projectid > 0) { print "
'.$langs->trans("Description").'
'; + print '
'; + print dolPrintHTML($project->description); + print '
'; + print '
'; $typeofdata = 'checkbox:'.($project->accept_conference_suggestions ? ' checked="checked"' : ''); $htmltext = $langs->trans("AllowUnknownPeopleSuggestConfHelp"); diff --git a/htdocs/eventorganization/conferenceorboothattendee_list.php b/htdocs/eventorganization/conferenceorboothattendee_list.php index c5934e13ecd..98ea7f6adf9 100644 --- a/htdocs/eventorganization/conferenceorboothattendee_list.php +++ b/htdocs/eventorganization/conferenceorboothattendee_list.php @@ -484,17 +484,6 @@ if ($projectstatic->id > 0 || $confOrBooth > 0) { print '
'.$langs->trans("Visibility").''; - if ($projectstatic->public == 0) { - print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); - print $langs->trans("PrivateProject"); - } else { - print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); - print $langs->trans("SharedProject"); - } - print '
'.$langs->trans("Budget").''; if (strcmp($projectstatic->budget_amount, '')) { @@ -526,6 +515,17 @@ if ($projectstatic->id > 0 || $confOrBooth > 0) { } print '
'.$langs->trans("Visibility").''; + if ($projectstatic->public == 0) { + print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"'); + print $langs->trans("PrivateProject"); + } else { + print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"'); + print $langs->trans("SharedProject"); + } + print '
'.$langs->trans("Location").''; print $projectstatic->location; @@ -547,11 +547,6 @@ if ($projectstatic->id > 0 || $confOrBooth > 0) { print ''; - // Description - print ''; - // Categories if (isModEnabled('category')) { print '"; } + // Description + print ''; + if ($projectstatic->description) { + print ''; + } + print ''; } -if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES')) { +if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES') && !empty($object->usage_opportunity)) { // Opportunity status print ''; if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { - print ''; + print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch actioncolumn '); + $totalarray['nbfield']++; + } + if (!empty($arrayfields['t.rowid']['checked'])) { + print ''; + } + if (!empty($arrayfields['t.libelle']['checked'])) { + print ''; + } + if (!empty($arrayfields['t.morphy']['checked'])) { + print ''; } - print ''; - print ''; - print ''; print ''; print ''; print ''; @@ -353,7 +369,8 @@ if (!$rowid && $action != 'create' && $action != 'edit') { print ''; print ''; if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { - print ''; + print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'maxwidthsearch center '); + $totalarray['nbfield']++; } print "\n"; @@ -397,13 +414,15 @@ if (!$rowid && $action != 'create' && $action != 'edit') { print ''; } } - - print ''; - - print ''; + if (!empty($arrayfields['t.rowid']['checked'])) { + print ''; + } + if (!empty($arrayfields['t.libelle']['checked'])) { + print ''; + } print ''; + $totalarray['nbfield']++; } if (!empty($arrayfields['t.libelle']['checked'])) { print ''; + $totalarray['nbfield']++; } if (!empty($arrayfields['t.morphy']['checked'])) { print ''; + $totalarray['nbfield']++; } print ''; print ''; @@ -423,16 +426,17 @@ if (!$rowid && $action != 'create' && $action != 'edit') { if (!empty($arrayfields['t.libelle']['checked'])) { print ''; } - - print ''; } - print ''; print ''; $totalarray['nbfield']++; } - print ''; + if (!empty($arrayfields['t.duration']['checked'])) { + print ''; + $totalarray['nbfield']++; + } print ''; print ''; print ''; @@ -437,19 +440,20 @@ if (!$rowid && $action != 'create' && $action != 'edit') { } print ''; } - - print ''; } - print ''; print ''; From 0cbedd4ff0a4e8c24b85c7a43eae70ebb37de050 Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Wed, 29 Jan 2025 19:15:57 +0100 Subject: [PATCH 175/383] Fix warnings --- htdocs/comm/propal/class/propal.class.php | 18 ++++++++-------- .../comm/propal/class/propaleligne.class.php | 8 ++----- htdocs/commande/class/commande.class.php | 21 ++++++++----------- htdocs/commande/class/orderline.class.php | 9 ++------ htdocs/compta/facture/class/facture.class.php | 14 ++++++------- .../facture/class/factureligne.class.php | 10 +++------ htdocs/product/class/product.class.php | 15 ++++++------- htdocs/product/price.php | 6 +++--- 8 files changed, 41 insertions(+), 60 deletions(-) diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index eb81c4c084e..2fb35bdcf2f 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -634,7 +634,7 @@ class Propal extends CommonObject */ public function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1 = 0.0, $txlocaltax2 = 0.0, $fk_product = 0, $remise_percent = 0.0, $price_base_type = 'HT', $pu_ttc = 0.0, $info_bits = 0, $type = 0, $rang = -1, $special_code = 0, $fk_parent_line = 0, $fk_fournprice = 0, $pa_ht = 0, $label = '', $date_start = '', $date_end = '', $array_options = array(), $fk_unit = null, $origin = '', $origin_id = 0, $pu_ht_devise = 0, $fk_remise_except = 0, $noupdateafterinsertline = 0) { - global $mysoc, $conf, $langs; + global $mysoc, $langs; dol_syslog(get_class($this)."::addline propalid=$this->id, desc=$desc, pu_ht=$pu_ht, qty=$qty, txtva=$txtva, fk_product=$fk_product, remise_except=$remise_percent, price_base_type=$price_base_type, pu_ttc=$pu_ttc, info_bits=$info_bits, type=$type, fk_remise_except=".$fk_remise_except); @@ -659,7 +659,7 @@ class Propal extends CommonObject } $remise_percent = price2num($remise_percent); - $qty = (float) price2num($qty); + $qty = (float) price2num($qty, 'MS'); $pu_ht = price2num($pu_ht); $pu_ht_devise = price2num($pu_ht_devise); $pu_ttc = price2num($pu_ttc); @@ -710,14 +710,14 @@ class Propal extends CommonObject $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc); if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { - $product = new Product($this->db); - $result = $product->fetch($fk_product); - if ($qty < $product->packaging) { - $qty = $product->packaging; + $tmpproduct = new Product($this->db); + $result = $tmpproduct->fetch($fk_product); + if (abs($qty) < $tmpproduct->packaging) { + $qty = (float) $tmpproduct->packaging; } else { - if (!empty($product->packaging) && (fmod((float) $qty, $product->packaging) > 0.000001)) { - $coeff = intval((float) $qty / $product->packaging) + 1; - $qty = (float) $product->packaging * $coeff; + if (!empty($tmpproduct->packaging) && $qty > $tmpproduct->packaging) { + $coeff = intval(abs($qty) / $tmpproduct->packaging) + 1; + $qty = price2num((float) $tmpproduct->packaging * $coeff, 'MS'); setEventMessages($langs->trans('QtyRecalculatedWithPackaging'), null, 'mesgs'); } } diff --git a/htdocs/comm/propal/class/propaleligne.class.php b/htdocs/comm/propal/class/propaleligne.class.php index 67c941e9851..b976193a0e1 100644 --- a/htdocs/comm/propal/class/propaleligne.class.php +++ b/htdocs/comm/propal/class/propaleligne.class.php @@ -373,10 +373,8 @@ class PropaleLigne extends CommonObjectLine $sql .= ' pd.localtax1_tx, pd.localtax2_tx, pd.total_localtax1, pd.total_localtax2,'; $sql .= ' pd.fk_multicurrency, pd.multicurrency_code, pd.multicurrency_subprice, pd.multicurrency_total_ht, pd.multicurrency_total_tva, pd.multicurrency_total_ttc,'; $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc,'; + $sql .= ' p.packaging,'; $sql .= ' pd.date_start, pd.date_end, pd.product_type'; - if (getDolGlobalInt('PRODUCT_USE_CUSTOMER_PACKAGING')) { - $sql .= ', p.packaging'; - } $sql .= ' FROM '.MAIN_DB_PREFIX.'propaldet as pd'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON pd.fk_product = p.rowid'; $sql .= ' WHERE pd.rowid = '.((int) $rowid); @@ -425,9 +423,7 @@ class PropaleLigne extends CommonObjectLine $this->product_desc = $objp->product_desc; $this->fk_unit = $objp->fk_unit; - if (getDolGlobalInt('PRODUCT_USE_CUSTOMER_PACKAGING')) { - $this->packaging = $objp->packaging; - } + $this->packaging = $objp->packaging; $this->date_start = $this->db->jdate($objp->date_start); $this->date_end = $this->db->jdate($objp->date_end); diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index 71e03085f69..b052263ee7e 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -1635,14 +1635,14 @@ class Commande extends CommonOrder $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc); if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { - $product = new Product($this->db); - $result = $product->fetch($fk_product); - if ($qty < $product->packaging) { - $qty = $product->packaging; + $tmpproduct = new Product($this->db); + $result = $tmpproduct->fetch($fk_product); + if (abs($qty) < $tmpproduct->packaging) { + $qty = (float) $tmpproduct->packaging; } else { - if (!empty($product->packaging) && (fmod((float) $qty, $product->packaging) > 0.000001)) { - $coeff = intval((float) $qty / $product->packaging) + 1; - $qty = (float) $product->packaging * $coeff; + if (!empty($tmpproduct->packaging) && $qty > $tmpproduct->packaging) { + $coeff = intval(abs($qty) / $tmpproduct->packaging) + 1; + $qty = price2num((float) $tmpproduct->packaging * $coeff, 'MS'); setEventMessages($langs->trans('QtyRecalculatedWithPackaging'), null, 'mesgs'); } } @@ -2130,7 +2130,7 @@ class Commande extends CommonOrder $sql .= ' l.fk_unit,'; $sql .= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,'; $sql .= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label, p.tosell as product_tosell, p.tobuy as product_tobuy, p.tobatch as product_tobatch, p.barcode as product_barcode,'; - $sql .= ' p.weight, p.weight_units, p.volume, p.volume_units'; + $sql .= ' p.weight, p.weight_units, p.volume, p.volume_units, p.packaging'; $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line.' as l'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON (p.rowid = l.fk_product)'; $sql .= ' WHERE l.fk_commande = '.((int) $this->id); @@ -2205,10 +2205,7 @@ class Commande extends CommonOrder $line->weight_units = $objp->weight_units; $line->volume = $objp->volume; $line->volume_units = $objp->volume_units; - - if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { - $line->packaging = $objp->packaging; - } + $line->packaging = $objp->packaging; $line->date_start = $this->db->jdate($objp->date_start); $line->date_end = $this->db->jdate($objp->date_end); diff --git a/htdocs/commande/class/orderline.class.php b/htdocs/commande/class/orderline.class.php index 10519dd0cf2..ec78db8e44d 100644 --- a/htdocs/commande/class/orderline.class.php +++ b/htdocs/commande/class/orderline.class.php @@ -174,10 +174,8 @@ class OrderLine extends CommonOrderLine $sql .= ' cd.fk_unit,'; $sql .= ' cd.fk_multicurrency, cd.multicurrency_code, cd.multicurrency_subprice, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc,'; $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc, p.tobatch as product_tobatch,'; + $sql .= ' p.packaging,'; $sql .= ' cd.date_start, cd.date_end, cd.vat_src_code'; - if (getDolGlobalInt('PRODUCT_USE_CUSTOMER_PACKAGING')) { - $sql .= ', p.packaging'; - } $sql .= ' FROM '.MAIN_DB_PREFIX.'commandedet as cd'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON cd.fk_product = p.rowid'; $sql .= ' WHERE cd.rowid = '.((int) $rowid); @@ -231,10 +229,7 @@ class OrderLine extends CommonOrderLine $this->product_desc = $objp->product_desc; $this->product_tobatch = $objp->product_tobatch; $this->fk_unit = $objp->fk_unit; - - if (getDolGlobalInt('PRODUCT_USE_CUSTOMER_PACKAGING')) { - $this->packaging = $objp->packaging; - } + $this->packaging = $objp->packaging; $this->date_start = $this->db->jdate($objp->date_start); $this->date_end = $this->db->jdate($objp->date_end); diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 09dddafbbd5..8307f205204 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -4000,14 +4000,14 @@ class Facture extends CommonInvoice $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc); if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { - $product = new Product($this->db); - $result = $product->fetch($fk_product); - if ($qty < $product->packaging) { - $qty = $product->packaging; + $tmpproduct = new Product($this->db); + $result = $tmpproduct->fetch($fk_product); + if (abs($qty) < $tmpproduct->packaging) { + $qty = (float) $tmpproduct->packaging; } else { - if (!empty($product->packaging) && (fmod((float) $qty, $product->packaging) > 0.000001)) { - $coeff = intval((float) $qty / $product->packaging) + 1; - $qty = (float) $product->packaging * $coeff; + if (!empty($tmpproduct->packaging) && $qty > $tmpproduct->packaging) { + $coeff = intval(abs($qty) / $tmpproduct->packaging) + 1; + $qty = price2num((float) $tmpproduct->packaging * $coeff, 'MS'); setEventMessages($langs->trans('QtyRecalculatedWithPackaging'), null, 'mesgs'); } } diff --git a/htdocs/compta/facture/class/factureligne.class.php b/htdocs/compta/facture/class/factureligne.class.php index c397b5ddf00..c0b69cb14d3 100644 --- a/htdocs/compta/facture/class/factureligne.class.php +++ b/htdocs/compta/facture/class/factureligne.class.php @@ -215,10 +215,8 @@ class FactureLigne extends CommonInvoiceLine $sql .= ' fd.multicurrency_total_ht,'; $sql .= ' fd.multicurrency_total_tva,'; $sql .= ' fd.multicurrency_total_ttc,'; - $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc'; - if (getDolGlobalInt('PRODUCT_USE_CUSTOMER_PACKAGING')) { - $sql .= ', p.packaging'; - } + $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc,'; + $sql .= ' p.packaging'; $sql .= ' FROM '.MAIN_DB_PREFIX.'facturedet as fd'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON fd.fk_product = p.rowid'; $sql .= ' WHERE fd.rowid = '.((int) $rowid); @@ -285,9 +283,7 @@ class FactureLigne extends CommonInvoiceLine $this->multicurrency_total_tva = $objp->multicurrency_total_tva; $this->multicurrency_total_ttc = $objp->multicurrency_total_ttc; - if (getDolGlobalInt('PRODUCT_USE_CUSTOMER_PACKAGING')) { - $this->packaging = $objp->packaging; - } + $this->packaging = $objp->packaging; $this->fetch_optionals(); diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 05d88261d19..46121f12a94 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -1596,8 +1596,8 @@ class Product extends CommonObject $sql .= ", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression : 'NULL'); $sql .= ", fk_user_modif = ".($user->id > 0 ? $user->id : 'NULL'); $sql .= ", mandatory_period = ".($this->mandatory_period); - if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING') && !empty($this->packaging)) { - $sql .= ", packaging = " . (float) $this->packaging; + if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { + $sql .= ", packaging = ".(float) $this->packaging; } // stock field is not here because it is a denormalized value from product_stock. $sql .= " WHERE rowid = ".((int) $id); @@ -2893,15 +2893,12 @@ class Product extends CommonObject $sql .= " p.price_min, p.price_min_ttc, p.price_base_type, p.cost_price, p.default_vat_code, p.tva_tx, p.recuperableonly as tva_npr, p.localtax1_tx, p.localtax2_tx, p.localtax1_type, p.localtax2_type, p.tosell,"; $sql .= " p.tobuy, p.fk_product_type, p.duration, p.fk_default_warehouse, p.fk_default_workstation, p.seuil_stock_alerte, p.canvas, p.net_measure, p.net_measure_units, p.weight, p.weight_units,"; $sql .= " p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.last_main_doc,"; - $sql .= " p.surface, p.surface_units, p.volume, p.volume_units, p.barcode, p.fk_barcode_type, p.finished, p.fk_default_bom, p.mandatory_period,"; + $sql .= " p.surface, p.surface_units, p.volume, p.volume_units, p.barcode, p.fk_barcode_type, p.finished, p.fk_default_bom, p.mandatory_period, p.packaging,"; if (!getDolGlobalString('MAIN_PRODUCT_PERENTITY_SHARED')) { $sql .= " p.accountancy_code_buy, p.accountancy_code_buy_intra, p.accountancy_code_buy_export, p.accountancy_code_sell, p.accountancy_code_sell_intra, p.accountancy_code_sell_export,"; } else { $sql .= " ppe.accountancy_code_buy, ppe.accountancy_code_buy_intra, ppe.accountancy_code_buy_export, ppe.accountancy_code_sell, ppe.accountancy_code_sell_intra, ppe.accountancy_code_sell_export,"; } - if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) { - $sql .= " p.packaging,"; - } // For MultiCompany // PMP per entity & Stocks Sharings stock_reel includes only stocks shared with this entity @@ -2959,7 +2956,7 @@ class Product extends CommonObject $sql .= " p.price_min, p.price_min_ttc, p.price_base_type, p.cost_price, p.default_vat_code, p.tva_tx, p.recuperableonly, p.localtax1_tx, p.localtax2_tx, p.localtax1_type, p.localtax2_type, p.tosell,"; $sql .= " p.tobuy, p.fk_product_type, p.duration, p.fk_default_warehouse, p.fk_default_workstation, p.seuil_stock_alerte, p.canvas, p.net_measure, p.net_measure_units, p.weight, p.weight_units,"; $sql .= " p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,"; - $sql .= " p.surface, p.surface_units, p.volume, p.volume_units, p.barcode, p.fk_barcode_type, p.finished, p.fk_default_bom, p.mandatory_period,"; + $sql .= " p.surface, p.surface_units, p.volume, p.volume_units, p.barcode, p.fk_barcode_type, p.finished, p.fk_default_bom, p.mandatory_period, p.packaging,"; if (!getDolGlobalString('MAIN_PRODUCT_PERENTITY_SHARED')) { $sql .= " p.accountancy_code_buy, p.accountancy_code_buy_intra, p.accountancy_code_buy_export, p.accountancy_code_sell, p.accountancy_code_sell_intra, p.accountancy_code_sell_export,"; } else { @@ -2971,8 +2968,8 @@ class Product extends CommonObject $sql .= " p.pmp,"; } $sql .= " p.datec, p.tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.sell_or_eat_by_mandatory, p.batch_mask, p.fk_unit,"; - $sql .= " p.fk_price_expression, p.price_autogen, p.model_pdf"; - $sql .= " ,p.price_label"; + $sql .= " p.fk_price_expression, p.price_autogen, p.model_pdf,"; + $sql .= " p.price_label"; if (!$separatedStock) { $sql .= ", p.stock"; } diff --git a/htdocs/product/price.php b/htdocs/product/price.php index 2a3dc750d9b..7e455771536 100644 --- a/htdocs/product/price.php +++ b/htdocs/product/price.php @@ -279,12 +279,12 @@ if (empty($reshook)) { $error = 0; $pricestoupdate = array(); - $psq = GETPOST('psqflag'); - $psq = empty($newpsq) ? 0 : $newpsq; + $psq = GETPOSTINT('psqflag'); + $maxpricesupplier = $object->min_recommended_price(); // Packaging - $packaging = getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING') ? GETPOST('packaging') : null; + $packaging = getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING') ? price2num(GETPOST('packaging', 'alpha'), 'MS') : null; if (isModEnabled('dynamicprices')) { $object->fk_price_expression = empty($eid) ? 0 : $eid; //0 discards expression From d1adfb32a453e3f0b8d272d5657820a1812993db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 29 Jan 2025 19:21:44 +0100 Subject: [PATCH 176/383] enhance member types list --- htdocs/adherents/type.php | 51 +++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/htdocs/adherents/type.php b/htdocs/adherents/type.php index 5e0a853eaa8..221c76c7bfa 100644 --- a/htdocs/adherents/type.php +++ b/htdocs/adherents/type.php @@ -369,11 +369,26 @@ if (!$rowid && $action != 'create' && $action != 'edit') { print ''; $totalarray['nbfield']++; } - print ''; - print ''; - print ''; - print ''; - print ''; + if (!empty($arrayfields['t.subscription']['checked'])) { + print ''; + $totalarray['nbfield']++; + } + if (!empty($arrayfields['t.amount']['checked'])) { + print ''; + $totalarray['nbfield']++; + } + if (!empty($arrayfields['t.caneditamount']['checked'])) { + print ''; + $totalarray['nbfield']++; + } + if (!empty($arrayfields['t.vote']['checked'])) { + print ''; + $totalarray['nbfield']++; + } + if (!empty($arrayfields['t.statut']['checked'])) { + print ''; + $totalarray['nbfield']++; + } if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'maxwidthsearch center '); $totalarray['nbfield']++; @@ -454,17 +469,21 @@ if (!$rowid && $action != 'create' && $action != 'edit') { } print ''; } - - print ''; - - print ''; - - print ''; - - print ''; - - print ''; - + if (!empty($arrayfields['t.subscription']['checked'])) { + print ''; + } + if (!empty($arrayfields['t.amount']['checked'])) { + print ''; + } + if (!empty($arrayfields['t.caneditamount']['checked'])) { + print ''; + } + if (!empty($arrayfields['t.vote']['checked'])) { + print ''; + } + if (!empty($arrayfields['t.statut']['checked'])) { + print ''; + } if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { if ($user->hasRight('adherent', 'configurer')) { print ''; From 1c94227320c639e1a6318b2ec89a2ff3636a0e8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 29 Jan 2025 19:24:40 +0100 Subject: [PATCH 177/383] fix phan --- htdocs/comm/propal/class/propal.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index 070f9914417..eb81c4c084e 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -713,9 +713,9 @@ class Propal extends CommonObject $product = new Product($this->db); $result = $product->fetch($fk_product); if ($qty < $product->packaging) { - $qty = (float) $product->packaging; + $qty = $product->packaging; } else { - if (!empty($product->packaging) && (fmod((float) $qty, (float) $product->packaging) > 0.000001)) { + if (!empty($product->packaging) && (fmod((float) $qty, $product->packaging) > 0.000001)) { $coeff = intval((float) $qty / $product->packaging) + 1; $qty = (float) $product->packaging * $coeff; setEventMessages($langs->trans('QtyRecalculatedWithPackaging'), null, 'mesgs'); From 7a6b650e828c39b0fae8200d87983548c562c757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 29 Jan 2025 19:25:32 +0100 Subject: [PATCH 178/383] fix phan --- htdocs/commande/class/commande.class.php | 4 ++-- htdocs/compta/facture/class/facture.class.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index ccce40846ce..71e03085f69 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -1638,9 +1638,9 @@ class Commande extends CommonOrder $product = new Product($this->db); $result = $product->fetch($fk_product); if ($qty < $product->packaging) { - $qty = (float) $product->packaging; + $qty = $product->packaging; } else { - if (!empty($product->packaging) && (fmod((float) $qty, (float) $product->packaging) > 0.000001)) { + if (!empty($product->packaging) && (fmod((float) $qty, $product->packaging) > 0.000001)) { $coeff = intval((float) $qty / $product->packaging) + 1; $qty = (float) $product->packaging * $coeff; setEventMessages($langs->trans('QtyRecalculatedWithPackaging'), null, 'mesgs'); diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 68a019043d5..09dddafbbd5 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -4003,9 +4003,9 @@ class Facture extends CommonInvoice $product = new Product($this->db); $result = $product->fetch($fk_product); if ($qty < $product->packaging) { - $qty = (float) $product->packaging; + $qty = $product->packaging; } else { - if (!empty($product->packaging) && (fmod((float) $qty, (float) $product->packaging) > 0.000001)) { + if (!empty($product->packaging) && (fmod((float) $qty, $product->packaging) > 0.000001)) { $coeff = intval((float) $qty / $product->packaging) + 1; $qty = (float) $product->packaging * $coeff; setEventMessages($langs->trans('QtyRecalculatedWithPackaging'), null, 'mesgs'); From 82eb875fabed66fe5554ac528f9e360a196abbbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 29 Jan 2025 19:34:35 +0100 Subject: [PATCH 179/383] enhance member types list --- htdocs/adherents/type.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/htdocs/adherents/type.php b/htdocs/adherents/type.php index 221c76c7bfa..7db9917b1d2 100644 --- a/htdocs/adherents/type.php +++ b/htdocs/adherents/type.php @@ -286,6 +286,9 @@ $help_url = 'EN:Module_Foundations|FR:Module_Adhérents|ES:Módulo_M llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-member page-type'); $arrayofselected = is_array($toselect) ? $toselect : array(); +$totalarray = [ + 'nbfield' => 0, +]; // List of members type if (!$rowid && $action != 'create' && $action != 'edit') { From 4fc66c6ee16062b44747ce3442e8be307af53570 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Wed, 29 Jan 2025 19:44:50 +0100 Subject: [PATCH 180/383] FIX missing quick edit for extrafields --- htdocs/core/tpl/extrafields_view.tpl.php | 3 +++ htdocs/projet/card.php | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/htdocs/core/tpl/extrafields_view.tpl.php b/htdocs/core/tpl/extrafields_view.tpl.php index 10481b4ad10..26c11f099a6 100644 --- a/htdocs/core/tpl/extrafields_view.tpl.php +++ b/htdocs/core/tpl/extrafields_view.tpl.php @@ -159,6 +159,9 @@ if (empty($reshook) && !empty($object->table_element) && isset($extrafields->att if ($object->element == 'product') { $keyforperm = 'produit'; } + if ($object->element == 'project') { + $keyforperm = 'projet'; + } if (isset($user->rights->$keyforperm)) { $permok = $user->hasRight($keyforperm, 'creer') || $user->hasRight($keyforperm, 'create') || $user->hasRight($keyforperm, 'write'); } diff --git a/htdocs/projet/card.php b/htdocs/projet/card.php index 1b17aff16af..fd6fa35d136 100644 --- a/htdocs/projet/card.php +++ b/htdocs/projet/card.php @@ -553,6 +553,30 @@ if (empty($reshook)) { } } + // Quick edit for extrafields + if ($action == 'update_extras' && $permissiontoadd) { + $object->oldcopy = dol_clone($object, 2); + + // Fill array 'array_options' with data from update form + $ret = $extrafields->setOptionalsFromPost(null, $object, GETPOST('attribute', 'restricthtml')); + if ($ret < 0) { + $error++; + } + + if (!$error) { + // Actions on extra fields + $result = $object->insertExtraFields('PROJECT_MODIFY'); + if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } + } + + if ($error) { + $action = 'edit_extras'; + } + } + // Actions to send emails $triggersendname = 'PROJECT_SENTBYMAIL'; $paramname = 'id'; From 65ebb94181d55c268040d50a0292617ee783e21d Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Thu, 30 Jan 2025 01:12:50 +0100 Subject: [PATCH 181/383] FIX wrong var name --- htdocs/societe/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/societe/card.php b/htdocs/societe/card.php index b00bb69b3fb..bc59136f69e 100644 --- a/htdocs/societe/card.php +++ b/htdocs/societe/card.php @@ -1578,7 +1578,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($canvasdisplayactio // Vat is used print ''; print ''; if ($conf->browser->layout == 'phone') { print ''; From d831e30869e1e17edc881458d6b8851376a5c377 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Thu, 30 Jan 2025 08:29:46 +0100 Subject: [PATCH 182/383] FIX multicompany compatibility --- htdocs/admin/multicurrency.php | 6 +++--- htdocs/multicurrency/multicurrency_rate.php | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/htdocs/admin/multicurrency.php b/htdocs/admin/multicurrency.php index 2a6713ef599..a4b503b3f24 100644 --- a/htdocs/admin/multicurrency.php +++ b/htdocs/admin/multicurrency.php @@ -130,9 +130,9 @@ if ($action == 'add_currency') { } } elseif ($action == 'setapilayer') { if (GETPOSTISSET('modify_apilayer')) { - dolibarr_set_const($db, 'MULTICURRENCY_APP_ID', GETPOST('MULTICURRENCY_APP_ID', 'alpha')); - dolibarr_set_const($db, 'MULTICURRENCY_APP_SOURCE', GETPOST('MULTICURRENCY_APP_SOURCE', 'alpha')); - //dolibarr_set_const($db, 'MULTICURRENCY_ALTERNATE_SOURCE', GETPOST('MULTICURRENCY_ALTERNATE_SOURCE', 'alpha')); + dolibarr_set_const($db, 'MULTICURRENCY_APP_ID', GETPOST('MULTICURRENCY_APP_ID', 'alpha'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, 'MULTICURRENCY_APP_SOURCE', GETPOST('MULTICURRENCY_APP_SOURCE', 'alpha'), 'chaine', 0, '', $conf->entity); + //dolibarr_set_const($db, 'MULTICURRENCY_ALTERNATE_SOURCE', GETPOST('MULTICURRENCY_ALTERNATE_SOURCE', 'alpha'), 'chaine', 0, '', $conf->entity); } else { $multiurrency = new MultiCurrency($db); $result = $multiurrency->syncRates(getDolGlobalString('MULTICURRENCY_APP_ID')); diff --git a/htdocs/multicurrency/multicurrency_rate.php b/htdocs/multicurrency/multicurrency_rate.php index ef05976018e..7cfe91e5e14 100644 --- a/htdocs/multicurrency/multicurrency_rate.php +++ b/htdocs/multicurrency/multicurrency_rate.php @@ -354,7 +354,8 @@ if ($search_rate) { if ($search_code) { $sql .= natural_search('m.code', $search_code); } -$sql .= " WHERE m.code <> '".$db->escape($conf->currency)."'"; +$sql .= " WHERE cr.entity IN (".getEntity('multicurrency').")"; +$sql .= " AND m.code <> '".$db->escape($conf->currency)."'"; // Add where from hooks $parameters = array(); From c07be3dfc39d892e094e07c7967a0212a8b25a9e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 30 Jan 2025 09:30:10 +0100 Subject: [PATCH 183/383] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 136f946a257..607ab21f166 100644 --- a/README.md +++ b/README.md @@ -34,12 +34,12 @@ There is a lot of different solutions to install Dolibarr. ### Using packages -If you have low technical skills and you're looking to install Dolibarr ERP/CRM with just a few clicks, you can use one of the packaged versions: +If you have low technical skills and you're looking to install Dolibarr ERP/CRM with just few clicks, you can use one of the packaged versions (see next chapter if you have IT knowledge) : - [DoliWamp for Windows](https://wiki.dolibarr.org/index.php/Dolibarr_for_Windows_(DoliWamp)) -- [DoliDeb for Debian](https://wiki.dolibarr.org/index.php/Dolibarr_for_Ubuntu_or_Debian) +- [DoliDeb for Debian, Ubuntu](https://wiki.dolibarr.org/index.php/Dolibarr_for_Ubuntu_or_Debian) - DoliRpm for Red Hat, Fedora, OpenSuse, Mandriva or Mageia -- The Docker image (see next chapter) +- The Docker image (see chapter "Using Docker") Releases can be downloaded from [official website](https://www.dolibarr.org/). From 7848d77830373d1881d5f5851f375eb0e6910c49 Mon Sep 17 00:00:00 2001 From: Irvine Fleith Date: Thu, 30 Jan 2025 09:58:29 +0100 Subject: [PATCH 184/383] fix(contrat,facture-rec): undefined properties --- htdocs/compta/facture/class/facture-rec.class.php | 7 +++++++ htdocs/contrat/class/contrat.class.php | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/htdocs/compta/facture/class/facture-rec.class.php b/htdocs/compta/facture/class/facture-rec.class.php index 228badc04dc..a45feec9cdc 100644 --- a/htdocs/compta/facture/class/facture-rec.class.php +++ b/htdocs/compta/facture/class/facture-rec.class.php @@ -125,6 +125,13 @@ class FactureRec extends CommonInvoice public $cond_reglement_code; // Code in llx_c_paiement public $mode_reglement_code; // Code in llx_c_paiement + public $fk_multicurrency; + public $multicurrency_code; + public $multicurrency_tx; + public $multicurrency_total_ht; + public $multicurrency_total_tva; + public $multicurrency_total_ttc; + public $suspended; // status public $auto_validate; // 0 to create in draft, 1 to create and validate the new invoice diff --git a/htdocs/contrat/class/contrat.class.php b/htdocs/contrat/class/contrat.class.php index a29df83b834..d78c636b0f1 100644 --- a/htdocs/contrat/class/contrat.class.php +++ b/htdocs/contrat/class/contrat.class.php @@ -3097,7 +3097,7 @@ class ContratLigne extends CommonObjectLine $sql .= " t.label,"; // This field is not used. Only label of product $sql .= " p.ref as product_ref,"; $sql .= " p.label as product_label,"; - $sql .= " p.description as product_desc,"; + $sql .= " p.description as product_description,"; $sql .= " p.fk_product_type as product_type,"; $sql .= " t.description,"; $sql .= " t.date_commande,"; From 72604763977f4c32d22feed2b834d4bb508740ec Mon Sep 17 00:00:00 2001 From: Pratush Raj Date: Thu, 30 Jan 2025 15:14:07 +0530 Subject: [PATCH 185/383] Bug Fix: #32206 --- htdocs/core/class/discount.class.php | 6 ++++-- htdocs/societe/class/societe.class.php | 24 ++++++++++++++++++------ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/htdocs/core/class/discount.class.php b/htdocs/core/class/discount.class.php index 29e663f4e27..06929becacc 100644 --- a/htdocs/core/class/discount.class.php +++ b/htdocs/core/class/discount.class.php @@ -278,13 +278,15 @@ class DiscountAbsolute extends CommonObject $sql .= " (entity, datec, fk_soc, discount_type, fk_user, description,"; $sql .= " amount_ht, amount_tva, amount_ttc, tva_tx, vat_src_code,"; $sql .= " multicurrency_amount_ht, multicurrency_amount_tva, multicurrency_amount_ttc,"; - $sql .= " fk_facture_source, fk_invoice_supplier_source"; + $sql .= " fk_facture_source, fk_invoice_supplier_source, multicurrency_code, multicurrency_tx"; $sql .= ")"; $sql .= " VALUES (".$conf->entity.", '".$this->db->idate($this->datec != '' ? $this->datec : dol_now())."', ".((int) $this->socid).", ".(empty($this->discount_type) ? 0 : intval($this->discount_type)).", ".((int) $userid).", '".$this->db->escape($this->description)."',"; $sql .= " ".price2num($this->amount_ht).", ".price2num($this->amount_tva).", ".price2num($this->amount_ttc).", ".price2num($this->tva_tx).", '".$this->db->escape($this->vat_src_code)."',"; $sql .= " ".price2num($this->multicurrency_amount_ht).", ".price2num($this->multicurrency_amount_tva).", ".price2num($this->multicurrency_amount_ttc).", "; $sql .= " ".($this->fk_facture_source ? ((int) $this->fk_facture_source) : "null").","; - $sql .= " ".($this->fk_invoice_supplier_source ? ((int) $this->fk_invoice_supplier_source) : "null"); + $sql .= " ".($this->fk_invoice_supplier_source ? ((int) $this->fk_invoice_supplier_source) : "null").","; + $sql .= " '".($this->multicurrency_code ? $this->multicurrency_code : "null")."',"; + $sql .= " ".($this->multicurrency_tx ? price2num($this->multicurrency_tx) : "null"); $sql .= ")"; dol_syslog(get_class($this)."::create", LOG_DEBUG); diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 1f6e6377ca0..65c0c3e6145 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -2505,15 +2505,27 @@ class Societe extends CommonObject $discount->socid = $this->id; $discount->discount_type = $discount_type; + $discount->multicurrency_code = $this->multicurrency_code; + list($this->fk_multicurrency, $this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code); + $discount->multicurrency_tx = $this->multicurrency_tx; if ($price_base_type == 'TTC') { - $discount->amount_ttc = $discount->multicurrency_amount_ttc = price2num($remise, 'MT'); - $discount->amount_ht = $discount->multicurrency_amount_ht = price2num((float) $remise / (1 + (float) $vatrate / 100), 'MT'); - $discount->amount_tva = $discount->multicurrency_amount_tva = price2num((float) $discount->amount_ttc - (float) $discount->amount_ht, 'MT'); + $discount->multicurrency_amount_ttc = price2num($remise * (float) $discount->multicurrency_tx, 'MT'); + $discount->multicurrency_amount_ht = price2num(((float) $remise / (1 + (float) $vatrate / 100)) * (float) $discount->multicurrency_tx, 'MT'); + $discount->multicurrency_amount_tva = price2num(((float) $discount->amount_ttc - (float) $discount->amount_ht) * (float) $discount->multicurrency_tx, 'MT'); + + $discount->amount_ttc = price2num($remise, 'MT'); + $discount->amount_ht = price2num((float) $remise / (1 + (float) $vatrate / 100), 'MT'); + $discount->amount_tva = price2num((float) $discount->amount_ttc - (float) $discount->amount_ht, 'MT'); + } else { - $discount->amount_ht = $discount->multicurrency_amount_ht = price2num($remise, 'MT'); - $discount->amount_tva = $discount->multicurrency_amount_tva = price2num((float) $remise * (float) $vatrate / 100, 'MT'); - $discount->amount_ttc = $discount->multicurrency_amount_ttc = price2num((float) $discount->amount_ht + (float) $discount->amount_tva, 'MT'); + $discount->amount_ht = price2num($remise, 'MT'); + $discount->amount_tva = price2num((float) $remise * (float) $vatrate / 100, 'MT'); + $discount->amount_ttc = price2num((float) $discount->amount_ht + (float) $discount->amount_tva, 'MT'); + + $discount->multicurrency_amount_ht = price2num($remise * (float)$discount->multicurrency_tx, 'MT'); + $discount->multicurrency_amount_tva = price2num(((float) $remise * (float) $vatrate / 100) * (float) $discount->multicurrency_tx, 'MT'); + $discount->multicurrency_amount_ttc= price2num(((float) $discount->amount_ht + (float) $discount->amount_tva) * (float) $discount->multicurrency_tx, 'MT'); } $discount->tva_tx = (float) price2num($vatrate); From 1298229345a4a9e05c2d3160e8772eaf089ffa9c Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Thu, 30 Jan 2025 12:10:21 +0100 Subject: [PATCH 186/383] Doc --- dev/build/makepack-howto.txt | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/dev/build/makepack-howto.txt b/dev/build/makepack-howto.txt index 61a6006f0ae..b23b21e1bd7 100644 --- a/dev/build/makepack-howto.txt +++ b/dev/build/makepack-howto.txt @@ -1,14 +1,14 @@ ----- Dolibarr Makepack How To ----- -This documentation describe steps to build a BETA or RELEASE versions -of Dolibarr. There is a chapter for BETA version and a chapter for RELEASE version. +This documentation describe steps to build a BETA or RELEASE versions of Dolibarr. +There is a chapter for BETA version and a chapter for RELEASE version. -***** Prerequisites For Linux ***** +***** Prerequisites on Linux ***** -Prerequisites to build tgz, debian and rpm packages: +Prerequisites to build the tgz, debian and rpm packages: > apt-get install perl tar dpkg dpatch p7zip-full rpm zip php-cli -Prerequisites to build autoexe DoliWamp package from Linux (solution seems broken since Ubuntu 20.04): +Prerequisites to build autoexe DoliWamp package from Linux (solution seems broken since Ubuntu 20.04+): > apt-get install wine q4wine > Launch "wine cmd" to check a drive Z: pointing to / exists. > Install InnoSetup @@ -23,7 +23,7 @@ Prerequisites to build autoexe DoliWamp package from Linux (solution seems broke The .exe file will be build into directory build. -***** Prerequisites For Windows ***** +***** Prerequisites on Windows ***** Prerequisites to build autoexe DoliWamp package from Windows: @@ -49,9 +49,9 @@ This files describe steps made by Dolibarr packaging team to make a beta version - Check all files are committed. - Update version/info in ChangeLog, for this you can: -To generate a changelog of a major new version x.y.0 (from a repo on branch develop), you can do "cd ~/git/dolibarr; git log `diff -u <(git rev-list --first-parent x.(y-1).0) <(git rev-list --first-parent develop) | sed -ne 's/^ //p' | head -1`.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/aaa" -To generate a changelog of a major new version x.y.0 (from a repo on branch x.y repo), you can do "cd ~/git/dolibarr_x.y; git log `diff -u <(git rev-list --first-parent x.(y-1).0) <(git rev-list --first-parent x.y.0) | sed -ne 's/^ //p' | head -1`.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/aaa" -To generate a changelog of a maintenance version x.y.z, you can do "cd ~/git/dolibarr_x.y; git log x.y.z-1.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/aaa" +To generate a changelog of a major new version x.y.0 (from a repo on branch develop), you can do "cd ~/git/dolibarr; git log `diff -u <(git rev-list --first-parent x.(y-1).0) <(git rev-list --first-parent develop) | sed -ne 's/^ //p' | head -1`.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/changelogtocopy" +To generate a changelog of a major new version x.y.0 (from a repo on branch x.y repo), you can do "cd ~/git/dolibarr_x.y; git log `diff -u <(git rev-list --first-parent x.(y-1).0) <(git rev-list --first-parent x.y.0) | sed -ne 's/^ //p' | head -1`.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/changelogtocopy" +To generate a changelog of a maintenance version x.y.z, you can do "cd ~/git/dolibarr_x.y; git log x.y.z-1.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/changelogtocopy" Recopy the content of the output file into the file ChangeLog. - Note: To know number of lines changes: git diff --shortstat A B - Update version number with x.y.z-w in file htdocs/filefunc.inc.php @@ -67,15 +67,15 @@ Recopy the content of the output file into the file ChangeLog. ***** Actions to do a RELEASE ***** This files describe steps made by Dolibarr packaging team to make a complete release of Dolibarr, step by step. -We suppose the branch x.y has already been created during the beta (see previous step). +We suppose the branch x.y has already been created during the beta (see previous step) and we want to release a version x.y.z (with z >= 0) - Check all files are committed. -- Update version/info in ChangeLog, for this you can: -To generate a changelog of a major new version x.y.0 (from a repo on branch develop), you can do "cd ~/git/dolibarr; git log `diff -u <(git rev-list --first-parent x.(y-1).0) <(git rev-list --first-parent develop) | sed -ne 's/^ //p' | head -1`.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/aaa" -To generate a changelog of a major new version x.y.0 (from a repo pn branch x.y), you can do "cd ~/git/dolibarr_x.y; git log `diff -u <(git rev-list --first-parent x.(y-1).0) <(git rev-list --first-parent x.y.0) | sed -ne 's/^ //p' | head -1`.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/aaa" -To generate a changelog of a maintenance version x.y.z, you can do "cd ~/git/dolibarr_x.y; git log x.y.z-1.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/aaa" +- Update version/info in ChangeLog, for this: +To generate a changelog of a major new version x.y.0 (from a repo on branch develop), you can do "cd ~/git/dolibarr; git log `diff -u <(git rev-list --first-parent x.(y-1).0) <(git rev-list --first-parent develop) | sed -ne 's/^ //p' | head -1`.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/changelogtocopy" +To generate a changelog of a major new version x.y.0 (from a repo pn branch x.y), you can do "cd ~/git/dolibarr_x.y; git log `diff -u <(git rev-list --first-parent x.(y-1).0) <(git rev-list --first-parent x.y.0) | sed -ne 's/^ //p' | head -1`.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/changelogtocopy" +To generate a changelog of a maintenance version x.y.z, you can do "cd ~/git/dolibarr_x.y; git log x.y.z-1.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/changelogtocopy" Recopy the content of the output file into the file ChangeLog. -- Note: To know the number of lines changes: git diff --shortstat A B +- Note: To know the number of lines changes: git diff --shortstat vA vB - Update version number with x.y.z in file htdocs/filefunc.inc.php - Commit all changes. @@ -84,6 +84,6 @@ Recopy the content of the output file into the file ChangeLog. - Check content of built packages. - Run makepack-dolibarr.pl again with option to publish files on dolibarr foundation server (Dir /home/dolibarr/wwwroot/files/stable on www.dolibarr.org). -- Run makepack-dolibarr.pl again with option to publish files on sourceforge. This will also add official tag. +- Run makepack-dolibarr.pl again with option to publish files on sourceforge. This will also add the official tag x.y.z. -- Post a news on dolibarr.org/dolibarr.fr + social networks +- Post a news in english dolibarr.org/dolibarr.fr web site by cloning a past news (the news will be propagated on social networks) From 4e1a319113b3880e1b3161ce0b74c3dece6c8557 Mon Sep 17 00:00:00 2001 From: Dolibot Date: Thu, 30 Jan 2025 12:06:34 +0000 Subject: [PATCH 187/383] PHPStan > Update baseline --- dev/build/phpstan/phpstan-baseline.neon | 78 ------------------------- 1 file changed, 78 deletions(-) diff --git a/dev/build/phpstan/phpstan-baseline.neon b/dev/build/phpstan/phpstan-baseline.neon index 2d9c290b25a..740e50d80c5 100644 --- a/dev/build/phpstan/phpstan-baseline.neon +++ b/dev/build/phpstan/phpstan-baseline.neon @@ -9540,12 +9540,6 @@ parameters: count: 1 path: ../../../htdocs/core/class/dolgraph.class.php - - - message: '#^Comparison operation "\>" between 0 and 0 is always false\.$#' - identifier: greater.alwaysFalse - count: 3 - path: ../../../htdocs/core/class/dolgraph.class.php - - message: '#^If condition is always false\.$#' identifier: if.alwaysFalse @@ -9564,24 +9558,6 @@ parameters: count: 1 path: ../../../htdocs/core/class/dolgraph.class.php - - - message: '#^Loose comparison using \=\= between 0 and 0 will always evaluate to true\.$#' - identifier: equal.alwaysTrue - count: 2 - path: ../../../htdocs/core/class/dolgraph.class.php - - - - message: '#^Loose comparison using \=\= between 1 and 3 will always evaluate to false\.$#' - identifier: equal.alwaysFalse - count: 1 - path: ../../../htdocs/core/class/dolgraph.class.php - - - - message: '#^Offset 0 on array\{array\{stacknum\: int, legend\: mixed, legendwithgroup\: non\-falsy\-string\}\} in empty\(\) always exists and is not falsy\.$#' - identifier: empty.offset - count: 1 - path: ../../../htdocs/core/class/dolgraph.class.php - - message: '#^Ternary operator condition is always true\.$#' identifier: ternary.alwaysTrue @@ -14670,24 +14646,12 @@ parameters: count: 12 path: ../../../htdocs/core/tpl/card_presend.tpl.php - - - message: '#^Variable \$hidedesc might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: ../../../htdocs/core/tpl/card_presend.tpl.php - - message: '#^Variable \$hidedetails might not be defined\.$#' identifier: variable.undefined count: 1 path: ../../../htdocs/core/tpl/card_presend.tpl.php - - - message: '#^Variable \$hideref might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: ../../../htdocs/core/tpl/card_presend.tpl.php - - message: '#^Variable \$hookmanager might not be defined\.$#' identifier: variable.undefined @@ -15444,12 +15408,6 @@ parameters: count: 1 path: ../../../htdocs/cron/list.php - - - message: '#^Variable \$texttoshow might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: ../../../htdocs/cron/list.php - - message: '#^Offset ''css'' on array\{css\: ''minwidth200'', picto\: mixed\} in empty\(\) always exists and is not falsy\.$#' identifier: empty.offset @@ -15510,12 +15468,6 @@ parameters: count: 1 path: ../../../htdocs/delivery/card.php - - - message: '#^Variable \$arrayoptions might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: ../../../htdocs/delivery/card.php - - message: '#^Variable \$hidedesc might not be defined\.$#' identifier: variable.undefined @@ -15786,42 +15738,12 @@ parameters: count: 1 path: ../../../htdocs/don/paiement/list.php - - - message: '#^Variable \$morecss might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: ../../../htdocs/don/paiement/list.php - - - - message: '#^Variable \$morejs might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: ../../../htdocs/don/paiement/list.php - - - - message: '#^Variable \$outputlangs might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: ../../../htdocs/don/payment/card.php - - message: '#^Negated boolean expression is always true\.$#' identifier: booleanNot.alwaysTrue count: 1 path: ../../../htdocs/don/payment/payment.php - - - message: '#^Variable \$sumpaid might not be defined\.$#' - identifier: variable.undefined - count: 3 - path: ../../../htdocs/don/payment/payment.php - - - - message: '#^Variable \$objectlink might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: ../../../htdocs/don/tpl/linkedobjectblock.tpl.php - - message: '#^Property EcmFiles\:\:\$acl \(string\) in isset\(\) is not nullable\.$#' identifier: isset.property From 7fa1baf1ddbf35d4710f175d1a5ad387672abcc0 Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Thu, 30 Jan 2025 13:34:26 +0100 Subject: [PATCH 188/383] Fix regression --- htdocs/categories/class/categorie.class.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/htdocs/categories/class/categorie.class.php b/htdocs/categories/class/categorie.class.php index 305649da4e4..5dd92761cdb 100644 --- a/htdocs/categories/class/categorie.class.php +++ b/htdocs/categories/class/categorie.class.php @@ -1785,10 +1785,9 @@ class Categorie extends CommonObject } // Check contrast with background and correct text color - //$forced_color = 'categtextwhite'; // TODO This css class hide the link - $forced_color = 'categtextblack'; + $forced_color = 'categtextwhite'; // We want color white because the background is dark (grey or other) if ($this->color) { - if (colorIsLight($this->color)) { + if (colorIsLight($this->color)) { // If color is light, we force color to dark $forced_color = 'categtextblack'; } } From 09d745057c92804bf27bc18b6813257c4ea49951 Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Thu, 30 Jan 2025 14:36:43 +0100 Subject: [PATCH 189/383] Fix structured data --- htdocs/core/lib/website.lib.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/htdocs/core/lib/website.lib.php b/htdocs/core/lib/website.lib.php index 697d3f5674d..00de6abe9ae 100644 --- a/htdocs/core/lib/website.lib.php +++ b/htdocs/core/lib/website.lib.php @@ -779,13 +779,13 @@ function getStructuredData($type, $data = array()) $pageurl = $websitepage->pageurl; $title = $websitepage->title; - $image = $websitepage->image; + $image = getImageFromHtmlContent($websitepage->content); $companyname = $mysoc->name; $description = $websitepage->description; $pageurl = str_replace('__WEBSITE_KEY__', $website->ref, $pageurl); $title = str_replace('__WEBSITE_KEY__', $website->ref, $title); - $image = '/medias'.(preg_match('/^\//', $image) ? '' : '/').str_replace('__WEBSITE_KEY__', $website->ref, $image); + $imagepath = '/medias'.(preg_match('/^\//', $image) ? '' : '/').str_replace('__WEBSITE_KEY__', $website->ref, $image); $companyname = str_replace('__WEBSITE_KEY__', $website->ref, $companyname); $description = str_replace('__WEBSITE_KEY__', $website->ref, $description); @@ -798,10 +798,14 @@ function getStructuredData($type, $data = array()) "@type": "WebPage", "@id": "'.dol_escape_json($pageurl).'" }, - "headline": "'.dol_escape_json($title).'", + "headline": "'.dol_escape_json($title).'",'; + if ($image) { + $ret .= ' "image": [ - "'.dol_escape_json($image).'" - ], + "'.dol_escape_json($imagepath).'" + ],'; + } + $ret .= ' "dateCreated": "'.dol_print_date($websitepage->date_creation, 'dayhourrfc').'", "datePublished": "'.dol_print_date($websitepage->date_creation, 'dayhourrfc').'", "dateModified": "'.dol_print_date($websitepage->date_modification, 'dayhourrfc').'", @@ -814,7 +818,7 @@ function getStructuredData($type, $data = array()) "name": "'.dol_escape_json($companyname).'", "logo": { "@type": "ImageObject", - "url": "/wrapper.php?modulepart=mycompany&file=logos%2F'.urlencode($mysoc->logo).'" + "url": "/wrapper.php?modulepart=mycompany&file='.urlencode('logos/'.$mysoc->logo).'" } },'."\n"; if ($websitepage->keywords) { From 0cc2ce2c1190bca56cf0d984e27bdb1bb5ee816d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sol=C3=A8ne?= Date: Thu, 30 Jan 2025 15:48:50 +0100 Subject: [PATCH 190/383] Translations fixed --- htdocs/core/lib/fichinter.lib.php | 2 +- htdocs/langs/en_US/interventions.lang | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/core/lib/fichinter.lib.php b/htdocs/core/lib/fichinter.lib.php index 64b91da0206..2eeb365cc62 100644 --- a/htdocs/core/lib/fichinter.lib.php +++ b/htdocs/core/lib/fichinter.lib.php @@ -232,7 +232,7 @@ function fichinter_rec_prepare_head($object) $head = array(); $head[$h][0] = DOL_URL_ROOT.'/fichinter/card-rec.php?id='.$object->id; - $head[$h][1] = $langs->trans("CardFichinter"); + $head[$h][1] = $langs->trans("InterventionCard"); $head[$h][2] = 'card'; $h++; diff --git a/htdocs/langs/en_US/interventions.lang b/htdocs/langs/en_US/interventions.lang index 1d7b2ada84f..2e3e1d1f510 100644 --- a/htdocs/langs/en_US/interventions.lang +++ b/htdocs/langs/en_US/interventions.lang @@ -86,3 +86,4 @@ TypeContact_fichinter_external_BILLING=Customer contact of intervention billing TypeContact_fichinter_external_CUSTOMER=Customer contact of intervention follow-up NotARecurringInterventionalTemplate=Not a recurring intervention template ShowInterventionModel=Show intervention model +CreateRepeatableIntervention=Create recurring intervention From e83e318fc92bef80fa98d919ed694ec627e850d7 Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Thu, 30 Jan 2025 16:04:25 +0100 Subject: [PATCH 191/383] Enhance selectForForms --- htdocs/core/class/commonobject.class.php | 31 +++++++++++------- htdocs/core/class/html.form.class.php | 41 +++++++++++++----------- htdocs/hrm/class/position.class.php | 6 ++-- htdocs/hrm/position_list.php | 14 +++++--- 4 files changed, 55 insertions(+), 37 deletions(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 3aa18de36e9..6ba5e3e730f 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -7450,16 +7450,15 @@ abstract class CommonObject * Return HTML string to put an input field into a page * Code very similar with showInputField of extra fields * - * @param ?array{type:string,label:string,enabled:int<0,2>|string,position:int,notnull?:int,visible:int,noteditable?:int,default?:string,index?:int,foreignkey?:string,searchall?:int,isameasure?:int,css?:string,csslist?:string,help?:string,showoncombobox?:int,disabled?:int,arrayofkeyval?:array,comment?:string} $val Array of properties for field to show (used only if ->fields not defined) - * Array of properties of field to show - * @param string $key Key of attribute - * @param string|string[] $value Preselected value to show (for date type it must be in timestamp format, for amount or price it must be a php numeric value, for array type must be array) - * @param string $moreparam To add more parameters on html input tag - * @param string $keysuffix Suffix string to add into name and id of field (can be used to avoid duplicate names) - * @param string $keyprefix Prefix string to add into name and id of field (can be used to avoid duplicate names) - * @param string|int $morecss Value for css to define style/length of field. May also be a numeric. - * @param int<0,1> $nonewbutton Force to not show the new button on field that are links to object - * @return string + * @param ?array{type:string,label:string,enabled:int<0,2>|string,position:int,notnull?:int,visible:int,noteditable?:int,default?:string,index?:int,foreignkey?:string,searchall?:int,isameasure?:int,css?:string,csslist?:string,help?:string,showoncombobox?:int,disabled?:int,arrayofkeyval?:array,comment?:string} $val Array of properties for field to show (used only if ->fields not defined, so try to keep this null) + * @param string $key Key of attribute + * @param string|string[] $value Preselected value to show (for date type it must be in timestamp format, for amount or price it must be a php numeric value, for array type must be array) + * @param string $moreparam To add more parameters on html input tag + * @param string $keysuffix Suffix string to add into name and id of field (can be used to avoid duplicate names) + * @param string $keyprefix Prefix string to add into name and id of field (can be used to avoid duplicate names) + * @param string|int $morecss Value for css to define style/length of field. May also be a numeric. + * @param int<0,1> $nonewbutton Force to not show the new button on field that are links to object + * @return string */ public function showInputField($val, $key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = 0, $nonewbutton = 0) { @@ -8269,7 +8268,17 @@ abstract class CommonObject } } } - $objectfield = $this->element.($this->module ? '@'.$this->module : '').':'.$key.$keysuffix; + + // $param_list_array[0] can be the name of object (Example 'User' the field is linked to). Not as taking the information from the record in ->fields found from $objectfield. + + // $valparent is a string 'dataobject@module:keyoffieldinfieldsarray' to find the record field to link to. + // $valparent = $this->element.($this->module ? '@'.$this->module : '').':'.$key.$keysuffix; + + // $val is already the record field found at same place than found by $valparent but already loaded and may have been modified by parent caller. + + //$objectfield = $valparent; + $objectfield = $val; // Is better than using old method $valparent + $out = $form->selectForForms($param_list_array[0], $keyprefix.$key.$keysuffix, $value, $showempty, '', '', $morecss, $moreparam, 0, (empty($val['disabled']) ? 0 : 1), '', $objectfield); if (!empty($param_list_array[2])) { // If the entry into $fields is set, we must add a create button diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index e611d3ec66f..af533b9474b 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -8486,22 +8486,22 @@ class Form /** * Generic method to select a component from a combo list. - * Can use autocomplete with ajax after x key pressed or a full combo, depending on setup. + * Can use autocomplete with ajax after x key pressed (if $objecttmp->element.'_USE_SEARCH_TO_SELECT' is set) or a full combo, depending on setup. * This is the generic method that will replace all specific existing methods. * - * @param string $objectdesc 'ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]'. For hard coded custom needs. Try to prefer method using $objectfield instead of $objectdesc. - * @param string $htmlname Name of HTML select component - * @param int $preSelectedValue Preselected value (ID of element) + * @param string $objectdesc 'ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]'. For hard coded custom needs. Try to prefer method using $objectfield array instead of $objectdesc. + * @param string $htmlname Name of HTML select component + * @param int $preSelectedValue Preselected value (ID of element) * @param string|int<0,1> $showempty ''=empty values not allowed, 'string'=value show if we allow empty values (for example 'All', ...) - * @param string $searchkey Search criteria - * @param string $placeholder Place holder - * @param string $morecss More CSS - * @param string $moreparams More params provided to ajax call - * @param int $forcecombo Force to load all values and output a standard combobox (with no beautification) - * @param int<0,1> $disabled 1=Html component is disabled - * @param string $selected_input_value Value of preselected input text (for use with ajax) - * @param string $objectfield Object:Field that contains the definition of parent (in table $fields or $extrafields). Example: 'Object:xxx' or 'Object@module:xxx' (old syntax 'Module_Object:xxx') or 'Object:options_xxx' or 'Object@module:options_xxx' (old syntax 'Module_Object:options_xxx') - * @return string Return HTML string + * @param string $searchkey Search criteria + * @param string $placeholder Place holder + * @param string $morecss More CSS + * @param string $moreparams More params provided to ajax call + * @param int $forcecombo Force to load all values and output a standard combobox (with no beautification) + * @param int<0,1> $disabled 1=Html component is disabled + * @param string $selected_input_value Value of preselected input text (for use with ajax) + * @param string|array $objectfield 'Object:Field' that contains the definition of parent (in table $fields or $extrafields). Example: 'Object:xxx' or 'Object@module:xxx' or 'Object:options_xxx' or 'Object@module:options_xxx' or, better, the full entry array in ->fields + * @return string Return HTML string * @see selectForFormsList(), select_thirdparty_list() */ public function selectForForms($objectdesc, $htmlname, $preSelectedValue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '', $objectfield = '') @@ -8511,14 +8511,16 @@ class Form // Example of common usage for a link to a thirdparty // We got this in a modulebuilder form of "MyObject" of module "mymodule". - // ->fields is array( ... "fk_soc" => array("type"=>"integer:Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...) + // When ->fields is array( ... "fk_soc" => array("type"=>"integer:Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...), we have // $objectdesc = 'Societe' - // $objectfield = 'myobject@mymodule:fk_soc' ('fk_soc' is code to retrieve myobject->fields['fk_soc']) + // $objectfield = 'myobject@mymodule:fk_soc' ('fk_soc' is code to retrieve myobject->fields['fk_soc']) or it can be an array that is directly + // array("type"=>"integer:Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...) // We got this when showing an extrafields on resource that is a link to societe - // extrafields 'link_to_societe' of Resource is 'link' to 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)' + // When extrafields 'link_to_societe' of Resource is 'link' to 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)', we have // $objectdesc = 'Societe' - // $objectfield = 'resource:options_link_to_societe' + // $objectfield = 'resource:options_link_to_societe' or it can be an array that is directly + // array("type"=>'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...) // With old usage: // $objectdesc = 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))' @@ -8534,7 +8536,10 @@ class Form $filter = ''; // Ensure filter has value (for static analysis) $sortfield = ''; // Ensure filter has value (for static analysis) - if ($objectfield) { // We must retrieve the objectdesc from the field or extrafield + if (is_array($objectfield)) { + $objectdesc = $objectfield['type']; + $objectdesc = preg_replace('/^integer[^:]*:/', '', $objectdesc); + } elseif ($objectfield) { // We must retrieve the objectdesc from the field or extrafield. Deprecated, it is better to provide the array record directly. // Example: $objectfield = 'product:options_package' or 'myobject@mymodule:options_myfield' $tmparray = explode(':', $objectfield); diff --git a/htdocs/hrm/class/position.class.php b/htdocs/hrm/class/position.class.php index 50705c1ece5..2059a1d4ff5 100644 --- a/htdocs/hrm/class/position.class.php +++ b/htdocs/hrm/class/position.class.php @@ -207,7 +207,7 @@ class Position extends CommonObject */ public function __construct(DoliDB $db) { - global $conf, $langs; + global $langs; $this->db = $db; @@ -873,7 +873,7 @@ class Position extends CommonObject * Return HTML string to put an input field into a page * Code very similar with showInputField of extra fields * - * @param ?array{type:string,label:string,enabled:int|string,position:int,notnull?:int,visible:int,noteditable?:int,default?:string,index?:int,foreignkey?:string,searchall?:int,isameasure?:int,css?:string,csslist?:string,help?:string,showoncombobox?:int,disabled?:int,arrayofkeyval?:array,comment?:string} $val Array of properties for field to show + * @param ?array{type:string,label:string,enabled:int|string,position:int,notnull?:int,visible:int,noteditable?:int,default?:string,index?:int,foreignkey?:string,searchall?:int,isameasure?:int,css?:string,csslist?:string,help?:string,showoncombobox?:int,disabled?:int,arrayofkeyval?:array,comment?:string} $val Array of properties for field to show. If ->fields is defined, keep this null. * @param string $key Key of attribute * @param string $value Preselected value to show (for date type it must be in timestamp format, for amount or price it must be a php numeric value) * @param string $moreparam To add more parameters on html input tag @@ -890,7 +890,7 @@ class Position extends CommonObject if ($key == 'fk_user') { $vacantId = $keyprefix.$key.'vacant'.$keysuffix; - $out = parent::showInputField($val, $key, $value, $moreparam, $keysuffix, $keyprefix, $morecss); + $out = parent::showInputField(null, $key, $value, $moreparam, $keysuffix, $keyprefix, $morecss); $out .= ''; ?> '."\n"; } - if (defined('JS_JQUERY_UI') && constant('JS_JQUERY_UI')) { - print ''."\n"; - } else { - print ''."\n"; + if (!defined('DISABLE_JQUERY_UI')) { + if (defined('JS_JQUERY_UI') && constant('JS_JQUERY_UI')) { + print '' . "\n"; + } else { + print '' . "\n"; + } } // jQuery jnotify if (!getDolGlobalString('MAIN_DISABLE_JQUERY_JNOTIFY') && !defined('DISABLE_JQUERY_JNOTIFY')) { From 15dec468cb555e43e3454d431b7c23b87e89d093 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Fri, 7 Feb 2025 10:05:06 +0100 Subject: [PATCH 370/383] NEW: add const to not include JQuery UI in top_htmlhead DISABLE_JQUERY_UI --- htdocs/main.inc.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index 9004839fa99..3ddad620a92 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -2120,6 +2120,8 @@ function top_htmlhead($head, $title = '', $disablejs = 0, $disablehead = 0, $arr } else { print ''."\n"; } + + if (!defined('DISABLE_JQUERY_UI')) { if (defined('JS_JQUERY_UI') && constant('JS_JQUERY_UI')) { print '' . "\n"; From 867215e2eae009af0b4e5f11b84f01363fed2104 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Fri, 7 Feb 2025 10:05:17 +0100 Subject: [PATCH 371/383] NEW: add const to not include JQuery UI in top_htmlhead DISABLE_JQUERY_UI --- htdocs/main.inc.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index 3ddad620a92..9004839fa99 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -2120,8 +2120,6 @@ function top_htmlhead($head, $title = '', $disablejs = 0, $disablehead = 0, $arr } else { print ''."\n"; } - - if (!defined('DISABLE_JQUERY_UI')) { if (defined('JS_JQUERY_UI') && constant('JS_JQUERY_UI')) { print '' . "\n"; From a8811551092404b7ea028c21001033173884af5d Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Fri, 7 Feb 2025 10:10:45 +0100 Subject: [PATCH 372/383] NEW: add const to not include default CSS in top_htmlhead with DISABLE_CSS_DEFAULT_THEME --- htdocs/main.inc.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index d25d87140b9..9b126b49724 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -2036,21 +2036,21 @@ function top_htmlhead($head, $title = '', $disablejs = 0, $disablehead = 0, $arr print ''."\n"; } - if (!defined('DISABLE_CSS_DEFAULT_THEME')) { - print ''."\n"; - // Output style sheets (optioncss='print' or ''). Note: $conf->css looks like '/theme/eldy/style.css.php' - $themepath = dol_buildpath($conf->css, 1); - $themesubdir = ''; - if (!empty($conf->modules_parts['theme'])) { // This slow down - foreach ($conf->modules_parts['theme'] as $reldir) { - if (file_exists(dol_buildpath($reldir.$conf->css, 0))) { - $themepath = dol_buildpath($reldir.$conf->css, 1); - $themesubdir = $reldir; - break; - } + // Output style sheets (optioncss='print' or ''). Note: $conf->css looks like '/theme/eldy/style.css.php' + $themepath = dol_buildpath($conf->css, 1); + $themesubdir = ''; + if (!empty($conf->modules_parts['theme'])) { // This slow down + foreach ($conf->modules_parts['theme'] as $reldir) { + if (file_exists(dol_buildpath($reldir.$conf->css, 0))) { + $themepath = dol_buildpath($reldir.$conf->css, 1); + $themesubdir = $reldir; + break; } } + } + if (!defined('DISABLE_CSS_DEFAULT_THEME')) { + print ''."\n"; print '' . "\n"; } From e0a8caec45b9d9dece3ec63a54a484bc7618d357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Fri, 7 Feb 2025 10:45:03 +0100 Subject: [PATCH 373/383] fix phpstan --- dev/build/phpstan/phpstan-baseline.neon | 6 ------ htdocs/core/class/commondocgenerator.class.php | 6 +++--- .../modules/asset/doc/doc_generic_asset_odt.modules.php | 6 +++--- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/dev/build/phpstan/phpstan-baseline.neon b/dev/build/phpstan/phpstan-baseline.neon index 4f95b73a9fb..deba1cbbeb2 100644 --- a/dev/build/phpstan/phpstan-baseline.neon +++ b/dev/build/phpstan/phpstan-baseline.neon @@ -8862,12 +8862,6 @@ parameters: count: 1 path: ../../../htdocs/core/class/commondocgenerator.class.php - - - message: '#^Parameter \#2 \$array_to_fill of method CommonDocGenerator\:\:fill_substitutionarray_with_extrafields\(\) expects array\, array\ given\.$#' - identifier: argument.type - count: 1 - path: ../../../htdocs/core/class/commondocgenerator.class.php - - message: '#^Property CommonObject\:\:\$element \(string\) in isset\(\) is not nullable\.$#' identifier: isset.property diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index 884639b234e..1f52f57bc31 100644 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -5,7 +5,7 @@ * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2015 Marcos García * Copyright (C) 2016-2023 Charlene Benke - * Copyright (C) 2018-2024 Frédéric France + * Copyright (C) 2018-2025 Frédéric France * Copyright (C) 2020 Josep Lluís Amador * Copyright (C) 2024 MDW * Copyright (C) 2024 Mélina Joum @@ -1174,11 +1174,11 @@ abstract class CommonDocGenerator * Note that vars into substitutions array are formatted. * * @param CommonObject $object Object with extrafields (must have $object->array_options filled) - * @param array $array_to_fill Substitution array + * @param array $array_to_fill Substitution array * @param Extrafields $extrafields Extrafields object * @param string $array_key Prefix for name of the keys into returned array * @param Translate $outputlangs Lang object to use for output - * @return array Substitution array + * @return array Substitution array */ public function fill_substitutionarray_with_extrafields($object, $array_to_fill, $extrafields, $array_key, $outputlangs) { diff --git a/htdocs/core/modules/asset/doc/doc_generic_asset_odt.modules.php b/htdocs/core/modules/asset/doc/doc_generic_asset_odt.modules.php index 92792da10e8..9848d61fbbd 100644 --- a/htdocs/core/modules/asset/doc/doc_generic_asset_odt.modules.php +++ b/htdocs/core/modules/asset/doc/doc_generic_asset_odt.modules.php @@ -4,7 +4,7 @@ * Copyright (C) 2014 Marcos García * Copyright (C) 2016 Charlie Benke * Copyright (C) 2018-2021 Philippe Grand - * Copyright (C) 2018-2024 Frédéric France + * Copyright (C) 2018-2025 Frédéric France * Copyright (C) 2024 MDW * * This program is free software; you can redistribute it and/or modify @@ -398,7 +398,7 @@ class doc_generic_asset_odt extends ModelePDFAsset } } // Replace tags of lines - $foundtagforlines = 1; + /*$foundtagforlines = 1; try { $listlines = $odfHandler->setSegment('lines'); } catch (OdfExceptionSegmentNotFound $e) { @@ -431,7 +431,7 @@ class doc_generic_asset_odt extends ModelePDFAsset dol_syslog($this->error, LOG_WARNING); return -1; } - } + }*/ // Replace labels translated $tmparray = $outputlangs->get_translations_for_substitutions(); From 712a2b544a3b4e058934736d21aa1872df2400fb Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Fri, 7 Feb 2025 10:46:13 +0100 Subject: [PATCH 374/383] Fix false positive --- htdocs/core/class/commondocgenerator.class.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index ba37cce06b2..ba2c7d0ae94 100644 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -927,6 +927,7 @@ abstract class CommonDocGenerator foreach ($date_specs as $date_spec) { $propertyname = $date_spec[1]; if (property_exists($line, $propertyname)) { + // @phan-suppress-next-line PhanUndeclaredProperty $resarray[$date_spec[0]] = dol_print_date($line->$propertyname, $date_spec[2], $date_spec[3], $date_spec[4]); } } From 28724db69e1e64e294b3dc871561e5c1b19b1669 Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Fri, 7 Feb 2025 10:52:23 +0100 Subject: [PATCH 375/383] Try to fix phpstan false positive --- htdocs/core/modules/bom/doc/doc_generic_bom_odt.modules.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/core/modules/bom/doc/doc_generic_bom_odt.modules.php b/htdocs/core/modules/bom/doc/doc_generic_bom_odt.modules.php index f8a99d51d40..006d797f5b6 100644 --- a/htdocs/core/modules/bom/doc/doc_generic_bom_odt.modules.php +++ b/htdocs/core/modules/bom/doc/doc_generic_bom_odt.modules.php @@ -405,6 +405,7 @@ class doc_generic_bom_odt extends ModelePDFBom if ($foundtagforlines) { $linenumber = 0; foreach ($object->lines as $line) { + /** @var BOMLine $line */ $linenumber++; if ($line->fk_product > 0) { From d01274ef4c5966b873476b40d30c75b55590d5d3 Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Fri, 7 Feb 2025 11:28:13 +0100 Subject: [PATCH 376/383] Fix phan --- .../modules/commande/doc/doc_generic_order_odt.modules.php | 1 + .../contract/doc/doc_generic_contract_odt.modules.php | 1 + .../modules/facture/doc/doc_generic_invoice_odt.modules.php | 1 + htdocs/core/modules/mrp/doc/doc_generic_mo_odt.modules.php | 1 + .../project/task/doc/doc_generic_task_odt.modules.php | 2 +- .../modules/propale/doc/doc_generic_proposal_odt.modules.php | 1 + .../reception/doc/doc_generic_reception_odt.modules.php | 1 + .../doc/doc_generic_supplier_invoice_odt.modules.php | 1 + .../doc/doc_generic_supplier_order_odt.modules.php | 1 + .../doc/doc_generic_supplier_proposal_odt.modules.php | 1 + htdocs/supplier_proposal/class/supplier_proposal.class.php | 5 +++++ 11 files changed, 15 insertions(+), 1 deletion(-) diff --git a/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php b/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php index 5ee13332781..3495cc57265 100644 --- a/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php +++ b/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php @@ -426,6 +426,7 @@ class doc_generic_order_odt extends ModelePDFCommandes if ($foundtagforlines) { $linenumber = 0; foreach ($object->lines as $line) { + /** @var OrderLine $line */ $linenumber++; $tmparray = $this->get_substitutionarray_lines($line, $outputlangs, $linenumber); complete_substitutions_array($tmparray, $outputlangs, $object, $line, "completesubstitutionarray_lines"); diff --git a/htdocs/core/modules/contract/doc/doc_generic_contract_odt.modules.php b/htdocs/core/modules/contract/doc/doc_generic_contract_odt.modules.php index 27a295e61e4..6c68888cebc 100644 --- a/htdocs/core/modules/contract/doc/doc_generic_contract_odt.modules.php +++ b/htdocs/core/modules/contract/doc/doc_generic_contract_odt.modules.php @@ -420,6 +420,7 @@ class doc_generic_contract_odt extends ModelePDFContract if ($foundtagforlines) { $linenumber = 0; foreach ($object->lines as $line) { + /** @var ContratLigne $line */ $linenumber++; $tmparray = $this->get_substitutionarray_lines($line, $outputlangs, $linenumber); complete_substitutions_array($tmparray, $outputlangs, $object, $line, "completesubstitutionarray_lines"); diff --git a/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php b/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php index f4435c982ed..7b081f4d4bd 100644 --- a/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php +++ b/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php @@ -482,6 +482,7 @@ class doc_generic_invoice_odt extends ModelePDFFactures if ($foundtagforlines) { $linenumber = 0; foreach ($object->lines as $line) { + /** @var FactureLigne $line */ $linenumber++; $tmparray = $this->get_substitutionarray_lines($line, $outputlangs, $linenumber); complete_substitutions_array($tmparray, $outputlangs, $object, $line, "completesubstitutionarray_lines"); diff --git a/htdocs/core/modules/mrp/doc/doc_generic_mo_odt.modules.php b/htdocs/core/modules/mrp/doc/doc_generic_mo_odt.modules.php index ff22719c4ab..93ce87f2be5 100644 --- a/htdocs/core/modules/mrp/doc/doc_generic_mo_odt.modules.php +++ b/htdocs/core/modules/mrp/doc/doc_generic_mo_odt.modules.php @@ -408,6 +408,7 @@ class doc_generic_mo_odt extends ModelePDFMo if ($foundtagforlines) { $linenumber = 0; foreach ($object->lines as $line) { + /** @var MoLine $line */ $linenumber++; $tmparray = $this->get_substitutionarray_lines($line, $outputlangs, $linenumber); complete_substitutions_array($tmparray, $outputlangs, $object, $line, "completesubstitutionarray_lines"); diff --git a/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php b/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php index a0c7210392a..2eb87a0189f 100644 --- a/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php +++ b/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php @@ -458,7 +458,7 @@ class doc_generic_task_odt extends ModelePDFTask /** * Function to build a document on disk using the generic odt module. * - * @param Project $object Object source to build document + * @param Task $object Object source to build document * @param Translate $outputlangs Lang output object * @param string $srctemplatepath Full path of source filename for generator using a template file * @return int<-1,1> 1 if OK, <=0 if KO diff --git a/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php b/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php index 86266b76b16..4e3f9adb01b 100644 --- a/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php +++ b/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php @@ -463,6 +463,7 @@ class doc_generic_proposal_odt extends ModelePDFPropales if ($foundtagforlines) { $linenumber = 0; foreach ($object->lines as $line) { + /** @var PropaleLigne $line */ $linenumber++; $tmparray = $this->get_substitutionarray_lines($line, $outputlangs, $linenumber); complete_substitutions_array($tmparray, $outputlangs, $object, $line, "completesubstitutionarray_lines"); diff --git a/htdocs/core/modules/reception/doc/doc_generic_reception_odt.modules.php b/htdocs/core/modules/reception/doc/doc_generic_reception_odt.modules.php index bf7247fdde8..68b20c45977 100644 --- a/htdocs/core/modules/reception/doc/doc_generic_reception_odt.modules.php +++ b/htdocs/core/modules/reception/doc/doc_generic_reception_odt.modules.php @@ -412,6 +412,7 @@ class doc_generic_reception_odt extends ModelePdfReception if ($foundtagforlines) { $linenumber = 0; foreach ($object->lines as $line) { + /** @var ReceptionLineBatch $line */ $linenumber++; $tmparray = $this->get_substitutionarray_lines($line, $outputlangs); complete_substitutions_array($tmparray, $outputlangs, $object, $line, "completesubstitutionarray_lines"); diff --git a/htdocs/core/modules/supplier_invoice/doc/doc_generic_supplier_invoice_odt.modules.php b/htdocs/core/modules/supplier_invoice/doc/doc_generic_supplier_invoice_odt.modules.php index d59451d9be9..6ec79297018 100644 --- a/htdocs/core/modules/supplier_invoice/doc/doc_generic_supplier_invoice_odt.modules.php +++ b/htdocs/core/modules/supplier_invoice/doc/doc_generic_supplier_invoice_odt.modules.php @@ -417,6 +417,7 @@ class doc_generic_supplier_invoice_odt extends ModelePDFSuppliersInvoices if ($foundtagforlines) { $linenumber = 0; foreach ($object->lines as $line) { + /** @var CommonInvoiceLine $line */ $linenumber++; $tmparray = $this->get_substitutionarray_lines($line, $outputlangs, $linenumber); complete_substitutions_array($tmparray, $outputlangs, $object, $line, "completesubstitutionarray_lines"); diff --git a/htdocs/core/modules/supplier_order/doc/doc_generic_supplier_order_odt.modules.php b/htdocs/core/modules/supplier_order/doc/doc_generic_supplier_order_odt.modules.php index fcfa4212862..2c26e3fb876 100644 --- a/htdocs/core/modules/supplier_order/doc/doc_generic_supplier_order_odt.modules.php +++ b/htdocs/core/modules/supplier_order/doc/doc_generic_supplier_order_odt.modules.php @@ -412,6 +412,7 @@ class doc_generic_supplier_order_odt extends ModelePDFSuppliersOrders if ($foundtagforlines) { $linenumber = 0; foreach ($object->lines as $line) { + /** @var CommonOrderLine $line */ $linenumber++; $tmparray = $this->get_substitutionarray_lines($line, $outputlangs, $linenumber); complete_substitutions_array($tmparray, $outputlangs, $object, $line, "completesubstitutionarray_lines"); diff --git a/htdocs/core/modules/supplier_proposal/doc/doc_generic_supplier_proposal_odt.modules.php b/htdocs/core/modules/supplier_proposal/doc/doc_generic_supplier_proposal_odt.modules.php index a17f724a5fa..b207a616be8 100644 --- a/htdocs/core/modules/supplier_proposal/doc/doc_generic_supplier_proposal_odt.modules.php +++ b/htdocs/core/modules/supplier_proposal/doc/doc_generic_supplier_proposal_odt.modules.php @@ -441,6 +441,7 @@ class doc_generic_supplier_proposal_odt extends ModelePDFSupplierProposal if ($foundtagforlines) { $linenumber = 0; foreach ($object->lines as $line) { + /** @var SupplierProposalLine $line */ $linenumber++; $tmparray = $this->get_substitutionarray_lines($line, $outputlangs, $linenumber); complete_substitutions_array($tmparray, $outputlangs, $object, $line, "completesubstitutionarray_lines"); diff --git a/htdocs/supplier_proposal/class/supplier_proposal.class.php b/htdocs/supplier_proposal/class/supplier_proposal.class.php index e33cdc6c377..fd534683010 100644 --- a/htdocs/supplier_proposal/class/supplier_proposal.class.php +++ b/htdocs/supplier_proposal/class/supplier_proposal.class.php @@ -192,7 +192,12 @@ class SupplierProposal extends CommonObject * @var array (Encoded as JSON in database) */ public $extraparams = array(); + + /** + * @var SupplierProposalLine[] + */ public $lines = array(); + /** * @var SupplierProposalLine */ From f05bc70b2e24b2401b6b1e99a600fe78e336c2e3 Mon Sep 17 00:00:00 2001 From: MDW Date: Wed, 5 Feb 2025 22:59:37 +0100 Subject: [PATCH 377/383] Qual: Fix phan notices (modulebuilder) --- dev/tools/phan/baseline.txt | 30 +--------- htdocs/core/lib/functions.lib.php | 7 ++- .../doc/doc_generic_usergroup_odt.modules.php | 4 +- htdocs/modulebuilder/index.php | 60 ++++++++----------- htdocs/modulebuilder/template/admin/setup.php | 4 +- .../modulebuilder/template/ajax/myobject.php | 2 +- .../template/class/api_mymodule.class.php | 26 ++++---- .../template/class/myobject.class.php | 2 +- .../doc/pdf_standard_myobject.modules.php | 12 ++-- .../mymodule/mod_myobject_advanced.php | 4 +- .../modulebuilder/template/myobject_list.php | 18 +++--- 11 files changed, 71 insertions(+), 98 deletions(-) diff --git a/dev/tools/phan/baseline.txt b/dev/tools/phan/baseline.txt index 716996e9d84..0da0c9a1237 100644 --- a/dev/tools/phan/baseline.txt +++ b/dev/tools/phan/baseline.txt @@ -9,9 +9,9 @@ */ return [ // # Issue statistics: - // PhanTypeMismatchArgument : 2560+ occurrences + // PhanTypeMismatchArgument : 2490+ occurrences // PhanUndeclaredProperty : 530+ occurrences - // PhanTypeMismatchArgumentNullable : 450+ occurrences + // PhanTypeMismatchArgumentNullable : 430+ occurrences // PhanUndeclaredGlobalVariable : 190+ occurrences // PhanPluginUnknownArrayMethodReturnType : 180+ occurrences // PhanPossiblyUndeclaredGlobalVariable : 160+ occurrences @@ -84,7 +84,7 @@ return [ 'htdocs/adherents/admin/website.php' => ['PhanTypeMismatchArgument'], 'htdocs/adherents/canvas/actions_adherentcard_common.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/adherents/card.php' => ['PhanTypeMismatchArgument'], - 'htdocs/adherents/class/adherent.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], + 'htdocs/adherents/class/adherent.class.php' => ['PhanTypeMismatchArgumentNullable'], 'htdocs/adherents/class/adherent_type.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/adherents/class/api_members.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/adherents/list.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredGlobalVariable'], @@ -411,20 +411,16 @@ return [ 'htdocs/core/login/functions_dolibarr.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/login/functions_ldap.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/core/menus/standard/auguria.lib.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/asset/doc/doc_generic_asset_odt.modules.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/asset/doc/pdf_standard_asset.modules.php' => ['PhanTypeMismatchArgumentNullable'], 'htdocs/core/modules/asset/mod_asset_advanced.php' => ['PhanUndeclaredProperty'], 'htdocs/core/modules/barcode/mod_barcode_product_standard.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/barcode/mod_barcode_thirdparty_standard.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/bom/doc/doc_generic_bom_odt.modules.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/bom/mod_bom_advanced.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], 'htdocs/core/modules/cheque/doc/pdf_blochet.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/core/modules/cheque/modules_chequereceipts.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/commande/doc/pdf_einstein.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchDimFetch', 'PhanTypeMismatchProperty', 'PhanUndeclaredProperty'], 'htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchDimFetch', 'PhanTypeMismatchProperty', 'PhanUndeclaredProperty'], 'htdocs/core/modules/commande/mod_commande_saphir.php' => ['PhanTypeMismatchArgumentNullable'], - 'htdocs/core/modules/contract/doc/doc_generic_contract_odt.modules.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/contract/doc/pdf_strato.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/core/modules/delivery/doc/pdf_storm.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/core/modules/delivery/doc/pdf_typhon.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], @@ -435,7 +431,6 @@ return [ 'htdocs/core/modules/expedition/doc/pdf_rouget.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/core/modules/expensereport/doc/pdf_standard_expensereport.modules.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], 'htdocs/core/modules/expensereport/mod_expensereport_jade.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/facture/doc/pdf_crabe.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/core/modules/facture/doc/pdf_octopus.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/core/modules/facture/doc/pdf_sponge.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], @@ -471,38 +466,29 @@ return [ 'htdocs/core/modules/modSupplierProposal.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/modTicket.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/movement/doc/pdf_standard_movementstock.modules.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/mrp/doc/doc_generic_mo_odt.modules.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/mrp/doc/pdf_vinci.modules.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], 'htdocs/core/modules/mrp/mod_mo_advanced.php' => ['PhanUndeclaredProperty'], 'htdocs/core/modules/oauth/github_oauthcallback.php' => ['PhanUndeclaredGlobalVariable'], 'htdocs/core/modules/printsheet/doc/pdf_standardlabel.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/printsheet/doc/pdf_tcpdflabel.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/product/doc/doc_generic_product_odt.modules.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/project/doc/doc_generic_project_odt.modules.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], 'htdocs/core/modules/project/doc/pdf_beluga.modules.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/project/doc/pdf_timespent.modules.php' => ['PhanUndeclaredProperty'], 'htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], - 'htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/propale/doc/pdf_azur.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/core/modules/propale/doc/pdf_cyan.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], - 'htdocs/core/modules/reception/doc/doc_generic_reception_odt.modules.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/reception/doc/pdf_squille.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/core/modules/societe/doc/doc_generic_odt.modules.php' => ['PhanTypeMismatchArgumentNullable'], - 'htdocs/core/modules/stock/doc/doc_generic_stock_odt.modules.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/stocktransfer/doc/pdf_eagle.modules.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], 'htdocs/core/modules/stocktransfer/doc/pdf_eagle_proforma.modules.php' => ['PhanTypeMismatchArgumentNullable'], 'htdocs/core/modules/stocktransfer/mod_stocktransfer_advanced.php' => ['PhanUndeclaredProperty'], - 'htdocs/core/modules/supplier_invoice/doc/doc_generic_supplier_invoice_odt.modules.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/supplier_invoice/doc/pdf_canelle.modules.php' => ['PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchProperty'], - 'htdocs/core/modules/supplier_order/doc/doc_generic_supplier_order_odt.modules.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/supplier_order/doc/pdf_cornas.modules.php' => ['PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchDimFetch', 'PhanTypeMismatchProperty', 'PhanUndeclaredProperty'], 'htdocs/core/modules/supplier_order/doc/pdf_muscadet.modules.php' => ['PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchDimFetch', 'PhanTypeMismatchProperty', 'PhanUndeclaredProperty'], - 'htdocs/core/modules/supplier_proposal/doc/doc_generic_supplier_proposal_odt.modules.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/supplier_proposal/doc/pdf_aurore.modules.php' => ['PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchDimFetch', 'PhanTypeMismatchProperty', 'PhanUndeclaredProperty'], 'htdocs/core/modules/supplier_proposal/doc/pdf_zenith.modules.php' => ['PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchDimFetch', 'PhanTypeMismatchProperty', 'PhanUndeclaredProperty'], 'htdocs/core/modules/syslog/mod_syslog_file.php' => ['PhanPluginDuplicateArrayKey'], 'htdocs/core/modules/user/doc/doc_generic_user_odt.modules.php' => ['PhanTypeMismatchArgumentNullable'], - 'htdocs/core/modules/usergroup/doc/doc_generic_usergroup_odt.modules.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/workstation/mod_workstation_advanced.php' => ['PhanUndeclaredProperty'], 'htdocs/core/multicompany_page.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/search_page.php' => ['PhanTypeMismatchArgument'], @@ -622,15 +608,6 @@ return [ 'htdocs/loan/document.php' => ['PhanUndeclaredProperty'], 'htdocs/loan/note.php' => ['PhanUndeclaredProperty'], 'htdocs/loan/payment/payment.php' => ['PhanUndeclaredProperty'], - 'htdocs/modulebuilder/index.php' => ['PhanTypeMismatchArgumentNullable'], - 'htdocs/modulebuilder/template/admin/setup.php' => ['PhanTypeMismatchArgument'], - 'htdocs/modulebuilder/template/ajax/myobject.php' => ['PhanTypeMismatchArgument'], - 'htdocs/modulebuilder/template/class/api_mymodule.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/modulebuilder/template/class/myobject.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/modulebuilder/template/core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php' => ['PhanTypeMismatchArgument'], - 'htdocs/modulebuilder/template/core/modules/mymodule/doc/pdf_standard_myobject.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], - 'htdocs/modulebuilder/template/core/modules/mymodule/mod_myobject_advanced.php' => ['PhanTypeMismatchArgument'], - 'htdocs/modulebuilder/template/myobject_list.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/mrp/ajax/ajax_bom.php' => ['PhanTypeMismatchArgument'], 'htdocs/mrp/class/api_mos.class.php' => ['PhanPluginUnknownArrayMethodParamType', 'PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument'], 'htdocs/mrp/class/mo.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchProperty'], @@ -802,7 +779,6 @@ return [ 'htdocs/recruitment/class/api_recruitments.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/recruitment/class/recruitmentcandidature.class.php' => ['PhanUndeclaredProperty'], 'htdocs/recruitment/class/recruitmentjobposition.class.php' => ['PhanUndeclaredProperty'], - 'htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php' => ['PhanTypeMismatchArgument'], 'htdocs/recruitment/core/modules/recruitment/doc/pdf_standard_recruitmentjobposition.modules.php' => ['PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/recruitment/core/modules/recruitment/mod_recruitmentcandidature_advanced.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], 'htdocs/recruitment/core/modules/recruitment/mod_recruitmentjobposition_advanced.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 3695a1eeb69..567eb7e4b86 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -1207,7 +1207,7 @@ function checkVal($out = '', $check = 'alphanohtml', $filter = null, $options = /** * Return a sanitized or empty value after checking value against a rule. * - * @param string|array $out Value to check/clear. + * @param string|mixed[]|null $out Value to check/clear. * @param string $check Type of check/sanitizing * @param ?int $filter Filter to apply when $check is set to 'custom'. (See http://php.net/manual/en/filter.filters.php for détails) * @param ?mixed $options Options to pass to filter_var when $check is set to 'custom' @@ -1217,6 +1217,9 @@ function sanitizeVal($out = '', $check = 'alphanohtml', $filter = null, $options { // TODO : use class "Validate" to perform tests (and add missing tests) if needed for factorize // Check is done after replacement + if ($out === null) { + $out = ''; + } switch ($check) { case 'none': case 'password': @@ -9895,7 +9898,7 @@ function make_substitutions($text, $substitutionarray, $outputlangs = null, $con * Complete the $substitutionarray with more entries coming from external module that had set the "substitutions=1" into module_part array. * In this case, method completesubstitutionarray provided by module is called. * - * @param array $substitutionarray Array substitution old value => new value value + * @param array $substitutionarray Array substitution old value => new value value * @param Translate $outputlangs Output language * @param ?CommonObject $object Source object * @param ?mixed $parameters Add more parameters (useful to pass product lines) diff --git a/htdocs/core/modules/usergroup/doc/doc_generic_usergroup_odt.modules.php b/htdocs/core/modules/usergroup/doc/doc_generic_usergroup_odt.modules.php index da30d9a0b21..55015b96550 100644 --- a/htdocs/core/modules/usergroup/doc/doc_generic_usergroup_odt.modules.php +++ b/htdocs/core/modules/usergroup/doc/doc_generic_usergroup_odt.modules.php @@ -2,7 +2,7 @@ /* Copyright (C) 2010-2012 Laurent Destailleur * Copyright (C) 2012 Juanjo Menent * Copyright (C) 2018-2024 Frédéric France - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 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 @@ -447,7 +447,7 @@ class doc_generic_usergroup_odt extends ModelePDFUserGroup $reshook = $hookmanager->executeHooks('ODTSubstitutionLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks foreach ($tmparray as $key => $val) { try { - if (!is_array($val)) { + if (!is_array($val)) { // @phpstan-ignore-line $listlines->setVars($key, $val, true, 'UTF-8'); } } catch (SegmentException $e) { diff --git a/htdocs/modulebuilder/index.php b/htdocs/modulebuilder/index.php index 86726bb5543..a947d497024 100644 --- a/htdocs/modulebuilder/index.php +++ b/htdocs/modulebuilder/index.php @@ -2,7 +2,7 @@ /* Copyright (C) 2004-2023 Laurent Destailleur * Copyright (C) 2018-2019 Nicolas ZABOURI * Copyright (C) 2023 Alexandre Janniaux - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) 2024 Frédéric France * * This program is free software; you can redistribute it and/or modify @@ -67,7 +67,7 @@ $sortfield = GETPOST('sortfield', 'alpha'); $sortorder = GETPOST('sortorder', 'aZ09'); $module = GETPOST('module', 'alpha'); -$tab = GETPOST('tab', 'aZ09'); +$tab = (string) GETPOST('tab', 'aZ09'); $tabobj = GETPOST('tabobj', 'alpha'); $tabdic = GETPOST('tabdic', 'alpha'); $propertykey = GETPOST('propertykey', 'alpha'); @@ -77,6 +77,7 @@ if (empty($module)) { if (empty($tab)) { $tab = 'description'; } +'@phan-var-force string $tab'; // Workaround 'empty()' bug of phan if (empty($tabobj)) { $tabobj = 'newobjectifnoobj'; } @@ -850,6 +851,7 @@ if ($dirins && $action == 'initcli' && !empty($module) && $user->hasRight("modul $moduledescriptorfile = '/not_set/'; +$modulelowercase = null; // init Doc if ($dirins && $action == 'initdoc' && !empty($module) && $user->hasRight("modulebuilder", "run")) { @@ -1288,7 +1290,7 @@ if ($dirins && $action == 'initobject' && $module && $objectname && $user->hasRi $position = 900; } // $alwayseditable - $alwayseditable=0; + $alwayseditable = 0; if ($fieldname == 'label') { $alwayseditable = 1; } else { @@ -2347,15 +2349,12 @@ if ($dirins && $action == 'generatepackage' && $user->hasRight("modulebuilder", $dirofmodule = dol_buildpath($modulelowercase, 0).'/bin'; $outputfilezip = $dirofmodule.'/'.$FILENAMEZIP; - if ($dirofmodule) { - if (!dol_is_dir($dirofmodule)) { - dol_mkdir($dirofmodule); - } - // Note: We exclude /bin/ to not include the already generated zip - $result = dol_compress_dir($dir, $outputfilezip, 'zip', '/\/bin\/|\.git|\.old|\.back|\.ssh/', $modulelowercase); - } else { - $result = -1; + + if (!dol_is_dir($dirofmodule)) { + dol_mkdir($dirofmodule); } + // Note: We exclude /bin/ to not include the already generated zip + $result = dol_compress_dir($dir, $outputfilezip, 'zip', '/\/bin\/|\.git|\.old|\.back|\.ssh/', $modulelowercase); if ($result > 0) { setEventMessages($langs->trans("ZipFileGeneratedInto", $outputfilezip), null); @@ -2706,12 +2705,9 @@ if ($action == 'set' && $user->admin && $user->hasRight("modulebuilder", "run")) if ($module) { $param .= '&module='.urlencode($module); } - if ($tab) { - $param .= '&tab='.urlencode($tab); - } - if ($tabobj) { - $param .= '&tabobj='.urlencode($tabobj); - } + + $param .= '&tab='.urlencode($tab); + $param .= '&tabobj='.urlencode($tabobj); $value = GETPOST('value', 'alpha'); $resarray = activateModule($value); @@ -2744,12 +2740,8 @@ if ($action == 'reset' && $user->admin && $user->hasRight("modulebuilder", "run" if ($module) { $param .= '&module='.urlencode($module); } - if ($tab) { - $param .= '&tab='.urlencode($tab); - } - if ($tabobj) { - $param .= '&tabobj='.urlencode($tabobj); - } + $param .= '&tab='.urlencode($tab); + $param .= '&tabobj='.urlencode($tabobj); $value = GETPOST('value', 'alpha'); $result = unActivateModule($value); @@ -3310,15 +3302,12 @@ if (is_array($listofmodules) && count($listofmodules) > 0) { $modulelowercase = strtolower($module); $param = ''; - if ($tab) { - $param .= '&tab='.urlencode($tab); - } if ($module) { $param .= '&module='.urlencode($module); } - if ($tabobj) { - $param .= '&tabobj='.urlencode($tabobj); - } + + $param .= '&tab='.urlencode($tab); + $param .= '&tabobj='.urlencode($tabobj); $urltomodulesetup = ''.$langs->trans('Home').'-'.$langs->trans("Setup").'-'.$langs->trans("Modules").''; @@ -3333,9 +3322,7 @@ if (is_array($listofmodules) && count($listofmodules) > 0) { $objMod = $moduleobj; $backtourlparam = ''; $backtourlparam .= ($backtourlparam ? '&' : '?').'module='.$module; // No urlencode here, done later - if ($tab) { - $backtourlparam .= ($backtourlparam ? '&' : '?').'tab='.$tab; // No urlencode here, done later - } + $backtourlparam .= ($backtourlparam ? '&' : '?').'tab='.$tab; // No urlencode here, done later $backtourl = $_SERVER["PHP_SELF"].$backtourlparam; $regs = array(); @@ -3493,7 +3480,7 @@ if ($module == 'initmodule') { print ''; print ''; print ''; -} elseif (!empty($module) && isset($modulelowercase)) { +} elseif (!empty($module) && $modulelowercase !== null) { // Tabs for module if (!$error) { $dirread = $listofmodules[strtolower($module)]['moduledescriptorrootpath']; @@ -3848,6 +3835,7 @@ if ($module == 'initmodule') { } else { // Edit text file $fullpathoffile = dol_buildpath($file, 0, 1); // Description - level 2 + $content = ''; if ($fullpathoffile) { $content = file_get_contents($fullpathoffile); } @@ -4377,7 +4365,7 @@ if ($module == 'initmodule') { print $form->textwithpicto('', $langs->trans("InfoForApiFile"), 1, 'warning'); print '   '; // Comparing to null (phan considers $modulelowercase can be null here) - if ($modulelowercase !== null && !isModEnabled($modulelowercase)) { // If module is not activated + if (!isModEnabled($modulelowercase)) { // If module is not activated print ''.$langs->trans("ApiExplorer").''; } else { print ''.$langs->trans("ApiExplorer").''; @@ -6418,7 +6406,7 @@ if ($module == 'initmodule') { print ''; print ''; print "\n"; @@ -589,7 +589,7 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) { $htmltooltip .= '
'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang, 1, 1); print ''; // Preview diff --git a/htdocs/modulebuilder/template/ajax/myobject.php b/htdocs/modulebuilder/template/ajax/myobject.php index d4ca191942b..98bd1909bde 100644 --- a/htdocs/modulebuilder/template/ajax/myobject.php +++ b/htdocs/modulebuilder/template/ajax/myobject.php @@ -66,7 +66,7 @@ dol_include_once('/mymodule/class/myobject.class.php'); */ $mode = GETPOST('mode', 'aZ09'); -$objectId = GETPOST('objectId', 'aZ09'); +$objectId = GETPOSTINT('objectId'); $field = GETPOST('field', 'aZ09'); $value = GETPOST('value', 'aZ09'); diff --git a/htdocs/modulebuilder/template/class/api_mymodule.class.php b/htdocs/modulebuilder/template/class/api_mymodule.class.php index a57d497ea30..11da9de8345 100644 --- a/htdocs/modulebuilder/template/class/api_mymodule.class.php +++ b/htdocs/modulebuilder/template/class/api_mymodule.class.php @@ -38,7 +38,7 @@ dol_include_once('/mymodule/class/myobject.class.php'); class MyModuleApi extends DolibarrApi { /** - * @var MyObject $myobject {@type MyObject} + * @var MyObject {@type MyObject} */ public $myobject; @@ -46,7 +46,6 @@ class MyModuleApi extends DolibarrApi * Constructor * * @url GET / - * */ public function __construct() { @@ -194,8 +193,8 @@ class MyModuleApi extends DolibarrApi * Create myobject object * * @param array $request_data Request data - * @phan-param array{string,mixed} $request_data - * @phpstan-param array{string,mixed} $request_data + * @phan-param ?array $request_data + * @phpstan-param ?array $request_data * @return int ID of myobject * * @throws RestException 403 Not allowed @@ -215,7 +214,7 @@ class MyModuleApi extends DolibarrApi foreach ($request_data as $field => $value) { if ($field === 'caller') { // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again with the caller @phan-suppress-next-line PhanTypeInvalidDimOffset - $this->myobject->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09'); + $this->myobject->context['caller'] = sanitizeVal((string) $request_data['caller'], 'aZ09'); continue; } @@ -243,8 +242,8 @@ class MyModuleApi extends DolibarrApi * * @param int $id Id of myobject to update * @param array $request_data Data - * @phan-param mixed[] $request_data - * @phpstan-param mixed[] $request_data + * @phan-param ?array $request_data + * @phpstan-param ?array $request_data * @return Object Object after update * @phan-return MyObject * @phpstan-return MyObject @@ -301,7 +300,7 @@ class MyModuleApi extends DolibarrApi // Clean data // $this->myobject->abc = sanitizeVal($this->myobject->abc, 'alphanohtml'); - if ($this->myobject->update(DolibarrApiAccess::$user, false) > 0) { + if ($this->myobject->update(DolibarrApiAccess::$user, 0) > 0) { return $this->get($id); } else { throw new RestException(500, $this->myobject->error); @@ -356,16 +355,19 @@ class MyModuleApi extends DolibarrApi * Validate fields before creating or updating object * * @param array $data Array of data to validate - * @phan-param array $data - * @phpstan-param array $data + * @phan-param ?array $data + * @phpstan-param ?array $data * @return array - * @phan-return array|array{} - * @phpstan-return array|array{} + * @phan-return array|array{} + * @phpstan-return array|array{} * * @throws RestException */ private function _validateMyObject($data) { + if (!is_array($data)) { + $data = array(); + } $myobject = array(); foreach ($this->myobject->fields as $field => $propfield) { if (in_array($field, array('rowid', 'entity', 'date_creation', 'tms', 'fk_user_creat')) || $propfield['notnull'] != 1) { diff --git a/htdocs/modulebuilder/template/class/myobject.class.php b/htdocs/modulebuilder/template/class/myobject.class.php index ceefd2998b0..500cdcaa476 100644 --- a/htdocs/modulebuilder/template/class/myobject.class.php +++ b/htdocs/modulebuilder/template/class/myobject.class.php @@ -802,7 +802,7 @@ class MyObject extends CommonObject $result = ''; $params = [ - 'id' => $this->id, + 'id' => (string) $this->id, 'objecttype' => $this->element.($this->module ? '@'.$this->module : ''), 'option' => $option, ]; diff --git a/htdocs/modulebuilder/template/core/modules/mymodule/doc/pdf_standard_myobject.modules.php b/htdocs/modulebuilder/template/core/modules/mymodule/doc/pdf_standard_myobject.modules.php index 7ac4f25e47e..9abc8daff75 100644 --- a/htdocs/modulebuilder/template/core/modules/mymodule/doc/pdf_standard_myobject.modules.php +++ b/htdocs/modulebuilder/template/core/modules/mymodule/doc/pdf_standard_myobject.modules.php @@ -9,7 +9,7 @@ * Copyright (C) 2015 Marcos García * Copyright (C) 2017 Ferran Marcet * Copyright (C) 2018-2024 Frédéric France - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) 2024 Alexandre Spangaro * Copyright (C) ---Replace with your own copyright and developer email--- * @@ -431,12 +431,12 @@ class pdf_standard_myobject extends ModelePDFMyObject // $this->_pagefoot($pdf,$object,$outputlangs,1); $pdf->setTopMargin($tab_top_newpage); // The only function to edit the bottom margin of current page to set it. - $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); + $pdf->setPageOrientation('', true, $heightforfooter + $heightforfreetext); } // back to start $pdf->setPage($pageposbeforenote); - $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); + $pdf->setPageOrientation('', true, $heightforfooter + $heightforfreetext); $pdf->SetFont('', '', $default_font_size - 1); $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1); $pageposafternote = $pdf->getPage(); @@ -450,7 +450,7 @@ class pdf_standard_myobject extends ModelePDFMyObject $pdf->setPage($pageposafternote); $pdf->setTopMargin($tab_top_newpage); // The only function to edit the bottom margin of current page to set it. - $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); + $pdf->setPageOrientation('', true, $heightforfooter + $heightforfreetext); //$posyafter = $tab_top_newpage; } @@ -472,7 +472,7 @@ class pdf_standard_myobject extends ModelePDFMyObject } // Add footer - $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + $pdf->setPageOrientation('', true, 0); // The only function to edit the bottom margin of current page to set it. $this->_pagefoot($pdf, $object, $outputlangs, 1); $i++; @@ -1174,7 +1174,7 @@ class pdf_standard_myobject extends ModelePDFMyObject $pdf->SetXY($posx + 2, $posy + 3); $pdf->SetFont('', 'B', $default_font_size); // @phan-suppress-next-line PhanPluginSuspiciousParamOrder - $pdf->MultiCell($widthrecbox, 2, $carac_client_name, 0, $ltrdirection); + $pdf->MultiCell($widthrecbox, 2, (string) $carac_client_name, 0, $ltrdirection); $posy = $pdf->getY(); diff --git a/htdocs/modulebuilder/template/core/modules/mymodule/mod_myobject_advanced.php b/htdocs/modulebuilder/template/core/modules/mymodule/mod_myobject_advanced.php index c8117863f12..b900878417c 100644 --- a/htdocs/modulebuilder/template/core/modules/mymodule/mod_myobject_advanced.php +++ b/htdocs/modulebuilder/template/core/modules/mymodule/mod_myobject_advanced.php @@ -4,7 +4,7 @@ * Copyright (C) 2005-2009 Regis Houssin * Copyright (C) 2008i Raphael Bertrand (Resultic) * Copyright (C) 2019-2024 Frédéric France - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) ---Replace with your own copyright and developer email--- * * This program is free software; you can redistribute it and/or modify @@ -83,7 +83,7 @@ class mod_myobject_advanced extends ModeleNumRefMyObject // prefix configuration $text .= ''; - $text .= ''; + $text .= ''; $text .= ''; $text .= ''; diff --git a/htdocs/modulebuilder/template/myobject_list.php b/htdocs/modulebuilder/template/myobject_list.php index 2451c35d972..6972f0f2567 100644 --- a/htdocs/modulebuilder/template/myobject_list.php +++ b/htdocs/modulebuilder/template/myobject_list.php @@ -336,14 +336,18 @@ foreach ($search as $key => $val) { if ($key == 'status' && $search[$key] == -1) { continue; } - $mode_search = (($object->isInt($object->fields[$key]) || $object->isFloat($object->fields[$key])) ? 1 : 0); - if ((strpos($object->fields[$key]['type'], 'integer:') === 0) || (strpos($object->fields[$key]['type'], 'sellist:') === 0) || !empty($object->fields[$key]['arrayofkeyval'])) { - if ($search[$key] == '-1' || ($search[$key] === '0' && (empty($object->fields[$key]['arrayofkeyval']) || !array_key_exists('0', $object->fields[$key]['arrayofkeyval'])))) { + $field_spec = $object->fields[$key]; + if ($field_spec === null) { + continue; + } + $mode_search = (($object->isInt($field_spec) || $object->isFloat($field_spec)) ? 1 : 0); + if ((strpos($field_spec['type'], 'integer:') === 0) || (strpos($field_spec['type'], 'sellist:') === 0) || !empty($field_spec['arrayofkeyval'])) { + if ($search[$key] == '-1' || ($search[$key] === '0' && (empty($field_spec['arrayofkeyval']) || !array_key_exists('0', $field_spec['arrayofkeyval'])))) { $search[$key] = ''; } $mode_search = 2; } - if (empty($object->fields[$key]['searchmulti'])) { + if (empty($field_spec['searchmulti'])) { if (!is_array($search[$key]) && $search[$key] != '') { $sql .= natural_search("t.".$db->escape($key), $search[$key], (($key == 'status') ? 2 : $mode_search)); } @@ -829,15 +833,15 @@ while ($i < $imaxinloop) { if (!empty($arrayfields['t.'.$key]['checked'])) { print '$key) && !in_array($key, array('ref'))) { - print ' title="'.dol_escape_htmltag($object->$key).'"'; + print ' title="'.dol_escape_htmltag((string) $object->$key).'"'; } print '>'; if ($key == 'status') { print $object->getLibStatut(5); } elseif ($key == 'rowid') { - print $object->showOutputField($val, $key, $object->id, ''); + print $object->showOutputField($val, $key, (string) $object->id, ''); } else { - print $object->showOutputField($val, $key, $object->$key, ''); + print $object->showOutputField($val, $key, (string) $object->$key, ''); } print ''; if (!$i) { From 68ffd2b6a8011bd176b4570d41c27d4555fa3573 Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Fri, 7 Feb 2025 12:51:44 +0100 Subject: [PATCH 378/383] Doc --- htdocs/install/mysql/migration/repair.sql | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/htdocs/install/mysql/migration/repair.sql b/htdocs/install/mysql/migration/repair.sql index 8262a3e1c98..dfae51fd352 100644 --- a/htdocs/install/mysql/migration/repair.sql +++ b/htdocs/install/mysql/migration/repair.sql @@ -602,6 +602,10 @@ DELETE FROM llx_rights_def WHERE module = 'hrm' AND perms = 'employee'; -- UPDATE llx_bank as b SET b.amount_main_currency = -b.amount_main_currency WHERE b.amount IS NOT NULL AND b.amount_main_currency IS NOT NULL AND SIGN(b.amount_main_currency) <> SIGN(b.amount); +-- Sequence to fix the table llx_paiement_facture and llx_paiement for payment record on a bank account that does not exists anymore. +-- delete from llx_paiement_facture where fk_paiement in (select rowid from llx_paiement WHERE fk_bank is not null AND fk_bank not in (select rowid from llx_bank)); +-- delete from llx_paiement WHERE fk_bank is not null AND fk_bank not in (select rowid from llx_bank); + -- Delete duplicate entries into llx_c_transport_mode -- VMYSQL4.1 DELETE T1 FROM llx_c_transport_mode as T1, llx_c_transport_mode as T2 where T1.entity = T2.entity AND T1.code = T2.code and T1.rowid > T2.rowid; From 0b67bf4dad96eb0bc42c8a7b77684eb32e11fb50 Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Fri, 7 Feb 2025 13:00:24 +0100 Subject: [PATCH 379/383] Fix phan --- htdocs/core/modules/project/modules_project.php | 2 +- .../modules/project/task/doc/doc_generic_task_odt.modules.php | 2 ++ .../modules/mymodule/doc/doc_generic_myobject_odt.modules.php | 1 + .../doc/doc_generic_recruitmentjobposition_odt.modules.php | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/htdocs/core/modules/project/modules_project.php b/htdocs/core/modules/project/modules_project.php index 48885f0e4c7..f0f8bdf6cb1 100644 --- a/htdocs/core/modules/project/modules_project.php +++ b/htdocs/core/modules/project/modules_project.php @@ -68,7 +68,7 @@ abstract class ModelePDFProjects extends CommonDocGenerator /** * Function to build pdf project onto disk * - * @param Project $object Object source to build document + * @param Task $object Object source to build document * @param Translate $outputlangs Lang output object * @param string $srctemplatepath Full path of source filename for generator using a template file * @return int<-1,1> 1 if OK, <=0 if KO diff --git a/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php b/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php index 2eb87a0189f..6c9f3b43861 100644 --- a/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php +++ b/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php @@ -606,6 +606,8 @@ class doc_generic_task_odt extends ModelePDFTask } } + /** var Task $object */ + // Replace tags of lines for tasks try { // Security check diff --git a/htdocs/modulebuilder/template/core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php b/htdocs/modulebuilder/template/core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php index e4f82b3a537..59ae7b1ec71 100644 --- a/htdocs/modulebuilder/template/core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php +++ b/htdocs/modulebuilder/template/core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php @@ -445,6 +445,7 @@ class doc_generic_myobject_odt extends ModelePDFMyObject if ($foundtagforlines) { $linenumber = 0; foreach ($object->lines as $line) { + /** @var CommonObjectLine $line */ $linenumber++; $tmparray = $this->get_substitutionarray_lines($line, $outputlangs, $linenumber); complete_substitutions_array($tmparray, $outputlangs, $object, $line, "completesubstitutionarray_lines"); diff --git a/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php b/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php index f40dcf70b41..637ba4f0cba 100644 --- a/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php +++ b/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php @@ -437,6 +437,7 @@ class doc_generic_recruitmentjobposition_odt extends ModelePDFRecruitmentJobPosi if ($foundtagforlines) { $linenumber = 0; foreach ($object->lines as $line) { + /** @var CommonObjectLine $line */ $linenumber++; $tmparray = $this->get_substitutionarray_lines($line, $outputlangs, $linenumber); complete_substitutions_array($tmparray, $outputlangs, $object, $line, "completesubstitutionarray_lines"); From c01c49074c4f11a636bc38ba0044c5813e73f5ea Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Fri, 7 Feb 2025 14:12:42 +0100 Subject: [PATCH 380/383] Fix phan --- .../modules/project/task/doc/doc_generic_task_odt.modules.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php b/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php index 6c9f3b43861..e45ce84f946 100644 --- a/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php +++ b/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php @@ -606,7 +606,7 @@ class doc_generic_task_odt extends ModelePDFTask } } - /** var Task $object */ + /** @var Task $object */ // Replace tags of lines for tasks try { From 568a7723c92584b05294b79e5a3f5df0dc7bb329 Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Fri, 7 Feb 2025 14:16:48 +0100 Subject: [PATCH 381/383] Fix phan --- htdocs/core/modules/project/modules_project.php | 8 ++++---- htdocs/core/modules/project/task/modules_task.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/htdocs/core/modules/project/modules_project.php b/htdocs/core/modules/project/modules_project.php index f0f8bdf6cb1..26ffc207484 100644 --- a/htdocs/core/modules/project/modules_project.php +++ b/htdocs/core/modules/project/modules_project.php @@ -68,10 +68,10 @@ abstract class ModelePDFProjects extends CommonDocGenerator /** * Function to build pdf project onto disk * - * @param Task $object Object source to build document - * @param Translate $outputlangs Lang output object - * @param string $srctemplatepath Full path of source filename for generator using a template file - * @return int<-1,1> 1 if OK, <=0 if KO + * @param Project $object Object source to build document + * @param Translate $outputlangs Lang output object + * @param string $srctemplatepath Full path of source filename for generator using a template file + * @return int<-1,1> 1 if OK, <=0 if KO */ abstract public function write_file($object, $outputlangs, $srctemplatepath = ''); // phpcs:enable diff --git a/htdocs/core/modules/project/task/modules_task.php b/htdocs/core/modules/project/task/modules_task.php index 4bc906f6fae..5409b887914 100644 --- a/htdocs/core/modules/project/task/modules_task.php +++ b/htdocs/core/modules/project/task/modules_task.php @@ -60,7 +60,7 @@ abstract class ModelePDFTask extends CommonDocGenerator /** * Function to build a document on disk using the generic odt module. * - * @param Project $object Object source to build document + * @param Task $object Object source to build document * @param Translate $outputlangs Lang output object * @param string $srctemplatepath Full path of source filename for generator using a template file * @return int<-1,1> 1 if OK, <=0 if KO From baa6a7928e5fab30d1e7f8b5702a30eb3fab39bd Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Fri, 7 Feb 2025 14:38:28 +0100 Subject: [PATCH 382/383] Fix type --- htdocs/societe/class/societe.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 27fb8fd3c27..21eb8e910d6 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -2525,7 +2525,7 @@ class Societe extends CommonObject // Position current discount $sql = "UPDATE ".MAIN_DB_PREFIX."societe "; - $sql .= " SET remise_supplier = '".$this->db->escape($remise)."'"; + $sql .= " SET remise_supplier = ".((float) $remise); $sql .= " WHERE rowid = ".((int) $this->id); $resql = $this->db->query($sql); if (!$resql) { @@ -2574,7 +2574,7 @@ class Societe extends CommonObject global $langs; // Clean parameters - $remise = price2num($remise); + $remise = (float) price2num($remise); $desc = trim($desc); // Check parameters From e57e185ef15e6b12a29cd67e0c075e62b2b75d99 Mon Sep 17 00:00:00 2001 From: "Laurent Destailleur (aka Eldy)" Date: Fri, 7 Feb 2025 14:39:37 +0100 Subject: [PATCH 383/383] Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop --- htdocs/societe/class/societe.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 21eb8e910d6..cb7cc1ad018 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -2537,7 +2537,7 @@ class Societe extends CommonObject // Writes trace in discount history $sql = "INSERT INTO ".MAIN_DB_PREFIX."societe_remise_supplier"; $sql .= " (entity, datec, fk_soc, remise_supplier, note, fk_user_author)"; - $sql .= " VALUES (".((int) $conf->entity).", '".$this->db->idate($now)."', ".((int) $this->id).", '".$this->db->escape($remise)."',"; + $sql .= " VALUES (".((int) $conf->entity).", '".$this->db->idate($now)."', ".((int) $this->id).", ".((float) $remise).","; $sql .= " '".$this->db->escape($note)."',"; $sql .= " ".((int) $user->id); $sql .= ")";
'.$langs->trans("Description").''; - print dol_htmlentitiesbr($projectstatic->description); - print '
'.$langs->trans("Categories").''; @@ -559,6 +554,16 @@ if ($projectstatic->id > 0 || $confOrBooth > 0) { print "
'.$langs->trans("Description").'
'; + print '
'; + print dolPrintHTML($projectstatic->description); + print '
'; + print '
'; $typeofdata = 'checkbox:'.($projectstatic->accept_conference_suggestions ? ' checked="checked"' : ''); $htmltext = $langs->trans("AllowUnknownPeopleSuggestConfHelp"); diff --git a/htdocs/projet/element.php b/htdocs/projet/element.php index 80af93b7cd0..f416f4fc55d 100644 --- a/htdocs/projet/element.php +++ b/htdocs/projet/element.php @@ -311,7 +311,7 @@ if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES') || !getDolGlobalString('PROJ print '
'.$langs->trans("OpportunityStatus").''; $code = dol_getIdFromCode($db, $object->opp_status, 'c_lead_status', 'rowid', 'code'); From 5b1c5397bac1056c6bc58948806495861b9371f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20de=20Grandpr=C3=A9?= Date: Wed, 29 Jan 2025 09:34:16 -0500 Subject: [PATCH 162/383] Adding global variables to have more flexibility on external calendars location. --- htdocs/comm/action/class/ical.class.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/htdocs/comm/action/class/ical.class.php b/htdocs/comm/action/class/ical.class.php index da003149657..3024513dfed 100644 --- a/htdocs/comm/action/class/ical.class.php +++ b/htdocs/comm/action/class/ical.class.php @@ -96,7 +96,16 @@ class ICal $file_text = ''; //$tmpresult = getURLContent($file, 'GET', '', 1, [], ['http', 'https'], 2, 0); // To test with any URL - $tmpresult = getURLContent($file, 'GET'); + $localip = 0; + $sslverify = -1; + if(getDolGlobalString('AGENDA_EXT_CALENDAR_IP_MODE')) { + $localip = intval(getDolGlobalString('AGENDA_EXT_CALENDAR_IP_MODE')); + } + if(getDolGlobalString('AGENDA_EXT_CALENDAR_SSLVERIFY_MODE')) { + $sslverify = intval(getDolGlobalString('AGENDA_EXT_CALENDAR_SSLVERIFY_MODE')); + } + // See documentation of getURLContent function for $localip and $sslverify possible values + $tmpresult = getURLContent($file, 'GET', '', 1, [], ['http', 'https'], $localip, $sslverify); if ($tmpresult['http_code'] != 200) { $file_text = null; $this->error = 'Error: '.$tmpresult['http_code'].' '.$tmpresult['content']; From 841356613e24a05566e50ecc8d74f16179d75de9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20de=20Grandpr=C3=A9?= Date: Wed, 29 Jan 2025 09:40:57 -0500 Subject: [PATCH 163/383] code format --- htdocs/comm/action/class/ical.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/comm/action/class/ical.class.php b/htdocs/comm/action/class/ical.class.php index 3024513dfed..405c84d1046 100644 --- a/htdocs/comm/action/class/ical.class.php +++ b/htdocs/comm/action/class/ical.class.php @@ -98,10 +98,10 @@ class ICal //$tmpresult = getURLContent($file, 'GET', '', 1, [], ['http', 'https'], 2, 0); // To test with any URL $localip = 0; $sslverify = -1; - if(getDolGlobalString('AGENDA_EXT_CALENDAR_IP_MODE')) { + if (getDolGlobalString('AGENDA_EXT_CALENDAR_IP_MODE')) { $localip = intval(getDolGlobalString('AGENDA_EXT_CALENDAR_IP_MODE')); } - if(getDolGlobalString('AGENDA_EXT_CALENDAR_SSLVERIFY_MODE')) { + if (getDolGlobalString('AGENDA_EXT_CALENDAR_SSLVERIFY_MODE')) { $sslverify = intval(getDolGlobalString('AGENDA_EXT_CALENDAR_SSLVERIFY_MODE')); } // See documentation of getURLContent function for $localip and $sslverify possible values From 71d13cc77af248fc01148ec32a96fd6bf4fcc632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20de=20Grandpr=C3=A9?= Date: Wed, 29 Jan 2025 10:13:01 -0500 Subject: [PATCH 164/383] added cpr --- htdocs/comm/action/class/ical.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/comm/action/class/ical.class.php b/htdocs/comm/action/class/ical.class.php index 405c84d1046..648f96aba4d 100644 --- a/htdocs/comm/action/class/ical.class.php +++ b/htdocs/comm/action/class/ical.class.php @@ -4,7 +4,8 @@ * Copyright (C) 2013-2014 Laurent Destailleur * Copyright (C) 2012 Regis Houssin * Copyright (C) 2019-2024 Frédéric France - * Copyright (C) 2024 MDW + * Copyright (C) 2024 MDW + * Copyright (C) 2024 Vincent de Grandpré * * 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 From 8f3b814aaf2febfa4a4b4b7b65d398d3c42d946a Mon Sep 17 00:00:00 2001 From: UT from dolibit <45215329+dolibit-ut@users.noreply.github.com> Date: Wed, 29 Jan 2025 17:31:07 +0100 Subject: [PATCH 165/383] Update llx_c_forme_juridique.sql added new Austrian business entity type FlexKapG #32803 --- htdocs/install/mysql/data/llx_c_forme_juridique.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/install/mysql/data/llx_c_forme_juridique.sql b/htdocs/install/mysql/data/llx_c_forme_juridique.sql index fd094e387ef..38140954e39 100644 --- a/htdocs/install/mysql/data/llx_c_forme_juridique.sql +++ b/htdocs/install/mysql/data/llx_c_forme_juridique.sql @@ -10,7 +10,7 @@ -- Copyright (C) 2012 Tommaso Basilici -- Copyright (C) 2012 Ricardo Schluter -- Copyright (C) 2013 Cedric GROSS --- Copyright (C) 2020-2021 Udo Tamm +-- Copyright (C) 2020-2025 Udo Tamm -- Copyright (C) 2022 Miro Sertić -- -- This program is free software; you can redistribute it and/or modify @@ -83,6 +83,7 @@ INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (41, ' INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (41, '4112', 'GesbR - Gesellschaft nach bürgerlichem Recht', 1); INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (41, '4113', 'GesnbR - Gesellschaft nach bürgerlichem Recht', 1); INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (41, '4114', 'e.U. - eingetragener Einzelunternehmer', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (41, '4115', 'FlexKapG - Flexible Kapitalgesellschaft', 1); -- Belgium From 40567ce7f680e422b90f138859dc9a7f5ad0bbca Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Wed, 29 Jan 2025 18:13:03 +0100 Subject: [PATCH 166/383] FIX E_STRICT is deprecated since PHP 8.4 --- htdocs/filefunc.inc.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/htdocs/filefunc.inc.php b/htdocs/filefunc.inc.php index aa03bc81bd9..abba0355be6 100644 --- a/htdocs/filefunc.inc.php +++ b/htdocs/filefunc.inc.php @@ -205,10 +205,19 @@ if (!$result && !empty($_SERVER["GATEWAY_INTERFACE"])) { // If install not do } // Force PHP error_reporting setup (Dolibarr may report warning without this) -if (!empty($dolibarr_strict_mode)) { - error_reporting(E_ALL | E_STRICT); +if (version_compare(phpversion(), '8.4', '<')) { + if (!empty($dolibarr_strict_mode)) { + error_reporting(E_ALL | E_STRICT); + } else { + error_reporting(E_ALL & ~(E_STRICT | E_NOTICE | E_DEPRECATED)); + } } else { - error_reporting(E_ALL & ~(E_STRICT | E_NOTICE | E_DEPRECATED)); + // E_STRICT is deprecated since PHP 8.4 + if (!empty($dolibarr_strict_mode)) { + error_reporting(E_ALL); + } else { + error_reporting(E_ALL & ~(E_NOTICE | E_DEPRECATED)); + } } // Disable php display errors From 9cb16ea555ee945da759107f8b16c229013204d5 Mon Sep 17 00:00:00 2001 From: sonikf <93765174+sonikf@users.noreply.github.com> Date: Wed, 29 Jan 2025 19:34:18 +0200 Subject: [PATCH 167/383] fix trans --- htdocs/langs/en_US/datapolicy.lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/langs/en_US/datapolicy.lang b/htdocs/langs/en_US/datapolicy.lang index 38a4f48f39f..3f8e33544fa 100644 --- a/htdocs/langs/en_US/datapolicy.lang +++ b/htdocs/langs/en_US/datapolicy.lang @@ -19,7 +19,7 @@ Module4100Desc = Module to manage Data Privacy (Conformity with the GDPR) datapolicySetup = Module Data Privacy Policy Setup DataDeletion=Deletion of data DataAnonymization=Anonymization of data -datapolicySetupPage = Depending on the laws of your countries (Example Article 5 of the GDPR), personal data must be kept for a period not exceeding the duration the data is needed for the purpose for which it was collected, except for archival purposes.
This module will make an anonymization automatically after a certain duration without events (the duration which you will have indicated below) and if the object has no existing business object children. +datapolicySetupPage = Depending on the laws of your country (Example Article 5 of the GDPR), personal data must be kept for a period not exceeding the duration the data is needed for the purpose for which it was collected, except for archival purposes.
This module will make an anonymization automatically after a certain duration without events (the duration which you will have indicated below) and if the object has no existing business object children. NB_MONTHS = %s months ONE_YEAR = 1 year NB_YEARS = %s years From a4c397a68b723cb4390eef76f2fcb83cd4d4a33e Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Wed, 29 Jan 2025 18:35:54 +0100 Subject: [PATCH 168/383] fix: php 8 warning --- htdocs/expensereport/tpl/expensereport_linktofile.tpl.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/expensereport/tpl/expensereport_linktofile.tpl.php b/htdocs/expensereport/tpl/expensereport_linktofile.tpl.php index 2e02e7b8808..b789360e3f2 100644 --- a/htdocs/expensereport/tpl/expensereport_linktofile.tpl.php +++ b/htdocs/expensereport/tpl/expensereport_linktofile.tpl.php @@ -95,7 +95,7 @@ if (!getDolGlobalString('EXPENSEREPORT_DISABLE_ATTACHMENT_ON_LINES')) { } print '
'; - print $thumbshown ? $thumbshown : img_mime($minifile); + print $thumbshown ? $thumbshown : ($minifile ? img_mime($minifile): ''); print '
'; if (empty($urlforhref) || empty($thumbshown)) { From 4d8f28f22bd42202cbd981b0a23d49e3f5bf7dcb Mon Sep 17 00:00:00 2001 From: sonikf <93765174+sonikf@users.noreply.github.com> Date: Wed, 29 Jan 2025 19:36:31 +0200 Subject: [PATCH 169/383] fix typo --- htdocs/langs/en_US/website.lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/langs/en_US/website.lang b/htdocs/langs/en_US/website.lang index 212147881ff..892960dc610 100644 --- a/htdocs/langs/en_US/website.lang +++ b/htdocs/langs/en_US/website.lang @@ -92,7 +92,7 @@ DisableSiteFirst=Put website offline first MyContainerTitle=My web site title AnotherContainer=This is how to include content of another page/container (you may have an error here if you enable dynamic code because the embedded subcontainer may not exists) SorryWebsiteIsCurrentlyOffLine=Sorry, this website is currently off line. Please comme back later... -WEBSITE_USE_WEBSITE_ACCOUNTS=Enable the table of web site account fo thirdparties +WEBSITE_USE_WEBSITE_ACCOUNTS=Enable the table of web site account for thirdparties WEBSITE_USE_WEBSITE_ACCOUNTSTooltip=Enable the table to store the web site accounts (login/pass) for each third party YouMustDefineTheHomePage=You must first define the default Home page OnlyEditionOfSourceForGrabbedContentFuture=Warning: Creating a web page by importing an external web page is reserved for experienced users. Depending on the complexity of source page, the result of importation may differ from the original. Also if the source page uses common CSS styles or conflicting JavaScript, it may break the look or features of the Website editor when working on this page. This method is a quicker way to create a page but it is recommended to create your new page from scratch or from a suggested page template.
Note also that the inline editor might not work correctly when used on a grabbed external page. From d66ff94c72f89e5521a63c46ea1ccb9c0315214e Mon Sep 17 00:00:00 2001 From: sonikf <93765174+sonikf@users.noreply.github.com> Date: Wed, 29 Jan 2025 19:38:49 +0200 Subject: [PATCH 170/383] fix trans --- htdocs/langs/en_US/members.lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/langs/en_US/members.lang b/htdocs/langs/en_US/members.lang index 4d1c90f9e1b..f730d33d5f4 100644 --- a/htdocs/langs/en_US/members.lang +++ b/htdocs/langs/en_US/members.lang @@ -191,7 +191,7 @@ MembersStatisticsByRegion=Members statistics by region NbOfMembers=Total number of members NbOfActiveMembers=Total number of current active members NoValidatedMemberYet=No validated members found -MembersByCountryDesc=This screen shows you the statistics of members by countries. +MembersByCountryDesc=This screen shows you the statistics of members by country. MembersByCountryDesc2=Graphs and charts depend on the availability of the Google online graph service as well as on the availability of a working internet connection. MembersByStateDesc=This screen show you statistics of members by state/provinces/canton. MembersByTownDesc=This screen show you statistics of members by town. From 9984652a4502bc47d9472179279577502f6f2230 Mon Sep 17 00:00:00 2001 From: sonikf <93765174+sonikf@users.noreply.github.com> Date: Wed, 29 Jan 2025 19:43:00 +0200 Subject: [PATCH 171/383] fix trans --- htdocs/langs/en_US/admin.lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index a5e14c17cb8..4166884bdf2 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -2606,5 +2606,5 @@ AttributeCodeHelp=A code of your choice (without special chars and spaces) to id ThereIsMoreThanXAnswers=There is more than %s answers with your filter. Please add more filters... PdfAddTermOfSaleHelp=You can upload the terms and conditions of sale file at the bottom of this setup page WarningOnlineSignature=Please note that this function allows a person (customer, supplier...) to insert, online, the image of his signature in the PDF document. As for a handwritten signature, such a signature can be made by anyone and might not have the same legal value as a legal electronic signature system going through an authorized trusted third party. If you need this level of security, you can contact an integrator for more information or check for addons on www.dolistore.org. -UploadExtensionRestriction=File exension list forbidden to upload +UploadExtensionRestriction=List of forbidden file extensions to upload UploadExtensionRestrictionExemple=htm, html, shtml, js, php From 841cd5f570ad44c9fabdc4b30ce73c3bf8e26445 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 29 Jan 2025 19:08:08 +0100 Subject: [PATCH 172/383] enhance member types list --- htdocs/adherents/type.php | 45 +++++++++++++++++++++++---------- htdocs/langs/en_US/members.lang | 4 ++- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/htdocs/adherents/type.php b/htdocs/adherents/type.php index 91f105c48b8..25bdae150a5 100644 --- a/htdocs/adherents/type.php +++ b/htdocs/adherents/type.php @@ -9,7 +9,7 @@ * Copyright (C) 2020 Josep Lluís Amador * Copyright (C) 2021 Waël Almoman * Copyright (C) 2024 MDW - * Copyright (C) 2024 Frédéric France + * Copyright (C) 2024-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 @@ -136,6 +136,9 @@ $result = restrictedArea($user, 'adherent', $rowid, 'adherent_type'); */ $error = 0; +// Selection of new fields +include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers $search_ref = ""; $search_lastname = ""; @@ -329,8 +332,14 @@ if (!$rowid && $action != 'create' && $action != 'edit') { print ''; print ''; print ''; + print ''; + print ''; print ''; + $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; + $htmlofselectarray = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')); // This also change content of $arrayfields with user setup + $selectedfields = ($mode != 'kanban' ? $htmlofselectarray : ''); + // $selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); print_barre_liste($langs->trans("MembersTypes"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'members', 0, $newcardbutton, '', $limit, 0, 0, 1); @@ -341,11 +350,18 @@ if (!$rowid && $action != 'create' && $action != 'edit') { print '
 '.$langs->trans("Ref").''.$langs->trans($arrayfields['t.libelle']['label']).''.$langs->trans("MembersNature").''.$langs->trans("Ref").''.$langs->trans("Label").''.$langs->trans("MembersNature").''.$langs->trans("MembershipDuration").''.$langs->trans("SubscriptionRequired").''.$langs->trans("Amount").''.$langs->trans("VoteAllowed").''.$langs->trans("Status").' 
rowid.'">'.img_edit().''; - print $membertype->getNomUrl(1); - //'.img_object($langs->trans("ShowType"),'group').' '.$objp->rowid.' - print ''.dol_escape_htmltag($objp->label).''; + print $membertype->getNomUrl(1); + //'.img_object($langs->trans("ShowType"),'group').' '.$objp->rowid.' + print ''.dol_escape_htmltag($objp->label).''; if ($objp->morphy == 'phy') { diff --git a/htdocs/langs/en_US/members.lang b/htdocs/langs/en_US/members.lang index 4d1c90f9e1b..a4cecf6be82 100644 --- a/htdocs/langs/en_US/members.lang +++ b/htdocs/langs/en_US/members.lang @@ -191,7 +191,7 @@ MembersStatisticsByRegion=Members statistics by region NbOfMembers=Total number of members NbOfActiveMembers=Total number of current active members NoValidatedMemberYet=No validated members found -MembersByCountryDesc=This screen shows you the statistics of members by countries. +MembersByCountryDesc=This screen shows you the statistics of members by countries. MembersByCountryDesc2=Graphs and charts depend on the availability of the Google online graph service as well as on the availability of a working internet connection. MembersByStateDesc=This screen show you statistics of members by state/provinces/canton. MembersByTownDesc=This screen show you statistics of members by town. @@ -251,3 +251,5 @@ XSubsriptionErrors=%s subscription(s) where in error CreateSubscription=Create subscription WarningNoComplementaryActionDone=No Complementary action on recording will be executed with this massaction NewMembership=New membership +Caneditamount=Can edit amount +Morphy=Moral or physical From 0338b5c65851f490b3458113a642b57a43910ddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 29 Jan 2025 19:11:03 +0100 Subject: [PATCH 173/383] enhance member types list --- htdocs/adherents/type.php | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/htdocs/adherents/type.php b/htdocs/adherents/type.php index 25bdae150a5..c1584085f12 100644 --- a/htdocs/adherents/type.php +++ b/htdocs/adherents/type.php @@ -355,12 +355,15 @@ if (!$rowid && $action != 'create' && $action != 'edit') { } if (!empty($arrayfields['t.rowid']['checked'])) { print ''.$langs->trans("Ref").''.$langs->trans($arrayfields['t.libelle']['label']).''.$langs->trans("MembersNature").''.$langs->trans("MembershipDuration").''.$langs->trans("SubscriptionRequired").''.dol_escape_htmltag($objp->label).''; - if ($objp->morphy == 'phy') { - print $langs->trans("Physical"); - } elseif ($objp->morphy == 'mor') { - print $langs->trans("Moral"); - } else { - print $langs->trans("MorAndPhy"); + if (!empty($arrayfields['t.morphy']['checked'])) { + print ''; + if ($objp->morphy == 'phy') { + print $langs->trans("Physical"); + } elseif ($objp->morphy == 'mor') { + print $langs->trans("Moral"); + } else { + print $langs->trans("MorAndPhy"); + } + print ''; if ($objp->duration) { From de131d7d8ef262862c7dd18af426a82f4fbc3df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 29 Jan 2025 19:13:23 +0100 Subject: [PATCH 174/383] enhance member types list --- htdocs/adherents/type.php | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/htdocs/adherents/type.php b/htdocs/adherents/type.php index c1584085f12..5e0a853eaa8 100644 --- a/htdocs/adherents/type.php +++ b/htdocs/adherents/type.php @@ -365,7 +365,10 @@ if (!$rowid && $action != 'create' && $action != 'edit') { print ''.$langs->trans("MembersNature").''.$langs->trans("MembershipDuration").''.$langs->trans("MembershipDuration").''.$langs->trans("SubscriptionRequired").''.$langs->trans("Amount").''.$langs->trans("CanEditAmountShort").''; - if ($objp->duration) { - $duration_value = intval($objp->duration); - if ($duration_value > 1) { - $dur = array("i" => $langs->trans("Minutes"), "h" => $langs->trans("Hours"), "d" => $langs->trans("Days"), "w" => $langs->trans("Weeks"), "m" => $langs->trans("Months"), "y" => $langs->trans("Years")); - } else { - $dur = array("i" => $langs->trans("Minute"), "h" => $langs->trans("Hour"), "d" => $langs->trans("Day"), "w" => $langs->trans("Week"), "m" => $langs->trans("Month"), "y" => $langs->trans("Year")); + if (!empty($arrayfields['t.duration']['checked'])) { + print ''; + if ($objp->duration) { + $duration_value = intval($objp->duration); + if ($duration_value > 1) { + $dur = array("i" => $langs->trans("Minutes"), "h" => $langs->trans("Hours"), "d" => $langs->trans("Days"), "w" => $langs->trans("Weeks"), "m" => $langs->trans("Months"), "y" => $langs->trans("Years")); + } else { + $dur = array("i" => $langs->trans("Minute"), "h" => $langs->trans("Hour"), "d" => $langs->trans("Day"), "w" => $langs->trans("Week"), "m" => $langs->trans("Month"), "y" => $langs->trans("Year")); + } + $unit = preg_replace("/[^a-zA-Z]+/", "", $objp->duration); + print max(1, $duration_value).' '.$dur[$unit]; } - $unit = preg_replace("/[^a-zA-Z]+/", "", $objp->duration); - print max(1, $duration_value).' '.$dur[$unit]; + print ''.yn($objp->subscription).''.$langs->trans("MembershipDuration").''.$langs->trans("SubscriptionRequired").''.$langs->trans("Amount").''.$langs->trans("CanEditAmountShort").''.$langs->trans("VoteAllowed").''.$langs->trans("Status").''.$langs->trans("SubscriptionRequired").''.$langs->trans("Amount").''.$langs->trans("CanEditAmountShort").''.$langs->trans("VoteAllowed").''.$langs->trans("Status").''.yn($objp->subscription).''.(is_null($objp->amount) || $objp->amount === '' ? '' : price($objp->amount)).''.yn($objp->caneditamount).''.yn($objp->vote).''.$membertype->getLibStatut(5).''.yn($objp->subscription).''.(is_null($objp->amount) || $objp->amount === '' ? '' : price($objp->amount)).''.yn($objp->caneditamount).''.yn($objp->vote).''.$membertype->getLibStatut(5).'rowid.'">'.img_edit().'
'.$form->editfieldkey('VATIsUsed', 'assujtva_value', '', $object, 0).''; - print ''; // Assujeti par default en creation + print ''; // Assujeti par default en creation print '
'; - $texttoshow = null; + $texttoshow = ''; if ($cron['jobtype'] == 'method') { $text = $langs->trans("CronClass"); $texttoshow = $langs->trans('CronModule').': '.$module.'
'; @@ -6658,7 +6646,7 @@ if ($module == 'initmodule') { print '
'; print ' '.$langs->trans("PathToModulePackage").' : '; - if (!dol_is_file($outputfilezip)) { + if ($outputfilezip === null || !dol_is_file($outputfilezip)) { print ''.$langs->trans("FileNotYetGenerated").''; } else { $relativepath = $modulelowercase.'/bin/'.$FILENAMEZIP; diff --git a/htdocs/modulebuilder/template/admin/setup.php b/htdocs/modulebuilder/template/admin/setup.php index ad7fc9de5de..8825d6419ea 100644 --- a/htdocs/modulebuilder/template/admin/setup.php +++ b/htdocs/modulebuilder/template/admin/setup.php @@ -453,7 +453,7 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) { } print '
'; - print $form->textwithpicto('', $htmltooltip, 1, 0); + print $form->textwithpicto('', $htmltooltip, 1, 'info'); print '
'; - print $form->textwithpicto('', $htmltooltip, 1, 0); + print $form->textwithpicto('', $htmltooltip, 1, 'info'); print '
'.$langs->trans("Mask").':'.$form->textwithpicto('', $tooltip, 1, 1).''.$form->textwithpicto('', $tooltip, 1, 'help').'