diff --git a/COPYRIGHT b/COPYRIGHT index a5e1f4a4005..a2101a1db0a 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -50,8 +50,8 @@ TCPDI 1.0.0 LGPL-3+ / Apache 2.0 Yes JS libraries: Ace 1.4.14 BSD Yes JS library to get code syntaxique coloration in a textarea. ChartJS 3.7.1 MIT License Yes JS library for graph -jQuery 3.5.1 MIT License Yes JS library -jQuery UI 1.12.1 GPL and MIT License Yes JS library plugin UI +jQuery 3.6.0 MIT License Yes JS library +jQuery UI 1.13.1 GPL and MIT License Yes JS library plugin UI jQuery select2 4.0.13 GPL and Apache License Yes JS library plugin for sexier multiselect. Warning: 4.0.6+ create troubles without patching css jQuery blockUI 2.70.0 GPL and MIT License Yes JS library plugin blockUI (to use ajax popups) jQuery Colorpicker 1.1 MIT License Yes JS library for color picker for a defined list of colors diff --git a/ChangeLog b/ChangeLog index 880406bb189..31bfa1c1cff 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,7 +9,8 @@ English Dolibarr ChangeLog For users: --------------- -NEW: ... +NEW: PHP 8.0 compatibility + Modules diff --git a/dev/resources/iso-normes/currencies_iso-4217.txt b/dev/resources/iso-normes/currencies_iso-4217.txt index bc392b72e9c..e24faa4283e 100644 --- a/dev/resources/iso-normes/currencies_iso-4217.txt +++ b/dev/resources/iso-normes/currencies_iso-4217.txt @@ -1,8 +1,12 @@ # File of all ISO-4217 currencies codes -# http://en.wikipedia.org/wiki/ISO_4217 -# http://fx.sauder.ubc.ca/currency_table.html for symbols for 2 letter code # -# Code,Name,Nb decimals +# https://en.wikipedia.org/wiki/ISO_4217 +# https://en.wikipedia.org/wiki/Currency_symbol for symbols for 2 letter code +# + + +# Code, Currency Name, Nb decimals + AED,UAE Dirham,2 AFN,Afghanistan Afghani,2 ALL,Albanian Lek,2 diff --git a/htdocs/adherents/list.php b/htdocs/adherents/list.php index 996f2d16c8d..e58def3f481 100644 --- a/htdocs/adherents/list.php +++ b/htdocs/adherents/list.php @@ -505,7 +505,7 @@ if (GETPOSTISSET("search_status")) { if ($search_type > 0) { $membertype = new AdherentType($db); - $result = $membertype->fetch(GETPOST("type", 'int')); + $result = $membertype->fetch($search_type); $titre .= " (".$membertype->label.")"; } @@ -767,7 +767,7 @@ if (!empty($arrayfields['d.email']['checked'])) { } // End of subscription date if (!empty($arrayfields['d.datefin']['checked'])) { - print ''; + print ''; $selectarray = array('-1'=>'', 'withoutsubscription'=>$langs->trans("WithoutSubscription"), 'uptodate'=>$langs->trans("UpToDate"), 'outofdate'=>$langs->trans("OutOfDate")); print $form->selectarray('search_filter', $selectarray, $search_filter); print ''; @@ -858,7 +858,7 @@ if (!empty($arrayfields['state.nom']['checked'])) { print_liste_field_titre($arrayfields['state.nom']['label'], $_SERVER["PHP_SELF"], "state.nom", "", $param, '', $sortfield, $sortorder); } if (!empty($arrayfields['country.code_iso']['checked'])) { - print_liste_field_titre($arrayfields['country.code_iso']['label'], $_SERVER["PHP_SELF"], "country.code_iso", "", $param, 'align="center"', $sortfield, $sortorder); + print_liste_field_titre($arrayfields['country.code_iso']['label'], $_SERVER["PHP_SELF"], "country.code_iso", "", $param, '', $sortfield, $sortorder, 'center '); } if (!empty($arrayfields['d.phone']['checked'])) { print_liste_field_titre($arrayfields['d.phone']['label'], $_SERVER["PHP_SELF"], 'd.phone', '', $param, '', $sortfield, $sortorder); @@ -873,7 +873,7 @@ if (!empty($arrayfields['d.email']['checked'])) { print_liste_field_titre($arrayfields['d.email']['label'], $_SERVER["PHP_SELF"], 'd.email', '', $param, '', $sortfield, $sortorder); } if (!empty($arrayfields['d.datefin']['checked'])) { - print_liste_field_titre($arrayfields['d.datefin']['label'], $_SERVER["PHP_SELF"], 'd.datefin', '', $param, 'align="center"', $sortfield, $sortorder); + print_liste_field_titre($arrayfields['d.datefin']['label'], $_SERVER["PHP_SELF"], 'd.datefin', '', $param, '', $sortfield, $sortorder, 'center '); } // Extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; @@ -1110,16 +1110,14 @@ while ($i < min($num, $limit)) { // End of subscription date $datefin = $db->jdate($obj->datefin); if (!empty($arrayfields['d.datefin']['checked'])) { + print ''; if ($datefin) { - print ''; print dol_print_date($datefin, 'day'); if ($memberstatic->hasDelay()) { $textlate = ' ('.$langs->trans("DateReference").' > '.$langs->trans("DateToday").' '.(ceil($conf->adherent->subscription->warning_delay / 60 / 60 / 24) >= 0 ? '+' : '').ceil($conf->adherent->subscription->warning_delay / 60 / 60 / 24).' '.$langs->trans("days").')'; print " ".img_warning($langs->trans("SubscriptionLate").$textlate); } - print ''; } else { - print ''; if (!empty($obj->subscription)) { print $langs->trans("SubscriptionNotReceived"); if ($obj->statut > 0) { @@ -1128,8 +1126,8 @@ while ($i < min($num, $limit)) { } else { print ' '; } - print ''; } + print ''; } // Extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; diff --git a/htdocs/admin/expensereport_rules.php b/htdocs/admin/expensereport_rules.php index 6799ab339bd..1146232dca3 100644 --- a/htdocs/admin/expensereport_rules.php +++ b/htdocs/admin/expensereport_rules.php @@ -185,31 +185,31 @@ if ($action != 'edit') { echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; echo ''; echo ''; echo ''; echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; echo ''; echo '
' . $langs->trans('ExpenseReportApplyTo') . '' . $langs->trans('Type') . '' . $langs->trans('ExpenseReportLimitOn') . '' . $langs->trans('ExpenseReportDateStart') . '' . $langs->trans('ExpenseReportDateEnd') . '' . $langs->trans('ExpenseReportLimitAmount') . '' . $langs->trans('ExpenseReportRestrictive') . '
' . $langs->trans('ExpenseReportApplyTo') . '' . $langs->trans('Type') . '' . $langs->trans('ExpenseReportLimitOn') . '' . $langs->trans('ExpenseReportDateStart') . '' . $langs->trans('ExpenseReportDateEnd') . '' . $langs->trans('ExpenseReportLimitAmount') . '' . $langs->trans('ExpenseReportRestrictive') . ' 
'; - echo '
' . $form->selectarray('apply_to', $tab_apply, '', 0) . '
'; - echo '
' . $form->select_dolusers('', 'fk_user') . '
'; - echo '
' . $form->select_dolgroups('', 'fk_usergroup') . '
'; + echo '
' . $form->selectarray('apply_to', $tab_apply, '', 0) . '
'; + echo '
' . $form->select_dolusers('', 'fk_user') . '
'; + echo '
' . $form->select_dolgroups('', 'fk_usergroup') . '
'; echo '
' . $form->selectExpense('', 'fk_c_type_fees', 0, 1, 1) . '' . $form->selectarray('code_expense_rules_type', $tab_rules_type, '', 0) . '' . $form->selectDate(strtotime(date('Y-m-01', dol_now())), 'start', '', '', 0, '', 1, 0) . '' . $form->selectDate(strtotime(date('Y-m-t', dol_now())), 'end', '', '', 0, '', 1, 0) . ' ' . $conf->currency . '' . $form->selectyesno('restrictive', 0, 1) . '' . $form->selectExpense('', 'fk_c_type_fees', 0, 1, 1) . '' . $form->selectarray('code_expense_rules_type', $tab_rules_type, '', 0) . '' . $form->selectDate(strtotime(date('Y-m-01', dol_now())), 'start', '', '', 0, '', 1, 0) . ' ' . $conf->currency . '' . $form->selectyesno('restrictive', 0, 1) . '
'; @@ -227,21 +227,21 @@ if ($action == 'edit') { echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; echo ''; echo ''; foreach ($rules as $rule) { - echo ''; + echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; + print ''; } else { print ''; } } diff --git a/htdocs/contrat/class/contrat.class.php b/htdocs/contrat/class/contrat.class.php index 68ac203d955..d85ad51946a 100644 --- a/htdocs/contrat/class/contrat.class.php +++ b/htdocs/contrat/class/contrat.class.php @@ -2474,6 +2474,23 @@ class Contrat extends CommonObject return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'contratdet' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } + /** * Load an object from its id and create a new one in database * diff --git a/htdocs/contrat/list.php b/htdocs/contrat/list.php index 55bd7071ee8..6c23cfcf720 100644 --- a/htdocs/contrat/list.php +++ b/htdocs/contrat/list.php @@ -338,18 +338,24 @@ if (!empty($extrafields->attributes[$object->table_element]['label'])) { } } // Add where from hooks -$parameters = array(); -$reshook = $hookmanager->executeHooks('printFieldListGroupBy', $parameters); // Note that $action and $object may have been modified by hook +$parameters = array('search_dfyear' => $search_dfyear, 'search_op2df'=>$search_op2df); +$reshook = $hookmanager->executeHooks('printFieldListGroupBy', $parameters, $object); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; -if ($search_dfyear > 0 && $search_op2df) { - if ($search_op2df == '<=') { - $sql .= " HAVING MIN(".$db->ifsql("cd.statut=4", "cd.date_fin_validite", "null").") <= '".$db->idate(dol_get_last_day($search_dfyear, $search_dfmonth, false))."'"; - } elseif ($search_op2df == '>=') { - $sql .= " HAVING MIN(".$db->ifsql("cd.statut=4", "cd.date_fin_validite", "null").") >= '".$db->idate(dol_get_first_day($search_dfyear, $search_dfmonth, false))."'"; - } else { - $sql .= " HAVING MIN(".$db->ifsql("cd.statut=4", "cd.date_fin_validite", "null").") <= '".$db->idate(dol_get_last_day($search_dfyear, $search_dfmonth, false))."' AND MIN(".$db->ifsql("cd.statut=4", "cd.date_fin_validite", "null").") >= '".$db->idate(dol_get_first_day($search_dfyear, $search_dfmonth, false))."'"; +// Add HAVING from hooks +$parameters = array('search_dfyear' => $search_dfyear, 'search_op2df'=>$search_op2df); +$reshook = $hookmanager->executeHooks('printFieldListHaving', $parameters, $object); // Note that $action and $object may have been modified by hook +if (empty($reshook)) { + if ($search_dfyear > 0 && $search_op2df) { + if ($search_op2df == '<=') { + $sql .= " HAVING MIN(".$db->ifsql("cd.statut=4", "cd.date_fin_validite", "null").") <= '".$db->idate(dol_get_last_day($search_dfyear, $search_dfmonth, false))."'"; + } elseif ($search_op2df == '>=') { + $sql .= " HAVING MIN(".$db->ifsql("cd.statut=4", "cd.date_fin_validite", "null").") >= '".$db->idate(dol_get_first_day($search_dfyear, $search_dfmonth, false))."'"; + } else { + $sql .= " HAVING MIN(".$db->ifsql("cd.statut=4", "cd.date_fin_validite", "null").") <= '".$db->idate(dol_get_last_day($search_dfyear, $search_dfmonth, false))."' AND MIN(".$db->ifsql("cd.statut=4", "cd.date_fin_validite", "null").") >= '".$db->idate(dol_get_first_day($search_dfyear, $search_dfmonth, false))."'"; + } } } +$sql .= $hookmanager->resPrint; $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { diff --git a/htdocs/contrat/services_list.php b/htdocs/contrat/services_list.php index 39dfe336a31..adf7a4b6ed7 100644 --- a/htdocs/contrat/services_list.php +++ b/htdocs/contrat/services_list.php @@ -326,25 +326,25 @@ if (!empty($filter_opouvertureprevue) && $filter_opouvertureprevue != -1 && $fil $sql .= " AND cd.date_ouverture_prevue ".$filter_opouvertureprevue." '".$db->idate($filter_dateouvertureprevue_start)."'"; } if (!empty($filter_opouvertureprevue) && $filter_opouvertureprevue == ' BETWEEN ') { - $sql .= " AND '".$db->idate($filter_dateouvertureprevue_end)."'"; + $sql .= " AND cd.date_ouverture_prevue ".$filter_opouvertureprevue." '".$db->idate($filter_dateouvertureprevue_start)."' AND '".$db->idate($filter_dateouvertureprevue_end)."'"; } if (!empty($filter_op1) && $filter_op1 != -1 && $filter_op1 != ' BETWEEN ' && $filter_date1_start != '') { $sql .= " AND cd.date_ouverture ".$filter_op1." '".$db->idate($filter_date1_start)."'"; } if (!empty($filter_op1) && $filter_op1 == ' BETWEEN ') { - $sql .= " AND '".$db->idate($filter_date1_end)."'"; + $sql .= " AND cd.date_ouverture ".$filter_op1." '".$db->idate($filter_date1_start)."' AND '".$db->idate($filter_date1_end)."'"; } if (!empty($filter_op2) && $filter_op2 != -1 && $filter_op2 != ' BETWEEN ' && $filter_date2_start != '') { $sql .= " AND cd.date_fin_validite ".$filter_op2." '".$db->idate($filter_date2_start)."'"; } if (!empty($filter_op2) && $filter_op2 == ' BETWEEN ') { - $sql .= " AND '".$db->idate($filter_date2_end)."'"; + $sql .= " AND cd.date_fin_validite ".$filter_op2." '".$db->idate($filter_date2_start)."' AND '".$db->idate($filter_date2_end)."'"; } if (!empty($filter_opcloture) && $filter_opcloture != ' BETWEEN ' && $filter_opcloture != -1 && $filter_datecloture_start != '') { $sql .= " AND cd.date_cloture ".$filter_opcloture." '".$db->idate($filter_datecloture_start)."'"; } if (!empty($filter_opcloture) && $filter_opcloture == ' BETWEEN ') { - $sql .= " AND '".$db->idate($filter_datecloture_end)."'"; + $sql .= " AND cd.date_cloture ".$filter_opcloture." '".$db->idate($filter_datecloture_start)."' AND '".$db->idate($filter_datecloture_end)."'"; } // Add where from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; diff --git a/htdocs/core/actions_sendmails.inc.php b/htdocs/core/actions_sendmails.inc.php index d31f8d60dfc..f0ef66eb78b 100644 --- a/htdocs/core/actions_sendmails.inc.php +++ b/htdocs/core/actions_sendmails.inc.php @@ -109,7 +109,7 @@ if (($action == 'send' || $action == 'relance') && !GETPOST('addfile') && !GETPO } $subject = ''; - $actionmsg = ''; + //$actionmsg = ''; $actionmsg2 = ''; $langs->load('mails'); @@ -317,7 +317,7 @@ if (($action == 'send' || $action == 'relance') && !GETPOST('addfile') && !GETPO if ($action == 'send' || $action == 'relance') { $actionmsg2 = $langs->transnoentities('MailSentBy').' '.CMailFile::getValidAddress($from, 4, 0, 1).' '.$langs->transnoentities('To').' '.CMailFile::getValidAddress($sendto, 4, 0, 1); - if ($message) { + /*if ($message) { $actionmsg = $langs->transnoentities('MailFrom').': '.dol_escape_htmltag($from); $actionmsg = dol_concatdesc($actionmsg, $langs->transnoentities('MailTo').': '.dol_escape_htmltag($sendto)); if ($sendtocc) { @@ -326,7 +326,7 @@ if (($action == 'send' || $action == 'relance') && !GETPOST('addfile') && !GETPO $actionmsg = dol_concatdesc($actionmsg, $langs->transnoentities('MailTopic').": ".$subject); $actionmsg = dol_concatdesc($actionmsg, $langs->transnoentities('TextUsedInTheMessageBody').":"); $actionmsg = dol_concatdesc($actionmsg, $message); - } + }*/ } // Create form object @@ -376,7 +376,7 @@ if (($action == 'send' || $action == 'relance') && !GETPOST('addfile') && !GETPO $object->socid = $sendtosocid; // To link to a company $object->sendtoid = $sendtoid; // To link to contact-addresses. This is an array. $object->actiontypecode = $actiontypecode; // Type of event ('AC_OTH', 'AC_OTH_AUTO', 'AC_XXX'...) - $object->actionmsg = $actionmsg; // Long text (@todo Replace this with $message, we already have details of email in dedicated properties) + $object->actionmsg = $message; // Long text $object->actionmsg2 = $actionmsg2; // Short text ($langs->transnoentities('MailSentBy')...); $object->trackid = $trackid; diff --git a/htdocs/core/class/commoninvoice.class.php b/htdocs/core/class/commoninvoice.class.php index eedc1b2fa10..e49f8a6a728 100644 --- a/htdocs/core/class/commoninvoice.class.php +++ b/htdocs/core/class/commoninvoice.class.php @@ -93,6 +93,14 @@ abstract class CommonInvoice extends CommonObject const STATUS_ABANDONED = 3; + public $sumpayed; + public $sumpayed_multicurrency; + public $sumdeposit; + public $sumdeposit_multicurrency; + public $sumcreditnote; + public $sumcreditnote_multicurrency; + + /** * Return remain amount to pay. Property ->id and ->total_ttc must be set. * This does not include open direct debit requests. @@ -118,8 +126,8 @@ abstract class CommonInvoice extends CommonObject * Return amount of payments already done. This must include ONLY the record into the payment table. * Payments dones using discounts, credit notes, etc are not included. * - * @param int $multicurrency Return multicurrency_amount instead of amount - * @return float Amount of payment already done, <0 if KO + * @param int $multicurrency Return multicurrency_amount instead of amount + * @return float Amount of payment already done, <0 and set ->error if KO */ public function getSommePaiement($multicurrency = 0) { @@ -138,10 +146,13 @@ abstract class CommonInvoice extends CommonObject $resql = $this->db->query($sql); if ($resql) { $obj = $this->db->fetch_object($resql); + $this->db->free($resql); if ($multicurrency) { + $this->sumpayed_multicurrency = $obj->multicurrency_amount; return $obj->multicurrency_amount; } else { + $this->sumpayed = $obj->amount; return $obj->amount; } } else { @@ -154,13 +165,13 @@ abstract class CommonInvoice extends CommonObject * Return amount (with tax) of all deposits invoices used by invoice. * Should always be empty, except if option FACTURE_DEPOSITS_ARE_JUST_PAYMENTS is on (not recommended). * - * @param int $multicurrency Return multicurrency_amount instead of amount - * @return float <0 if KO, Sum of deposits amount otherwise + * @param int $multicurrency Return multicurrency_amount instead of amount + * @return float <0 and set ->error if KO, Sum of deposits amount otherwise */ public function getSumDepositsUsed($multicurrency = 0) { if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') { - // TODO + // FACTURE_DEPOSITS_ARE_JUST_PAYMENTS was never supported for purchase invoice, so we can return 0 with no need of SQL for this case. return 0.0; } @@ -170,6 +181,12 @@ abstract class CommonInvoice extends CommonObject $result = $discountstatic->getSumDepositsUsed($this, $multicurrency); if ($result >= 0) { + if ($multicurrency) { + $this->sumdeposit_multicurrency = $result; + } else { + $this->sumdeposit = $result; + } + return $result; } else { $this->error = $discountstatic->error; @@ -180,8 +197,8 @@ abstract class CommonInvoice extends CommonObject /** * Return amount (with tax) of all credit notes invoices + excess received used by invoice * - * @param int $multicurrency Return multicurrency_amount instead of amount - * @return float <0 if KO, Sum of credit notes and deposits amount otherwise + * @param int $multicurrency Return multicurrency_amount instead of amount + * @return float <0 and set ->error if KO, Sum of credit notes and deposits amount otherwise */ public function getSumCreditNotesUsed($multicurrency = 0) { @@ -190,6 +207,12 @@ abstract class CommonInvoice extends CommonObject $discountstatic = new DiscountAbsolute($this->db); $result = $discountstatic->getSumCreditNotesUsed($this, $multicurrency); if ($result >= 0) { + if ($multicurrency) { + $this->sumcreditnote_multicurrency = $result; + } else { + $this->sumcreditnote = $result; + } + return $result; } else { $this->error = $discountstatic->error; diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 7e574ef605c..63d0eb475e5 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -15,6 +15,7 @@ * Copyright (C) 2018-2021 Frédéric France * Copyright (C) 2018 Josep Lluís Amador * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2021 Grégory Blémand * * 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 @@ -42,6 +43,7 @@ */ abstract class CommonObject { + const TRIGGER_PREFIX = ''; // to be overriden in child class implementations, i.e. 'BILL', 'TASK', 'PROPAL', etc. /** * @var DoliDb Database handler (result of a new DoliDB) */ @@ -123,6 +125,12 @@ abstract class CommonObject */ public $linkedObjects; + /** + * @var boolean is linkedObjects full loaded. Loaded by ->fetchObjectLinked + * important for pdf generation time reduction + */ + public $linkedObjectsFullLoaded = false; + /** * @var Object To store a cloned copy of object before to edit it and keep track of old properties */ @@ -3773,6 +3781,10 @@ abstract class CommonObject { global $conf, $hookmanager, $action; + // important for pdf generation time reduction + // this boolean is true if $this->linkedObjects has already been loaded with all objects linked without filter + if ($this->linkedObjectsFullLoaded) return 1; + $this->linkedObjectsIds = array(); $this->linkedObjects = array(); @@ -3834,6 +3846,9 @@ abstract class CommonObject } else { $sql .= "(fk_source = ".((int) $sourceid)." AND sourcetype = '".$this->db->escape($sourcetype)."')"; $sql .= " ".$clause." (fk_target = ".((int) $targetid)." AND targettype = '".$this->db->escape($targettype)."')"; + if ($sourceid == $this->id && $sourcetype == $this->element && $targetid == $this->id && $targettype == $this->element && $clause == 'OR') { + $this->linkedObjectsFullLoaded = true; + } } $sql .= " ORDER BY ".$orderby; @@ -4948,6 +4963,7 @@ abstract class CommonObject print ''; } print ''; + print ''; print ''; print ''; $i = 0; @@ -5078,6 +5094,7 @@ abstract class CommonObject } $this->tpl['price'] = price($line->subprice); + $this->tpl['total_ht'] = price($line->total_ht); $this->tpl['multicurrency_price'] = price($line->multicurrency_subprice); $this->tpl['qty'] = (($line->info_bits & 2) != 2) ? $line->qty : ' '; if (!empty($conf->global->PRODUCT_USE_UNITS)) { @@ -5602,7 +5619,10 @@ abstract class CommonObject { // phpcs:enable global $langs, $conf; - + if (!empty(self::TRIGGER_PREFIX) && strpos($triggerName, self::TRIGGER_PREFIX . '_') !== 0) { + dol_print_error('', 'The trigger "' . $triggerName . '" does not start with "' . self::TRIGGER_PREFIX . '_" as required.'); + exit; + } if (!is_object($langs)) { // If lang was not defined, we set it. It is required by run_triggers. include_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php'; $langs = new Translate('', $conf); @@ -8104,7 +8124,7 @@ abstract class CommonObject /** * Function used to replace a thirdparty id with another one. - * This function is meant to be called from replaceThirdparty with the appropiate tables + * This function is meant to be called from replaceThirdparty with the appropriate tables * Column name fk_soc MUST be used to identify thirdparties * * @param DoliDB $db Database handler @@ -8121,7 +8141,36 @@ abstract class CommonObject if (!$db->query($sql)) { if ($ignoreerrors) { - return true; // TODO Not enough. If there is A-B on kept thirdarty and B-C on old one, we must get A-B-C after merge. Not A-B. + return true; // TODO Not enough. If there is A-B on kept thirdparty and B-C on old one, we must get A-B-C after merge. Not A-B. + } + //$this->errors = $db->lasterror(); + return false; + } + } + + return true; + } + + /** + * Function used to replace a product id with another one. + * This function is meant to be called from replaceProduct with the appropriate tables + * Column name fk_product MUST be used to identify products + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id (the product to delete) + * @param int $dest_id New product id (the product that will received element of the other) + * @param string[] $tables Tables that need to be changed + * @param int $ignoreerrors Ignore errors. Return true even if errors. We need this when replacement can fails like for categories (categorie of old product may already exists on new one) + * @return bool True if success, False if error + */ + public static function commonReplaceProduct(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors = 0) + { + foreach ($tables as $table) { + $sql = 'UPDATE '.MAIN_DB_PREFIX.$table.' SET fk_product = '.((int) $dest_id).' WHERE fk_product = '.((int) $origin_id); + + if (!$db->query($sql)) { + if ($ignoreerrors) { + return true; // TODO Not enough. If there is A-B on kept product and B-C on old one, we must get A-B-C after merge. Not A-B. } //$this->errors = $db->lasterror(); return false; diff --git a/htdocs/core/class/discount.class.php b/htdocs/core/class/discount.class.php index bdc5e746566..dff1383a629 100644 --- a/htdocs/core/class/discount.class.php +++ b/htdocs/core/class/discount.class.php @@ -562,7 +562,7 @@ class DiscountAbsolute * Should always be empty, except if option FACTURE_DEPOSITS_ARE_JUST_PAYMENTS is on (not recommended). * * @param CommonInvoice $invoice Object invoice (customer of supplier) - * @param int $multicurrency 1=Return multicurrency_amount instead of amount + * @param int $multicurrency 1=Return multicurrency_amount instead of amount. TODO Add a mode multicurrency = -1 to return array with amount + multicurrency amount * @return int <0 if KO, Sum of credit notes and deposits amount otherwise */ public function getSumDepositsUsed($invoice, $multicurrency = 0) @@ -603,7 +603,7 @@ class DiscountAbsolute * Return amount (with tax) of all credit notes invoices + excess received used by invoice as a payment * * @param CommonInvoice $invoice Object invoice - * @param int $multicurrency 1=Return multicurrency_amount instead of amount + * @param int $multicurrency 1=Return multicurrency_amount instead of amount. TODO Add a mode multicurrency = -1 to return array with amount + multicurrency amount * @return int <0 if KO, Sum of credit notes and excess received amount otherwise */ public function getSumCreditNotesUsed($invoice, $multicurrency = 0) @@ -643,7 +643,7 @@ class DiscountAbsolute * Return amount (with tax) of all converted amount for this credit note * * @param CommonInvoice $invoice Object invoice - * @param int $multicurrency Return multicurrency_amount instead of amount + * @param int $multicurrency Return multicurrency_amount instead of amount. TODO Add a mode multicurrency = -1 to return array with amount + multicurrency amount * @return int <0 if KO, Sum of credit notes and deposits amount otherwise */ public function getSumFromThisCreditNotesNotUsed($invoice, $multicurrency = 0) diff --git a/htdocs/core/class/dolgraph.class.php b/htdocs/core/class/dolgraph.class.php index b46ca096547..488becd06b7 100644 --- a/htdocs/core/class/dolgraph.class.php +++ b/htdocs/core/class/dolgraph.class.php @@ -1303,11 +1303,13 @@ class DolGraph $this->stringtoshow .= $xaxis; /* For Chartjs v2.9 */ + /* if (empty($showlegend)) { $this->stringtoshow .= 'legend: { display: false }, '."\n"; } else { $this->stringtoshow .= 'legend: { maxWidth: '.round($this->width / 2).', labels: { boxWidth: 15 }, position: \'' . ($showlegend == 2 ? 'right' : 'top') . '\' }, '."\n"; } + */ /* For Chartjs v3.5 */ $this->stringtoshow .= 'plugins: { '."\n"; @@ -1318,7 +1320,9 @@ class DolGraph } $this->stringtoshow .= "}, \n"; - $this->stringtoshow .= 'scales: { xAxes: [{ '; + /* For Chartjs v2.9 */ + /* + $this->stringtoshow .= 'scales: { xAxis: [{ '; if ($this->hideXValues) { $this->stringtoshow .= ' ticks: { display: false }, display: true,'; } @@ -1328,11 +1332,12 @@ class DolGraph $this->stringtoshow .= ', stacked: true'; } $this->stringtoshow .= ' }]'; - $this->stringtoshow .= ', yAxes: [{ ticks: { beginAtZero: true }'; + $this->stringtoshow .= ', yAxis: [{ ticks: { beginAtZero: true }'; if ($type == 'bar' && count($arrayofgroupslegend) > 0) { $this->stringtoshow .= ', stacked: true'; } $this->stringtoshow .= ' }] }'; + */ // Add a callback to change label to show only positive value if (is_array($this->tooltipsLabels) || is_array($this->tooltipsTitles)) { diff --git a/htdocs/core/class/hookmanager.class.php b/htdocs/core/class/hookmanager.class.php index a40ec3e30c3..5f87d81db9d 100644 --- a/htdocs/core/class/hookmanager.class.php +++ b/htdocs/core/class/hookmanager.class.php @@ -195,6 +195,7 @@ class HookManager 'getFormatedSupplierRef', 'getIdProfUrl', 'getInputIdProf', + 'menuDropdownQuickaddItems', 'menuLeftMenuItems', 'moveUploadedFile', 'moreHtmlStatus', diff --git a/htdocs/core/class/html.formcompany.class.php b/htdocs/core/class/html.formcompany.class.php index fbaee3331c5..f976fac978d 100644 --- a/htdocs/core/class/html.formcompany.class.php +++ b/htdocs/core/class/html.formcompany.class.php @@ -406,7 +406,7 @@ class FormCompany extends Form // Show break $key = $langs->trans("Country".strtoupper($obj->country_code)); $valuetoshow = ($key != "Country".strtoupper($obj->country_code)) ? $obj->country_code." - ".$key : $obj->country; - print '\n"; + print '\n"; $country = $obj->country; } diff --git a/htdocs/core/db/DoliDB.class.php b/htdocs/core/db/DoliDB.class.php index 66e54a4fc3c..aae315ec992 100644 --- a/htdocs/core/db/DoliDB.class.php +++ b/htdocs/core/db/DoliDB.class.php @@ -96,6 +96,17 @@ abstract class DoliDB implements Database return '(CASE WHEN '.$test.' THEN '.$resok.' ELSE '.$resko.' END)'; } + /** + * Return SQL string to force an index + * + * @param string $nameofindex Name of index + * @return string SQL string + */ + public function hintindex($nameofindex) + { + return ''; + } + /** * Convert (by PHP) a GM Timestamp date into a string date with PHP server TZ to insert into a date field. * Function to use to build INSERT, UPDATE or WHERE predica diff --git a/htdocs/core/db/mysqli.class.php b/htdocs/core/db/mysqli.class.php index 81a331add8a..582fd08811f 100644 --- a/htdocs/core/db/mysqli.class.php +++ b/htdocs/core/db/mysqli.class.php @@ -168,6 +168,18 @@ class DoliDBMysqli extends DoliDB } + /** + * Return SQL string to force an index + * + * @param string $nameofindex Name of index + * @return string SQL string + */ + public function hintindex($nameofindex) + { + return " FORCE INDEX(".preg_replace('/[^a-z0-9_]/', '', $nameofindex).")"; + } + + /** * Convert a SQL request in Mysql syntax to native syntax * @@ -180,6 +192,7 @@ class DoliDBMysqli extends DoliDB return $line; } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Select a database diff --git a/htdocs/core/js/lib_head.js.php b/htdocs/core/js/lib_head.js.php index 5d47fa5f605..3fe6dee8820 100644 --- a/htdocs/core/js/lib_head.js.php +++ b/htdocs/core/js/lib_head.js.php @@ -1198,4 +1198,22 @@ $(document).ready(function() { } }); + +/* + * Hacky fix for a bug in select2 with jQuery 3.6.0's new nested-focus "protection" + * see: https://github.com/select2/select2/issues/5993 + * see: https://github.com/jquery/jquery/issues/4382 + * + * TODO: Recheck with the select2 GH issue and remove once this is fixed on their side + */ +$(document).on('select2:open', () => { + console.log("Execute the focus (click on combo or use space when on component"); + let allFound = document.querySelectorAll('.select2-container--open .select2-search__field'); + $(this).one('mouseup keyup',()=>{ + setTimeout(()=>{ + allFound[allFound.length - 1].focus(); + },0); + }); +}); + // End of lib_head.js.php diff --git a/htdocs/core/lib/agenda.lib.php b/htdocs/core/lib/agenda.lib.php index d2528f45dfa..488010609f9 100644 --- a/htdocs/core/lib/agenda.lib.php +++ b/htdocs/core/lib/agenda.lib.php @@ -93,7 +93,7 @@ function print_actions_filter($form, $canedit, $status, $year, $month, $day, $sh print $form->select_dolgroups($usergroupid, 'usergroup', 1, '', !$canedit, '', '', '0', false, 'minwidth100 maxwidth500 widthcentpercentminusxx'); print ''; - if ($conf->resource->enabled) { + if (!empty($conf->resource->enabled)) { include_once DOL_DOCUMENT_ROOT.'/resource/class/html.formresource.class.php'; $formresource = new FormResource($db); @@ -105,14 +105,14 @@ function print_actions_filter($form, $canedit, $status, $year, $month, $day, $sh } } - if (!empty($conf->societe->enabled) && $user->rights->societe->lire) { + if (!empty($conf->societe->enabled) && !empty($user->rights->societe->lire)) { print '
'; print img_picto($langs->trans("ThirdParty"), 'company', 'class="fawidth30 inline-block"'); print $form->select_company($socid, 'search_socid', '', ' ', 0, 0, null, 0, 'minwidth100 maxwidth500'); print '
'; } - if (!empty($conf->projet->enabled) && $user->rights->projet->lire) { + if (!empty($conf->projet->enabled) && !empty($user->rights->projet->lire)) { require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php'; $formproject = new FormProjets($db); diff --git a/htdocs/core/lib/company.lib.php b/htdocs/core/lib/company.lib.php index b8b6d1c728a..197a6c95687 100644 --- a/htdocs/core/lib/company.lib.php +++ b/htdocs/core/lib/company.lib.php @@ -180,7 +180,7 @@ function societe_prepare_head(Societe $object) // Related items if ((!empty($conf->commande->enabled) || !empty($conf->propal->enabled) || !empty($conf->facture->enabled) || !empty($conf->ficheinter->enabled) || (!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) || !empty($conf->supplier_order->enabled) || !empty($conf->supplier_invoice->enabled)) - && empty($conf->global->THIRPARTIES_DISABLE_RELATED_OBJECT_TAB)) { + && empty($conf->global->THIRDPARTIES_DISABLE_RELATED_OBJECT_TAB)) { $head[$h][0] = DOL_URL_ROOT.'/societe/consumption.php?socid='.$object->id; $head[$h][1] = $langs->trans("Referers"); $head[$h][2] = 'consumption'; diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index a9739989c41..50d0e8ee9e3 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -7470,13 +7470,23 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $substitutionarray['__DATE_YMD__'] = is_object($object) ? (isset($object->date) ? dol_print_date($object->date, 'day', 0, $outputlangs) : null) : ''; $substitutionarray['__DATE_DUE_YMD__'] = is_object($object) ? (isset($object->date_lim_reglement) ? dol_print_date($object->date_lim_reglement, 'day', 0, $outputlangs) : null) : ''; + $already_payed_all = 0; + if (is_object($object) && ($object instanceof Facture)) { + $already_payed_all = $object->sumpayed + $object->sumdeposit + $object->sumcreditnote; + } + + $substitutionarray['__AMOUNT_EXCL_TAX__'] = is_object($object) ? $object->total_ht : ''; + $substitutionarray['__AMOUNT__'] = is_object($object) ? $object->total_ttc : ''; $substitutionarray['__AMOUNT_TEXT__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, '', true) : ''; $substitutionarray['__AMOUNT_TEXTCURRENCY__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, $conf->currency, true) : ''; - $substitutionarray['__AMOUNT_EXCL_TAX__'] = is_object($object) ? $object->total_ht : ''; + + $substitutionarray['__AMOUNT_REMAIN__'] = is_object($object) ? $object->total_ttc - $already_payed_all : ''; + $substitutionarray['__AMOUNT_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : ''; $substitutionarray['__AMOUNT_VAT_TEXT__'] = is_object($object) ? (isset($object->total_vat) ? dol_convertToWord($object->total_vat, $outputlangs, '', true) : dol_convertToWord($object->total_tva, $outputlangs, '', true)) : ''; $substitutionarray['__AMOUNT_VAT_TEXTCURRENCY__'] = is_object($object) ? (isset($object->total_vat) ? dol_convertToWord($object->total_vat, $outputlangs, $conf->currency, true) : dol_convertToWord($object->total_tva, $outputlangs, $conf->currency, true)) : ''; + if ($onlykey != 2 || $mysoc->useLocalTax(1)) { $substitutionarray['__AMOUNT_TAX2__'] = is_object($object) ? $object->total_localtax1 : ''; } @@ -7484,8 +7494,10 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $substitutionarray['__AMOUNT_TAX3__'] = is_object($object) ? $object->total_localtax2 : ''; } - $substitutionarray['__AMOUNT_FORMATED__'] = is_object($object) ? ($object->total_ttc ? price($object->total_ttc, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : ''; + // Amount keys formated in a currency $substitutionarray['__AMOUNT_EXCL_TAX_FORMATED__'] = is_object($object) ? ($object->total_ht ? price($object->total_ht, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : ''; + $substitutionarray['__AMOUNT_FORMATED__'] = is_object($object) ? ($object->total_ttc ? price($object->total_ttc, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : ''; + $substitutionarray['__AMOUNT_REMAIN_FORMATED__'] = is_object($object) ? ($object->total_ttc ? price($object->total_ttc - $already_payed_all, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : ''; $substitutionarray['__AMOUNT_VAT_FORMATED__'] = is_object($object) ? (isset($object->total_vat) ? price($object->total_vat, 0, $outputlangs, 0, -1, -1, $conf->currency) : ($object->total_tva ? price($object->total_tva, 0, $outputlangs, 0, -1, -1, $conf->currency) : null)) : ''; if ($onlykey != 2 || $mysoc->useLocalTax(1)) { $substitutionarray['__AMOUNT_TAX2_FORMATED__'] = is_object($object) ? ($object->total_localtax1 ? price($object->total_localtax1, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : ''; diff --git a/htdocs/core/lib/pdf.lib.php b/htdocs/core/lib/pdf.lib.php index ea8c6c2ce23..d9612d58652 100644 --- a/htdocs/core/lib/pdf.lib.php +++ b/htdocs/core/lib/pdf.lib.php @@ -1130,6 +1130,11 @@ function pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_ $pdf->SetFont('', '', 7); $pdf->SetDrawColor(224, 224, 224); + // Option for footer text color + if (!empty($conf->global->PDF_FOOTER_TEXT_COLOR)) { + list($r, $g, $b) = sscanf($conf->global->PDF_FOOTER_TEXT_COLOR, '%d, %d, %d'); + $pdf->SetTextColor($r, $g, $b); + } // The start of the bottom of this page footer is positioned according to # of lines $freetextheight = 0; @@ -1161,6 +1166,14 @@ function pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_ $marginwithfooter = $marge_basse + $freetextheight + $mycustomfooterheight; $posy = $marginwithfooter + 0; + // Option for footer background color (without freetext zone) + if (!empty($conf->global->PDF_FOOTER_BACKGROUND_COLOR)) { + list($r, $g, $b) = sscanf($conf->global->PDF_FOOTER_BACKGROUND_COLOR, '%d, %d, %d'); + $pdf->SetAutoPageBreak(0, 0); // Disable auto pagebreak + $pdf->Rect(0, $dims['hk'] - $posy + $freetextheight, $dims['wk'] + 1, $marginwithfooter + 1, 'F', '', $fill_color = array($r, $g, $b)); + $pdf->SetAutoPageBreak(1, 0); // Restore pagebreak + } + if ($line) { // Free text $pdf->SetXY($dims['lm'], -$posy); if (empty($conf->global->PDF_ALLOW_HTML_FOR_FREE_TEXT)) { // by default @@ -1172,10 +1185,20 @@ function pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_ } $pdf->SetY(-$posy); - $pdf->line($dims['lm'], $dims['hk'] - $posy, $dims['wk'] - $dims['rm'], $dims['hk'] - $posy); - $posy--; - $pdf->writeHTMLCell($pdf->page_largeur - $pdf->margin_left - $pdf->margin_right, $freetextheight, $dims['lm'], $dims['hk'] - $posy, dol_htmlentitiesbr($mycustomfooter, 1, 'UTF-8', 0)); + // Hide footer line if footer background color is set + if (empty($conf->global->PDF_FOOTER_BACKGROUND_COLOR)) { + $pdf->line($dims['lm'], $dims['hk'] - $posy, $dims['wk'] - $dims['rm'], $dims['hk'] - $posy); + } + + // Option for set top margin height of footer after freetext + if (!empty($conf->global->PDF_FOOTER_TOP_MARGIN) || ($conf->global->PDF_FOOTER_TOP_MARGIN === '0')) { + $posy -= $conf->global->PDF_FOOTER_TOP_MARGIN; + } else { $posy--; } + + if ($conf->global->PDF_FOOTER_DISABLE_PAGEBREAK === '1') { $pdf->SetAutoPageBreak(0, 0); } // Option for disable auto pagebreak + $pdf->writeHTMLCell($pdf->page_largeur - $pdf->margin_left - $pdf->margin_right, $mycustomfooterheight, $dims['lm'], $dims['hk'] - $posy, dol_htmlentitiesbr($mycustomfooter, 1, 'UTF-8', 0)); + if ($conf->global->PDF_FOOTER_DISABLE_PAGEBREAK === '1') { $pdf->SetAutoPageBreak(1, 0); } // Restore pagebreak $posy -= $mycustomfooterheight - 3; } else { @@ -1183,6 +1206,14 @@ function pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_ $marginwithfooter = $marge_basse + $freetextheight + (!empty($line1) ? 3 : 0) + (!empty($line2) ? 3 : 0) + (!empty($line3) ? 3 : 0) + (!empty($line4) ? 3 : 0); $posy = $marginwithfooter + 0; + // Option for footer background color (without freetext zone) + if (!empty($conf->global->PDF_FOOTER_BACKGROUND_COLOR)) { + list($r, $g, $b) = sscanf($conf->global->PDF_FOOTER_BACKGROUND_COLOR, '%d, %d, %d'); + $pdf->SetAutoPageBreak(0, 0); // Disable auto pagebreak + $pdf->Rect(0, $dims['hk'] - $posy + $freetextheight, $dims['wk'] + 1, $marginwithfooter + 1, 'F', '', $fill_color = array($r, $g, $b)); + $pdf->SetAutoPageBreak(1, 0); // Restore pagebreak + } + if ($line) { // Free text $pdf->SetXY($dims['lm'], -$posy); if (empty($conf->global->PDF_ALLOW_HTML_FOR_FREE_TEXT)) { // by default @@ -1194,8 +1225,16 @@ function pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_ } $pdf->SetY(-$posy); - $pdf->line($dims['lm'], $dims['hk'] - $posy, $dims['wk'] - $dims['rm'], $dims['hk'] - $posy); - $posy--; + + // Hide footer line if footer background color is set + if (empty($conf->global->PDF_FOOTER_BACKGROUND_COLOR)) { + $pdf->line($dims['lm'], $dims['hk'] - $posy, $dims['wk'] - $dims['rm'], $dims['hk'] - $posy); + } + + // Option for set top margin height of footer after freetext + if (!empty($conf->global->PDF_FOOTER_TOP_MARGIN) || ($conf->global->PDF_FOOTER_TOP_MARGIN === '0')) { + $posy -= $conf->global->PDF_FOOTER_TOP_MARGIN; + } else { $posy--; } if (!empty($line1)) { $pdf->SetFont('', 'B', 7); diff --git a/htdocs/core/login/functions_dolibarr.php b/htdocs/core/login/functions_dolibarr.php index 292ce1b44f5..610072aa35a 100644 --- a/htdocs/core/login/functions_dolibarr.php +++ b/htdocs/core/login/functions_dolibarr.php @@ -143,7 +143,11 @@ function check_user_password_dolibarr($usertotest, $passwordtotest, $entitytotes $ret = $mc->checkRight($obj->rowid, $entitytotest); if ($ret < 0) { dol_syslog("functions_dolibarr::check_user_password_dolibarr Authentication KO entity '".$entitytotest."' not allowed for user '".$obj->rowid."'", LOG_NOTICE); + $login = ''; // force authentication failure + if ($mc->db->lasterror()) { + $_SESSION["dol_loginmesg"] = $mc->db->lasterror(); + } } } } diff --git a/htdocs/core/modules/modFacture.class.php b/htdocs/core/modules/modFacture.class.php index b64ecca6cc1..817fa1b53cf 100644 --- a/htdocs/core/modules/modFacture.class.php +++ b/htdocs/core/modules/modFacture.class.php @@ -113,7 +113,7 @@ class modFacture extends DolibarrModules $datestart = dol_mktime(23, 0, 0, $arraydate['mon'], $arraydate['mday'], $arraydate['year']); $this->cronjobs = array( 0 => array( - 'label'=>'RecurringInvoices', + 'label'=>'RecurringInvoicesJob', 'jobtype'=>'method', 'class'=>'compta/facture/class/facture-rec.class.php', 'objectname'=>'FactureRec', @@ -122,7 +122,7 @@ class modFacture extends DolibarrModules 'comment'=>'Generate recurring invoices', 'frequency'=>1, 'unitfrequency'=>3600 * 24, - 'priority'=>50, + 'priority'=>51, 'status'=>1, 'test'=>'$conf->facture->enabled', 'datestart'=>$datestart diff --git a/htdocs/core/modules/modFournisseur.class.php b/htdocs/core/modules/modFournisseur.class.php index 708cd1fb408..aef28514c61 100644 --- a/htdocs/core/modules/modFournisseur.class.php +++ b/htdocs/core/modules/modFournisseur.class.php @@ -133,7 +133,7 @@ class modFournisseur extends DolibarrModules $datestart = dol_mktime(23, 0, 0, $arraydate['mon'], $arraydate['mday'], $arraydate['year']); $this->cronjobs = array( 0 => array( - 'label'=>'RecurringSupplierInvoices', + 'label'=>'RecurringSupplierInvoicesJob', 'jobtype'=>'method', 'class'=>'fourn/class/fournisseur.facture-rec.class.php', 'objectname'=>'FactureFournisseurRec', @@ -142,7 +142,7 @@ class modFournisseur extends DolibarrModules 'comment'=>'Generate recurring supplier invoices', 'frequency'=>1, 'unitfrequency'=>3600 * 24, - 'priority'=>50, + 'priority'=>51, 'status'=>1, 'datestart'=>$datestart )); diff --git a/htdocs/core/tpl/contacts.tpl.php b/htdocs/core/tpl/contacts.tpl.php index 2dd9751a4c6..5f463e44846 100644 --- a/htdocs/core/tpl/contacts.tpl.php +++ b/htdocs/core/tpl/contacts.tpl.php @@ -259,7 +259,7 @@ $arrayfields = array( 'rowid' => array('label'=>$langs->trans("Id"), 'checked'=>1), 'nature' => array('label'=>$langs->trans("NatureOfContact"), 'checked'=>1), 'thirdparty' => array('label'=>$langs->trans("ThirdParty"), 'checked'=>1), - 'contact' => array('label'=>$langs->trans("Users").'/'.$langs->trans("Contacts"), 'checked'=>1), + 'contact' => array('label'=>$langs->trans("Users").' | '.$langs->trans("Contacts"), 'checked'=>1), 'type' => array('label'=>$langs->trans("ContactType"), 'checked'=>1), 'status' => array('label'=>$langs->trans("Status"), 'checked'=>1), 'link' => array('label'=>$langs->trans("Link"), 'checked'=>1), diff --git a/htdocs/core/tpl/list_print_total.tpl.php b/htdocs/core/tpl/list_print_total.tpl.php index b015dc51fdc..8d84228e2ec 100644 --- a/htdocs/core/tpl/list_print_total.tpl.php +++ b/htdocs/core/tpl/list_print_total.tpl.php @@ -14,7 +14,7 @@ if (isset($totalarray['pos'])) { $i++; if (!empty($totalarray['pos'][$i])) { print ''; print ''; print ''; print ''; @@ -41,6 +42,7 @@ if (!empty($conf->global->PRODUCT_USE_UNITS)) { } print ''; +print ''; $selected = 1; if (!empty($selectedLines) && !in_array($this->tpl['id'], $selectedLines)) { diff --git a/htdocs/core/tpl/resource_add.tpl.php b/htdocs/core/tpl/resource_add.tpl.php index 64d545ba583..02bc8ce421f 100644 --- a/htdocs/core/tpl/resource_add.tpl.php +++ b/htdocs/core/tpl/resource_add.tpl.php @@ -13,9 +13,11 @@ require_once DOL_DOCUMENT_ROOT.'/resource/class/html.formresource.class.php'; $form = new Form($db); $formresources = new FormResource($db); -$out = '
'; +$out = ''; -$out .= '
'; +$out .= '
'; + +$out .= ''; $out .= ''; $out .= ''; $out .= ''; @@ -23,21 +25,30 @@ $out .= ''; $out .= ''; $out .= ''; +$out .= '
'; // Place -$out .= '
'.$langs->trans("SelectResource").'
'; -$out .= '
'; +$out .= '
'.$langs->trans("SelectResource").'
'; +$out .= '
'; $events = array(); $out .= $formresources->select_resource_list('', 'fk_resource', '', 1, 1, 0, $events, '', 2, null); $out .= '
'; -$out .= '
'.$form->selectyesno('busy', (GETPOSTISSET('busy') ? GETPOST('busy') : 1), 1).'
'; -$out .= '
'.$form->selectyesno('mandatory', (GETPOSTISSET('mandatory') ? GETPOST('mandatory') : 0), 1).'
'; +$out .= '
'; +//$out .= $form->selectyesno('busy', (GETPOSTISSET('busy') ? GETPOST('busy') : 1), 1); +$out .= ''; +$out .= '
'; +$out .= '
'; +//$out .= $form->selectyesno('mandatory', (GETPOSTISSET('mandatory') ? GETPOST('mandatory') : 0), 1); +$out .= ''; +$out .= '
'; -$out .= '
'; +$out .= '
'; $out .= ''; $out .= '
'; +$out .= '
'; + $out .= ''; $out .= '
'; diff --git a/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php b/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php index 2ff5d3f9c43..cf6a8220c29 100644 --- a/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php +++ b/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php @@ -958,11 +958,13 @@ class InterfaceActionsAuto extends DolibarrTriggers } } + /* Seems no more required: We have the data in dedicated field now. if (!empty($user->login)) { $object->actionmsg = dol_concatdesc($langs->transnoentities("Author").': '.$user->login, $object->actionmsg); } elseif (isset($object->origin_email)) { $object->actionmsg = dol_concatdesc($langs->transnoentities("Author").': '.$object->origin_email, $object->actionmsg); } + */ dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id); @@ -1019,7 +1021,7 @@ class InterfaceActionsAuto extends DolibarrTriggers $actioncomm->type_code = $object->actiontypecode; // Type of event ('AC_OTH', 'AC_OTH_AUTO', 'AC_XXX'...) $actioncomm->code = 'AC_'.$action; $actioncomm->label = $object->actionmsg2; - $actioncomm->note_private = $object->actionmsg; // TODO Replace with ($actioncomm->email_msgid ? $object->email_content : $object->actionmsg) + $actioncomm->note_private = $object->actionmsg; $actioncomm->fk_project = $projectid; $actioncomm->datep = $now; $actioncomm->datef = $now; diff --git a/htdocs/core/triggers/interface_80_modStripe_Stripe.class.php b/htdocs/core/triggers/interface_80_modStripe_Stripe.class.php index 0e571f26c98..dfac4c5b84d 100644 --- a/htdocs/core/triggers/interface_80_modStripe_Stripe.class.php +++ b/htdocs/core/triggers/interface_80_modStripe_Stripe.class.php @@ -183,7 +183,7 @@ class InterfaceStripe extends DolibarrTriggers if ($action == 'COMPANY_DELETE') { dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id); - if (!empty($conf->global->STRIPE_DELETE_STRIPE_ACCOUNT_WHEN_DELETING_THIRPARTY)) { + if (!empty($conf->global->STRIPE_DELETE_STRIPE_ACCOUNT_WHEN_DELETING_THIRDPARTY)) { // By default, we do not delete the stripe account. We may need to reuse it with its payment_intent, for example if delete is for a merge of thirdparties. $stripeacc = $stripe->getStripeAccount($service); // No need of network access for this. May return '' if no Oauth defined. diff --git a/htdocs/datapolicy/README.md b/htdocs/datapolicy/README.md index e2bde95a6d8..0d70b287a81 100644 --- a/htdocs/datapolicy/README.md +++ b/htdocs/datapolicy/README.md @@ -1,5 +1,7 @@ DataPolicy ========== + This module provides features to be compliant with data privacy rules of your country. -A schedlued job is installed to automatically clean old record in your database. You defined what to delete and when in the setup of module. \ No newline at end of file +A scheduled job is installed to automatically delete old records in your database. +In the setup of the module you define what should be deleted and when. diff --git a/htdocs/delivery/class/delivery.class.php b/htdocs/delivery/class/delivery.class.php index ab1f1563ab7..f41b855e123 100644 --- a/htdocs/delivery/class/delivery.class.php +++ b/htdocs/delivery/class/delivery.class.php @@ -1092,6 +1092,23 @@ class Delivery extends CommonObject return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'deliverydet' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } } diff --git a/htdocs/fichinter/card.php b/htdocs/fichinter/card.php index 80f39e17730..0d7e5278a14 100644 --- a/htdocs/fichinter/card.php +++ b/htdocs/fichinter/card.php @@ -1003,11 +1003,13 @@ if ($action == 'create') { $title = $langs->trans('Services'); print load_fiche_titre($title); + print '
'; print '
' . $langs->trans('ExpenseReportApplyTo') . '' . $langs->trans('Type') . '' . $langs->trans('ExpenseReportLimitOn') . '' . $langs->trans('ExpenseReportDateStart') . '' . $langs->trans('ExpenseReportDateEnd') . '' . $langs->trans('ExpenseReportLimitAmount') . '' . $langs->trans('ExpenseReportRestrictive') . '
' . $langs->trans('ExpenseReportApplyTo') . '' . $langs->trans('Type') . '' . $langs->trans('ExpenseReportLimitOn') . '' . $langs->trans('ExpenseReportDateStart') . '' . $langs->trans('ExpenseReportDateEnd') . '' . $langs->trans('ExpenseReportLimitAmount') . '' . $langs->trans('ExpenseReportRestrictive') . ' 
'; + echo ''; if ($action == 'edit' && $object->id == $rule->id) { $selected = ($object->is_for_all > 0) ? 'A' : ($object->fk_usergroup > 0 ? 'G' : 'U'); echo '
' . $form->selectarray('apply_to', $tab_apply, $selected, 0) . '
'; @@ -259,7 +259,7 @@ foreach ($rules as $rule) { echo '
'; + echo ''; if ($action == 'edit' && $object->id == $rule->id) { echo $form->selectExpense($object->fk_c_type_fees, 'fk_c_type_fees', 0, 1, 1); } else { @@ -278,7 +278,7 @@ foreach ($rules as $rule) { echo ''; + echo ''; if ($action == 'edit' && $object->id == $rule->id) { echo $form->selectarray('code_expense_rules_type', $tab_rules_type, $object->code_expense_rules_type, 0); } else { @@ -287,7 +287,7 @@ foreach ($rules as $rule) { echo ''; + echo ''; if ($action == 'edit' && $object->id == $rule->id) { print $form->selectDate(strtotime(date('Y-m-d', $object->dates)), 'start', '', '', 0, '', 1, 0); } else { @@ -296,7 +296,7 @@ foreach ($rules as $rule) { echo ''; + echo ''; if ($action == 'edit' && $object->id == $rule->id) { print $form->selectDate(strtotime(date('Y-m-d', $object->datee)), 'end', '', '', 0, '', 1, 0); } else { @@ -305,7 +305,7 @@ foreach ($rules as $rule) { echo ''; + echo ''; if ($action == 'edit' && $object->id == $rule->id) { echo '' . $conf->currency; } else { @@ -314,7 +314,7 @@ foreach ($rules as $rule) { echo ''; + echo ''; if ($action == 'edit' && $object->id == $rule->id) { echo $form->selectyesno('restrictive', $object->restrictive, 1); } else { diff --git a/htdocs/admin/system/security.php b/htdocs/admin/system/security.php index 40656928824..8a480ea49ca 100644 --- a/htdocs/admin/system/security.php +++ b/htdocs/admin/system/security.php @@ -266,10 +266,20 @@ print '
'; print '$dolibarr_main_restrict_ip: '; if (empty($dolibarr_main_restrict_ip)) { - print ''.$langs->trans("None").''; + print $langs->trans("None"); //print ' ('.$langs->trans("RecommendedValueIs", $langs->transnoentitiesnoconv("IPsOfUsers")).')'; +} else { + print $dolibarr_main_restrict_ip; } +print '
'; +print '$dolibarr_main_restrict_os_commands: '; +if (empty($dolibarr_main_restrict_os_commands)) { + print $langs->trans("None"); +} else { + print $dolibarr_main_restrict_os_commands; +} +print ' ('.$langs->trans("RecommendedValueIs", 'mysqldump, mysql, pg_dump, pgrestore').')'; print '
'; if (empty($conf->global->SECURITY_DISABLE_TEST_ON_OBFUSCATED_CONF)) { diff --git a/htdocs/bom/class/bom.class.php b/htdocs/bom/class/bom.class.php index 09f69993310..86e07ed424d 100644 --- a/htdocs/bom/class/bom.class.php +++ b/htdocs/bom/class/bom.class.php @@ -1103,6 +1103,23 @@ class BOM extends CommonObject } } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'bom_bomline' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } + /** * Get Net needs by product * diff --git a/htdocs/comm/action/class/actioncomm.class.php b/htdocs/comm/action/class/actioncomm.class.php index a5b4f1d8ce9..ac26cf0c56a 100644 --- a/htdocs/comm/action/class/actioncomm.class.php +++ b/htdocs/comm/action/class/actioncomm.class.php @@ -868,6 +868,16 @@ class ActionComm extends CommonObject $this->event_paid = $obj->event_paid; $this->status = $obj->status; + //email information + $this->email_msgid=$obj->email_msgid; + $this->email_from=$obj->email_from; + $this->email_sender=$obj->email_sender; + $this->email_to=$obj->email_to; + $this->email_tocc=$obj->email_tocc; + $this->email_tobcc=$obj->email_tobcc; + $this->email_subject=$obj->email_subject; + $this->errors_to=$obj->errors_to; + $this->fetch_optionals(); if ($loadresources) { @@ -1582,8 +1592,25 @@ class ActionComm extends CommonObject if (isset($this->transparency)) { $tooltip .= '
'.$langs->trans('Busy').': '.yn($this->transparency); } + if (!empty($this->email_msgid)) { + $langs->load("mails"); + $tooltip .= '
'; + //$tooltip .= '
'.img_picto('', 'email').' '.$langs->trans("Email").''; + $tooltip .= '
'.$langs->trans('MailTopic').': '.$this->email_subject; + $tooltip .= '
'.$langs->trans('MailFrom').': '.str_replace(array('<', '>'), array('&lt', '&gt'), $this->email_from); + $tooltip .= '
'.$langs->trans('MailTo').':, '.str_replace(array('<', '>'), array('&lt', '&gt'), $this->email_to); + if (!empty($this->email_tocc)) { + $tooltip .= '
'.$langs->trans('MailCC').': '.str_replace(array('<', '>'), array('&lt', '&gt'), $this->email_tocc); + } + /* Disabled because bcc must remain by defintion not visible + if (!empty($this->email_tobcc)) { + $tooltip .= '
'.$langs->trans('MailCCC').': '.$this->email_tobcc; + } */ + } if (!empty($this->note_private)) { - $tooltip .= '
'.$langs->trans('Note').': '.(dol_textishtml($this->note_private) ? str_replace(array("\r", "\n"), "", $this->note_private) : str_replace(array("\r", "\n"), '
', $this->note_private)); + $tooltip .= '

'.$langs->trans('Description').':
'; + $texttoshow = dolGetFirstLineOfText($this->note_private, 10); + $tooltip .= (dol_textishtml($texttoshow) ? str_replace(array("\r", "\n"), "", $texttoshow) : str_replace(array("\r", "\n"), '
', $texttoshow)); } $linkclose = ''; //if (!empty($conf->global->AGENDA_USE_EVENT_TYPE) && $this->type_color) @@ -1594,9 +1621,8 @@ class ActionComm extends CommonObject $label = $langs->trans("ShowAction"); $linkclose .= ' alt="'.dol_escape_htmltag($tooltip, 1).'"'; } - $linkclose .= ' title="'.dol_escape_htmltag($tooltip, 1).'"'; + $linkclose .= ' title="'.dol_escape_htmltag($tooltip, 1, 0, 0, '', 1).'"'; $linkclose .= ' class="'.$classname.' classfortooltip"'; - /* $hookmanager->initHooks(array('actiondao')); $parameters=array('id'=>$this->id); @@ -2210,6 +2236,26 @@ class ActionComm extends CommonObject return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $dbs Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $dbs, $origin_id, $dest_id) + { + $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'actioncomm SET fk_element = ' . ((int) $dest_id) . ' WHERE elementtype="product" AND fk_element = '.((int) $origin_id); + // using $dbs, not $this->db because function is static + if (!$dbs->query($sql)) { + //$this->errors = $dbs->lasterror(); + return false; + } + + return true; + } + /** * Is the action delayed? * diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index 10903ea3556..d73a9769d17 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -1892,11 +1892,13 @@ if ($action == 'create') { $title = $langs->trans('ProductsAndServices'); print load_fiche_titre($title); + print '
'; print ''; $objectsrc->printOriginLinesList(); print '
'; + print '
'; } } elseif ($object->id > 0) { /* diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index a30fc456b18..be10e45383c 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -3821,8 +3821,24 @@ class Propal extends CommonObject return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } -} + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'propaldet' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } +} /** * Class to manage commercial proposal lines diff --git a/htdocs/commande/card.php b/htdocs/commande/card.php index e8f88800693..b54784a82b2 100644 --- a/htdocs/commande/card.php +++ b/htdocs/commande/card.php @@ -1862,11 +1862,13 @@ if ($action == 'create' && $usercancreate) { $title = $langs->trans('ProductsAndServices'); print load_fiche_titre($title); + print '
'; print ''; $objectsrc->printOriginLinesList('', $selectedLines); print '
'; + print '
'; } print ''; diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index 4c745948f52..f17006738bf 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -4039,6 +4039,23 @@ class Commande extends CommonOrder return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'commandedet', + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } + /** * Is the customer order delayed? * diff --git a/htdocs/compta/bank/card.php b/htdocs/compta/bank/card.php index b0444b90dcc..8ca3272dd78 100644 --- a/htdocs/compta/bank/card.php +++ b/htdocs/compta/bank/card.php @@ -65,7 +65,7 @@ $hookmanager->initHooks(array('bankcard', 'globalcard')); // Security check $id = GETPOST("id", 'int') ? GETPOST("id", 'int') : GETPOST('ref', 'alpha'); -$fieldid = GETPOST("id") ? 'rowid' : 'ref'; +$fieldid = GETPOST("id", 'int') ? 'rowid' : 'ref'; $result = restrictedArea($user, 'banque', $id, 'bank_account&bank_account', '', '', $fieldid); diff --git a/htdocs/compta/bank/class/account.class.php b/htdocs/compta/bank/class/account.class.php index 219d8bee154..324800910da 100644 --- a/htdocs/compta/bank/class/account.class.php +++ b/htdocs/compta/bank/class/account.class.php @@ -1728,7 +1728,7 @@ class Account extends CommonObject if ($dbs->query($sql)) { return true; } else { - //if ($ignoreerrors) return true; // TODO Not enough. If there is A-B on kept thirdarty and B-C on old one, we must get A-B-C after merge. Not A-B. + //if ($ignoreerrors) return true; // TODO Not enough. If there is A-B on kept thirdparty and B-C on old one, we must get A-B-C after merge. Not A-B. //$this->errors = $dbs->lasterror(); return false; } diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index 102e0cf7f4a..2cf5e13ff8b 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -2560,9 +2560,10 @@ if (empty($reshook)) { setEventMessages($mesg, null, 'warnings'); $result = -1; } else { - $object->update_percent($line, GETPOST('all_progress')); + $object->update_percent($line, GETPOST('all_progress'), false); } } + $object->update_price(1); } } elseif ($action == 'updateline' && $usercancreate && !$cancel) { header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id); // To show again edited page @@ -3522,7 +3523,7 @@ if ($action == 'create') { if ($socid > 0) { // Discounts for third party - print '
'.$langs->trans('Discounts').''; + print '
'.$langs->trans('DiscountStillRemaining').''; $thirdparty = $soc; $discount_type = 0; @@ -3815,11 +3816,13 @@ if ($action == 'create') { $title = $langs->trans('ProductsAndServices'); print load_fiche_titre($title); + print '
'; print ''; $objectsrc->printOriginLinesList('', $selectedLines); print '
'; + print '
'; } print "\n"; @@ -4353,8 +4356,8 @@ if ($action == 'create') { // Relative and absolute discounts print ''."\n"; - print '
'.$langs->trans('Discounts'); - print ''; + print '
'.$langs->trans('DiscountStillRemaining').''; $thirdparty = $soc; $discount_type = 0; $backtopage = urlencode($_SERVER["PHP_SELF"].'?facid='.$object->id); @@ -5220,7 +5223,7 @@ if ($action == 'create') { print ''; print ''; - print '

'; + print '


'; if (!empty($conf->global->MAIN_DISABLE_CONTACTS_TAB)) { $blocname = 'contacts'; diff --git a/htdocs/compta/facture/class/facture-rec.class.php b/htdocs/compta/facture/class/facture-rec.class.php index 290467a9d54..91d0fd0f20a 100644 --- a/htdocs/compta/facture/class/facture-rec.class.php +++ b/htdocs/compta/facture/class/facture-rec.class.php @@ -1759,6 +1759,23 @@ class FactureRec extends CommonInvoice return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'facturedet_rec' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } + /** * Update frequency and unit * diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index af029376d53..2b368d7bd75 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -3725,11 +3725,12 @@ class Facture extends CommonInvoice /** * Update invoice line with percentage * - * @param FactureLigne $line Invoice line - * @param int $percent Percentage + * @param FactureLigne $line Invoice line + * @param int $percent Percentage + * @param boolean $update_price Update object price * @return void */ - public function update_percent($line, $percent) + public function update_percent($line, $percent, $update_price = true) { // phpcs:enable global $mysoc, $user; @@ -3756,7 +3757,11 @@ class Facture extends CommonInvoice $line->multicurrency_total_tva = $tabprice[17]; $line->multicurrency_total_ttc = $tabprice[18]; $line->update($user); - $this->update_price(1); + + // sometimes it is better to not update price for each line, ie when updating situation on all lines + if ($update_price) { + $this->update_price(1); + } } /** @@ -4818,6 +4823,23 @@ class Facture extends CommonInvoice return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'facturedet' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } + /** * Is the customer invoice delayed? * diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php index 02c0ec21e7a..eedc3297018 100644 --- a/htdocs/compta/facture/list.php +++ b/htdocs/compta/facture/list.php @@ -598,6 +598,9 @@ if (!empty($search_categ_cus) && $search_categ_cus != '-1') { } $sql .= ', '.MAIN_DB_PREFIX.'facture as f'; +if ($sortfield == "f.datef") { + $sql .= $db->hintindex('idx_facture_datef'); +} if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (f.rowid = ef.fk_object)"; } @@ -846,6 +849,37 @@ $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListHaving', $parameters, $object); // Note that $action and $object may have been modified by hook $sql .= empty($hookmanager->resPrint) ? "" : " HAVING 1=1 ".$hookmanager->resPrint; +$nbtotalofrecords = ''; +if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { + /* This old and fast method to get and count full list returns all record so use a high amount of memory. + $result = $db->query($sql); + $nbtotalofrecords = $db->num_rows($result); + */ + /* The fast and low memory method to get and count full list converts the sql into a sql count */ + if ($sall || $search_product_category > 0 || $search_user > 0) { + $sqlforcount = preg_replace('/^SELECT[a-zA-Z0-9\._\s\(\),=<>\:\-\']+\sFROM/', 'SELECT COUNT(DISTINCT f.rowid) as nbtotalofrecords FROM', $sql); + } else { + $sqlforcount = preg_replace('/^SELECT[a-zA-Z0-9\._\s\(\),=<>\:\-\']+\sFROM/', 'SELECT COUNT(f.rowid) as nbtotalofrecords FROM', $sql); + $sqlforcount = preg_replace('/LEFT JOIN '.MAIN_DB_PREFIX.'paiement_facture as pf ON pf.fk_facture = f.rowid/', '', $sqlforcount); + } + $sqlforcount = preg_replace('/GROUP BY.*$/', '', $sqlforcount); + + $resql = $db->query($sqlforcount); + if ($resql) { + $objforcount = $db->fetch_object($resql); + $nbtotalofrecords = $objforcount->nbtotalofrecords; + } else { + dol_print_error($db); + } + + if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 + $page = 0; + $offset = 0; + } + $db->free($resql); +} + +// Complete request and execute it with limit $sql .= ' ORDER BY '; $listfield = explode(',', $sortfield); $listorder = explode(',', $sortorder); @@ -853,19 +887,10 @@ foreach ($listfield as $key => $value) { $sql .= $listfield[$key].' '.($listorder[$key] ? $listorder[$key] : 'DESC').','; } $sql .= ' f.rowid DESC '; - -$nbtotalofrecords = ''; -if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { - $result = $db->query($sql); - $nbtotalofrecords = $db->num_rows($result); - if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0 - $page = 0; - $offset = 0; - } +if ($limit) { + $sql .= $db->plimit($limit + 1, $offset); } -$sql .= $db->plimit($limit + 1, $offset); - $resql = $db->query($sql); if ($resql) { diff --git a/htdocs/contact/card.php b/htdocs/contact/card.php index 229bfc0530b..ee1d10181ca 100644 --- a/htdocs/contact/card.php +++ b/htdocs/contact/card.php @@ -624,7 +624,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { */ $object->canvas = $canvas; - $object->state_id = GETPOST("state_id"); + $object->state_id = GETPOST("state_id", "int"); // We set country_id, country_code and label for the selected country $object->country_id = GETPOST("country_id") ? GETPOST("country_id", "int") : (empty($objsoc->country_id) ? $mysoc->country_id : $objsoc->country_id); @@ -697,7 +697,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { print '
'; - print img_picto('', 'company').$form->select_company($socid, 'socid', '', 'SelectThirdParty'); + print img_picto('', 'company').$form->select_company($socid, 'socid', '', 'SelectThirdParty', 0, 0, null, 0, 'minwidth300 maxwidth500 widthcentpercentminusxx'); print '
'.$langs->trans('Unit').''.$langs->trans('ReductionShort').''.$langs->trans('TotalHT').''.$form->showCheckAddButtons('checkforselect', 1).'
'; - if ($totalarray['type'][$i] == 'duration') { + if (isset($totalarray['type']) && $totalarray['type'][$i] == 'duration') { print (!empty($totalarray['val'][$totalarray['pos'][$i]])?convertSecondToTime($totalarray['val'][$totalarray['pos'][$i]], 'allhourmin'):0); } else { print price(!empty($totalarray['val'][$totalarray['pos'][$i]])?$totalarray['val'][$totalarray['pos'][$i]]:0); diff --git a/htdocs/core/tpl/originproductline.tpl.php b/htdocs/core/tpl/originproductline.tpl.php index 7e56611a282..55d385fcd50 100644 --- a/htdocs/core/tpl/originproductline.tpl.php +++ b/htdocs/core/tpl/originproductline.tpl.php @@ -1,6 +1,7 @@ * Copyright (C) 2017 Charlie Benke + * Copyright (C) 2022 Gauthier VERDOL * * 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 @@ -26,7 +27,7 @@ if (empty($conf) || !is_object($conf)) { tpl['strike']) ? '' : ' strikefordisabled').'">'; +print '
'.$this->tpl['label'].''.$this->tpl['description'].''.$this->tpl['vat_rate'].''.$this->tpl['remise_percent'].''.$this->tpl['total_ht'].'
'; $objectsrc->printOriginLinesList(empty($conf->global->FICHINTER_PRINT_PRODUCTS) ? 'services' : ''); // Show only service, except if option FICHINTER_PRINT_PRODUCTS is on print '
'; + print ''; } print ''; diff --git a/htdocs/fichinter/class/fichinterrec.class.php b/htdocs/fichinter/class/fichinterrec.class.php index d3f3c82636e..4488b4643b8 100644 --- a/htdocs/fichinter/class/fichinterrec.class.php +++ b/htdocs/fichinter/class/fichinterrec.class.php @@ -40,7 +40,7 @@ class FichinterRec extends Fichinter { public $element = 'fichinterrec'; public $table_element = 'fichinter_rec'; - public $table_element_line = 'fichinter_rec'; + public $table_element_line = 'fichinterdet_rec'; /** * @var string Fieldname with ID of parent key if this field has a parent @@ -706,6 +706,22 @@ class FichinterRec extends Fichinter return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'fichinterdet_rec' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } /** * Update frequency and unit diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 327bfc867d9..07ae8554a86 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -3249,6 +3249,23 @@ class CommandeFournisseur extends CommonOrder return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'commande_fournisseurdet' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } + /** * Is the supplier order delayed? * We suppose a purchase ordered as late if a the purchase order has been sent and the delivery date is set and before the delay. diff --git a/htdocs/fourn/class/fournisseur.facture-rec.class.php b/htdocs/fourn/class/fournisseur.facture-rec.class.php index fea334e43cf..ab68cd3ecc6 100644 --- a/htdocs/fourn/class/fournisseur.facture-rec.class.php +++ b/htdocs/fourn/class/fournisseur.facture-rec.class.php @@ -79,8 +79,19 @@ class FactureFournisseurRec extends CommonInvoice public $suspended; public $libelle; + public $label; + + /** + * @var double $amount + * @deprecated + */ public $amount; + /** + * @var double $remise + * @deprecated + */ public $remise; + public $vat_src_code; public $localtax1; public $localtax2; @@ -168,8 +179,6 @@ class FactureFournisseurRec extends CommonInvoice 'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>40), 'suspended' =>array('type'=>'integer', 'label'=>'Suspended', 'enabled'=>1, 'visible'=>-1, 'position'=>225), 'libelle' =>array('type'=>'varchar(100)', 'label'=>'Libelle', 'enabled'=>1, 'showoncombobox' => 0, 'visible'=>-1, 'position'=>15), - 'amount' =>array('type'=>'double(24,8)', 'label'=>'Amount', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>35), - 'remise' =>array('type'=>'double', 'label'=>'Remise', 'enabled'=>1, 'visible'=>-1, 'position'=>40), 'localtax1' =>array('type'=>'double(24,8)', 'label'=>'Localtax1', 'enabled'=>1, 'visible'=>-1, 'position'=>60, 'isameasure'=>1), 'localtax2' =>array('type'=>'double(24,8)', 'label'=>'Localtax2', 'enabled'=>1, 'visible'=>-1, 'position'=>65, 'isameasure'=>1), @@ -273,8 +282,7 @@ class FactureFournisseurRec extends CommonInvoice $sql .= ', datec'; $sql .= ', suspended'; $sql .= ', libelle'; - $sql .= ', amount'; - $sql .= ', remise'; + $sql .= ', total_ttc'; $sql .= ', fk_user_author'; $sql .= ', fk_projet'; $sql .= ', fk_account'; @@ -305,7 +313,6 @@ class FactureFournisseurRec extends CommonInvoice $sql .= ", ".((int) $this->suspended); $sql .= ", '".$this->db->escape($this->libelle)."'"; $sql .= ", " .(!empty($facfourn_src->total_ttc) ? (float) $facfourn_src->total_ttc : '0'); // amount - $sql .= ", " .(!empty($facfourn_src->remise) ? (float) $facfourn_src->remise : '0'); $sql .= ", " .((int) $user->id); $sql .= ", " .(!empty($this->fk_project) ? ((int) $this->fk_project) : 'NULL'); $sql .= ", " .(!empty($facfourn_src->fk_account) ? ((int) $facfourn_src->fk_account) : 'NULL'); @@ -475,8 +482,6 @@ class FactureFournisseurRec extends CommonInvoice if ($this->fk_soc > 0) $sql .= " fk_soc = ". (int) $this->fk_soc. ','; $sql .= " suspended = ". (!empty($this->suspended) ? ((int) $this->suspended) : 0) . ','; $sql .= " libelle = ". (!empty($this->libelle) ? "'".$this->db->escape($this->libelle)."'" : 'NULL') . ","; - $sql .= " amount = ". (!empty($this->amount) ? ((float) $this->amount) : 0.00) . ','; - $sql .= " remise = ". (!empty($this->remise) ? ((float) $this->remise) : 'NULL') . ','; $sql .= " vat_src_code = ". (!empty($this->vat_src_code) ? "'".$this->db->escape($this->vat_src_code)."'" : 'NULL') . ','; $sql .= " localtax1 = ". (!empty($this->localtax1) ? ((float) $this->localtax1) : 0.00) . ','; $sql .= " localtax2 = ". (!empty($this->localtax2) ? ((float) $this->localtax2) : 0.00) . ','; @@ -548,7 +553,7 @@ class FactureFournisseurRec extends CommonInvoice { $sql = 'SELECT f.rowid, f.titre, f.ref_supplier, f.entity, f.fk_soc'; $sql .= ', f.datec, f.tms, f.suspended'; - $sql .= ', f.libelle, f.amount, f.remise'; + $sql .= ', f.libelle as label'; $sql .= ', f.vat_src_code, f.localtax1, f.localtax2'; $sql .= ', f.total_tva, f.total_ht, f.total_ttc'; $sql .= ', f.fk_user_author, f.fk_user_modif'; @@ -588,9 +593,8 @@ class FactureFournisseurRec extends CommonInvoice $this->date_creation = $obj->datec; $this->date_modification = $obj->tms; $this->suspended = $obj->suspended; - $this->libelle = $obj->libelle; - $this->amount = $obj->amount; - $this->remise = $obj->remise; + $this->libelle = $obj->label; + $this->label = $obj->label; $this->vat_src_code = $obj->vat_src_code; $this->total_localtax1 = $obj->localtax1; $this->total_localtax2 = $obj->localtax2; diff --git a/htdocs/fourn/class/fournisseur.facture.class.php b/htdocs/fourn/class/fournisseur.facture.class.php index 24561e08785..0af7e083aec 100644 --- a/htdocs/fourn/class/fournisseur.facture.class.php +++ b/htdocs/fourn/class/fournisseur.facture.class.php @@ -181,7 +181,15 @@ class FactureFournisseur extends CommonInvoice */ public $date_echeance; + /** + * @var double $amount + * @deprecated + */ public $amount = 0; + /** + * @var double $remise + * @deprecated + */ public $remise = 0; /** @@ -400,11 +408,6 @@ class FactureFournisseur extends CommonInvoice $this->date = $now; } - $socid = $this->socid; - $ref_supplier = $this->ref_supplier; - $amount = $this->amount; - $remise = $this->remise; - // Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate) if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) { list($this->fk_multicurrency, $this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code, $this->date); @@ -452,7 +455,6 @@ class FactureFournisseur extends CommonInvoice $this->total_ttc = $_facrec->total_ttc; // Fields always coming from template - $this->remise = $_facrec->remise; $this->fk_incoterms = $_facrec->fk_incoterms; $this->location_incoterms = $_facrec->location_incoterms; @@ -471,7 +473,6 @@ class FactureFournisseur extends CommonInvoice $this->array_options = $_facrec->array_options; - //if (! $this->remise) $this->remise = 0; if (! $this->mode_reglement_id) { $this->mode_reglement_id = 0; } @@ -541,10 +542,6 @@ class FactureFournisseur extends CommonInvoice $this->date_echeance = $forceduedate; } - if (!$remise) { - $remise = 0; - } - $sql = "INSERT INTO ".MAIN_DB_PREFIX."facture_fourn ("; $sql .= "ref"; $sql .= ", ref_supplier"; @@ -878,8 +875,6 @@ class FactureFournisseur extends CommonInvoice $sql .= " t.tms,"; $sql .= " t.libelle as label,"; $sql .= " t.paye,"; - $sql .= " t.amount,"; - $sql .= " t.remise,"; $sql .= " t.close_code,"; $sql .= " t.close_note,"; $sql .= " t.tva,"; @@ -944,11 +939,8 @@ class FactureFournisseur extends CommonInvoice $this->label = $obj->label; $this->paye = $obj->paye; $this->paid = $obj->paye; - $this->amount = $obj->amount; - $this->remise = $obj->remise; $this->close_code = $obj->close_code; $this->close_note = $obj->close_note; - //$this->tva = $obj->tva; $this->total_localtax1 = $obj->localtax1; $this->total_localtax2 = $obj->localtax2; $this->total_ht = $obj->total_ht; @@ -1173,21 +1165,12 @@ class FactureFournisseur extends CommonInvoice if (isset($this->paye)) { $this->paye = trim($this->paye); } - if (isset($this->amount)) { - $this->amount = trim($this->amount); - } - if (isset($this->remise)) { - $this->remise = trim($this->remise); - } if (isset($this->close_code)) { $this->close_code = trim($this->close_code); } if (isset($this->close_note)) { $this->close_note = trim($this->close_note); } - /*if (isset($this->tva)) { - $this->tva = trim($this->tva); - }*/ if (isset($this->localtax1)) { $this->localtax1 = trim($this->localtax1); } @@ -1221,7 +1204,8 @@ class FactureFournisseur extends CommonInvoice $this->fk_facture_source = trim($this->fk_facture_source); } if (isset($this->fk_project)) { - $this->fk_project = trim($this->fk_project); + if (empty($this->fk_project)) $this->fk_project = null; + else $this->fk_project = intval($this->fk_project); } if (isset($this->cond_reglement_id)) { $this->cond_reglement_id = trim($this->cond_reglement_id); @@ -1258,8 +1242,6 @@ class FactureFournisseur extends CommonInvoice } $sql .= " libelle=".(isset($this->label) ? "'".$this->db->escape($this->label)."'" : "null").","; $sql .= " paye=".(isset($this->paye) ? $this->paye : "null").","; - $sql .= " amount=".(isset($this->amount) ? $this->amount : "null").","; - $sql .= " remise=".(isset($this->remise) ? $this->remise : "null").","; $sql .= " close_code=".(isset($this->close_code) ? "'".$this->db->escape($this->close_code)."'" : "null").","; $sql .= " close_note=".(isset($this->close_note) ? "'".$this->db->escape($this->close_note)."'" : "null").","; //$sql .= " tva=".(isset($this->tva) ? $this->tva : "null").","; @@ -2446,7 +2428,7 @@ class FactureFournisseur extends CommonInvoice $this->db->begin(); - // Libere remise liee a ligne de facture + // Free the discount linked to a line of invoice $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except'; $sql .= ' SET fk_invoice_supplier_line = NULL'; $sql .= ' WHERE fk_invoice_supplier_line = '.((int) $rowid); @@ -2645,7 +2627,7 @@ class FactureFournisseur extends CommonInvoice // phpcs:enable global $conf, $langs; - $sql = 'SELECT ff.rowid, ff.date_lim_reglement as datefin, ff.fk_statut as status'; + $sql = 'SELECT ff.rowid, ff.date_lim_reglement as datefin, ff.fk_statut as status, ff.total_ht, ff.total_ttc'; $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as ff'; if (empty($user->rights->societe->client->voir) && !$user->socid) { $sql .= " JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ff.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id); @@ -3171,6 +3153,23 @@ class FactureFournisseur extends CommonInvoice return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'facture_fourn_det' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } + /** * Is the payment of the supplier invoice having a delay? * diff --git a/htdocs/fourn/class/fournisseur.product.class.php b/htdocs/fourn/class/fournisseur.product.class.php index 396995c4c86..55aabde8141 100644 --- a/htdocs/fourn/class/fournisseur.product.class.php +++ b/htdocs/fourn/class/fournisseur.product.class.php @@ -972,6 +972,23 @@ class ProductFournisseur extends Product return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'product_fournisseur_price' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } + /** * List supplier prices log of a supplier price * diff --git a/htdocs/fourn/commande/card.php b/htdocs/fourn/commande/card.php index b71ba0de941..d895e688080 100644 --- a/htdocs/fourn/commande/card.php +++ b/htdocs/fourn/commande/card.php @@ -1840,11 +1840,13 @@ if ($action == 'create') { $title = $langs->trans('ProductsAndServices'); print load_fiche_titre($title); + print '
'; print ''; $objectsrc->printOriginLinesList('', $selectedLines); print '
'; + print '
'; } print "\n"; } elseif (!empty($object->id)) { diff --git a/htdocs/fourn/facture/card.php b/htdocs/fourn/facture/card.php index f4d628d5882..454577b41b6 100644 --- a/htdocs/fourn/facture/card.php +++ b/htdocs/fourn/facture/card.php @@ -76,7 +76,7 @@ $lineid = GETPOST('lineid', 'int'); $projectid = GETPOST('projectid', 'int'); $origin = GETPOST('origin', 'alpha'); $originid = GETPOST('originid', 'int'); -$fac_rec = GETPOST('fac_rec', 'int'); +$fac_recid = GETPOST('fac_rec', 'int'); // PDF $hidedetails = (GETPOST('hidedetails', 'int') ? GETPOST('hidedetails', 'int') : (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS) ? 1 : 0)); @@ -882,10 +882,8 @@ if (empty($reshook)) { } } } - } - - // Standard invoice or Deposit invoice, created from a Predefined template invoice - if ((GETPOST('type') == FactureFournisseur::TYPE_STANDARD || GETPOST('type') == FactureFournisseur::TYPE_DEPOSIT) && GETPOST('fac_rec', 'int') > 0) { + } elseif ($fac_recid > 0 && (GETPOST('type') == FactureFournisseur::TYPE_STANDARD || GETPOST('type') == FactureFournisseur::TYPE_DEPOSIT)) { + // Standard invoice or Deposit invoice, created from a Predefined template invoice if (empty($dateinvoice)) { $error++; setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors'); @@ -903,7 +901,7 @@ if (empty($reshook)) { $object->date = $dateinvoice; $object->note_public = trim(GETPOST('note_public', 'restricthtml')); $object->note_private = trim(GETPOST('note_private', 'restricthtml')); - $object->ref_client = GETPOST('ref_client'); + $object->ref_supplier = GETPOST('ref_supplier', 'nohtml'); $object->model_pdf = GETPOST('model'); $object->fk_project = GETPOST('projectid', 'int'); $object->cond_reglement_id = (GETPOST('type') == 3 ? 1 : GETPOST('cond_reglement_id')); @@ -918,7 +916,7 @@ if (empty($reshook)) { $object->multicurrency_tx = GETPOST('originmulticurrency_tx', 'int'); // Source facture - $object->fac_rec = GETPOST('fac_rec', 'int'); + $object->fac_rec = $fac_recid; $fac_rec = new FactureFournisseurRec($db); $fac_rec->fetch($object->fac_rec); $fac_rec->fetch_lines(); @@ -926,10 +924,8 @@ if (empty($reshook)) { $id = $object->create($user); // This include recopy of links from recurring invoice and recurring invoice lines } - } - - // Standard invoice or Deposit invoice, not from a Predefined template invoice - if (GETPOST('type') == FactureFournisseur::TYPE_STANDARD || GETPOST('type') == FactureFournisseur::TYPE_DEPOSIT && GETPOST('fac_rec') <= 0) { + } elseif ($fac_recid <= 0 && (GETPOST('type') == FactureFournisseur::TYPE_STANDARD || GETPOST('type') == FactureFournisseur::TYPE_DEPOSIT)) { + // Standard invoice or Deposit invoice, not from a Predefined template invoice if (GETPOST('socid', 'int') < 1) { setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentities('Supplier')), null, 'errors'); $action = 'create'; @@ -2024,15 +2020,15 @@ if ($action == 'create') { $exampletemplateinvoice = new FactureFournisseurRec($db); $invoice_predefined = new FactureFournisseurRec($db); - if (empty($origin) && empty($originid) && GETPOST('fac_rec', 'int') > 0) { - $invoice_predefined->fetch(GETPOST('fac_rec', 'int')); + if (empty($origin) && empty($originid) && $fac_recid > 0) { + $invoice_predefined->fetch($fac_recid); } // Third party print ''.$langs->trans('Supplier').''; print ''; - if ($societe->id > 0 && (!GETPOST('fac_rec', 'int') || !empty($invoice_predefined->frequency))) { + if ($societe->id > 0 && ($fac_recid <= 0 || !empty($invoice_predefined->frequency))) { $absolute_discount = $societe->getAvailableDiscounts('', '', 0, 1); print $societe->getNomUrl(1, 'supplier'); print ''; @@ -2050,15 +2046,15 @@ if ($action == 'create') { }); '; } - if (!GETPOST('fac_rec', 'int')) { + if ($fac_recid <= 0) { print ' '; } } print ''; // Overwrite some values if creation of invoice is from a predefined invoice - if (empty($origin) && empty($originid) && GETPOST('fac_rec', 'int') > 0) { - $invoice_predefined->fetch(GETPOST('fac_rec', 'int')); + if (empty($origin) && empty($originid) && $fac_recid > 0) { + $invoice_predefined->fetch($fac_recid); $dateinvoice = $invoice_predefined->date_when; // To use next gen date by default later if (empty($projectid)) { @@ -2088,15 +2084,15 @@ if ($action == 'create') { if ($num > 0) { print ''.$langs->trans('CreateFromRepeatableInvoice').''; - //print ''; + //print ''; print ''; + //print '
'; } - print '
+ print '
-
'; - - print ' -
'; print '
'; @@ -2418,9 +2414,12 @@ if (preg_match('/^dopayment/', $action)) { // If we choosed/click on the payme // Create a Stripe client. var stripe = Stripe(''); - + var cardButton = document.getElementById('buttontopay'); + var clientSecret = cardButton.dataset.secret; + var options = { clientSecret: clientSecret,}; + // Create an instance of Elements - var elements = stripe.elements(); + var elements = stripe.elements(options); // Custom styling can be passed to options when creating an Element. // (Note that this demo uses a wider set of styles than the guide below.) @@ -2441,49 +2440,28 @@ if (preg_match('/^dopayment/', $action)) { // If we choosed/click on the payme } }; - var cardElement = elements.create('card', {style: style}); + var paymentElement = elements.create("payment"); // Add an instance of the card Element into the `card-element`
- cardElement.mount('#card-element'); - - // Handle real-time validation errors from the card Element. - cardElement.addEventListener('change', function(event) { - var displayError = document.getElementById('card-errors'); - if (event.error) { - console.log("Show event error (like 'Incorrect card number', ...)"); - displayError.textContent = event.error.message; - } else { - console.log("Reset error message"); - displayError.textContent = ''; - } - }); + paymentElement.mount("#payment-element"); // Handle form submission - var cardholderName = document.getElementById('cardholder-name'); var cardButton = document.getElementById('buttontopay'); - var clientSecret = cardButton.dataset.secret; cardButton.addEventListener('click', function(event) { console.log("We click on buttontopay"); event.preventDefault(); - if (cardholderName.value == '') - { - console.log("Field Card holder is empty"); - var displayError = document.getElementById('card-errors'); - displayError.textContent = 'trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("CardOwner"))); ?>'; - } - else - { /* Disable button to pay and show hourglass cursor */ jQuery('#hourglasstopay').show(); jQuery('#buttontopay').hide(); - stripe.handleCardPayment( - clientSecret, cardElement, { + stripe.confirmPayment({ + elements,confirmParams: { + return_url: '', payment_method_data: { billing_details: { - name: cardholderName.value + name: 'test' thirdparty) && !empty($object->thirdparty->email))) { ?>, email: 'thirdparty->email); ?>' @@ -2507,6 +2485,7 @@ if (preg_match('/^dopayment/', $action)) { // If we choosed/click on the payme } else { print 'false'; } ?> /* true when a customer was provided when creating payment intent. true ask to save the card */ + }, } ).then(function(result) { console.log(result); @@ -2527,7 +2506,7 @@ if (preg_match('/^dopayment/', $action)) { // If we choosed/click on the payme jQuery('#payment-form').submit(); } }); - } + }); rights->resource->read) { - accessforbidden(); -} - $object = new Dolresource($db); $hookmanager->initHooks(array('element_resource')); @@ -71,11 +67,22 @@ $cancel = GETPOST('cancel', 'alpha'); $confirm = GETPOST('confirm', 'alpha'); $socid = GETPOST('socid', 'int'); +if (empty($mandatory)) { + $mandatory = 0; +} +if (empty($busy)) { + $busy = 0; +} + if ($socid > 0) { // Special for thirdparty $element_id = $socid; $element = 'societe'; } +if (!$user->rights->resource->read) { + accessforbidden(); +} + // Permission is not permission on resources. We just make link here on objects. if ($element == 'action') { $result = restrictedArea($user, 'agenda', $element_id, 'actioncomm&societe', 'myactions|allactions', 'fk_soc', 'id'); @@ -365,7 +372,7 @@ if (!$ret) { print '
'; - print ''; + print '
'; // Type if (!empty($conf->global->AGENDA_USE_EVENT_TYPE)) { diff --git a/htdocs/societe/card.php b/htdocs/societe/card.php index 45bbefabdab..a8b2fb151c6 100644 --- a/htdocs/societe/card.php +++ b/htdocs/societe/card.php @@ -1180,13 +1180,15 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { document.formsoc.private.value=1; }); + var canHaveCategoryIfNotCustomerProspectSupplier = ' . (empty($conf->global->THIRDPARTY_CAN_HAVE_CATEGORY_EVEN_IF_NOT_CUSTOMER_PROSPECT) ? '0' : '1') . '; + init_customer_categ(); $("#customerprospect").change(function() { init_customer_categ(); }); function init_customer_categ() { console.log("is customer or prospect = "+jQuery("#customerprospect").val()); - if (jQuery("#customerprospect").val() == 0 && (jQuery("#fournisseur").val() == 0 || ' . (empty($conf->global->THIRDPARTY_CAN_HAVE_CATEGORY_EVEN_IF_NOT_CUSTOMER_PROSPECT_SUPPLIER) ? '1' : '0').')) + if (jQuery("#customerprospect").val() == 0 && !canHaveCategoryIfNotCustomerProspectSupplier) { jQuery(".visibleifcustomer").hide(); } @@ -1318,16 +1320,6 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { print ''; print ''; - // Parent company - if (empty($conf->global->SOCIETE_DISABLE_PARENTCOMPANY)) { - print ''; - print ''; - print ''; - } - // Prospect/Customer print ''; print '"; - //} if (!empty($conf->global->THIRDPARTY_SUGGEST_ALSO_ADDRESS_CREATION)) { print ''; + print ''; + print ''; + } + // Assign a sale representative print ''; print ''; @@ -1914,13 +1914,15 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { } }); + var canHaveCategoryIfNotCustomerProspectSupplier = ' . (empty($conf->global->THIRDPARTY_CAN_HAVE_CUSTOMER_CATEGORY_EVEN_IF_NOT_CUSTOMER_PROSPECT) ? '0' : '1') . '; + init_customer_categ(); $("#customerprospect").change(function() { init_customer_categ(); }); function init_customer_categ() { console.log("is customer or prospect = "+jQuery("#customerprospect").val()); - if (jQuery("#customerprospect").val() == 0 && (jQuery("#fournisseur").val() == 0 || '.(empty($conf->global->THIRDPARTY_CAN_HAVE_CATEGORY_EVEN_IF_NOT_CUSTOMER_PROSPECT_SUPPLIER) ? '1' : '0').')) + if (jQuery("#customerprospect").val() == 0 && !canHaveCategoryIfNotCustomerProspectSupplier) { jQuery(".visibleifcustomer").hide(); } @@ -2734,7 +2736,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { // Tags / categories if (!empty($conf->categorie->enabled) && !empty($user->rights->categorie->lire)) { // Customer - if ($object->prospect || $object->client || (!$object->fournisseur && !empty($conf->global->THIRDPARTY_CAN_HAVE_CATEGORY_EVEN_IF_NOT_CUSTOMER_PROSPECT_SUPPLIER))) { + if ($object->prospect || $object->client || !empty($conf->global->THIRDPARTY_CAN_HAVE_CUSTOMER_CATEGORY_EVEN_IF_NOT_CUSTOMER_PROSPECT)) { print ''; print '
'.$langs->trans('ParentCompany').''; - print img_picto('', 'company', 'class="paddingrightonly"'); - print $form->select_thirdparty_list('', 'parent_company_id', '', $langs->trans("ThirdParty")); - print '
'.$form->editfieldkey('ProspectCustomer', 'customerprospect', '', $object, 0, 'string', '', 1).''; @@ -1639,12 +1631,10 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { $langs->load('categories'); // Customer - //if ($object->prospect || $object->client || (! $object->fournisseur && ! empty($conf->global->THIRDPARTY_CAN_HAVE_CATEGORY_EVEN_IF_NOT_CUSTOMER_PROSPECT_SUPPLIER))) { print '
'.$form->editfieldkey('CustomersProspectsCategoriesShort', 'custcats', '', $object, 0).''; $cate_arbo = $form->select_all_categories(Categorie::TYPE_CUSTOMER, null, 'parent', null, null, 1); print img_picto('', 'category', 'class="pictofixedwidth"').$form->multiselectarray('custcats', $cate_arbo, GETPOST('custcats', 'array'), null, null, 'quatrevingtpercent widthcentpercentminusx', 0, 0); print "
'.$form->editfieldkey('ContactCategoriesShort', 'contcats', '', $object, 0).''; @@ -1675,6 +1665,16 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { $parameters = array('socid'=>$socid, 'colspan' => ' colspan="3"', 'colspanvalue' => '3'); include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_add.tpl.php'; + // Parent company + if (empty($conf->global->SOCIETE_DISABLE_PARENTCOMPANY)) { + print '
'.$langs->trans('ParentCompany').''; + print img_picto('', 'company', 'class="paddingrightonly"'); + print $form->select_company(GETPOST('parent_company_id'), 'parent_company_id', '', 'SelectThirdParty', 0, 0, null, 0, 'minwidth300 maxwidth500 widthcentpercentminusxx'); + print '
'.$form->editfieldkey('AllocateCommercial', 'commercial_id', '', $object, 0).'
'.$langs->trans("CustomersCategoriesShort").''; print $form->showCategories($object->id, Categorie::TYPE_CUSTOMER, 1); diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 015a8c92af6..25d2831f853 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -193,8 +193,8 @@ class Societe extends CommonObject 'tva_intra' =>array('type'=>'varchar(20)', 'label'=>'Tva intra', 'enabled'=>1, 'visible'=>-1, 'position'=>210), 'capital' =>array('type'=>'double(24,8)', 'label'=>'Capital', 'enabled'=>1, 'visible'=>-1, 'position'=>215), 'fk_stcomm' =>array('type'=>'integer', 'label'=>'CommercialStatus', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>220), - 'note_private' =>array('type'=>'text', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>225), - 'note_public' =>array('type'=>'text', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>230), + 'note_public' =>array('type'=>'text', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>225), + 'note_private' =>array('type'=>'text', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>230), 'prefix_comm' =>array('type'=>'varchar(5)', 'label'=>'Prefix comm', 'enabled'=>'$conf->global->SOCIETE_USEPREFIX', 'visible'=>-1, 'position'=>235), 'client' =>array('type'=>'tinyint(4)', 'label'=>'Client', 'enabled'=>1, 'visible'=>-1, 'position'=>240), 'fournisseur' =>array('type'=>'tinyint(4)', 'label'=>'Fournisseur', 'enabled'=>1, 'visible'=>-1, 'position'=>245), diff --git a/htdocs/supplier_proposal/card.php b/htdocs/supplier_proposal/card.php index f0594b90b6f..077300f9386 100644 --- a/htdocs/supplier_proposal/card.php +++ b/htdocs/supplier_proposal/card.php @@ -1425,11 +1425,13 @@ if ($action == 'create') { $title = $langs->trans('ProductsAndServices'); print load_fiche_titre($title); + print '
'; print ''; $objectsrc->printOriginLinesList(); print '
'; + print '
'; } } else { /* diff --git a/htdocs/supplier_proposal/class/supplier_proposal.class.php b/htdocs/supplier_proposal/class/supplier_proposal.class.php index 168a0f8d4ee..6fa4c0e5de9 100644 --- a/htdocs/supplier_proposal/class/supplier_proposal.class.php +++ b/htdocs/supplier_proposal/class/supplier_proposal.class.php @@ -2697,6 +2697,23 @@ class SupplierProposal extends CommonObject return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'supplier_proposaldet' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } } diff --git a/htdocs/takepos/index.php b/htdocs/takepos/index.php index 31c51a4c7b1..b23907b64f1 100644 --- a/htdocs/takepos/index.php +++ b/htdocs/takepos/index.php @@ -57,7 +57,7 @@ $action = GETPOST('action', 'aZ09'); $setterminal = GETPOST('setterminal', 'int'); $setcurrency = GETPOST('setcurrency', 'aZ09'); -if ($_SESSION["takeposterminal"] == "") { +if (empty($_SESSION["takeposterminal"])) { if ($conf->global->TAKEPOS_NUM_TERMINALS == "1") { $_SESSION["takeposterminal"] = 1; // Use terminal 1 if there is only 1 terminal } elseif (!empty($_COOKIE["takeposterminal"])) { @@ -114,6 +114,11 @@ $result = restrictedArea($user, 'takepos', 0, ''); $form = new Form($db); +$disablejs = 0; +$disablehead = 0; +$arrayofjs = array(); +$arrayofcss = array(); + // Title $title = 'TakePOS - Dolibarr '.DOL_VERSION; if (!empty($conf->global->MAIN_APPLICATION_TITLE)) { @@ -129,22 +134,22 @@ top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss); global->TAKEPOS_COLOR_THEME == 1) { +if (getDolGlobalInt('TAKEPOS_COLOR_THEME') == 1) { print ''; } ?>