dolibarr 25.0.0-alpha
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 Jose MARTINEZ <jose.martinez@pichinov.com>
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 ) {
718 // Use this->fromname and this->frommail or error if not defined
719 $out .= $this->fromname;
720 if ($this->frommail) {
721 $out .= ' &lt;'.$this->frommail.'&gt;';
722 } else {
723 if ($this->fromtype) {
724 $langs->load('errors');
725 $out .= '<span class="warning"> &lt;'.$langs->trans('ErrorNoMailDefinedForThisUser').'&gt; </span>';
726 }
727 }
728 } else {
729 $liste = array();
730
731 // Add user email
732 if (empty($user->email)) {
733 $langs->load('errors');
734 $s = $user->getFullName($langs).' &lt;'.$langs->trans('ErrorNoMailDefinedForThisUser').'&gt;';
735 } else {
736 $s = $user->getFullName($langs).' &lt;'.$user->email.'&gt;';
737 }
738 $liste['user'] = array('label' => $s, 'data-html' => $s);
739
740 // Add also company main email
741 if (getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')) {
742 $s = getDolGlobalString('MAIN_INFO_SOCIETE_NOM', getDolGlobalString('MAIN_INFO_SOCIETE_EMAIL')).' &lt;' . getDolGlobalString('MAIN_INFO_SOCIETE_MAIL').'&gt;';
743 $liste['company'] = array('label' => $s, 'data-html' => $s);
744 }
745
746 // Add also email aliases if there is some
747 $listaliases = array(
748 'global_aliases' => getDolGlobalString('MAIN_INFO_SOCIETE_MAIL_ALIASES'),
749 );
750
751 if (!empty($arraydefaultmessage->email_from) && !empty($arraydefaultmessage->id)) {
752 $templatemailfrom = ' &lt;'.$arraydefaultmessage->email_from.'&gt;';
753 $liste['from_template_'.((int) $arraydefaultmessage->id)] = array('label' => $templatemailfrom, 'data-html' => $templatemailfrom);
754 }
755
756 // Also add robot email
757 if (!empty($this->fromalsorobot)) {
758 if (getDolGlobalString('MAIN_MAIL_EMAIL_FROM') && getDolGlobalString('MAIN_MAIL_EMAIL_FROM') != getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')) {
759 $s = getDolGlobalString('MAIN_MAIL_EMAIL_FROM');
760 if ($this->frommail) {
761 $s .= ' &lt;' . getDolGlobalString('MAIN_MAIL_EMAIL_FROM').'&gt;';
762 }
763 $liste['main_from'] = array('label' => $s, 'data-html' => $s);
764 }
765 }
766
767 // Add also email aliases from the c_email_senderprofile table
768 $sql = "SELECT rowid, label, email FROM ".$this->db->prefix()."c_email_senderprofile";
769 $sql .= " WHERE active = 1 AND (private = 0 OR private = ".((int) $user->id).") AND entity IN (".getEntity('c_email_senderprofile').")";
770 $sql .= " ORDER BY position";
771 $resql = $this->db->query($sql);
772 if ($resql) {
773 $num = $this->db->num_rows($resql);
774 $i = 0;
775 while ($i < $num) {
776 $obj = $this->db->fetch_object($resql);
777 if ($obj) {
778 $listaliases['senderprofile_'.$obj->rowid] = $obj->label.' <'.$obj->email.'>';
779 }
780 $i++;
781 }
782 } else {
783 dol_print_error($this->db);
784 }
785
786 foreach ($listaliases as $typealias => $listalias) {
787 $posalias = 0;
788 $listaliasarray = explode(',', $listalias);
789 foreach ($listaliasarray as $listaliasval) {
790 $posalias++;
791 $listaliasval = trim($listaliasval);
792 if ($listaliasval) {
793 $listaliasval = preg_replace('/</', '&lt;', $listaliasval);
794 $listaliasval = preg_replace('/>/', '&gt;', $listaliasval);
795 if (!preg_match('/&lt;/', $listaliasval)) {
796 $listaliasval = '&lt;'.$listaliasval.'&gt;';
797 }
798 $liste[$typealias.'_'.$posalias] = array('label' => $listaliasval, 'data-html' => $listaliasval);
799 }
800 }
801 }
802
803 // Using ajaxcombo here make the '<email>' no more visible on list because <emailofuser> is not a valid html tag,
804 // so we transform before each record into $liste to be printable with ajaxcombo by replacing <> into ()
805 // $liste['senderprofile_0_0'] = array('label'=>'rrr', 'data-html'=>'rrr &lt;aaaa&gt;');
806 foreach ($liste as $key => $val) {
807 if (!empty($liste[$key]['data-html'])) {
808 $liste[$key]['data-html'] = str_replace(array('&lt;', '<', '&gt;', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $liste[$key]['data-html']);
809 $liste[$key]['data-html'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('<span class="opacitymedium">(', ')</span>'), $liste[$key]['data-html']);
810 }
811 }
812 $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);
813 }
814
815 $out .= "</td></tr>\n";
816 } else {
817 $out .= '<tr><td class="fieldrequired width200">'.$langs->trans("MailFrom")."</td><td>";
818 $out .= $langs->trans("Name").':<input type="text" id="fromname" name="fromname" class="maxwidth200onsmartphone" value="'.$this->fromname.'" />';
819 $out .= '&nbsp; &nbsp; ';
820 $out .= $langs->trans("EMail").':&lt;<input type="text" id="frommail" name="frommail" class="maxwidth200onsmartphone" value="'.$this->frommail.'" />&gt;';
821 $out .= "</td></tr>\n";
822 }
823 }
824
825 // Hook to let a module render the whole recipients block (e.g. a modern tokenized To/CC/BCC field). If the hook handles it (returns > 0), the native recipient rows below are skipped.
826 $parameters = array();
827 $reshook = $hookmanager->executeHooks('printEmailRecipients', $parameters, $this);
828 if ($reshook < 0) {
829 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
830 }
831 $out .= $hookmanager->resPrint;
832 if (empty($reshook)) {
833 // To
834 if (!empty($this->withto) || is_array($this->withto)) {
835 $out .= $this->getHtmlForTo();
836 }
837
838 // To User
839 if (!empty($this->withtouser) && is_array($this->withtouser) && getDolGlobalString('MAIN_MAIL_ENABLED_USER_DEST_SELECT')) {
840 $out .= '<tr><td>';
841 $out .= $langs->trans("MailToUsers");
842 $out .= '</td><td>';
843
844 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
845 $tmparray = $this->withtouser;
846 foreach ($tmparray as $key => $val) {
847 $tmparray[$key] = dol_htmlentities($tmparray[$key], 0, 'UTF-8', true);
848 }
849 $withtoselected = GETPOST("receiveruser", 'array'); // Array of selected value
850 if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') {
851 $withtoselected = array_keys($tmparray);
852 }
853 $out .= $form->multiselectarray("receiveruser", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, "");
854 $out .= "</td></tr>\n";
855 }
856
857 // With option for one email per recipient
858 if (!empty($this->withoptiononeemailperrecipient)) {
859 if (abs($this->withoptiononeemailperrecipient) == 1) {
860 $out .= '<tr><td class="minwidth200">';
861 $out .= $langs->trans("GroupEmails");
862 $out .= '</td><td>';
863 $out .= ' <input type="checkbox" id="oneemailperrecipient" value="1" name="oneemailperrecipient"'.($this->withoptiononeemailperrecipient > 0 ? ' checked="checked"' : '').'> ';
864 $out .= '<label for="oneemailperrecipient">';
865 $out .= $form->textwithpicto($langs->trans("OneEmailPerRecipient"), $langs->trans("WarningIfYouCheckOneRecipientPerEmail"), 1, 'help');
866 $out .= '</label>';
867 //$out .= '<span class="hideonsmartphone opacitymedium">';
868 //$out .= ' - ';
869 //$out .= $langs->trans("WarningIfYouCheckOneRecipientPerEmail");
870 //$out .= '</span>';
871 if (getDolGlobalString('MASS_ACTION_EMAIL_ON_DIFFERENT_THIRPARTIES_ADD_CUSTOM_EMAIL')) {
872 if (!empty($this->withto) && !is_array($this->withto)) {
873 $out .= ' <span class="opacitymedium">'.$langs->trans("or").'</span> <input type="email" name="emailto" value="">';
874 }
875 }
876 $out .= '</td></tr>';
877 } else {
878 $out .= '<tr><td><input type="hidden" name="oneemailperrecipient" value="1"></td><td></td></tr>';
879 }
880 }
881
882 // CC
883 if (!empty($this->withtocc) || is_array($this->withtocc)) {
884 $out .= $this->getHtmlForCc();
885 }
886
887 // To User cc
888 if (!empty($this->withtoccuser) && is_array($this->withtoccuser) && getDolGlobalString('MAIN_MAIL_ENABLED_USER_DEST_SELECT')) {
889 $out .= '<tr><td>';
890 $out .= $langs->trans("MailToCCUsers");
891 $out .= '</td><td>';
892
893 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
894 $tmparray = $this->withtoccuser;
895 foreach ($tmparray as $key => $val) {
896 $tmparray[$key] = dol_htmlentities($tmparray[$key], 0, 'UTF-8', true);
897 }
898 $withtoselected = GETPOST("receiverccuser", 'array'); // Array of selected value
899 if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') {
900 $withtoselected = array_keys($tmparray);
901 }
902 $out .= $form->multiselectarray("receiverccuser", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, "");
903 $out .= "</td></tr>\n";
904 }
905
906 // CCC
907 if (!empty($this->withtoccc) || is_array($this->withtoccc)) {
908 $out .= $this->getHtmlForWithCcc();
909 }
910 }
911
912 // Replyto
913 if (!empty($this->withreplyto)) {
914 if ($this->withreplytoreadonly) {
915 $out .= '<input type="hidden" id="replyname" name="replyname" value="'.$this->replytoname.'" />';
916 $out .= '<input type="hidden" id="replymail" name="replymail" value="'.$this->replytomail.'" />';
917 $out .= "<tr><td>".$langs->trans("MailReply")."</td><td>".$this->replytoname.($this->replytomail ? (" &lt;".$this->replytomail."&gt;") : "");
918 $out .= "</td></tr>\n";
919 }
920 }
921
922 // Errorsto
923 if (!empty($this->witherrorsto)) {
924 $out .= $this->getHtmlForWithErrorsTo();
925 }
926
927 // Ask delivery receipt
928 if (!empty($this->withdeliveryreceipt) && getDolGlobalInt('MAIN_EMAIL_SUPPORT_ACK')) {
929 $out .= $this->getHtmlForDeliveryreceipt();
930 }
931
932 // Topic
933 if (!empty($this->withtopic)) {
934 $out .= $this->getHtmlForTopic($arraydefaultmessage, $helpforsubstitution);
935 }
936
937 // Attached files
938 if (!empty($this->withfile)) {
939 $out .= '<tr>';
940 $out .= '<td class="tdtop">'.$langs->trans("MailFile").'</td>';
941
942 $out .= '<td>';
943
944 if ($this->withmaindocfile) {
945 // withmaindocfile is set to 1 or -1 to show the checkbox (-1 = checked or 1 = not checked)
946 if (GETPOSTISSET('sendmail')) {
947 $this->withmaindocfile = (GETPOST('addmaindocfile', 'alpha') ? -1 : 1);
948 } elseif (is_object($arraydefaultmessage) && $arraydefaultmessage->id > 0) {
949 // If a template was selected, we use setup of template to define if join file checkbox is selected or not.
950 $this->withmaindocfile = ($arraydefaultmessage->joinfiles ? -1 : 1);
951 }
952 }
953
954 if (!empty($this->withmaindocfile)) {
955 if ($this->withmaindocfile == 1) {
956 $out .= '<input type="checkbox" id="addmaindocfile" name="addmaindocfile" value="1" />';
957 } elseif ($this->withmaindocfile == -1) {
958 $out .= '<input type="checkbox" id="addmaindocfile" name="addmaindocfile" value="1" checked="checked" />';
959 }
960 if (getDolGlobalString('MAIL_MASS_ACTION_ADD_LAST_IF_MAIN_DOC_NOT_FOUND')) {
961 $out .= ' <label for="addmaindocfile">'.$langs->trans("JoinMainDocOrLastGenerated").'.</label><br>';
962 } else {
963 $out .= ' <label for="addmaindocfile">'.$langs->trans("JoinMainDoc").'.</label><br>';
964 }
965 }
966
967 if (is_numeric($this->withfile)) {
968 // TODO Trick to have param removedfile containing nb of file to delete. But this does not works without javascript
969 $out .= '<input type="hidden" class="removedfilehidden" name="removedfile" value="">'."\n";
970 $out .= '<script nonce="'.getNonce().'" type="text/javascript">';
971 $out .= 'jQuery(document).ready(function () {';
972 $out .= ' jQuery(".removedfile").click(function() {';
973 $out .= ' jQuery(".removedfilehidden").val(jQuery(this).val());';
974 $out .= ' });';
975 $out .= '})';
976 $out .= '</script>'."\n";
977 if (count($listofpaths)) {
978 foreach ($listofpaths as $key => $val) {
979 $relativepathtofile = substr($val, (strlen(DOL_DATA_ROOT) - strlen($val)));
980
981 $entity = (isset($this->param['object_entity']) ? $this->param['object_entity'] : $conf->entity);
982 if ($entity > 1) {
983 $relativepathtofile = str_replace('/'.$entity.'/', '/', $relativepathtofile);
984 }
985 // Try to extract data from full path
986 $formfile_params = array();
987 preg_match('#^(/)(\w+)(/)(.+)$#', $relativepathtofile, $formfile_params);
988
989 $out .= '<div id="attachfile_'.$key.'">';
990 // Preview of attachment
991 $out .= img_mime($listofnames[$key]).$listofnames[$key];
992
993 $out .= ' '.$formfile->showPreview(array('fullname' => $val,'name' => basename($val)), $formfile_params[2], $formfile_params[4], 0, ($entity == 1 ? '' : 'entity='.((int) $entity)));
994
995 if (!$this->withfilereadonly) {
996 $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.'" />';
997 //$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>';
998 }
999 $out .= '<br></div>';
1000 }
1001 } /*elseif (empty($this->withmaindocfile)) {
1002 //$out .= '<span class="opacitymedium">'.$langs->trans("NoAttachedFiles").'</span><br>';
1003 }*/
1004 if ($this->withfile == 2) {
1005 $maxfilesizearray = getMaxFileSizeArray();
1006 $maxmin = $maxfilesizearray['maxmin'];
1007 if ($maxmin > 0) {
1008 $out .= '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
1009 }
1010 // Can add other files
1011 if (!getDolGlobalString('FROM_MAIL_DONT_USE_INPUT_FILE_MULTIPLE')) {
1012 $out .= '<input type="file" class="flat" id="addedfile" name="addedfile[]" value="'.$langs->trans("Upload").'" multiple />';
1013 } else {
1014 $out .= '<input type="file" class="flat" id="addedfile" name="addedfile" value="'.$langs->trans("Upload").'" />';
1015 }
1016 $out .= ' ';
1017 $out .= '<input type="submit" class="button smallpaddingimp" id="'.$addfileaction.'" name="'.$addfileaction.'" value="'.$langs->trans("MailingAddFile").'" />';
1018 }
1019 } else {
1020 $out .= $this->withfile;
1021 }
1022
1023 $out .= "</td></tr>\n";
1024 }
1025
1026 // Message (+ Links to choose layout or ai prompt)
1027 if (!empty($this->withbody)) {
1028 $defaultmessage = GETPOST('message', 'restricthtml');
1029 if (!GETPOST('modelselected', 'alpha') || GETPOST('modelmailselected') != '-1') {
1030 if ($arraydefaultmessage && $arraydefaultmessage->content) {
1031 $defaultmessage = (string) $arraydefaultmessage->content;
1032 } elseif (!is_numeric($this->withbody)) {
1033 $defaultmessage = $this->withbody;
1034 }
1035 }
1036
1037 // Complete substitution array with the url to make online payment
1038 $paymenturl = '';
1039 // Set the online payment url link into __ONLINE_PAYMENT_URL__ key
1040 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
1041 $validpaymentmethod = getValidOnlinePaymentMethods('');
1042
1043 if (empty($this->substit['__REF__'])) { // @phan-suppress-current-line PhanTypeMismatchProperty
1044 $paymenturl = '';
1045 } else {
1046 $langs->loadLangs(array('paypal', 'other'));
1047 $typeforonlinepayment = 'free';
1048 if ($this->param["models"] == 'order' || $this->param["models"] == 'order_send') {
1049 $typeforonlinepayment = 'order'; // TODO use detection on something else than template
1050 }
1051 if ($this->param["models"] == 'invoice' || $this->param["models"] == 'facture_send') {
1052 $typeforonlinepayment = 'invoice'; // TODO use detection on something else than template
1053 }
1054 if ($this->param["models"] == 'member') {
1055 $typeforonlinepayment = 'member'; // TODO use detection on something else than template
1056 }
1057 $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $this->substit['__REF__']);
1058 $paymenturl = $url;
1059 }
1060
1061 if (count($validpaymentmethod) > 0 && $paymenturl) {
1062 $langs->load('other');
1063 $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = str_replace('\n', "\n", $langs->transnoentities("PredefinedMailContentLink", $paymenturl));
1064 $this->substit['__ONLINE_PAYMENT_URL__'] = $paymenturl;
1065 } elseif (count($validpaymentmethod) > 0) {
1066 $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = '__ONLINE_PAYMENT_TEXT_AND_URL__';
1067 $this->substit['__ONLINE_PAYMENT_URL__'] = '__ONLINE_PAYMENT_URL__';
1068 } else {
1069 $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = '';
1070 $this->substit['__ONLINE_PAYMENT_URL__'] = '';
1071 }
1072
1073 $this->substit['__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__'] = '';
1074
1075 // Generate the string with the template for lines repeated and filled for each line
1076 $lines = '';
1077 $defaultlines = $arraydefaultmessage->content_lines;
1078 if (isset($defaultlines)) {
1079 foreach ($this->substit_lines as $lineid => $substit_line) {
1080 $lines .= make_substitutions($defaultlines, $substit_line, $outputlangs)."\n";
1081 }
1082 }
1083 $this->substit['__LINES__'] = $lines;
1084
1085 $defaultmessage = str_replace('\n', "\n", $defaultmessage);
1086
1087 // Deal with format differences between message and some substitution variables (text / HTML)
1088 $atleastonecomponentishtml = 0;
1089 if (strpos($defaultmessage, '__USER_SIGNATURE__') !== false && dol_textishtml($this->substit['__USER_SIGNATURE__'])) {
1090 $atleastonecomponentishtml++;
1091 }
1092 if (strpos($defaultmessage, '__SENDEREMAIL_SIGNATURE__') !== false && dol_textishtml($this->substit['__SENDEREMAIL_SIGNATURE__'])) {
1093 $atleastonecomponentishtml++;
1094 }
1095 if (strpos($defaultmessage, '__ONLINE_PAYMENT_TEXT_AND_URL__') !== false && dol_textishtml($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'])) {
1096 $atleastonecomponentishtml++;
1097 }
1098 if (strpos($defaultmessage, '__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__') !== false && dol_textishtml($this->substit['__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__'])) {
1099 $atleastonecomponentishtml++;
1100 }
1101 if (dol_textishtml($defaultmessage)) {
1102 $atleastonecomponentishtml++;
1103 }
1104 if ($atleastonecomponentishtml) {
1105 if (!dol_textishtml($this->substit['__USER_SIGNATURE__'])) {
1106 $this->substit['__USER_SIGNATURE__'] = dol_nl2br($this->substit['__USER_SIGNATURE__']);
1107 }
1108 if (!dol_textishtml($this->substit['__SENDEREMAIL_SIGNATURE__'])) {
1109 $this->substit['__SENDEREMAIL_SIGNATURE__'] = dol_nl2br($this->substit['__SENDEREMAIL_SIGNATURE__']);
1110 }
1111 if (!dol_textishtml($this->substit['__LINES__'])) {
1112 $this->substit['__LINES__'] = dol_nl2br($this->substit['__LINES__']);
1113 }
1114 if (!dol_textishtml($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'])) {
1115 $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = dol_nl2br($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__']);
1116 }
1117 if (!dol_textishtml($defaultmessage)) {
1118 $defaultmessage = dol_nl2br($defaultmessage);
1119 }
1120 }
1121
1122 if (GETPOSTISSET("message") && !GETPOST('modelselected')) {
1123 $defaultmessage = GETPOST("message", "restricthtml");
1124 } else {
1125 // Pass $outputlangs so __(TranslationKey)__ in the template body is resolved
1126 // in the language of the selected email template, not the operator's language
1127 // (see issue #34540).
1128 $defaultmessage = make_substitutions($defaultmessage, $this->substit, $outputlangs);
1129 // Clean first \n and br (to avoid empty line when CONTACTCIVNAME is empty)
1130 $defaultmessage = preg_replace("/^(<br>)+/", "", $defaultmessage);
1131 $defaultmessage = preg_replace("/^\n+/", "", $defaultmessage);
1132 }
1133
1134 $out .= '<!-- Message line from get_form -->';
1135 $out .= '<tr>';
1136 $out .= '<td class="tdtop">';
1137 $out .= $form->textwithpicto($langs->trans('MailText'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltipfrombody');
1138 $out .= '</td>';
1139 $out .= '<td class="tdtop">';
1140
1141 $formmail = $this;
1142 $showlinktolayout = ($formmail->withfckeditor && getDolGlobalInt('MAIN_EMAIL_USE_LAYOUT')) ? $formmail->withlayout : '';
1143 $showlinktolayoutlabel = $langs->trans("FillMessageWithALayout");
1144 $showlinktoai = ($formmail->withaiprompt && isModEnabled('ai')) ? 'textgenerationemail' : '';
1145 $showlinktoailabel = $langs->trans("AIEnhancements");
1146 $formatforouput = '';
1147 $htmlname = 'message';
1148
1149 $formai->substit = $this->substit;
1150 $formai->substit_lines = $this->substit_lines;
1151
1152 // Fill $out
1153 $db = $this->db;
1154 include DOL_DOCUMENT_ROOT.'/core/tpl/formlayoutai.tpl.php';
1155
1156 $out .= '</td>';
1157 $out .= '</tr>';
1158
1159 $out .= '<tr>';
1160 $out .= '<td colspan="2">';
1161 if ($this->withbodyreadonly) {
1162 $out .= nl2br($defaultmessage);
1163 $out .= '<input type="hidden" id="message" name="message" disabled value="'.$defaultmessage.'" />';
1164 } else {
1165 if (!isset($this->ckeditortoolbar)) {
1166 $this->ckeditortoolbar = 'dolibarr_mailings';
1167 }
1168
1169 // Editor wysiwyg
1170 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1171 if ($this->withfckeditor == -1) {
1172 if (getDolGlobalString('FCKEDITOR_ENABLE_MAIL')) {
1173 $this->withfckeditor = 1;
1174 } else {
1175 $this->withfckeditor = 0;
1176 }
1177 }
1178
1179 $uselocalbrowser = getDolGlobalBool('FCKEDITOR_ENABLE_IMAGE_UPLOAD');
1180 // $uselocalbrowser = true;
1181
1182 $doleditor = new DolEditor('message', $defaultmessage, '', 280, $this->ckeditortoolbar, 'In', true, $uselocalbrowser, $this->withfckeditor, 8, '95%');
1183 $out .= $doleditor->Create(1);
1184 }
1185 $out .= "</td></tr>\n";
1186 }
1187
1188 $out .= '</table>'."\n";
1189
1190 if ($this->withform == 1 || $this->withform == -1) {
1191 $out .= '<div class="center">';
1192 $out .= '<input type="submit" class="button button-add" id="sendmail" name="sendmail" value="'.$langs->trans("SendMail").'"';
1193 // Add a javascript test to avoid to forget to submit file before sending email
1194 if ($this->withfile == 2 && $conf->use_javascript_ajax) {
1195 $out .= ' onClick="if (document.mailform.addedfile.value != \'\') { alert(\''.dol_escape_js($langs->trans("FileWasNotUploaded")).'\'); return false; } else { return true; }"';
1196 }
1197 $out .= ' />';
1198 if ($this->withcancel) {
1199 $out .= '<input class="button button-cancel" type="submit" id="cancel" name="cancel" value="'.$langs->trans("Cancel").'" />';
1200 }
1201 $out .= '</div>'."\n";
1202 }
1203
1204 if ($this->withform == 1) {
1205 $out .= '</form>'."\n";
1206 }
1207
1208 // Disable enter key if option MAIN_MAILFORM_DISABLE_ENTERKEY is set
1209 if (getDolGlobalString('MAIN_MAILFORM_DISABLE_ENTERKEY')) {
1210 $out .= '<script nonce="'.getNonce().'" type="text/javascript">';
1211 $out .= 'jQuery(document).ready(function () {';
1212 $out .= ' $(document).on("keypress", \'#mailform\', function (e) { /* Note this is called at every key pressed ! */
1213 var code = e.keyCode || e.which;
1214 if (code == 13) {
1215 console.log("Enter was intercepted and blocked");
1216 e.preventDefault();
1217 return false;
1218 }
1219 });';
1220 $out .= ' })';
1221 $out .= '</script>';
1222 }
1223
1224 $out .= "<!-- End form mail -->\n";
1225
1226 return $out;
1227 }
1228 }
1229
1235 public function getHtmlForTo()
1236 {
1237 global $langs, $form;
1238 $out = '<tr><td class="fieldrequired">';
1239 if ($this->withtofree) {
1240 $out .= $form->textwithpicto($langs->trans("MailTo"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"));
1241 } else {
1242 $out .= $langs->trans("MailTo");
1243 }
1244 $out .= '</td><td>';
1245 if ($this->withtoreadonly) {
1246 if (!empty($this->toname) && !empty($this->tomail)) {
1247 $out .= '<input type="hidden" id="toname" name="toname" value="'.$this->toname.'" />';
1248 $out .= '<input type="hidden" id="tomail" name="tomail" value="'.$this->tomail.'" />';
1249 if ($this->totype == 'thirdparty') {
1250 $soc = new Societe($this->db);
1251 $soc->fetch($this->toid);
1252 $out .= $soc->getNomUrl(1);
1253 } elseif ($this->totype == 'contact') {
1254 $contact = new Contact($this->db);
1255 $contact->fetch($this->toid);
1256 $out .= $contact->getNomUrl(1);
1257 } else {
1258 $out .= $this->toname;
1259 }
1260 $out .= ' &lt;'.$this->tomail.'&gt;';
1261 if ($this->withtofree) {
1262 $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) : "").'" />';
1263 }
1264 } else {
1265 // Note withto may be a text like 'AllRecipientSelected'
1266 $out .= (!is_array($this->withto) && !is_numeric($this->withto)) ? $this->withto : "";
1267 }
1268 } else {
1269 // The free input of email
1270 if (!empty($this->withtofree)) {
1271 $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) : "")).'" />';
1272 }
1273 // The select combo
1274 if (!empty($this->withto) && is_array($this->withto)) {
1275 if (!empty($this->withtofree)) {
1276 $out .= ' <span class="opacitymedium">'.$langs->trans("and")."/".$langs->trans("or")."</span> ";
1277 }
1278
1279 $tmparray = $this->withto;
1280 foreach ($tmparray as $key => $val) {
1281 if (is_array($val)) {
1282 $label = $val['label'];
1283 } else {
1284 $label = $val;
1285 }
1286
1287 $tmparray[$key] = array();
1288 $tmparray[$key]['id'] = $key;
1289
1290 $tmparray[$key]['label'] = $label;
1291 $tmparray[$key]['label'] = str_replace(array('<', '>'), array('(', ')'), $tmparray[$key]['label']);
1292 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
1293 $tmparray[$key]['label'] = dol_htmlentities($tmparray[$key]['label'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', true);
1294
1295 $tmparray[$key]['labelhtml'] = $label;
1296 $tmparray[$key]['labelhtml'] = str_replace(array('&lt;', '<', '&gt;', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $tmparray[$key]['labelhtml']);
1297 $tmparray[$key]['labelhtml'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('<span class="opacitymedium">(', ')</span>'), $tmparray[$key]['labelhtml']);
1298 }
1299
1300 $withtoselected = GETPOST("receiver", 'array'); // Array of selected value
1301 if (!getDolGlobalInt('MAIN_MAIL_NO_WITH_TO_SELECTED')) {
1302 if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') {
1303 $withtoselected = array_keys($tmparray);
1304 }
1305 }
1306
1307 $out .= $form->multiselectarray("receiver", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, 0);
1308 }
1309 }
1310 $out .= "</td></tr>\n";
1311 return $out;
1312 }
1313
1319 public function getHtmlForCc()
1320 {
1321 global $langs, $form;
1322 $out = '<tr><td>';
1323 $out .= $form->textwithpicto($langs->trans("MailCC"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"));
1324 $out .= '</td><td>';
1325 if ($this->withtoccreadonly) {
1326 $out .= (!is_array($this->withtocc) && !is_numeric($this->withtocc)) ? $this->withtocc : "";
1327 } else {
1328 $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 : '')).'" />';
1329 if (!empty($this->withtocc) && is_array($this->withtocc)) {
1330 $out .= ' <span class="opacitymedium">'.$langs->trans("and")."/".$langs->trans("or")."</span> ";
1331
1332 $tmparray = $this->withtocc;
1333 foreach ($tmparray as $key => $val) {
1334 if (is_array($val)) {
1335 $label = $val['label'];
1336 } else {
1337 $label = $val;
1338 }
1339
1340 $tmparray[$key] = array();
1341 $tmparray[$key]['id'] = $key;
1342
1343 $tmparray[$key]['label'] = $label;
1344 $tmparray[$key]['label'] = str_replace(array('<', '>'), array('(', ')'), $tmparray[$key]['label']);
1345 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
1346 $tmparray[$key]['label'] = dol_htmlentities($tmparray[$key]['label'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', true);
1347
1348 $tmparray[$key]['labelhtml'] = $label;
1349 $tmparray[$key]['labelhtml'] = str_replace(array('&lt;', '<', '&gt;', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $tmparray[$key]['labelhtml']);
1350 $tmparray[$key]['labelhtml'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('<span class="opacitymedium">(', ')</span>'), $tmparray[$key]['labelhtml']);
1351 }
1352
1353 $withtoccselected = GETPOST("receivercc", 'array'); // Array of selected value
1354
1355 $out .= $form->multiselectarray("receivercc", $tmparray, $withtoccselected, 0, 0, 'inline-block minwidth500', 0, 0);
1356 }
1357 }
1358 $out .= "</td></tr>\n";
1359 return $out;
1360 }
1361
1368 public function getHtmlForWithCcc()
1369 {
1370 global $langs, $form;
1371
1372 $out = '<tr><td>';
1373 $out .= $form->textwithpicto($langs->trans("MailCCC"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"));
1374 $out .= '</td><td>';
1375 if (!empty($this->withtocccreadonly)) {
1376 $out .= (!is_array($this->withtoccc) && !is_numeric($this->withtoccc)) ? $this->withtoccc : "";
1377 } else {
1378 $out .= '<input class="minwidth200" id="sendtoccc" name="sendtoccc" value="'.(GETPOSTISSET("sendtoccc") ? GETPOST("sendtoccc", "alpha") : ((!is_array($this->withtoccc) && !is_numeric($this->withtoccc)) ? $this->withtoccc : '')).'" />';
1379 if (!empty($this->withtoccc) && is_array($this->withtoccc)) {
1380 $out .= ' <span class="opacitymedium">'.$langs->trans("and")."/".$langs->trans("or")."</span> ";
1381
1382 $tmparray = $this->withtoccc;
1383 foreach ($tmparray as $key => $val) {
1384 if (is_array($val)) {
1385 $label = $val['label'];
1386 } else {
1387 $label = $val;
1388 }
1389 $tmparray[$key] = array();
1390 $tmparray[$key]['id'] = $key;
1391
1392 $tmparray[$key]['label'] = $label;
1393 $tmparray[$key]['label'] = str_replace(array('<', '>'), array('(', ')'), $tmparray[$key]['label']);
1394 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
1395 $tmparray[$key]['label'] = dol_htmlentities($tmparray[$key]['label'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', true);
1396
1397 $tmparray[$key]['labelhtml'] = $label;
1398 $tmparray[$key]['labelhtml'] = str_replace(array('&lt;', '<', '&gt;', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $tmparray[$key]['labelhtml']);
1399 $tmparray[$key]['labelhtml'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('<span class="opacitymedium">(', ')</span>'), $tmparray[$key]['labelhtml']);
1400 }
1401
1402 $withtocccselected = GETPOST("receiverccc", 'array'); // Array of selected value
1403
1404 $out .= $form->multiselectarray("receiverccc", $tmparray, $withtocccselected, 0, 0, 'inline-block minwidth500', 0, 0);
1405 }
1406 }
1407
1408 $showinfobcc = '';
1409 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_PROPOSAL_TO') && !empty($this->param['models']) && $this->param['models'] == 'propal_send') {
1410 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_PROPOSAL_TO');
1411 }
1412 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_ORDER_TO') && !empty($this->param['models']) && $this->param['models'] == 'order_send') {
1413 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_ORDER_TO');
1414 }
1415 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_INVOICE_TO') && !empty($this->param['models']) && $this->param['models'] == 'facture_send') {
1416 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_INVOICE_TO');
1417 }
1418 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_PROPOSAL_TO') && !empty($this->param['models']) && $this->param['models'] == 'supplier_proposal_send') {
1419 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_PROPOSAL_TO');
1420 }
1421 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_ORDER_TO') && !empty($this->param['models']) && $this->param['models'] == 'order_supplier_send') {
1422 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_ORDER_TO');
1423 }
1424 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_INVOICE_TO') && !empty($this->param['models']) && $this->param['models'] == 'invoice_supplier_send') {
1425 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_INVOICE_TO');
1426 }
1427 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.
1428 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_PROJECT_TO');
1429 }
1430 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SHIPMENT_TO') && !empty($this->param['models']) && $this->param['models'] == 'shipping_send') {
1431 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SHIPMENT_TO');
1432 }
1433 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_RECEPTION_TO') && !empty($this->param['models']) && $this->param['models'] == 'reception_send') {
1434 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_RECEPTION_TO');
1435 }
1436 if ($showinfobcc) {
1437 $out .= ' + '.$showinfobcc;
1438 }
1439 $out .= "</td></tr>\n";
1440 return $out;
1441 }
1442
1448 public function getHtmlForWithErrorsTo()
1449 {
1450 global $langs;
1451
1452 //if (! $this->errorstomail) $this->errorstomail=$this->frommail;
1453 $errorstomail = getDolGlobalString('MAIN_MAIL_ERRORS_TO', (!empty($this->errorstomail) ? $this->errorstomail : ''));
1454 if ($this->witherrorstoreadonly) {
1455 $out = '<tr><td>'.$langs->trans("MailErrorsTo").'</td><td>';
1456 $out .= '<input type="hidden" id="errorstomail" name="errorstomail" value="'.$errorstomail.'" />';
1457 $out .= $errorstomail;
1458 $out .= "</td></tr>\n";
1459 } else {
1460 $out = '<tr><td>'.$langs->trans("MailErrorsTo").'</td><td>';
1461 $out .= '<input class="minwidth200" id="errorstomail" name="errorstomail" value="'.$errorstomail.'" />';
1462 $out .= "</td></tr>\n";
1463 }
1464 return $out;
1465 }
1466
1472 public function getHtmlForDeliveryreceipt()
1473 {
1474 global $langs;
1475
1476 $out = '<tr><td><label for="deliveryreceipt">'.$langs->trans("DeliveryReceipt").'</label></td><td>';
1477
1478 if (!empty($this->withdeliveryreceiptreadonly)) {
1479 $out .= yn($this->withdeliveryreceipt);
1480 } else {
1481 $defaultvaluefordeliveryreceipt = 0;
1482 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_PROPAL') && !empty($this->param['models']) && $this->param['models'] == 'propal_send') {
1483 $defaultvaluefordeliveryreceipt = 1;
1484 }
1485 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_SUPPLIER_PROPOSAL') && !empty($this->param['models']) && $this->param['models'] == 'supplier_proposal_send') {
1486 $defaultvaluefordeliveryreceipt = 1;
1487 }
1488 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_ORDER') && !empty($this->param['models']) && $this->param['models'] == 'order_send') {
1489 $defaultvaluefordeliveryreceipt = 1;
1490 }
1491 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_INVOICE') && !empty($this->param['models']) && $this->param['models'] == 'facture_send') {
1492 $defaultvaluefordeliveryreceipt = 1;
1493 }
1494 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_SUPPLIER_ORDER') && !empty($this->param['models']) && $this->param['models'] == 'order_supplier_send') {
1495 $defaultvaluefordeliveryreceipt = 1;
1496 }
1497 //$out .= $form->selectyesno('deliveryreceipt', (GETPOSTISSET("deliveryreceipt") ? GETPOST("deliveryreceipt") : $defaultvaluefordeliveryreceipt), 1);
1498 $out .= '<input type="checkbox" id="deliveryreceipt" name="deliveryreceipt" value="1"'.((GETPOSTISSET("deliveryreceipt") ? GETPOST("deliveryreceipt") : $defaultvaluefordeliveryreceipt) ? ' checked="checked"' : '').'>';
1499 }
1500 $out .= "</td></tr>\n";
1501 return $out;
1502 }
1503
1511 public function getHtmlForTopic($arraydefaultmessage, $helpforsubstitution)
1512 {
1513 global $conf, $langs, $form;
1514
1515 $defaulttopic = GETPOST('subject', 'restricthtml');
1516
1517 if (!GETPOST('modelselected', 'alpha') || GETPOST('modelmailselected') != '-1') {
1518 if ($arraydefaultmessage && $arraydefaultmessage->topic) {
1519 $defaulttopic = $arraydefaultmessage->topic;
1520 } elseif (!is_numeric($this->withtopic)) {
1521 $defaulttopic = $this->withtopic;
1522 }
1523 }
1524
1525 // Resolve __(TranslationKey)__ in the language of the selected template
1526 // (see issue #34540). Falls back to the caller's language when the template
1527 // has no explicit language pinned.
1528 $outputlangs = $langs;
1529 if (is_object($arraydefaultmessage) && !empty($arraydefaultmessage->lang)) {
1530 $outputlangs = new Translate("", $conf);
1531 $outputlangs->setDefaultLang($arraydefaultmessage->lang);
1532 $outputlangs->load('other');
1533 }
1534
1535 $defaulttopic = make_substitutions($defaulttopic, $this->substit, $outputlangs);
1536
1537 $out = '<tr>';
1538 $out .= '<td class="fieldrequired">';
1539 $out .= $form->textwithpicto($langs->trans('MailTopicShort'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltipfromtopic');
1540 $out .= '</td>';
1541 $out .= '<td>';
1542 if ($this->withtopicreadonly) {
1543 $out .= $defaulttopic;
1544 $out .= '<input type="hidden" class="quatrevingtpercent" id="subject" name="subject" value="'.$defaulttopic.'" spellcheck="false">';
1545 } else {
1546 $out .= '<input type="text" class="quatrevingtpercent" id="subject" name="subject" value="'.((GETPOSTISSET("subject") && !GETPOST('modelselected')) ? GETPOST("subject") : ($defaulttopic ? $defaulttopic : '')).'" spellcheck="false">';
1547 }
1548 $out .= "</td></tr>\n";
1549 return $out;
1550 }
1551
1560 public function getEmailLayoutSelector($htmlContent = 'message', $showlinktolayout = 'email')
1561 {
1562 global $conf, $db, $websitepage, $langs;
1563
1564 require_once DOL_DOCUMENT_ROOT.'/core/lib/emaillayout.lib.php';
1565 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1566 require_once DOL_DOCUMENT_ROOT.'/website/class/website.class.php';
1567 require_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php';
1568
1569 $out = '<div id="template-selector" class="template-selector email-layout-container hidden" style="display:none;">';
1570 $out .= '<div>';
1571
1572 // Define list of email layouts to use
1573 $layouts = array(
1574 'none' => 'None',
1575 );
1576 // Add layouts found on disk in install/doctemplates/maillayout directory
1577 $arrayoflayoutemplates = dol_dir_list(DOL_DOCUMENT_ROOT.'/install/doctemplates/maillayout/', 'files', 0, '\.html$');
1578 foreach ($arrayoflayoutemplates as $layouttemplatefile) {
1579 $layoutname = preg_replace('/\.html$/i', '', $layouttemplatefile['name']);
1580
1581 // Exclude some layouts for some use cases
1582 if ($layoutname == 'news' && (!in_array($showlinktolayout, array('emailing', 'websitepage')) || !isModEnabled('website'))) {
1583 continue;
1584 }
1585 if ($layoutname == 'product' && (!in_array($showlinktolayout, array('emailing', 'websitepage')) || (!isModEnabled('product') && !isModEnabled('service')))) {
1586 continue;
1587 }
1588
1589 $layouts[$layoutname] = ucfirst($layoutname);
1590 }
1591 //}
1592 // TODO Add a hook to allow to complete the list
1593 foreach ($layouts as $layout => $templateFunction) {
1594 $contentHtml = getHtmlOfLayout($layout);
1595
1596 $out .= '<div class="template-option" data-template="'.$layout.'" data-content="'.htmlentities($contentHtml).'">';
1597 $out .= '<img class="maillayout" alt="'.$layout.'" src="'.DOL_URL_ROOT.'/theme/common/maillayout/'.$layout.'.png" />';
1598 $out .= '<span class="template-option-text">'.$langs->trans($templateFunction).'</span>';
1599 $out .= '</div>';
1600 }
1601 $out .= '</div>';
1602
1603 // Prepare the array for multiselect
1604
1605 // Fetch blogs
1606 $blogArray = array();
1607 if (isModEnabled('website')) {
1608 $websitepage = new WebsitePage($this->db);
1609 $arrayofblogs = $websitepage->fetchAll('', 'ASC,DESC', 'fk_website,date_creation', 0, 0, array('type_container' => 'blogpost'));
1610
1611 if (empty($conf->cache['websiteurl'])) {
1612 $conf->cache['websiteurl'] = array();
1613 }
1614
1615 if (!empty($arrayofblogs)) {
1616 foreach ($arrayofblogs as $blog) {
1617 if (!isset($conf->cache['websiteurl'][$blog->id])) {
1618 $tmpwebsite = new Website($db);
1619 $tmpwebsite->fetch($blog->fk_website);
1620 $conf->cache['websiteurl'][$blog->fk_website] = (empty($tmpwebsite->virtualhost) ? $tmpwebsite->ref : $tmpwebsite->virtualhost);
1621 }
1622
1623 $labelwebsite = $conf->cache['websiteurl'][$blog->fk_website];
1624 //$blog->fk_website
1625
1626 $blogArray[$blog->id] = array(
1627 'id' => $blog->id,
1628 'label' => '['.$labelwebsite.' '.$blog->type_container.' '.$blog->id.'] '.dol_trunc($blog->title, 40),
1629 'labelhtml' => '<span class="opacitymedium">['.$labelwebsite.' '.$blog->type_container.' '.$blog->id.']</span> '.dol_trunc($blog->title, 40),
1630 );
1631 }
1632 }
1633 }
1634
1635 // Fetch Product / Services
1636 /* to use with multiselectarray but consume too much memory so replaced
1637 if (in_array('product', array_keys($layouts))) {
1638 $productArray = array();
1639 if (isModEnabled('product') || isModEnabled('service')) {
1640 include_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
1641 $form = new Form($this->db);
1642 $arrayofproduct = $form->select_produits_list(0, 'product-select', '', 0, 0, '', 1, 2, 1);
1643 if (!empty($arrayofproduct)) {
1644 foreach ($arrayofproduct as $product) {
1645 $productArray[$product["key"]] = array(
1646 'id' => $product["key"],
1647 'label' => $product["value"].' - '.dol_trunc($product["label2"], 40),
1648 'labelhtml' => $product["value"].' - '.dol_trunc($product["label2"], 40),
1649 );
1650 }
1651 }
1652 }
1653 }
1654 */
1655
1656 // Use the multiselect array function to create the dropdown
1657 if (in_array('news', array_keys($layouts)) && (isModEnabled('product') || isModEnabled('service'))) {
1658 $out .= '<div id="post-dropdown-container" class="email-layout-container hidden" style="margin-top: 8px; display:none;">';
1659 $out .= '<label for="blogpost-select">Select Posts: </label>';
1660 $out .= '<!-- select component for selection of blog posts -->'."\n";
1661 // TODO WARNING: multiselectarray is ok only for very small list
1662 $out .= self::multiselectarray('blogpost-select', $blogArray, array(), 0, 0, 'minwidth200 select-template');
1663 $out .= ' <input type="submit" class="smallpaddingimp button reposition" name="submit" id="post-submit" value="'.dolPrintHTMLForAttribute($langs->trans("Select")).'">';
1664 $out .= '</div>';
1665 }
1666 if (in_array('product', array_keys($layouts)) && (isModEnabled('product') || isModEnabled('service'))) {
1667 include_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
1668 $form = new Form($this->db);
1669 $out .= '<div id="product-dropdown-container" class="email-layout-container hidden" style="margin-top: 8px; display:none;">';
1670 $out .= '<label for="product-select">'.img_picto('', 'product', 'class="pictofixedwidth"').$langs->trans("Product").' : </label>';
1671 $out .= '<!-- select component for selection of product -->'."\n";
1672 $out .= $form->select_produits(0, 'product-select', '', 0, 0, -1, 2, '', 0, array(), 0, '1', 0, 'inline-block valignmiddle', 0, '', null, 1);
1673 // TODO multiselectarray is ok only for very small list but is ok for multiselect. We need a multiselect ok with ajax for long list
1674 //$out .= self::multiselectarray('product-select', $productArray, array(), 0, 0, 'minwidth200 select-template');
1675 $out .= ' <input type="submit" class="smallpaddingimp button reposition" name="submit" id="product-submit" value="'.dolPrintHTMLForAttribute($langs->trans("Select")).'">';
1676 $out .= '</div>';
1677 }
1678
1679 $out .= '</div>';
1680
1681 $out .= '<!-- Js code to manage choice of an email layout -->'."\n";
1682 $out .= '<script type="text/javascript">
1683 $(document).ready(function() {
1684 $(".template-option").click(function() {
1685 var template = $(this).data("template");
1686 var subject = jQuery("#subject").val();
1687 var fromtype = jQuery("#fromtype").val();
1688 var sendto = jQuery("#sendto").val();
1689 var sendtocc = jQuery("#sendtocc").val();
1690 var sendtoccc = jQuery("#sendtoccc").val();
1691
1692 console.log("We choose a layout for email template=" + template + ", subject="+subject);
1693
1694 $(".template-option").removeClass("selected");
1695 $(this).addClass("selected");
1696 $(".select-template").val("").trigger("change");
1697
1698 if (template === "news") {
1699 $("#post-dropdown-container").show();
1700 $("#product-dropdown-container").hide();
1701 console.log("Displaying dropdown for news selection");
1702 } else if (template === "product") {
1703 $("#product-dropdown-container").show();
1704 $("#post-dropdown-container").hide();
1705 console.log("Displaying dropdown for product selection");
1706 } else {
1707 $("#post-dropdown-container").hide();
1708 $("#product-dropdown-container").hide();
1709 }
1710
1711 var csrfToken = "' .newToken().'";
1712 $.ajax({
1713 type: "POST",
1714 url: "'.DOL_URL_ROOT.'/core/ajax/mailtemplate.php",
1715 data: {
1716 token: csrfToken,
1717 template: template,
1718 subject: subject,
1719 fromtype: fromtype,
1720 sendto: sendto,
1721 sendtocc: sendtocc,
1722 sendtoccc: sendtoccc,
1723 selectedPosts: "[]"
1724 },
1725 success: function(response) {
1726 jQuery("#'.$htmlContent.'").val(response);
1727 var editorInstance = CKEDITOR.instances["'.$htmlContent.'"];
1728 if (editorInstance) {
1729 editorInstance.setData(response);
1730 }
1731 },
1732 error: function(xhr, status, error) {
1733 console.error("An error occurred: " + xhr.responseText);
1734 }
1735 });
1736 });
1737
1738 $("#blogpost-select").change(function() {
1739 var selectedIds = $(this).val();
1740 var contentHtml = $(".template-option.selected").data("content");
1741
1742 updateSelectedPostsContent(contentHtml, selectedIds);
1743 });
1744 $("#product-select").change(function() {
1745 var selectedIds = $(this).val();
1746 var contentHtml = $(".template-option.selected").data("content");
1747
1748 updateSelectedPostsContent(contentHtml, selectedIds);
1749 });
1750
1751 function updateSelectedPostsContent(contentHtml, selectedIds) {
1752 var csrfToken = "' .newToken().'";
1753 template = $(".template-option.selected").data("template");
1754 var subject = $("#subject").val();
1755 $.ajax({
1756 type: "POST",
1757 url: "'.dol_buildpath('/core/ajax/mailtemplate.php', 1).'",
1758 data: {
1759 token: csrfToken,
1760 template: template,
1761 subject: subject,
1762 selectedPosts: JSON.stringify(selectedIds)
1763 },
1764 success: function(response) {
1765 jQuery("#'.$htmlContent.'").val(response);
1766 var editorInstance = CKEDITOR.instances["'.$htmlContent.'"];
1767 if (editorInstance) {
1768 editorInstance.setData(response);
1769 }
1770 },
1771 error: function(xhr, status, error) {
1772 console.error("An error occurred: " + xhr.responseText);
1773 }
1774 });
1775
1776 }
1777 });
1778 </script>';
1779
1780 return $out;
1781 }
1782
1800 public function getEMailTemplate($dbs, $type_template, $user, $outputlangs, $id = 0, $active = 1, $label = '', $defaultfortype = -1)
1801 {
1802 global $conf;
1803
1804 if ($id == -2 && empty($label)) {
1805 $this->error = 'LabelIsMandatoryWhenIdIs-2or-3';
1806 return -1;
1807 }
1808 if ($type_template === 'societe') {
1809 $type_template = 'thirdparty';
1810 }
1811 $ret = new CEmailTemplate($dbs);
1812
1813 $languagetosearch = (is_object($outputlangs) ? $outputlangs->defaultlang : '');
1814 // Define $languagetosearchmain to fall back on main language (for example to get 'es_ES' for 'es_MX')
1815 $tmparray = explode('_', $languagetosearch);
1816 $languagetosearchmain = $tmparray[0].'_'.strtoupper($tmparray[0]);
1817 if ($languagetosearchmain == $languagetosearch) {
1818 $languagetosearchmain = '';
1819 }
1820
1821 $sql = "SELECT rowid, entity, module, label, type_template, topic, email_from, joinfiles, content, content_lines, lang, email_from, email_to, email_tocc, email_tobcc";
1822 $sql .= " FROM ".$dbs->prefix().'c_email_templates';
1823 $sql .= " WHERE (type_template = '".$dbs->escape($type_template)."' OR type_template = '".$dbs->escape($type_template)."_send' OR type_template = 'all')";
1824 $sql .= " AND entity IN (".getEntity('c_email_templates').")";
1825 $sql .= " AND (private = 0 OR fk_user = ".((int) $user->id).")"; // Get all public or private owned
1826 if ($active >= 0) {
1827 $sql .= " AND active = ".((int) $active);
1828 }
1829 if ($defaultfortype >= 0) {
1830 $sql .= " AND defaultfortype = ".((int) $defaultfortype);
1831 }
1832 if ($label) {
1833 $sql .= " AND label = '".$dbs->escape($label)."'";
1834 }
1835 if (!($id > 0) && $languagetosearch) {
1836 $sql .= " AND (lang = '".$dbs->escape($languagetosearch)."'".($languagetosearchmain ? " OR lang = '".$dbs->escape($languagetosearchmain)."'" : "")." OR lang IS NULL OR lang = '')";
1837 }
1838 if ($id > 0) {
1839 $sql .= " AND rowid = ".(int) $id;
1840 }
1841 if ($id == -1) {
1842 $sql .= " AND position = 0";
1843 }
1844 $sql .= " AND entity IN(".getEntity('c_email_templates', 1).")";
1845 if ($languagetosearch) {
1846 $sql .= $dbs->order("position,lang,label", "ASC,DESC,ASC"); // We want line with lang set first, then with lang null or ''
1847 } else {
1848 $sql .= $dbs->order("position,lang,label", "ASC,ASC,ASC"); // If no language provided, we give priority to lang not defined
1849 }
1850 //$sql .= $dbs->plimit(1);
1851 //print $sql;
1852
1853 $resql = $dbs->query($sql);
1854 if (!$resql) {
1855 dol_print_error($dbs);
1856 return -1;
1857 }
1858
1859 // Get first found
1860 while (1) {
1861 $obj = $dbs->fetch_object($resql);
1862
1863 if ($obj) {
1864 // If template is for a module, check module is enabled; if not, take next template
1865 if ($obj->module) {
1866 $tempmodulekey = $obj->module;
1867 if (empty($conf->$tempmodulekey) || !isModEnabled($tempmodulekey)) {
1868 continue;
1869 }
1870 }
1871
1872 // If a record was found
1873 $ret->id = (int) $obj->rowid;
1874 $ret->module = (string) $obj->module;
1875 $ret->label = (string) $obj->label;
1876 $ret->lang = $obj->lang;
1877 $ret->topic = $obj->topic;
1878 $ret->content = (string) $obj->content;
1879 $ret->content_lines = (string) $obj->content_lines;
1880 $ret->joinfiles = $obj->joinfiles;
1881 $ret->email_from = (string) $obj->email_from;
1882 $ret->email_tocc = (string) $obj->email_tocc;
1883 $ret->email_tobcc = (string) $obj->email_tobcc;
1884
1885 break;
1886 } else {
1887 // If no record found
1888 if ($id == -2) {
1889 // Not found with the provided label
1890 return -1;
1891 } else {
1892 // If there is no template at all
1893 $defaultmessage = '';
1894
1895 if ($type_template == 'body') {
1896 // Special case to use this->withbody as content
1897 $defaultmessage = (string) $this->withbody;
1898 } elseif ($type_template == 'facture_send' || $type_template == 'facture' || $type_template == 'facture_relance') {
1899 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendInvoice");
1900 } elseif ($type_template == 'propal_send' || $type_template == 'propal') {
1901 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendProposal");
1902 } elseif ($type_template == 'supplier_proposal_send' || $type_template == 'supplier_proposal') {
1903 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendSupplierProposal");
1904 } elseif ($type_template == 'order_send' || $type_template == 'order') {
1905 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendOrder");
1906 } elseif ($type_template == 'order_supplier_send' || $type_template == 'order_supplier') {
1907 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendSupplierOrder");
1908 } elseif ($type_template == 'invoice_supplier_send' || $type_template == 'invoice_supplier') {
1909 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendSupplierInvoice");
1910 } elseif ($type_template == 'shipping_send' || $type_template == 'shipping') {
1911 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendShipping");
1912 } elseif ($type_template == 'reception_send' || $type_template == 'reception') {
1913 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendReception");
1914 } elseif ($type_template == 'fichinter_send' || $type_template == 'fichinter') {
1915 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendFichInter");
1916 } elseif ($type_template == 'actioncomm_send' || $type_template == 'actioncomm') {
1917 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendActionComm");
1918 } elseif (!empty($type_template)) {
1919 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentGeneric");
1920 }
1921
1922 $ret->label = 'default';
1923 $ret->lang = $outputlangs->defaultlang;
1924 $ret->topic = '';
1925 $ret->joinfiles = 1;
1926 $ret->content = $defaultmessage;
1927 $ret->content_lines = '';
1928
1929 break;
1930 }
1931 }
1932 }
1933
1934 $dbs->free($resql);
1935
1936 return $ret;
1937 }
1938
1948 public function isEMailTemplate($type_template, $user, $outputlangs)
1949 {
1950 $sql = "SELECT label, topic, content, lang";
1951 $sql .= " FROM ".$this->db->prefix().'c_email_templates';
1952 $sql .= " WHERE type_template='".$this->db->escape($type_template)."'";
1953 $sql .= " AND entity IN (".getEntity('c_email_templates').")";
1954 $sql .= " AND (fk_user is NULL or fk_user = 0 or fk_user = ".((int) $user->id).")";
1955 if (is_object($outputlangs)) {
1956 $sql .= " AND (lang = '".$this->db->escape($outputlangs->defaultlang)."' OR lang IS NULL OR lang = '')";
1957 }
1958 $sql .= $this->db->order("lang,label", "ASC");
1959 //print $sql;
1960
1961 $resql = $this->db->query($sql);
1962 if ($resql) {
1963 $num = $this->db->num_rows($resql);
1964 $this->db->free($resql);
1965 return $num;
1966 } else {
1967 $this->error = get_class($this).' '.__METHOD__.' ERROR:'.$this->db->lasterror();
1968 return -1;
1969 }
1970 }
1971
1982 public function fetchAllEMailTemplate($type_template, $user, $outputlangs, $active = 1)
1983 {
1984 global $db, $conf;
1985
1986 $sql = "SELECT rowid, module, label, topic, content, content_lines, lang, fk_user, private, position";
1987 $sql .= " FROM ".$this->db->prefix().'c_email_templates';
1988 $sql .= " WHERE type_template IN ('".$this->db->escape($type_template)."', 'all')";
1989 $sql .= " AND entity IN (".getEntity('c_email_templates').")";
1990 $sql .= " AND (private = 0 OR fk_user = ".((int) $user->id).")"; // See all public templates or templates I own.
1991 if ($active >= 0) {
1992 $sql .= " AND active = ".((int) $active);
1993 }
1994 //if (is_object($outputlangs)) $sql.= " AND (lang = '".$this->db->escape($outputlangs->defaultlang)."' OR lang IS NULL OR lang = '')"; // Return all languages
1995 $sql .= $this->db->order("lang,position,label", "ASC");
1996 //print $sql;
1997
1998 $resql = $this->db->query($sql);
1999 if ($resql) {
2000 $num = $this->db->num_rows($resql);
2001 $this->lines_model = array();
2002 while ($obj = $this->db->fetch_object($resql)) {
2003 // If template is for a module, check module is enabled.
2004 if ($obj->module) {
2005 $tempmodulekey = $obj->module;
2006 if (empty($conf->$tempmodulekey) || !isModEnabled($tempmodulekey)) {
2007 continue;
2008 }
2009 }
2010
2011 $line = new CEmailTemplate($db);
2012 $line->id = (int) $obj->rowid;
2013 $line->label = (string) $obj->label;
2014 $line->lang = $obj->lang;
2015 $line->fk_user = $obj->fk_user;
2016 $line->private = $obj->private;
2017 $line->position = $obj->position;
2018 $line->topic = $obj->topic;
2019 $line->content = $obj->content;
2020 $line->content_lines = $obj->content_lines;
2021
2022 $this->lines_model[] = $line;
2023 }
2024 $this->db->free($resql);
2025 return $num;
2026 } else {
2027 $this->error = get_class($this).' '.__METHOD__.' ERROR:'.$this->db->lasterror();
2028 return -1;
2029 }
2030 }
2031
2037 private static function normalizeTextForComparison($value)
2038 {
2039 $value = dol_string_nohtmltag((string) $value);
2040 $value = preg_replace('/\s+/', ' ', $value);
2041 return trim((string) $value);
2042 }
2043
2049 private static function getLangPrefix($langcode)
2050 {
2051 $langcode = trim((string) $langcode);
2052 if ($langcode === '') {
2053 return '';
2054 }
2055
2056 $prefix = preg_replace('/[_-].*$/', '', $langcode);
2057 $prefix = strtolower((string) $prefix);
2058 return preg_replace('/[^a-z]/', '', $prefix);
2059 }
2060
2068 private static function getBestProductTranslation($multilangs, $langcode)
2069 {
2070 $langcode = trim((string) $langcode);
2071 if ($langcode === '' || !is_array($multilangs) || empty($multilangs)) {
2072 return array('label' => '', 'description' => '');
2073 }
2074
2075 $prefix = self::getLangPrefix($langcode);
2076 $candidates = array($langcode);
2077 if ($prefix !== '' && $prefix !== $langcode) {
2078 $candidates[] = $prefix;
2079 }
2080
2081 foreach ($candidates as $candidate) {
2082 if (empty($multilangs[$candidate]) || !is_array($multilangs[$candidate])) {
2083 continue;
2084 }
2085 $label = trim((string) (isset($multilangs[$candidate]['label']) ? $multilangs[$candidate]['label'] : ''));
2086 $description = trim((string) (isset($multilangs[$candidate]['description']) ? $multilangs[$candidate]['description'] : ''));
2087 if ($label !== '' || $description !== '') {
2088 return array('label' => $label, 'description' => $description);
2089 }
2090 }
2091
2092 if ($prefix !== '') {
2093 foreach ($multilangs as $code => $row) {
2094 if (!is_array($row)) {
2095 continue;
2096 }
2097 if (!(strpos($code, $prefix.'_') === 0 || strpos($code, $prefix.'-') === 0)) {
2098 continue;
2099 }
2100 $label = trim((string) (isset($row['label']) ? $row['label'] : ''));
2101 $description = trim((string) (isset($row['description']) ? $row['description'] : ''));
2102 if ($label !== '' || $description !== '') {
2103 return array('label' => $label, 'description' => $description);
2104 }
2105 }
2106 }
2107
2108 return array('label' => '', 'description' => '');
2109 }
2110
2118 public function setSubstitFromObject($object, $outputlangs)
2119 {
2120 global $extrafields;
2121
2122 $parameters = array();
2123 $tmparray = getCommonSubstitutionArray($outputlangs, 0, null, $object);
2124 complete_substitutions_array($tmparray, $outputlangs, null, $parameters);
2125
2126 $this->substit = $tmparray;
2127 $targetLang = '';
2128 if (is_object($outputlangs) && !empty($outputlangs->defaultlang)) {
2129 $targetLang = trim((string) $outputlangs->defaultlang);
2130 }
2131
2132 // Fill substit_lines with each object lines content
2133 if (is_array($object->lines)) {
2134 foreach ($object->lines as $line) {
2135 $substit_line = array(
2136 '__PRODUCT_REF__' => isset($line->product_ref) ? $line->product_ref : '',
2137 '__PRODUCT_LABEL__' => isset($line->product_label) ? $line->product_label : '',
2138 '__PRODUCT_DESCRIPTION__' => isset($line->product_desc) ? $line->product_desc : '',
2139 '__LABEL__' => isset($line->label) ? $line->label : '',
2140 '__DESCRIPTION__' => isset($line->desc) ? $line->desc : '',
2141 '__DATE_START_YMD__' => dol_print_date($line->date_start, 'day', false, $outputlangs),
2142 '__DATE_END_YMD__' => dol_print_date($line->date_end, 'day', false, $outputlangs),
2143 '__QUANTITY__' => $line->qty,
2144 '__SUBPRICE__' => price($line->subprice),
2145 '__AMOUNT__' => price($line->total_ttc),
2146 '__AMOUNT_EXCL_TAX__' => price($line->total_ht)
2147 );
2148
2149 // Create dynamic tags for __PRODUCT_EXTRAFIELD_FIELD__
2150 if (!empty($line->fk_product)) {
2151 if (!is_object($extrafields)) {
2152 $extrafields = new ExtraFields($this->db);
2153 }
2154 $product = new Product($this->db);
2155 $product->fetch($line->fk_product, '', '', '1');
2156 $product->fetch_optionals();
2157
2158 if (getDolGlobalInt('MAIN_MULTILANGS') && $targetLang !== '' && !empty($product->multilangs) && is_array($product->multilangs)) {
2159 $translated = self::getBestProductTranslation($product->multilangs, $targetLang);
2160 $translatedLabel = trim((string) (isset($translated['label']) ? $translated['label'] : ''));
2161 $translatedDescription = trim((string) (isset($translated['description']) ? $translated['description'] : ''));
2162
2163 $currentLabelNorm = self::normalizeTextForComparison($substit_line['__PRODUCT_LABEL__']);
2164 $currentProductDescriptionNorm = self::normalizeTextForComparison($substit_line['__PRODUCT_DESCRIPTION__']);
2165 $currentLineDescriptionNorm = self::normalizeTextForComparison($substit_line['__DESCRIPTION__']);
2166 $productLabelNorm = self::normalizeTextForComparison($product->label);
2167 $productDescriptionNorm = self::normalizeTextForComparison($product->description);
2168
2169 if ($translatedLabel !== '' && ($currentLabelNorm === '' || $currentLabelNorm === $productLabelNorm)) {
2170 $substit_line['__PRODUCT_LABEL__'] = $translatedLabel;
2171 }
2172 if ($translatedDescription !== '' && ($currentProductDescriptionNorm === '' || $currentProductDescriptionNorm === $productDescriptionNorm)) {
2173 $substit_line['__PRODUCT_DESCRIPTION__'] = $translatedDescription;
2174 }
2175 if ($translatedDescription !== '' && ($currentLineDescriptionNorm === '' || $currentLineDescriptionNorm === $productDescriptionNorm || $currentLineDescriptionNorm === $currentProductDescriptionNorm)) {
2176 $substit_line['__DESCRIPTION__'] = $translatedDescription;
2177 }
2178 }
2179
2180 $extrafields->fetch_name_optionals_label($product->table_element, true);
2181
2182 if (!empty($extrafields->attributes[$product->table_element]['label']) && is_array($extrafields->attributes[$product->table_element]['label']) && count($extrafields->attributes[$product->table_element]['label']) > 0) {
2183 foreach ($extrafields->attributes[$product->table_element]['label'] as $key => $label) {
2184 $substit_line['__PRODUCT_EXTRAFIELD_'.strtoupper($key).'__'] = isset($product->array_options['options_'.$key]) ? $product->array_options['options_'.$key] : '';
2185 }
2186 }
2187 }
2188
2189 $this->substit_lines[$line->id] = $substit_line; // @phan-suppress-current-line PhanTypeMismatchProperty
2190 }
2191 }
2192 }
2193
2201 public static function getAvailableSubstitKey($mode = 'formemail', $object = null)
2202 {
2203 global $langs;
2204
2205 $tmparray = array();
2206 if ($mode == 'formemail' || $mode == 'formemailwithlines' || $mode == 'formemailforlines') {
2207 $parameters = array('mode' => $mode);
2208 $tmparray = getCommonSubstitutionArray($langs, 2, null, $object); // Note: On email template creation, this may be null because it is related to all type of objects
2209 complete_substitutions_array($tmparray, $langs, null, $parameters);
2210
2211 if ($mode == 'formwithlines') {
2212 $tmparray['__LINES__'] = '__LINES__'; // Will be set by the get_form function
2213 }
2214 if ($mode == 'formforlines') {
2215 $tmparray['__QUANTITY__'] = '__QUANTITY__'; // Will be set by the get_form function
2216 }
2217 }
2218
2219 if ($mode == 'emailing') {
2220 $parameters = array('mode' => $mode);
2221 $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
2222 complete_substitutions_array($tmparray, $langs, null, $parameters);
2223
2224 // For mass emailing, we have different keys specific to the data into tagerts list
2225 $tmparray['__ID__'] = 'IdRecord';
2226 $tmparray['__EMAIL__'] = 'EMailRecipient';
2227 $tmparray['__LASTNAME__'] = 'Lastname';
2228 $tmparray['__FIRSTNAME__'] = 'Firstname';
2229 $tmparray['__MAILTOEMAIL__'] = 'TagMailtoEmail';
2230 $tmparray['__OTHER1__'] = 'Other1';
2231 $tmparray['__OTHER2__'] = 'Other2';
2232 $tmparray['__OTHER3__'] = 'Other3';
2233 $tmparray['__OTHER4__'] = 'Other4';
2234 $tmparray['__OTHER5__'] = 'Other5';
2235
2236 $tmparray['__THIRDPARTY_CUSTOMER_CODE__'] = 'CustomerCode'; // If source is a thirdparty
2237
2238 $tmparray['__CHECK_READ__'] = $langs->trans('TagCheckMail');
2239 $tmparray['__UNSUBSCRIBE__'] = $langs->trans('TagUnsubscribe');
2240 $tmparray['__UNSUBSCRIBE_URL__'] = $langs->trans('TagUnsubscribe').' (URL)';
2241
2242 $onlinepaymentenabled = 0;
2243 if (isModEnabled('paypal')) {
2244 $onlinepaymentenabled++;
2245 }
2246 if (isModEnabled('stripe')) {
2247 $onlinepaymentenabled++;
2248 }
2249 if ($onlinepaymentenabled && getDolGlobalString('PAYMENT_SECURITY_TOKEN')) {
2250 $tmparray['__SECUREKEYPAYMENT__'] = getDolGlobalString('PAYMENT_SECURITY_TOKEN');
2251 if (isModEnabled('member')) {
2252 $tmparray['__SECUREKEYPAYMENT_MEMBER__'] = 'SecureKeyPAYMENTUniquePerMember';
2253 }
2254 if (isModEnabled('don')) {
2255 $tmparray['__SECUREKEYPAYMENT_DONATION__'] = 'SecureKeyPAYMENTUniquePerDonation';
2256 }
2257 if (isModEnabled('invoice')) {
2258 $tmparray['__SECUREKEYPAYMENT_INVOICE__'] = 'SecureKeyPAYMENTUniquePerInvoice';
2259 }
2260 if (isModEnabled('order')) {
2261 $tmparray['__SECUREKEYPAYMENT_ORDER__'] = 'SecureKeyPAYMENTUniquePerOrder';
2262 }
2263 if (isModEnabled('contract')) {
2264 $tmparray['__SECUREKEYPAYMENT_CONTRACTLINE__'] = 'SecureKeyPAYMENTUniquePerContractLine';
2265 }
2266
2267 //Online payment link
2268 if (isModEnabled('member')) {
2269 $tmparray['__ONLINEPAYMENTLINK_MEMBER__'] = 'OnlinePaymentLinkUniquePerMember';
2270 }
2271 if (isModEnabled('don')) {
2272 $tmparray['__ONLINEPAYMENTLINK_DONATION__'] = 'OnlinePaymentLinkUniquePerDonation';
2273 }
2274 if (isModEnabled('invoice')) {
2275 $tmparray['__ONLINEPAYMENTLINK_INVOICE__'] = 'OnlinePaymentLinkUniquePerInvoice';
2276 }
2277 if (isModEnabled('order')) {
2278 $tmparray['__ONLINEPAYMENTLINK_ORDER__'] = 'OnlinePaymentLinkUniquePerOrder';
2279 }
2280 if (isModEnabled('contract')) {
2281 $tmparray['__ONLINEPAYMENTLINK_CONTRACTLINE__'] = 'OnlinePaymentLinkUniquePerContractLine';
2282 }
2283 } else {
2284 /* No need to show into tooltip help, option is not enabled
2285 $vars['__SECUREKEYPAYMENT__']='';
2286 $vars['__SECUREKEYPAYMENT_MEMBER__']='';
2287 $vars['__SECUREKEYPAYMENT_INVOICE__']='';
2288 $vars['__SECUREKEYPAYMENT_ORDER__']='';
2289 $vars['__SECUREKEYPAYMENT_CONTRACTLINE__']='';
2290 */
2291 }
2292 if (getDolGlobalString('MEMBER_ENABLE_PUBLIC')) {
2293 $tmparray['__PUBLICLINK_NEWMEMBERFORM__'] = 'BlankSubscriptionForm';
2294 }
2295 }
2296
2297 foreach ($tmparray as $key => $val) {
2298 if (empty($val)) {
2299 $tmparray[$key] = $key;
2300 }
2301 }
2302
2303 return $tmparray;
2304 }
2305}
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)
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.
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.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
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
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.
img_mime($file, $titlealt='', $morecss='')
Show MIME img of a file.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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.
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...
Definition html.lib.php:172
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
getMaxFileSizeArray()
Return the max allowed for file upload.