diff --git a/ChangeLog b/ChangeLog index 08d445cdfc7..4d2045839ef 100644 --- a/ChangeLog +++ b/ChangeLog @@ -21,11 +21,12 @@ For developers: --------------- NEW: + + Following changes may create regressions for some external modules, but were necessary to make Dolibarr better: * verifCond('stringtoevaluate') now return false when string contains a bad syntax content instead of true. - - +* The deprecated mdethod thirdparty_doc_create() has been removed. You can use the generateDocument() instead. @@ -36,6 +37,7 @@ For users: NEW: Online proposal signature NEW: Can define some max limit on expense report (per period, per type or expense, ...) +NEW: Provide a special pages for bookmarks and multicompany for a better use of some mobile applications (like DoliDroid) NEW: Allow the use of __NEWREF__ to get for example the new reference a draft order will get after validation. NEW: Add option to disable globaly some notifications emails. NEW: #18401 Add __NEWREF__ subtitute to get new object reference. diff --git a/htdocs/adherents/tpl/linkedobjectblock.tpl.php b/htdocs/adherents/tpl/linkedobjectblock.tpl.php index 3acb14a4cdb..5928b706a8e 100644 --- a/htdocs/adherents/tpl/linkedobjectblock.tpl.php +++ b/htdocs/adherents/tpl/linkedobjectblock.tpl.php @@ -23,7 +23,7 @@ if (empty($conf) || !is_object($conf)) { exit; } -echo "\n"; +echo "\n"; global $user; diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php index a75fc74691f..128518b7dde 100644 --- a/htdocs/admin/dict.php +++ b/htdocs/admin/dict.php @@ -8,7 +8,7 @@ * Copyright (C) 2011 Remy Younes * Copyright (C) 2012-2015 Marcos García * Copyright (C) 2012 Christophe Battarel - * Copyright (C) 2011-2021 Alexandre Spangaro + * Copyright (C) 2011-2022 Alexandre Spangaro * Copyright (C) 2015 Ferran Marcet * Copyright (C) 2016 Raphaël Doursenaud * Copyright (C) 2019-2020 Frédéric France @@ -201,7 +201,7 @@ $tabsql = array(); $tabsql[1] = "SELECT f.rowid as rowid, f.code, f.libelle, c.code as country_code, c.label as country, f.active FROM ".MAIN_DB_PREFIX."c_forme_juridique as f, ".MAIN_DB_PREFIX."c_country as c WHERE f.fk_pays=c.rowid"; $tabsql[2] = "SELECT d.rowid as rowid, d.code_departement as code, d.nom as libelle, d.fk_region as region_id, r.nom as region, c.code as country_code, c.label as country, d.active FROM ".MAIN_DB_PREFIX."c_departements as d, ".MAIN_DB_PREFIX."c_regions as r, ".MAIN_DB_PREFIX."c_country as c WHERE d.fk_region=r.code_region and r.fk_pays=c.rowid and r.active=1 and c.active=1"; $tabsql[3] = "SELECT r.rowid as rowid, r.code_region as state_code, r.nom as libelle, r.fk_pays as country_id, c.code as country_code, c.label as country, r.active FROM ".MAIN_DB_PREFIX."c_regions as r, ".MAIN_DB_PREFIX."c_country as c WHERE r.fk_pays=c.rowid and c.active=1"; -$tabsql[4] = "SELECT c.rowid as rowid, c.code, c.label, c.active, c.favorite FROM ".MAIN_DB_PREFIX."c_country AS c"; +$tabsql[4] = "SELECT c.rowid as rowid, c.code, c.label, c.active, c.favorite, c.eec FROM ".MAIN_DB_PREFIX."c_country AS c"; $tabsql[5] = "SELECT c.rowid as rowid, c.code as code, c.label, c.active FROM ".MAIN_DB_PREFIX."c_civility AS c"; $tabsql[6] = "SELECT a.id as rowid, a.code as code, a.libelle AS libelle, a.type, a.active, a.module, a.color, a.position FROM ".MAIN_DB_PREFIX."c_actioncomm AS a"; $tabsql[7] = "SELECT a.id as rowid, a.code as code, a.libelle AS libelle, a.accountancy_code as accountancy_code, c.code as country_code, c.label as country, a.fk_pays as country_id, a.active FROM ".MAIN_DB_PREFIX."c_chargesociales AS a, ".MAIN_DB_PREFIX."c_country as c WHERE a.fk_pays=c.rowid and c.active=1"; @@ -1096,6 +1096,45 @@ if ($action == 'disable_favorite') { } } +// Is in EEC - Activate +if ($action == 'activate_eec') { + if ($tabrowid[$id]) { + $rowidcol = $tabrowid[$id]; + } else { + $rowidcol = "rowid"; + } + + if ($rowid) { + $sql = "UPDATE ".$tabname[$id]." SET eec = 1 WHERE ".$rowidcol."='".$db->escape($rowid)."'".($entity != '' ? " AND entity = ".(int) $entity : ''); + } elseif ($code) { + $sql = "UPDATE ".$tabname[$id]." SET eec = 1 WHERE code='".dol_escape_htmltag($code)."'".($entity != '' ? " AND entity = ".(int) $entity : ''); + } + + $result = $db->query($sql); + if (!$result) { + dol_print_error($db); + } +} + +// Is in EEC - Disable +if ($action == 'disable_eec') { + if ($tabrowid[$id]) { + $rowidcol = $tabrowid[$id]; + } else { + $rowidcol = "rowid"; + } + + if ($rowid) { + $sql = "UPDATE ".$tabname[$id]." SET eec = 0 WHERE ".$rowidcol."='".$db->escape($rowid)."'".($entity != '' ? " AND entity = ".(int) $entity : ''); + } elseif ($code) { + $sql = "UPDATE ".$tabname[$id]." SET eec = 0 WHERE code='".dol_escape_htmltag($code)."'".($entity != '' ? " AND entity = ".(int) $entity : ''); + } + + $result = $db->query($sql); + if (!$result) { + dol_print_error($db); + } +} /* * View @@ -1459,6 +1498,7 @@ if ($id) { if ($id == 4) { $tdsoffields .= ''; + $tdsoffields .= ''; } $tdsoffields .= ''; $tdsoffields .= ''; @@ -1503,6 +1543,7 @@ if ($id) { if ($id == 4) { print ''; + print ''; } print ''; if ($action != 'edit') { @@ -1576,6 +1617,7 @@ if ($id) { } if ($id == 4) { print ''; + print ''; } print ''; print ''; @@ -1599,10 +1641,10 @@ if ($id) { // Determines the name of the field in relation to the possible names // in data dictionaries - $showfield = 1; // By defaut + $showfield = 1; // By default $cssprefix = ''; $sortable = 1; - $valuetoshow = ucfirst($value); // By defaut + $valuetoshow = ucfirst($value); // By default $valuetoshow = $langs->trans($valuetoshow); // try to translate // Special cases @@ -1805,8 +1847,9 @@ if ($id) { print getTitleFieldOfList($newvaluetoshow, 0, $_SERVER["PHP_SELF"], ($sortable ? $value : ''), ($page ? 'page='.$page.'&' : ''), $param, '', $sortfield, $sortorder, $cssprefix); } } - // Favorite - Only activated on country dictionary + // Favorite & EEC - Only activated on country dictionary if ($id == 4) { + print getTitleFieldOfList($langs->trans("InEEC"), 0, $_SERVER["PHP_SELF"], "eec", ($page ? 'page='.$page.'&' : ''), $param, 'align="center"', $sortfield, $sortorder, '', 0, $langs->trans("CountryIsInEEC")); print getTitleFieldOfList($langs->trans("Favorite"), 0, $_SERVER["PHP_SELF"], "favorite", ($page ? 'page='.$page.'&' : ''), $param, 'align="center"', $sortfield, $sortorder); } @@ -2100,10 +2143,19 @@ if ($id) { } $url .= '&'; - // Favorite + // Favorite & EEC // Only activated on country dictionary if ($id == 4) { print ''; + // Is in EEC + if ($iserasable) { + print ''.$actl[$obj->eec].''; + } else { + print $langs->trans("AlwaysActive"); + } + print ''; + print ''; + // Favorite if ($iserasable) { print ''.$actl[$obj->favorite].''; } else { diff --git a/htdocs/admin/multicurrency.php b/htdocs/admin/multicurrency.php index b622ef192ce..c91af2fcc36 100644 --- a/htdocs/admin/multicurrency.php +++ b/htdocs/admin/multicurrency.php @@ -332,8 +332,8 @@ foreach ($TCurrency as &$currency) { print ''; print '1 '.$conf->currency.' = '; print ' '.$currency->code.' '; - print ' '; - print ''; + print ' '; + print ''; print ''; print ''; } diff --git a/htdocs/admin/ticket.php b/htdocs/admin/ticket.php index c36f6ae1d1b..68f256e2009 100644 --- a/htdocs/admin/ticket.php +++ b/htdocs/admin/ticket.php @@ -203,6 +203,12 @@ if ($action == 'setvarother') { if (!($res > 0)) { $error++; } + + $param_auto_notify_close = GETPOST('TICKET_NOTIFY_AT_CLOSING', 'alpha'); + $res = dolibarr_set_const($db, 'TICKET_NOTIFY_AT_CLOSING', $param_auto_notify_close, 'chaine', 0, '', $conf->entity); + if (!($res > 0)) { + $error++; + } } @@ -530,6 +536,21 @@ print $form->textwithpicto('', $langs->trans("TicketsAutoAssignTicketHelp"), 1, print ''; print ''; +// Auto notify contacts when closing the ticket +print ''.$langs->trans("TicketsAutoNotifyClose").''; +print ''; +if ($conf->use_javascript_ajax) { + print ajax_constantonoff('TICKET_NOTIFY_AT_CLOSING'); +} else { + $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); + print $form->selectarray("TICKET_NOTIFY_AT_CLOSING", $arrval, $conf->global->TICKET_NOTIFY_AT_CLOSING); +} +print ''; +print ''; +print $form->textwithpicto('', $langs->trans("TicketsAutoNotifyCloseHelp"), 1, 'help'); +print ''; +print ''; + if (!$conf->use_javascript_ajax) { print ''; } diff --git a/htdocs/admin/ticket_public.php b/htdocs/admin/ticket_public.php index 818141e5cde..88a7db9b1d7 100644 --- a/htdocs/admin/ticket_public.php +++ b/htdocs/admin/ticket_public.php @@ -327,33 +327,6 @@ if (!empty($conf->global->TICKET_ENABLE_PUBLIC_INTERFACE)) { print $form->textwithpicto('', $langs->trans("TicketPublicInterfaceTextHelpMessageHelpAdmin"), 1, 'help'); print ''; - // Activate email creation to user - print ''.$langs->trans("TicketsDisableCustomerEmail").''; - print ''; - if ($conf->use_javascript_ajax) { - print ajax_constantonoff('TICKET_DISABLE_CUSTOMER_MAILS'); - } else { - $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); - print $form->selectarray("TICKET_DISABLE_CUSTOMER_MAILS", $arrval, $conf->global->TICKET_DISABLE_CUSTOMER_MAILS); - } - print ''; - print ''; - print $form->textwithpicto('', $langs->trans("TicketsDisableEmailHelp"), 1, 'help'); - print ''; - print ''; - - // Texte de création d'un ticket - $mail_mesg_new = $conf->global->TICKET_MESSAGE_MAIL_NEW ? $conf->global->TICKET_MESSAGE_MAIL_NEW : $langs->trans('TicketNewEmailBody'); - print ''.$langs->trans("TicketNewEmailBodyLabel").''; - print ''; - require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; - $doleditor = new DolEditor('TICKET_MESSAGE_MAIL_NEW', $mail_mesg_new, '100%', 120, 'dolibarr_mailings', '', false, true, $conf->global->FCKEDITOR_ENABLE_MAIL, ROWS_2, 70); - $doleditor->Create(); - print ''; - print ''; - print $form->textwithpicto('', $langs->trans("TicketNewEmailBodyHelp"), 1, 'help'); - print ''; - // Url public interface $url_interface = $conf->global->TICKET_URL_PUBLIC_INTERFACE; print ''.$langs->trans("TicketUrlPublicInterfaceLabelAdmin").''; @@ -364,8 +337,45 @@ if (!empty($conf->global->TICKET_ENABLE_PUBLIC_INTERFACE)) { print $form->textwithpicto('', $langs->trans("TicketUrlPublicInterfaceHelpAdmin"), 1, 'help'); print ''; + print ''; + + print '

'; + + print_fiche_titre($langs->trans("Emails")); + + print '
'; + print ''; + + // Activate email creation to user + print ''; + print ''; + print ''; + + // Text of email after creatio of a ticket + $mail_mesg_new = $conf->global->TICKET_MESSAGE_MAIL_NEW ? $conf->global->TICKET_MESSAGE_MAIL_NEW : $langs->trans('TicketNewEmailBody'); + print ''; + print ''; + // Activate email notification when a new message is added - print ''; + print ''; print ''; - print ''; print ''; // Send notification when a new message is added to a email if a user is not assigned to the ticket - print ''; print ''; - print ''; + print ''; print '
'; + print $form->textwithpicto($langs->trans("TicketsDisableCustomerEmail"), $langs->trans("TicketsDisableEmailHelp"), 1, 'help'); + print ''; + if ($conf->use_javascript_ajax) { + print ajax_constantonoff('TICKET_DISABLE_CUSTOMER_MAILS'); + } else { + $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); + print $form->selectarray("TICKET_DISABLE_CUSTOMER_MAILS", $arrval, $conf->global->TICKET_DISABLE_CUSTOMER_MAILS); + } + print '
'; + print $form->textwithpicto($langs->trans("TicketNewEmailBodyLabel"), $langs->trans("TicketNewEmailBodyHelp"), 1, 'help'); + print ''; + print ''; + require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; + $doleditor = new DolEditor('TICKET_MESSAGE_MAIL_NEW', $mail_mesg_new, '100%', 120, 'dolibarr_mailings', '', false, true, $conf->global->FCKEDITOR_ENABLE_MAIL, ROWS_2, 70); + $doleditor->Create(); + print '
'.$langs->trans("TicketsPublicNotificationNewMessage").'
'; + print $form->textwithpicto($langs->trans("TicketsPublicNotificationNewMessage"), $langs->trans("TicketsPublicNotificationNewMessageHelp"), 1, 'help'); + print ''; if ($conf->use_javascript_ajax) { print ajax_constantonoff('TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_ENABLED'); @@ -374,19 +384,15 @@ if (!empty($conf->global->TICKET_ENABLE_PUBLIC_INTERFACE)) { print $form->selectarray("TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_ENABLED", $arrval, $conf->global->TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_ENABLED); } print ''; - print $form->textwithpicto('', $langs->trans("TicketsPublicNotificationNewMessageHelp"), 1, 'help'); - print '
'.$langs->trans("TicketPublicNotificationNewMessageDefaultEmail").''; + print '
'; + print $form->textwithpicto($langs->trans("TicketPublicNotificationNewMessageDefaultEmail"), $langs->trans("TicketPublicNotificationNewMessageDefaultEmailHelp"), 1, 'help'); print ''; print ''; - print $form->textwithpicto('', $langs->trans("TicketPublicNotificationNewMessageDefaultEmailHelp"), 1, 'help'); - print '
'; print '
'; diff --git a/htdocs/api/README.md b/htdocs/api/README.md index 7ab85cc26bb..1af112920ce 100644 --- a/htdocs/api/README.md +++ b/htdocs/api/README.md @@ -41,7 +41,7 @@ https://**yourdolibarr.tld**/mydolibarr/api/index.php/otherservice?DOLAPIKEY=**a Develop an API -------------- -The API uses Lucarast Restler framework. Please check documentation https://www.luracast.com/products/restler and examples http://help.luracast.com/restler/examples/ +The API uses Lucarast Restler framework. Please check documentation https://www.luracast.com/products/restler and examples https://restler3.luracast.com/examples/index.html Github contains also useful information : https://github.com/Luracast/Restler diff --git a/htdocs/asset/tpl/linkedobjectblock.tpl.php b/htdocs/asset/tpl/linkedobjectblock.tpl.php index 59df306c829..aef30995432 100644 --- a/htdocs/asset/tpl/linkedobjectblock.tpl.php +++ b/htdocs/asset/tpl/linkedobjectblock.tpl.php @@ -23,7 +23,7 @@ if (empty($conf) || !is_object($conf)) { exit; } -print "\n"; +print "\n"; global $user; global $noMoreLinkedObjectBlockAfter; diff --git a/htdocs/bom/tpl/linkedobjectblock.tpl.php b/htdocs/bom/tpl/linkedobjectblock.tpl.php index 2737b425c9c..8a98c078bc5 100644 --- a/htdocs/bom/tpl/linkedobjectblock.tpl.php +++ b/htdocs/bom/tpl/linkedobjectblock.tpl.php @@ -24,7 +24,7 @@ if (empty($conf) || !is_object($conf)) { exit; } -print "\n"; +print "\n"; global $user, $db; global $noMoreLinkedObjectBlockAfter; diff --git a/htdocs/comm/action/class/cactioncomm.class.php b/htdocs/comm/action/class/cactioncomm.class.php index 32c2345a657..8dd6b008045 100644 --- a/htdocs/comm/action/class/cactioncomm.class.php +++ b/htdocs/comm/action/class/cactioncomm.class.php @@ -186,35 +186,55 @@ class CActionComm $qualified = 1; - // $obj->type can be system, systemauto, module, moduleauto, xxx, xxxauto + // $obj->type can be 'system', 'systemauto', 'module', 'moduleauto', 'xxx', 'xxxauto' + // Note: type = system... than type of event is added among other standard events. + // type = module... then type of event is grouped into module defined into module = myobject@mymodule. Example: Event organization or external modules + // type = xxx... then type of event is added into list as a new flat value (not grouped). Example: Agefod external module if ($qualified && $onlyautoornot > 0 && preg_match('/^system/', $obj->type) && !preg_match('/^AC_OTH/', $obj->code)) { $qualified = 0; // We discard detailed system events. We keep only the 2 generic lines (AC_OTH and AC_OTH_AUTO) } if ($qualified && !empty($obj->module)) { - if ($obj->module == 'invoice' && empty($conf->facture->enabled) && empty($user->facture->lire)) { - $qualified = 0; + //var_dump($obj->type.' '.$obj->module.' '); var_dump($user->rights->facture->lire); + $qualified = 0; + // Special cases + if ($obj->module == 'invoice' && !empty($conf->facture->enabled) && !empty($user->rights->facture->lire)) { + $qualified = 1; } - if ($obj->module == 'order' && empty($conf->commande->enabled) && empty($user->commande->lire)) { - $qualified = 0; + if ($obj->module == 'order' && !empty($conf->commande->enabled) && empty($user->rights->commande->lire)) { + $qualified = 1; } - if ($obj->module == 'propal' && empty($conf->propal->enabled) && empty($user->propale->lire)) { - $qualified = 0; + if ($obj->module == 'propal' && !empty($conf->propal->enabled) && !empty($user->rights->propale->lire)) { + $qualified = 1; } - if ($obj->module == 'invoice_supplier' && ((!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && empty($user->fournisseur->facture->lire)) || (!empty($conf->supplier_invoice->enabled) && empty($user->supplier_invoice->lire)))) { - $qualified = 0; + if ($obj->module == 'invoice_supplier' && ((!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && !empty($user->rights->fournisseur->facture->lire)) || (!empty($conf->rights->supplier_invoice->enabled) && !empty($user->rights->supplier_invoice->lire)))) { + $qualified = 1; } - if ($obj->module == 'order_supplier' && ((!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && empty($user->fournisseur->commande->lire)) || (empty($conf->supplier_order->enabled) && empty($user->supplier_order->lire)))) { - $qualified = 0; + if ($obj->module == 'order_supplier' && ((!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && !empty($user->rights->fournisseur->commande->lire)) || (empty($conf->rights->supplier_order->enabled) && !empty($user->rights->supplier_order->lire)))) { + $qualified = 1; } - if ($obj->module == 'shipping' && empty($conf->expedition->enabled) && empty($user->expedition->lire)) { - $qualified = 0; + if ($obj->module == 'shipping' && !empty($conf->expedition->enabled) && !empty($user->rights->expedition->lire)) { + $qualified = 1; } - if (preg_match('/@eventorganization/', $obj->module) && empty($conf->eventorganization->enabled) && empty($user->eventorganization->read)) { - $qualified = 0; + // For the generic case with type = 'module...' and module = 'myobject@mymodule' + $regs = array(); + if (preg_match('/^module/', $obj->type)) { + if (preg_match('/^(.+)@(.+)$/', $obj->module, $regs)) { + $tmpobject = $regs[1]; + $tmpmodule = $regs[2]; + //var_dump($user->$tmpmodule); + if ($tmpmodule && isset($conf->$tmpmodule) && !empty($conf->$tmpmodule->enabled) && (!empty($user->rights->$tmpmodule->read) || !empty($user->rights->$tmpmodule->lire) || !empty($user->rights->$tmpmodule->$tmpobject->read) || !empty($user->rights->$tmpmodule->$tmpobject->lire))) { + $qualified = 1; + } + } } - if (!preg_match('/^system/', $obj->type) && isset($conf->{$obj->module}) && empty($conf->{$obj->module}->enabled)) { - $qualified = 0; + // For the case type is not 'system...' neither 'module', we just check module is on + if (! in_array($obj->type, array('system', 'systemauto', 'module', 'moduleauto'))) { + $tmpmodule = $obj->module; + //var_dump($tmpmodule); + if ($tmpmodule && isset($conf->$tmpmodule) && !empty($conf->$tmpmodule->enabled)) { + $qualified = 1; + } } } diff --git a/htdocs/comm/action/index.php b/htdocs/comm/action/index.php index e8060bc314d..4142ff9a958 100644 --- a/htdocs/comm/action/index.php +++ b/htdocs/comm/action/index.php @@ -49,10 +49,11 @@ if (empty($conf->global->AGENDA_EXT_NB)) { } $MAXAGENDA = $conf->global->AGENDA_EXT_NB; -$filter = GETPOST("search_filter", 'alpha', 3) ?GETPOST("search_filter", 'alpha', 3) : GETPOST("filter", 'alpha', 3); -$filtert = GETPOST("search_filtert", "int", 3) ?GETPOST("search_filtert", "int", 3) : GETPOST("filtert", "int", 3); -$usergroup = GETPOST("search_usergroup", "int", 3) ?GETPOST("search_usergroup", "int", 3) : GETPOST("usergroup", "int", 3); -$showbirthday = empty($conf->use_javascript_ajax) ?GETPOST("showbirthday", "int") : 1; +$check_holiday = GETPOST('check_holiday', 'int'); +$filter = GETPOST("search_filter", 'alpha', 3) ? GETPOST("search_filter", 'alpha', 3) : GETPOST("filter", 'alpha', 3); +$filtert = GETPOST("search_filtert", "int", 3) ? GETPOST("search_filtert", "int", 3) : GETPOST("filtert", "int", 3); +$usergroup = GETPOST("search_usergroup", "int", 3) ? GETPOST("search_usergroup", "int", 3) : GETPOST("usergroup", "int", 3); +$showbirthday = empty($conf->use_javascript_ajax) ? GETPOST("showbirthday", "int") : 1; // If not choice done on calendar owner (like on left menu link "Agenda"), we filter on user. if (empty($filtert) && empty($conf->global->AGENDA_ALL_CALENDARS)) { @@ -207,16 +208,16 @@ if (GETPOST("viewperuser", 'alpha') || $mode == 'show_peruser') { } /* -if ($action == 'delete_action' && $user->rights->agenda->delete) { - $event = new ActionComm($db); - $event->fetch($actionid); - $event->fetch_optionals(); - $event->fetch_userassigned(); - $event->oldcopy = clone $event; + if ($action == 'delete_action' && $user->rights->agenda->delete) { + $event = new ActionComm($db); + $event->fetch($actionid); + $event->fetch_optionals(); + $event->fetch_userassigned(); + $event->oldcopy = clone $event; - $result = $event->delete(); -} -*/ + $result = $event->delete(); + } + */ /* @@ -579,10 +580,10 @@ if (!empty($conf->use_javascript_ajax)) { // If javascript on $s .= ''."\n"; // Local calendar - $s .= '
'.$langs->trans("LocalAgenda").'  
'; + $s .= '
'.$langs->trans("LocalAgenda").'  
'; // Holiday calendar - $s .= '
 
'; + $s .= '
 
'; // External calendars if (is_array($showextcals) && count($showextcals) > 0) { @@ -607,13 +608,13 @@ if (!empty($conf->use_javascript_ajax)) { // If javascript on foreach ($showextcals as $val) { $htmlname = md5($val['name']); - if (!empty($val['default'])) { + if (!empty($val['default']) || GETPOST('check_ext'.$htmlname, 'int')) { $default = "checked"; } else { $default = ''; } - $s .= '
 
'; + $s .= '
 
'; } } @@ -848,6 +849,7 @@ if ($resql) { $event->fk_project = $obj->fk_project; $event->socid = $obj->fk_soc; + $event->thirdparty_id = $obj->fk_soc; $event->contact_id = $obj->fk_contact; // Defined date_start_in_calendar and date_end_in_calendar property @@ -890,13 +892,13 @@ if ($resql) { $daykey = dol_mktime(0, 0, 0, $mois, $jour, $annee, 'gmt'); // $mois, $jour, $annee has been set for user tz $daykeyend = dol_mktime(0, 0, 0, $moisend, $jourend, $anneeend, 'gmt'); // $moisend, $jourend, $anneeend has been set for user tz /* - print 'GMT '.$event->date_start_in_calendar.' '.dol_print_date($event->date_start_in_calendar, 'dayhour', 'gmt').'
'; - print 'TZSERVER '.$event->date_start_in_calendar.' '.dol_print_date($event->date_start_in_calendar, 'dayhour', 'tzserver').'
'; - print 'TZUSERREL '.$event->date_start_in_calendar.' '.dol_print_date($event->date_start_in_calendar, 'dayhour', 'tzuserrel').'
'; - print 'GMT '.$event->date_end_in_calendar.' '.dol_print_date($event->date_end_in_calendar, 'dayhour', 'gmt').'
'; - print 'TZSERVER '.$event->date_end_in_calendar.' '.dol_print_date($event->date_end_in_calendar, 'dayhour', 'tzserver').'
'; - print 'TZUSER '.$event->date_end_in_calendar.' '.dol_print_date($event->date_end_in_calendar, 'dayhour', 'tzuserrel').'
'; - */ + print 'GMT '.$event->date_start_in_calendar.' '.dol_print_date($event->date_start_in_calendar, 'dayhour', 'gmt').'
'; + print 'TZSERVER '.$event->date_start_in_calendar.' '.dol_print_date($event->date_start_in_calendar, 'dayhour', 'tzserver').'
'; + print 'TZUSERREL '.$event->date_start_in_calendar.' '.dol_print_date($event->date_start_in_calendar, 'dayhour', 'tzuserrel').'
'; + print 'GMT '.$event->date_end_in_calendar.' '.dol_print_date($event->date_end_in_calendar, 'dayhour', 'gmt').'
'; + print 'TZSERVER '.$event->date_end_in_calendar.' '.dol_print_date($event->date_end_in_calendar, 'dayhour', 'tzserver').'
'; + print 'TZUSER '.$event->date_end_in_calendar.' '.dol_print_date($event->date_end_in_calendar, 'dayhour', 'tzuserrel').'
'; + */ do { //if ($event->id==408) //print 'daykey='.$daykey.' daykeyend='.$daykeyend.' '.dol_print_date($daykey, 'dayhour', 'gmt').' - '.dol_print_date($event->datep, 'dayhour', 'gmt').' '.dol_print_date($event->datef, 'dayhour', 'gmt').'
'; diff --git a/htdocs/comm/propal/tpl/linkedobjectblock.tpl.php b/htdocs/comm/propal/tpl/linkedobjectblock.tpl.php index adc9de9339e..613f06a6feb 100644 --- a/htdocs/comm/propal/tpl/linkedobjectblock.tpl.php +++ b/htdocs/comm/propal/tpl/linkedobjectblock.tpl.php @@ -30,7 +30,7 @@ if (empty($conf) || !is_object($conf)) { } -print "\n"; +print "\n"; global $user; diff --git a/htdocs/commande/card.php b/htdocs/commande/card.php index f7a190c7974..96350de5d8f 100644 --- a/htdocs/commande/card.php +++ b/htdocs/commande/card.php @@ -1415,7 +1415,7 @@ if (empty($reshook)) { include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; // Actions to build doc - $upload_dir = !empty($conf->propal->multidir_output[$object->entity])?$conf->propal->multidir_output[$object->entity]:$conf->propal->dir_output; + $upload_dir = !empty($conf->commande->multidir_output[$object->entity])?$conf->commande->multidir_output[$object->entity]:$conf->commande->dir_output; $permissiontoadd = $usercancreate; include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php'; diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index 43431df50c0..efa40f6c5db 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -3677,9 +3677,10 @@ class Commande extends CommonOrder * @param int $notooltip 1=Disable tooltip * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking * @param int $addlinktonotes Add link to notes + * @param string $target attribute target for link * @return string String with URL */ - public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0) + public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0, $target = '') { global $conf, $langs, $user, $hookmanager; @@ -3748,6 +3749,11 @@ class Commande extends CommonOrder } $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; $linkclose .= ' class="classfortooltip"'; + + $target_value=array('_self', '_blank', '_parent', '_top'); + if (in_array($target, $target_value)) { + $linkclose .= ' target="'.dol_escape_htmltag($target).'"'; + } } $linkstart = '\n"; +print "\n"; global $user; global $noMoreLinkedObjectBlockAfter; diff --git a/htdocs/compta/facture/tpl/linkedobjectblock.tpl.php b/htdocs/compta/facture/tpl/linkedobjectblock.tpl.php index 0b22e31be4b..03b410466f0 100644 --- a/htdocs/compta/facture/tpl/linkedobjectblock.tpl.php +++ b/htdocs/compta/facture/tpl/linkedobjectblock.tpl.php @@ -23,7 +23,7 @@ if (empty($conf) || !is_object($conf)) { exit; } -print "\n"; +print "\n"; global $user; global $noMoreLinkedObjectBlockAfter; diff --git a/htdocs/compta/facture/tpl/linkedobjectblockForRec.tpl.php b/htdocs/compta/facture/tpl/linkedobjectblockForRec.tpl.php index d222dfd21dc..d2ef4657586 100644 --- a/htdocs/compta/facture/tpl/linkedobjectblockForRec.tpl.php +++ b/htdocs/compta/facture/tpl/linkedobjectblockForRec.tpl.php @@ -24,7 +24,7 @@ if (empty($conf) || !is_object($conf)) { } -print "\n"; +print "\n"; global $user; diff --git a/htdocs/compta/paiement/cheque/card.php b/htdocs/compta/paiement/cheque/card.php index 610974e5528..8c859e6e689 100644 --- a/htdocs/compta/paiement/cheque/card.php +++ b/htdocs/compta/paiement/cheque/card.php @@ -41,12 +41,7 @@ $ref = GETPOST('ref', 'alpha'); $action = GETPOST('action', 'aZ09'); $confirm = GETPOST('confirm', 'alpha'); -// Security check -$fieldname = (!empty($ref) ? 'ref' : 'rowid'); -if ($user->socid) { - $socid = $user->socid; -} -$result = restrictedArea($user, 'cheque', $id, 'bordereau_cheque', '', 'fk_user_author', $fieldname); +$object = new RemiseCheque($db); $sortfield = GETPOST('sortfield', 'aZ09comma'); $sortorder = GETPOST('sortorder', 'aZ09comma'); @@ -63,11 +58,22 @@ if (empty($page) || $page == -1) { $limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit; $offset = $limit * $page; -$dir = $conf->bank->dir_output.'/checkdeposits/'; +$upload_dir = $conf->bank->multidir_output[$object->entity ? $object->entity : $conf->entity]."/checkdeposits"; + $filterdate = dol_mktime(0, 0, 0, GETPOST('fdmonth'), GETPOST('fdday'), GETPOST('fdyear')); $filteraccountid = GETPOST('accountid', 'int'); -$object = new RemiseCheque($db); +// Security check +$fieldname = (!empty($ref) ? 'ref' : 'rowid'); +if ($user->socid) { + $socid = $user->socid; +} +$result = restrictedArea($user, 'cheque', $id, 'bordereau_cheque', '', 'fk_user_author', $fieldname); + +$usercanread = $user->rights->banque->cheque; +$usercancreate = $user->rights->banque->cheque; +$usercandelete = $user->rights->banque->cheque; + /* @@ -241,7 +247,9 @@ if ($action == 'builddoc' && $user->rights->banque->cheque) { $langs->load("other"); - $file = $dir.get_exdir($object->ref, 0, 1, 0, $object, 'cheque').GETPOST('file'); + $filetodelete = GETPOST('file', 'alpha'); + $file = $upload_dir.'/'.$filetodelete; + $ret = dol_delete_file($file, 0, 0, 0, $object); if ($ret) { setEventMessages($langs->trans("FileWasRemoved", GETPOST('file')), null, 'mesgs'); @@ -634,6 +642,12 @@ if ($action == 'new') { $i = 1; if ($num > 0) { while ($objp = $db->fetch_object($resql)) { + $paymentstatic->id = $objp->pid; + $paymentstatic->ref = $objp->pref; + + $accountlinestatic->id = $objp->rowid; + $accountlinestatic->ref = $objp->ref; + print ''; print ''.$i.''; print ''.dol_print_date($db->jdate($objp->date), 'day').''; // Operation date @@ -643,8 +657,6 @@ if ($action == 'new') { print ''.price($objp->amount).''; // Link to payment print ''; - $paymentstatic->id = $objp->pid; - $paymentstatic->ref = $objp->pref; if ($paymentstatic->id) { print $paymentstatic->getNomUrl(1); } else { @@ -653,8 +665,6 @@ if ($action == 'new') { print ''; // Link to bank transaction print ''; - $accountlinestatic->id = $objp->rowid; - $accountlinestatic->ref = $objp->ref; if ($accountlinestatic->id > 0) { print $accountlinestatic->getNomUrl(1); } else { @@ -664,10 +674,10 @@ if ($action == 'new') { // Action button print ''; if ($object->statut == 0) { - print 'rowid.'">'.img_delete().''; + print 'rowid.'">'.img_delete().''; } if ($object->statut == 1 && $objp->statut != 2) { - print 'rowid.'">'.img_picto($langs->trans("RejectCheck"), 'disable').''; + print 'rowid.'">'.img_picto($langs->trans("RejectCheck"), 'disable').''; } if ($objp->statut == 2) { print '   '.img_picto($langs->trans('CheckRejected'), 'statut8').''; @@ -723,11 +733,13 @@ print ''; if ($action != 'new') { if ($object->statut == 1) { - $filename = dol_sanitizeFileName($object->ref); - $filedir = $dir.get_exdir($object->ref, 0, 1, 0, $object, 'checkdeposits'); + // Documents + $objref = dol_sanitizeFileName($object->ref); + $filedir = $upload_dir.'/'.$objref; $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id; - - print $formfile->showdocuments('remisecheque', $filename, $filedir, $urlsource, 1, 1); + $genallowed = $usercancreate; + $delallowed = $usercandelete; + print $formfile->showdocuments('remisecheque', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $langs->defaultlang); print '
'; } diff --git a/htdocs/compta/paiement/cheque/class/remisecheque.class.php b/htdocs/compta/paiement/cheque/class/remisecheque.class.php index c66edfc8fe1..6b1053240c8 100644 --- a/htdocs/compta/paiement/cheque/class/remisecheque.class.php +++ b/htdocs/compta/paiement/cheque/class/remisecheque.class.php @@ -615,6 +615,7 @@ class RemiseCheque extends CommonObject // We save charset_output to restore it because write_file can change it if needed for // output format that does not support UTF8. $sav_charseSupprimert_output = $outputlangs->charset_output; + $result = $docmodel->write_file($this, $conf->bank->dir_output.'/checkdeposits', $this->ref, $outputlangs); if ($result > 0) { //$outputlangs->charset_output=$sav_charset_output; diff --git a/htdocs/compta/paiement_vat.php b/htdocs/compta/paiement_vat.php index 916a0bf5498..ce224735927 100644 --- a/htdocs/compta/paiement_vat.php +++ b/htdocs/compta/paiement_vat.php @@ -83,7 +83,7 @@ if ($action == 'add_payment' || ($action == 'confirm_paiement' && $confirm == 'y } } - if ($amounts[key($amounts)] <= 0) { + if (empty($amounts[key($amounts)])) { $error++; setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Amount")), null, 'errors'); $action = 'create'; diff --git a/htdocs/contrat/tpl/linkedobjectblock.tpl.php b/htdocs/contrat/tpl/linkedobjectblock.tpl.php index cdbda7a17b8..5297026d5d3 100644 --- a/htdocs/contrat/tpl/linkedobjectblock.tpl.php +++ b/htdocs/contrat/tpl/linkedobjectblock.tpl.php @@ -23,7 +23,7 @@ if (empty($conf) || !is_object($conf)) { } -print "\n"; +print "\n"; global $user; diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php index af92138c5d5..5a4ec3bf02f 100644 --- a/htdocs/core/actions_massactions.inc.php +++ b/htdocs/core/actions_massactions.inc.php @@ -1579,17 +1579,20 @@ if (!$error && ($massaction == 'approveleave' || ($action == 'approveleave' && $ $nbok = 0; foreach ($toselect as $toselectid) { $result = $objecttmp->fetch($toselectid); - if ($result>0) { - if ($objecttmp->statut == Holiday::STATUS_VALIDATED && $user->id == $objecttmp->fk_validator) { + if ($result > 0) { + if ($objecttmp->statut != Holiday::STATUS_VALIDATED) { + setEventMessages($langs->trans('StatusOfRefMustBe', $objecttmp->ref, $langs->transnoentitiesnoconv('Validated')), null, 'warnings'); + continue; + } + if ($user->id == $objecttmp->fk_validator) { $objecttmp->oldcopy = dol_clone($objecttmp); $objecttmp->date_valid = dol_now(); $objecttmp->fk_user_valid = $user->id; $objecttmp->statut = Holiday::STATUS_APPROVED; - $db->begin(); - $verif = $objecttmp->approve($user); + if ($verif <= 0) { setEventMessages($objecttmp->error, $objecttmp->errors, 'errors'); $error++; @@ -1664,14 +1667,9 @@ if (!$error && ($massaction == 'approveleave' || ($action == 'approveleave' && $ } } } - - if (!$error) { - $db->commit(); - $nbok++; - } else { - $db->rollback(); - $action = ''; - } + } else { + $langs->load("errors"); + setEventMessages($langs->trans('ErrorNotApproverForHoliday', $objecttmp->ref), null, 'errors'); } } else { setEventMessages($objecttmp->error, $objecttmp->errors, 'errors'); @@ -1683,7 +1681,7 @@ if (!$error && ($massaction == 'approveleave' || ($action == 'approveleave' && $ if (!$error) { if ($nbok > 1) { setEventMessages($langs->trans("RecordsApproved", $nbok), null, 'mesgs'); - } else { + } elseif ($nbok == 1) { setEventMessages($langs->trans("RecordAproved"), null, 'mesgs'); } $db->commit(); diff --git a/htdocs/core/class/conf.class.php b/htdocs/core/class/conf.class.php index c7d01cab586..f59441eb8d4 100644 --- a/htdocs/core/class/conf.class.php +++ b/htdocs/core/class/conf.class.php @@ -165,7 +165,7 @@ class Conf /** * Load setup values into conf object (read llx_const) for a specified entity - * Note that this->db->xxx, this->file->xxx and this->multicompany have been already loaded when setValues is called. + * Note that this->db->xxx, this->file->xxx and this->multicompany have been already loaded when setEntityValues is called. * * @param DoliDB $db Database handler * @param int $entity Entity to get diff --git a/htdocs/core/class/dolreceiptprinter.class.php b/htdocs/core/class/dolreceiptprinter.class.php index 7653fd24437..37b8d580d1c 100644 --- a/htdocs/core/class/dolreceiptprinter.class.php +++ b/htdocs/core/class/dolreceiptprinter.class.php @@ -642,14 +642,14 @@ class dolReceiptPrinter extends Printer case 'DOL_PRINT_OBJECT_LINES': foreach ($object->lines as $line) { if ($line->fk_product) { - $spacestoadd = $nbcharactbyline - strlen($line->ref) - strlen($line->qty) - 10 - 1; + $spacestoadd = $nbcharactbyline - strlen($line->ref) - strlen($line->qty) - strlen($line->subprice) - 10 - 1; $spaces = str_repeat(' ', $spacestoadd > 0 ? $spacestoadd : 0); - $this->printer->text($line->ref.$spaces.$line->qty.' '.str_pad(price($line->total_ttc), 10, ' ', STR_PAD_LEFT)."\n"); - $this->printer->text(strip_tags(htmlspecialchars_decode($line->product_label))."\n"); + $this->printer->text($line->ref . $spaces . $line->qty . str_pad(price($line->subprice), 10, ' ', STR_PAD_LEFT) . ' ' . str_pad(price($line->total_ttc), 10, ' ', STR_PAD_LEFT) . "\n"); + $this->printer->text(strip_tags(htmlspecialchars_decode($line->product_label))."\n \n"); } else { - $spacestoadd = $nbcharactbyline - strlen($line->description) - strlen($line->qty) - 10 - 1; + $spacestoadd = $nbcharactbyline - strlen($line->description) - strlen($line->qty) - strlen($line->subprice) - 10 - 1; $spaces = str_repeat(' ', $spacestoadd > 0 ? $spacestoadd : 0); - $this->printer->text($line->description.$spaces.$line->qty.' '.str_pad(price($line->total_ttc), 10, ' ', STR_PAD_LEFT)."\n"); + $this->printer->text($line->description.$spaces.$line->qty.' '.str_pad(price($line->subprice), 10, ' ', STR_PAD_LEFT).' '.str_pad(price($line->total_ttc), 10, ' ', STR_PAD_LEFT)."\n"); } } break; diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 4cb6bbaf48d..6a4995b93ca 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -791,7 +791,7 @@ class Form // Warning: if you set submit button to disabled, post using 'Enter' will no more work if there is no another input submit. So we add a hidden button $ret .= ''; // Hidden button BEFORE so it is the one used when we submit with ENTER. - $ret .= 'use_javascript_ajax) ? '' : ' style="display: none"').' class="button small'.(empty($conf->use_javascript_ajax) ? '' : ' hideobject').' '.$name.' '.$name.'confirmed" value="'.dol_escape_htmltag($langs->trans("Confirm")).'">'; + $ret .= 'use_javascript_ajax) ? '' : ' style="display: none"').' class="button smallpaddingimp'.(empty($conf->use_javascript_ajax) ? '' : ' hideobject').' '.$name.' '.$name.'confirmed" value="'.dol_escape_htmltag($langs->trans("Confirm")).'">'; $ret .= ''; if (!empty($conf->use_javascript_ajax)) { @@ -5177,7 +5177,7 @@ class Form $formconfirm .= ''.$question.''; $formconfirm .= ''; $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly'); - $formconfirm .= ''; + $formconfirm .= ''; $formconfirm .= ''; $formconfirm .= ''."\n"; @@ -5248,6 +5248,7 @@ class Form $out .= ''; $out .= ''; } else { + $out .= ''; if ($selected) { $projet = new Project($this->db); $projet->fetch($selected); @@ -5255,6 +5256,7 @@ class Form } else { $out .= " "; } + $out .= ''; } if (empty($nooutput)) { diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index 217bba55330..56d9ca95842 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -360,8 +360,8 @@ class FormFile * This also set the property $this->numoffiles * * @param string $modulepart Module the files are related to ('propal', 'facture', 'facture_fourn', 'mymodule', 'mymodule:MyObject', 'mymodule_temp', ...) - * @param string $modulesubdir Existing (so sanitized) sub-directory to scan (Example: '0/1/10', 'FA/DD/MM/YY/9999'). Use '' if file is not into subdir of module. - * @param string $filedir Directory to scan + * @param string $modulesubdir Existing (so sanitized) sub-directory to scan (Example: '0/1/10', 'FA/DD/MM/YY/9999'). Use '' if file is not into a subdir of module. + * @param string $filedir Directory to scan (must not end with a /). Example: '/mydolibarrdocuments/facture/FAYYMM-1234' * @param string $urlsource Url of origin page (for return) * @param int|string[] $genallowed Generation is allowed (1/0 or array list of templates) * @param int $delallowed Remove is allowed (1/0) diff --git a/htdocs/core/class/html.formmail.class.php b/htdocs/core/class/html.formmail.class.php index 752f57dfdf9..0c9a1b2531a 100644 --- a/htdocs/core/class/html.formmail.class.php +++ b/htdocs/core/class/html.formmail.class.php @@ -1250,7 +1250,7 @@ class FormMail extends Form * Return templates of email with type = $type_template or type = 'all'. * This search into table c_email_templates. Used by the get_form function. * - * @param DoliDB $db Database handler + * @param DoliDB $dbs Database handler * @param string $type_template Get message for model/type=$type_template, type='all' also included. * @param User $user Get template public or limited to this user * @param Translate $outputlangs Output lang object @@ -1259,7 +1259,7 @@ class FormMail extends Form * @param string $label Label of template * @return ModelMail|integer One instance of ModelMail or -1 if error */ - public function getEMailTemplate($db, $type_template, $user, $outputlangs, $id = 0, $active = 1, $label = '') + public function getEMailTemplate($dbs, $type_template, $user, $outputlangs, $id = 0, $active = 1, $label = '') { global $conf, $langs; @@ -1279,18 +1279,18 @@ class FormMail extends Form } $sql = "SELECT rowid, module, label, type_template, topic, joinfiles, content, content_lines, lang"; - $sql .= " FROM ".$db->prefix().'c_email_templates'; - $sql .= " WHERE (type_template='".$db->escape($type_template)."' OR type_template='all')"; + $sql .= " FROM ".$dbs->prefix().'c_email_templates'; + $sql .= " WHERE (type_template='".$dbs->escape($type_template)."' OR type_template='all')"; $sql .= " AND entity IN (".getEntity('c_email_templates').")"; $sql .= " AND (private = 0 OR fk_user = ".((int) $user->id).")"; // Get all public or private owned if ($active >= 0) { $sql .= " AND active = ".((int) $active); } if ($label) { - $sql .= " AND label = '".$db->escape($label)."'"; + $sql .= " AND label = '".$dbs->escape($label)."'"; } if (!($id > 0) && $languagetosearch) { - $sql .= " AND (lang = '".$db->escape($languagetosearch)."'".($languagetosearchmain ? " OR lang = '".$db->escape($languagetosearchmain)."'" : "")." OR lang IS NULL OR lang = '')"; + $sql .= " AND (lang = '".$dbs->escape($languagetosearch)."'".($languagetosearchmain ? " OR lang = '".$dbs->escape($languagetosearchmain)."'" : "")." OR lang IS NULL OR lang = '')"; } if ($id > 0) { $sql .= " AND rowid=".(int) $id; @@ -1299,22 +1299,22 @@ class FormMail extends Form $sql .= " AND position=0"; } if ($languagetosearch) { - $sql .= $db->order("position,lang,label", "ASC,DESC,ASC"); // We want line with lang set first, then with lang null or '' + $sql .= $dbs->order("position,lang,label", "ASC,DESC,ASC"); // We want line with lang set first, then with lang null or '' } else { - $sql .= $db->order("position,lang,label", "ASC,ASC,ASC"); // If no language provided, we give priority to lang not defined + $sql .= $dbs->order("position,lang,label", "ASC,ASC,ASC"); // If no language provided, we give priority to lang not defined } - //$sql .= $db->plimit(1); + //$sql .= $dbs->plimit(1); //print $sql; - $resql = $db->query($sql); + $resql = $dbs->query($sql); if (!$resql) { - dol_print_error($db); + dol_print_error($dbs); return -1; } // Get first found while (1) { - $obj = $db->fetch_object($resql); + $obj = $dbs->fetch_object($resql); if ($obj) { // If template is for a module, check module is enabled; if not, take next template @@ -1386,7 +1386,8 @@ class FormMail extends Form } } - $db->free($resql); + $dbs->free($resql); + return $ret; } diff --git a/htdocs/core/class/utils.class.php b/htdocs/core/class/utils.class.php index 2fa329406fb..de6a47d2d46 100644 --- a/htdocs/core/class/utils.class.php +++ b/htdocs/core/class/utils.class.php @@ -1,6 +1,7 @@ * Copyright (C) 2021 Regis Houssin + * Copyright (C) 2022 Anthony Berton * * 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 @@ -1176,4 +1177,112 @@ class Utils return 1; } + + /** + * Make a send last backup of database or fil in param + * CAN BE A CRON TASK + * + * @param string $sendto Recipients emails + * @param string $from Sender email + * @param string $subject Topic/Subject of mail + * @param string $message Message + * @param string $filename List of files to attach (full path of filename on file system) + * @param string $filter Filter file send + * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK) + */ + public function sendBackup($sendto = '', $from = '', $subject = '', $message = '', $filename = '', $filter = '') + { + global $conf, $langs; + + $filepath = ''; + $output = ''; + $error = 0; + + if (!empty($from)) { + $from = dol_escape_htmltag($from); + } elseif (!empty($conf->global->MAIN_INFO_SOCIETE_MAIL)) { + $from = dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_MAIL); + } else { + $error++; + } + + if (!empty($sendto)) { + $sendto = dol_escape_htmltag($sendto); + } elseif (!empty($conf->global->MAIN_INFO_SOCIETE_MAIL)) { + $from = dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_MAIL); + } else { + $error++; + } + + if (!empty($subject)) { + $subject = dol_escape_htmltag($subject); + } else { + $subject = dol_escape_htmltag($langs->trans('MakeSendLocalDatabaseDumpShort')); + } + + if (empty($message)) { + $message = dol_escape_htmltag($langs->trans('MakeSendLocalDatabaseDumpShort')); + } + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + if ($filename) { + if (dol_is_file($conf->admin->dir_output.'/backup/'.$filename)) { + $tmpfiles = dol_most_recent_file($conf->admin->dir_output.'/backup', $filename); + } + } else { + $tmpfiles = dol_most_recent_file($conf->admin->dir_output.'/backup', $filter); + } + if ($tmpfiles) { + foreach ($tmpfiles as $key => $val) { + if ($key == 'fullname') { + $filepath = array($val); + $filesize = dol_filesize($val); + } + if ($key == 'type') { + $mimetype = array($val); + } + if ($key == 'relativename') { + $filename = array($val); + } + } + } + + if ($filepath) { + if ($filesize > 100000000) { + $output = 'Sorry, last backup file is too large to be send by email'; + $error++; + } + } else { + $output = 'No backup file found'; + $error++; + } + + if (!$error) { + include_once DOL_DOCUMENT_ROOT . '/core/class/CMailFile.class.php'; + $mailfile = new CMailFile($subject, $sendto, $from, $message, $filepath, $mimetype, $filename, '', '', 0, -1); + if ($mailfile->error) { + $error++; + $output = $mailfile->error; + } + } + + if (!$error) { + $result = $mailfile->sendfile(); + if ($result <= 0) { + $error++; + $output = $mailfile->error; + } + } + + dol_syslog(__METHOD__, LOG_DEBUG); + + $this->error = $error; + $this->output = $output; + + if ($result == true) { + return 0; + } else { + return $result; + } + } } diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index d8595c15bbf..af5671437ae 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -10142,7 +10142,7 @@ function dolGetButtonAction($label, $html = '', $actionType = 'default', $url = $class = 'butAction'; if ($actionType == 'danger' || $actionType == 'delete') { $class = 'butActionDelete'; - if (strpos($url, 'token=') === false) $url .= '&token='.newToken(); + if (!empty($url) && strpos($url, 'token=') === false) $url .= '&token='.newToken(); } $attr = array( @@ -10153,6 +10153,7 @@ function dolGetButtonAction($label, $html = '', $actionType = 'default', $url = if (empty($html)) { $html = $label; + $attr['title'] = ''; // if html not set, leave label on title is redundant } else { $attr['aria-label'] = $label; } @@ -10166,6 +10167,7 @@ function dolGetButtonAction($label, $html = '', $actionType = 'default', $url = $attr['id'] = $id; } + // Override attr if (!empty($params['attr']) && is_array($params['attr'])) { foreach ($params['attr'] as $key => $value) { @@ -10179,6 +10181,11 @@ function dolGetButtonAction($label, $html = '', $actionType = 'default', $url = } } + // automatic add tooltip when title is detected + if (!empty($attr['title']) && !empty($attr['class']) && strpos($attr['class'], 'classfortooltip') === false) { + $attr['class'].= ' classfortooltip'; + } + // Js Confirm button if ($userRight && !empty($params['confirm'])) { if (!is_array($params['confirm'])) { diff --git a/htdocs/core/modules/cheque/modules_chequereceipts.php b/htdocs/core/modules/cheque/modules_chequereceipts.php index dfdf0fbe363..e50a6877848 100644 --- a/htdocs/core/modules/cheque/modules_chequereceipts.php +++ b/htdocs/core/modules/cheque/modules_chequereceipts.php @@ -126,8 +126,7 @@ abstract class ModeleNumRefChequeReceipts } /** - * \class ModeleChequeReceipts - * \brief Classe mere des modeles de + * Class parent for templates of document generation */ abstract class ModeleChequeReceipts extends CommonDocGenerator { diff --git a/htdocs/core/modules/modCron.class.php b/htdocs/core/modules/modCron.class.php index 60d713d5fc4..290eea449f5 100644 --- a/htdocs/core/modules/modCron.class.php +++ b/htdocs/core/modules/modCron.class.php @@ -1,6 +1,7 @@ + * Copyright (C) 2022 Anthony Berton * * 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 @@ -98,7 +99,8 @@ class modCron extends DolibarrModules // Cronjobs $this->cronjobs = array( 0=>array('entity'=>0, 'label'=>'PurgeDeleteTemporaryFilesShort', 'jobtype'=>'method', 'class'=>'core/class/utils.class.php', 'objectname'=>'Utils', 'method'=>'purgeFiles', 'parameters'=>'tempfilesold+logfiles', 'comment'=>'PurgeDeleteTemporaryFiles', 'frequency'=>2, 'unitfrequency'=>3600 * 24 * 7, 'priority'=>50, 'status'=>1, 'test'=>true), - 1=>array('entity'=>0, 'label'=>'MakeLocalDatabaseDumpShort', 'jobtype'=>'method', 'class'=>'core/class/utils.class.php', 'objectname'=>'Utils', 'method'=>'dumpDatabase', 'parameters'=>'none,auto,1,auto,10', 'comment'=>'MakeLocalDatabaseDump', 'frequency'=>1, 'unitfrequency'=>3600 * 24 * 7, 'priority'=>90, 'status'=>0, 'test'=>in_array($this->db->type, array('mysql', 'mysqli'))), + 1=>array('entity'=>0, 'label'=>'MakeLocalDatabaseDumpShort', 'jobtype'=>'method', 'class'=>'core/class/utils.class.php', 'objectname'=>'Utils', 'method'=>'dumpDatabase', 'parameters'=>'none,auto,1,auto,10', 'comment'=>'MakeLocalDatabaseDump', 'frequency'=>1, 'unitfrequency'=>3600 * 24 * 7, 'priority'=>90, 'status'=>0, 'test'=>'in_array($conf->db->type, array(\'mysql\', \'mysqli\'))'), + 2=>array('entity'=>0, 'label'=>'MakeSendLocalDatabaseDumpShort', 'jobtype'=>'method', 'class'=>'core/class/utils.class.php', 'objectname'=>'Utils', 'method'=>'sendDumpDatabase', 'parameters'=>',,,,,sql', 'comment'=>'MakeSendLocalDatabaseDump', 'frequency'=>1, 'unitfrequency'=>604800, 'priority'=>91, 'status'=>0, 'test'=>'!empty($conf->global->MAIN_ALLOW_BACKUP_BY_EMAIL) && in_array($conf->db->type, array(\'mysql\', \'mysqli\'))'), // 1=>array('entity'=>0, 'label'=>'My label', 'jobtype'=>'command', 'command'=>'', 'parameters'=>'', 'comment'=>'Comment', 'frequency'=>1, 'unitfrequency'=>3600*24) ); diff --git a/htdocs/core/modules/modSociete.class.php b/htdocs/core/modules/modSociete.class.php index a733484d043..b81dffc0657 100644 --- a/htdocs/core/modules/modSociete.class.php +++ b/htdocs/core/modules/modSociete.class.php @@ -5,6 +5,7 @@ * Copyright (C) 2004 Benoit Mortier * Copyright (C) 2005-2013 Regis Houssin * Copyright (C) 2012-2014 Juanjo Menent + * Copyright (C) 2022 Ferran Marcet * * 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 @@ -480,7 +481,6 @@ class modSociete extends DolibarrModules 's.fax' => "Fax", 's.url' => "Url", 's.email' => "Email", - 's.skype' => "Skype", 's.fk_effectif' => "Staff", 's.fk_typent' => "ThirdPartyType", "s.fk_forme_juridique" => "JuridicalStatus", @@ -621,7 +621,6 @@ class modSociete extends DolibarrModules 's.fax' => "eg. +34987654321", 's.url' => "e.g. https://www.mybigcompany.com", 's.email' => "e.g. test@mybigcompany.com", - 's.skype' => "Skype name", 's.fk_effectif' => "1/2/3/5: represents one of the five ranges of employees", 's.fk_typent' => 'matches field "id" (1-9 etc.) OR "code" (TE_SMALL etc.) in table "'.MAIN_DB_PREFIX.'c_typent"', 's.fk_forme_juridique' => '1/2/3 etc...matches field "code" in table "'.MAIN_DB_PREFIX.'c_forme_juridique"', @@ -693,7 +692,6 @@ class modSociete extends DolibarrModules 's.phone_mobile' => "PhoneMobile", 's.fax' => "Fax", 's.email' => "Email", - 's.skype' => "Skype", 's.note_private' => "NotePrivate", 's.note_public' => "NotePublic" ); @@ -759,7 +757,6 @@ class modSociete extends DolibarrModules 's.phone_mobile' => "5551144", 's.fax' => "5551155", 's.email' => "johnsmith@email.com", - 's.skype' => "skype username", 's.note_private' => "My private note", 's.note_public' => "My public note" ); diff --git a/htdocs/core/modules/modTicket.class.php b/htdocs/core/modules/modTicket.class.php index 0ae6b00b1c3..86841ce5932 100644 --- a/htdocs/core/modules/modTicket.class.php +++ b/htdocs/core/modules/modTicket.class.php @@ -109,7 +109,8 @@ class modTicket extends DolibarrModules 3 => array('TICKET_ADDON_PDF_ODT_PATH', 'chaine', 'DOL_DATA_ROOT/doctemplates/tickets', 'Ticket templates ODT/ODS directory for templates', 0), 4 => array('TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND', 'chaine', 0, 'Automatically mark ticket as read when created from backend', 0), 5 => array('TICKET_DELAY_BEFORE_FIRST_RESPONSE', 'chaine', '0', 'Maximum wanted elapsed time before a first answer to a ticket (in hours). Display a warning in tickets list if not respected.', 0), - 6 => array('TICKET_DELAY_SINCE_LAST_RESPONSE', 'chaine', '0', 'Maximum wanted elapsed time between two answers on the same ticket (in hours). Display a warning in tickets list if not respected.', 0) + 6 => array('TICKET_DELAY_SINCE_LAST_RESPONSE', 'chaine', '0', 'Maximum wanted elapsed time between two answers on the same ticket (in hours). Display a warning in tickets list if not respected.', 0), + 7 => array('TICKET_NOTIFY_AT_CLOSING', 'chaine', '0', 'Default notify contacts when closing a module', 0), ); diff --git a/htdocs/core/modules/product/modules_product.class.php b/htdocs/core/modules/product/modules_product.class.php index fef12717e3b..4b00cbe132e 100644 --- a/htdocs/core/modules/product/modules_product.class.php +++ b/htdocs/core/modules/product/modules_product.class.php @@ -43,20 +43,18 @@ abstract class ModelePDFProduct extends CommonDocGenerator /** * Return list of active generation modules * - * @param DoliDB $db Database handler + * @param DoliDB $dbs Database handler * @param integer $maxfilenamelength Max length of value to show * @return array List of templates */ - public static function liste_modeles($db, $maxfilenamelength = 0) + public static function liste_modeles($dbs, $maxfilenamelength = 0) { // phpcs:enable - global $conf; - $type = 'product'; $list = array(); include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; - $list = getListOfModels($db, $type, $maxfilenamelength); + $list = getListOfModels($dbs, $type, $maxfilenamelength); return $list; } } @@ -156,22 +154,22 @@ abstract class ModeleProductCode /** * Renvoi la liste des modeles de numérotation * - * @param DoliDB $db Database handler + * @param DoliDB $dbs Database handler * @param integer $maxfilenamelength Max length of value to show * @return array List of numbers */ - public static function liste_modeles($db, $maxfilenamelength = 0) + public static function liste_modeles($dbs, $maxfilenamelength = 0) { // phpcs:enable $list = array(); $sql = ""; - $resql = $db->query($sql); + $resql = $dbs->query($sql); if ($resql) { - $num = $db->num_rows($resql); + $num = $dbs->num_rows($resql); $i = 0; while ($i < $num) { - $row = $db->fetch_row($resql); + $row = $dbs->fetch_row($resql); $list[$row[0]] = $row[1]; $i++; } diff --git a/htdocs/core/modules/societe/modules_societe.class.php b/htdocs/core/modules/societe/modules_societe.class.php index 09f6cb9c29d..e8b0fbe9193 100644 --- a/htdocs/core/modules/societe/modules_societe.class.php +++ b/htdocs/core/modules/societe/modules_societe.class.php @@ -41,20 +41,19 @@ abstract class ModeleThirdPartyDoc extends CommonDocGenerator /** * Return list of active generation modules * - * @param DoliDB $db Database handler + * @param DoliDB $dbs Database handler * @param integer $maxfilenamelength Max length of value to show * @return array List of templates */ - public static function liste_modeles($db, $maxfilenamelength = 0) + public static function liste_modeles($dbs, $maxfilenamelength = 0) { // phpcs:enable - global $conf; $type = 'company'; $list = array(); include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; - $list = getListOfModels($db, $type, $maxfilenamelength); + $list = getListOfModels($dbs, $type, $maxfilenamelength); return $list; } @@ -161,22 +160,22 @@ abstract class ModeleThirdPartyCode /** * Renvoie la liste des modeles de numérotation * - * @param DoliDB $db Database handler + * @param DoliDB $dbs Database handler * @param integer $maxfilenamelength Max length of value to show * @return array|int List of numbers */ - public static function liste_modeles($db, $maxfilenamelength = 0) + public static function liste_modeles($dbs, $maxfilenamelength = 0) { // phpcs:enable $list = array(); $sql = ""; - $resql = $db->query($sql); + $resql = $dbs->query($sql); if ($resql) { - $num = $db->num_rows($resql); + $num = $dbs->num_rows($resql); $i = 0; while ($i < $num) { - $row = $db->fetch_row($resql); + $row = $dbs->fetch_row($resql); $list[$row[0]] = $row[1]; $i++; } @@ -401,26 +400,3 @@ abstract class ModeleAccountancyCode return $langs->trans("NotAvailable"); } } - - -/** - * Create a document onto disk according to template module. - * - * @param DoliDB $db Database handler - * @param Facture $object Object invoice - * @param string $message Message (not used, deprecated) - * @param string $modele Force template to use ('' to not force) - * @param Translate $outputlangs objet lang a utiliser pour traduction - * @param int $hidedetails Hide details of lines - * @param int $hidedesc Hide description - * @param int $hideref Hide ref - * @return int <0 if KO, >0 if OK - * @deprecated Use the new function generateDocument of Objects class - * @see Societe::generateDocument() - */ -function thirdparty_doc_create(DoliDB $db, Societe $object, $message, $modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0) -{ - dol_syslog(__METHOD__." is deprecated", LOG_WARNING); - - return $object->generateDocument($modele, $outputlangs, $hidedetails, $hidedesc, $hideref); -} diff --git a/htdocs/core/tpl/massactions_pre.tpl.php b/htdocs/core/tpl/massactions_pre.tpl.php index b3a40ba3582..de034f652d3 100644 --- a/htdocs/core/tpl/massactions_pre.tpl.php +++ b/htdocs/core/tpl/massactions_pre.tpl.php @@ -212,14 +212,14 @@ if ($massaction == 'presend') { } if ($massaction == 'preenable') { - print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassEnabling"), $langs->trans("ConfirmMassEnablingQuestion", count($toselect)), "enable", null, '', 0, 200, 500, 1); + print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassEnabling"), $langs->trans("ConfirmMassEnablingQuestion", count($toselect)), "enable", null, 'yes', 0, 200, 500, 1); } if ($massaction == 'predisable') { print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassDisabling"), $langs->trans("ConfirmMassDisablingQuestion", count($toselect)), "disable", null, '', 0, 200, 500, 1); } if ($massaction == 'preapproveleave') { - print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassLeaveApproval"), $langs->trans("ConfirmMassLeaveApprovalQuestion", count($toselect)), "approveleave", null, '', 0, 200, 500, 1); + print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassLeaveApproval"), $langs->trans("ConfirmMassLeaveApprovalQuestion", count($toselect)), "approveleave", null, 'yes', 0, 200, 500, 1); } // Allow Pre-Mass-Action hook (eg for confirmation dialog) diff --git a/htdocs/core/triggers/interface_50_modTicket_TicketEmail.class.php b/htdocs/core/triggers/interface_50_modTicket_TicketEmail.class.php index dfd83022393..e13328e0a2a 100644 --- a/htdocs/core/triggers/interface_50_modTicket_TicketEmail.class.php +++ b/htdocs/core/triggers/interface_50_modTicket_TicketEmail.class.php @@ -133,77 +133,28 @@ class InterfaceTicketEmail extends DolibarrTriggers $langs->load('ticket'); + $subject_admin = 'TicketNewEmailSubjectAdmin'; + $body_admin = 'TicketNewEmailBodyAdmin'; + $subject_customer = 'TicketNewEmailSubjectCustomer'; + $body_customer = 'TicketNewEmailBodyCustomer'; + $see_ticket_customer = 'TicketNewEmailBodyInfosTrackUrlCustomer'; + // Send email to notification email if (!empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO) && empty($object->context['disableticketemail'])) { $sendto = empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO) ? '' : $conf->global->TICKET_NOTIFICATION_EMAIL_TO; - if ($sendto) { - // Init to avoid errors - $filepath = array(); - $filename = array(); - $mimetype = array(); - - /* Send email to admin */ - $subject = '['.$conf->global->MAIN_INFO_SOCIETE_NOM.'] '.$langs->transnoentities('TicketNewEmailSubjectAdmin'); - $message_admin = $langs->transnoentities('TicketNewEmailBodyAdmin', $object->track_id).'

'; - $message_admin .= '
  • '.$langs->trans('Title').' : '.$object->subject.'
  • '; - $message_admin .= '
  • '.$langs->trans('Type').' : '.$langs->getLabelFromKey($this->db, 'TicketTypeShort'.$object->type_code, 'c_ticket_type', 'code', 'label', $object->type_code).'
  • '; - $message_admin .= '
  • '.$langs->trans('Category').' : '.$langs->getLabelFromKey($this->db, 'TicketCategoryShort'.$object->category_code, 'c_ticket_category', 'code', 'label', $object->category_code).'
  • '; - $message_admin .= '
  • '.$langs->trans('Severity').' : '.$langs->getLabelFromKey($this->db, 'TicketSeverityShort'.$object->severity_code, 'c_ticket_severity', 'code', 'label', $object->severity_code).'
  • '; - $message_admin .= '
  • '.$langs->trans('From').' : '.($object->email_from ? $object->email_from : ($object->fk_user_create > 0 ? $langs->trans('Internal') : '')).'
  • '; - // Extrafields - $extraFields = new ExtraFields($this->db); - $extraFields->fetch_name_optionals_label($object->table_element); - if (is_array($object->array_options) && count($object->array_options) > 0) { - foreach ($object->array_options as $key => $value) { - $key = substr($key, 8); // remove "options_" - $message_admin .= '
  • '.$langs->trans($extraFields->attributes[$object->element]['label'][$key]).' : '.$extraFields->showOutputField($key, $value, '', $object->table_element).'
  • '; - } - } - $message_admin .= '
'; - - if ($object->fk_soc > 0) { - $object->fetch_thirdparty(); - $message_admin .= '

'.$langs->trans('Company').' : '.$object->thirdparty->name.'

'; - } - - $message = $object->message; - if (!dol_textishtml($message)) { - $message = dol_nl2br($message); - } - $message_admin .= '

'.$langs->trans('Message').' :
'.$message.'

'; - $message_admin .= '

'.$langs->trans('SeeThisTicketIntomanagementInterface').'

'; - - $from = $conf->global->MAIN_INFO_SOCIETE_NOM.'<'.$conf->global->TICKET_NOTIFICATION_EMAIL_FROM.'>'; - $replyto = $from; - - $trackid = 'tic'.$object->id; - - if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) { - $old_MAIN_MAIL_AUTOCOPY_TO = $conf->global->MAIN_MAIL_AUTOCOPY_TO; - $conf->global->MAIN_MAIL_AUTOCOPY_TO = ''; - } - include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php'; - $mailfile = new CMailFile($subject, $sendto, $from, $message_admin, $filepath, $mimetype, $filename, '', '', 0, -1, '', '', $trackid, '', 'ticket'); - if ($mailfile->error) { - dol_syslog($mailfile->error, LOG_DEBUG); - } else { - $result = $mailfile->sendfile(); - } - if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) { - $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO; - } + $this->composeAndSendAdminMessage($sendto, $subject_admin, $body_admin, $object, $langs); } } // Send email to customer - if (empty($conf->global->TICKET_DISABLE_CUSTOMER_MAILS) && empty($object->context['disableticketemail']) && $object->notify_tiers_at_create) { $sendto = ''; //if contact selected send to email's contact else send to email's thirdparty $contactid = GETPOST('contactid', 'alpha'); + $res = 0; if (!empty($contactid)) { $contact = new Contact($this->db); @@ -218,77 +169,7 @@ class InterfaceTicketEmail extends DolibarrTriggers } if ($sendto) { - // Init to avoid errors - $filepath = array(); - $filename = array(); - $mimetype = array(); - - $subject = '['.$conf->global->MAIN_INFO_SOCIETE_NOM.'] '.$langs->transnoentities('TicketNewEmailSubjectCustomer'); - $message_customer = $langs->transnoentities('TicketNewEmailBodyCustomer', $object->track_id).'

'; - $message_customer .= '
  • '.$langs->trans('Title').' : '.$object->subject.'
  • '; - $message_customer .= '
  • '.$langs->trans('Type').' : '.$langs->getLabelFromKey($this->db, 'TicketTypeShort'.$object->type_code, 'c_ticket_type', 'code', 'label', $object->type_code).'
  • '; - $message_customer .= '
  • '.$langs->trans('Category').' : '.$langs->getLabelFromKey($this->db, 'TicketCategoryShort'.$object->category_code, 'c_ticket_category', 'code', 'label', $object->category_code).'
  • '; - $message_customer .= '
  • '.$langs->trans('Severity').' : '.$langs->getLabelFromKey($this->db, 'TicketSeverityShort'.$object->severity_code, 'c_ticket_severity', 'code', 'label', $object->severity_code).'
  • '; - - // Extrafields - foreach ($this->attributes[$object->table_element]['label'] as $key => $value) { - $enabled = 1; - if ($enabled && isset($this->attributes[$object->table_element]['list'][$key])) { - $enabled = dol_eval($this->attributes[$object->table_element]['list'][$key], 1); - } - $perms = 1; - if ($perms && isset($this->attributes[$object->table_element]['perms'][$key])) { - $perms = dol_eval($this->attributes[$object->table_element]['perms'][$key], 1); - } - - $qualified = true; - if (empty($enabled)) { - $qualified = false; - } - if (empty($perms)) { - $qualified = false; - } - - if ($qualified) { - $message_customer .= '
  • '.$langs->trans($key).' : '.$value.'
  • '; - } - } - - $message_customer .= '
'; - - $message = $object->message; - if (!dol_textishtml($message)) { - $message = dol_nl2br($message); - } - $message_customer .= '

'.$langs->trans('Message').' :
'.$message.'

'; - $url_public_ticket = ($conf->global->TICKET_URL_PUBLIC_INTERFACE ? $conf->global->TICKET_URL_PUBLIC_INTERFACE.'/' : dol_buildpath('/public/ticket/view.php', 2)).'?track_id='.$object->track_id; - $message_customer .= '

'.$langs->trans('TicketNewEmailBodyInfosTrackUrlCustomer').' : '.$url_public_ticket.'

'; - $message_customer .= '

'.$langs->trans('TicketEmailPleaseDoNotReplyToThisEmail').'

'; - - $from = (empty($conf->global->MAIN_INFO_SOCIETE_NOM) ? '' : $conf->global->MAIN_INFO_SOCIETE_NOM.' ').'<'.$conf->global->TICKET_NOTIFICATION_EMAIL_FROM.'>'; - $replyto = $from; - - $trackid = 'tic'.$object->id; - - if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) { - $old_MAIN_MAIL_AUTOCOPY_TO = $conf->global->MAIN_MAIL_AUTOCOPY_TO; - $conf->global->MAIN_MAIL_AUTOCOPY_TO = ''; - } - include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php'; - $mailfile = new CMailFile($subject, $sendto, $from, $message_customer, $filepath, $mimetype, $filename, '', '', 0, -1, '', '', $trackid, '', 'ticket'); - if ($mailfile->error) { - dol_syslog($mailfile->error, LOG_DEBUG); - } else { - $result = $mailfile->sendfile(); - if ($result) { - // update last_msg_sent date - $object->date_last_msg_sent = dol_now(); - $object->update($user); - } - } - if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) { - $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO; - } + $this->composeAndSendCustomerMessage($sendto, $subject_customer, $body_customer, $see_ticket_customer, $object, $langs, $conf); } } @@ -305,10 +186,226 @@ class InterfaceTicketEmail extends DolibarrTriggers case 'TICKET_CLOSE': dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id); + $langs->load('ticket'); + + $subject_admin = 'TicketCloseEmailSubjectAdmin'; + $body_admin = 'TicketCloseEmailBodyAdmin'; + $subject_customer = 'TicketCloseEmailSubjectCustomer'; + $body_customer = 'TicketCloseEmailBodyCustomer'; + $see_ticket_customer = 'TicketCloseEmailBodyInfosTrackUrlCustomer'; + + // Send email to notification email + if (!empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO) && empty($object->context['disableticketemail'])) { + $sendto = empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO) ? '' : $conf->global->TICKET_NOTIFICATION_EMAIL_TO; + if ($sendto) { + $this->composeAndSendAdminMessage($sendto, $subject_admin, $body_admin, $object, $langs); + } + } + + // Send email to customer. + if (empty($conf->global->TICKET_DISABLE_CUSTOMER_MAILS) && empty($object->context['disableticketemail'])) { + $linked_contacts = $object->listeContact(-1, 'thirdparty'); + $linked_contacts = array_merge($linked_contacts, $object->listeContact(-1, 'internal')); + if (empty($linked_contacts) && !empty($conf->global->TICKET_NOTIFY_AT_CLOSING) && !empty($object->fk_soc)) { + $object->fetch_thirdparty(); + $linked_contacts[] = $object->thirdparty->email; + } + + $contactid = GETPOST('contactid', 'int'); + $res = 0; + + if ($contactid > 0) { + $contact = new Contact($this->db); + $res = $contact->fetch($contactid); + if (! in_array($contact, $linked_contacts)) { + $error_msg = $langs->trans('Error'). ': '; + $error_msg .= $langs->transnoentities('TicketWrongContact'); + setEventMessages($error_msg, [], 'errors'); + $ok = 0; + break; + } + } + + $sendto = ''; + if ($res > 0 && !empty($contact->email) && !empty($contact->statut)) { + $sendto = $contact->email; + } elseif ( !empty($linked_contacts) && ($contactid == -2 || (GETPOST('massaction', 'alpha') == 'close' && GETPOST('confirm', 'alpha') == 'yes'))) { + // if sending to all contacts or sending to contacts while mass closing + $temp_emails = []; + foreach ($linked_contacts as $contact) { + $temp_emails[] = $contact['email']; + } + $sendto = implode(", ", $temp_emails); + unset($temp_emails); + unset($linked_contacts); + } + if ($sendto) { + $this->composeAndSendCustomerMessage($sendto, $subject_customer, $body_customer, $see_ticket_customer, $object, $langs, $conf); + } + } + $ok = 1; break; } - return $ok; } + + /** + * Composes and sends a message concerning a ticket, to be sent to admin address. + * + * @param string $sendto Addresses to send the mail, format "first@address.net, second@address.net," etc. + * @param string $base_subject email subject. Non-translated string. + * @param string $body email body (first line). Non-translated string. + * @param Ticket $object the ticket thet the email refers to + * @param Translate $langs the translation object + * @return void + */ + private function composeAndSendAdminMessage($sendto, $base_subject, $body, Ticket $object, Translate $langs) + { + global $conf; + + // Init to avoid errors + $filepath = array(); + $filename = array(); + $mimetype = array(); + + /* Send email to admin */ + $subject = '['.$conf->global->MAIN_INFO_SOCIETE_NOM.'] '.$langs->transnoentities($base_subject, $object->ref, $object->track_id); + $message_admin = $langs->transnoentities($body, $object->track_id).'
'; + $message_admin .= '
  • '.$langs->trans('Title').' : '.$object->subject.'
  • '; + $message_admin .= '
  • '.$langs->trans('Type').' : '.$langs->getLabelFromKey($this->db, 'TicketTypeShort'.$object->type_code, 'c_ticket_type', 'code', 'label', $object->type_code).'
  • '; + $message_admin .= '
  • '.$langs->trans('Category').' : '.$langs->getLabelFromKey($this->db, 'TicketCategoryShort'.$object->category_code, 'c_ticket_category', 'code', 'label', $object->category_code).'
  • '; + $message_admin .= '
  • '.$langs->trans('Severity').' : '.$langs->getLabelFromKey($this->db, 'TicketSeverityShort'.$object->severity_code, 'c_ticket_severity', 'code', 'label', $object->severity_code).'
  • '; + $message_admin .= '
  • '.$langs->trans('From').' : '.($object->email_from ? $object->email_from : ($object->fk_user_create > 0 ? $langs->trans('Internal') : '')).'
  • '; + // Extrafields + $extraFields = new ExtraFields($this->db); + $extraFields->fetch_name_optionals_label($object->table_element); + if (is_array($object->array_options) && count($object->array_options) > 0) { + foreach ($object->array_options as $key => $value) { + $key = substr($key, 8); // remove "options_" + $message_admin .= '
  • '.$langs->trans($extraFields->attributes[$object->element]['label'][$key]).' : '.$extraFields->showOutputField($key, $value, '', $object->table_element).'
  • '; + } + } + if ($object->fk_soc > 0) { + $object->fetch_thirdparty(); + $message_admin .= '
  • '.$langs->trans('Company').' : '.$object->thirdparty->name.'
  • '; + } + $message_admin .= '
'; + + $message = $object->message; + if (!dol_textishtml($message)) { + $message = dol_nl2br($message); + } + $message_admin .= '

'.$langs->trans('Message').' :

'.$message.'


'; + $message_admin .= '

'.$langs->trans('SeeThisTicketIntomanagementInterface').'

'; + + $from = $conf->global->MAIN_INFO_SOCIETE_NOM.'<'.$conf->global->TICKET_NOTIFICATION_EMAIL_FROM.'>'; + + $trackid = 'tic'.$object->id; + + if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) { + $old_MAIN_MAIL_AUTOCOPY_TO = $conf->global->MAIN_MAIL_AUTOCOPY_TO; + $conf->global->MAIN_MAIL_AUTOCOPY_TO = ''; + } + include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php'; + $mailfile = new CMailFile($subject, $sendto, $from, $message_admin, $filepath, $mimetype, $filename, '', '', 0, -1, '', '', $trackid, '', 'ticket'); + if ($mailfile->error) { + dol_syslog($mailfile->error, LOG_DEBUG); + } else { + $result = $mailfile->sendfile(); + } + if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) { + $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO; + } + } + + /** + * Composes and sends a message concerning a ticket, to be sent to customer addresses. + * + * @param string $sendto Addresses to send the mail, format "first@address.net, second@address.net, " etc. + * @param string $base_subject email subject. Non-translated string. + * @param string $body email body (first line). Non-translated string. + * @param string $see_ticket string indicating the ticket public address + * @param Ticket $object the ticket thet the email refers to + * @param Translate $langs the translation object + * @return void + */ + private function composeAndSendCustomerMessage($sendto, $base_subject, $body, $see_ticket, Ticket $object, Translate $langs) + { + global $conf, $user; + + // Init to avoid errors + $filepath = array(); + $filename = array(); + $mimetype = array(); + + $subject = '['.$conf->global->MAIN_INFO_SOCIETE_NOM.'] '.$langs->transnoentities($base_subject); + $message_customer = $langs->transnoentities($body, $object->track_id).'
'; + $message_customer .= '
  • '.$langs->trans('Title').' : '.$object->subject.'
  • '; + $message_customer .= '
  • '.$langs->trans('Type').' : '.$langs->getLabelFromKey($this->db, 'TicketTypeShort'.$object->type_code, 'c_ticket_type', 'code', 'label', $object->type_code).'
  • '; + $message_customer .= '
  • '.$langs->trans('Category').' : '.$langs->getLabelFromKey($this->db, 'TicketCategoryShort'.$object->category_code, 'c_ticket_category', 'code', 'label', $object->category_code).'
  • '; + $message_customer .= '
  • '.$langs->trans('Severity').' : '.$langs->getLabelFromKey($this->db, 'TicketSeverityShort'.$object->severity_code, 'c_ticket_severity', 'code', 'label', $object->severity_code).'
  • '; + + // Extrafields + if (is_array($this->attributes[$object->table_element]['label'])) { + foreach ($this->attributes[$object->table_element]['label'] as $key => $value) { + $enabled = 1; + if ($enabled && isset($this->attributes[$object->table_element]['list'][$key])) { + $enabled = dol_eval($this->attributes[$object->table_element]['list'][$key], 1); + } + $perms = 1; + if ($perms && isset($this->attributes[$object->table_element]['perms'][$key])) { + $perms = dol_eval($this->attributes[$object->table_element]['perms'][$key], 1); + } + + $qualified = true; + if (empty($enabled)) { + $qualified = false; + } + if (empty($perms)) { + $qualified = false; + } + + if ($qualified) { + $message_customer .= '
  • ' . $langs->trans($key) . ' : ' . $value . '
  • '; + } + } + } + + $message_customer .= '
'; + + $message = $object->message; + if (!dol_textishtml($message)) { + $message = dol_nl2br($message); + } + $message_customer .= '

'.$langs->trans('Message').' :

'.$message.'


'; + $url_public_ticket = ($conf->global->TICKET_URL_PUBLIC_INTERFACE ? $conf->global->TICKET_URL_PUBLIC_INTERFACE.'/' : dol_buildpath('/public/ticket/view.php', 2)).'?track_id='.$object->track_id; + $message_customer .= '

'.$langs->trans($see_ticket).' : '.$url_public_ticket.'

'; + $message_customer .= '

'.$langs->trans('TicketEmailPleaseDoNotReplyToThisEmail').'

'; + + $from = (empty($conf->global->MAIN_INFO_SOCIETE_NOM) ? '' : $conf->global->MAIN_INFO_SOCIETE_NOM.' ').'<'.$conf->global->TICKET_NOTIFICATION_EMAIL_FROM.'>'; + + $trackid = 'tic'.$object->id; + + if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) { + $old_MAIN_MAIL_AUTOCOPY_TO = $conf->global->MAIN_MAIL_AUTOCOPY_TO; + $conf->global->MAIN_MAIL_AUTOCOPY_TO = ''; + } + include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php'; + $mailfile = new CMailFile($subject, $sendto, $from, $message_customer, $filepath, $mimetype, $filename, '', '', 0, -1, '', '', $trackid, '', 'ticket'); + if ($mailfile->error) { + dol_syslog($mailfile->error, LOG_DEBUG); + } else { + $result = $mailfile->sendfile(); + if ($result) { + // update last_msg_sent date + $object->fetch($object->id); + $object->date_last_msg_sent = dol_now(); + $object->update($user); + } + } + if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) { + $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO; + } + } } diff --git a/htdocs/cron/list.php b/htdocs/cron/list.php index fc208fd9ac3..7ee64ec2c6f 100644 --- a/htdocs/cron/list.php +++ b/htdocs/cron/list.php @@ -478,8 +478,12 @@ if ($num > 0) { if (empty($obj)) { break; } - if (isset($obj->test) && !verifCond($obj->test)) { - continue; // Discard line with test = false + + if (isset($obj->test)) { + $veriftest = verifCond($obj->test); + if (!$veriftest) { + continue; // Discard line with test = false + } } $object->id = $obj->rowid; diff --git a/htdocs/don/tpl/linkedobjectblock.tpl.php b/htdocs/don/tpl/linkedobjectblock.tpl.php index 4097e73d560..5d564d43f7a 100644 --- a/htdocs/don/tpl/linkedobjectblock.tpl.php +++ b/htdocs/don/tpl/linkedobjectblock.tpl.php @@ -19,7 +19,7 @@ * */ -print "\n"; +print "\n"; global $user; global $noMoreLinkedObjectBlockAfter; diff --git a/htdocs/ecm/class/ecmfiles.class.php b/htdocs/ecm/class/ecmfiles.class.php index 2f9bf4c41e5..3c5ef15875f 100644 --- a/htdocs/ecm/class/ecmfiles.class.php +++ b/htdocs/ecm/class/ecmfiles.class.php @@ -327,7 +327,11 @@ class EcmFiles extends CommonObject $resql = $this->db->query($sql); if (!$resql) { $error++; - $this->errors[] = 'Error '.$this->db->lasterror(); + if ($this->db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') { + $this->errors[] = 'Error DB_ERROR_RECORD_ALREADY_EXISTS : '.$this->db->lasterror(); + } else { + $this->errors[] = 'Error '.$this->db->lasterror(); + } dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR); } diff --git a/htdocs/eventorganization/tpl/linkedobjectblock.tpl.php b/htdocs/eventorganization/tpl/linkedobjectblock.tpl.php index 9f761c24bc6..127ea95a424 100644 --- a/htdocs/eventorganization/tpl/linkedobjectblock.tpl.php +++ b/htdocs/eventorganization/tpl/linkedobjectblock.tpl.php @@ -23,7 +23,7 @@ if (empty($conf) || !is_object($conf)) { exit; } -echo "\n"; +echo "\n"; global $user; diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php index 00693469948..163761c1f6f 100644 --- a/htdocs/expedition/card.php +++ b/htdocs/expedition/card.php @@ -1208,6 +1208,7 @@ if ($action == 'create') { print ''; } else { if (! empty($conf->global->SHIPMENT_GETS_ALL_ORDER_PRODUCTS)) { + print ''; print ''; } diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index 8490fa67753..b4bcea985cc 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -367,13 +367,15 @@ class Expedition extends CommonObject // Insert of lines $num = count($this->lines); for ($i = 0; $i < $num; $i++) { - if (!isset($this->lines[$i]->detail_batch)) { // no batch management - if ($this->create_line($this->lines[$i]->entrepot_id, $this->lines[$i]->origin_line_id, $this->lines[$i]->qty, $this->lines[$i]->rang, $this->lines[$i]->array_options) <= 0) { - $error++; - } - } else { // with batch management - if ($this->create_line_batch($this->lines[$i], $this->lines[$i]->array_options) <= 0) { - $error++; + if (empty($this->lines[$i]->product_type) || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) { + if (!isset($this->lines[$i]->detail_batch)) { // no batch management + if ($this->create_line($this->lines[$i]->entrepot_id, $this->lines[$i]->origin_line_id, $this->lines[$i]->qty, $this->lines[$i]->rang, $this->lines[$i]->array_options) <= 0) { + $error++; + } + } else { // with batch management + if ($this->create_line_batch($this->lines[$i], $this->lines[$i]->array_options) <= 0) { + $error++; + } } } } @@ -913,6 +915,7 @@ class Expedition extends CommonObject // Copy the rang of the order line to the expedition line $line->rang = $orderline->rang; + $line->product_type = $orderline->product_type; if (!empty($conf->stock->enabled) && !empty($orderline->fk_product)) { $fk_product = $orderline->fk_product; @@ -965,6 +968,8 @@ class Expedition extends CommonObject } $this->lines[$num] = $line; + + return 1; } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps @@ -2611,6 +2616,12 @@ class ExpeditionLigne extends CommonObjectLine */ public $product_desc; + /** + * Type of the product. 0 for product, 1 for service + * @var int + */ + public $product_type = 0; + /** * @var int rang of line */ diff --git a/htdocs/expedition/tpl/linkedobjectblock.tpl.php b/htdocs/expedition/tpl/linkedobjectblock.tpl.php index 26e4ebbb47d..2305b0d4fac 100644 --- a/htdocs/expedition/tpl/linkedobjectblock.tpl.php +++ b/htdocs/expedition/tpl/linkedobjectblock.tpl.php @@ -23,7 +23,7 @@ if (empty($conf) || !is_object($conf)) { } -print "\n"; +print "\n"; global $user; diff --git a/htdocs/expensereport/tpl/linkedobjectblock.tpl.php b/htdocs/expensereport/tpl/linkedobjectblock.tpl.php index 6a36b62f924..f97099e57dc 100644 --- a/htdocs/expensereport/tpl/linkedobjectblock.tpl.php +++ b/htdocs/expensereport/tpl/linkedobjectblock.tpl.php @@ -24,7 +24,7 @@ if (empty($conf) || !is_object($conf)) { } -print "\n"; +print "\n"; global $user; diff --git a/htdocs/fichinter/tpl/linkedobjectblock.tpl.php b/htdocs/fichinter/tpl/linkedobjectblock.tpl.php index e5903ee5863..8da01bb4f8f 100644 --- a/htdocs/fichinter/tpl/linkedobjectblock.tpl.php +++ b/htdocs/fichinter/tpl/linkedobjectblock.tpl.php @@ -22,7 +22,7 @@ if (empty($conf) || !is_object($conf)) { } -print "\n"; +print "\n"; global $user; diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 8a0e0de299e..d67516cb0dd 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -477,15 +477,15 @@ class CommandeFournisseur extends CommonOrder $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as l"; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid'; if (!empty($conf->global->PRODUCT_USE_SUPPLIER_PACKAGING)) { - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON pfp.entity IN (".getEntity('product_fournisseur_price').") AND l.fk_product = pfp.fk_product and l.ref = pfp.ref_fourn AND pfp.fk_soc = ".((int) $this->socid); + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON pfp.entity IN (".getEntity('product_fournisseur_price').") AND l.fk_product = pfp.fk_product and l.ref = pfp.ref_fourn AND l.qty >= pfp.quantity AND pfp.fk_soc = ".((int) $this->socid); } $sql .= " WHERE l.fk_commande = ".((int) $this->id); if ($only_product) { $sql .= ' AND p.fk_product_type = 0'; } if (!empty($conf->global->PRODUCT_USE_SUPPLIER_PACKAGING)) { - $sql.= " AND l.qty >= pfp.quantity "; - $sql.= " GROUP BY l.rowid HAVING max_qty = MAX(pfp.quantity) "; + $sql.= " GROUP BY l.rowid"; + $sql.= " HAVING (max_qty = MAX(pfp.quantity) OR max_qty IS NULL)"; } $sql .= " ORDER BY l.rang, l.rowid"; //print $sql; @@ -3552,11 +3552,11 @@ class CommandeFournisseurLigne extends CommonOrderLine $sql .= ' FROM '.MAIN_DB_PREFIX.'commande_fournisseurdet as cd'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON cd.fk_product = p.rowid'; if (!empty($conf->global->PRODUCT_USE_SUPPLIER_PACKAGING)) { - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON pfp.entity IN (".getEntity('product_fournisseur_price').") AND cd.fk_product = pfp.fk_product and cd.ref = pfp.ref_fourn"; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON pfp.entity IN (".getEntity('product_fournisseur_price').") AND cd.fk_product = pfp.fk_product and cd.ref = pfp.ref_fourn AND cd.qty >= pfp.quantity"; } $sql .= ' WHERE cd.rowid = '.((int) $rowid); if (!empty($conf->global->PRODUCT_USE_SUPPLIER_PACKAGING)) { - $sql .= " AND cd.qty >= pfp.quantity GROUP BY cd.rowid HAVING max_qty = MAX(pfp.quantity)"; + $sql .= " GROUP BY cd.rowid HAVING (max_qty = MAX(pfp.quantity) OR max_qty IS NULL)"; } $result = $this->db->query($sql); if ($result) { diff --git a/htdocs/fourn/class/fournisseur.facture.class.php b/htdocs/fourn/class/fournisseur.facture.class.php index 922d9f25e29..ce101573677 100644 --- a/htdocs/fourn/class/fournisseur.facture.class.php +++ b/htdocs/fourn/class/fournisseur.facture.class.php @@ -12,7 +12,7 @@ * Copyright (C) 2015-2019 Ferran Marcet * Copyright (C) 2016-2021 Alexandre Spangaro * Copyright (C) 2018 Nicolas ZABOURI - * Copyright (C) 2018-2020 Frédéric France + * Copyright (C) 2018-2022 Frédéric France * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -245,7 +245,7 @@ class FactureFournisseur extends CommonInvoice public $multicurrency_total_ht; public $multicurrency_total_tva; public $multicurrency_total_ttc; - //! id of source var_dump($$this);invoice if replacement invoice or credit note + //! id of source invoice if replacement invoice or credit note /** * @var int ID */ diff --git a/htdocs/fourn/commande/tpl/linkedobjectblock.tpl.php b/htdocs/fourn/commande/tpl/linkedobjectblock.tpl.php index 1efd78df372..192a39c9b06 100644 --- a/htdocs/fourn/commande/tpl/linkedobjectblock.tpl.php +++ b/htdocs/fourn/commande/tpl/linkedobjectblock.tpl.php @@ -23,7 +23,7 @@ if (empty($conf) || !is_object($conf)) { } -print "\n"; +print "\n"; global $user; diff --git a/htdocs/fourn/facture/tpl/linkedobjectblock.tpl.php b/htdocs/fourn/facture/tpl/linkedobjectblock.tpl.php index 3f728d99567..e9ec8accf30 100644 --- a/htdocs/fourn/facture/tpl/linkedobjectblock.tpl.php +++ b/htdocs/fourn/facture/tpl/linkedobjectblock.tpl.php @@ -25,7 +25,7 @@ if (empty($conf) || !is_object($conf)) { } -print "\n"; +print "\n"; global $user; diff --git a/htdocs/holiday/card.php b/htdocs/holiday/card.php index d8643c0783b..a9bfe8ab4f2 100644 --- a/htdocs/holiday/card.php +++ b/htdocs/holiday/card.php @@ -1083,7 +1083,9 @@ if ((empty($id) && empty($ref)) || $action == 'create' || $action == 'add') { if (empty($include_users)) { print img_warning().' '.$langs->trans("NobodyHasPermissionToValidateHolidays"); } else { - $defaultselectuser = (empty($user->fk_user_holiday_validator) ? $user->fk_user : $user->fk_user_holiday_validator); // Will work only if supervisor has permission to approve so is inside include_users + // Defined default approver (the forced approved of user or the supervisor if no forced value defined) + // Note: This use will be set only if the deinfed approvr has permission to approve so is inside include_users + $defaultselectuser = (empty($user->fk_user_holiday_validator) ? $user->fk_user : $user->fk_user_holiday_validator); if (!empty($conf->global->HOLIDAY_DEFAULT_VALIDATOR)) { $defaultselectuser = $conf->global->HOLIDAY_DEFAULT_VALIDATOR; // Can force default approver } diff --git a/htdocs/install/mysql/data/llx_c_availability.sql b/htdocs/install/mysql/data/llx_c_availability.sql index 7291c399da0..02a7b37fc91 100644 --- a/htdocs/install/mysql/data/llx_c_availability.sql +++ b/htdocs/install/mysql/data/llx_c_availability.sql @@ -25,10 +25,9 @@ -- Availability type -- -delete from llx_c_availability; -INSERT INTO llx_c_availability (rowid,code,label,active,position) VALUES (1, 'AV_NOW', 'Immediate', 1, 10); -INSERT INTO llx_c_availability (rowid,code,label,active,position) VALUES (2, 'AV_1W', '1 week', 1, 20); -INSERT INTO llx_c_availability (rowid,code,label,active,position) VALUES (3, 'AV_2W', '2 weeks', 1, 30); -INSERT INTO llx_c_availability (rowid,code,label,active,position) VALUES (4, 'AV_3W', '3 weeks', 1, 40); -INSERT INTO llx_c_availability (rowid,code,label,active,position) VALUES (5, 'AV_4W', '4 weeks', 1, 50); +INSERT INTO llx_c_availability (code,label,active,position) VALUES ('AV_NOW', 'Immediate', 1, 10); +INSERT INTO llx_c_availability (code,label,active,position) VALUES ('AV_1W', '1 week', 1, 20); +INSERT INTO llx_c_availability (code,label,active,position) VALUES ('AV_2W', '2 weeks', 1, 30); +INSERT INTO llx_c_availability (code,label,active,position) VALUES ('AV_3W', '3 weeks', 1, 40); +INSERT INTO llx_c_availability (code,label,active,position) VALUES ('AV_4W', '4 weeks', 1, 50); diff --git a/htdocs/install/mysql/data/llx_c_civilite.sql b/htdocs/install/mysql/data/llx_c_civilite.sql index 1288fb23cea..7c20e73ef7c 100644 --- a/htdocs/install/mysql/data/llx_c_civilite.sql +++ b/htdocs/install/mysql/data/llx_c_civilite.sql @@ -30,9 +30,8 @@ -- Civilities -- -delete from llx_c_civility; -insert into llx_c_civility (rowid, code, label, active) values (1 , 'MME', 'Madame', 1); -insert into llx_c_civility (rowid, code, label, active) values (3 , 'MR', 'Monsieur', 1); -insert into llx_c_civility (rowid, code, label, active) values (5 , 'MLE', 'Mademoiselle', 1); -insert into llx_c_civility (rowid, code, label, active) values (7 , 'MTRE', 'Maître', 1); -insert into llx_c_civility (rowid, code, label, active) values (8 , 'DR', 'Docteur', 1); +insert into llx_c_civility (code, label, active) values ('MME', 'Madame', 1); +insert into llx_c_civility (code, label, active) values ('MR', 'Monsieur', 1); +insert into llx_c_civility (code, label, active) values ('MLE', 'Mademoiselle', 1); +insert into llx_c_civility (code, label, active) values ('MTRE', 'Maître', 1); +insert into llx_c_civility (code, label, active) values ('DR', 'Docteur', 1); diff --git a/htdocs/install/mysql/data/llx_c_hrm_public_holiday.sql b/htdocs/install/mysql/data/llx_c_hrm_public_holiday.sql index 9f779ecf64b..80f59680df5 100644 --- a/htdocs/install/mysql/data/llx_c_hrm_public_holiday.sql +++ b/htdocs/install/mysql/data/llx_c_hrm_public_holiday.sql @@ -6,6 +6,7 @@ -- Copyright (C) 2005-2012 Regis Houssin -- Copyright (C) 2007 Patrick Raguin -- Copyright (C) 2019 Markus Welters +-- Copyright (C) 2022 Joachim Kueter -- -- 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 @@ -62,6 +63,24 @@ INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, m INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('ES-CONSTITUIZION', 0, 4, '', 0, 12, 6, 1); INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('ES-IMMACULE', 0, 4, '', 0, 12, 8, 1); +-- Germany (5) +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('DE-NEUJAHR', 0, 5, '', 0, 1, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('DE-HL3KOEN--TLW', 0, 5, '', 0, 1, 6, 0); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('DE-INTFRAUENTAG--TLW', 0, 5, '', 0, 3, 8, 0); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('DE-KARFREITAG', 0, 5, 'goodfriday', 0, 0, 0, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('DE-OSTERMONTAG', 0, 5, 'eastermonday', 0, 0, 0, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('DE-TAGDERARBEIT', 0, 5, '', 0, 5, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('DE-HIMMELFAHRT', 0, 5, 'ascension', 0, 0, 0, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('DE-PFINGSTEN', 0, 5, 'pentecotemonday', 0, 0, 0, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('DE-FRONLEICHNAM--TLW', 0, 5, 'fronleichnam', 0, 0, 0, 0); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('DE-MARIAEHIMMEL--TLW', 0, 5, '', 0, 8, 15, 0); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('DE-WELTKINDERTAG--TLW', 0, 5, '', 0, 9, 20, 0); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('DE-TAGDERDEUTEINHEIT', 0, 5, '', 0, 10, 3, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('DE-REFORMATIONSTAG--TLW', 0, 5, '', 0, 10, 31, 0); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('DE-ALLERHEILIGEN--TLW', 0, 5, '', 0, 11, 1, 0); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('DE-WEIHNACHTSTAG1', 0, 5, '', 0, 12, 25, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('DE-WEIHNACHTSTAG2', 0, 5, '', 0, 12, 26, 1); + -- Austria (41) INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-EASTER', 0, 41, 'eastermonday', 0, 0, 0, 1); INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-ASCENSION', 0, 41, 'ascension', 0, 0, 0, 1); diff --git a/htdocs/install/mysql/migration/11.0.0-12.0.0.sql b/htdocs/install/mysql/migration/11.0.0-12.0.0.sql index fa8cb0197cc..b9a5e535d21 100644 --- a/htdocs/install/mysql/migration/11.0.0-12.0.0.sql +++ b/htdocs/install/mysql/migration/11.0.0-12.0.0.sql @@ -43,6 +43,8 @@ create table llx_commande_fournisseur_dispatch_extrafields ALTER TABLE llx_commande_fournisseur_dispatch_extrafields ADD INDEX idx_commande_fournisseur_dispatch_extrafields (fk_object); +ALTER TABLE llx_product_fournisseur_price ADD COLUMN packaging double(24,8) DEFAULT 1; + UPDATE llx_accounting_system SET fk_country = NULL, active = 0 WHERE pcg_version = 'SYSCOHADA'; create table llx_c_shipment_package_type diff --git a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql index 517771ced4e..a632a32271b 100644 --- a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql +++ b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql @@ -566,7 +566,8 @@ INSERT INTO llx_c_socialnetworks (entity, code, label, url, icon, active) VALUES -- VMYSQL4.1 INSERT INTO llx_boxes_def (file, entity) SELECT 'box_customers_outstanding_bill_reached.php', 1 FROM DUAL WHERE NOT EXISTS (SELECT * FROM llx_boxes_def WHERE file = 'box_customers_outstanding_bill_reached.php' AND entity = 1); -- VMYSQL4.1 INSERT INTO llx_boxes_def (file, entity) SELECT 'box_scheduled_jobs.php', 1 FROM DUAL WHERE NOT EXISTS (SELECT * FROM llx_boxes_def WHERE file = 'box_scheduled_jobs.php' AND entity = 1); -ALTER TABLE llx_product_fournisseur_price ADD COLUMN packaging varchar(64); +ALTER TABLE llx_product_fournisseur_price ADD COLUMN packaging varchar(64) DEFAULT NULL; +ALTER TABLE llx_product_fournisseur_price MODIFY COLUMN packaging varchar(64) DEFAULT NULL; ALTER TABLE llx_projet ADD COLUMN fk_opp_status_end integer DEFAULT NULL; diff --git a/htdocs/install/mysql/migration/13.0.0-14.0.0.sql b/htdocs/install/mysql/migration/13.0.0-14.0.0.sql index 6d2d0ae3033..434d30bdfe4 100644 --- a/htdocs/install/mysql/migration/13.0.0-14.0.0.sql +++ b/htdocs/install/mysql/migration/13.0.0-14.0.0.sql @@ -84,6 +84,9 @@ UPDATE llx_const set value = __ENCRYPT('eldy')__ WHERE __DECRYPT('value')__ = 'a UPDATE llx_const set value = __ENCRYPT('eldy')__ WHERE __DECRYPT('value')__ = 'cameleo'; DELETE FROM llx_user_param where param = 'MAIN_THEME' and value in ('auguria', 'amarok', 'cameleo'); +ALTER TABLE llx_product_fournisseur_price ADD COLUMN packaging varchar(64) DEFAULT NULL; +ALTER TABLE llx_product_fournisseur_price MODIFY COLUMN packaging varchar(64) DEFAULT NULL; + -- For v14 diff --git a/htdocs/install/mysql/migration/14.0.0-15.0.0.sql b/htdocs/install/mysql/migration/14.0.0-15.0.0.sql index f744abffde4..3e0fa10ccd0 100644 --- a/htdocs/install/mysql/migration/14.0.0-15.0.0.sql +++ b/htdocs/install/mysql/migration/14.0.0-15.0.0.sql @@ -35,6 +35,9 @@ -- VMYSQL4.3 ALTER TABLE llx_partnership MODIFY COLUMN date_partnership_end date NULL; -- VPGSQL8.2 ALTER TABLE llx_partnership ALTER COLUMN date_partnership_end DROP NOT NULL; +ALTER TABLE llx_product_fournisseur_price ADD COLUMN packaging varchar(64) DEFAULT NULL; +ALTER TABLE llx_product_fournisseur_price MODIFY COLUMN packaging varchar(64) DEFAULT NULL; + ALTER TABLE llx_accounting_bookkeeping ADD COLUMN date_export datetime DEFAULT NULL; ALTER TABLE llx_eventorganization_conferenceorboothattendee ADD COLUMN fk_project integer NOT NULL; diff --git a/htdocs/install/mysql/migration/15.0.0-16.0.0.sql b/htdocs/install/mysql/migration/15.0.0-16.0.0.sql index db1617e8bdd..cd82760b245 100644 --- a/htdocs/install/mysql/migration/15.0.0-16.0.0.sql +++ b/htdocs/install/mysql/migration/15.0.0-16.0.0.sql @@ -275,9 +275,16 @@ ALTER TABLE llx_bank_account ADD COLUMN pti_in_ctti smallint DEFAULT 0 AFTER dom UPDATE llx_c_ticket_type SET use_default=1 WHERE code='OTHER' AND NOT EXISTS(SELECT * FROM (SELECT * FROM llx_c_ticket_type) AS t WHERE use_default=1); +ALTER TABLE llx_propal ADD last_main_doc VARCHAR(255) NULL AFTER model_pdf; + +UPDATE llx_c_country SET eec=0 WHERE eec IS NULL; +ALTER TABLE llx_c_country MODIFY COLUMN eec tinyint DEFAULT 0 NOT NULL; + + -- Deposit generation helper with specific payment terms ALTER TABLE llx_c_payment_term ADD COLUMN deposit_percent VARCHAR(63) DEFAULT NULL AFTER decalage; ALTER TABLE llx_societe ADD COLUMN deposit_percent VARCHAR(63) DEFAULT NULL AFTER cond_reglement; ALTER TABLE llx_propal ADD COLUMN deposit_percent VARCHAR(63) DEFAULT NULL AFTER fk_cond_reglement; ALTER TABLE llx_commande ADD COLUMN deposit_percent VARCHAR(63) DEFAULT NULL AFTER fk_cond_reglement; INSERT INTO llx_c_payment_term(code, sortorder, active, libelle, libelle_facture, type_cdr, nbjour, deposit_percent) values ('DEP30PCTDEL', 13, 0, '__DEPOSIT_PERCENT__% deposit', '__DEPOSIT_PERCENT__% deposit, remainder on delivery', 0, 1, '30'); + diff --git a/htdocs/install/mysql/tables/llx_c_country.sql b/htdocs/install/mysql/tables/llx_c_country.sql index d97c3b90371..7419b68c26d 100644 --- a/htdocs/install/mysql/tables/llx_c_country.sql +++ b/htdocs/install/mysql/tables/llx_c_country.sql @@ -24,8 +24,8 @@ create table llx_c_country rowid integer PRIMARY KEY, code varchar(2) NOT NULL, code_iso varchar(3) , - label varchar(128) NOT NULL, - eec integer , + label varchar(128) NOT NULL, + eec tinyint DEFAULT 0 NOT NULL, active tinyint DEFAULT 1 NOT NULL, favorite tinyint DEFAULT 0 NOT NULL )ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_product_fournisseur_price.sql b/htdocs/install/mysql/tables/llx_product_fournisseur_price.sql index 25b295ec383..83b97c201ad 100644 --- a/htdocs/install/mysql/tables/llx_product_fournisseur_price.sql +++ b/htdocs/install/mysql/tables/llx_product_fournisseur_price.sql @@ -50,8 +50,7 @@ create table llx_product_fournisseur_price import_key varchar(14), -- Import key delivery_time_days integer, supplier_reputation varchar(10), - packaging varchar(64), - + packaging varchar(64) DEFAULT NULL, fk_multicurrency integer, multicurrency_code varchar(3), multicurrency_tx double(24,8) DEFAULT 1, diff --git a/htdocs/install/mysql/tables/llx_societe.sql b/htdocs/install/mysql/tables/llx_societe.sql index 1198e89e578..4004dc36d0b 100644 --- a/htdocs/install/mysql/tables/llx_societe.sql +++ b/htdocs/install/mysql/tables/llx_societe.sql @@ -77,7 +77,8 @@ create table llx_societe fk_stcomm integer DEFAULT 0 NOT NULL, -- commercial status note_private text, -- note_public text, -- - model_pdf varchar(255), + model_pdf varchar(255), + last_main_doc varchar(255), -- relative filepath+filename of last main generated document prefix_comm varchar(5), -- prefix commercial (deprecated) client tinyint DEFAULT 0, -- client 0/1/2 fournisseur tinyint DEFAULT 0, -- fournisseur 0/1 diff --git a/htdocs/langs/en_US/cron.lang b/htdocs/langs/en_US/cron.lang index 4fd2220dea6..9705f8823b0 100644 --- a/htdocs/langs/en_US/cron.lang +++ b/htdocs/langs/en_US/cron.lang @@ -82,6 +82,8 @@ UseMenuModuleToolsToAddCronJobs=Go into menu "Home - Admin tools - JobDisabled=Job disabled MakeLocalDatabaseDumpShort=Local database backup MakeLocalDatabaseDump=Create a local database dump. Parameters are: compression ('gz' or 'bz' or 'none'), backup type ('mysql', 'pgsql', 'auto'), 1, 'auto' or filename to build, number of backup files to keep +MakeSendLocalDatabaseDumpShort=Send local database backup +MakeSendLocalDatabaseDump=Send local database backup by email. Parameters are: to, from, subject, message, filename (Name of file sent), filter ('sql' for backup of database only) WarningCronDelayed=Attention, for performance purpose, whatever is next date of execution of enabled jobs, your jobs may be delayed to a maximum of %s hours, before being run. DATAPOLICYJob=Data cleaner and anonymizer JobXMustBeEnabled=Job %s must be enabled diff --git a/htdocs/langs/en_US/errors.lang b/htdocs/langs/en_US/errors.lang index 7ab5d41f285..86d11ec59ea 100644 --- a/htdocs/langs/en_US/errors.lang +++ b/htdocs/langs/en_US/errors.lang @@ -278,6 +278,7 @@ ErrorIsNotADraft=%s is not a draft ErrorExecIdFailed=Can't execute command "id" ErrorBadCharIntoLoginName=Unauthorized character in the login name ErrorRequestTooLarge=Error, request too large +ErrorNotApproverForHoliday=You are not the approver for leave %s # Warnings WarningParamUploadMaxFileSizeHigherThanPostMaxSize=Your PHP parameter upload_max_filesize (%s) is higher than PHP parameter post_max_size (%s). This is not a consistent setup. diff --git a/htdocs/langs/en_US/ticket.lang b/htdocs/langs/en_US/ticket.lang index 9dfc4874cc5..310ac8dd7f6 100644 --- a/htdocs/langs/en_US/ticket.lang +++ b/htdocs/langs/en_US/ticket.lang @@ -142,6 +142,9 @@ TicketsDelayBeforeFirstAnswer=A new ticket should receive a first answer before TicketsDelayBeforeFirstAnswerHelp=If a new ticket has not received an answer after this time period (in hours), an important warning icon will be displayed in the list view. TicketsDelayBetweenAnswers=An unresolved ticket should not be unactive during (hours): TicketsDelayBetweenAnswersHelp=If an unresolved ticket that has already received an answer has not had further interaction after this time period (in hours), a warning icon will be displayed in the list view. +TicketsAutoNotifyClose=Automatically notify thirdparty when closing a ticket +TicketsAutoNotifyCloseHelp=When closing a ticket, you will be proposed to send a message to one of thirdparty's contacts. On mass closing, a message will be sent to one contact of the thirdparty linked to the ticket. +TicketWrongContact=Provided contact is not part of current ticket contacts. Email not sent. # # Index & list page @@ -158,6 +161,8 @@ OrderByDateAsc=Sort by ascending date OrderByDateDesc=Sort by descending date ShowAsConversation=Show as conversation list MessageListViewType=Show as table list +ConfirmMassTicketClosingSendEmail=Automatically send emails when closing tickets +ConfirmMassTicketClosingSendEmailQuestion=Do you want to notify thirdparties when closing these tickets ? # # Ticket card @@ -245,6 +250,9 @@ TicketChangeStatus=Change status TicketConfirmChangeStatus=Confirm the status change: %s ? TicketLogStatusChanged=Status changed: %s to %s TicketNotNotifyTiersAtCreate=Not notify company at create +NotifyThirdpartyOnTicketClosing=Contacts to notify while closing the ticket +TicketNotifyAllTiersAtClose=All related contacts +TicketNotNotifyTiersAtClose=No related contact Unread=Unread TicketNotCreatedFromPublicInterface=Not available. Ticket was not created from public interface. ErrorTicketRefRequired=Ticket reference name is required @@ -279,6 +287,7 @@ TicketNewEmailBodyInfosTicket=Information for monitoring the ticket TicketNewEmailBodyInfosTrackId=Ticket tracking number: %s TicketNewEmailBodyInfosTrackUrl=You can view the progress of the ticket by clicking the link above. TicketNewEmailBodyInfosTrackUrlCustomer=You can view the progress of the ticket in the specific interface by clicking the following link +TicketCloseEmailBodyInfosTrackUrlCustomer=You can consult the history of this ticket by clicking the following link TicketEmailPleaseDoNotReplyToThisEmail=Please do not reply directly to this email! Use the link to reply into the interface. TicketPublicInfoCreateTicket=This form allows you to record a support ticket in our management system. TicketPublicPleaseBeAccuratelyDescribe=Please accurately describe the problem. Provide the most information possible to allow us to correctly identify your request. @@ -300,6 +309,10 @@ NewUser=New user NumberOfTicketsByMonth=Number of tickets per month NbOfTickets=Number of tickets # notifications +TicketCloseEmailSubjectCustomer=Ticket closed +TicketCloseEmailBodyCustomer=This is an automatic message to notify you that ticket %s has just been closed. +TicketCloseEmailSubjectAdmin=Ticket closed - Réf %s (public ticket ID %s) +TicketCloseEmailBodyAdmin=A ticket with ID #%s has just been closed, see information: TicketNotificationEmailSubject=Ticket %s updated TicketNotificationEmailBody=This is an automatic message to notify you that ticket %s has just been updated TicketNotificationRecipient=Notification recipient diff --git a/htdocs/modulebuilder/template/core/modules/modMyModule.class.php b/htdocs/modulebuilder/template/core/modules/modMyModule.class.php index 13e34593bba..02eb1c18fb6 100644 --- a/htdocs/modulebuilder/template/core/modules/modMyModule.class.php +++ b/htdocs/modulebuilder/template/core/modules/modMyModule.class.php @@ -432,7 +432,7 @@ class modMyModule extends DolibarrModules $sql = array(); // Document templates - $moduledir = 'mymodule'; + $moduledir = dol_sanitizeFileName('mymodule'); $myTmpObjects = array(); $myTmpObjects['MyObject'] = array('includerefgeneration'=>0, 'includedocgeneration'=>0); @@ -441,8 +441,8 @@ class modMyModule extends DolibarrModules continue; } if ($myTmpObjectArray['includerefgeneration']) { - $src = DOL_DOCUMENT_ROOT.'/install/doctemplates/mymodule/template_myobjects.odt'; - $dirodt = DOL_DATA_ROOT.'/doctemplates/mymodule'; + $src = DOL_DOCUMENT_ROOT.'/install/doctemplates/'.$moduledir.'/template_myobjects.odt'; + $dirodt = DOL_DATA_ROOT.'/doctemplates/'.$moduledir; $dest = $dirodt.'/template_myobjects.odt'; if (file_exists($src) && !file_exists($dest)) { diff --git a/htdocs/modulebuilder/template/core/tpl/linkedobjectblock_myobject.tpl.php b/htdocs/modulebuilder/template/core/tpl/linkedobjectblock_myobject.tpl.php index 2f0ecd06774..21cb16c3644 100644 --- a/htdocs/modulebuilder/template/core/tpl/linkedobjectblock_myobject.tpl.php +++ b/htdocs/modulebuilder/template/core/tpl/linkedobjectblock_myobject.tpl.php @@ -22,7 +22,7 @@ if (empty($conf) || !is_object($conf)) { } -print "\n"; +print "\n"; global $user; diff --git a/htdocs/mrp/class/mo.class.php b/htdocs/mrp/class/mo.class.php index 2da1672e089..21ebd1ec5f5 100644 --- a/htdocs/mrp/class/mo.class.php +++ b/htdocs/mrp/class/mo.class.php @@ -113,8 +113,8 @@ class Mo extends CommonObject 'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'position'=>500, 'notnull'=>1,), 'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-2, 'position'=>501, 'notnull'=>1,), 'date_valid' => array('type'=>'datetime', 'label'=>'DateValidation', 'enabled'=>1, 'visible'=>-2, 'position'=>502,), - 'fk_user_creat' => array('type'=>'integer', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-2, 'position'=>510, 'notnull'=>1, 'foreignkey'=>'user.rowid', 'csslist'=>'tdoverflowmax100'), - 'fk_user_modif' => array('type'=>'integer', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'position'=>511, 'notnull'=>-1, 'csslist'=>'tdoverflowmax100'), + 'fk_user_creat' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-2, 'position'=>510, 'notnull'=>1, 'foreignkey'=>'user.rowid', 'csslist'=>'tdoverflowmax100'), + 'fk_user_modif' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'position'=>511, 'notnull'=>-1, 'csslist'=>'tdoverflowmax100'), 'date_start_planned' => array('type'=>'datetime', 'label'=>'DateStartPlannedMo', 'enabled'=>1, 'visible'=>1, 'position'=>55, 'notnull'=>-1, 'index'=>1, 'help'=>'KeepEmptyForAsap'), 'date_end_planned' => array('type'=>'datetime', 'label'=>'DateEndPlannedMo', 'enabled'=>1, 'visible'=>1, 'position'=>56, 'notnull'=>-1, 'index'=>1,), 'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>1000, 'notnull'=>-1,), diff --git a/htdocs/mrp/tpl/linkedobjectblock.tpl.php b/htdocs/mrp/tpl/linkedobjectblock.tpl.php index 5dbe583fd21..ff9aa269678 100644 --- a/htdocs/mrp/tpl/linkedobjectblock.tpl.php +++ b/htdocs/mrp/tpl/linkedobjectblock.tpl.php @@ -24,7 +24,7 @@ if (empty($conf) || !is_object($conf)) { exit; } -print "\n"; +print "\n"; global $user, $db; global $noMoreLinkedObjectBlockAfter; diff --git a/htdocs/multicurrency/class/multicurrency.class.php b/htdocs/multicurrency/class/multicurrency.class.php index 0dc9f7ce63a..1ebf33d3925 100644 --- a/htdocs/multicurrency/class/multicurrency.class.php +++ b/htdocs/multicurrency/class/multicurrency.class.php @@ -493,20 +493,20 @@ class MultiCurrency extends CommonObject /** * Get id of currency from code * - * @param DoliDB $db object db + * @param DoliDB $dbs object db * @param string $code code value search * * @return int 0 if not found, >0 if OK */ - public static function getIdFromCode($db, $code) + public static function getIdFromCode($dbs, $code) { global $conf; - $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."multicurrency WHERE code = '".$db->escape($code)."' AND entity = ".$conf->entity; + $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."multicurrency WHERE code = '".$dbs->escape($code)."' AND entity = ".((int) $conf->entity); dol_syslog(__METHOD__, LOG_DEBUG); - $resql = $db->query($sql); - if ($resql && $obj = $db->fetch_object($resql)) { + $resql = $dbs->query($sql); + if ($resql && $obj = $dbs->fetch_object($resql)) { return $obj->rowid; } else { return 0; @@ -516,38 +516,38 @@ class MultiCurrency extends CommonObject /** * Get id and rate of currency from code * - * @param DoliDB $db Object db + * @param DoliDB $dbs Object db * @param string $code Code value search * @param integer $date_document Date from document (propal, order, invoice, ...) * * @return array [0] => id currency * [1] => rate */ - public static function getIdAndTxFromCode($db, $code, $date_document = '') + public static function getIdAndTxFromCode($dbs, $code, $date_document = '') { global $conf; $sql1 = "SELECT m.rowid, mc.rate FROM ".MAIN_DB_PREFIX."multicurrency m"; $sql1 .= ' LEFT JOIN '.MAIN_DB_PREFIX.'multicurrency_rate mc ON (m.rowid = mc.fk_multicurrency)'; - $sql1 .= " WHERE m.code = '".$db->escape($code)."'"; + $sql1 .= " WHERE m.code = '".$dbs->escape($code)."'"; $sql1 .= " AND m.entity IN (".getEntity('multicurrency').")"; $sql2 = ''; if (!empty($conf->global->MULTICURRENCY_USE_RATE_ON_DOCUMENT_DATE) && !empty($date_document)) { // Use last known rate compared to document date $tmparray = dol_getdate($date_document); - $sql2 .= " AND mc.date_sync <= '".$db->idate(dol_mktime(23, 59, 59, $tmparray['mon'], $tmparray['mday'], $tmparray['year'], true))."'"; + $sql2 .= " AND mc.date_sync <= '".$dbs->idate(dol_mktime(23, 59, 59, $tmparray['mon'], $tmparray['mday'], $tmparray['year'], true))."'"; } $sql3 = " ORDER BY mc.date_sync DESC LIMIT 1"; dol_syslog(__METHOD__, LOG_DEBUG); - $resql = $db->query($sql1.$sql2.$sql3); + $resql = $dbs->query($sql1.$sql2.$sql3); - if ($resql && $obj = $db->fetch_object($resql)) { + if ($resql && $obj = $dbs->fetch_object($resql)) { return array($obj->rowid, $obj->rate); } else { if (!empty($conf->global->MULTICURRENCY_USE_RATE_ON_DOCUMENT_DATE)) { - $resql = $db->query($sql1.$sql3); - if ($resql && $obj = $db->fetch_object($resql)) { + $resql = $dbs->query($sql1.$sql3); + if ($resql && $obj = $dbs->fetch_object($resql)) { return array($obj->rowid, $obj->rate); } } @@ -746,7 +746,7 @@ class CurrencyRate extends CommonObjectLine */ public function __construct(DoliDB $db) { - $this->db = &$db; + $this->db = $db; return 1; } diff --git a/htdocs/multicurrency/multicurrency_rate.php b/htdocs/multicurrency/multicurrency_rate.php index 73cff1b4502..46742995bec 100644 --- a/htdocs/multicurrency/multicurrency_rate.php +++ b/htdocs/multicurrency/multicurrency_rate.php @@ -250,6 +250,7 @@ if (!in_array($action, array("updateRate", "deleteRate"))) { print '
'; print ''; + print '
'; print ''; print ' '; @@ -265,10 +266,12 @@ if (!in_array($action, array("updateRate", "deleteRate"))) { print ''; print '
'.$langs->trans('Date').''; print ''; - print ''; + print ''; print '
'; + print '
'; + print '
'; print '
'; @@ -404,7 +407,7 @@ if ($resql) { $selectedfields .= $form->showCheckAddButtons('checkforselect', 1); } - print '
'; + print '
'; print ''."\n"; // Lines with input filters @@ -426,7 +429,7 @@ if ($resql) { // rate if (!empty($arrayfields['cr.rate']['checked'])) { print ''; } diff --git a/htdocs/product/admin/product.php b/htdocs/product/admin/product.php index 2d7d99a9ab3..e2e06bef551 100644 --- a/htdocs/product/admin/product.php +++ b/htdocs/product/admin/product.php @@ -150,25 +150,8 @@ if ($action == 'other') { $value = GETPOST('activate_FillProductDescAuto', 'alpha'); $res = dolibarr_set_const($db, "PRODUIT_AUTOFILL_DESC", $value, 'chaine', 0, '', $conf->entity); - if ($value) { - $sql_test = "SELECT count(desc_fourn) as cpt FROM ".MAIN_DB_PREFIX."product_fournisseur_price WHERE 1"; - $resql = $db->query($sql_test); - if (!$resql && $db->lasterrno == 'DB_ERROR_NOSUCHFIELD') { // if the field does not exist, we create it - $sql_new = "ALTER TABLE ".MAIN_DB_PREFIX."product_fournisseur_price ADD COLUMN desc_fourn text"; - $resql_new = $db->query($sql_new); - } - } - $value = GETPOST('activate_useProdSupplierPackaging', 'alpha'); $res = dolibarr_set_const($db, "PRODUCT_USE_SUPPLIER_PACKAGING", $value, 'chaine', 0, '', $conf->entity); - if ($value) { - $sql_test = "SELECT count(packaging) as cpt FROM ".MAIN_DB_PREFIX."product_fournisseur_price WHERE 1"; - $resql = $db->query($sql_test); - if (!$resql && $db->lasterrno == 'DB_ERROR_NOSUCHFIELD') { // if the field does not exist, we create it - $sql_new = "ALTER TABLE ".MAIN_DB_PREFIX."product_fournisseur_price ADD COLUMN packaging double(24,8) DEFAULT 1"; - $resql_new = $db->query($sql_new); - } - } } if ($action == 'specimen') { // For products diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 8e61663d339..839a9f18ba2 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -272,7 +272,7 @@ class Product extends CommonObject public $fk_default_bom; /** - * We must manage lot/batch number, sell-by date and so on : '1':yes '0':no + * We must manage lot/batch number, sell-by date and so on : '0':no, '1':yes, '2": yes with unique serial number * * @var int */ @@ -1979,7 +1979,10 @@ class Product extends CommonObject $sql .= " pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,"; $sql .= " pfp.packaging"; $sql .= " FROM ".$this->db->prefix()."product_fournisseur_price as pfp"; - $sql .= " WHERE pfp.fk_product = ".((int) $product_id); + $sql .= " WHERE 1 = 1"; + if ($product_id > 0) { + $sql .= " AND pfp.fk_product = ".((int) $product_id); + } if ($fourn_ref != 'none') { $sql .= " AND pfp.ref_fourn = '".$this->db->escape($fourn_ref)."'"; } diff --git a/htdocs/projet/document.php b/htdocs/projet/document.php index 9e8d3a6ce8e..2301017edd9 100644 --- a/htdocs/projet/document.php +++ b/htdocs/projet/document.php @@ -32,6 +32,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; // Load translation files required by the page $langs->loadLangs(array('projects', 'other')); +$hookmanager->initHooks(array('projectcarddocument')); $action = GETPOST('action', 'alpha'); $confirm = GETPOST('confirm', 'alpha'); diff --git a/htdocs/projet/info.php b/htdocs/projet/info.php index c0afe5d1370..9b0544bccf6 100644 --- a/htdocs/projet/info.php +++ b/htdocs/projet/info.php @@ -62,6 +62,8 @@ if (GETPOST('actioncode', 'array')) { } $search_agenda_label = GETPOST('search_agenda_label'); +$hookmanager->initHooks(array('projectcardinfo')); + // Security check $id = GETPOST("id", 'int'); $socid = 0; diff --git a/htdocs/reception/tpl/linkedobjectblock.tpl.php b/htdocs/reception/tpl/linkedobjectblock.tpl.php index c8ff1196c0f..1bfecac3f1d 100644 --- a/htdocs/reception/tpl/linkedobjectblock.tpl.php +++ b/htdocs/reception/tpl/linkedobjectblock.tpl.php @@ -25,7 +25,7 @@ if (empty($conf) || !is_object($conf)) { ?> - +initHooks(array('thirdpartydao')); diff --git a/htdocs/takepos/invoice.php b/htdocs/takepos/invoice.php index 66a75ef7050..3453d0e0579 100644 --- a/htdocs/takepos/invoice.php +++ b/htdocs/takepos/invoice.php @@ -912,6 +912,7 @@ $form = new Form($db);
'; - print ''; + print ''; print '