dolibarr 21.0.4
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-2024 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 MDW <mdeweerd@users.noreply.github.com>
11 *
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <https://www.gnu.org/licenses/>.
25 */
26
32require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
33
34
41class FormMail extends Form
42{
46 public $db;
47
53 public $withform;
54
58 public $fromname;
59
63 public $frommail;
64
68 public $fromtype;
69
73 public $fromid;
74
78 public $fromalsorobot;
79
83 public $totype;
84
88 public $toid;
89
93 public $replytoname;
94
98 public $replytomail;
99
103 public $toname;
104
108 public $tomail;
109
113 public $trackid;
114
118 public $inreplyto;
119
123 public $withsubstit; // Show substitution array
127 public $withfrom;
128
132 public $withto; // Show recipient emails
136 public $withreplyto;
137
143 public $withtofree;
147 public $withtocc;
151 public $withtoccc;
155 public $withtopic;
159 public $witherrorsto;
160
164 public $withfile;
165
169 public $withlayout;
170
174 public $withaiprompt;
175
179 public $withmaindocfile;
183 public $withbody;
184
188 public $withfromreadonly;
192 public $withreplytoreadonly;
196 public $withtoreadonly;
200 public $withtoccreadonly;
204 public $witherrorstoreadonly;
208 public $withtocccreadonly;
212 public $withtopicreadonly;
216 public $withbodyreadonly;
220 public $withfilereadonly;
224 public $withdeliveryreceipt;
228 public $withcancel;
232 public $withdeliveryreceiptreadonly;
236 public $withfckeditor;
237
241 public $ckeditortoolbar;
242
246 public $substit = array();
247
251 public $substit_lines = array();
252
256 public $param = array();
257
261 public $withtouser = array();
265 public $withtoccuser = array();
266
270 public $lines_model;
271
275 public $withoptiononeemailperrecipient;
276
277
283 public function __construct($db)
284 {
285 $this->db = $db;
286
287 $this->withform = 1;
288
289 $this->withfrom = 1;
290 $this->withto = 1;
291 $this->withtofree = 1;
292 $this->withtocc = 1;
293 $this->withtoccc = '0';
294 $this->witherrorsto = 0;
295 $this->withtopic = 1;
296 $this->withfile = 0; // 1=Add section "Attached files". 2=Can add files.
297 $this->withmaindocfile = 0; // 1=Add a checkbox "Attach also main document" for mass actions (checked by default), -1=Add checkbox (not checked by default)
298 $this->withbody = 1;
299
300 $this->withfromreadonly = 1;
301 $this->withreplytoreadonly = 1;
302 $this->withtoreadonly = 0;
303 $this->withtoccreadonly = 0;
304 $this->withtocccreadonly = 0;
305 $this->witherrorstoreadonly = 0;
306 $this->withtopicreadonly = 0;
307 $this->withfilereadonly = 0;
308 $this->withbodyreadonly = 0;
309 $this->withdeliveryreceiptreadonly = 0;
310 $this->withfckeditor = -1; // -1 = Auto
311 }
312
313 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
319 public function clear_attached_files()
320 {
321 // phpcs:enable
322 global $conf, $user;
323 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
324
325 // Set tmp user directory
326 $vardir = $conf->user->dir_output."/".$user->id;
327 $upload_dir = $vardir.'/temp/'; // TODO Add $keytoavoidconflict in upload_dir path
328 if (is_dir($upload_dir)) {
329 dol_delete_dir_recursive($upload_dir);
330 }
331
332 $keytoavoidconflict = empty($this->trackid) ? '' : '-'.$this->trackid; // this->trackid must be defined
333 unset($_SESSION["listofpaths".$keytoavoidconflict]);
334 unset($_SESSION["listofnames".$keytoavoidconflict]);
335 unset($_SESSION["listofmimes".$keytoavoidconflict]);
336 }
337
338 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
347 public function add_attached_files($path, $file = '', $type = '')
348 {
349 // phpcs:enable
350 $listofpaths = array();
351 $listofnames = array();
352 $listofmimes = array();
353
354 if (empty($file)) {
355 $file = basename($path);
356 }
357 if (empty($type)) {
358 $type = dol_mimetype($file);
359 }
360
361 $keytoavoidconflict = empty($this->trackid) ? '' : '-'.$this->trackid; // this->trackid must be defined
362 if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) {
363 $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
364 }
365 if (!empty($_SESSION["listofnames".$keytoavoidconflict])) {
366 $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
367 }
368 if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) {
369 $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
370 }
371 if (!in_array($file, $listofnames)) {
372 $listofpaths[] = $path;
373 $listofnames[] = $file;
374 $listofmimes[] = $type;
375 $_SESSION["listofpaths".$keytoavoidconflict] = implode(';', $listofpaths);
376 $_SESSION["listofnames".$keytoavoidconflict] = implode(';', $listofnames);
377 $_SESSION["listofmimes".$keytoavoidconflict] = implode(';', $listofmimes);
378 }
379 }
380
381 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
388 public function remove_attached_files($keytodelete)
389 {
390 // phpcs:enable
391 $listofpaths = array();
392 $listofnames = array();
393 $listofmimes = array();
394
395 $keytoavoidconflict = empty($this->trackid) ? '' : '-'.$this->trackid; // this->trackid must be defined
396 if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) {
397 $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
398 }
399 if (!empty($_SESSION["listofnames".$keytoavoidconflict])) {
400 $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
401 }
402 if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) {
403 $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
404 }
405 if ($keytodelete >= 0) {
406 unset($listofpaths[$keytodelete]);
407 unset($listofnames[$keytodelete]);
408 unset($listofmimes[$keytodelete]);
409 $_SESSION["listofpaths".$keytoavoidconflict] = implode(';', $listofpaths);
410 $_SESSION["listofnames".$keytoavoidconflict] = implode(';', $listofnames);
411 $_SESSION["listofmimes".$keytoavoidconflict] = implode(';', $listofmimes);
412 //var_dump($_SESSION['listofpaths']);
413 }
414 }
415
416 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
422 public function get_attached_files()
423 {
424 // phpcs:enable
425 $listofpaths = array();
426 $listofnames = array();
427 $listofmimes = array();
428
429 $keytoavoidconflict = empty($this->trackid) ? '' : '-'.$this->trackid; // this->trackid must be defined
430 if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) {
431 $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
432 }
433 if (!empty($_SESSION["listofnames".$keytoavoidconflict])) {
434 $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
435 }
436 if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) {
437 $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
438 }
439 return array('paths' => $listofpaths, 'names' => $listofnames, 'mimes' => $listofmimes);
440 }
441
442 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
453 public function show_form($addfileaction = 'addfile', $removefileaction = 'removefile')
454 {
455 // phpcs:enable
456 print $this->get_form($addfileaction, $removefileaction);
457 }
458
459 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
470 public function get_form($addfileaction = 'addfile', $removefileaction = 'removefile')
471 {
472 // phpcs:enable
473 global $conf, $langs, $user, $hookmanager, $form;
474
475 // Required to show preview wof mail attachments
476 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
477 $formfile = new FormFile($this->db);
478
479 if (!is_object($form)) {
480 $form = new Form($this->db);
481 }
482
483 // Load translation files required by the page
484 $langs->loadLangs(array('other', 'mails', 'members'));
485
486 // Clear temp files. Must be done before call of triggers, at beginning (mode = init), or when we select a new template
487 if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
488 $this->clear_attached_files();
489 }
490
491 // Call hook getFormMail
492 $hookmanager->initHooks(array('formmail'));
493
494 $parameters = array(
495 'addfileaction' => $addfileaction,
496 'removefileaction' => $removefileaction,
497 'trackid' => $this->trackid
498 );
499 $reshook = $hookmanager->executeHooks('getFormMail', $parameters, $this);
500
501 if (!empty($reshook)) {
502 return $hookmanager->resPrint;
503 } else {
504 $out = '';
505
506 $disablebademails = 1;
507
508 // Define output language
509 $outputlangs = $langs;
510 $newlang = '';
511 if (getDolGlobalInt('MAIN_MULTILANGS') && !empty($this->param['langsmodels'])) {
512 $newlang = $this->param['langsmodels'];
513 }
514 if (!empty($newlang)) {
515 $outputlangs = new Translate("", $conf);
516 $outputlangs->setDefaultLang($newlang);
517 $outputlangs->load('other');
518 }
519
520 // Get message template for $this->param["models"] into c_email_templates
521 $arraydefaultmessage = -1;
522 if ($this->param['models'] != 'none') {
523 $model_id = 0;
524 if (array_key_exists('models_id', $this->param)) {
525 $model_id = $this->param["models_id"];
526 }
527
528 $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
529 }
530
531 // Define list of attached files
532 $listofpaths = array();
533 $listofnames = array();
534 $listofmimes = array();
535 $keytoavoidconflict = empty($this->trackid) ? '' : '-'.$this->trackid; // this->trackid must be defined
536
537 if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
538 if (!empty($arraydefaultmessage->joinfiles) && !empty($this->param['fileinit']) && is_array($this->param['fileinit'])) {
539 foreach ($this->param['fileinit'] as $path) {
540 if (!empty($path)) {
541 $this->add_attached_files($path);
542 }
543 }
544 }
545 }
546
547 if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) {
548 $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
549 }
550 if (!empty($_SESSION["listofnames".$keytoavoidconflict])) {
551 $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
552 }
553 if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) {
554 $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
555 }
556
557
558 $out .= "\n".'<!-- Begin form mail type='.$this->param["models"].' --><div id="mailformdiv"></div>'."\n";
559 if ($this->withform == 1) {
560 $out .= '<form method="POST" name="mailform" id="mailform" enctype="multipart/form-data" action="'.$this->param["returnurl"].'#formmail">'."\n";
561
562 $out .= '<a id="formmail" name="formmail"></a>';
563 $out .= '<input style="display:none" type="submit" id="sendmailhidden" name="sendmail">';
564 $out .= '<input type="hidden" name="token" value="'.newToken().'" />';
565 $out .= '<input type="hidden" name="trackid" value="'.$this->trackid.'" />';
566 $out .= '<input type="hidden" name="inreplyto" value="'.$this->inreplyto.'" />';
567 }
568 if (!empty($this->withfrom)) {
569 if (!empty($this->withfromreadonly)) {
570 $out .= '<input type="hidden" id="fromname" name="fromname" value="'.$this->fromname.'" />';
571 $out .= '<input type="hidden" id="frommail" name="frommail" value="'.$this->frommail.'" />';
572 }
573 }
574 foreach ($this->param as $key => $value) {
575 if (is_array($value)) {
576 $out .= "<!-- param key=".$key." is array, we do not output input field for it -->\n";
577 } else {
578 $out .= '<input type="hidden" id="'.$key.'" name="'.$key.'" value="'.$value.'" />'."\n";
579 }
580 }
581
582 $modelmail_array = array();
583 if ($this->param['models'] != 'none') {
584 $result = $this->fetchAllEMailTemplate($this->param["models"], $user, $outputlangs);
585 if ($result < 0) {
586 setEventMessages($this->error, $this->errors, 'errors');
587 }
588
589 foreach ($this->lines_model as $line) {
590 $reg = array();
591 if (preg_match('/\‍((.*)\‍)/', $line->label, $reg)) {
592 $labeltouse = $langs->trans($reg[1]); // langs->trans when label is __(xxx)__
593 } else {
594 $labeltouse = $line->label;
595 }
596
597 // We escape the $labeltouse to store it into $modelmail_array.
598 $modelmail_array[$line->id] = dol_escape_htmltag($labeltouse);
599 if ($line->lang) {
600 $modelmail_array[$line->id] .= ' '.picto_from_langcode($line->lang);
601 }
602 if ($line->private) {
603 $modelmail_array[$line->id] .= ' - <span class="opacitymedium">'.dol_escape_htmltag($langs->trans("Private")).'</span>';
604 }
605 }
606 }
607
608 // Zone to select email template
609 if (count($modelmail_array) > 0) {
610 $model_mail_selected_id = GETPOSTISSET('modelmailselected') ? GETPOSTINT('modelmailselected') : ($arraydefaultmessage->id > 0 ? $arraydefaultmessage->id : 0);
611
612 // If list of template is filled
613 $out .= '<div class="center" style="padding: 0px 0 12px 0">'."\n";
614
615 $out .= $this->selectarray('modelmailselected', $modelmail_array, $model_mail_selected_id, $langs->trans('SelectMailModel'), 0, 0, '', 0, 0, 0, '', 'minwidth100', 1, '', 0, 1);
616 if ($user->admin) {
617 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFrom", $langs->transnoentitiesnoconv('Setup').' - '.$langs->transnoentitiesnoconv('EMails')), 1);
618 }
619
620 $out .= ' &nbsp; ';
621 $out .= '<input type="submit" class="button reposition smallpaddingimp" value="'.$langs->trans('Apply').'" name="modelselected" id="modelselected">';
622 $out .= ' &nbsp; ';
623 $out .= '</div>';
624 } elseif (!empty($this->param['models']) && in_array($this->param['models'], array(
625 'propal_send', 'order_send', 'facture_send',
626 'shipping_send', 'fichinter_send', 'supplier_proposal_send', 'order_supplier_send',
627 'invoice_supplier_send', 'thirdparty', 'contract', 'user', 'recruitmentcandidature_send', 'all'
628 ))) {
629 // If list of template is empty
630 $out .= '<div class="center" style="padding: 0px 0 12px 0">'."\n";
631 $out .= '<span class="opacitymedium">'.$langs->trans('SelectMailModel').':</span> ';
632 $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.
633 if ($user->admin) {
634 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFrom", $langs->transnoentitiesnoconv('Setup').' - '.$langs->transnoentitiesnoconv('EMails')), 1);
635 }
636 $out .= ' &nbsp; ';
637 $out .= '<input type="submit" class="button reposition smallpaddingimp" value="'.$langs->trans('Apply').'" name="modelselected" disabled="disabled" id="modelselected">';
638 $out .= ' &nbsp; ';
639 $out .= '</div>';
640 } else {
641 $out .= '<!-- No template available for $this->param["models"] = '.$this->param['models'].' -->';
642 }
643
644
645 $out .= '<table class="tableforemailform boxtablenotop centpercent">'."\n";
646
647 // Substitution array/string
648 $helpforsubstitution = '';
649 if (is_array($this->substit) && count($this->substit)) {
650 $helpforsubstitution .= $langs->trans('AvailableVariables').' :<br><br><span class="small">'."\n";
651 }
652 foreach ($this->substit as $key => $val) {
653 // Do not show deprecated variables into the tooltip help of substitution variables
654 if (in_array($key, array('__NEWREF__', '__REFCLIENT__', '__REFSUPPLIER__', '__SUPPLIER_ORDER_DATE_DELIVERY__', '__SUPPLIER_ORDER_DELAY_DELIVERY__'))) {
655 continue;
656 }
657 $helpforsubstitution .= $key.' -> '.$langs->trans(dol_string_nohtmltag(dolGetFirstLineOfText($val))).'<br>';
658 }
659 if (is_array($this->substit) && count($this->substit)) {
660 $helpforsubstitution .= '</span>';
661 }
662
663 /*
664 if (!empty($this->withsubstit)) { // Unset or set ->withsubstit=0 to disable this.
665 $out .= '<tr><td colspan="2" class="right">';
666 if (is_numeric($this->withsubstit)) {
667 $out .= $form->textwithpicto($langs->trans("EMailTestSubstitutionReplacedByGenericValues"), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltip'); // Old usage
668 } else {
669 $out .= $form->textwithpicto($langs->trans('AvailableVariables'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltip'); // New usage
670 }
671 $out .= "</td></tr>\n";
672 }*/
673
674 // From
675 if (!empty($this->withfrom)) {
676 if (!empty($this->withfromreadonly)) {
677 $out .= '<tr><td class="fieldrequired minwidth200">'.$langs->trans("MailFrom").'</td><td>';
678
679 // $this->fromtype is the default value to use to select sender
680 if (!($this->fromtype === 'user' && $this->fromid > 0)
681 && !($this->fromtype === 'company')
682 && !($this->fromtype === 'robot')
683 && !preg_match('/user_aliases/', $this->fromtype)
684 && !preg_match('/global_aliases/', $this->fromtype)
685 && !preg_match('/senderprofile/', $this->fromtype)
686 ) {
687 // Use this->fromname and this->frommail or error if not defined
688 $out .= $this->fromname;
689 if ($this->frommail) {
690 $out .= ' &lt;'.$this->frommail.'&gt;';
691 } else {
692 if ($this->fromtype) {
693 $langs->load('errors');
694 $out .= '<span class="warning"> &lt;'.$langs->trans('ErrorNoMailDefinedForThisUser').'&gt; </span>';
695 }
696 }
697 } else {
698 $liste = array();
699
700 // Add user email
701 if (empty($user->email)) {
702 $langs->load('errors');
703 $s = $user->getFullName($langs).' &lt;'.$langs->trans('ErrorNoMailDefinedForThisUser').'&gt;';
704 } else {
705 $s = $user->getFullName($langs).' &lt;'.$user->email.'&gt;';
706 }
707 $liste['user'] = array('label' => $s, 'data-html' => $s);
708
709 // Add also company main email
710 if (getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')) {
711 $s = (!getDolGlobalString('MAIN_INFO_SOCIETE_NOM') ? $conf->global->MAIN_INFO_SOCIETE_EMAIL : $conf->global->MAIN_INFO_SOCIETE_NOM).' &lt;' . getDolGlobalString('MAIN_INFO_SOCIETE_MAIL').'&gt;';
712 $liste['company'] = array('label' => $s, 'data-html' => $s);
713 }
714
715 // Add also email aliases if there is some
716 $listaliases = array(
717 'user_aliases' => (empty($user->email_aliases) ? '' : $user->email_aliases),
718 'global_aliases' => getDolGlobalString('MAIN_INFO_SOCIETE_MAIL_ALIASES'),
719 );
720
721 if (!empty($arraydefaultmessage->email_from)) {
722 $templatemailfrom = ' &lt;'.$arraydefaultmessage->email_from.'&gt;';
723 $liste['from_template_'.GETPOST('modelmailselected')] = array('label' => $templatemailfrom, 'data-html' => $templatemailfrom);
724 }
725
726 // Also add robot email
727 if (!empty($this->fromalsorobot)) {
728 if (getDolGlobalString('MAIN_MAIL_EMAIL_FROM') && getDolGlobalString('MAIN_MAIL_EMAIL_FROM') != getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')) {
729 $s = getDolGlobalString('MAIN_MAIL_EMAIL_FROM');
730 if ($this->frommail) {
731 $s .= ' &lt;' . getDolGlobalString('MAIN_MAIL_EMAIL_FROM').'&gt;';
732 }
733 $liste['main_from'] = array('label' => $s, 'data-html' => $s);
734 }
735 }
736
737 // Add also email aliases from the c_email_senderprofile table
738 $sql = "SELECT rowid, label, email FROM ".$this->db->prefix()."c_email_senderprofile";
739 $sql .= " WHERE active = 1 AND (private = 0 OR private = ".((int) $user->id).") AND entity IN (".getEntity('c_email_senderprofile').")";
740 $sql .= " ORDER BY position";
741 $resql = $this->db->query($sql);
742 if ($resql) {
743 $num = $this->db->num_rows($resql);
744 $i = 0;
745 while ($i < $num) {
746 $obj = $this->db->fetch_object($resql);
747 if ($obj) {
748 $listaliases['senderprofile_'.$obj->rowid] = $obj->label.' <'.$obj->email.'>';
749 }
750 $i++;
751 }
752 } else {
753 dol_print_error($this->db);
754 }
755
756 foreach ($listaliases as $typealias => $listalias) {
757 $posalias = 0;
758 $listaliasarray = explode(',', $listalias);
759 foreach ($listaliasarray as $listaliasval) {
760 $posalias++;
761 $listaliasval = trim($listaliasval);
762 if ($listaliasval) {
763 $listaliasval = preg_replace('/</', '&lt;', $listaliasval);
764 $listaliasval = preg_replace('/>/', '&gt;', $listaliasval);
765 if (!preg_match('/&lt;/', $listaliasval)) {
766 $listaliasval = '&lt;'.$listaliasval.'&gt;';
767 }
768 $liste[$typealias.'_'.$posalias] = array('label' => $listaliasval, 'data-html' => $listaliasval);
769 }
770 }
771 }
772
773 // Using ajaxcombo here make the '<email>' no more visible on list because <emailofuser> is not a valid html tag,
774 // so we transform before each record into $liste to be printable with ajaxcombo by replacing <> into ()
775 // $liste['senderprofile_0_0'] = array('label'=>'rrr', 'data-html'=>'rrr &lt;aaaa&gt;');
776 foreach ($liste as $key => $val) {
777 if (!empty($liste[$key]['data-html'])) {
778 $liste[$key]['data-html'] = str_replace(array('&lt;', '<', '&gt;', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $liste[$key]['data-html']);
779 $liste[$key]['data-html'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('<span class="opacitymedium">(', ')</span>'), $liste[$key]['data-html']);
780 }
781 }
782 $out .= ' '.$form->selectarray('fromtype', $liste, empty($arraydefaultmessage->email_from) ? $this->fromtype : 'from_template_'.GETPOST('modelmailselected'), 0, 0, 0, '', 0, 0, 0, '', 'fromforsendingprofile maxwidth200onsmartphone', 1, '', $disablebademails);
783 }
784
785 $out .= "</td></tr>\n";
786 } else {
787 $out .= '<tr><td class="fieldrequired width200">'.$langs->trans("MailFrom")."</td><td>";
788 $out .= $langs->trans("Name").':<input type="text" id="fromname" name="fromname" class="maxwidth200onsmartphone" value="'.$this->fromname.'" />';
789 $out .= '&nbsp; &nbsp; ';
790 $out .= $langs->trans("EMail").':&lt;<input type="text" id="frommail" name="frommail" class="maxwidth200onsmartphone" value="'.$this->frommail.'" />&gt;';
791 $out .= "</td></tr>\n";
792 }
793 }
794
795 // To
796 if (!empty($this->withto) || is_array($this->withto)) {
797 $out .= $this->getHtmlForTo();
798 }
799
800 // To User
801 if (!empty($this->withtouser) && is_array($this->withtouser) && getDolGlobalString('MAIN_MAIL_ENABLED_USER_DEST_SELECT')) {
802 $out .= '<tr><td>';
803 $out .= $langs->trans("MailToUsers");
804 $out .= '</td><td>';
805
806 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
807 $tmparray = $this->withtouser;
808 foreach ($tmparray as $key => $val) {
809 $tmparray[$key] = dol_htmlentities($tmparray[$key], 0, 'UTF-8', true);
810 }
811 $withtoselected = GETPOST("receiveruser", 'array'); // Array of selected value
812 if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') {
813 $withtoselected = array_keys($tmparray);
814 }
815 $out .= $form->multiselectarray("receiveruser", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, "");
816 $out .= "</td></tr>\n";
817 }
818
819 // With option for one email per recipient
820 if (!empty($this->withoptiononeemailperrecipient)) {
821 if (abs($this->withoptiononeemailperrecipient) == 1) {
822 $out .= '<tr><td class="minwidth200">';
823 $out .= $langs->trans("GroupEmails");
824 $out .= '</td><td>';
825 $out .= ' <input type="checkbox" id="oneemailperrecipient" value="1" name="oneemailperrecipient"'.($this->withoptiononeemailperrecipient > 0 ? ' checked="checked"' : '').'> ';
826 $out .= '<label for="oneemailperrecipient">';
827 $out .= $form->textwithpicto($langs->trans("OneEmailPerRecipient"), $langs->trans("WarningIfYouCheckOneRecipientPerEmail"), 1, 'help');
828 $out .= '</label>';
829 //$out .= '<span class="hideonsmartphone opacitymedium">';
830 //$out .= ' - ';
831 //$out .= $langs->trans("WarningIfYouCheckOneRecipientPerEmail");
832 //$out .= '</span>';
833 if (getDolGlobalString('MASS_ACTION_EMAIL_ON_DIFFERENT_THIRPARTIES_ADD_CUSTOM_EMAIL')) {
834 if (!empty($this->withto) && !is_array($this->withto)) {
835 $out .= ' '.$langs->trans("or").' <input type="email" name="emailto" value="">';
836 }
837 }
838 $out .= '</td></tr>';
839 } else {
840 $out .= '<tr><td><input type="hidden" name="oneemailperrecipient" value="1"></td><td></td></tr>';
841 }
842 }
843
844 // CC
845 if (!empty($this->withtocc) || is_array($this->withtocc)) {
846 $out .= $this->getHtmlForCc();
847 }
848
849 // To User cc
850 if (!empty($this->withtoccuser) && is_array($this->withtoccuser) && getDolGlobalString('MAIN_MAIL_ENABLED_USER_DEST_SELECT')) {
851 $out .= '<tr><td>';
852 $out .= $langs->trans("MailToCCUsers");
853 $out .= '</td><td>';
854
855 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
856 $tmparray = $this->withtoccuser;
857 foreach ($tmparray as $key => $val) {
858 $tmparray[$key] = dol_htmlentities($tmparray[$key], 0, 'UTF-8', true);
859 }
860 $withtoselected = GETPOST("receiverccuser", 'array'); // Array of selected value
861 if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') {
862 $withtoselected = array_keys($tmparray);
863 }
864 $out .= $form->multiselectarray("receiverccuser", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, "");
865 $out .= "</td></tr>\n";
866 }
867
868 // CCC
869 if (!empty($this->withtoccc) || is_array($this->withtoccc)) {
870 $out .= $this->getHtmlForWithCcc();
871 }
872
873 // Replyto
874 if (!empty($this->withreplyto)) {
875 if ($this->withreplytoreadonly) {
876 $out .= '<input type="hidden" id="replyname" name="replyname" value="'.$this->replytoname.'" />';
877 $out .= '<input type="hidden" id="replymail" name="replymail" value="'.$this->replytomail.'" />';
878 $out .= "<tr><td>".$langs->trans("MailReply")."</td><td>".$this->replytoname.($this->replytomail ? (" &lt;".$this->replytomail."&gt;") : "");
879 $out .= "</td></tr>\n";
880 }
881 }
882
883 // Errorsto
884 if (!empty($this->witherrorsto)) {
885 $out .= $this->getHtmlForWithErrorsTo();
886 }
887
888 // Ask delivery receipt
889 if (!empty($this->withdeliveryreceipt) && getDolGlobalInt('MAIN_EMAIL_SUPPORT_ACK')) {
890 $out .= $this->getHtmlForDeliveryreceipt();
891 }
892
893 // Topic
894 if (!empty($this->withtopic)) {
895 $out .= $this->getHtmlForTopic($arraydefaultmessage, $helpforsubstitution);
896 }
897
898 // Attached files
899 if (!empty($this->withfile)) {
900 $out .= '<tr>';
901 $out .= '<td class="tdtop">'.$langs->trans("MailFile").'</td>';
902
903 $out .= '<td>';
904
905 if ($this->withmaindocfile) {
906 // withmaindocfile is set to 1 or -1 to show the checkbox (-1 = checked or 1 = not checked)
907 if (GETPOSTISSET('sendmail')) {
908 $this->withmaindocfile = (GETPOST('addmaindocfile', 'alpha') ? -1 : 1);
909 } elseif (is_object($arraydefaultmessage) && $arraydefaultmessage->id > 0) {
910 // If a template was selected, we use setup of template to define if join file checkbox is selected or not.
911 $this->withmaindocfile = ($arraydefaultmessage->joinfiles ? -1 : 1);
912 }
913 }
914
915 if (!empty($this->withmaindocfile)) {
916 if ($this->withmaindocfile == 1) {
917 $out .= '<input type="checkbox" id="addmaindocfile" name="addmaindocfile" value="1" />';
918 } elseif ($this->withmaindocfile == -1) {
919 $out .= '<input type="checkbox" id="addmaindocfile" name="addmaindocfile" value="1" checked="checked" />';
920 }
921 if (getDolGlobalString('MAIL_MASS_ACTION_ADD_LAST_IF_MAIN_DOC_NOT_FOUND')) {
922 $out .= ' <label for="addmaindocfile">'.$langs->trans("JoinMainDocOrLastGenerated").'.</label><br>';
923 } else {
924 $out .= ' <label for="addmaindocfile">'.$langs->trans("JoinMainDoc").'.</label><br>';
925 }
926 }
927
928 if (is_numeric($this->withfile)) {
929 // TODO Trick to have param removedfile containing nb of file to delete. But this does not works without javascript
930 $out .= '<input type="hidden" class="removedfilehidden" name="removedfile" value="">'."\n";
931 $out .= '<script nonce="'.getNonce().'" type="text/javascript">';
932 $out .= 'jQuery(document).ready(function () {';
933 $out .= ' jQuery(".removedfile").click(function() {';
934 $out .= ' jQuery(".removedfilehidden").val(jQuery(this).val());';
935 $out .= ' });';
936 $out .= '})';
937 $out .= '</script>'."\n";
938 if (count($listofpaths)) {
939 foreach ($listofpaths as $key => $val) {
940 $relativepathtofile = substr($val, (strlen(DOL_DATA_ROOT) - strlen($val)));
941
942 $entity = (isset($this->param['object_entity']) ? $this->param['object_entity'] : $conf->entity);
943 if ($entity > 1) {
944 $relativepathtofile = str_replace('/'.$entity.'/', '/', $relativepathtofile);
945 }
946 // Try to extract data from full path
947 $formfile_params = array();
948 preg_match('#^(/)(\w+)(/)(.+)$#', $relativepathtofile, $formfile_params);
949
950 $out .= '<div id="attachfile_'.$key.'">';
951 // Preview of attachment
952 $out .= img_mime($listofnames[$key]).$listofnames[$key];
953
954 $out .= ' '.$formfile->showPreview(array(), $formfile_params[2], $formfile_params[4], 0, ($entity == 1 ? '' : 'entity='.((int) $entity)));
955
956 if (!$this->withfilereadonly) {
957 $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.'" />';
958 //$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>';
959 }
960 $out .= '<br></div>';
961 }
962 } /*elseif (empty($this->withmaindocfile)) {
963 //$out .= '<span class="opacitymedium">'.$langs->trans("NoAttachedFiles").'</span><br>';
964 }*/
965 if ($this->withfile == 2) {
966 $maxfilesizearray = getMaxFileSizeArray();
967 $maxmin = $maxfilesizearray['maxmin'];
968 if ($maxmin > 0) {
969 $out .= '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
970 }
971 // Can add other files
972 if (!getDolGlobalString('FROM_MAIL_DONT_USE_INPUT_FILE_MULTIPLE')) {
973 $out .= '<input type="file" class="flat" id="addedfile" name="addedfile[]" value="'.$langs->trans("Upload").'" multiple />';
974 } else {
975 $out .= '<input type="file" class="flat" id="addedfile" name="addedfile" value="'.$langs->trans("Upload").'" />';
976 }
977 $out .= ' ';
978 $out .= '<input type="submit" class="button smallpaddingimp" id="'.$addfileaction.'" name="'.$addfileaction.'" value="'.$langs->trans("MailingAddFile").'" />';
979 }
980 } else {
981 $out .= $this->withfile;
982 }
983
984 $out .= "</td></tr>\n";
985 }
986
987 // Message (+ Links to choose layout or ai prompt)
988 if (!empty($this->withbody)) {
989 $defaultmessage = GETPOST('message', 'restricthtml');
990 if (!GETPOST('modelselected', 'alpha') || GETPOST('modelmailselected') != '-1') {
991 if ($arraydefaultmessage && $arraydefaultmessage->content) {
992 $defaultmessage = $arraydefaultmessage->content;
993 } elseif (!is_numeric($this->withbody)) {
994 $defaultmessage = $this->withbody;
995 }
996 }
997
998 // Complete substitution array with the url to make online payment
999 $paymenturl = '';
1000 // Set the online payment url link into __ONLINE_PAYMENT_URL__ key
1001 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
1002 $validpaymentmethod = getValidOnlinePaymentMethods('');
1003
1004 if (empty($this->substit['__REF__'])) { // @phan-suppress-current-line PhanTypeMismatchProperty
1005 $paymenturl = '';
1006 } else {
1007 $langs->loadLangs(array('paypal', 'other'));
1008 $typeforonlinepayment = 'free';
1009 if ($this->param["models"] == 'order' || $this->param["models"] == 'order_send') {
1010 $typeforonlinepayment = 'order'; // TODO use detection on something else than template
1011 }
1012 if ($this->param["models"] == 'invoice' || $this->param["models"] == 'facture_send') {
1013 $typeforonlinepayment = 'invoice'; // TODO use detection on something else than template
1014 }
1015 if ($this->param["models"] == 'member') {
1016 $typeforonlinepayment = 'member'; // TODO use detection on something else than template
1017 }
1018 $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $this->substit['__REF__']);
1019 $paymenturl = $url;
1020 }
1021
1022 if (count($validpaymentmethod) > 0 && $paymenturl) {
1023 $langs->load('other');
1024 $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = str_replace('\n', "\n", $langs->transnoentities("PredefinedMailContentLink", $paymenturl));
1025 $this->substit['__ONLINE_PAYMENT_URL__'] = $paymenturl;
1026 } elseif (count($validpaymentmethod) > 0) {
1027 $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = '__ONLINE_PAYMENT_TEXT_AND_URL__';
1028 $this->substit['__ONLINE_PAYMENT_URL__'] = '__ONLINE_PAYMENT_URL__';
1029 } else {
1030 $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = '';
1031 $this->substit['__ONLINE_PAYMENT_URL__'] = '';
1032 }
1033
1034 $this->substit['__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__'] = '';
1035
1036 // Generate the string with the template for lines repeated and filled for each line
1037 $lines = '';
1038 $defaultlines = $arraydefaultmessage->content_lines;
1039 if (isset($defaultlines)) {
1040 foreach ($this->substit_lines as $lineid => $substit_line) {
1041 $lines .= make_substitutions($defaultlines, $substit_line)."\n";
1042 }
1043 }
1044 $this->substit['__LINES__'] = $lines;
1045
1046 $defaultmessage = str_replace('\n', "\n", $defaultmessage);
1047
1048 // Deal with format differences between message and some substitution variables (text / HTML)
1049 $atleastonecomponentishtml = 0;
1050 if (strpos($defaultmessage, '__USER_SIGNATURE__') !== false && dol_textishtml($this->substit['__USER_SIGNATURE__'])) {
1051 $atleastonecomponentishtml++;
1052 }
1053 if (strpos($defaultmessage, '__SENDEREMAIL_SIGNATURE__') !== false && dol_textishtml($this->substit['__SENDEREMAIL_SIGNATURE__'])) {
1054 $atleastonecomponentishtml++;
1055 }
1056 if (strpos($defaultmessage, '__ONLINE_PAYMENT_TEXT_AND_URL__') !== false && dol_textishtml($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'])) {
1057 $atleastonecomponentishtml++;
1058 }
1059 if (strpos($defaultmessage, '__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__') !== false && dol_textishtml($this->substit['__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__'])) {
1060 $atleastonecomponentishtml++;
1061 }
1062 if (dol_textishtml($defaultmessage)) {
1063 $atleastonecomponentishtml++;
1064 }
1065 if ($atleastonecomponentishtml) {
1066 if (!dol_textishtml($this->substit['__USER_SIGNATURE__'])) {
1067 $this->substit['__USER_SIGNATURE__'] = dol_nl2br($this->substit['__USER_SIGNATURE__']);
1068 }
1069 if (!dol_textishtml($this->substit['__SENDEREMAIL_SIGNATURE__'])) {
1070 $this->substit['__SENDEREMAIL_SIGNATURE__'] = dol_nl2br($this->substit['__SENDEREMAIL_SIGNATURE__']);
1071 }
1072 if (!dol_textishtml($this->substit['__LINES__'])) {
1073 $this->substit['__LINES__'] = dol_nl2br($this->substit['__LINES__']);
1074 }
1075 if (!dol_textishtml($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'])) {
1076 $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = dol_nl2br($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__']);
1077 }
1078 if (!dol_textishtml($defaultmessage)) {
1079 $defaultmessage = dol_nl2br($defaultmessage);
1080 }
1081 }
1082
1083 if (GETPOSTISSET("message") && !GETPOST('modelselected')) {
1084 $defaultmessage = GETPOST("message", "restricthtml");
1085 } else {
1086 $defaultmessage = make_substitutions($defaultmessage, $this->substit);
1087 // Clean first \n and br (to avoid empty line when CONTACTCIVNAME is empty)
1088 $defaultmessage = preg_replace("/^(<br>)+/", "", $defaultmessage);
1089 $defaultmessage = preg_replace("/^\n+/", "", $defaultmessage);
1090 }
1091
1092 $out .= '<tr>';
1093 $out .= '<td class="tdtop">';
1094 $out .= $form->textwithpicto($langs->trans('MailText'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltipfrombody');
1095 $out .= '</td>';
1096 $out .= '<td class="tdtop">';
1097
1098 $formmail = $this;
1099 $showlinktolayout = ($formmail->withfckeditor && getDolGlobalInt('MAIN_EMAIL_USE_LAYOUT')) ? $formmail->withlayout : '';
1100 $showlinktolayoutlabel = $langs->trans("FillMessageWithALayout");
1101 $showlinktoai = ($formmail->withaiprompt && isModEnabled('ai')) ? 'textgenerationemail' : '';
1102 $showlinktoailabel = $langs->trans("FillMessageWithAIContent");
1103 $formatforouput = '';
1104 $htmlname = 'message';
1105
1106 // Fill $out
1107 include DOL_DOCUMENT_ROOT.'/core/tpl/formlayoutai.tpl.php';
1108
1109 $out .= '</td>';
1110 $out .= '</tr>';
1111
1112 $out .= '<tr>';
1113 $out .= '<td colspan="2">';
1114 if ($this->withbodyreadonly) {
1115 $out .= nl2br($defaultmessage);
1116 $out .= '<input type="hidden" id="message" name="message" disabled value="'.$defaultmessage.'" />';
1117 } else {
1118 if (!isset($this->ckeditortoolbar)) {
1119 $this->ckeditortoolbar = 'dolibarr_mailings';
1120 }
1121
1122 // Editor wysiwyg
1123 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1124 if ($this->withfckeditor == -1) {
1125 if (getDolGlobalString('FCKEDITOR_ENABLE_MAIL')) {
1126 $this->withfckeditor = 1;
1127 } else {
1128 $this->withfckeditor = 0;
1129 }
1130 }
1131
1132 $doleditor = new DolEditor('message', $defaultmessage, '', 280, $this->ckeditortoolbar, 'In', true, true, $this->withfckeditor, 8, '95%');
1133 $out .= $doleditor->Create(1);
1134 }
1135 $out .= "</td></tr>\n";
1136 }
1137
1138 $out .= '</table>'."\n";
1139
1140 if ($this->withform == 1 || $this->withform == -1) {
1141 $out .= '<div class="center">';
1142 $out .= '<input type="submit" class="button button-add" id="sendmail" name="sendmail" value="'.$langs->trans("SendMail").'"';
1143 // Add a javascript test to avoid to forget to submit file before sending email
1144 if ($this->withfile == 2 && $conf->use_javascript_ajax) {
1145 $out .= ' onClick="if (document.mailform.addedfile.value != \'\') { alert(\''.dol_escape_js($langs->trans("FileWasNotUploaded")).'\'); return false; } else { return true; }"';
1146 }
1147 $out .= ' />';
1148 if ($this->withcancel) {
1149 $out .= '<input class="button button-cancel" type="submit" id="cancel" name="cancel" value="'.$langs->trans("Cancel").'" />';
1150 }
1151 $out .= '</div>'."\n";
1152 }
1153
1154 if ($this->withform == 1) {
1155 $out .= '</form>'."\n";
1156 }
1157
1158 // Disable enter key if option MAIN_MAILFORM_DISABLE_ENTERKEY is set
1159 if (getDolGlobalString('MAIN_MAILFORM_DISABLE_ENTERKEY')) {
1160 $out .= '<script nonce="'.getNonce().'" type="text/javascript">';
1161 $out .= 'jQuery(document).ready(function () {';
1162 $out .= ' $(document).on("keypress", \'#mailform\', function (e) { /* Note this is called at every key pressed ! */
1163 var code = e.keyCode || e.which;
1164 if (code == 13) {
1165 console.log("Enter was intercepted and blocked");
1166 e.preventDefault();
1167 return false;
1168 }
1169 });';
1170 $out .= ' })';
1171 $out .= '</script>';
1172 }
1173
1174 $out .= "<!-- End form mail -->\n";
1175
1176 return $out;
1177 }
1178 }
1179
1185 public function getHtmlForTo()
1186 {
1187 global $langs, $form;
1188 $out = '<tr><td class="fieldrequired">';
1189 if ($this->withtofree) {
1190 $out .= $form->textwithpicto($langs->trans("MailTo"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"));
1191 } else {
1192 $out .= $langs->trans("MailTo");
1193 }
1194 $out .= '</td><td>';
1195 if ($this->withtoreadonly) {
1196 if (!empty($this->toname) && !empty($this->tomail)) {
1197 $out .= '<input type="hidden" id="toname" name="toname" value="'.$this->toname.'" />';
1198 $out .= '<input type="hidden" id="tomail" name="tomail" value="'.$this->tomail.'" />';
1199 if ($this->totype == 'thirdparty') {
1200 $soc = new Societe($this->db);
1201 $soc->fetch($this->toid);
1202 $out .= $soc->getNomUrl(1);
1203 } elseif ($this->totype == 'contact') {
1204 $contact = new Contact($this->db);
1205 $contact->fetch($this->toid);
1206 $out .= $contact->getNomUrl(1);
1207 } else {
1208 $out .= $this->toname;
1209 }
1210 $out .= ' &lt;'.$this->tomail.'&gt;';
1211 if ($this->withtofree) {
1212 $out .= '<br>'.$langs->trans("and").' <input class="minwidth200" id="sendto" name="sendto" value="'.(!is_array($this->withto) && !is_numeric($this->withto) ? (GETPOSTISSET("sendto") ? GETPOST("sendto") : $this->withto) : "").'" />';
1213 }
1214 } else {
1215 // Note withto may be a text like 'AllRecipientSelected'
1216 $out .= (!is_array($this->withto) && !is_numeric($this->withto)) ? $this->withto : "";
1217 }
1218 } else {
1219 // The free input of email
1220 if (!empty($this->withtofree)) {
1221 $out .= '<input class="minwidth200" id="sendto" name="sendto" value="'.(($this->withtofree && !is_numeric($this->withtofree)) ? $this->withtofree : (!is_array($this->withto) && !is_numeric($this->withto) ? (GETPOSTISSET("sendto") ? GETPOST("sendto") : $this->withto) : "")).'" />';
1222 }
1223 // The select combo
1224 if (!empty($this->withto) && is_array($this->withto)) {
1225 if (!empty($this->withtofree)) {
1226 $out .= " ".$langs->trans("and")."/".$langs->trans("or")." ";
1227 }
1228
1229 $tmparray = $this->withto;
1230 foreach ($tmparray as $key => $val) {
1231 if (is_array($val)) {
1232 $label = $val['label'];
1233 } else {
1234 $label = $val;
1235 }
1236
1237 $tmparray[$key] = array();
1238 $tmparray[$key]['id'] = $key;
1239
1240 $tmparray[$key]['label'] = $label;
1241 $tmparray[$key]['label'] = str_replace(array('<', '>'), array('(', ')'), $tmparray[$key]['label']);
1242 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
1243 $tmparray[$key]['label'] = dol_htmlentities($tmparray[$key]['label'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', true);
1244
1245 $tmparray[$key]['labelhtml'] = $label;
1246 $tmparray[$key]['labelhtml'] = str_replace(array('&lt;', '<', '&gt;', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $tmparray[$key]['labelhtml']);
1247 $tmparray[$key]['labelhtml'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('<span class="opacitymedium">(', ')</span>'), $tmparray[$key]['labelhtml']);
1248 }
1249
1250 $withtoselected = GETPOST("receiver", 'array'); // Array of selected value
1251 if (!getDolGlobalInt('MAIN_MAIL_NO_WITH_TO_SELECTED')) {
1252 if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') {
1253 $withtoselected = array_keys($tmparray);
1254 }
1255 }
1256
1257 $out .= $form->multiselectarray("receiver", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, 0);
1258 }
1259 }
1260 $out .= "</td></tr>\n";
1261 return $out;
1262 }
1263
1269 public function getHtmlForCc()
1270 {
1271 global $langs, $form;
1272 $out = '<tr><td>';
1273 $out .= $form->textwithpicto($langs->trans("MailCC"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"));
1274 $out .= '</td><td>';
1275 if ($this->withtoccreadonly) {
1276 $out .= (!is_array($this->withtocc) && !is_numeric($this->withtocc)) ? $this->withtocc : "";
1277 } else {
1278 $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 : '')).'" />';
1279 if (!empty($this->withtocc) && is_array($this->withtocc)) {
1280 $out .= " ".$langs->trans("and")."/".$langs->trans("or")." ";
1281
1282 $tmparray = $this->withtocc;
1283 foreach ($tmparray as $key => $val) {
1284 if (is_array($val)) {
1285 $label = $val['label'];
1286 } else {
1287 $label = $val;
1288 }
1289
1290 $tmparray[$key] = array();
1291 $tmparray[$key]['id'] = $key;
1292
1293 $tmparray[$key]['label'] = $label;
1294 $tmparray[$key]['label'] = str_replace(array('<', '>'), array('(', ')'), $tmparray[$key]['label']);
1295 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
1296 $tmparray[$key]['label'] = dol_htmlentities($tmparray[$key]['label'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', true);
1297
1298 $tmparray[$key]['labelhtml'] = $label;
1299 $tmparray[$key]['labelhtml'] = str_replace(array('&lt;', '<', '&gt;', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $tmparray[$key]['labelhtml']);
1300 $tmparray[$key]['labelhtml'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('<span class="opacitymedium">(', ')</span>'), $tmparray[$key]['labelhtml']);
1301 }
1302
1303 $withtoccselected = GETPOST("receivercc", 'array'); // Array of selected value
1304
1305 $out .= $form->multiselectarray("receivercc", $tmparray, $withtoccselected, 0, 0, 'inline-block minwidth500', 0, 0);
1306 }
1307 }
1308 $out .= "</td></tr>\n";
1309 return $out;
1310 }
1311
1318 public function getHtmlForWithCcc()
1319 {
1320 global $langs, $form;
1321
1322 $out = '<tr><td>';
1323 $out .= $form->textwithpicto($langs->trans("MailCCC"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"));
1324 $out .= '</td><td>';
1325 if (!empty($this->withtocccreadonly)) {
1326 $out .= (!is_array($this->withtoccc) && !is_numeric($this->withtoccc)) ? $this->withtoccc : "";
1327 } else {
1328 $out .= '<input class="minwidth200" id="sendtoccc" name="sendtoccc" value="'.(GETPOSTISSET("sendtoccc") ? GETPOST("sendtoccc", "alpha") : ((!is_array($this->withtoccc) && !is_numeric($this->withtoccc)) ? $this->withtoccc : '')).'" />';
1329 if (!empty($this->withtoccc) && is_array($this->withtoccc)) {
1330 $out .= " ".$langs->trans("and")."/".$langs->trans("or")." ";
1331
1332 $tmparray = $this->withtoccc;
1333 foreach ($tmparray as $key => $val) {
1334 if (is_array($val)) {
1335 $label = $val['label'];
1336 } else {
1337 $label = $val;
1338 }
1339 $tmparray[$key] = array();
1340 $tmparray[$key]['id'] = $key;
1341
1342 $tmparray[$key]['label'] = $label;
1343 $tmparray[$key]['label'] = str_replace(array('<', '>'), array('(', ')'), $tmparray[$key]['label']);
1344 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
1345 $tmparray[$key]['label'] = dol_htmlentities($tmparray[$key]['label'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', true);
1346
1347 $tmparray[$key]['labelhtml'] = $label;
1348 $tmparray[$key]['labelhtml'] = str_replace(array('&lt;', '<', '&gt;', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $tmparray[$key]['labelhtml']);
1349 $tmparray[$key]['labelhtml'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('<span class="opacitymedium">(', ')</span>'), $tmparray[$key]['labelhtml']);
1350 }
1351
1352 $withtocccselected = GETPOST("receiverccc", 'array'); // Array of selected value
1353
1354 $out .= $form->multiselectarray("receiverccc", $tmparray, $withtocccselected, 0, 0, 'inline-block minwidth500', 0, 0);
1355 }
1356 }
1357
1358 $showinfobcc = '';
1359 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_PROPOSAL_TO') && !empty($this->param['models']) && $this->param['models'] == 'propal_send') {
1360 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_PROPOSAL_TO');
1361 }
1362 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_ORDER_TO') && !empty($this->param['models']) && $this->param['models'] == 'order_send') {
1363 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_ORDER_TO');
1364 }
1365 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_INVOICE_TO') && !empty($this->param['models']) && $this->param['models'] == 'facture_send') {
1366 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_INVOICE_TO');
1367 }
1368 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_PROPOSAL_TO') && !empty($this->param['models']) && $this->param['models'] == 'supplier_proposal_send') {
1369 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_PROPOSAL_TO');
1370 }
1371 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_ORDER_TO') && !empty($this->param['models']) && $this->param['models'] == 'order_supplier_send') {
1372 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_ORDER_TO');
1373 }
1374 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_INVOICE_TO') && !empty($this->param['models']) && $this->param['models'] == 'invoice_supplier_send') {
1375 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_INVOICE_TO');
1376 }
1377 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.
1378 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_PROJECT_TO');
1379 }
1380 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SHIPMENT_TO') && !empty($this->param['models']) && $this->param['models'] == 'shipping_send') {
1381 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SHIPMENT_TO');
1382 }
1383 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_RECEPTION_TO') && !empty($this->param['models']) && $this->param['models'] == 'reception_send') {
1384 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_RECEPTION_TO');
1385 }
1386 if ($showinfobcc) {
1387 $out .= ' + '.$showinfobcc;
1388 }
1389 $out .= "</td></tr>\n";
1390 return $out;
1391 }
1392
1398 public function getHtmlForWithErrorsTo()
1399 {
1400 global $langs;
1401
1402 //if (! $this->errorstomail) $this->errorstomail=$this->frommail;
1403 $errorstomail = getDolGlobalString('MAIN_MAIL_ERRORS_TO', (!empty($this->errorstomail) ? $this->errorstomail : ''));
1404 if ($this->witherrorstoreadonly) {
1405 $out = '<tr><td>'.$langs->trans("MailErrorsTo").'</td><td>';
1406 $out .= '<input type="hidden" id="errorstomail" name="errorstomail" value="'.$errorstomail.'" />';
1407 $out .= $errorstomail;
1408 $out .= "</td></tr>\n";
1409 } else {
1410 $out = '<tr><td>'.$langs->trans("MailErrorsTo").'</td><td>';
1411 $out .= '<input class="minwidth200" id="errorstomail" name="errorstomail" value="'.$errorstomail.'" />';
1412 $out .= "</td></tr>\n";
1413 }
1414 return $out;
1415 }
1416
1422 public function getHtmlForDeliveryreceipt()
1423 {
1424 global $langs;
1425
1426 $out = '<tr><td><label for="deliveryreceipt">'.$langs->trans("DeliveryReceipt").'</label></td><td>';
1427
1428 if (!empty($this->withdeliveryreceiptreadonly)) {
1429 $out .= yn($this->withdeliveryreceipt);
1430 } else {
1431 $defaultvaluefordeliveryreceipt = 0;
1432 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_PROPAL') && !empty($this->param['models']) && $this->param['models'] == 'propal_send') {
1433 $defaultvaluefordeliveryreceipt = 1;
1434 }
1435 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_SUPPLIER_PROPOSAL') && !empty($this->param['models']) && $this->param['models'] == 'supplier_proposal_send') {
1436 $defaultvaluefordeliveryreceipt = 1;
1437 }
1438 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_ORDER') && !empty($this->param['models']) && $this->param['models'] == 'order_send') {
1439 $defaultvaluefordeliveryreceipt = 1;
1440 }
1441 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_INVOICE') && !empty($this->param['models']) && $this->param['models'] == 'facture_send') {
1442 $defaultvaluefordeliveryreceipt = 1;
1443 }
1444 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_SUPPLIER_ORDER') && !empty($this->param['models']) && $this->param['models'] == 'order_supplier_send') {
1445 $defaultvaluefordeliveryreceipt = 1;
1446 }
1447 //$out .= $form->selectyesno('deliveryreceipt', (GETPOSTISSET("deliveryreceipt") ? GETPOST("deliveryreceipt") : $defaultvaluefordeliveryreceipt), 1);
1448 $out .= '<input type="checkbox" id="deliveryreceipt" name="deliveryreceipt" value="1"'.((GETPOSTISSET("deliveryreceipt") ? GETPOST("deliveryreceipt") : $defaultvaluefordeliveryreceipt) ? ' checked="checked"' : '').'>';
1449 }
1450 $out .= "</td></tr>\n";
1451 return $out;
1452 }
1453
1461 public function getHtmlForTopic($arraydefaultmessage, $helpforsubstitution)
1462 {
1463 global $langs, $form;
1464
1465 $defaulttopic = GETPOST('subject', 'restricthtml');
1466
1467 if (!GETPOST('modelselected', 'alpha') || GETPOST('modelmailselected') != '-1') {
1468 if ($arraydefaultmessage && $arraydefaultmessage->topic) {
1469 $defaulttopic = $arraydefaultmessage->topic;
1470 } elseif (!is_numeric($this->withtopic)) {
1471 $defaulttopic = $this->withtopic;
1472 }
1473 }
1474
1475 $defaulttopic = make_substitutions($defaulttopic, $this->substit);
1476
1477 $out = '<tr>';
1478 $out .= '<td class="fieldrequired">';
1479 $out .= $form->textwithpicto($langs->trans('MailTopic'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltipfromtopic');
1480 $out .= '</td>';
1481 $out .= '<td>';
1482 if ($this->withtopicreadonly) {
1483 $out .= $defaulttopic;
1484 $out .= '<input type="hidden" class="quatrevingtpercent" id="subject" name="subject" value="'.$defaulttopic.'" />';
1485 } else {
1486 $out .= '<input type="text" class="quatrevingtpercent" id="subject" name="subject" value="'.((GETPOSTISSET("subject") && !GETPOST('modelselected')) ? GETPOST("subject") : ($defaulttopic ? $defaulttopic : '')).'" />';
1487 }
1488 $out .= "</td></tr>\n";
1489 return $out;
1490 }
1491
1500 public function getSectionForAIPrompt($function = 'textgeneration', $format = '', $htmlContent = 'message')
1501 {
1502 global $langs;
1503
1504 $langs->load("other");
1505
1506 $htmlContent = preg_replace('/[^a-z0-9_]/', '', $htmlContent);
1507
1508 $out = '<div id="ai_input'.$htmlContent.'" class="hidden paddingtop paddingbottom">';
1509 $out .= '<input type="text" class="quatrevingtpercent" id="ai_instructions'.$htmlContent.'" name="instruction" placeholder="'.$langs->trans("EnterYourAIPromptHere").'..." />';
1510 $out .= '<input id="generate_button'.$htmlContent.'" type="button" class="button smallpaddingimp" value="'.$langs->trans('Generate').'"/>';
1511 $out .= '<div id="ai_status_message'.$htmlContent.'" class="fieldrequired hideobject marginrightonly margintoponly">';
1512 $out .= '<i class="fa fa-spinner fa-spin fa-2x fa-fw valignmiddle marginrightonly"></i>'.$langs->trans("AIProcessingPleaseWait", getDolGlobalString('AI_API_SERVICE', 'chatgpt'));
1513 $out .= '</div>';
1514
1515 if ($function == 'imagegeneration') {
1516 $out .= '<div id="ai_image_result" class="margintoponly"></div>'; // Div for displaying the generated image
1517 }
1518
1519 $out .= "</div>\n";
1520
1521 $out .= "<script type='text/javascript'>
1522 $(document).ready(function() {
1523 // for keydown
1524 $('#ai_instructions".$htmlContent."').keydown(function(event) {
1525 if (event.keyCode === 13) {
1526 event.preventDefault();
1527 $('#generate_button".$htmlContent."').click();
1528 }
1529 });
1530
1531 $('#generate_button".$htmlContent."').click(function() {
1532 console.log('We click on generate_button".$htmlContent." ai button');
1533
1534 var instructions = $('#ai_instructions".$htmlContent."').val();
1535 var timeoutfinished = 0;
1536 var apicallfinished = 0;
1537
1538 $('#ai_status_message".$htmlContent."').show();
1539 $('.icon-container .loader').show();
1540 setTimeout(function() {
1541 timeoutfinished = 1;
1542 if (apicallfinished) {
1543 $('#ai_status_message".$htmlContent."').hide();
1544 }
1545 }, 2000);
1546
1547 if ('".$function."' === 'imagegeneration') {
1548 // Handle image generation request
1549 $.ajax({
1550 url: '". DOL_URL_ROOT."/ai/ajax/generate_content.php?token=".currentToken()."',
1551 type: 'POST',
1552 contentType: 'application/json',
1553 data: JSON.stringify({
1554 'format': '".dol_escape_js($format)."', /* the format for output */
1555 'function': '".dol_escape_js($function)."', /* the AI feature to call */
1556 'instructions': instructions, /* the prompt string */
1557 }),
1558 success: function(response) {
1559 console.log('Received image URL: '+response);
1560 // Assuming response is the URL of the generated image
1561 var imageUrl = response;
1562 $('#ai_image_result').html('<img src=\"' + imageUrl + '\" alt=\"Generated Image\" />');
1563
1564 // Clear the input field
1565 $('#ai_instructions').val('');
1566
1567 apicallfinished = 1;
1568 if (timeoutfinished) {
1569 $('#ai_status_message').hide();
1570 }
1571 },
1572 error: function(xhr, status, error) {
1573 alert(error);
1574 console.error('error ajax', status, error);
1575 $('#ai_status_message').hide();
1576 }
1577 });
1578 } else {
1579
1580 // set editor in readonly
1581 if (CKEDITOR.instances.".$htmlContent.") {
1582 CKEDITOR.instances.".$htmlContent.".setReadOnly(1);
1583 }
1584
1585 $.ajax({
1586 url: '". DOL_URL_ROOT."/ai/ajax/generate_content.php?token=".currentToken()."',
1587 type: 'POST',
1588 contentType: 'application/json',
1589 data: JSON.stringify({
1590 'format': '".dol_escape_js($format)."', /* the format for output */
1591 'function': '".dol_escape_js($function)."', /* the AI feature to call */
1592 'instructions': instructions, /* the prompt string */
1593 }),
1594 success: function(response) {
1595 console.log('Add response into field \'#".$htmlContent."\': '+response);
1596
1597 jQuery('#".$htmlContent."').val(response); // If #htmlcontent is a input name or textarea
1598 jQuery('#".$htmlContent."').html(response); // If #htmlContent is a div
1599 //jQuery('#".$htmlContent."preview').val(response);
1600
1601 if (CKEDITOR.instances) {
1602 var editorInstance = CKEDITOR.instances.".$htmlContent.";
1603 if (editorInstance) {
1604 editorInstance.setReadOnly(0);
1605 editorInstance.setData(response);
1606 }
1607 //var editorInstancepreview = CKEDITOR.instances.".$htmlContent."preview;
1608 //if (editorInstancepreview) {
1609 // editorInstancepreview.setData(response);
1610 //}
1611 }
1612
1613 // remove readonly
1614 $('#ai_instructions".$htmlContent."').val('');
1615
1616 apicallfinished = 1;
1617 if (timeoutfinished) {
1618 $('#ai_status_message".$htmlContent."').hide();
1619 }
1620 },
1621 error: function(xhr, status, error) {
1622 alert(error);
1623 console.error('error ajax', status, error);
1624 $('#ai_status_message".$htmlContent."').hide();
1625 }
1626
1627 });
1628 }
1629 });
1630 });
1631 </script>
1632 ";
1633 return $out;
1634 }
1635
1643 public function getModelEmailTemplate($htmlContent = 'message', $showlinktolayout = 'email')
1644 {
1645 global $websitepage, $langs;
1646
1647 require_once DOL_DOCUMENT_ROOT.'/core/lib/emaillayout.lib.php';
1648 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1649 require_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php';
1650
1651 // Fetch blogs
1652 $websitepage = new WebsitePage($this->db);
1653 $arrayofblogs = $websitepage->fetchAll('', 'DESC', 'date_creation', 0, 0, array('type_container' => 'blogpost'));
1654
1655 $out = '<div id="template-selector" class="email-layout-container hidden" style="display:none;">';
1656
1657 // Define list of email layouts to use
1658 $layouts = array(
1659 'empty' => 'empty',
1660 );
1661 // Search available layouts on disk
1662 $arrayoflayoutemplates = dol_dir_list(DOL_DOCUMENT_ROOT.'/install/doctemplates/maillayout/', 'files', 0, '\.html$');
1663 foreach ($arrayoflayoutemplates as $layouttemplatefile) {
1664 $layoutname = preg_replace('/\.html$/i', '', $layouttemplatefile['name']);
1665
1666 // Exclude some layouts for some use cases
1667 if ($layoutname == 'news' && !in_array($showlinktolayout, array('emailing', 'websitepage'))) {
1668 continue;
1669 }
1670 if ($layoutname == 'products' && !in_array($showlinktolayout, array('emailing', 'websitepage'))) {
1671 continue;
1672 }
1673
1674 $layouts[$layoutname] = ucfirst($layoutname);
1675 }
1676 //}
1677 // TODO Add a hook to allow to complete the list
1678
1679 foreach ($layouts as $layout => $templateFunction) {
1680 $contentHtml = getHtmlOfLayout($layout);
1681
1682 $out .= '<div class="template-option" data-template="'.$layout.'" data-content="'.htmlentities($contentHtml).'">';
1683 $out .= '<img class="maillayout" alt="'.$layout.'" src="'.DOL_URL_ROOT.'/theme/common/maillayout/'.$layout.'.png" />';
1684 $out .= '<span class="template-option-text">'.$langs->trans($templateFunction).'</span>';
1685 $out .= '</div>';
1686 }
1687 $out .= '</div>';
1688
1689 // Prepare the array for multiselect
1690 $blogArray = array();
1691 if (!empty($arrayofblogs)) {
1692 foreach ($arrayofblogs as $blog) {
1693 $blogArray[$blog->id] = substr(htmlentities($blog->title), 0, 30);
1694 }
1695 }
1696
1697 // Use the multiselect array function to create the dropdown
1698 $out .= '<div id="post-dropdown-container" class="email-layout-container hidden" style="display:none;">';
1699 $out .= '<label for="blogpost-select">Select Posts: </label>';
1700 $out .= self::multiselectarray('blogpost-select', $blogArray, array(), 0, 0, 'minwidth200');
1701 $out .= '</div>';
1702
1703 $out .= '<script type="text/javascript">
1704 $(document).ready(function() {
1705 $(".template-option").click(function() {
1706 var template = $(this).data("template");
1707 var subject = jQuery("#subject").val();
1708 var fromtype = jQuery("#fromtype").val();
1709 var sendto = jQuery("#sendto").val();
1710 var sendtocc = jQuery("#sendtocc").val();
1711 var sendtoccc = jQuery("#sendtoccc").val();
1712
1713 console.log("We choose a layout for email template=" + template + ", subject="+subject);
1714
1715 $(".template-option").removeClass("selected");
1716 $(this).addClass("selected");
1717
1718 var subject = $("#sujet").val();
1719
1720 var contentHtml = $(this).data("content");
1721 contentHtml = contentHtml.replace(/__SUBJECT__/g, subject);
1722
1723 if (template === "news") {
1724 $("#post-dropdown-container").show();
1725 console.log("Displaying dropdown for news template");
1726 } else {
1727 $("#post-dropdown-container").hide();
1728
1729 var csrfToken = "' .newToken().'";
1730 $.ajax({
1731 type: "POST",
1732 url: "'.DOL_URL_ROOT.'/core/ajax/mailtemplate.php",
1733 data: {
1734 template: template,
1735 subject: subject,
1736 fromtype: fromtype,
1737 sendto: sendto,
1738 sendtocc: sendtocc,
1739 sendtoccc: sendtoccc,
1740 content: contentHtml,
1741 selectedPosts: "[]",
1742 token: csrfToken
1743 },
1744 success: function(response) {
1745 jQuery("#'.$htmlContent.'").val(response);
1746 var editorInstance = CKEDITOR.instances["'.$htmlContent.'"];
1747 if (editorInstance) {
1748 editorInstance.setData(response);
1749 }
1750 },
1751 error: function(xhr, status, error) {
1752 console.error("An error occurred: " + xhr.responseText);
1753 }
1754 });
1755 }
1756 });
1757
1758 $("#blogpost-select").change(function() {
1759 var selectedIds = $(this).val();
1760 var contentHtml = $(".template-option.selected").data("content");
1761
1762 updateSelectedPostsContent(contentHtml, selectedIds);
1763 });
1764
1765 function updateSelectedPostsContent(contentHtml, selectedIds) {
1766 var csrfToken = "' .newToken().'";
1767 $.ajax({
1768 type: "POST",
1769 url: "/core/ajax/getnews.php",
1770 data: {
1771 selectedIds: JSON.stringify(selectedIds),
1772 token : csrfToken
1773 },
1774 success: function(response) {
1775 var selectedPosts = JSON.parse(response);
1776 var subject = $("#sujet").val();
1777
1778 contentHtml = contentHtml.replace(/__SUBJECT__/g, subject);
1779
1780 $.ajax({
1781 type: "POST",
1782 url: "/core/ajax/mailtemplate.php",
1783 data: {
1784 content: contentHtml,
1785 selectedPosts: selectedIds.join(","),
1786 token: csrfToken
1787 },
1788 success: function(response) {
1789 jQuery("#'.$htmlContent.'").val(response);
1790 var editorInstance = CKEDITOR.instances["'.$htmlContent.'"];
1791 if (editorInstance) {
1792 editorInstance.setData(response);
1793 }
1794 },
1795 error: function(xhr, status, error) {
1796 console.error("An error occurred: " + xhr.responseText);
1797 }
1798 });
1799 },
1800 error: function(xhr, status, error) {
1801 console.error("An error occurred: " + xhr.responseText);
1802 }
1803 });
1804 }
1805 });
1806 </script>';
1807
1808 return $out;
1809 }
1810
1828 public function getEMailTemplate($dbs, $type_template, $user, $outputlangs, $id = 0, $active = 1, $label = '', $defaultfortype = -1)
1829 {
1830 global $conf;
1831
1832 if ($id == -2 && empty($label)) {
1833 $this->error = 'LabelIsMandatoryWhenIdIs-2or-3';
1834 return -1;
1835 }
1836
1837 $ret = new ModelMail($dbs);
1838
1839 $languagetosearch = (is_object($outputlangs) ? $outputlangs->defaultlang : '');
1840 // Define $languagetosearchmain to fall back on main language (for example to get 'es_ES' for 'es_MX')
1841 $tmparray = explode('_', $languagetosearch);
1842 $languagetosearchmain = $tmparray[0].'_'.strtoupper($tmparray[0]);
1843 if ($languagetosearchmain == $languagetosearch) {
1844 $languagetosearchmain = '';
1845 }
1846
1847 $sql = "SELECT rowid, entity, module, label, type_template, topic, email_from, joinfiles, content, content_lines, lang, email_from, email_to, email_tocc, email_tobcc";
1848 $sql .= " FROM ".$dbs->prefix().'c_email_templates';
1849 $sql .= " WHERE (type_template = '".$dbs->escape($type_template)."' OR type_template = 'all')";
1850 $sql .= " AND entity IN (".getEntity('c_email_templates').")";
1851 $sql .= " AND (private = 0 OR fk_user = ".((int) $user->id).")"; // Get all public or private owned
1852 if ($active >= 0) {
1853 $sql .= " AND active = ".((int) $active);
1854 }
1855 if ($defaultfortype >= 0) {
1856 $sql .= " AND defaultfortype = ".((int) $defaultfortype);
1857 }
1858 if ($label) {
1859 $sql .= " AND label = '".$dbs->escape($label)."'";
1860 }
1861 if (!($id > 0) && $languagetosearch) {
1862 $sql .= " AND (lang = '".$dbs->escape($languagetosearch)."'".($languagetosearchmain ? " OR lang = '".$dbs->escape($languagetosearchmain)."'" : "")." OR lang IS NULL OR lang = '')";
1863 }
1864 if ($id > 0) {
1865 $sql .= " AND rowid = ".(int) $id;
1866 }
1867 if ($id == -1) {
1868 $sql .= " AND position = 0";
1869 }
1870 $sql .= " AND entity IN(".getEntity('c_email_templates', 1).")";
1871 if ($languagetosearch) {
1872 $sql .= $dbs->order("position,lang,label", "ASC,DESC,ASC"); // We want line with lang set first, then with lang null or ''
1873 } else {
1874 $sql .= $dbs->order("position,lang,label", "ASC,ASC,ASC"); // If no language provided, we give priority to lang not defined
1875 }
1876 //$sql .= $dbs->plimit(1);
1877 //print $sql;
1878
1879 $resql = $dbs->query($sql);
1880 if (!$resql) {
1881 dol_print_error($dbs);
1882 return -1;
1883 }
1884
1885 // Get first found
1886 while (1) {
1887 $obj = $dbs->fetch_object($resql);
1888
1889 if ($obj) {
1890 // If template is for a module, check module is enabled; if not, take next template
1891 if ($obj->module) {
1892 $tempmodulekey = $obj->module;
1893 if (empty($conf->$tempmodulekey) || !isModEnabled($tempmodulekey)) {
1894 continue;
1895 }
1896 }
1897
1898 // If a record was found
1899 $ret->id = $obj->rowid;
1900 $ret->module = $obj->module;
1901 $ret->label = $obj->label;
1902 $ret->lang = $obj->lang;
1903 $ret->topic = $obj->topic;
1904 $ret->content = $obj->content;
1905 $ret->content_lines = $obj->content_lines;
1906 $ret->joinfiles = $obj->joinfiles;
1907 $ret->email_from = $obj->email_from;
1908
1909 break;
1910 } else {
1911 // If no record found
1912 if ($id == -2) {
1913 // Not found with the provided label
1914 return -1;
1915 } else {
1916 // If there is no template at all
1917 $defaultmessage = '';
1918
1919 if ($type_template == 'body') {
1920 // Special case to use this->withbody as content
1921 $defaultmessage = $this->withbody;
1922 } elseif ($type_template == 'facture_send') {
1923 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendInvoice");
1924 } elseif ($type_template == 'facture_relance') {
1925 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendInvoiceReminder");
1926 } elseif ($type_template == 'propal_send') {
1927 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendProposal");
1928 } elseif ($type_template == 'supplier_proposal_send') {
1929 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendSupplierProposal");
1930 } elseif ($type_template == 'order_send') {
1931 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendOrder");
1932 } elseif ($type_template == 'order_supplier_send') {
1933 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendSupplierOrder");
1934 } elseif ($type_template == 'invoice_supplier_send') {
1935 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendSupplierInvoice");
1936 } elseif ($type_template == 'shipping_send') {
1937 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendShipping");
1938 } elseif ($type_template == 'fichinter_send') {
1939 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendFichInter");
1940 } elseif ($type_template == 'actioncomm_send') {
1941 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendActionComm");
1942 } elseif (!empty($type_template)) {
1943 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentGeneric");
1944 }
1945
1946 $ret->label = 'default';
1947 $ret->lang = $outputlangs->defaultlang;
1948 $ret->topic = '';
1949 $ret->joinfiles = 1;
1950 $ret->content = $defaultmessage;
1951 $ret->content_lines = '';
1952
1953 break;
1954 }
1955 }
1956 }
1957
1958 $dbs->free($resql);
1959
1960 return $ret;
1961 }
1962
1972 public function isEMailTemplate($type_template, $user, $outputlangs)
1973 {
1974 $sql = "SELECT label, topic, content, lang";
1975 $sql .= " FROM ".$this->db->prefix().'c_email_templates';
1976 $sql .= " WHERE type_template='".$this->db->escape($type_template)."'";
1977 $sql .= " AND entity IN (".getEntity('c_email_templates').")";
1978 $sql .= " AND (fk_user is NULL or fk_user = 0 or fk_user = ".((int) $user->id).")";
1979 if (is_object($outputlangs)) {
1980 $sql .= " AND (lang = '".$this->db->escape($outputlangs->defaultlang)."' OR lang IS NULL OR lang = '')";
1981 }
1982 $sql .= $this->db->order("lang,label", "ASC");
1983 //print $sql;
1984
1985 $resql = $this->db->query($sql);
1986 if ($resql) {
1987 $num = $this->db->num_rows($resql);
1988 $this->db->free($resql);
1989 return $num;
1990 } else {
1991 $this->error = get_class($this).' '.__METHOD__.' ERROR:'.$this->db->lasterror();
1992 return -1;
1993 }
1994 }
1995
2006 public function fetchAllEMailTemplate($type_template, $user, $outputlangs, $active = 1)
2007 {
2008 global $db, $conf;
2009
2010 $sql = "SELECT rowid, module, label, topic, content, content_lines, lang, fk_user, private, position";
2011 $sql .= " FROM ".$this->db->prefix().'c_email_templates';
2012 $sql .= " WHERE type_template IN ('".$this->db->escape($type_template)."', 'all')";
2013 $sql .= " AND entity IN (".getEntity('c_email_templates').")";
2014 $sql .= " AND (private = 0 OR fk_user = ".((int) $user->id).")"; // See all public templates or templates I own.
2015 if ($active >= 0) {
2016 $sql .= " AND active = ".((int) $active);
2017 }
2018 //if (is_object($outputlangs)) $sql.= " AND (lang = '".$this->db->escape($outputlangs->defaultlang)."' OR lang IS NULL OR lang = '')"; // Return all languages
2019 $sql .= $this->db->order("position,lang,label", "ASC");
2020 //print $sql;
2021
2022 $resql = $this->db->query($sql);
2023 if ($resql) {
2024 $num = $this->db->num_rows($resql);
2025 $this->lines_model = array();
2026 while ($obj = $this->db->fetch_object($resql)) {
2027 // If template is for a module, check module is enabled.
2028 if ($obj->module) {
2029 $tempmodulekey = $obj->module;
2030 if (empty($conf->$tempmodulekey) || !isModEnabled($tempmodulekey)) {
2031 continue;
2032 }
2033 }
2034
2035 $line = new ModelMail($db);
2036 $line->id = $obj->rowid;
2037 $line->label = $obj->label;
2038 $line->lang = $obj->lang;
2039 $line->fk_user = $obj->fk_user;
2040 $line->private = $obj->private;
2041 $line->position = $obj->position;
2042 $line->topic = $obj->topic;
2043 $line->content = $obj->content;
2044 $line->content_lines = $obj->content_lines;
2045
2046 $this->lines_model[] = $line;
2047 }
2048 $this->db->free($resql);
2049 return $num;
2050 } else {
2051 $this->error = get_class($this).' '.__METHOD__.' ERROR:'.$this->db->lasterror();
2052 return -1;
2053 }
2054 }
2055
2056
2057
2066 public function setSubstitFromObject($object, $outputlangs)
2067 {
2068 global $extrafields;
2069
2070 $parameters = array();
2071 $tmparray = getCommonSubstitutionArray($outputlangs, 0, null, $object);
2072 complete_substitutions_array($tmparray, $outputlangs, null, $parameters);
2073
2074 $this->substit = $tmparray;
2075
2076 // Fill substit_lines with each object lines content
2077 if (is_array($object->lines)) {
2078 foreach ($object->lines as $line) {
2079 $substit_line = array(
2080 '__PRODUCT_REF__' => isset($line->product_ref) ? $line->product_ref : '',
2081 '__PRODUCT_LABEL__' => isset($line->product_label) ? $line->product_label : '',
2082 '__PRODUCT_DESCRIPTION__' => isset($line->product_desc) ? $line->product_desc : '',
2083 '__LABEL__' => isset($line->label) ? $line->label : '',
2084 '__DESCRIPTION__' => isset($line->desc) ? $line->desc : '',
2085 '__DATE_START_YMD__' => dol_print_date($line->date_start, 'day', false, $outputlangs),
2086 '__DATE_END_YMD__' => dol_print_date($line->date_end, 'day', false, $outputlangs),
2087 '__QUANTITY__' => $line->qty,
2088 '__SUBPRICE__' => price($line->subprice),
2089 '__AMOUNT__' => price($line->total_ttc),
2090 '__AMOUNT_EXCL_TAX__' => price($line->total_ht)
2091 );
2092
2093 // Create dynamic tags for __PRODUCT_EXTRAFIELD_FIELD__
2094 if (!empty($line->fk_product)) {
2095 if (!is_object($extrafields)) {
2096 $extrafields = new ExtraFields($this->db);
2097 }
2098 $product = new Product($this->db);
2099 $product->fetch($line->fk_product, '', '', 1);
2100 $product->fetch_optionals();
2101
2102 $extrafields->fetch_name_optionals_label($product->table_element, true);
2103
2104 if (!empty($extrafields->attributes[$product->table_element]['label']) && is_array($extrafields->attributes[$product->table_element]['label']) && count($extrafields->attributes[$product->table_element]['label']) > 0) {
2105 foreach ($extrafields->attributes[$product->table_element]['label'] as $key => $label) {
2106 $substit_line['__PRODUCT_EXTRAFIELD_'.strtoupper($key).'__'] = isset($product->array_options['options_'.$key]) ? $product->array_options['options_'.$key] : '';
2107 }
2108 }
2109 }
2110
2111 $this->substit_lines[$line->id] = $substit_line; // @phan-suppress-current-line PhanTypeMismatchProperty
2112 }
2113 }
2114 }
2115
2124 public static function getAvailableSubstitKey($mode = 'formemail', $object = null)
2125 {
2126 global $langs;
2127
2128 $tmparray = array();
2129 if ($mode == 'formemail' || $mode == 'formemailwithlines' || $mode == 'formemailforlines') {
2130 $parameters = array('mode' => $mode);
2131 $tmparray = getCommonSubstitutionArray($langs, 2, null, $object); // Note: On email templated edition, this is null because it is related to all type of objects
2132 complete_substitutions_array($tmparray, $langs, null, $parameters);
2133
2134 if ($mode == 'formwithlines') {
2135 $tmparray['__LINES__'] = '__LINES__'; // Will be set by the get_form function
2136 }
2137 if ($mode == 'formforlines') {
2138 $tmparray['__QUANTITY__'] = '__QUANTITY__'; // Will be set by the get_form function
2139 }
2140 }
2141
2142 if ($mode == 'emailing') {
2143 $parameters = array('mode' => $mode);
2144 $tmparray = getCommonSubstitutionArray($langs, 2, array('object', 'objectamount'), $object); // Note: On email templated edition, this is null because it is related to all type of objects
2145 complete_substitutions_array($tmparray, $langs, null, $parameters);
2146
2147 // For mass emailing, we have different keys specific to the data into tagerts list
2148 $tmparray['__ID__'] = 'IdRecord';
2149 $tmparray['__THIRDPARTY_CUSTOMER_CODE__'] = 'CustomerCode';
2150 $tmparray['__EMAIL__'] = 'EMailRecipient';
2151 $tmparray['__LASTNAME__'] = 'Lastname';
2152 $tmparray['__FIRSTNAME__'] = 'Firstname';
2153 $tmparray['__MAILTOEMAIL__'] = 'TagMailtoEmail';
2154 $tmparray['__OTHER1__'] = 'Other1';
2155 $tmparray['__OTHER2__'] = 'Other2';
2156 $tmparray['__OTHER3__'] = 'Other3';
2157 $tmparray['__OTHER4__'] = 'Other4';
2158 $tmparray['__OTHER5__'] = 'Other5';
2159 $tmparray['__CHECK_READ__'] = $langs->trans('TagCheckMail');
2160 $tmparray['__UNSUBSCRIBE__'] = $langs->trans('TagUnsubscribe');
2161 $tmparray['__UNSUBSCRIBE_URL__'] = $langs->trans('TagUnsubscribe').' (URL)';
2162
2163 $onlinepaymentenabled = 0;
2164 if (isModEnabled('paypal')) {
2165 $onlinepaymentenabled++;
2166 }
2167 if (isModEnabled('paybox')) {
2168 $onlinepaymentenabled++;
2169 }
2170 if (isModEnabled('stripe')) {
2171 $onlinepaymentenabled++;
2172 }
2173 if ($onlinepaymentenabled && getDolGlobalString('PAYMENT_SECURITY_TOKEN')) {
2174 $tmparray['__SECUREKEYPAYMENT__'] = getDolGlobalString('PAYMENT_SECURITY_TOKEN');
2175 if (getDolGlobalString('PAYMENT_SECURITY_TOKEN_UNIQUE')) {
2176 if (isModEnabled('member')) {
2177 $tmparray['__SECUREKEYPAYMENT_MEMBER__'] = 'SecureKeyPAYMENTUniquePerMember';
2178 }
2179 if (isModEnabled('don')) {
2180 $tmparray['__SECUREKEYPAYMENT_DONATION__'] = 'SecureKeyPAYMENTUniquePerDonation';
2181 }
2182 if (isModEnabled('invoice')) {
2183 $tmparray['__SECUREKEYPAYMENT_INVOICE__'] = 'SecureKeyPAYMENTUniquePerInvoice';
2184 }
2185 if (isModEnabled('order')) {
2186 $tmparray['__SECUREKEYPAYMENT_ORDER__'] = 'SecureKeyPAYMENTUniquePerOrder';
2187 }
2188 if (isModEnabled('contract')) {
2189 $tmparray['__SECUREKEYPAYMENT_CONTRACTLINE__'] = 'SecureKeyPAYMENTUniquePerContractLine';
2190 }
2191
2192 //Online payment link
2193 if (isModEnabled('member')) {
2194 $tmparray['__ONLINEPAYMENTLINK_MEMBER__'] = 'OnlinePaymentLinkUniquePerMember';
2195 }
2196 if (isModEnabled('don')) {
2197 $tmparray['__ONLINEPAYMENTLINK_DONATION__'] = 'OnlinePaymentLinkUniquePerDonation';
2198 }
2199 if (isModEnabled('invoice')) {
2200 $tmparray['__ONLINEPAYMENTLINK_INVOICE__'] = 'OnlinePaymentLinkUniquePerInvoice';
2201 }
2202 if (isModEnabled('order')) {
2203 $tmparray['__ONLINEPAYMENTLINK_ORDER__'] = 'OnlinePaymentLinkUniquePerOrder';
2204 }
2205 if (isModEnabled('contract')) {
2206 $tmparray['__ONLINEPAYMENTLINK_CONTRACTLINE__'] = 'OnlinePaymentLinkUniquePerContractLine';
2207 }
2208 }
2209 } else {
2210 /* No need to show into tooltip help, option is not enabled
2211 $vars['__SECUREKEYPAYMENT__']='';
2212 $vars['__SECUREKEYPAYMENT_MEMBER__']='';
2213 $vars['__SECUREKEYPAYMENT_INVOICE__']='';
2214 $vars['__SECUREKEYPAYMENT_ORDER__']='';
2215 $vars['__SECUREKEYPAYMENT_CONTRACTLINE__']='';
2216 */
2217 }
2218 if (getDolGlobalString('MEMBER_ENABLE_PUBLIC')) {
2219 $tmparray['__PUBLICLINK_NEWMEMBERFORM__'] = 'BlankSubscriptionForm';
2220 }
2221 }
2222
2223 foreach ($tmparray as $key => $val) {
2224 if (empty($val)) {
2225 $tmparray[$key] = $key;
2226 }
2227 }
2228
2229 return $tmparray;
2230 }
2231}
2232
2233
2234require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
2235
2241class ModelMail extends CommonObject
2242{
2246 public $element = 'email_template';
2247
2251 public $table_element = 'c_email_templates';
2252
2253
2254 // BEGIN MODULEBUILDER PROPERTIES
2258 public $fields = array(
2259 "rowid" => array("type" => "integer", "label" => "TechnicalID", 'enabled' => 1, 'position' => 10, 'notnull' => 1, 'visible' => -1,),
2260 "module" => array("type" => "varchar(32)", "label" => "Module", 'enabled' => 1, 'position' => 20, 'notnull' => 0, 'visible' => -1,),
2261 "type_template" => array("type" => "varchar(32)", "label" => "Typetemplate", 'enabled' => 1, 'position' => 25, 'notnull' => 0, 'visible' => -1,),
2262 "lang" => array("type" => "varchar(6)", "label" => "Lang", 'enabled' => 1, 'position' => 30, 'notnull' => 0, 'visible' => -1,),
2263 "private" => array("type" => "smallint(6)", "label" => "Private", 'enabled' => 1, 'position' => 35, 'notnull' => 1, 'visible' => -1,),
2264 "fk_user" => array("type" => "integer:User:user/class/user.class.php", "label" => "Fkuser", 'enabled' => 1, 'position' => 40, 'notnull' => 0, 'visible' => -1, "css" => "maxwidth500 widthcentpercentminusxx", "csslist" => "tdoverflowmax150",),
2265 "datec" => array("type" => "datetime", "label" => "DateCreation", 'enabled' => 1, 'position' => 45, 'notnull' => 0, 'visible' => -1,),
2266 "tms" => array("type" => "timestamp", "label" => "DateModification", 'enabled' => 1, 'position' => 50, 'notnull' => 1, 'visible' => -1,),
2267 "label" => array("type" => "varchar(255)", "label" => "Label", 'enabled' => 1, 'position' => 55, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1, "css" => "minwidth300", "cssview" => "wordbreak", "csslist" => "tdoverflowmax150",),
2268 "position" => array("type" => "smallint(6)", "label" => "Position", 'enabled' => 1, 'position' => 60, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2269 "active" => array("type" => "integer", "label" => "Active", 'enabled' => 1, 'position' => 65, 'notnull' => 1, 'visible' => -1, 'alwayseditable' => 1,),
2270 "topic" => array("type" => "text", "label" => "Topic", 'enabled' => 1, 'position' => 70, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2271 "content" => array("type" => "mediumtext", "label" => "Content", 'enabled' => 1, 'position' => 75, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2272 "content_lines" => array("type" => "text", "label" => "Contentlines", "enabled" => "getDolGlobalString('MAIN_EMAIL_TEMPLATES_FOR_OBJECT_LINES')", 'position' => 80, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2273 "enabled" => array("type" => "varchar(255)", "label" => "Enabled", 'enabled' => 1, 'position' => 85, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2274 "joinfiles" => array("type" => "varchar(255)", "label" => "Joinfiles", 'enabled' => 1, 'position' => 90, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2275 "email_from" => array("type" => "varchar(255)", "label" => "Emailfrom", 'enabled' => 1, 'position' => 95, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2276 "email_to" => array("type" => "varchar(255)", "label" => "Emailto", 'enabled' => 1, 'position' => 100, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2277 "email_tocc" => array("type" => "varchar(255)", "label" => "Emailtocc", 'enabled' => 1, 'position' => 105, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2278 "email_tobcc" => array("type" => "varchar(255)", "label" => "Emailtobcc", 'enabled' => 1, 'position' => 110, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2279 "defaultfortype" => array("type" => "smallint(6)", "label" => "Defaultfortype", 'enabled' => 1, 'position' => 115, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2280 );
2284 public $rowid;
2288 public $type_template;
2292 public $datec;
2296 public $tms;
2300 public $active;
2304 public $enabled;
2308 public $defaultfortype;
2309
2313 public $id;
2314
2318 public $label;
2319
2323 public $fk_user;
2324
2328 public $private;
2329
2333 public $topic;
2334
2338 public $content;
2342 public $content_lines;
2343
2347 public $lang;
2351 public $joinfiles;
2352
2356 public $email_from;
2360 public $email_to;
2364 public $email_tocc;
2368 public $email_tobcc;
2369
2373 public $module;
2374
2378 public $position;
2379 // END MODULEBUILDER PROPERTIES
2380
2381
2382
2388 public function __construct(DoliDB $db)
2389 {
2390 global $langs;
2391
2392 $this->db = $db;
2393 $this->ismultientitymanaged = 0;
2394 $this->isextrafieldmanaged = 1;
2395
2396 // @phan-suppress-next-line PhanTypeMismatchProperty
2397 if (!getDolGlobalInt('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid']) && !empty($this->fields['ref'])) {
2398 $this->fields['rowid']['visible'] = 0;
2399 }
2400 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
2401 $this->fields['entity']['enabled'] = 0;
2402 }
2403
2404 // Example to show how to set values of fields definition dynamically
2405 /*if ($user->hasRight('test', 'mailtemplate', 'read')) {
2406 $this->fields['myfield']['visible'] = 1;
2407 $this->fields['myfield']['noteditable'] = 0;
2408 }*/
2409
2410 // Unset fields that are disabled
2411 foreach ($this->fields as $key => $val) {
2412 if (isset($val['enabled']) && empty($val['enabled'])) {
2413 unset($this->fields[$key]);
2414 }
2415 }
2416
2417 // Translate some data of arrayofkeyval
2418 if (is_object($langs)) {
2419 foreach ($this->fields as $key => $val) {
2420 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
2421 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
2422 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
2423 }
2424 }
2425 }
2426 }
2427 }
2428
2429
2439 public function fetch($id, $ref = null, $noextrafields = 0, $nolines = 0)
2440 {
2441 // The table llx_c_email_templates has no field ref. The field ref was named "label" instead. So we change the call to fetchCommon.
2442 //$result = $this->fetchCommon($id, $ref, '', $noextrafields);
2443 $result = $this->fetchCommon($id, '', (empty($ref) ? '' : " AND t.label = '".$this->db->escape($ref)."'"), $noextrafields);
2444
2445 if ($result > 0 && !empty($this->table_element_line) && empty($nolines)) {
2446 $this->fetchLines($noextrafields);
2447 }
2448 return $result;
2449 }
2450}
print $object position
Definition edit.php:204
Class to manage a WYSIWYG editor.
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 permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new Form...
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 for Position.
Class to manage translations.
Class to manage Dolibarr users.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:171
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").
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0, $level=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
dol_mimetype($file, $default='application/octet-stream', $mode=0)
Return MIME type of a file from its name with extension.
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
img_mime($file, $titlealt='', $morecss='')
Show MIME img of a file.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
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.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='')
Show information in HTML for admin users or standard users.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
ui state ui widget content ui state ui widget header ui state a ui button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
$conf db user
Active Directory does not allow anonymous connections.
Definition repair.php:154
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:150
getMaxFileSizeArray()
Return the max allowed for file upload.