dolibarr 24.0.1
html.formmail.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2005-2012 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2010-2011 Juanjo Menent <jmenent@2byte.es>
5 * Copyright (C) 2015-2017 Marcos García <marcosgdf@gmail.com>
6 * Copyright (C) 2015-2017 Nicolas ZABOURI <info@inovea-conseil.com>
7 * Copyright (C) 2018-2025 Frédéric France <frederic.france@free.fr>
8 * Copyright (C) 2022 Charlene Benke <charlene@patas-monkey.com>
9 * Copyright (C) 2023 Anthony Berton <anthony.berton@bb2a.fr>
10 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
11 * Copyright (C) 2026 Nathan Pixodeo <nathan@pixodeo.net>
12 *
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program. If not, see <https://www.gnu.org/licenses/>.
26 */
27
33require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
34require_once DOL_DOCUMENT_ROOT.'/core/class/cemailtemplate.class.php'; // So the class ModelMail that was defined into this file in old version is still available when including this file
35
36
43class FormMail extends Form
44{
48 public $db;
49
55 public $withform;
56
60 public $fromname;
61
65 public $frommail;
66
70 public $fromtype;
71
75 public $fromid;
76
80 public $fromalsorobot;
81
85 public $totype;
86
90 public $toid;
91
95 public $replytoname;
96
100 public $replytomail;
101
105 public $toname;
106
110 public $tomail;
111
115 public $trackid;
116
120 public $inreplyto;
121
125 public $withsubstit; // Show substitution array
129 public $withfrom;
130
134 public $withto; // Show recipient emails
138 public $withreplyto;
139
145 public $withtofree;
149 public $withtocc;
153 public $withtoccc;
157 public $withtopic;
161 public $witherrorsto;
162
166 public $withfile;
167
171 public $withlayout;
172
176 public $withaiprompt;
177
181 public $withmaindocfile;
185 public $withbody;
186
190 public $withfromreadonly;
194 public $withreplytoreadonly;
198 public $withtoreadonly;
202 public $withtoccreadonly;
206 public $witherrorstoreadonly;
210 public $withtocccreadonly;
214 public $withtopicreadonly;
218 public $withbodyreadonly;
222 public $withfilereadonly;
226 public $withdeliveryreceipt;
230 public $withcancel;
234 public $withdeliveryreceiptreadonly;
238 public $withfckeditor;
239
243 public $ckeditortoolbar;
244
248 public $substit = array();
249
253 public $substit_lines = array();
254
258 public $param = array();
259
263 public $withtouser = array();
267 public $withtoccuser = array();
268
272 public $lines_model;
273
277 public $withoptiononeemailperrecipient;
278
279
285 public function __construct($db)
286 {
287 $this->db = $db;
288
289 $this->withform = 1;
290
291 $this->withfrom = 1;
292 $this->withto = 1;
293 $this->withtofree = 1;
294 $this->withtocc = 1;
295 $this->withtoccc = '0';
296 $this->witherrorsto = 0;
297 $this->withtopic = 1;
298 $this->withfile = 0; // 1=Add section "Attached files". 2=Can add files.
299 $this->withmaindocfile = 0; // 1=Add a checkbox "Attach also main document" for mass actions (checked by default), -1=Add checkbox (not checked by default)
300 $this->withbody = 1;
301
302 $this->withfromreadonly = 1;
303 $this->withreplytoreadonly = 1;
304 $this->withtoreadonly = 0;
305 $this->withtoccreadonly = 0;
306 $this->withtocccreadonly = 0;
307 $this->witherrorstoreadonly = 0;
308 $this->withtopicreadonly = 0;
309 $this->withfilereadonly = 0;
310 $this->withbodyreadonly = 0;
311 $this->withdeliveryreceiptreadonly = 0;
312 $this->withfckeditor = -1; // -1 = Auto
313 }
314
315 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
321 public function clear_attached_files()
322 {
323 // phpcs:enable
324 global $conf, $user;
325 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
326
327 // Set tmp user directory
328 $vardir = $conf->user->dir_output."/".$user->id;
329 $upload_dir = $vardir.'/temp/'; // TODO Add $keytoavoidconflict in upload_dir path
330 if (is_dir($upload_dir)) {
331 dol_delete_dir_recursive($upload_dir);
332 }
333
334 $keytoavoidconflict = empty($this->trackid) ? '' : '-'.$this->trackid; // this->trackid must be defined
335 unset($_SESSION["listofpaths".$keytoavoidconflict]);
336 unset($_SESSION["listofnames".$keytoavoidconflict]);
337 unset($_SESSION["listofmimes".$keytoavoidconflict]);
338 }
339
340 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
349 public function add_attached_files($path, $file = '', $type = '')
350 {
351 // phpcs:enable
352 $listofpaths = array();
353 $listofnames = array();
354 $listofmimes = array();
355
356 if (empty($file)) {
357 $file = basename($path);
358 }
359 if (empty($type)) {
360 $type = dol_mimetype($file);
361 }
362
363 $keytoavoidconflict = empty($this->trackid) ? '' : '-'.$this->trackid; // this->trackid must be defined
364 if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) {
365 $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
366 }
367 if (!empty($_SESSION["listofnames".$keytoavoidconflict])) {
368 $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
369 }
370 if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) {
371 $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
372 }
373 if (!in_array($file, $listofnames)) {
374 $listofpaths[] = $path;
375 $listofnames[] = $file;
376 $listofmimes[] = $type;
377 $_SESSION["listofpaths".$keytoavoidconflict] = implode(';', $listofpaths);
378 $_SESSION["listofnames".$keytoavoidconflict] = implode(';', $listofnames);
379 $_SESSION["listofmimes".$keytoavoidconflict] = implode(';', $listofmimes);
380 }
381 }
382
383 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
390 public function remove_attached_files($keytodelete)
391 {
392 // phpcs:enable
393 $listofpaths = array();
394 $listofnames = array();
395 $listofmimes = array();
396
397 $keytoavoidconflict = empty($this->trackid) ? '' : '-'.$this->trackid; // this->trackid must be defined
398 if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) {
399 $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
400 }
401 if (!empty($_SESSION["listofnames".$keytoavoidconflict])) {
402 $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
403 }
404 if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) {
405 $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
406 }
407 if ($keytodelete >= 0) {
408 unset($listofpaths[$keytodelete]);
409 unset($listofnames[$keytodelete]);
410 unset($listofmimes[$keytodelete]);
411 $_SESSION["listofpaths".$keytoavoidconflict] = implode(';', $listofpaths);
412 $_SESSION["listofnames".$keytoavoidconflict] = implode(';', $listofnames);
413 $_SESSION["listofmimes".$keytoavoidconflict] = implode(';', $listofmimes);
414 //var_dump($_SESSION['listofpaths']);
415 }
416 }
417
418 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
424 public function get_attached_files()
425 {
426 // phpcs:enable
427 $listofpaths = array();
428 $listofnames = array();
429 $listofmimes = array();
430
431 $keytoavoidconflict = empty($this->trackid) ? '' : '-'.$this->trackid; // this->trackid must be defined
432 if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) {
433 $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
434 }
435 if (!empty($_SESSION["listofnames".$keytoavoidconflict])) {
436 $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
437 }
438 if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) {
439 $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
440 }
441 return array('paths' => $listofpaths, 'names' => $listofnames, 'mimes' => $listofmimes);
442 }
443
444 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
455 public function show_form($addfileaction = 'addfile', $removefileaction = 'removefile')
456 {
457 // phpcs:enable
458 print $this->get_form($addfileaction, $removefileaction);
459 }
460
461 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
472 public function get_form($addfileaction = 'addfile', $removefileaction = 'removefile')
473 {
474 // phpcs:enable
475 global $conf, $langs, $user, $hookmanager, $form;
476
477 if (!is_object($form)) {
478 $form = new Form($this->db);
479 }
480
481 // Required to show editor assistants
482 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
483 $formfile = new FormFile($this->db);
484
485 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formai.class.php';
486 $formai = new FormAI($this->db);
487
488 // Load translation files required by the page
489 $langs->loadLangs(array('other', 'mails', 'members'));
490
491 // Clear temp files. Must be done before call of triggers, at beginning (mode = init), or when we select a new template
492 if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
493 $this->clear_attached_files();
494 }
495
496 // Call hook getFormMail
497 $hookmanager->initHooks(array('formmail'));
498
499 $parameters = array(
500 'addfileaction' => $addfileaction,
501 'removefileaction' => $removefileaction,
502 'trackid' => $this->trackid
503 );
504 $reshook = $hookmanager->executeHooks('getFormMail', $parameters, $this);
505
506 if (!empty($reshook)) {
507 return $hookmanager->resPrint;
508 } else {
509 $out = '';
510
511 $disablebademails = 1;
512
513 // Define output language
514 $outputlangs = $langs;
515 $newlang = '';
516 if (getDolGlobalInt('MAIN_MULTILANGS') && !empty($this->param['langsmodels'])) {
517 $newlang = $this->param['langsmodels'];
518 }
519 if (!empty($newlang)) {
520 $outputlangs = new Translate("", $conf);
521 $outputlangs->setDefaultLang($newlang);
522 $outputlangs->load('other');
523 }
524
525 // Get message template for $this->param["models"] into c_email_templates
526 $arraydefaultmessage = -1;
527 if ($this->param['models'] != 'none') {
528 $model_id = 0;
529 if (array_key_exists('models_id', $this->param)) {
530 $model_id = $this->param["models_id"];
531 }
532
533 $arraydefaultmessage = $this->getEMailTemplate($this->db, $this->param["models"], $user, $outputlangs, $model_id, 1, '', ($model_id > 0 ? -1 : 1)); // If $model_id is empty, preselect the first one
534 }
535
536 // Define list of attached files
537 $listofpaths = array();
538 $listofnames = array();
539 $listofmimes = array();
540 $keytoavoidconflict = empty($this->trackid) ? '' : '-'.$this->trackid; // this->trackid must be defined
541
542 if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
543 if (!empty($arraydefaultmessage->joinfiles) && !empty($this->param['fileinit']) && is_array($this->param['fileinit'])) {
544 foreach ($this->param['fileinit'] as $path) {
545 if (!empty($path)) {
546 $this->add_attached_files($path);
547 }
548 }
549 }
550 }
551
552 if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) {
553 $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
554 }
555 if (!empty($_SESSION["listofnames".$keytoavoidconflict])) {
556 $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
557 }
558 if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) {
559 $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
560 }
561
562
563 $out .= "\n".'<!-- Begin form mail type='.$this->param["models"].' --><div id="mailformdiv"></div>'."\n";
564 if ($this->withform == 1) {
565 $out .= '<form method="POST" name="mailform" id="mailform" enctype="multipart/form-data" action="'.$this->param["returnurl"].'#formmail">'."\n";
566
567 $out .= '<a id="formmail" name="formmail"></a>';
568 $out .= '<input style="display:none" type="submit" id="sendmailhidden" name="sendmail">';
569 $out .= '<input type="hidden" name="token" value="'.newToken().'" />';
570 $out .= '<input type="hidden" name="page_y" value="" />';
571 $out .= '<input type="hidden" name="trackid" value="'.$this->trackid.'" />';
572 $out .= '<input type="hidden" name="inreplyto" value="'.$this->inreplyto.'" />';
573 }
574 if (!empty($this->withfrom)) {
575 if (!empty($this->withfromreadonly)) {
576 $out .= '<input type="hidden" id="fromname" name="fromname" value="'.$this->fromname.'" />';
577 $out .= '<input type="hidden" id="frommail" name="frommail" value="'.$this->frommail.'" />';
578 }
579 }
580 foreach ($this->param as $key => $value) {
581 if (is_array($value)) {
582 $out .= "<!-- param key=".$key." is array, we do not output input field for it -->\n";
583 } else {
584 $out .= '<input type="hidden" id="'.$key.'" name="'.$key.'" value="'.$value.'" />'."\n";
585 }
586 }
587
588 $modelmail_array = array();
589 $break = '';
590 if ($this->param['models'] != 'none') {
591 $result = $this->fetchAllEMailTemplate($this->param["models"], $user, $outputlangs);
592 if ($result < 0) {
593 setEventMessages($this->error, $this->errors, 'errors');
594 }
595
596 foreach ($this->lines_model as $line) {
597 $reg = array();
598 if (preg_match('/\‍((.*)\‍)/', $line->label, $reg)) {
599 $labeltouse = $langs->trans($reg[1]); // langs->trans when label is __(xxx)__
600 } else {
601 $labeltouse = $line->label;
602 }
603
604 if ($break != $line->lang) {
605 // New break for a new language, we add the break
606 $s = $line->lang;
607 $shtml = '----- '.$langs->trans("Language_".$line->lang).' -----';
608 $modelmail_array['separator_'.$line->lang] = array('label' => $s, 'data-html' => $shtml, 'disabled' => 'disabled');
609 }
610
611 // We escape the $labeltouse to store it into $modelmail_array.
612 $s = dol_escape_htmltag($labeltouse);
613 $shtml = dol_escape_htmltag($labeltouse);
614 if ($line->lang) {
615 $shtml = picto_from_langcode($line->lang).'</span> '.$shtml;
616 }
617 if ($line->private) {
618 $shtml .= ' - <span class="opacitymedium small">'.dol_escape_htmltag($langs->trans("Private")).'</span>';
619 }
620
621 $modelmail_array[$line->id] = array('label' => $s, 'data-html' => $shtml);
622 }
623 }
624
625 // Zone to select email template
626 if (count($modelmail_array) > 0) {
627 $model_mail_selected_id = GETPOSTISSET('modelmailselected') ? GETPOSTINT('modelmailselected') : ($arraydefaultmessage->id > 0 ? $arraydefaultmessage->id : 0);
628
629 // If list of template is filled
630 $out .= '<div class="center" style="padding: 0px 0 12px 0">'."\n";
631
632 $out .= $this->selectarray('modelmailselected', $modelmail_array, $model_mail_selected_id, $langs->trans('SelectMailModel'), 0, 0, '', 0, 0, 0, '', 'minwidth150', 1, '', 0, 1);
633 if ($user->admin) {
634 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFrom", $langs->transnoentitiesnoconv('Setup').' - '.$langs->transnoentitiesnoconv('EMails')), 1);
635 }
636
637 // Language selector for predefined message templates (only when multilang is enabled)
638 if (getDolGlobalInt('MAIN_MULTILANGS')) {
639 // This feature is in conflict with the existing one where all templates are show with the language in a flag so user
640 // can choose the template in the correct language.To avoid duplicate and conflict selection, we currently enable this on a hidden constant.
641 // A solution to be compatible would be to wait the user has selected the template, and the combo to select language is shown if no language is forced for the template.
642 if (getDolGlobalInt('MAIN_MULTILANGS_ASK_LANG_IN_SEPARATE_COMBO')) {
643 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php';
644 $formadmin = new FormAdmin($this->db);
645 $currentlang = (is_object($outputlangs) ? $outputlangs->defaultlang : $langs->defaultlang);
646 $out .= ' &nbsp; ';
647 $out .= $formadmin->select_language($currentlang, 'lang_id', 0, array(), 1, 0, 0, 'maxwidth150');
648 }
649 }
650
651 $out .= '<input type="submit" class="button reposition smallpaddingimp" value="'.$langs->trans('Apply').'" name="modelselected" id="modelselected">';
652 $out .= ' &nbsp; ';
653 $out .= '</div>';
654 } elseif (!empty($this->param['models']) && in_array($this->param['models'], array(
655 'propal_send', 'order_send', 'facture_send',
656 'shipping_send', 'reception_send', 'fichinter_send', 'supplier_proposal_send', 'order_supplier_send',
657 'invoice_supplier_send', 'supplier_payment_send', 'thirdparty', 'contract', 'user', 'recruitmentcandidature_send', 'product_send', 'all'
658 ))) {
659 // If list of template is empty
660 $out .= '<div class="center" style="padding: 0px 0 12px 0">'."\n";
661 $out .= '<span class="opacitymedium">'.$langs->trans('SelectMailModel').':</span> ';
662 $out .= '<select name="modelmailselected" disabled="disabled"><option value="none">'.$langs->trans("NoTemplateDefined").'</option></select>'; // Do not put 'disabled' on 'option' tag, it is already on 'select' and it makes chrome crazy.
663 if ($user->admin) {
664 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFrom", $langs->transnoentitiesnoconv('Setup').' - '.$langs->transnoentitiesnoconv('EMails')), 1);
665 }
666 $out .= ' &nbsp; ';
667 $out .= '<input type="submit" class="button reposition smallpaddingimp" value="'.$langs->trans('Apply').'" name="modelselected" disabled="disabled" id="modelselected">';
668 $out .= ' &nbsp; ';
669 $out .= '</div>';
670 } else {
671 $out .= '<!-- No template available for $this->param["models"] = '.$this->param['models'].' -->';
672 }
673
674
675 $out .= '<table class="tableforemailform boxtablenotop centpercent">'."\n";
676
677 // Substitution array/string
678 $helpforsubstitution = '';
679 if (is_array($this->substit) && count($this->substit)) {
680 $helpforsubstitution .= $langs->trans('AvailableVariables').' :<br><br><span class="small">'."\n";
681 foreach ($this->substit as $key => $val) {
682 // Do not show deprecated variables into the tooltip help of substitution variables
683 if (in_array($key, array('__NEWREF__', '__REFCLIENT__', '__REFSUPPLIER__', '__SUPPLIER_ORDER_DATE_DELIVERY__', '__SUPPLIER_ORDER_DELAY_DELIVERY__'))) {
684 continue;
685 }
686 if (is_array($val)) {
687 $val = implode(', ', $val);
688 } // key __MULTICURRENCY_CODE__ is an array and crashes dolGetFirstLineOfText function which accept only text
689 $helpforsubstitution .= $key.' -> '.$langs->trans(dol_string_nohtmltag(dolGetFirstLineOfText((string) $val))).'<br>';
690 }
691 $helpforsubstitution .= '</span>';
692 }
693
694 /*
695 if (!empty($this->withsubstit)) { // Unset or set ->withsubstit=0 to disable this.
696 $out .= '<tr><td colspan="2" class="right">';
697 if (is_numeric($this->withsubstit)) {
698 $out .= $form->textwithpicto($langs->trans("EMailTestSubstitutionReplacedByGenericValues"), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltip'); // Old usage
699 } else {
700 $out .= $form->textwithpicto($langs->trans('AvailableVariables'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltip'); // New usage
701 }
702 $out .= "</td></tr>\n";
703 }*/
704
705 // From
706 if (!empty($this->withfrom)) {
707 if (!empty($this->withfromreadonly)) {
708 $out .= '<tr><td class="fieldrequired minwidth200">'.$langs->trans("MailFrom").'</td><td>';
709
710 // $this->fromtype is the default value to use to select sender
711 if (!($this->fromtype === 'user' && $this->fromid > 0)
712 && !($this->fromtype === 'company')
713 && !($this->fromtype === 'robot')
714 && !preg_match('/user_aliases/', $this->fromtype)
715 && !preg_match('/global_aliases/', $this->fromtype)
716 && !preg_match('/senderprofile/', $this->fromtype)
717 && !preg_match('/from_template_(\d+)/', $this->fromtype)
718 ) {
719 // Use this->fromname and this->frommail or error if not defined
720 $out .= $this->fromname;
721 if ($this->frommail) {
722 $out .= ' &lt;'.$this->frommail.'&gt;';
723 } else {
724 if ($this->fromtype) {
725 $langs->load('errors');
726 $out .= '<span class="warning"> &lt;'.$langs->trans('ErrorNoMailDefinedForThisUser').'&gt; </span>';
727 }
728 }
729 } else {
730 $liste = array();
731
732 // Add user email
733 if (empty($user->email)) {
734 $langs->load('errors');
735 $s = $user->getFullName($langs).' &lt;'.$langs->trans('ErrorNoMailDefinedForThisUser').'&gt;';
736 } else {
737 $s = $user->getFullName($langs).' &lt;'.$user->email.'&gt;';
738 }
739 $liste['user'] = array('label' => $s, 'data-html' => $s);
740
741 // Add also company main email
742 if (getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')) {
743 $s = getDolGlobalString('MAIN_INFO_SOCIETE_NOM', getDolGlobalString('MAIN_INFO_SOCIETE_EMAIL')).' &lt;' . getDolGlobalString('MAIN_INFO_SOCIETE_MAIL').'&gt;';
744 $liste['company'] = array('label' => $s, 'data-html' => $s);
745 }
746
747 // Add also email aliases if there is some
748 $listaliases = array(
749 'global_aliases' => getDolGlobalString('MAIN_INFO_SOCIETE_MAIL_ALIASES'),
750 );
751
752 if (!empty($arraydefaultmessage->email_from) && !empty($arraydefaultmessage->id)) {
753 $templatemailfrom = ' &lt;'.$arraydefaultmessage->email_from.'&gt;';
754 $liste['from_template_'.((int) $arraydefaultmessage->id)] = array('label' => $templatemailfrom, 'data-html' => $templatemailfrom);
755 }
756
757 // Also add robot email
758 if (!empty($this->fromalsorobot)) {
759 if (getDolGlobalString('MAIN_MAIL_EMAIL_FROM') && getDolGlobalString('MAIN_MAIL_EMAIL_FROM') != getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')) {
760 $s = getDolGlobalString('MAIN_MAIL_EMAIL_FROM');
761 if ($this->frommail) {
762 $s .= ' &lt;' . getDolGlobalString('MAIN_MAIL_EMAIL_FROM').'&gt;';
763 }
764 $liste['main_from'] = array('label' => $s, 'data-html' => $s);
765 }
766 }
767
768 // Add also email aliases from the c_email_senderprofile table
769 $sql = "SELECT rowid, label, email FROM ".$this->db->prefix()."c_email_senderprofile";
770 $sql .= " WHERE active = 1 AND (private = 0 OR private = ".((int) $user->id).") AND entity IN (".getEntity('c_email_senderprofile').")";
771 $sql .= " ORDER BY position";
772 $resql = $this->db->query($sql);
773 if ($resql) {
774 $num = $this->db->num_rows($resql);
775 $i = 0;
776 while ($i < $num) {
777 $obj = $this->db->fetch_object($resql);
778 if ($obj) {
779 $listaliases['senderprofile_'.$obj->rowid] = $obj->label.' <'.$obj->email.'>';
780 }
781 $i++;
782 }
783 } else {
784 dol_print_error($this->db);
785 }
786
787 foreach ($listaliases as $typealias => $listalias) {
788 $posalias = 0;
789 $listaliasarray = explode(',', $listalias);
790 foreach ($listaliasarray as $listaliasval) {
791 $posalias++;
792 $listaliasval = trim($listaliasval);
793 if ($listaliasval) {
794 $listaliasval = preg_replace('/</', '&lt;', $listaliasval);
795 $listaliasval = preg_replace('/>/', '&gt;', $listaliasval);
796 if (!preg_match('/&lt;/', $listaliasval)) {
797 $listaliasval = '&lt;'.$listaliasval.'&gt;';
798 }
799 $liste[$typealias.'_'.$posalias] = array('label' => $listaliasval, 'data-html' => $listaliasval);
800 }
801 }
802 }
803
804 // Using ajaxcombo here make the '<email>' no more visible on list because <emailofuser> is not a valid html tag,
805 // so we transform before each record into $liste to be printable with ajaxcombo by replacing <> into ()
806 // $liste['senderprofile_0_0'] = array('label'=>'rrr', 'data-html'=>'rrr &lt;aaaa&gt;');
807 foreach ($liste as $key => $val) {
808 if (!empty($liste[$key]['data-html'])) {
809 $liste[$key]['data-html'] = str_replace(array('&lt;', '<', '&gt;', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $liste[$key]['data-html']);
810 $liste[$key]['data-html'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('<span class="opacitymedium">(', ')</span>'), $liste[$key]['data-html']);
811 }
812 }
813 $out .= ' '.$form->selectarray('fromtype', $liste, (empty($arraydefaultmessage->email_from) || empty($arraydefaultmessage->id)) ? $this->fromtype : 'from_template_'.((int) $arraydefaultmessage->id), 0, 0, 0, '', 0, 0, 0, '', 'fromforsendingprofile maxwidth200onsmartphone', 1, '', $disablebademails);
814 }
815
816 $out .= "</td></tr>\n";
817 } else {
818 $out .= '<tr><td class="fieldrequired width200">'.$langs->trans("MailFrom")."</td><td>";
819 $out .= $langs->trans("Name").':<input type="text" id="fromname" name="fromname" class="maxwidth200onsmartphone" value="'.$this->fromname.'" />';
820 $out .= '&nbsp; &nbsp; ';
821 $out .= $langs->trans("EMail").':&lt;<input type="text" id="frommail" name="frommail" class="maxwidth200onsmartphone" value="'.$this->frommail.'" />&gt;';
822 $out .= "</td></tr>\n";
823 }
824 }
825
826 // To
827 if (!empty($this->withto) || is_array($this->withto)) {
828 $out .= $this->getHtmlForTo();
829 }
830
831 // To User
832 if (!empty($this->withtouser) && is_array($this->withtouser) && getDolGlobalString('MAIN_MAIL_ENABLED_USER_DEST_SELECT')) {
833 $out .= '<tr><td>';
834 $out .= $langs->trans("MailToUsers");
835 $out .= '</td><td>';
836
837 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
838 $tmparray = $this->withtouser;
839 foreach ($tmparray as $key => $val) {
840 $tmparray[$key] = dol_htmlentities($tmparray[$key], 0, 'UTF-8', true);
841 }
842 $withtoselected = GETPOST("receiveruser", 'array'); // Array of selected value
843 if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') {
844 $withtoselected = array_keys($tmparray);
845 }
846 $out .= $form->multiselectarray("receiveruser", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, "");
847 $out .= "</td></tr>\n";
848 }
849
850 // With option for one email per recipient
851 if (!empty($this->withoptiononeemailperrecipient)) {
852 if (abs($this->withoptiononeemailperrecipient) == 1) {
853 $out .= '<tr><td class="minwidth200">';
854 $out .= $langs->trans("GroupEmails");
855 $out .= '</td><td>';
856 $out .= ' <input type="checkbox" id="oneemailperrecipient" value="1" name="oneemailperrecipient"'.($this->withoptiononeemailperrecipient > 0 ? ' checked="checked"' : '').'> ';
857 $out .= '<label for="oneemailperrecipient">';
858 $out .= $form->textwithpicto($langs->trans("OneEmailPerRecipient"), $langs->trans("WarningIfYouCheckOneRecipientPerEmail"), 1, 'help');
859 $out .= '</label>';
860 //$out .= '<span class="hideonsmartphone opacitymedium">';
861 //$out .= ' - ';
862 //$out .= $langs->trans("WarningIfYouCheckOneRecipientPerEmail");
863 //$out .= '</span>';
864 if (getDolGlobalString('MASS_ACTION_EMAIL_ON_DIFFERENT_THIRPARTIES_ADD_CUSTOM_EMAIL')) {
865 if (!empty($this->withto) && !is_array($this->withto)) {
866 $out .= ' <span class="opacitymedium">'.$langs->trans("or").'</span> <input type="email" name="emailto" value="">';
867 }
868 }
869 $out .= '</td></tr>';
870 } else {
871 $out .= '<tr><td><input type="hidden" name="oneemailperrecipient" value="1"></td><td></td></tr>';
872 }
873 }
874
875 // CC
876 if (!empty($this->withtocc) || is_array($this->withtocc)) {
877 $out .= $this->getHtmlForCc();
878 }
879
880 // To User cc
881 if (!empty($this->withtoccuser) && is_array($this->withtoccuser) && getDolGlobalString('MAIN_MAIL_ENABLED_USER_DEST_SELECT')) {
882 $out .= '<tr><td>';
883 $out .= $langs->trans("MailToCCUsers");
884 $out .= '</td><td>';
885
886 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
887 $tmparray = $this->withtoccuser;
888 foreach ($tmparray as $key => $val) {
889 $tmparray[$key] = dol_htmlentities($tmparray[$key], 0, 'UTF-8', true);
890 }
891 $withtoselected = GETPOST("receiverccuser", 'array'); // Array of selected value
892 if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') {
893 $withtoselected = array_keys($tmparray);
894 }
895 $out .= $form->multiselectarray("receiverccuser", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, "");
896 $out .= "</td></tr>\n";
897 }
898
899 // CCC
900 if (!empty($this->withtoccc) || is_array($this->withtoccc)) {
901 $out .= $this->getHtmlForWithCcc();
902 }
903
904 // Replyto
905 if (!empty($this->withreplyto)) {
906 if ($this->withreplytoreadonly) {
907 $out .= '<input type="hidden" id="replyname" name="replyname" value="'.$this->replytoname.'" />';
908 $out .= '<input type="hidden" id="replymail" name="replymail" value="'.$this->replytomail.'" />';
909 $out .= "<tr><td>".$langs->trans("MailReply")."</td><td>".$this->replytoname.($this->replytomail ? (" &lt;".$this->replytomail."&gt;") : "");
910 $out .= "</td></tr>\n";
911 }
912 }
913
914 // Errorsto
915 if (!empty($this->witherrorsto)) {
916 $out .= $this->getHtmlForWithErrorsTo();
917 }
918
919 // Ask delivery receipt
920 if (!empty($this->withdeliveryreceipt) && getDolGlobalInt('MAIN_EMAIL_SUPPORT_ACK')) {
921 $out .= $this->getHtmlForDeliveryreceipt();
922 }
923
924 // Topic
925 if (!empty($this->withtopic)) {
926 $out .= $this->getHtmlForTopic($arraydefaultmessage, $helpforsubstitution);
927 }
928
929 // Attached files
930 if (!empty($this->withfile)) {
931 $out .= '<tr>';
932 $out .= '<td class="tdtop">'.$langs->trans("MailFile").'</td>';
933
934 $out .= '<td>';
935
936 if ($this->withmaindocfile) {
937 // withmaindocfile is set to 1 or -1 to show the checkbox (-1 = checked or 1 = not checked)
938 if (GETPOSTISSET('sendmail')) {
939 $this->withmaindocfile = (GETPOST('addmaindocfile', 'alpha') ? -1 : 1);
940 } elseif (is_object($arraydefaultmessage) && $arraydefaultmessage->id > 0) {
941 // If a template was selected, we use setup of template to define if join file checkbox is selected or not.
942 $this->withmaindocfile = ($arraydefaultmessage->joinfiles ? -1 : 1);
943 }
944 }
945
946 if (!empty($this->withmaindocfile)) {
947 if ($this->withmaindocfile == 1) {
948 $out .= '<input type="checkbox" id="addmaindocfile" name="addmaindocfile" value="1" />';
949 } elseif ($this->withmaindocfile == -1) {
950 $out .= '<input type="checkbox" id="addmaindocfile" name="addmaindocfile" value="1" checked="checked" />';
951 }
952 if (getDolGlobalString('MAIL_MASS_ACTION_ADD_LAST_IF_MAIN_DOC_NOT_FOUND')) {
953 $out .= ' <label for="addmaindocfile">'.$langs->trans("JoinMainDocOrLastGenerated").'.</label><br>';
954 } else {
955 $out .= ' <label for="addmaindocfile">'.$langs->trans("JoinMainDoc").'.</label><br>';
956 }
957 }
958
959 if (is_numeric($this->withfile)) {
960 // TODO Trick to have param removedfile containing nb of file to delete. But this does not works without javascript
961 $out .= '<input type="hidden" class="removedfilehidden" name="removedfile" value="">'."\n";
962 $out .= '<script nonce="'.getNonce().'" type="text/javascript">';
963 $out .= 'jQuery(document).ready(function () {';
964 $out .= ' jQuery(".removedfile").click(function() {';
965 $out .= ' jQuery(".removedfilehidden").val(jQuery(this).val());';
966 $out .= ' });';
967 $out .= '})';
968 $out .= '</script>'."\n";
969 if (count($listofpaths)) {
970 foreach ($listofpaths as $key => $val) {
971 $relativepathtofile = substr($val, (strlen(DOL_DATA_ROOT) - strlen($val)));
972
973 $entity = (isset($this->param['object_entity']) ? $this->param['object_entity'] : $conf->entity);
974 if ($entity > 1) {
975 $relativepathtofile = str_replace('/'.$entity.'/', '/', $relativepathtofile);
976 }
977 // Try to extract data from full path
978 $formfile_params = array();
979 preg_match('#^(/)(\w+)(/)(.+)$#', $relativepathtofile, $formfile_params);
980
981 $out .= '<div id="attachfile_'.$key.'">';
982 // Preview of attachment
983 $out .= img_mime($listofnames[$key]).$listofnames[$key];
984
985 $out .= ' '.$formfile->showPreview(array('fullname' => $val,'name' => basename($val)), $formfile_params[2], $formfile_params[4], 0, ($entity == 1 ? '' : 'entity='.((int) $entity)));
986
987 if (!$this->withfilereadonly) {
988 $out .= ' <input type="image" style="border: 0px;" src="'.DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/delete.png" value="'.($key + 1).'" class="removedfile input-nobottom" id="removedfile_'.$key.'" name="removedfile_'.$key.'" />';
989 //$out.= ' <a href="'.$_SERVER["PHP_SELF"].'?removedfile='.($key+1).'&id=removedfile_'.$key.'">'.img_delete($langs->trans("Remove"), 'id="removedfile_'.$key.'" name="removedfile_'.$key.'"', 'removedfile input-nobottom').'</a>';
990 }
991 $out .= '<br></div>';
992 }
993 } /*elseif (empty($this->withmaindocfile)) {
994 //$out .= '<span class="opacitymedium">'.$langs->trans("NoAttachedFiles").'</span><br>';
995 }*/
996 if ($this->withfile == 2) {
997 $maxfilesizearray = getMaxFileSizeArray();
998 $maxmin = $maxfilesizearray['maxmin'];
999 if ($maxmin > 0) {
1000 $out .= '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
1001 }
1002 // Can add other files
1003 if (!getDolGlobalString('FROM_MAIL_DONT_USE_INPUT_FILE_MULTIPLE')) {
1004 $out .= '<input type="file" class="flat" id="addedfile" name="addedfile[]" value="'.$langs->trans("Upload").'" multiple />';
1005 } else {
1006 $out .= '<input type="file" class="flat" id="addedfile" name="addedfile" value="'.$langs->trans("Upload").'" />';
1007 }
1008 $out .= ' ';
1009 $out .= '<input type="submit" class="button smallpaddingimp" id="'.$addfileaction.'" name="'.$addfileaction.'" value="'.$langs->trans("MailingAddFile").'" />';
1010 }
1011 } else {
1012 $out .= $this->withfile;
1013 }
1014
1015 $out .= "</td></tr>\n";
1016 }
1017
1018 // Message (+ Links to choose layout or ai prompt)
1019 if (!empty($this->withbody)) {
1020 $defaultmessage = GETPOST('message', 'restricthtml');
1021 if (!GETPOST('modelselected', 'alpha') || GETPOST('modelmailselected') != '-1') {
1022 if ($arraydefaultmessage && $arraydefaultmessage->content) {
1023 $defaultmessage = (string) $arraydefaultmessage->content;
1024 } elseif (!is_numeric($this->withbody)) {
1025 $defaultmessage = $this->withbody;
1026 }
1027 }
1028
1029 // Complete substitution array with the url to make online payment
1030 $paymenturl = '';
1031 // Set the online payment url link into __ONLINE_PAYMENT_URL__ key
1032 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
1033 $validpaymentmethod = getValidOnlinePaymentMethods('');
1034
1035 if (empty($this->substit['__REF__'])) { // @phan-suppress-current-line PhanTypeMismatchProperty
1036 $paymenturl = '';
1037 } else {
1038 $langs->loadLangs(array('paypal', 'other'));
1039 $typeforonlinepayment = 'free';
1040 if ($this->param["models"] == 'order' || $this->param["models"] == 'order_send') {
1041 $typeforonlinepayment = 'order'; // TODO use detection on something else than template
1042 }
1043 if ($this->param["models"] == 'invoice' || $this->param["models"] == 'facture_send') {
1044 $typeforonlinepayment = 'invoice'; // TODO use detection on something else than template
1045 }
1046 if ($this->param["models"] == 'member') {
1047 $typeforonlinepayment = 'member'; // TODO use detection on something else than template
1048 }
1049 $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $this->substit['__REF__']);
1050 $paymenturl = $url;
1051 }
1052
1053 if (count($validpaymentmethod) > 0 && $paymenturl) {
1054 $langs->load('other');
1055 $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = str_replace('\n', "\n", $langs->transnoentities("PredefinedMailContentLink", $paymenturl));
1056 $this->substit['__ONLINE_PAYMENT_URL__'] = $paymenturl;
1057 } elseif (count($validpaymentmethod) > 0) {
1058 $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = '__ONLINE_PAYMENT_TEXT_AND_URL__';
1059 $this->substit['__ONLINE_PAYMENT_URL__'] = '__ONLINE_PAYMENT_URL__';
1060 } else {
1061 $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = '';
1062 $this->substit['__ONLINE_PAYMENT_URL__'] = '';
1063 }
1064
1065 $this->substit['__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__'] = '';
1066
1067 // Generate the string with the template for lines repeated and filled for each line
1068 $lines = '';
1069 $defaultlines = $arraydefaultmessage->content_lines;
1070 if (isset($defaultlines)) {
1071 foreach ($this->substit_lines as $lineid => $substit_line) {
1072 $lines .= make_substitutions($defaultlines, $substit_line, $outputlangs)."\n";
1073 }
1074 }
1075 $this->substit['__LINES__'] = $lines;
1076
1077 $defaultmessage = str_replace('\n', "\n", $defaultmessage);
1078
1079 // Deal with format differences between message and some substitution variables (text / HTML)
1080 $atleastonecomponentishtml = 0;
1081 if (strpos($defaultmessage, '__USER_SIGNATURE__') !== false && dol_textishtml($this->substit['__USER_SIGNATURE__'])) {
1082 $atleastonecomponentishtml++;
1083 }
1084 if (strpos($defaultmessage, '__SENDEREMAIL_SIGNATURE__') !== false && dol_textishtml($this->substit['__SENDEREMAIL_SIGNATURE__'])) {
1085 $atleastonecomponentishtml++;
1086 }
1087 if (strpos($defaultmessage, '__ONLINE_PAYMENT_TEXT_AND_URL__') !== false && dol_textishtml($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'])) {
1088 $atleastonecomponentishtml++;
1089 }
1090 if (strpos($defaultmessage, '__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__') !== false && dol_textishtml($this->substit['__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__'])) {
1091 $atleastonecomponentishtml++;
1092 }
1093 if (dol_textishtml($defaultmessage)) {
1094 $atleastonecomponentishtml++;
1095 }
1096 if ($atleastonecomponentishtml) {
1097 if (!dol_textishtml($this->substit['__USER_SIGNATURE__'])) {
1098 $this->substit['__USER_SIGNATURE__'] = dol_nl2br($this->substit['__USER_SIGNATURE__']);
1099 }
1100 if (!dol_textishtml($this->substit['__SENDEREMAIL_SIGNATURE__'])) {
1101 $this->substit['__SENDEREMAIL_SIGNATURE__'] = dol_nl2br($this->substit['__SENDEREMAIL_SIGNATURE__']);
1102 }
1103 if (!dol_textishtml($this->substit['__LINES__'])) {
1104 $this->substit['__LINES__'] = dol_nl2br($this->substit['__LINES__']);
1105 }
1106 if (!dol_textishtml($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'])) {
1107 $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = dol_nl2br($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__']);
1108 }
1109 if (!dol_textishtml($defaultmessage)) {
1110 $defaultmessage = dol_nl2br($defaultmessage);
1111 }
1112 }
1113
1114 if (GETPOSTISSET("message") && !GETPOST('modelselected')) {
1115 $defaultmessage = GETPOST("message", "restricthtml");
1116 } else {
1117 // Pass $outputlangs so __(TranslationKey)__ in the template body is resolved
1118 // in the language of the selected email template, not the operator's language
1119 // (see issue #34540).
1120 $defaultmessage = make_substitutions($defaultmessage, $this->substit, $outputlangs);
1121 // Clean first \n and br (to avoid empty line when CONTACTCIVNAME is empty)
1122 $defaultmessage = preg_replace("/^(<br>)+/", "", $defaultmessage);
1123 $defaultmessage = preg_replace("/^\n+/", "", $defaultmessage);
1124 }
1125
1126 $out .= '<!-- Message line from get_form -->';
1127 $out .= '<tr>';
1128 $out .= '<td class="tdtop">';
1129 $out .= $form->textwithpicto($langs->trans('MailText'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltipfrombody');
1130 $out .= '</td>';
1131 $out .= '<td class="tdtop">';
1132
1133 $formmail = $this;
1134 $showlinktolayout = ($formmail->withfckeditor && getDolGlobalInt('MAIN_EMAIL_USE_LAYOUT')) ? $formmail->withlayout : '';
1135 $showlinktolayoutlabel = $langs->trans("FillMessageWithALayout");
1136 $showlinktoai = ($formmail->withaiprompt && isModEnabled('ai')) ? 'textgenerationemail' : '';
1137 $showlinktoailabel = $langs->trans("AIEnhancements");
1138 $formatforouput = '';
1139 $htmlname = 'message';
1140
1141 $formai->substit = $this->substit;
1142 $formai->substit_lines = $this->substit_lines;
1143
1144 // Fill $out
1145 $db = $this->db;
1146 include DOL_DOCUMENT_ROOT.'/core/tpl/formlayoutai.tpl.php';
1147
1148 $out .= '</td>';
1149 $out .= '</tr>';
1150
1151 $out .= '<tr>';
1152 $out .= '<td colspan="2">';
1153 if ($this->withbodyreadonly) {
1154 $out .= nl2br($defaultmessage);
1155 $out .= '<input type="hidden" id="message" name="message" disabled value="'.$defaultmessage.'" />';
1156 } else {
1157 if (!isset($this->ckeditortoolbar)) {
1158 $this->ckeditortoolbar = 'dolibarr_mailings';
1159 }
1160
1161 // Editor wysiwyg
1162 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1163 if ($this->withfckeditor == -1) {
1164 if (getDolGlobalString('FCKEDITOR_ENABLE_MAIL')) {
1165 $this->withfckeditor = 1;
1166 } else {
1167 $this->withfckeditor = 0;
1168 }
1169 }
1170
1171 $uselocalbrowser = getDolGlobalBool('FCKEDITOR_ENABLE_IMAGE_UPLOAD');
1172 // $uselocalbrowser = true;
1173
1174 $doleditor = new DolEditor('message', $defaultmessage, '', 280, $this->ckeditortoolbar, 'In', true, $uselocalbrowser, $this->withfckeditor, 8, '95%');
1175 $out .= $doleditor->Create(1);
1176 }
1177 $out .= "</td></tr>\n";
1178 }
1179
1180 $out .= '</table>'."\n";
1181
1182 if ($this->withform == 1 || $this->withform == -1) {
1183 $out .= '<div class="center">';
1184 $out .= '<input type="submit" class="button button-add" id="sendmail" name="sendmail" value="'.$langs->trans("SendMail").'"';
1185 // Add a javascript test to avoid to forget to submit file before sending email
1186 if ($this->withfile == 2 && $conf->use_javascript_ajax) {
1187 $out .= ' onClick="if (document.mailform.addedfile.value != \'\') { alert(\''.dol_escape_js($langs->trans("FileWasNotUploaded")).'\'); return false; } else { return true; }"';
1188 }
1189 $out .= ' />';
1190 if ($this->withcancel) {
1191 $out .= '<input class="button button-cancel" type="submit" id="cancel" name="cancel" value="'.$langs->trans("Cancel").'" />';
1192 }
1193 $out .= '</div>'."\n";
1194 }
1195
1196 if ($this->withform == 1) {
1197 $out .= '</form>'."\n";
1198 }
1199
1200 // Disable enter key if option MAIN_MAILFORM_DISABLE_ENTERKEY is set
1201 if (getDolGlobalString('MAIN_MAILFORM_DISABLE_ENTERKEY')) {
1202 $out .= '<script nonce="'.getNonce().'" type="text/javascript">';
1203 $out .= 'jQuery(document).ready(function () {';
1204 $out .= ' $(document).on("keypress", \'#mailform\', function (e) { /* Note this is called at every key pressed ! */
1205 var code = e.keyCode || e.which;
1206 if (code == 13) {
1207 console.log("Enter was intercepted and blocked");
1208 e.preventDefault();
1209 return false;
1210 }
1211 });';
1212 $out .= ' })';
1213 $out .= '</script>';
1214 }
1215
1216 $out .= "<!-- End form mail -->\n";
1217
1218 return $out;
1219 }
1220 }
1221
1227 public function getHtmlForTo()
1228 {
1229 global $langs, $form;
1230 $out = '<tr><td class="fieldrequired">';
1231 if ($this->withtofree) {
1232 $out .= $form->textwithpicto($langs->trans("MailTo"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"));
1233 } else {
1234 $out .= $langs->trans("MailTo");
1235 }
1236 $out .= '</td><td>';
1237 if ($this->withtoreadonly) {
1238 if (!empty($this->toname) && !empty($this->tomail)) {
1239 $out .= '<input type="hidden" id="toname" name="toname" value="'.$this->toname.'" />';
1240 $out .= '<input type="hidden" id="tomail" name="tomail" value="'.$this->tomail.'" />';
1241 if ($this->totype == 'thirdparty') {
1242 $soc = new Societe($this->db);
1243 $soc->fetch($this->toid);
1244 $out .= $soc->getNomUrl(1);
1245 } elseif ($this->totype == 'contact') {
1246 $contact = new Contact($this->db);
1247 $contact->fetch($this->toid);
1248 $out .= $contact->getNomUrl(1);
1249 } else {
1250 $out .= $this->toname;
1251 }
1252 $out .= ' &lt;'.$this->tomail.'&gt;';
1253 if ($this->withtofree) {
1254 $out .= '<br>'.$langs->trans("and").' <input class="minwidth200" id="sendto" name="sendto" spellcheck="false" value="'.(!is_array($this->withto) && !is_numeric($this->withto) ? (GETPOSTISSET("sendto") ? GETPOST("sendto") : $this->withto) : "").'" />';
1255 }
1256 } else {
1257 // Note withto may be a text like 'AllRecipientSelected'
1258 $out .= (!is_array($this->withto) && !is_numeric($this->withto)) ? $this->withto : "";
1259 }
1260 } else {
1261 // The free input of email
1262 if (!empty($this->withtofree)) {
1263 $out .= '<input class="minwidth200" id="sendto" name="sendto" spellcheck="false" value="'.(($this->withtofree && !is_numeric($this->withtofree)) ? $this->withtofree : (!is_array($this->withto) && !is_numeric($this->withto) ? (GETPOSTISSET("sendto") ? GETPOST("sendto") : $this->withto) : "")).'" />';
1264 }
1265 // The select combo
1266 if (!empty($this->withto) && is_array($this->withto)) {
1267 if (!empty($this->withtofree)) {
1268 $out .= ' <span class="opacitymedium">'.$langs->trans("and")."/".$langs->trans("or")."</span> ";
1269 }
1270
1271 $tmparray = $this->withto;
1272 foreach ($tmparray as $key => $val) {
1273 if (is_array($val)) {
1274 $label = $val['label'];
1275 } else {
1276 $label = $val;
1277 }
1278
1279 $tmparray[$key] = array();
1280 $tmparray[$key]['id'] = $key;
1281
1282 $tmparray[$key]['label'] = $label;
1283 $tmparray[$key]['label'] = str_replace(array('<', '>'), array('(', ')'), $tmparray[$key]['label']);
1284 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
1285 $tmparray[$key]['label'] = dol_htmlentities($tmparray[$key]['label'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', true);
1286
1287 $tmparray[$key]['labelhtml'] = $label;
1288 $tmparray[$key]['labelhtml'] = str_replace(array('&lt;', '<', '&gt;', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $tmparray[$key]['labelhtml']);
1289 $tmparray[$key]['labelhtml'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('<span class="opacitymedium">(', ')</span>'), $tmparray[$key]['labelhtml']);
1290 }
1291
1292 $withtoselected = GETPOST("receiver", 'array'); // Array of selected value
1293 if (!getDolGlobalInt('MAIN_MAIL_NO_WITH_TO_SELECTED')) {
1294 if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') {
1295 $withtoselected = array_keys($tmparray);
1296 }
1297 }
1298
1299 $out .= $form->multiselectarray("receiver", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, 0);
1300 }
1301 }
1302 $out .= "</td></tr>\n";
1303 return $out;
1304 }
1305
1311 public function getHtmlForCc()
1312 {
1313 global $langs, $form;
1314 $out = '<tr><td>';
1315 $out .= $form->textwithpicto($langs->trans("MailCC"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"));
1316 $out .= '</td><td>';
1317 if ($this->withtoccreadonly) {
1318 $out .= (!is_array($this->withtocc) && !is_numeric($this->withtocc)) ? $this->withtocc : "";
1319 } else {
1320 $out .= '<input class="minwidth200" id="sendtocc" name="sendtocc" value="'.(GETPOST("sendtocc", "alpha") ? GETPOST("sendtocc", "alpha") : ((!is_array($this->withtocc) && !is_numeric($this->withtocc)) ? $this->withtocc : '')).'" />';
1321 if (!empty($this->withtocc) && is_array($this->withtocc)) {
1322 $out .= ' <span class="opacitymedium">'.$langs->trans("and")."/".$langs->trans("or")."</span> ";
1323
1324 $tmparray = $this->withtocc;
1325 foreach ($tmparray as $key => $val) {
1326 if (is_array($val)) {
1327 $label = $val['label'];
1328 } else {
1329 $label = $val;
1330 }
1331
1332 $tmparray[$key] = array();
1333 $tmparray[$key]['id'] = $key;
1334
1335 $tmparray[$key]['label'] = $label;
1336 $tmparray[$key]['label'] = str_replace(array('<', '>'), array('(', ')'), $tmparray[$key]['label']);
1337 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
1338 $tmparray[$key]['label'] = dol_htmlentities($tmparray[$key]['label'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', true);
1339
1340 $tmparray[$key]['labelhtml'] = $label;
1341 $tmparray[$key]['labelhtml'] = str_replace(array('&lt;', '<', '&gt;', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $tmparray[$key]['labelhtml']);
1342 $tmparray[$key]['labelhtml'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('<span class="opacitymedium">(', ')</span>'), $tmparray[$key]['labelhtml']);
1343 }
1344
1345 $withtoccselected = GETPOST("receivercc", 'array'); // Array of selected value
1346
1347 $out .= $form->multiselectarray("receivercc", $tmparray, $withtoccselected, 0, 0, 'inline-block minwidth500', 0, 0);
1348 }
1349 }
1350 $out .= "</td></tr>\n";
1351 return $out;
1352 }
1353
1360 public function getHtmlForWithCcc()
1361 {
1362 global $langs, $form;
1363
1364 $out = '<tr><td>';
1365 $out .= $form->textwithpicto($langs->trans("MailCCC"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"));
1366 $out .= '</td><td>';
1367 if (!empty($this->withtocccreadonly)) {
1368 $out .= (!is_array($this->withtoccc) && !is_numeric($this->withtoccc)) ? $this->withtoccc : "";
1369 } else {
1370 $out .= '<input class="minwidth200" id="sendtoccc" name="sendtoccc" value="'.(GETPOSTISSET("sendtoccc") ? GETPOST("sendtoccc", "alpha") : ((!is_array($this->withtoccc) && !is_numeric($this->withtoccc)) ? $this->withtoccc : '')).'" />';
1371 if (!empty($this->withtoccc) && is_array($this->withtoccc)) {
1372 $out .= ' <span class="opacitymedium">'.$langs->trans("and")."/".$langs->trans("or")."</span> ";
1373
1374 $tmparray = $this->withtoccc;
1375 foreach ($tmparray as $key => $val) {
1376 if (is_array($val)) {
1377 $label = $val['label'];
1378 } else {
1379 $label = $val;
1380 }
1381 $tmparray[$key] = array();
1382 $tmparray[$key]['id'] = $key;
1383
1384 $tmparray[$key]['label'] = $label;
1385 $tmparray[$key]['label'] = str_replace(array('<', '>'), array('(', ')'), $tmparray[$key]['label']);
1386 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
1387 $tmparray[$key]['label'] = dol_htmlentities($tmparray[$key]['label'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', true);
1388
1389 $tmparray[$key]['labelhtml'] = $label;
1390 $tmparray[$key]['labelhtml'] = str_replace(array('&lt;', '<', '&gt;', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $tmparray[$key]['labelhtml']);
1391 $tmparray[$key]['labelhtml'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('<span class="opacitymedium">(', ')</span>'), $tmparray[$key]['labelhtml']);
1392 }
1393
1394 $withtocccselected = GETPOST("receiverccc", 'array'); // Array of selected value
1395
1396 $out .= $form->multiselectarray("receiverccc", $tmparray, $withtocccselected, 0, 0, 'inline-block minwidth500', 0, 0);
1397 }
1398 }
1399
1400 $showinfobcc = '';
1401 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_PROPOSAL_TO') && !empty($this->param['models']) && $this->param['models'] == 'propal_send') {
1402 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_PROPOSAL_TO');
1403 }
1404 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_ORDER_TO') && !empty($this->param['models']) && $this->param['models'] == 'order_send') {
1405 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_ORDER_TO');
1406 }
1407 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_INVOICE_TO') && !empty($this->param['models']) && $this->param['models'] == 'facture_send') {
1408 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_INVOICE_TO');
1409 }
1410 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_PROPOSAL_TO') && !empty($this->param['models']) && $this->param['models'] == 'supplier_proposal_send') {
1411 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_PROPOSAL_TO');
1412 }
1413 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_ORDER_TO') && !empty($this->param['models']) && $this->param['models'] == 'order_supplier_send') {
1414 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_ORDER_TO');
1415 }
1416 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_INVOICE_TO') && !empty($this->param['models']) && $this->param['models'] == 'invoice_supplier_send') {
1417 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_INVOICE_TO');
1418 }
1419 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_PROJECT_TO') && !empty($this->param['models']) && $this->param['models'] == 'project') { // don't know why there is not '_send' at end of this models name.
1420 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_PROJECT_TO');
1421 }
1422 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SHIPMENT_TO') && !empty($this->param['models']) && $this->param['models'] == 'shipping_send') {
1423 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SHIPMENT_TO');
1424 }
1425 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_RECEPTION_TO') && !empty($this->param['models']) && $this->param['models'] == 'reception_send') {
1426 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_RECEPTION_TO');
1427 }
1428 if ($showinfobcc) {
1429 $out .= ' + '.$showinfobcc;
1430 }
1431 $out .= "</td></tr>\n";
1432 return $out;
1433 }
1434
1440 public function getHtmlForWithErrorsTo()
1441 {
1442 global $langs;
1443
1444 //if (! $this->errorstomail) $this->errorstomail=$this->frommail;
1445 $errorstomail = getDolGlobalString('MAIN_MAIL_ERRORS_TO', (!empty($this->errorstomail) ? $this->errorstomail : ''));
1446 if ($this->witherrorstoreadonly) {
1447 $out = '<tr><td>'.$langs->trans("MailErrorsTo").'</td><td>';
1448 $out .= '<input type="hidden" id="errorstomail" name="errorstomail" value="'.$errorstomail.'" />';
1449 $out .= $errorstomail;
1450 $out .= "</td></tr>\n";
1451 } else {
1452 $out = '<tr><td>'.$langs->trans("MailErrorsTo").'</td><td>';
1453 $out .= '<input class="minwidth200" id="errorstomail" name="errorstomail" value="'.$errorstomail.'" />';
1454 $out .= "</td></tr>\n";
1455 }
1456 return $out;
1457 }
1458
1464 public function getHtmlForDeliveryreceipt()
1465 {
1466 global $langs;
1467
1468 $out = '<tr><td><label for="deliveryreceipt">'.$langs->trans("DeliveryReceipt").'</label></td><td>';
1469
1470 if (!empty($this->withdeliveryreceiptreadonly)) {
1471 $out .= yn($this->withdeliveryreceipt);
1472 } else {
1473 $defaultvaluefordeliveryreceipt = 0;
1474 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_PROPAL') && !empty($this->param['models']) && $this->param['models'] == 'propal_send') {
1475 $defaultvaluefordeliveryreceipt = 1;
1476 }
1477 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_SUPPLIER_PROPOSAL') && !empty($this->param['models']) && $this->param['models'] == 'supplier_proposal_send') {
1478 $defaultvaluefordeliveryreceipt = 1;
1479 }
1480 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_ORDER') && !empty($this->param['models']) && $this->param['models'] == 'order_send') {
1481 $defaultvaluefordeliveryreceipt = 1;
1482 }
1483 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_INVOICE') && !empty($this->param['models']) && $this->param['models'] == 'facture_send') {
1484 $defaultvaluefordeliveryreceipt = 1;
1485 }
1486 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_SUPPLIER_ORDER') && !empty($this->param['models']) && $this->param['models'] == 'order_supplier_send') {
1487 $defaultvaluefordeliveryreceipt = 1;
1488 }
1489 //$out .= $form->selectyesno('deliveryreceipt', (GETPOSTISSET("deliveryreceipt") ? GETPOST("deliveryreceipt") : $defaultvaluefordeliveryreceipt), 1);
1490 $out .= '<input type="checkbox" id="deliveryreceipt" name="deliveryreceipt" value="1"'.((GETPOSTISSET("deliveryreceipt") ? GETPOST("deliveryreceipt") : $defaultvaluefordeliveryreceipt) ? ' checked="checked"' : '').'>';
1491 }
1492 $out .= "</td></tr>\n";
1493 return $out;
1494 }
1495
1503 public function getHtmlForTopic($arraydefaultmessage, $helpforsubstitution)
1504 {
1505 global $conf, $langs, $form;
1506
1507 $defaulttopic = GETPOST('subject', 'restricthtml');
1508
1509 if (!GETPOST('modelselected', 'alpha') || GETPOST('modelmailselected') != '-1') {
1510 if ($arraydefaultmessage && $arraydefaultmessage->topic) {
1511 $defaulttopic = $arraydefaultmessage->topic;
1512 } elseif (!is_numeric($this->withtopic)) {
1513 $defaulttopic = $this->withtopic;
1514 }
1515 }
1516
1517 // Resolve __(TranslationKey)__ in the language of the selected template
1518 // (see issue #34540). Falls back to the caller's language when the template
1519 // has no explicit language pinned.
1520 $outputlangs = $langs;
1521 if (is_object($arraydefaultmessage) && !empty($arraydefaultmessage->lang)) {
1522 $outputlangs = new Translate("", $conf);
1523 $outputlangs->setDefaultLang($arraydefaultmessage->lang);
1524 $outputlangs->load('other');
1525 }
1526
1527 $defaulttopic = make_substitutions($defaulttopic, $this->substit, $outputlangs);
1528
1529 $out = '<tr>';
1530 $out .= '<td class="fieldrequired">';
1531 $out .= $form->textwithpicto($langs->trans('MailTopicShort'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltipfromtopic');
1532 $out .= '</td>';
1533 $out .= '<td>';
1534 if ($this->withtopicreadonly) {
1535 $out .= $defaulttopic;
1536 $out .= '<input type="hidden" class="quatrevingtpercent" id="subject" name="subject" value="'.$defaulttopic.'" spellcheck="false">';
1537 } else {
1538 $out .= '<input type="text" class="quatrevingtpercent" id="subject" name="subject" value="'.((GETPOSTISSET("subject") && !GETPOST('modelselected')) ? GETPOST("subject") : ($defaulttopic ? $defaulttopic : '')).'" spellcheck="false">';
1539 }
1540 $out .= "</td></tr>\n";
1541 return $out;
1542 }
1543
1552 public function getEmailLayoutSelector($htmlContent = 'message', $showlinktolayout = 'email')
1553 {
1554 global $conf, $db, $websitepage, $langs;
1555
1556 require_once DOL_DOCUMENT_ROOT.'/core/lib/emaillayout.lib.php';
1557 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1558 require_once DOL_DOCUMENT_ROOT.'/website/class/website.class.php';
1559 require_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php';
1560
1561 $out = '<div id="template-selector" class="template-selector email-layout-container hidden" style="display:none;">';
1562 $out .= '<div>';
1563
1564 // Define list of email layouts to use
1565 $layouts = array(
1566 'none' => 'None',
1567 );
1568 // Add layouts found on disk in install/doctemplates/maillayout directory
1569 $arrayoflayoutemplates = dol_dir_list(DOL_DOCUMENT_ROOT.'/install/doctemplates/maillayout/', 'files', 0, '\.html$');
1570 foreach ($arrayoflayoutemplates as $layouttemplatefile) {
1571 $layoutname = preg_replace('/\.html$/i', '', $layouttemplatefile['name']);
1572
1573 // Exclude some layouts for some use cases
1574 if ($layoutname == 'news' && (!in_array($showlinktolayout, array('emailing', 'websitepage')) || !isModEnabled('website'))) {
1575 continue;
1576 }
1577 if ($layoutname == 'product' && (!in_array($showlinktolayout, array('emailing', 'websitepage')) || (!isModEnabled('product') && !isModEnabled('service')))) {
1578 continue;
1579 }
1580
1581 $layouts[$layoutname] = ucfirst($layoutname);
1582 }
1583 //}
1584 // TODO Add a hook to allow to complete the list
1585 foreach ($layouts as $layout => $templateFunction) {
1586 $contentHtml = getHtmlOfLayout($layout);
1587
1588 $out .= '<div class="template-option" data-template="'.$layout.'" data-content="'.htmlentities($contentHtml).'">';
1589 $out .= '<img class="maillayout" alt="'.$layout.'" src="'.DOL_URL_ROOT.'/theme/common/maillayout/'.$layout.'.png" />';
1590 $out .= '<span class="template-option-text">'.$langs->trans($templateFunction).'</span>';
1591 $out .= '</div>';
1592 }
1593 $out .= '</div>';
1594
1595 // Prepare the array for multiselect
1596
1597 // Fetch blogs
1598 $blogArray = array();
1599 if (isModEnabled('website')) {
1600 $websitepage = new WebsitePage($this->db);
1601 $arrayofblogs = $websitepage->fetchAll('', 'ASC,DESC', 'fk_website,date_creation', 0, 0, array('type_container' => 'blogpost'));
1602
1603 if (empty($conf->cache['websiteurl'])) {
1604 $conf->cache['websiteurl'] = array();
1605 }
1606
1607 if (!empty($arrayofblogs)) {
1608 foreach ($arrayofblogs as $blog) {
1609 if (!isset($conf->cache['websiteurl'][$blog->id])) {
1610 $tmpwebsite = new Website($db);
1611 $tmpwebsite->fetch($blog->fk_website);
1612 $conf->cache['websiteurl'][$blog->fk_website] = (empty($tmpwebsite->virtualhost) ? $tmpwebsite->ref : $tmpwebsite->virtualhost);
1613 }
1614
1615 $labelwebsite = $conf->cache['websiteurl'][$blog->fk_website];
1616 //$blog->fk_website
1617
1618 $blogArray[$blog->id] = array(
1619 'id' => $blog->id,
1620 'label' => '['.$labelwebsite.' '.$blog->type_container.' '.$blog->id.'] '.dol_trunc($blog->title, 40),
1621 'labelhtml' => '<span class="opacitymedium">['.$labelwebsite.' '.$blog->type_container.' '.$blog->id.']</span> '.dol_trunc($blog->title, 40),
1622 );
1623 }
1624 }
1625 }
1626
1627 // Fetch Product / Services
1628 /* to use with multiselectarray but consume too much memory so replaced
1629 if (in_array('product', array_keys($layouts))) {
1630 $productArray = array();
1631 if (isModEnabled('product') || isModEnabled('service')) {
1632 include_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
1633 $form = new Form($this->db);
1634 $arrayofproduct = $form->select_produits_list(0, 'product-select', '', 0, 0, '', 1, 2, 1);
1635 if (!empty($arrayofproduct)) {
1636 foreach ($arrayofproduct as $product) {
1637 $productArray[$product["key"]] = array(
1638 'id' => $product["key"],
1639 'label' => $product["value"].' - '.dol_trunc($product["label2"], 40),
1640 'labelhtml' => $product["value"].' - '.dol_trunc($product["label2"], 40),
1641 );
1642 }
1643 }
1644 }
1645 }
1646 */
1647
1648 // Use the multiselect array function to create the dropdown
1649 if (in_array('news', array_keys($layouts)) && (isModEnabled('product') || isModEnabled('service'))) {
1650 $out .= '<div id="post-dropdown-container" class="email-layout-container hidden" style="margin-top: 8px; display:none;">';
1651 $out .= '<label for="blogpost-select">Select Posts: </label>';
1652 $out .= '<!-- select component for selection of blog posts -->'."\n";
1653 // TODO WARNING: multiselectarray is ok only for very small list
1654 $out .= self::multiselectarray('blogpost-select', $blogArray, array(), 0, 0, 'minwidth200 select-template');
1655 $out .= ' <input type="submit" class="smallpaddingimp button reposition" name="submit" id="post-submit" value="'.dolPrintHTMLForAttribute($langs->trans("Select")).'">';
1656 $out .= '</div>';
1657 }
1658 if (in_array('product', array_keys($layouts)) && (isModEnabled('product') || isModEnabled('service'))) {
1659 include_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
1660 $form = new Form($this->db);
1661 $out .= '<div id="product-dropdown-container" class="email-layout-container hidden" style="margin-top: 8px; display:none;">';
1662 $out .= '<label for="product-select">'.img_picto('', 'product', 'class="pictofixedwidth"').$langs->trans("Product").' : </label>';
1663 $out .= '<!-- select component for selection of product -->'."\n";
1664 $out .= $form->select_produits(0, 'product-select', '', 0, 0, -1, 2, '', 0, array(), 0, '1', 0, 'inline-block valignmiddle', 0, '', null, 1);
1665 // TODO multiselectarray is ok only for very small list but is ok for multiselect. We need a multiselect ok with ajax for long list
1666 //$out .= self::multiselectarray('product-select', $productArray, array(), 0, 0, 'minwidth200 select-template');
1667 $out .= ' <input type="submit" class="smallpaddingimp button reposition" name="submit" id="product-submit" value="'.dolPrintHTMLForAttribute($langs->trans("Select")).'">';
1668 $out .= '</div>';
1669 }
1670
1671 $out .= '</div>';
1672
1673 $out .= '<!-- Js code to manage choice of an email layout -->'."\n";
1674 $out .= '<script type="text/javascript">
1675 $(document).ready(function() {
1676 $(".template-option").click(function() {
1677 var template = $(this).data("template");
1678 var subject = jQuery("#subject").val();
1679 var fromtype = jQuery("#fromtype").val();
1680 var sendto = jQuery("#sendto").val();
1681 var sendtocc = jQuery("#sendtocc").val();
1682 var sendtoccc = jQuery("#sendtoccc").val();
1683
1684 console.log("We choose a layout for email template=" + template + ", subject="+subject);
1685
1686 $(".template-option").removeClass("selected");
1687 $(this).addClass("selected");
1688 $(".select-template").val("").trigger("change");
1689
1690 if (template === "news") {
1691 $("#post-dropdown-container").show();
1692 $("#product-dropdown-container").hide();
1693 console.log("Displaying dropdown for news selection");
1694 } else if (template === "product") {
1695 $("#product-dropdown-container").show();
1696 $("#post-dropdown-container").hide();
1697 console.log("Displaying dropdown for product selection");
1698 } else {
1699 $("#post-dropdown-container").hide();
1700 $("#product-dropdown-container").hide();
1701 }
1702
1703 var csrfToken = "' .newToken().'";
1704 $.ajax({
1705 type: "POST",
1706 url: "'.DOL_URL_ROOT.'/core/ajax/mailtemplate.php",
1707 data: {
1708 token: csrfToken,
1709 template: template,
1710 subject: subject,
1711 fromtype: fromtype,
1712 sendto: sendto,
1713 sendtocc: sendtocc,
1714 sendtoccc: sendtoccc,
1715 selectedPosts: "[]"
1716 },
1717 success: function(response) {
1718 jQuery("#'.$htmlContent.'").val(response);
1719 var editorInstance = CKEDITOR.instances["'.$htmlContent.'"];
1720 if (editorInstance) {
1721 editorInstance.setData(response);
1722 }
1723 },
1724 error: function(xhr, status, error) {
1725 console.error("An error occurred: " + xhr.responseText);
1726 }
1727 });
1728 });
1729
1730 $("#blogpost-select").change(function() {
1731 var selectedIds = $(this).val();
1732 var contentHtml = $(".template-option.selected").data("content");
1733
1734 updateSelectedPostsContent(contentHtml, selectedIds);
1735 });
1736 $("#product-select").change(function() {
1737 var selectedIds = $(this).val();
1738 var contentHtml = $(".template-option.selected").data("content");
1739
1740 updateSelectedPostsContent(contentHtml, selectedIds);
1741 });
1742
1743 function updateSelectedPostsContent(contentHtml, selectedIds) {
1744 var csrfToken = "' .newToken().'";
1745 template = $(".template-option.selected").data("template");
1746 var subject = $("#subject").val();
1747 $.ajax({
1748 type: "POST",
1749 url: "'.dol_buildpath('/core/ajax/mailtemplate.php', 1).'",
1750 data: {
1751 token: csrfToken,
1752 template: template,
1753 subject: subject,
1754 selectedPosts: JSON.stringify(selectedIds)
1755 },
1756 success: function(response) {
1757 jQuery("#'.$htmlContent.'").val(response);
1758 var editorInstance = CKEDITOR.instances["'.$htmlContent.'"];
1759 if (editorInstance) {
1760 editorInstance.setData(response);
1761 }
1762 },
1763 error: function(xhr, status, error) {
1764 console.error("An error occurred: " + xhr.responseText);
1765 }
1766 });
1767
1768 }
1769 });
1770 </script>';
1771
1772 return $out;
1773 }
1774
1792 public function getEMailTemplate($dbs, $type_template, $user, $outputlangs, $id = 0, $active = 1, $label = '', $defaultfortype = -1)
1793 {
1794 global $conf;
1795
1796 if ($id == -2 && empty($label)) {
1797 $this->error = 'LabelIsMandatoryWhenIdIs-2or-3';
1798 return -1;
1799 }
1800 if ($type_template === 'societe') {
1801 $type_template = 'thirdparty';
1802 }
1803 $ret = new CEmailTemplate($dbs);
1804
1805 $languagetosearch = (is_object($outputlangs) ? $outputlangs->defaultlang : '');
1806 // Define $languagetosearchmain to fall back on main language (for example to get 'es_ES' for 'es_MX')
1807 $tmparray = explode('_', $languagetosearch);
1808 $languagetosearchmain = $tmparray[0].'_'.strtoupper($tmparray[0]);
1809 if ($languagetosearchmain == $languagetosearch) {
1810 $languagetosearchmain = '';
1811 }
1812
1813 $sql = "SELECT rowid, entity, module, label, type_template, topic, email_from, joinfiles, content, content_lines, lang, email_from, email_to, email_tocc, email_tobcc";
1814 $sql .= " FROM ".$dbs->prefix().'c_email_templates';
1815 $sql .= " WHERE (type_template = '".$dbs->escape($type_template)."' OR type_template = '".$dbs->escape($type_template)."_send' OR type_template = 'all')";
1816 $sql .= " AND entity IN (".getEntity('c_email_templates').")";
1817 $sql .= " AND (private = 0 OR fk_user = ".((int) $user->id).")"; // Get all public or private owned
1818 if ($active >= 0) {
1819 $sql .= " AND active = ".((int) $active);
1820 }
1821 if ($defaultfortype >= 0) {
1822 $sql .= " AND defaultfortype = ".((int) $defaultfortype);
1823 }
1824 if ($label) {
1825 $sql .= " AND label = '".$dbs->escape($label)."'";
1826 }
1827 if (!($id > 0) && $languagetosearch) {
1828 $sql .= " AND (lang = '".$dbs->escape($languagetosearch)."'".($languagetosearchmain ? " OR lang = '".$dbs->escape($languagetosearchmain)."'" : "")." OR lang IS NULL OR lang = '')";
1829 }
1830 if ($id > 0) {
1831 $sql .= " AND rowid = ".(int) $id;
1832 }
1833 if ($id == -1) {
1834 $sql .= " AND position = 0";
1835 }
1836 $sql .= " AND entity IN(".getEntity('c_email_templates', 1).")";
1837 if ($languagetosearch) {
1838 $sql .= $dbs->order("position,lang,label", "ASC,DESC,ASC"); // We want line with lang set first, then with lang null or ''
1839 } else {
1840 $sql .= $dbs->order("position,lang,label", "ASC,ASC,ASC"); // If no language provided, we give priority to lang not defined
1841 }
1842 //$sql .= $dbs->plimit(1);
1843 //print $sql;
1844
1845 $resql = $dbs->query($sql);
1846 if (!$resql) {
1847 dol_print_error($dbs);
1848 return -1;
1849 }
1850
1851 // Get first found
1852 while (1) {
1853 $obj = $dbs->fetch_object($resql);
1854
1855 if ($obj) {
1856 // If template is for a module, check module is enabled; if not, take next template
1857 if ($obj->module) {
1858 $tempmodulekey = $obj->module;
1859 if (empty($conf->$tempmodulekey) || !isModEnabled($tempmodulekey)) {
1860 continue;
1861 }
1862 }
1863
1864 // If a record was found
1865 $ret->id = (int) $obj->rowid;
1866 $ret->module = (string) $obj->module;
1867 $ret->label = (string) $obj->label;
1868 $ret->lang = $obj->lang;
1869 $ret->topic = $obj->topic;
1870 $ret->content = (string) $obj->content;
1871 $ret->content_lines = (string) $obj->content_lines;
1872 $ret->joinfiles = $obj->joinfiles;
1873 $ret->email_from = (string) $obj->email_from;
1874 $ret->email_tocc = (string) $obj->email_tocc;
1875 $ret->email_tobcc = (string) $obj->email_tobcc;
1876
1877 break;
1878 } else {
1879 // If no record found
1880 if ($id == -2) {
1881 // Not found with the provided label
1882 return -1;
1883 } else {
1884 // If there is no template at all
1885 $defaultmessage = '';
1886
1887 if ($type_template == 'body') {
1888 // Special case to use this->withbody as content
1889 $defaultmessage = (string) $this->withbody;
1890 } elseif ($type_template == 'facture_send' || $type_template == 'facture' || $type_template == 'facture_relance') {
1891 $defaultmessage = $outputlangs->transnoentitiesnoconv("PredefinedMailContentSendInvoice");
1892 } elseif ($type_template == 'propal_send' || $type_template == 'propal') {
1893 $defaultmessage = $outputlangs->transnoentitiesnoconv("PredefinedMailContentSendProposal");
1894 } elseif ($type_template == 'supplier_proposal_send' || $type_template == 'supplier_proposal') {
1895 $defaultmessage = $outputlangs->transnoentitiesnoconv("PredefinedMailContentSendSupplierProposal");
1896 } elseif ($type_template == 'order_send' || $type_template == 'order') {
1897 $defaultmessage = $outputlangs->transnoentitiesnoconv("PredefinedMailContentSendOrder");
1898 } elseif ($type_template == 'order_supplier_send' || $type_template == 'order_supplier') {
1899 $defaultmessage = $outputlangs->transnoentitiesnoconv("PredefinedMailContentSendSupplierOrder");
1900 } elseif ($type_template == 'invoice_supplier_send' || $type_template == 'invoice_supplier') {
1901 $defaultmessage = $outputlangs->transnoentitiesnoconv("PredefinedMailContentSendSupplierInvoice");
1902 } elseif ($type_template == 'shipping_send' || $type_template == 'shipping') {
1903 $defaultmessage = $outputlangs->transnoentitiesnoconv("PredefinedMailContentSendShipping");
1904 } elseif ($type_template == 'reception_send' || $type_template == 'reception') {
1905 $defaultmessage = $outputlangs->transnoentitiesnoconv("PredefinedMailContentSendReception");
1906 } elseif ($type_template == 'fichinter_send' || $type_template == 'fichinter') {
1907 $defaultmessage = $outputlangs->transnoentitiesnoconv("PredefinedMailContentSendFichInter");
1908 } elseif ($type_template == 'actioncomm_send' || $type_template == 'actioncomm') {
1909 $defaultmessage = $outputlangs->transnoentitiesnoconv("PredefinedMailContentSendActionComm");
1910 } elseif (!empty($type_template)) {
1911 $defaultmessage = $outputlangs->transnoentitiesnoconv("PredefinedMailContentGeneric");
1912 }
1913
1914 $ret->label = 'default';
1915 $ret->lang = $outputlangs->defaultlang;
1916 $ret->topic = '';
1917 $ret->joinfiles = 1;
1918 $ret->content = $defaultmessage;
1919 $ret->content_lines = '';
1920
1921 break;
1922 }
1923 }
1924 }
1925
1926 $dbs->free($resql);
1927
1928 return $ret;
1929 }
1930
1940 public function isEMailTemplate($type_template, $user, $outputlangs)
1941 {
1942 $sql = "SELECT label, topic, content, lang";
1943 $sql .= " FROM ".$this->db->prefix().'c_email_templates';
1944 $sql .= " WHERE type_template='".$this->db->escape($type_template)."'";
1945 $sql .= " AND entity IN (".getEntity('c_email_templates').")";
1946 $sql .= " AND (fk_user is NULL or fk_user = 0 or fk_user = ".((int) $user->id).")";
1947 if (is_object($outputlangs)) {
1948 $sql .= " AND (lang = '".$this->db->escape($outputlangs->defaultlang)."' OR lang IS NULL OR lang = '')";
1949 }
1950 $sql .= $this->db->order("lang,label", "ASC");
1951 //print $sql;
1952
1953 $resql = $this->db->query($sql);
1954 if ($resql) {
1955 $num = $this->db->num_rows($resql);
1956 $this->db->free($resql);
1957 return $num;
1958 } else {
1959 $this->error = get_class($this).' '.__METHOD__.' ERROR:'.$this->db->lasterror();
1960 return -1;
1961 }
1962 }
1963
1974 public function fetchAllEMailTemplate($type_template, $user, $outputlangs, $active = 1)
1975 {
1976 global $db, $conf;
1977
1978 $sql = "SELECT rowid, module, label, topic, content, content_lines, lang, fk_user, private, position";
1979 $sql .= " FROM ".$this->db->prefix().'c_email_templates';
1980 $sql .= " WHERE type_template IN ('".$this->db->escape($type_template)."', 'all')";
1981 $sql .= " AND entity IN (".getEntity('c_email_templates').")";
1982 $sql .= " AND (private = 0 OR fk_user = ".((int) $user->id).")"; // See all public templates or templates I own.
1983 if ($active >= 0) {
1984 $sql .= " AND active = ".((int) $active);
1985 }
1986 //if (is_object($outputlangs)) $sql.= " AND (lang = '".$this->db->escape($outputlangs->defaultlang)."' OR lang IS NULL OR lang = '')"; // Return all languages
1987 $sql .= $this->db->order("lang,position,label", "ASC");
1988 //print $sql;
1989
1990 $resql = $this->db->query($sql);
1991 if ($resql) {
1992 $num = $this->db->num_rows($resql);
1993 $this->lines_model = array();
1994 while ($obj = $this->db->fetch_object($resql)) {
1995 // If template is for a module, check module is enabled.
1996 if ($obj->module) {
1997 $tempmodulekey = $obj->module;
1998 if (empty($conf->$tempmodulekey) || !isModEnabled($tempmodulekey)) {
1999 continue;
2000 }
2001 }
2002
2003 $line = new CEmailTemplate($db);
2004 $line->id = (int) $obj->rowid;
2005 $line->label = (string) $obj->label;
2006 $line->lang = $obj->lang;
2007 $line->fk_user = $obj->fk_user;
2008 $line->private = $obj->private;
2009 $line->position = $obj->position;
2010 $line->topic = $obj->topic;
2011 $line->content = $obj->content;
2012 $line->content_lines = $obj->content_lines;
2013
2014 $this->lines_model[] = $line;
2015 }
2016 $this->db->free($resql);
2017 return $num;
2018 } else {
2019 $this->error = get_class($this).' '.__METHOD__.' ERROR:'.$this->db->lasterror();
2020 return -1;
2021 }
2022 }
2023
2029 private static function normalizeTextForComparison($value)
2030 {
2031 $value = dol_string_nohtmltag((string) $value);
2032 $value = preg_replace('/\s+/', ' ', $value);
2033 return trim((string) $value);
2034 }
2035
2041 private static function getLangPrefix($langcode)
2042 {
2043 $langcode = trim((string) $langcode);
2044 if ($langcode === '') {
2045 return '';
2046 }
2047
2048 $prefix = preg_replace('/[_-].*$/', '', $langcode);
2049 $prefix = strtolower((string) $prefix);
2050 return preg_replace('/[^a-z]/', '', $prefix);
2051 }
2052
2060 private static function getBestProductTranslation($multilangs, $langcode)
2061 {
2062 $langcode = trim((string) $langcode);
2063 if ($langcode === '' || !is_array($multilangs) || empty($multilangs)) {
2064 return array('label' => '', 'description' => '');
2065 }
2066
2067 $prefix = self::getLangPrefix($langcode);
2068 $candidates = array($langcode);
2069 if ($prefix !== '' && $prefix !== $langcode) {
2070 $candidates[] = $prefix;
2071 }
2072
2073 foreach ($candidates as $candidate) {
2074 if (empty($multilangs[$candidate]) || !is_array($multilangs[$candidate])) {
2075 continue;
2076 }
2077 $label = trim((string) (isset($multilangs[$candidate]['label']) ? $multilangs[$candidate]['label'] : ''));
2078 $description = trim((string) (isset($multilangs[$candidate]['description']) ? $multilangs[$candidate]['description'] : ''));
2079 if ($label !== '' || $description !== '') {
2080 return array('label' => $label, 'description' => $description);
2081 }
2082 }
2083
2084 if ($prefix !== '') {
2085 foreach ($multilangs as $code => $row) {
2086 if (!is_array($row)) {
2087 continue;
2088 }
2089 if (!(strpos($code, $prefix.'_') === 0 || strpos($code, $prefix.'-') === 0)) {
2090 continue;
2091 }
2092 $label = trim((string) (isset($row['label']) ? $row['label'] : ''));
2093 $description = trim((string) (isset($row['description']) ? $row['description'] : ''));
2094 if ($label !== '' || $description !== '') {
2095 return array('label' => $label, 'description' => $description);
2096 }
2097 }
2098 }
2099
2100 return array('label' => '', 'description' => '');
2101 }
2102
2110 public function setSubstitFromObject($object, $outputlangs)
2111 {
2112 global $extrafields;
2113
2114 $parameters = array();
2115 $tmparray = getCommonSubstitutionArray($outputlangs, 0, null, $object);
2116 complete_substitutions_array($tmparray, $outputlangs, null, $parameters);
2117
2118 $this->substit = $tmparray;
2119 $targetLang = '';
2120 if (is_object($outputlangs) && !empty($outputlangs->defaultlang)) {
2121 $targetLang = trim((string) $outputlangs->defaultlang);
2122 }
2123
2124 // Fill substit_lines with each object lines content
2125 if (is_array($object->lines)) {
2126 foreach ($object->lines as $line) {
2127 $substit_line = array(
2128 '__PRODUCT_REF__' => isset($line->product_ref) ? $line->product_ref : '',
2129 '__PRODUCT_LABEL__' => isset($line->product_label) ? $line->product_label : '',
2130 '__PRODUCT_DESCRIPTION__' => isset($line->product_desc) ? $line->product_desc : '',
2131 '__LABEL__' => isset($line->label) ? $line->label : '',
2132 '__DESCRIPTION__' => isset($line->desc) ? $line->desc : '',
2133 '__DATE_START_YMD__' => dol_print_date($line->date_start, 'day', false, $outputlangs),
2134 '__DATE_END_YMD__' => dol_print_date($line->date_end, 'day', false, $outputlangs),
2135 '__QUANTITY__' => $line->qty,
2136 '__SUBPRICE__' => price($line->subprice),
2137 '__AMOUNT__' => price($line->total_ttc),
2138 '__AMOUNT_EXCL_TAX__' => price($line->total_ht)
2139 );
2140
2141 // Create dynamic tags for __PRODUCT_EXTRAFIELD_FIELD__
2142 if (!empty($line->fk_product)) {
2143 if (!is_object($extrafields)) {
2144 $extrafields = new ExtraFields($this->db);
2145 }
2146 $product = new Product($this->db);
2147 $product->fetch($line->fk_product, '', '', '1');
2148 $product->fetch_optionals();
2149
2150 if (getDolGlobalInt('MAIN_MULTILANGS') && $targetLang !== '' && !empty($product->multilangs) && is_array($product->multilangs)) {
2151 $translated = self::getBestProductTranslation($product->multilangs, $targetLang);
2152 $translatedLabel = trim((string) (isset($translated['label']) ? $translated['label'] : ''));
2153 $translatedDescription = trim((string) (isset($translated['description']) ? $translated['description'] : ''));
2154
2155 $currentLabelNorm = self::normalizeTextForComparison($substit_line['__PRODUCT_LABEL__']);
2156 $currentProductDescriptionNorm = self::normalizeTextForComparison($substit_line['__PRODUCT_DESCRIPTION__']);
2157 $currentLineDescriptionNorm = self::normalizeTextForComparison($substit_line['__DESCRIPTION__']);
2158 $productLabelNorm = self::normalizeTextForComparison($product->label);
2159 $productDescriptionNorm = self::normalizeTextForComparison($product->description);
2160
2161 if ($translatedLabel !== '' && ($currentLabelNorm === '' || $currentLabelNorm === $productLabelNorm)) {
2162 $substit_line['__PRODUCT_LABEL__'] = $translatedLabel;
2163 }
2164 if ($translatedDescription !== '' && ($currentProductDescriptionNorm === '' || $currentProductDescriptionNorm === $productDescriptionNorm)) {
2165 $substit_line['__PRODUCT_DESCRIPTION__'] = $translatedDescription;
2166 }
2167 if ($translatedDescription !== '' && ($currentLineDescriptionNorm === '' || $currentLineDescriptionNorm === $productDescriptionNorm || $currentLineDescriptionNorm === $currentProductDescriptionNorm)) {
2168 $substit_line['__DESCRIPTION__'] = $translatedDescription;
2169 }
2170 }
2171
2172 $extrafields->fetch_name_optionals_label($product->table_element, true);
2173
2174 if (!empty($extrafields->attributes[$product->table_element]['label']) && is_array($extrafields->attributes[$product->table_element]['label']) && count($extrafields->attributes[$product->table_element]['label']) > 0) {
2175 foreach ($extrafields->attributes[$product->table_element]['label'] as $key => $label) {
2176 $substit_line['__PRODUCT_EXTRAFIELD_'.strtoupper($key).'__'] = isset($product->array_options['options_'.$key]) ? $product->array_options['options_'.$key] : '';
2177 }
2178 }
2179 }
2180
2181 $this->substit_lines[$line->id] = $substit_line; // @phan-suppress-current-line PhanTypeMismatchProperty
2182 }
2183 }
2184 }
2185
2193 public static function getAvailableSubstitKey($mode = 'formemail', $object = null)
2194 {
2195 global $langs;
2196
2197 $tmparray = array();
2198 if ($mode == 'formemail' || $mode == 'formemailwithlines' || $mode == 'formemailforlines') {
2199 $parameters = array('mode' => $mode);
2200 $tmparray = getCommonSubstitutionArray($langs, 2, null, $object); // Note: On email template creation, this may be null because it is related to all type of objects
2201 complete_substitutions_array($tmparray, $langs, null, $parameters);
2202
2203 if ($mode == 'formwithlines') {
2204 $tmparray['__LINES__'] = '__LINES__'; // Will be set by the get_form function
2205 }
2206 if ($mode == 'formforlines') {
2207 $tmparray['__QUANTITY__'] = '__QUANTITY__'; // Will be set by the get_form function
2208 }
2209 }
2210
2211 if ($mode == 'emailing') {
2212 $parameters = array('mode' => $mode);
2213 $tmparray = getCommonSubstitutionArray($langs, 2, array('object', 'objectamount'), $object); // Note: On email template creation, this may be null because it is related to all type of objects
2214 complete_substitutions_array($tmparray, $langs, null, $parameters);
2215
2216 // For mass emailing, we have different keys specific to the data into tagerts list
2217 $tmparray['__ID__'] = 'IdRecord';
2218 $tmparray['__EMAIL__'] = 'EMailRecipient';
2219 $tmparray['__LASTNAME__'] = 'Lastname';
2220 $tmparray['__FIRSTNAME__'] = 'Firstname';
2221 $tmparray['__MAILTOEMAIL__'] = 'TagMailtoEmail';
2222 $tmparray['__OTHER1__'] = 'Other1';
2223 $tmparray['__OTHER2__'] = 'Other2';
2224 $tmparray['__OTHER3__'] = 'Other3';
2225 $tmparray['__OTHER4__'] = 'Other4';
2226 $tmparray['__OTHER5__'] = 'Other5';
2227
2228 $tmparray['__THIRDPARTY_CUSTOMER_CODE__'] = 'CustomerCode'; // If source is a thirdparty
2229
2230 $tmparray['__CHECK_READ__'] = $langs->trans('TagCheckMail');
2231 $tmparray['__UNSUBSCRIBE__'] = $langs->trans('TagUnsubscribe');
2232 $tmparray['__UNSUBSCRIBE_URL__'] = $langs->trans('TagUnsubscribe').' (URL)';
2233
2234 $onlinepaymentenabled = 0;
2235 if (isModEnabled('paypal')) {
2236 $onlinepaymentenabled++;
2237 }
2238 if (isModEnabled('stripe')) {
2239 $onlinepaymentenabled++;
2240 }
2241 if ($onlinepaymentenabled && getDolGlobalString('PAYMENT_SECURITY_TOKEN')) {
2242 $tmparray['__SECUREKEYPAYMENT__'] = getDolGlobalString('PAYMENT_SECURITY_TOKEN');
2243 if (isModEnabled('member')) {
2244 $tmparray['__SECUREKEYPAYMENT_MEMBER__'] = 'SecureKeyPAYMENTUniquePerMember';
2245 }
2246 if (isModEnabled('don')) {
2247 $tmparray['__SECUREKEYPAYMENT_DONATION__'] = 'SecureKeyPAYMENTUniquePerDonation';
2248 }
2249 if (isModEnabled('invoice')) {
2250 $tmparray['__SECUREKEYPAYMENT_INVOICE__'] = 'SecureKeyPAYMENTUniquePerInvoice';
2251 }
2252 if (isModEnabled('order')) {
2253 $tmparray['__SECUREKEYPAYMENT_ORDER__'] = 'SecureKeyPAYMENTUniquePerOrder';
2254 }
2255 if (isModEnabled('contract')) {
2256 $tmparray['__SECUREKEYPAYMENT_CONTRACTLINE__'] = 'SecureKeyPAYMENTUniquePerContractLine';
2257 }
2258
2259 //Online payment link
2260 if (isModEnabled('member')) {
2261 $tmparray['__ONLINEPAYMENTLINK_MEMBER__'] = 'OnlinePaymentLinkUniquePerMember';
2262 }
2263 if (isModEnabled('don')) {
2264 $tmparray['__ONLINEPAYMENTLINK_DONATION__'] = 'OnlinePaymentLinkUniquePerDonation';
2265 }
2266 if (isModEnabled('invoice')) {
2267 $tmparray['__ONLINEPAYMENTLINK_INVOICE__'] = 'OnlinePaymentLinkUniquePerInvoice';
2268 }
2269 if (isModEnabled('order')) {
2270 $tmparray['__ONLINEPAYMENTLINK_ORDER__'] = 'OnlinePaymentLinkUniquePerOrder';
2271 }
2272 if (isModEnabled('contract')) {
2273 $tmparray['__ONLINEPAYMENTLINK_CONTRACTLINE__'] = 'OnlinePaymentLinkUniquePerContractLine';
2274 }
2275 } else {
2276 /* No need to show into tooltip help, option is not enabled
2277 $vars['__SECUREKEYPAYMENT__']='';
2278 $vars['__SECUREKEYPAYMENT_MEMBER__']='';
2279 $vars['__SECUREKEYPAYMENT_INVOICE__']='';
2280 $vars['__SECUREKEYPAYMENT_ORDER__']='';
2281 $vars['__SECUREKEYPAYMENT_CONTRACTLINE__']='';
2282 */
2283 }
2284 if (getDolGlobalString('MEMBER_ENABLE_PUBLIC')) {
2285 $tmparray['__PUBLICLINK_NEWMEMBERFORM__'] = 'BlankSubscriptionForm';
2286 }
2287 }
2288
2289 foreach ($tmparray as $key => $val) {
2290 if (empty($val)) {
2291 $tmparray[$key] = $key;
2292 }
2293 }
2294
2295 return $tmparray;
2296 }
2297}
print $object position
Definition edit.php:206
Class to manage a WYSIWYG editor.
Class to generate HTML forms for single email Usage: $formai = new FormAI($db) $formai->proprietes=1 ...
Class to generate html code for admin pages.
Class to offer components to list and upload files.
Class to manage generation of HTML components Only common components must be here.
static selectarray($htmlname, $array, $id='', $show_empty=0, $key_in_label=0, $value_as_key=0, $moreparam='', $translate=0, $maxlen=0, $disabled=0, $sort='', $morecss='minwidth75', $addjscombo=1, $moreparamonempty='', $disablebademail=0, $nohtmlescape=0)
Return a HTML select string, built from an array of key+value.
Class to manage a HTML form to send a unitary email Usage: $formail = new FormMail($db) $formmail->pr...
get_attached_files()
Return list of attached files (stored in SECTION array)
getHtmlForWithErrorsTo()
get Html For WithErrorsTo
getHtmlForTopic($arraydefaultmessage, $helpforsubstitution)
Return Html section for the Topic of message.
clear_attached_files()
Clear list of attached files in send mail form (also stored in session)
fetchAllEMailTemplate($type_template, $user, $outputlangs, $active=1)
Find if template exists and are available for current user, then set them into $this->lines_model.
getHtmlForCc()
get html For CC
getHtmlForTo()
get html For To
add_attached_files($path, $file='', $type='')
Add a file into the list of attached files (stored in SECTION array)
getHtmlForWithCcc()
get html For WithCCC This information is show when MAIN_EMAIL_USECCC is set.
remove_attached_files($keytodelete)
Remove a file from the list of attached files (stored in SECTION array)
__construct($db)
Constructor.
getHtmlForDeliveryreceipt()
get Html For Asking for Delivery Receipt
getEMailTemplate($dbs, $type_template, $user, $outputlangs, $id=0, $active=1, $label='', $defaultfortype=-1)
Return templates of email with type = $type_template or type = 'all'.
show_form($addfileaction='addfile', $removefileaction='removefile')
Show the form to input an email this->withfile: 0=No attaches files, 1=Show attached files,...
get_form($addfileaction='addfile', $removefileaction='removefile')
Get the form to input an email this->withfile: 0=No attaches files, 1=Show attached files,...
Class to manage products or services.
Class to manage translations.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as p label as s rowid as s nom as s email
Sender: Who sends the email ("Sender" has sent emails on behalf of "From").
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0, $level=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
dol_mimetype($file, $default='application/octet-stream', $mode=0)
Return MIME type of a file from its name with extension.
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
img_mime($file, $titlealt='', $morecss='')
Show MIME img of a file.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0, $nodefault=0)
Return value of a param into GET or POST supervariable.
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
dol_textishtml($msg, $option=0)
Return if a text is a html content.
GETPOSTINT($paramname, $method=0, $nodefault=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
getDolGlobalBool($key, $default=false)
Return a Dolibarr global constant boolean value.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='', $textonpictotooltip='', $cssfordropdown='info_admin')
Show information in HTML for admin users or standard users.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
multi select button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
editval_textarea active
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
buildzip.php
getMaxFileSizeArray()
Return the max allowed for file upload.