diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 1eae1b063b040..d898628013e48 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -36,12 +36,13 @@ Definition: As the Developer: -1. [Fork](https://help.github.com/articles/fork-a-repo) the [GitHub repository](https://github.com/Dolibarr/dolibarr). -2. Clone your fork. -3. Choose a branch(See the [Branches](#branches) section below). -4. Read our developer documentation on the [Dolibarr Wiki](https://wiki.dolibarr.org/index.php?title=Developer_documentation). -5. Commit and push your changes. -6. [Make a pull request](https://help.github.com/articles/creating-a-pull-request). +1. Check you agree with the terms of the [DCO - Developer's Certificate of Origin](https://github.com/Dolibarr/dolibarr/DCO) +2. [Fork](https://help.github.com/articles/fork-a-repo) the [GitHub repository](https://github.com/Dolibarr/dolibarr). +3. Clone your fork. +4. Choose a branch(See the [Branches](#branches) section below). +5. Read our developer documentation on the [Dolibarr Wiki](https://wiki.dolibarr.org/index.php?title=Developer_documentation). +6. Commit and push your changes. +7. [Make a pull request](https://help.github.com/articles/creating-a-pull-request). As the PR Maintainer: diff --git a/SECURITY.md b/SECURITY.md index 50a74ea0716a9..062578e03b9fb 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -12,7 +12,7 @@ Security report are valid only on current stable version (see https://dolibarr.o To report a vulnerability, for a private report, you can: -- Send your report on Vulnerability Disclosure Program (VDP): Link will be upadeted soon (recommended for everybody) +- Send your report on Vulnerability Disclosure Program (VDP): Link will be updated soon (recommended for everybody) '; - $out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', 0, $this->id, $this->table_element); + $out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', 0, $this, $this->table_element); break; case "edit": $listoftypestoshowpicto = explode(',', getDolGlobalString('MAIN_TYPES_TO_SHOW_PICTO', 'email,phone,ip,password')); if (in_array($extrafields->attributes[$this->table_element]['type'][$key], $listoftypestoshowpicto)) { $out .= getPictoForType($extrafields->attributes[$this->table_element]['type'][$key], ($extrafields->attributes[$this->table_element]['type'][$key] == 'text' ? 'tdtop' : '')); } - $out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', '', $this->id, $this->table_element); + $out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', '', $this, $this->table_element); break; } diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index 221925075e18d..6aca908bffda1 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -51,7 +51,7 @@ class ExtraFields public $attributes = array(); /** - * @var array> Array with boolean of status of groups + * @var array>|null Array with boolean of status of groups */ public $expand_display; @@ -1076,18 +1076,18 @@ public function fetch_name_optionals_label($elementtype, $forceload = false, $at * Return HTML string to put an input field into a page * Code very similar with showInputField of common object * - * @param string $key Key of attribute + * @param string $key Key of attribute * @param string|array{start:int,end:int} $value Preselected value to show (for date type it must be in timestamp format, for amount or price it must be a php numeric value); for dates in filter mode, a range array('start'=>, 'end'=>) should be provided - * @param string $moreparam To add more parameters on html input tag - * @param string $keysuffix Suffix string to add after name and id of field (can be used to avoid duplicate names) - * @param string $keyprefix Prefix string to add before name and id of field (can be used to avoid duplicate names) - * @param string $morecss More css (to defined size of field. Old behaviour: may also be a numeric) - * @param int $objectid Current object id - * @param string $extrafieldsobjectkey The key to use to store retrieved data (commonly $object->table_element) - * @param int $mode 1=Used for search filters + * @param string $moreparam To add more parameters on html input tag + * @param string $keysuffix Suffix string to add after name and id of field (can be used to avoid duplicate names) + * @param string $keyprefix Prefix string to add before name and id of field (can be used to avoid duplicate names) + * @param string $morecss More css (to defined size of field. Old behaviour: may also be a numeric) + * @param int|CommonObject $object Current object or object ID. Preferably, pass the object itself. + * @param string $extrafieldsobjectkey The key to use to store retrieved data (commonly $object->table_element) + * @param int $mode 1=Used for search filters * @return string */ - public function showInputField($key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = '', $objectid = 0, $extrafieldsobjectkey = '', $mode = 0) + public function showInputField($key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = '', $object = 0, $extrafieldsobjectkey = '', $mode = 0) { global $conf, $langs, $form; @@ -1096,6 +1096,8 @@ public function showInputField($key, $value, $moreparam = '', $keysuffix = '', $ $form = new Form($this->db); } + $objectid = (is_numeric($object) ? $object : $object->id); + $out = ''; if (!preg_match('/options_$/', $keyprefix)) { // Because we work on extrafields, we add 'options_' to prefix if not already added @@ -1120,6 +1122,7 @@ public function showInputField($key, $value, $moreparam = '', $keysuffix = '', $ $list = (string) dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1, 1, '2'); $totalizable = $this->attributes[$extrafieldsobjectkey]['totalizable'][$key]; $help = $this->attributes[$extrafieldsobjectkey]['help'][$key]; + $alwayseditable = $this->attributes[$extrafieldsobjectkey]['alwayseditable'][$key]; $hidden = (empty($list) ? 1 : 0); // If empty, we are sure it is hidden, otherwise we show. If it depends on mode (view/create/edit form or list, this must be filtered by caller) //var_dump('key='.$key.' '.$value.' '.$moreparam.' '.$keysuffix.' '.$keyprefix.' '.$objectid.' '.$extrafieldsobjectkey.' '.$mode); @@ -1935,6 +1938,12 @@ public function showInputField($key, $value, $moreparam = '', $keysuffix = '', $ if (!empty($hidden)) { $out = ''; } + + // If alwayseditable is false, and object is not in draft, then showOutputField + // @phan-suppress-next-line PhanUndeclaredConstantOfClass + if ($alwayseditable == 0 && is_object($object) && isset($object->status) && defined(get_class($object)."::STATUS_DRAFT") && $object->status != $object::STATUS_DRAFT) { + $out = $this->showOutputField($key, $value, $moreparam, $extrafieldsobjectkey, null, $object); + } /* Add comments if ($type == 'date') $out.=' (YYYY-MM-DD)'; elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)'; @@ -1954,7 +1963,7 @@ public function showInputField($key, $value, $moreparam = '', $keysuffix = '', $ * @param string $moreparam To add more parameters on html input tag (only checkbox use html input for output rendering) * @param string $extrafieldsobjectkey Required (for example $object->table_element). * @param Translate|null $outputlangs Output - * @param object $object The parent object of field to show + * @param CommonObject $object The parent object of field to show * @return string Formatted value */ public function showOutputField($key, $value, $moreparam = '', $extrafieldsobjectkey = '', $outputlangs = null, $object = null) @@ -1988,7 +1997,7 @@ public function showOutputField($key, $value, $moreparam = '', $extrafieldsobjec // If alwayseditable is false, and object is not in draft, then we show value instead of input field $showValueInsteadOfInputField = 0; // Variable used to disable update of fields via ajax // @phan-suppress-next-line PhanUndeclaredConstantOfClass - if ($alwayseditable == 0 && !is_numeric($object) && isset($object->status) && $object->status != $object::STATUS_DRAFT) { + if ($alwayseditable == 0 && is_object($object) && isset($object->status) && defined(get_class($object)."::STATUS_DRAFT") && $object->status != $object::STATUS_DRAFT) { $showValueInsteadOfInputField = 1; } diff --git a/htdocs/core/lib/ajax.lib.php b/htdocs/core/lib/ajax.lib.php index eb867663795f6..20ebd6464df2d 100644 --- a/htdocs/core/lib/ajax.lib.php +++ b/htdocs/core/lib/ajax.lib.php @@ -677,9 +677,11 @@ function ajax_constantonoff($code, $input = array(), $entity = null, $revertonof // Set constant $("#set_" + code).click(function() { +console.log("ee"); if (warning) { alert(warning); } + if (input.alert && input.alert.set) { if (input.alert.set.yesButton) yesButton = input.alert.set.yesButton; if (input.alert.set.noButton) noButton = input.alert.set.noButton; diff --git a/htdocs/core/lib/bank.lib.php b/htdocs/core/lib/bank.lib.php index 787ae74594958..5815d177767be 100644 --- a/htdocs/core/lib/bank.lib.php +++ b/htdocs/core/lib/bank.lib.php @@ -38,7 +38,8 @@ */ function bank_prepare_head(Account $object) { - global $db, $langs, $conf; + global $db, $langs, $conf, $user; + $h = 0; $head = array(); @@ -52,23 +53,44 @@ function bank_prepare_head(Account $object) $head[$h][2] = 'journal'; $h++; - // if ($conf->global->MAIN_FEATURES_LEVEL >= 1) - // { - $head[$h][0] = DOL_URL_ROOT."/compta/bank/treso.php?account=".$object->id; - $head[$h][1] = $langs->trans("PlannedTransactions"); - $head[$h][2] = 'cash'; - $h++; - // } - - $head[$h][0] = DOL_URL_ROOT."/compta/bank/annuel.php?account=".$object->id; - $head[$h][1] = $langs->trans("IOMonthlyReporting"); - $head[$h][2] = 'annual'; - $h++; + if ($object->canBeConciliated() > 0) { + $allowautomaticconciliation = getDolGlobalBool('MAIN_ALLOW_AUTOMATIC_CONCILIATION'); // TODO + $titletoconciliatemanual = $langs->trans("Conciliate"); + $titletoconciliateauto = $langs->trans("Conciliate"); + if ($allowautomaticconciliation) { + $titletoconciliatemanual .= ' ('.$langs->trans("Manual").')'; + $titletoconciliateauto .= ' ('.$langs->trans("Auto").')'; + } - $head[$h][0] = DOL_URL_ROOT."/compta/bank/graph.php?account=".$object->id; - $head[$h][1] = $langs->trans("Graph"); - $head[$h][2] = 'graph'; - $h++; + $param = ''; + + // If not cash account and can be reconciliate + if ($user->hasRight('banque', 'consolidate')) { + $head[$h][0] = DOL_URL_ROOT."/compta/bank/bankentries_list.php?id=".$object->id.'&action=reconcile&sortfield=b.datev,b.dateo,b.rowid&sortorder=asc,asc,asc&search_conciliated=0&search_account='.$object->id.$param; + $head[$h][1] = $titletoconciliatemanual; + $head[$h][2] = 'reconcile'; + $h++; + }/* else { + $buttonreconcile = ''.$titletoconciliatemanual.''; + }*/ + + if ($allowautomaticconciliation) { + // If not cash account and can be reconciliate + if ($user->hasRight('banque', 'consolidate')) { + $newparam = $param; + $newparam = preg_replace('/search_conciliated=\d+/i', '', $newparam); + + $head[$h][0] = DOL_URL_ROOT."/compta/bank/bankentries_list.php?id=".$object->id.'&action=reconcile&sortfield=b.datev,b.dateo,b.rowid&sortorder=asc,asc,asc&search_conciliated=0&search_account='.$object->id.$newparam; + $head[$h][1] = $titletoconciliateauto; + $head[$h][2] = 'reconcileauto'; + $h++; + + //$buttonreconcile .= ' '.$titletoconciliateauto.''; + }/* else { + $buttonreconcile .= ' '.$titletoconciliateauto.''; + }*/ + } + } if ($object->type != Account::TYPE_CASH || getDolGlobalString('BANK_CAN_RECONCILIATE_CASHACCOUNT')) { $nbReceipts = 0; @@ -110,6 +132,21 @@ function bank_prepare_head(Account $object) $head[$h][2] = 'document'; $h++; + $head[$h][0] = DOL_URL_ROOT."/compta/bank/annuel.php?account=".$object->id; + $head[$h][1] = $langs->trans("IOMonthlyReporting"); + $head[$h][2] = 'annual'; + $h++; + + $head[$h][0] = DOL_URL_ROOT."/compta/bank/graph.php?account=".$object->id; + $head[$h][1] = $langs->trans("Graph"); + $head[$h][2] = 'graph'; + $h++; + + $head[$h][0] = DOL_URL_ROOT."/compta/bank/treso.php?account=".$object->id; + $head[$h][1] = $langs->trans("PlannedTransactions"); + $head[$h][2] = 'cash'; + $h++; + // Show more tabs from modules // Entries must be declared in modules descriptor with line // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 2a77d59434944..737f8ac24fc0a 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -1898,7 +1898,7 @@ function dol_init_file_process($pathtoscan = '', $trackid = '') * @param int<0,1> $generatethumbs 1=Generate also thumbs for uploaded image files * @param ?Object $object Object used to set 'src_object_*' fields * @param string $forceFullTestIndexation '1'=Force full text storage in database even if global option not set (consume a high level of data) - * @return int Return integer <=0 if KO, >0 if OK + * @return int Return integer <=0 if KO, nb of success if OK (>0) * @see dol_remove_file_process() */ function dol_add_file_process($upload_dir, $allowoverwrite = 0, $updatesessionordb = 0, $varfiles = 'addedfile', $savingdocmask = '', $link = null, $trackid = '', $generatethumbs = 1, $object = null, $forceFullTestIndexation = '') @@ -2041,7 +2041,7 @@ function dol_add_file_process($upload_dir, $allowoverwrite = 0, $updatesessionor } } if ($nbok > 0) { - $res = 1; + $res = $nbok; setEventMessages($langs->trans("FileTransferComplete"), null, 'mesgs'); } } else { diff --git a/htdocs/core/modules/expedition/doc/pdf_espadon.modules.php b/htdocs/core/modules/expedition/doc/pdf_espadon.modules.php index 190a50e6ae118..f5873eaeeb304 100644 --- a/htdocs/core/modules/expedition/doc/pdf_espadon.modules.php +++ b/htdocs/core/modules/expedition/doc/pdf_espadon.modules.php @@ -689,7 +689,7 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede $weighttxt = round($object->lines[$i]->weight * $object->lines[$i]->qty_shipped, getDolGlobalInt('SHIPMENT_ROUND_WEIGHT_ON_PDF', 5)).' '.measuringUnitString(0, "weight", $object->lines[$i]->weight_units, 1); } $voltxt = ''; - if (empty($object->lines[$i]->fk_product_type) && $object->lines[$i]->volume) { + if (empty($object->lines[$i]->fk_product_type) && $object->lines[$i]->volume && !getDolGlobalString('SHIPPING_PDF_HIDE_VOLUME')) { $voltxt = round($object->lines[$i]->volume * $object->lines[$i]->qty_shipped, getDolGlobalInt('SHIPMENT_ROUND_VOLUME_ON_PDF', 5)).' '.measuringUnitString(0, "volume", $object->lines[$i]->volume_units ? $object->lines[$i]->volume_units : 0, 1); } @@ -883,13 +883,13 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs if (!empty($totalWeight)) { $totalWeighttoshow = showDimensionInBestUnit($totalWeight, 0, "weight", $outputlangs, -1, 'no', 1); } - if (!empty($totalVolume)) { + if (!empty($totalVolume) && !getDolGlobalString('SHIPPING_PDF_HIDE_VOLUME')) { $totalVolumetoshow = showDimensionInBestUnit($totalVolume, 0, "volume", $outputlangs, -1, 'no', 1); } if (!empty($object->trueWeight)) { $totalWeighttoshow = showDimensionInBestUnit($object->trueWeight, (int) $object->weight_units, "weight", $outputlangs); } - if (!empty($object->trueVolume)) { + if (!empty($object->trueVolume) && !getDolGlobalString('SHIPPING_PDF_HIDE_VOLUME')) { if ($object->volume_units < 50) { $totalVolumetoshow = showDimensionInBestUnit($object->trueVolume, $object->volume_units, "volume", $outputlangs); } else { diff --git a/htdocs/core/modules/expedition/doc/pdf_rouget.modules.php b/htdocs/core/modules/expedition/doc/pdf_rouget.modules.php index dfaa64aafea81..9d54b5b4e880b 100644 --- a/htdocs/core/modules/expedition/doc/pdf_rouget.modules.php +++ b/htdocs/core/modules/expedition/doc/pdf_rouget.modules.php @@ -583,7 +583,7 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede $weighttxt = round($object->lines[$i]->weight * $object->lines[$i]->qty_shipped, getDolGlobalInt('SHIPMENT_ROUND_WEIGHT_ON_PDF', 5)).' '.measuringUnitString(0, "weight", $object->lines[$i]->weight_units, 1); } $voltxt = ''; - if (empty($object->lines[$i]->fk_product_type) && $object->lines[$i]->volume) { + if (empty($object->lines[$i]->fk_product_type) && $object->lines[$i]->volume && !getDolGlobalString('SHIPPING_PDF_HIDE_VOLUME')) { $voltxt = round($object->lines[$i]->volume * $object->lines[$i]->qty_shipped, getDolGlobalInt('SHIPMENT_ROUND_VOLUME_ON_PDF', 5)).' '.measuringUnitString(0, "volume", $object->lines[$i]->volume_units ? $object->lines[$i]->volume_units : 0, 1); } @@ -769,13 +769,13 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs if (!empty($totalWeight)) { $totalWeighttoshow = showDimensionInBestUnit($totalWeight, 0, "weight", $outputlangs, -1, 'no', 1); } - if (!empty($totalVolume)) { + if (!empty($totalVolume) && !getDolGlobalString('SHIPPING_PDF_HIDE_VOLUME')) { $totalVolumetoshow = showDimensionInBestUnit($totalVolume, 0, "volume", $outputlangs, -1, 'no', 1); } if (!empty($object->trueWeight)) { $totalWeighttoshow = showDimensionInBestUnit($object->trueWeight, (int) $object->weight_units, "weight", $outputlangs); } - if (!empty($object->trueVolume)) { + if (!empty($object->trueVolume) && !getDolGlobalString('SHIPPING_PDF_HIDE_VOLUME')) { $totalVolumetoshow = showDimensionInBestUnit($object->trueVolume, $object->volume_units, "volume", $outputlangs); } diff --git a/htdocs/core/tpl/extrafields_view.tpl.php b/htdocs/core/tpl/extrafields_view.tpl.php index e0dccc9b8ab7b..700824e7ae3f4 100644 --- a/htdocs/core/tpl/extrafields_view.tpl.php +++ b/htdocs/core/tpl/extrafields_view.tpl.php @@ -29,6 +29,7 @@ * @var CommonObject $object * @var Conf $conf * @var DoliDB $db + * @var ExtraFields $extrafields * @var Form $form * @var Translate $langs * @var User $user @@ -81,7 +82,7 @@ $enabled = 1; if ($enabled && isset($extrafields->attributes[$object->table_element]['enabled'][$tmpkeyextra])) { - $enabled = (int) dol_eval($extrafields->attributes[$object->table_element]['enabled'][$tmpkeyextra], 1, 1, '2'); + $enabled = (int) dol_eval((string) $extrafields->attributes[$object->table_element]['enabled'][$tmpkeyextra], 1, 1, '2'); } if ($enabled && isset($extrafields->attributes[$object->table_element]['list'][$tmpkeyextra])) { $enabled = (int) dol_eval($extrafields->attributes[$object->table_element]['list'][$tmpkeyextra], 1, 1, '2'); diff --git a/htdocs/core/triggers/interface_50_modTicket_TicketEmail.class.php b/htdocs/core/triggers/interface_50_modTicket_TicketEmail.class.php index 41b98dcf06d76..9661cdb6416a8 100644 --- a/htdocs/core/triggers/interface_50_modTicket_TicketEmail.class.php +++ b/htdocs/core/triggers/interface_50_modTicket_TicketEmail.class.php @@ -160,11 +160,13 @@ public function runTrigger($action, $object, User $user, Translate $langs, Conf $see_ticket_assignee = 'SeeThisTicketIntomanagementInterface'; // Send email to notification email + // Note: $object->context['disableticketemail'] is set to 1 by public interface at creation because email sending is already managed by page + // $object->context['createdfrompublicinterface'] may also be defined when creation done from public interface if (getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO') && empty($object->context['disableticketemail'])) { - $sendto = !getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO') ? '' : $conf->global->TICKET_NOTIFICATION_EMAIL_TO; - if ($sendto) { - $this->composeAndSendAdminMessage($sendto, $subject_admin, $body_admin, $object, $langs); - } + $sendto = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO'); + // if ($sendto) { // already test, can't be empty + $this->composeAndSendAdminMessage($sendto, $subject_admin, $body_admin, $object, $langs); + // } } // Send email to assignee if an assignee was set at creation @@ -196,7 +198,9 @@ public function runTrigger($action, $object, User $user, Translate $langs, Conf } // Send email to customer - if (!getDolGlobalInt('TICKET_DISABLE_CUSTOMER_MAILS') && empty($object->context['disableticketemail']) && $object->notify_tiers_at_create) { + // Note: $object->context['disableticketemail'] is set to 1 by public interface at creation because email sending is already managed by page + // $object->context['createdfrompublicinterface'] may also be defined when creation done from public interface + if (empty($object->context['disableticketemail']) && $object->notify_tiers_at_create) { $sendto = ''; // if contact selected send to email's contact else send to email's thirdparty @@ -244,15 +248,17 @@ public function runTrigger($action, $object, User $user, Translate $langs, Conf $see_ticket_customer = 'TicketCloseEmailBodyInfosTrackUrlCustomer'; // Send email to notification email + // Note: $object->context['disableticketemail'] is set to 1 by public interface at creation but not at closing if (getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO') && empty($object->context['disableticketemail'])) { - $sendto = !getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO') ? '' : $conf->global->TICKET_NOTIFICATION_EMAIL_TO; - if ($sendto) { - $this->composeAndSendAdminMessage($sendto, $subject_admin, $body_admin, $object, $langs); - } + $sendto = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO'); + // if ($sendto) { // already test, can't be empty + $this->composeAndSendAdminMessage($sendto, $subject_admin, $body_admin, $object, $langs); + // } } // Send email to customer. - if (!getDolGlobalString('TICKET_DISABLE_CUSTOMER_MAILS') && empty($object->context['disableticketemail'])) { + // Note: $object->context['disableticketemail'] is set to 1 by public interface at creation but not at closing + if (empty($object->context['disableticketemail'])) { $linked_contacts = $object->listeContact(-1, 'thirdparty'); $linked_contacts = array_merge($linked_contacts, $object->listeContact(-1, 'internal')); if (empty($linked_contacts) && getDolGlobalString('TICKET_NOTIFY_AT_CLOSING') && !empty($object->fk_soc)) { @@ -353,7 +359,7 @@ private function composeAndSendAdminMessage($sendto, $base_subject, $body, Ticke $message_admin .= '

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

'.$message.'


'; $message_admin .= '

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

'; - $from = getDolGlobalString('MAIN_INFO_SOCIETE_NOM') . '<' . getDolGlobalString('TICKET_NOTIFICATION_EMAIL_FROM').'>'; + $from = (getDolGlobalString('MAIN_INFO_SOCIETE_NOM') ? getDolGlobalString('MAIN_INFO_SOCIETE_NOM') . ' ' : '') . '<' . getDolGlobalString('TICKET_NOTIFICATION_EMAIL_FROM').'>'; $trackid = 'tic'.$object->id; @@ -442,7 +448,7 @@ private function composeAndSendCustomerMessage($sendto, $base_subject, $body, $s $message_customer .= '

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

'; $message_customer .= '

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

'; - $from = (!getDolGlobalString('MAIN_INFO_SOCIETE_NOM') ? '' : getDolGlobalString('MAIN_INFO_SOCIETE_NOM') . ' ').'<' . getDolGlobalString('TICKET_NOTIFICATION_EMAIL_FROM').'>'; + $from = (getDolGlobalString('MAIN_INFO_SOCIETE_NOM') ? getDolGlobalString('MAIN_INFO_SOCIETE_NOM') . ' ' : '').'<' . getDolGlobalString('TICKET_NOTIFICATION_EMAIL_FROM').'>'; $trackid = 'tic'.$object->id; diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php index 532b7ae411ebb..38e18e2302c97 100644 --- a/htdocs/expedition/card.php +++ b/htdocs/expedition/card.php @@ -560,6 +560,14 @@ if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); } + } elseif ($action == 'setdate_shipping' && $user->hasRight('expedition', 'creer')) { + $dateshipping = dol_mktime(GETPOSTINT('ship_hour'), GETPOSTINT('ship_min'), 0, GETPOSTINT('ship_month'), GETPOSTINT('ship_day'), GETPOSTINT('ship_year')); + + $object->fetch($id); + $result = $object->setShippingDate($user, $dateshipping); + if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + } } elseif (in_array($action, array('settracking_number', 'settracking_url', 'settrueWeight', 'settrueWidth', 'settrueHeight', 'settrueDepth', 'setshipping_method_id')) && $user->hasRight('expedition', 'creer')) { // Action update $error = 0; @@ -2061,10 +2069,10 @@ print ''; print ''; if ($action == 'editdate_shipping') { - print '
'; + print ''; print ''; - print ''; - print $form->selectDate($object->date_shipping ? $object->date_shipping : -1, 'liv_', 1, 1, 0, "setdate_shipping", 1, 0); + print ''; + print $form->selectDate($object->date_shipping ? $object->date_shipping : -1, 'ship_', 1, 1, 0, "setdate_shipping", 1, 0); print ''; print '
'; } else { diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index 8a49d6139a6b8..5193c3cde90d7 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -2223,6 +2223,34 @@ public function setDeliveryDate($user, $delivery_date) } } + /** + * Set the shipping date + * + * @param User $user Object user that modify + * @param integer $shipping_date Date of shipping + * @return int Return integer <0 if KO, >0 if OK + */ + public function setShippingDate($user, $shipping_date) + { + if ($user->hasRight('expedition', 'creer')) { + $sql = "UPDATE ".MAIN_DB_PREFIX."expedition"; + $sql .= " SET date_expedition = ".($shipping_date ? "'".$this->db->idate($shipping_date)."'" : 'null'); + $sql .= " WHERE rowid = ".((int) $this->id); + + dol_syslog(get_class($this)."::setShippingDate", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + $this->date_shipping = $shipping_date; + return 1; + } else { + $this->error = $this->db->error(); + return -1; + } + } else { + return -2; + } + } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Fetch deliveries method and return an array. Load array this->meths(rowid=>label). diff --git a/htdocs/install/mysql/migration/19.0.0-20.0.0.sql b/htdocs/install/mysql/migration/19.0.0-20.0.0.sql index b2397e2069cf0..ec3053a6a400c 100644 --- a/htdocs/install/mysql/migration/19.0.0-20.0.0.sql +++ b/htdocs/install/mysql/migration/19.0.0-20.0.0.sql @@ -349,7 +349,8 @@ ALTER TABLE llx_societe_commerciaux ADD COLUMN fk_c_type_contact_code varchar(32 -- VPGSQL8.2 DROP INDEX uk_societe_commerciaux; ALTER TABLE llx_societe_commerciaux ADD UNIQUE INDEX uk_societe_commerciaux_c_type_contact (fk_soc, fk_user, fk_c_type_contact_code); ALTER TABLE llx_c_type_contact ADD INDEX idx_c_type_contact_code (code); -ALTER TABLE llx_societe_commerciaux ADD CONSTRAINT fk_societe_commerciaux_fk_c_type_contact_code FOREIGN KEY (fk_c_type_contact_code) REFERENCES llx_c_type_contact(code); +--Removed, not unique. ALTER TABLE llx_societe_commerciaux ADD CONSTRAINT fk_societe_commerciaux_fk_c_type_contact_code FOREIGN KEY (fk_c_type_contact_code) REFERENCES llx_c_type_contact(code); +ALTER TABLE llx_societe_commerciaux DROP FOREIGN KEY fk_societe_commerciaux_fk_c_type_contact_code; ALTER TABLE llx_societe_commerciaux ADD CONSTRAINT fk_societe_commerciaux_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe(rowid); ALTER TABLE llx_societe_commerciaux ADD CONSTRAINT fk_societe_commerciaux_fk_user FOREIGN KEY (fk_user) REFERENCES llx_user(rowid); diff --git a/htdocs/install/mysql/tables/llx_societe_commerciaux.key.sql b/htdocs/install/mysql/tables/llx_societe_commerciaux.key.sql index 1672ff659c1f4..f4bc719c4ba32 100644 --- a/htdocs/install/mysql/tables/llx_societe_commerciaux.key.sql +++ b/htdocs/install/mysql/tables/llx_societe_commerciaux.key.sql @@ -17,6 +17,6 @@ -- =================================================================== ALTER TABLE llx_societe_commerciaux ADD UNIQUE INDEX uk_societe_commerciaux_c_type_contact (fk_soc, fk_user, fk_c_type_contact_code); -ALTER TABLE llx_societe_commerciaux ADD CONSTRAINT fk_societe_commerciaux_fk_c_type_contact_code FOREIGN KEY (fk_c_type_contact_code) REFERENCES llx_c_type_contact(code); +--Removed, not unique. ALTER TABLE llx_societe_commerciaux ADD CONSTRAINT fk_societe_commerciaux_fk_c_type_contact_code FOREIGN KEY (fk_c_type_contact_code) REFERENCES llx_c_type_contact(code); ALTER TABLE llx_societe_commerciaux ADD CONSTRAINT fk_societe_commerciaux_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe(rowid); ALTER TABLE llx_societe_commerciaux ADD CONSTRAINT fk_societe_commerciaux_fk_user FOREIGN KEY (fk_user) REFERENCES llx_user(rowid); diff --git a/htdocs/langs/en_US/banks.lang b/htdocs/langs/en_US/banks.lang index 7084a3332d782..fc5a428396503 100644 --- a/htdocs/langs/en_US/banks.lang +++ b/htdocs/langs/en_US/banks.lang @@ -133,7 +133,7 @@ DeleteTransaction=Delete entry ConfirmDeleteTransaction=Are you sure you want to delete this entry? ThisWillAlsoDeleteBankRecord=This will also delete generated bank entry BankMovements=Movements -PlannedTransactions=Planned entries +PlannedTransactions=Upcoming entries Graph=Graphs ExportDataset_banque_1=Bank entries and account statement ExportDataset_banque_2=Deposit slip diff --git a/htdocs/langs/en_US/stocks.lang b/htdocs/langs/en_US/stocks.lang index 400a39ec95175..0648dde54b4f4 100644 --- a/htdocs/langs/en_US/stocks.lang +++ b/htdocs/langs/en_US/stocks.lang @@ -348,3 +348,4 @@ QtyViewed=Quantity viewed QtyStock=Quantity on stock QtyRegulated=Quantity on stock correction InventoryEntrepot=Warehouse identity +SelectedWarehouse=Select a warehouse diff --git a/htdocs/langs/en_US/ticket.lang b/htdocs/langs/en_US/ticket.lang index ee2449ce74cdd..39b8ff61ce603 100644 --- a/htdocs/langs/en_US/ticket.lang +++ b/htdocs/langs/en_US/ticket.lang @@ -72,10 +72,10 @@ TicketPublicAccess=A public interface requiring no identification is available a TicketSetupDictionaries=The type of ticket, severity and analytic codes are configurable from dictionaries TicketParamModule=Module variable setup TicketParamMail=Email setup -TicketEmailNotificationFrom=Sender e-mail for notification on answers -TicketEmailNotificationFromHelp=Sender e-mail to use to send the notification email when an answer is provided inside the back office. For example noreply@example.com +TicketEmailNotificationFrom=Sender e-mail for notification on tickets +TicketEmailNotificationFromHelp=Sender e-mail to use to send the notification emails for tickets creation or messages. For example noreply@example.com TicketEmailNotificationTo=Notify ticket creation to this e-mail address -TicketEmailNotificationToHelp=If present, this e-mail address will be notified of a ticket creation +TicketEmailNotificationToHelp=If present, this e-mail address will be notified of a ticket creation (in addition to any other default recipients) TicketNewEmailBodyLabel=Text message sent after creating a ticket TicketNewEmailBodyHelp=The text specified here will be inserted into the email confirming the creation of a new ticket from the public interface. Information on the consultation of the ticket are automatically added. TicketParamPublicInterface=Public interface setup @@ -96,7 +96,9 @@ TicketPublicInterfaceTextHelpMessageHelpAdmin=This text will appear above the me ExtraFieldsTicket=Extra attributes TicketCkEditorEmailNotActivated=HTML editor is not activated. Please put FCKEDITOR_ENABLE_MAIL content to 1 to get it. TicketsDisableEmail=Do not send emails for ticket creation or message recording -TicketsDisableEmailHelp=By default, emails are sent when new tickets or messages created. Enable this option to disable *all* email notifications +TicketsDisableEmailHelp=By default, notification emails to third parties are sent when new tickets or messages are created for both backoffice and public interface. Enable this option to disable email notifications to thirdparties when creation is done from backoffice. +TicketsNotifyThirdPartyFromBackOfficeByDefault=Notify third party by default on ticket creation from backoffice +TicketsNotifyThirdPartyFromBackOfficeByDefaultHelp=When creating a ticket from the backoffice, the option "Notify third party" will be checked by default TicketsLogEnableEmail=Enable log by email TicketsLogEnableEmailHelp=At each change, an email will be sent **to each contact** associated with the ticket. TicketParams=Params @@ -119,7 +121,7 @@ TicketAutoChangeStatusOnAnswerHelp=When a user answers to a ticket, the status w TicketNumberingModules=Tickets numbering module TicketsModelModule=Document templates for tickets TicketNotifyTiersAtCreation=Notify third party at creation -TicketsDisableCustomerEmail=Always disable emails when a ticket is created from public interface +TicketsDisableCustomerEmail=Always disable emails to third parties when a ticket is created from the backoffice TicketsPublicNotificationNewMessage=Send email(s) when a new message/comment is added to a ticket TicketsPublicNotificationNewMessageHelp=Send email(s) when a new message is added from public interface (to assigned user or the notifications email to (update) and/or the notifications email to) TicketPublicNotificationNewMessageDefaultEmail=Notifications email to (update) diff --git a/htdocs/product/price.php b/htdocs/product/price.php index e10fe4caabd13..2ca40d0bad00f 100644 --- a/htdocs/product/price.php +++ b/htdocs/product/price.php @@ -2539,6 +2539,7 @@ function on_change() { $total_ttc = $resultarray[2]; if (!getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) { + print ''."\n"; print ''; print '' . $langs->trans('Default') . ''; @@ -2580,7 +2581,10 @@ function on_change() { print ''; if (!empty($extralabels)) { foreach ($extralabels as $key) { - print ''; + // Show field if not hidden + if (!empty($extrafields->attributes["product_customer_price"]['list'][$key]) && $extrafields->attributes["product_customer_price"]['list'][$key] != 3) { + print ''; + } } } if ($user->hasRight('produit', 'supprimer') || $user->hasRight('service', 'supprimer')) { diff --git a/htdocs/product/stock/class/mouvementstock.class.php b/htdocs/product/stock/class/mouvementstock.class.php index 6f4232b1ca759..45668188f936b 100644 --- a/htdocs/product/stock/class/mouvementstock.class.php +++ b/htdocs/product/stock/class/mouvementstock.class.php @@ -478,7 +478,7 @@ public function _create($user, $fk_product, $entrepot_id, $qty, $type, $price = return -8; } } else { - if (isset($product->stock_warehouse[$entrepot_id]) && (empty($product->stock_warehouse[$entrepot_id]->real) || $product->stock_warehouse[$entrepot_id]->real < abs($qty))) { + if (empty($product->stock_warehouse[$entrepot_id]) || empty($product->stock_warehouse[$entrepot_id]->real) || $product->stock_warehouse[$entrepot_id]->real < abs($qty)) { $langs->load("stocks"); $this->error = $langs->trans('qtyToTranferIsNotEnough').' : '.$product->ref; $this->errors[] = $langs->trans('qtyToTranferIsNotEnough').' : '.$product->ref; diff --git a/htdocs/product/stock/replenish.php b/htdocs/product/stock/replenish.php index 150984d40641c..1f0a72aeb43bb 100644 --- a/htdocs/product/stock/replenish.php +++ b/htdocs/product/stock/replenish.php @@ -745,7 +745,7 @@ $stocklabel = $langs->trans('PhysicalStock'); } if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) { - $stocklabelbis = $stocklabel.' (Selected warehouse)'; + $stocklabelbis = $stocklabel.' ('.$langs->trans('SelectedWarehouse').')'; $stocklabel .= ' ('.$langs->trans("AllWarehouses").')'; } $texte = $langs->trans('Replenishment'); diff --git a/htdocs/projet/tasks.php b/htdocs/projet/tasks.php index 632aa18b6a442..40217eded8899 100644 --- a/htdocs/projet/tasks.php +++ b/htdocs/projet/tasks.php @@ -883,7 +883,7 @@ print ''; } elseif ($id > 0 || !empty($ref)) { - $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields + $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')); // This also change content of $arrayfields // Projet card in view mode @@ -1085,6 +1085,11 @@ include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; + // Fields from hook + $parameters = array('arrayfields' => $arrayfields); + $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + print ' '; // Action column diff --git a/htdocs/public/ticket/ajax/ajax.php b/htdocs/public/ticket/ajax/ajax.php index e28b849eb2d62..a2f57cade82ec 100644 --- a/htdocs/public/ticket/ajax/ajax.php +++ b/htdocs/public/ticket/ajax/ajax.php @@ -57,7 +57,7 @@ * @var DoliDB $db */ - $action = GETPOST('action', 'aZ09'); +$action = GETPOST('action', 'aZ09'); $id = GETPOSTINT('id'); $email = GETPOST('email', 'custom', 0, FILTER_VALIDATE_EMAIL); diff --git a/htdocs/theme/eldy/info-box.inc.php b/htdocs/theme/eldy/info-box.inc.php index c0ae0fa7a93e8..1f5608090d75c 100644 --- a/htdocs/theme/eldy/info-box.inc.php +++ b/htdocs/theme/eldy/info-box.inc.php @@ -447,6 +447,9 @@ .infobox-order_supplier:not(.error) { color: #599caf; } +.infobox-order_supplier::before { + margin-left: 5px; +} .infobox-contrat, .infobox-ticket{ color: #3bbfa8; } diff --git a/htdocs/theme/md/info-box.inc.php b/htdocs/theme/md/info-box.inc.php index 2107fc5bec3f1..71ac51a3d7fea 100644 --- a/htdocs/theme/md/info-box.inc.php +++ b/htdocs/theme/md/info-box.inc.php @@ -136,6 +136,9 @@ .infobox-order_supplier:not(.pictotitle):not(.error) { color: #599caf; } +.infobox-order_supplier::before { + margin-left: 3px; +} .infobox-contrat, .infobox-ticket{ color: #46a676; diff --git a/htdocs/ticket/class/ticket.class.php b/htdocs/ticket/class/ticket.class.php index aafe16ca86894..848abcb41517b 100644 --- a/htdocs/ticket/class/ticket.class.php +++ b/htdocs/ticket/class/ticket.class.php @@ -227,7 +227,7 @@ class Ticket extends CommonObject public $cache_msgs_ticket; /** - * @var int Notify thirdparty at create + * @var int Save if a thirdparty was notified at creation at ticket or not */ public $notify_tiers_at_create; @@ -2186,7 +2186,7 @@ public function setCustomer($id) { if ($this->id) { $sql = "UPDATE ".MAIN_DB_PREFIX."ticket"; - $sql .= " SET fk_soc = ".($id > 0 ? $id : "null"); + $sql .= " SET fk_soc = ".($id > 0 ? (int) $id : "null"); $sql .= " WHERE rowid = ".((int) $this->id); dol_syslog(get_class($this).'::setCustomer sql='.$sql); $resql = $this->db->query($sql); @@ -2210,7 +2210,7 @@ public function setProgression($percent) { if ($this->id) { $sql = "UPDATE ".MAIN_DB_PREFIX."ticket"; - $sql .= " SET progress = ".($percent > 0 ? $percent : "null"); + $sql .= " SET progress = ".($percent > 0 ? (float) $percent : "null"); $sql .= " WHERE rowid = ".((int) $this->id); dol_syslog(get_class($this).'::set_progression sql='.$sql); $resql = $this->db->query($sql); @@ -2234,7 +2234,7 @@ public function setContract($contractid) { if ($this->id) { $sql = "UPDATE ".MAIN_DB_PREFIX."ticket"; - $sql .= " SET fk_contract = ".($contractid > 0 ? $contractid : "null"); + $sql .= " SET fk_contract = ".($contractid > 0 ? (int) $contractid : "null"); $sql .= " WHERE rowid = ".((int) $this->id); dol_syslog(get_class($this).'::setContract sql='.$sql); $resql = $this->db->query($sql); @@ -2778,10 +2778,10 @@ public function newMessage($user, &$action, $private = 1, $public_area = 0) } // Add global email address recipient - if (getDolGlobalString('TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS') && - getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO') && !array_key_exists(getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO'), $sendto) - ) { - $sendto[getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')] = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO'); + if (getDolGlobalString('TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS') && !array_key_exists(getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO'), $sendto)) { + if (getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')) { + $sendto[getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')] = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO'); + } } if (!empty($sendto)) {