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, $outputlangs)."\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 // Pass $outputlangs so __(TranslationKey)__ in the template body is resolved
1087 // in the language of the selected email template, not the operator's language
1088 // (see issue #34540).
1089 $defaultmessage = make_substitutions($defaultmessage, $this->substit, $outputlangs);
1090 // Clean first \n and br (to avoid empty line when CONTACTCIVNAME is empty)
1091 $defaultmessage = preg_replace("/^(<br>)+/", "", $defaultmessage);
1092 $defaultmessage = preg_replace("/^\n+/", "", $defaultmessage);
1093 }
1094
1095 $out .= '<tr>';
1096 $out .= '<td class="tdtop">';
1097 $out .= $form->textwithpicto($langs->trans('MailText'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltipfrombody');
1098 $out .= '</td>';
1099 $out .= '<td class="tdtop">';
1100
1101 $formmail = $this;
1102 $showlinktolayout = ($formmail->withfckeditor && getDolGlobalInt('MAIN_EMAIL_USE_LAYOUT')) ? $formmail->withlayout : '';
1103 $showlinktolayoutlabel = $langs->trans("FillMessageWithALayout");
1104 $showlinktoai = ($formmail->withaiprompt && isModEnabled('ai')) ? 'textgenerationemail' : '';
1105 $showlinktoailabel = $langs->trans("FillMessageWithAIContent");
1106 $formatforouput = '';
1107 $htmlname = 'message';
1108
1109 // Fill $out
1110 include DOL_DOCUMENT_ROOT.'/core/tpl/formlayoutai.tpl.php';
1111
1112 $out .= '</td>';
1113 $out .= '</tr>';
1114
1115 $out .= '<tr>';
1116 $out .= '<td colspan="2">';
1117 if ($this->withbodyreadonly) {
1118 $out .= nl2br($defaultmessage);
1119 $out .= '<input type="hidden" id="message" name="message" disabled value="'.$defaultmessage.'" />';
1120 } else {
1121 if (!isset($this->ckeditortoolbar)) {
1122 $this->ckeditortoolbar = 'dolibarr_mailings';
1123 }
1124
1125 // Editor wysiwyg
1126 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1127 if ($this->withfckeditor == -1) {
1128 if (getDolGlobalString('FCKEDITOR_ENABLE_MAIL')) {
1129 $this->withfckeditor = 1;
1130 } else {
1131 $this->withfckeditor = 0;
1132 }
1133 }
1134
1135 $doleditor = new DolEditor('message', $defaultmessage, '', 280, $this->ckeditortoolbar, 'In', true, true, $this->withfckeditor, 8, '95%');
1136 $out .= $doleditor->Create(1);
1137 }
1138 $out .= "</td></tr>\n";
1139 }
1140
1141 $out .= '</table>'."\n";
1142
1143 if ($this->withform == 1 || $this->withform == -1) {
1144 $out .= '<div class="center">';
1145 $out .= '<input type="submit" class="button button-add" id="sendmail" name="sendmail" value="'.$langs->trans("SendMail").'"';
1146 // Add a javascript test to avoid to forget to submit file before sending email
1147 if ($this->withfile == 2 && $conf->use_javascript_ajax) {
1148 $out .= ' onClick="if (document.mailform.addedfile.value != \'\') { alert(\''.dol_escape_js($langs->trans("FileWasNotUploaded")).'\'); return false; } else { return true; }"';
1149 }
1150 $out .= ' />';
1151 if ($this->withcancel) {
1152 $out .= '<input class="button button-cancel" type="submit" id="cancel" name="cancel" value="'.$langs->trans("Cancel").'" />';
1153 }
1154 $out .= '</div>'."\n";
1155 }
1156
1157 if ($this->withform == 1) {
1158 $out .= '</form>'."\n";
1159 }
1160
1161 // Disable enter key if option MAIN_MAILFORM_DISABLE_ENTERKEY is set
1162 if (getDolGlobalString('MAIN_MAILFORM_DISABLE_ENTERKEY')) {
1163 $out .= '<script nonce="'.getNonce().'" type="text/javascript">';
1164 $out .= 'jQuery(document).ready(function () {';
1165 $out .= ' $(document).on("keypress", \'#mailform\', function (e) { /* Note this is called at every key pressed ! */
1166 var code = e.keyCode || e.which;
1167 if (code == 13) {
1168 console.log("Enter was intercepted and blocked");
1169 e.preventDefault();
1170 return false;
1171 }
1172 });';
1173 $out .= ' })';
1174 $out .= '</script>';
1175 }
1176
1177 $out .= "<!-- End form mail -->\n";
1178
1179 return $out;
1180 }
1181 }
1182
1188 public function getHtmlForTo()
1189 {
1190 global $langs, $form;
1191 $out = '<tr><td class="fieldrequired">';
1192 if ($this->withtofree) {
1193 $out .= $form->textwithpicto($langs->trans("MailTo"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"));
1194 } else {
1195 $out .= $langs->trans("MailTo");
1196 }
1197 $out .= '</td><td>';
1198 if ($this->withtoreadonly) {
1199 if (!empty($this->toname) && !empty($this->tomail)) {
1200 $out .= '<input type="hidden" id="toname" name="toname" value="'.$this->toname.'" />';
1201 $out .= '<input type="hidden" id="tomail" name="tomail" value="'.$this->tomail.'" />';
1202 if ($this->totype == 'thirdparty') {
1203 $soc = new Societe($this->db);
1204 $soc->fetch($this->toid);
1205 $out .= $soc->getNomUrl(1);
1206 } elseif ($this->totype == 'contact') {
1207 $contact = new Contact($this->db);
1208 $contact->fetch($this->toid);
1209 $out .= $contact->getNomUrl(1);
1210 } else {
1211 $out .= $this->toname;
1212 }
1213 $out .= ' &lt;'.$this->tomail.'&gt;';
1214 if ($this->withtofree) {
1215 $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) : "").'" />';
1216 }
1217 } else {
1218 // Note withto may be a text like 'AllRecipientSelected'
1219 $out .= (!is_array($this->withto) && !is_numeric($this->withto)) ? $this->withto : "";
1220 }
1221 } else {
1222 // The free input of email
1223 if (!empty($this->withtofree)) {
1224 $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) : "")).'" />';
1225 }
1226 // The select combo
1227 if (!empty($this->withto) && is_array($this->withto)) {
1228 if (!empty($this->withtofree)) {
1229 $out .= " ".$langs->trans("and")."/".$langs->trans("or")." ";
1230 }
1231
1232 $tmparray = $this->withto;
1233 foreach ($tmparray as $key => $val) {
1234 if (is_array($val)) {
1235 $label = $val['label'];
1236 } else {
1237 $label = $val;
1238 }
1239
1240 $tmparray[$key] = array();
1241 $tmparray[$key]['id'] = $key;
1242
1243 $tmparray[$key]['label'] = $label;
1244 $tmparray[$key]['label'] = str_replace(array('<', '>'), array('(', ')'), $tmparray[$key]['label']);
1245 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
1246 $tmparray[$key]['label'] = dol_htmlentities($tmparray[$key]['label'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', true);
1247
1248 $tmparray[$key]['labelhtml'] = $label;
1249 $tmparray[$key]['labelhtml'] = str_replace(array('&lt;', '<', '&gt;', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $tmparray[$key]['labelhtml']);
1250 $tmparray[$key]['labelhtml'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('<span class="opacitymedium">(', ')</span>'), $tmparray[$key]['labelhtml']);
1251 }
1252
1253 $withtoselected = GETPOST("receiver", 'array'); // Array of selected value
1254 if (!getDolGlobalInt('MAIN_MAIL_NO_WITH_TO_SELECTED')) {
1255 if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') {
1256 $withtoselected = array_keys($tmparray);
1257 }
1258 }
1259
1260 $out .= $form->multiselectarray("receiver", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, 0);
1261 }
1262 }
1263 $out .= "</td></tr>\n";
1264 return $out;
1265 }
1266
1272 public function getHtmlForCc()
1273 {
1274 global $langs, $form;
1275 $out = '<tr><td>';
1276 $out .= $form->textwithpicto($langs->trans("MailCC"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"));
1277 $out .= '</td><td>';
1278 if ($this->withtoccreadonly) {
1279 $out .= (!is_array($this->withtocc) && !is_numeric($this->withtocc)) ? $this->withtocc : "";
1280 } else {
1281 $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 : '')).'" />';
1282 if (!empty($this->withtocc) && is_array($this->withtocc)) {
1283 $out .= " ".$langs->trans("and")."/".$langs->trans("or")." ";
1284
1285 $tmparray = $this->withtocc;
1286 foreach ($tmparray as $key => $val) {
1287 if (is_array($val)) {
1288 $label = $val['label'];
1289 } else {
1290 $label = $val;
1291 }
1292
1293 $tmparray[$key] = array();
1294 $tmparray[$key]['id'] = $key;
1295
1296 $tmparray[$key]['label'] = $label;
1297 $tmparray[$key]['label'] = str_replace(array('<', '>'), array('(', ')'), $tmparray[$key]['label']);
1298 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
1299 $tmparray[$key]['label'] = dol_htmlentities($tmparray[$key]['label'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', true);
1300
1301 $tmparray[$key]['labelhtml'] = $label;
1302 $tmparray[$key]['labelhtml'] = str_replace(array('&lt;', '<', '&gt;', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $tmparray[$key]['labelhtml']);
1303 $tmparray[$key]['labelhtml'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('<span class="opacitymedium">(', ')</span>'), $tmparray[$key]['labelhtml']);
1304 }
1305
1306 $withtoccselected = GETPOST("receivercc", 'array'); // Array of selected value
1307
1308 $out .= $form->multiselectarray("receivercc", $tmparray, $withtoccselected, 0, 0, 'inline-block minwidth500', 0, 0);
1309 }
1310 }
1311 $out .= "</td></tr>\n";
1312 return $out;
1313 }
1314
1321 public function getHtmlForWithCcc()
1322 {
1323 global $langs, $form;
1324
1325 $out = '<tr><td>';
1326 $out .= $form->textwithpicto($langs->trans("MailCCC"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"));
1327 $out .= '</td><td>';
1328 if (!empty($this->withtocccreadonly)) {
1329 $out .= (!is_array($this->withtoccc) && !is_numeric($this->withtoccc)) ? $this->withtoccc : "";
1330 } else {
1331 $out .= '<input class="minwidth200" id="sendtoccc" name="sendtoccc" value="'.(GETPOSTISSET("sendtoccc") ? GETPOST("sendtoccc", "alpha") : ((!is_array($this->withtoccc) && !is_numeric($this->withtoccc)) ? $this->withtoccc : '')).'" />';
1332 if (!empty($this->withtoccc) && is_array($this->withtoccc)) {
1333 $out .= " ".$langs->trans("and")."/".$langs->trans("or")." ";
1334
1335 $tmparray = $this->withtoccc;
1336 foreach ($tmparray as $key => $val) {
1337 if (is_array($val)) {
1338 $label = $val['label'];
1339 } else {
1340 $label = $val;
1341 }
1342 $tmparray[$key] = array();
1343 $tmparray[$key]['id'] = $key;
1344
1345 $tmparray[$key]['label'] = $label;
1346 $tmparray[$key]['label'] = str_replace(array('<', '>'), array('(', ')'), $tmparray[$key]['label']);
1347 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
1348 $tmparray[$key]['label'] = dol_htmlentities($tmparray[$key]['label'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', true);
1349
1350 $tmparray[$key]['labelhtml'] = $label;
1351 $tmparray[$key]['labelhtml'] = str_replace(array('&lt;', '<', '&gt;', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $tmparray[$key]['labelhtml']);
1352 $tmparray[$key]['labelhtml'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('<span class="opacitymedium">(', ')</span>'), $tmparray[$key]['labelhtml']);
1353 }
1354
1355 $withtocccselected = GETPOST("receiverccc", 'array'); // Array of selected value
1356
1357 $out .= $form->multiselectarray("receiverccc", $tmparray, $withtocccselected, 0, 0, 'inline-block minwidth500', 0, 0);
1358 }
1359 }
1360
1361 $showinfobcc = '';
1362 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_PROPOSAL_TO') && !empty($this->param['models']) && $this->param['models'] == 'propal_send') {
1363 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_PROPOSAL_TO');
1364 }
1365 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_ORDER_TO') && !empty($this->param['models']) && $this->param['models'] == 'order_send') {
1366 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_ORDER_TO');
1367 }
1368 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_INVOICE_TO') && !empty($this->param['models']) && $this->param['models'] == 'facture_send') {
1369 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_INVOICE_TO');
1370 }
1371 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_PROPOSAL_TO') && !empty($this->param['models']) && $this->param['models'] == 'supplier_proposal_send') {
1372 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_PROPOSAL_TO');
1373 }
1374 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_ORDER_TO') && !empty($this->param['models']) && $this->param['models'] == 'order_supplier_send') {
1375 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_ORDER_TO');
1376 }
1377 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_INVOICE_TO') && !empty($this->param['models']) && $this->param['models'] == 'invoice_supplier_send') {
1378 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_INVOICE_TO');
1379 }
1380 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.
1381 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_PROJECT_TO');
1382 }
1383 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SHIPMENT_TO') && !empty($this->param['models']) && $this->param['models'] == 'shipping_send') {
1384 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SHIPMENT_TO');
1385 }
1386 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_RECEPTION_TO') && !empty($this->param['models']) && $this->param['models'] == 'reception_send') {
1387 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_RECEPTION_TO');
1388 }
1389 if ($showinfobcc) {
1390 $out .= ' + '.$showinfobcc;
1391 }
1392 $out .= "</td></tr>\n";
1393 return $out;
1394 }
1395
1401 public function getHtmlForWithErrorsTo()
1402 {
1403 global $langs;
1404
1405 //if (! $this->errorstomail) $this->errorstomail=$this->frommail;
1406 $errorstomail = getDolGlobalString('MAIN_MAIL_ERRORS_TO', (!empty($this->errorstomail) ? $this->errorstomail : ''));
1407 if ($this->witherrorstoreadonly) {
1408 $out = '<tr><td>'.$langs->trans("MailErrorsTo").'</td><td>';
1409 $out .= '<input type="hidden" id="errorstomail" name="errorstomail" value="'.$errorstomail.'" />';
1410 $out .= $errorstomail;
1411 $out .= "</td></tr>\n";
1412 } else {
1413 $out = '<tr><td>'.$langs->trans("MailErrorsTo").'</td><td>';
1414 $out .= '<input class="minwidth200" id="errorstomail" name="errorstomail" value="'.$errorstomail.'" />';
1415 $out .= "</td></tr>\n";
1416 }
1417 return $out;
1418 }
1419
1425 public function getHtmlForDeliveryreceipt()
1426 {
1427 global $langs;
1428
1429 $out = '<tr><td><label for="deliveryreceipt">'.$langs->trans("DeliveryReceipt").'</label></td><td>';
1430
1431 if (!empty($this->withdeliveryreceiptreadonly)) {
1432 $out .= yn($this->withdeliveryreceipt);
1433 } else {
1434 $defaultvaluefordeliveryreceipt = 0;
1435 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_PROPAL') && !empty($this->param['models']) && $this->param['models'] == 'propal_send') {
1436 $defaultvaluefordeliveryreceipt = 1;
1437 }
1438 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_SUPPLIER_PROPOSAL') && !empty($this->param['models']) && $this->param['models'] == 'supplier_proposal_send') {
1439 $defaultvaluefordeliveryreceipt = 1;
1440 }
1441 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_ORDER') && !empty($this->param['models']) && $this->param['models'] == 'order_send') {
1442 $defaultvaluefordeliveryreceipt = 1;
1443 }
1444 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_INVOICE') && !empty($this->param['models']) && $this->param['models'] == 'facture_send') {
1445 $defaultvaluefordeliveryreceipt = 1;
1446 }
1447 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_SUPPLIER_ORDER') && !empty($this->param['models']) && $this->param['models'] == 'order_supplier_send') {
1448 $defaultvaluefordeliveryreceipt = 1;
1449 }
1450 //$out .= $form->selectyesno('deliveryreceipt', (GETPOSTISSET("deliveryreceipt") ? GETPOST("deliveryreceipt") : $defaultvaluefordeliveryreceipt), 1);
1451 $out .= '<input type="checkbox" id="deliveryreceipt" name="deliveryreceipt" value="1"'.((GETPOSTISSET("deliveryreceipt") ? GETPOST("deliveryreceipt") : $defaultvaluefordeliveryreceipt) ? ' checked="checked"' : '').'>';
1452 }
1453 $out .= "</td></tr>\n";
1454 return $out;
1455 }
1456
1464 public function getHtmlForTopic($arraydefaultmessage, $helpforsubstitution)
1465 {
1466 global $conf, $langs, $form;
1467
1468 $defaulttopic = GETPOST('subject', 'restricthtml');
1469
1470 if (!GETPOST('modelselected', 'alpha') || GETPOST('modelmailselected') != '-1') {
1471 if ($arraydefaultmessage && $arraydefaultmessage->topic) {
1472 $defaulttopic = $arraydefaultmessage->topic;
1473 } elseif (!is_numeric($this->withtopic)) {
1474 $defaulttopic = $this->withtopic;
1475 }
1476 }
1477
1478 // Resolve __(TranslationKey)__ in the language of the selected template
1479 // (see issue #34540). Falls back to the caller's language when the template
1480 // has no explicit language pinned.
1481 $outputlangs = $langs;
1482 if (is_object($arraydefaultmessage) && !empty($arraydefaultmessage->lang)) {
1483 $outputlangs = new Translate("", $conf);
1484 $outputlangs->setDefaultLang($arraydefaultmessage->lang);
1485 $outputlangs->load('other');
1486 }
1487
1488 $defaulttopic = make_substitutions($defaulttopic, $this->substit, $outputlangs);
1489
1490 $out = '<tr>';
1491 $out .= '<td class="fieldrequired">';
1492 $out .= $form->textwithpicto($langs->trans('MailTopic'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltipfromtopic');
1493 $out .= '</td>';
1494 $out .= '<td>';
1495 if ($this->withtopicreadonly) {
1496 $out .= $defaulttopic;
1497 $out .= '<input type="hidden" class="quatrevingtpercent" id="subject" name="subject" value="'.$defaulttopic.'" />';
1498 } else {
1499 $out .= '<input type="text" class="quatrevingtpercent" id="subject" name="subject" value="'.((GETPOSTISSET("subject") && !GETPOST('modelselected')) ? GETPOST("subject") : ($defaulttopic ? $defaulttopic : '')).'" />';
1500 }
1501 $out .= "</td></tr>\n";
1502 return $out;
1503 }
1504
1513 public function getSectionForAIPrompt($function = 'textgeneration', $format = '', $htmlContent = 'message')
1514 {
1515 global $langs;
1516
1517 $langs->load("other");
1518
1519 $htmlContent = preg_replace('/[^a-z0-9_]/', '', $htmlContent);
1520
1521 $out = '<div id="ai_input'.$htmlContent.'" class="hidden paddingtop paddingbottom">';
1522 $out .= '<input type="text" class="quatrevingtpercent" id="ai_instructions'.$htmlContent.'" name="instruction" placeholder="'.$langs->trans("EnterYourAIPromptHere").'..." />';
1523 $out .= '<input id="generate_button'.$htmlContent.'" type="button" class="button smallpaddingimp" value="'.$langs->trans('Generate').'"/>';
1524 $out .= '<div id="ai_status_message'.$htmlContent.'" class="fieldrequired hideobject marginrightonly margintoponly">';
1525 $out .= '<i class="fa fa-spinner fa-spin fa-2x fa-fw valignmiddle marginrightonly"></i>'.$langs->trans("AIProcessingPleaseWait", getDolGlobalString('AI_API_SERVICE', 'chatgpt'));
1526 $out .= '</div>';
1527
1528 if ($function == 'imagegeneration') {
1529 $out .= '<div id="ai_image_result" class="margintoponly"></div>'; // Div for displaying the generated image
1530 }
1531
1532 $out .= "</div>\n";
1533
1534 $out .= "<script type='text/javascript'>
1535 $(document).ready(function() {
1536 // for keydown
1537 $('#ai_instructions".$htmlContent."').keydown(function(event) {
1538 if (event.keyCode === 13) {
1539 event.preventDefault();
1540 $('#generate_button".$htmlContent."').click();
1541 }
1542 });
1543
1544 $('#generate_button".$htmlContent."').click(function() {
1545 console.log('We click on generate_button".$htmlContent." ai button');
1546
1547 var instructions = $('#ai_instructions".$htmlContent."').val();
1548 var timeoutfinished = 0;
1549 var apicallfinished = 0;
1550
1551 $('#ai_status_message".$htmlContent."').show();
1552 $('.icon-container .loader').show();
1553 setTimeout(function() {
1554 timeoutfinished = 1;
1555 if (apicallfinished) {
1556 $('#ai_status_message".$htmlContent."').hide();
1557 }
1558 }, 2000);
1559
1560 if ('".$function."' === 'imagegeneration') {
1561 // Handle image generation request
1562 $.ajax({
1563 url: '". DOL_URL_ROOT."/ai/ajax/generate_content.php?token=".currentToken()."',
1564 type: 'POST',
1565 contentType: 'application/json',
1566 data: JSON.stringify({
1567 'format': '".dol_escape_js($format)."', /* the format for output */
1568 'function': '".dol_escape_js($function)."', /* the AI feature to call */
1569 'instructions': instructions, /* the prompt string */
1570 }),
1571 success: function(response) {
1572 console.log('Received image URL: '+response);
1573 // Assuming response is the URL of the generated image
1574 var imageUrl = response;
1575 $('#ai_image_result').html('<img src=\"' + imageUrl + '\" alt=\"Generated Image\" />');
1576
1577 // Clear the input field
1578 $('#ai_instructions').val('');
1579
1580 apicallfinished = 1;
1581 if (timeoutfinished) {
1582 $('#ai_status_message').hide();
1583 }
1584 },
1585 error: function(xhr, status, error) {
1586 alert(error);
1587 console.error('error ajax', status, error);
1588 $('#ai_status_message').hide();
1589 }
1590 });
1591 } else {
1592
1593 // set editor in readonly
1594 if (CKEDITOR.instances.".$htmlContent.") {
1595 CKEDITOR.instances.".$htmlContent.".setReadOnly(1);
1596 }
1597
1598 $.ajax({
1599 url: '". DOL_URL_ROOT."/ai/ajax/generate_content.php?token=".currentToken()."',
1600 type: 'POST',
1601 contentType: 'application/json',
1602 data: JSON.stringify({
1603 'format': '".dol_escape_js($format)."', /* the format for output */
1604 'function': '".dol_escape_js($function)."', /* the AI feature to call */
1605 'instructions': instructions, /* the prompt string */
1606 }),
1607 success: function(response) {
1608 console.log('Add response into field \'#".$htmlContent."\': '+response);
1609
1610 jQuery('#".$htmlContent."').val(response); // If #htmlcontent is a input name or textarea
1611 jQuery('#".$htmlContent."').html(response); // If #htmlContent is a div
1612 //jQuery('#".$htmlContent."preview').val(response);
1613
1614 if (CKEDITOR.instances) {
1615 var editorInstance = CKEDITOR.instances.".$htmlContent.";
1616 if (editorInstance) {
1617 editorInstance.setReadOnly(0);
1618 editorInstance.setData(response);
1619 }
1620 //var editorInstancepreview = CKEDITOR.instances.".$htmlContent."preview;
1621 //if (editorInstancepreview) {
1622 // editorInstancepreview.setData(response);
1623 //}
1624 }
1625
1626 // remove readonly
1627 $('#ai_instructions".$htmlContent."').val('');
1628
1629 apicallfinished = 1;
1630 if (timeoutfinished) {
1631 $('#ai_status_message".$htmlContent."').hide();
1632 }
1633 },
1634 error: function(xhr, status, error) {
1635 alert(error);
1636 console.error('error ajax', status, error);
1637 $('#ai_status_message".$htmlContent."').hide();
1638 }
1639
1640 });
1641 }
1642 });
1643 });
1644 </script>
1645 ";
1646 return $out;
1647 }
1648
1656 public function getModelEmailTemplate($htmlContent = 'message', $showlinktolayout = 'email')
1657 {
1658 global $websitepage, $langs;
1659
1660 require_once DOL_DOCUMENT_ROOT.'/core/lib/emaillayout.lib.php';
1661 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1662 require_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php';
1663
1664 // Fetch blogs
1665 $websitepage = new WebsitePage($this->db);
1666 $arrayofblogs = $websitepage->fetchAll('', 'DESC', 'date_creation', 0, 0, array('type_container' => 'blogpost'));
1667
1668 $out = '<div id="template-selector" class="email-layout-container hidden" style="display:none;">';
1669
1670 // Define list of email layouts to use
1671 $layouts = array(
1672 'empty' => 'empty',
1673 );
1674 // Search available layouts on disk
1675 $arrayoflayoutemplates = dol_dir_list(DOL_DOCUMENT_ROOT.'/install/doctemplates/maillayout/', 'files', 0, '\.html$');
1676 foreach ($arrayoflayoutemplates as $layouttemplatefile) {
1677 $layoutname = preg_replace('/\.html$/i', '', $layouttemplatefile['name']);
1678
1679 // Exclude some layouts for some use cases
1680 if ($layoutname == 'news' && !in_array($showlinktolayout, array('emailing', 'websitepage'))) {
1681 continue;
1682 }
1683 if ($layoutname == 'products' && !in_array($showlinktolayout, array('emailing', 'websitepage'))) {
1684 continue;
1685 }
1686
1687 $layouts[$layoutname] = ucfirst($layoutname);
1688 }
1689 //}
1690 // TODO Add a hook to allow to complete the list
1691
1692 foreach ($layouts as $layout => $templateFunction) {
1693 $contentHtml = getHtmlOfLayout($layout);
1694
1695 $out .= '<div class="template-option" data-template="'.$layout.'" data-content="'.htmlentities($contentHtml).'">';
1696 $out .= '<img class="maillayout" alt="'.$layout.'" src="'.DOL_URL_ROOT.'/theme/common/maillayout/'.$layout.'.png" />';
1697 $out .= '<span class="template-option-text">'.$langs->trans($templateFunction).'</span>';
1698 $out .= '</div>';
1699 }
1700 $out .= '</div>';
1701
1702 // Prepare the array for multiselect
1703 $blogArray = array();
1704 if (!empty($arrayofblogs)) {
1705 foreach ($arrayofblogs as $blog) {
1706 $blogArray[$blog->id] = substr(htmlentities($blog->title), 0, 30);
1707 }
1708 }
1709
1710 // Use the multiselect array function to create the dropdown
1711 $out .= '<div id="post-dropdown-container" class="email-layout-container hidden" style="display:none;">';
1712 $out .= '<label for="blogpost-select">Select Posts: </label>';
1713 $out .= self::multiselectarray('blogpost-select', $blogArray, array(), 0, 0, 'minwidth200');
1714 $out .= '</div>';
1715
1716 $out .= '<script type="text/javascript">
1717 $(document).ready(function() {
1718 $(".template-option").click(function() {
1719 var template = $(this).data("template");
1720 var subject = jQuery("#subject").val();
1721 var fromtype = jQuery("#fromtype").val();
1722 var sendto = jQuery("#sendto").val();
1723 var sendtocc = jQuery("#sendtocc").val();
1724 var sendtoccc = jQuery("#sendtoccc").val();
1725
1726 console.log("We choose a layout for email template=" + template + ", subject="+subject);
1727
1728 $(".template-option").removeClass("selected");
1729 $(this).addClass("selected");
1730
1731 var subject = $("#sujet").val();
1732
1733 var contentHtml = $(this).data("content");
1734 contentHtml = contentHtml.replace(/__SUBJECT__/g, subject);
1735
1736 if (template === "news") {
1737 $("#post-dropdown-container").show();
1738 console.log("Displaying dropdown for news template");
1739 } else {
1740 $("#post-dropdown-container").hide();
1741
1742 var csrfToken = "' .newToken().'";
1743 $.ajax({
1744 type: "POST",
1745 url: "'.DOL_URL_ROOT.'/core/ajax/mailtemplate.php",
1746 data: {
1747 template: template,
1748 subject: subject,
1749 fromtype: fromtype,
1750 sendto: sendto,
1751 sendtocc: sendtocc,
1752 sendtoccc: sendtoccc,
1753 content: contentHtml,
1754 selectedPosts: "[]",
1755 token: csrfToken
1756 },
1757 success: function(response) {
1758 jQuery("#'.$htmlContent.'").val(response);
1759 var editorInstance = CKEDITOR.instances["'.$htmlContent.'"];
1760 if (editorInstance) {
1761 editorInstance.setData(response);
1762 }
1763 },
1764 error: function(xhr, status, error) {
1765 console.error("An error occurred: " + xhr.responseText);
1766 }
1767 });
1768 }
1769 });
1770
1771 $("#blogpost-select").change(function() {
1772 var selectedIds = $(this).val();
1773 var contentHtml = $(".template-option.selected").data("content");
1774
1775 updateSelectedPostsContent(contentHtml, selectedIds);
1776 });
1777
1778 function updateSelectedPostsContent(contentHtml, selectedIds) {
1779 var csrfToken = "' .newToken().'";
1780 $.ajax({
1781 type: "POST",
1782 url: "/core/ajax/getnews.php",
1783 data: {
1784 selectedIds: JSON.stringify(selectedIds),
1785 token : csrfToken
1786 },
1787 success: function(response) {
1788 var selectedPosts = JSON.parse(response);
1789 var subject = $("#sujet").val();
1790
1791 contentHtml = contentHtml.replace(/__SUBJECT__/g, subject);
1792
1793 $.ajax({
1794 type: "POST",
1795 url: "/core/ajax/mailtemplate.php",
1796 data: {
1797 content: contentHtml,
1798 selectedPosts: selectedIds.join(","),
1799 token: csrfToken
1800 },
1801 success: function(response) {
1802 jQuery("#'.$htmlContent.'").val(response);
1803 var editorInstance = CKEDITOR.instances["'.$htmlContent.'"];
1804 if (editorInstance) {
1805 editorInstance.setData(response);
1806 }
1807 },
1808 error: function(xhr, status, error) {
1809 console.error("An error occurred: " + xhr.responseText);
1810 }
1811 });
1812 },
1813 error: function(xhr, status, error) {
1814 console.error("An error occurred: " + xhr.responseText);
1815 }
1816 });
1817 }
1818 });
1819 </script>';
1820
1821 return $out;
1822 }
1823
1841 public function getEMailTemplate($dbs, $type_template, $user, $outputlangs, $id = 0, $active = 1, $label = '', $defaultfortype = -1)
1842 {
1843 global $conf;
1844
1845 if ($id == -2 && empty($label)) {
1846 $this->error = 'LabelIsMandatoryWhenIdIs-2or-3';
1847 return -1;
1848 }
1849
1850 $ret = new ModelMail($dbs);
1851
1852 $languagetosearch = (is_object($outputlangs) ? $outputlangs->defaultlang : '');
1853 // Define $languagetosearchmain to fall back on main language (for example to get 'es_ES' for 'es_MX')
1854 $tmparray = explode('_', $languagetosearch);
1855 $languagetosearchmain = $tmparray[0].'_'.strtoupper($tmparray[0]);
1856 if ($languagetosearchmain == $languagetosearch) {
1857 $languagetosearchmain = '';
1858 }
1859
1860 $sql = "SELECT rowid, entity, module, label, type_template, topic, email_from, joinfiles, content, content_lines, lang, email_from, email_to, email_tocc, email_tobcc";
1861 $sql .= " FROM ".$dbs->prefix().'c_email_templates';
1862 $sql .= " WHERE (type_template = '".$dbs->escape($type_template)."' OR type_template = 'all')";
1863 $sql .= " AND entity IN (".getEntity('c_email_templates').")";
1864 $sql .= " AND (private = 0 OR fk_user = ".((int) $user->id).")"; // Get all public or private owned
1865 if ($active >= 0) {
1866 $sql .= " AND active = ".((int) $active);
1867 }
1868 if ($defaultfortype >= 0) {
1869 $sql .= " AND defaultfortype = ".((int) $defaultfortype);
1870 }
1871 if ($label) {
1872 $sql .= " AND label = '".$dbs->escape($label)."'";
1873 }
1874 if (!($id > 0) && $languagetosearch) {
1875 $sql .= " AND (lang = '".$dbs->escape($languagetosearch)."'".($languagetosearchmain ? " OR lang = '".$dbs->escape($languagetosearchmain)."'" : "")." OR lang IS NULL OR lang = '')";
1876 }
1877 if ($id > 0) {
1878 $sql .= " AND rowid = ".(int) $id;
1879 }
1880 if ($id == -1) {
1881 $sql .= " AND position = 0";
1882 }
1883 $sql .= " AND entity IN(".getEntity('c_email_templates', 1).")";
1884 if ($languagetosearch) {
1885 $sql .= $dbs->order("position,lang,label", "ASC,DESC,ASC"); // We want line with lang set first, then with lang null or ''
1886 } else {
1887 $sql .= $dbs->order("position,lang,label", "ASC,ASC,ASC"); // If no language provided, we give priority to lang not defined
1888 }
1889 //$sql .= $dbs->plimit(1);
1890 //print $sql;
1891
1892 $resql = $dbs->query($sql);
1893 if (!$resql) {
1894 dol_print_error($dbs);
1895 return -1;
1896 }
1897
1898 // Get first found
1899 while (1) {
1900 $obj = $dbs->fetch_object($resql);
1901
1902 if ($obj) {
1903 // If template is for a module, check module is enabled; if not, take next template
1904 if ($obj->module) {
1905 $tempmodulekey = $obj->module;
1906 if (empty($conf->$tempmodulekey) || !isModEnabled($tempmodulekey)) {
1907 continue;
1908 }
1909 }
1910
1911 // If a record was found
1912 $ret->id = $obj->rowid;
1913 $ret->module = $obj->module;
1914 $ret->label = $obj->label;
1915 $ret->lang = $obj->lang;
1916 $ret->topic = $obj->topic;
1917 $ret->content = $obj->content;
1918 $ret->content_lines = $obj->content_lines;
1919 $ret->joinfiles = $obj->joinfiles;
1920 $ret->email_from = $obj->email_from;
1921
1922 break;
1923 } else {
1924 // If no record found
1925 if ($id == -2) {
1926 // Not found with the provided label
1927 return -1;
1928 } else {
1929 // If there is no template at all
1930 $defaultmessage = '';
1931
1932 if ($type_template == 'body') {
1933 // Special case to use this->withbody as content
1934 $defaultmessage = $this->withbody;
1935 } elseif ($type_template == 'facture_send') {
1936 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendInvoice");
1937 } elseif ($type_template == 'facture_relance') {
1938 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendInvoiceReminder");
1939 } elseif ($type_template == 'propal_send') {
1940 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendProposal");
1941 } elseif ($type_template == 'supplier_proposal_send') {
1942 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendSupplierProposal");
1943 } elseif ($type_template == 'order_send') {
1944 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendOrder");
1945 } elseif ($type_template == 'order_supplier_send') {
1946 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendSupplierOrder");
1947 } elseif ($type_template == 'invoice_supplier_send') {
1948 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendSupplierInvoice");
1949 } elseif ($type_template == 'shipping_send') {
1950 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendShipping");
1951 } elseif ($type_template == 'fichinter_send') {
1952 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendFichInter");
1953 } elseif ($type_template == 'actioncomm_send') {
1954 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendActionComm");
1955 } elseif (!empty($type_template)) {
1956 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentGeneric");
1957 }
1958
1959 $ret->label = 'default';
1960 $ret->lang = $outputlangs->defaultlang;
1961 $ret->topic = '';
1962 $ret->joinfiles = 1;
1963 $ret->content = $defaultmessage;
1964 $ret->content_lines = '';
1965
1966 break;
1967 }
1968 }
1969 }
1970
1971 $dbs->free($resql);
1972
1973 return $ret;
1974 }
1975
1985 public function isEMailTemplate($type_template, $user, $outputlangs)
1986 {
1987 $sql = "SELECT label, topic, content, lang";
1988 $sql .= " FROM ".$this->db->prefix().'c_email_templates';
1989 $sql .= " WHERE type_template='".$this->db->escape($type_template)."'";
1990 $sql .= " AND entity IN (".getEntity('c_email_templates').")";
1991 $sql .= " AND (fk_user is NULL or fk_user = 0 or fk_user = ".((int) $user->id).")";
1992 if (is_object($outputlangs)) {
1993 $sql .= " AND (lang = '".$this->db->escape($outputlangs->defaultlang)."' OR lang IS NULL OR lang = '')";
1994 }
1995 $sql .= $this->db->order("lang,label", "ASC");
1996 //print $sql;
1997
1998 $resql = $this->db->query($sql);
1999 if ($resql) {
2000 $num = $this->db->num_rows($resql);
2001 $this->db->free($resql);
2002 return $num;
2003 } else {
2004 $this->error = get_class($this).' '.__METHOD__.' ERROR:'.$this->db->lasterror();
2005 return -1;
2006 }
2007 }
2008
2019 public function fetchAllEMailTemplate($type_template, $user, $outputlangs, $active = 1)
2020 {
2021 global $db, $conf;
2022
2023 $sql = "SELECT rowid, module, label, topic, content, content_lines, lang, fk_user, private, position";
2024 $sql .= " FROM ".$this->db->prefix().'c_email_templates';
2025 $sql .= " WHERE type_template IN ('".$this->db->escape($type_template)."', 'all')";
2026 $sql .= " AND entity IN (".getEntity('c_email_templates').")";
2027 $sql .= " AND (private = 0 OR fk_user = ".((int) $user->id).")"; // See all public templates or templates I own.
2028 if ($active >= 0) {
2029 $sql .= " AND active = ".((int) $active);
2030 }
2031 //if (is_object($outputlangs)) $sql.= " AND (lang = '".$this->db->escape($outputlangs->defaultlang)."' OR lang IS NULL OR lang = '')"; // Return all languages
2032 $sql .= $this->db->order("position,lang,label", "ASC");
2033 //print $sql;
2034
2035 $resql = $this->db->query($sql);
2036 if ($resql) {
2037 $num = $this->db->num_rows($resql);
2038 $this->lines_model = array();
2039 while ($obj = $this->db->fetch_object($resql)) {
2040 // If template is for a module, check module is enabled.
2041 if ($obj->module) {
2042 $tempmodulekey = $obj->module;
2043 if (empty($conf->$tempmodulekey) || !isModEnabled($tempmodulekey)) {
2044 continue;
2045 }
2046 }
2047
2048 $line = new ModelMail($db);
2049 $line->id = $obj->rowid;
2050 $line->label = $obj->label;
2051 $line->lang = $obj->lang;
2052 $line->fk_user = $obj->fk_user;
2053 $line->private = $obj->private;
2054 $line->position = $obj->position;
2055 $line->topic = $obj->topic;
2056 $line->content = $obj->content;
2057 $line->content_lines = $obj->content_lines;
2058
2059 $this->lines_model[] = $line;
2060 }
2061 $this->db->free($resql);
2062 return $num;
2063 } else {
2064 $this->error = get_class($this).' '.__METHOD__.' ERROR:'.$this->db->lasterror();
2065 return -1;
2066 }
2067 }
2068
2069
2070
2079 public function setSubstitFromObject($object, $outputlangs)
2080 {
2081 global $extrafields;
2082
2083 $parameters = array();
2084 $tmparray = getCommonSubstitutionArray($outputlangs, 0, null, $object);
2085 complete_substitutions_array($tmparray, $outputlangs, null, $parameters);
2086
2087 $this->substit = $tmparray;
2088
2089 // Fill substit_lines with each object lines content
2090 if (is_array($object->lines)) {
2091 foreach ($object->lines as $line) {
2092 $substit_line = array(
2093 '__PRODUCT_REF__' => isset($line->product_ref) ? $line->product_ref : '',
2094 '__PRODUCT_LABEL__' => isset($line->product_label) ? $line->product_label : '',
2095 '__PRODUCT_DESCRIPTION__' => isset($line->product_desc) ? $line->product_desc : '',
2096 '__LABEL__' => isset($line->label) ? $line->label : '',
2097 '__DESCRIPTION__' => isset($line->desc) ? $line->desc : '',
2098 '__DATE_START_YMD__' => dol_print_date($line->date_start, 'day', false, $outputlangs),
2099 '__DATE_END_YMD__' => dol_print_date($line->date_end, 'day', false, $outputlangs),
2100 '__QUANTITY__' => $line->qty,
2101 '__SUBPRICE__' => price($line->subprice),
2102 '__AMOUNT__' => price($line->total_ttc),
2103 '__AMOUNT_EXCL_TAX__' => price($line->total_ht)
2104 );
2105
2106 // Create dynamic tags for __PRODUCT_EXTRAFIELD_FIELD__
2107 if (!empty($line->fk_product)) {
2108 if (!is_object($extrafields)) {
2109 $extrafields = new ExtraFields($this->db);
2110 }
2111 $product = new Product($this->db);
2112 $product->fetch($line->fk_product, '', '', 1);
2113 $product->fetch_optionals();
2114
2115 $extrafields->fetch_name_optionals_label($product->table_element, true);
2116
2117 if (!empty($extrafields->attributes[$product->table_element]['label']) && is_array($extrafields->attributes[$product->table_element]['label']) && count($extrafields->attributes[$product->table_element]['label']) > 0) {
2118 foreach ($extrafields->attributes[$product->table_element]['label'] as $key => $label) {
2119 $substit_line['__PRODUCT_EXTRAFIELD_'.strtoupper($key).'__'] = isset($product->array_options['options_'.$key]) ? $product->array_options['options_'.$key] : '';
2120 }
2121 }
2122 }
2123
2124 $this->substit_lines[$line->id] = $substit_line; // @phan-suppress-current-line PhanTypeMismatchProperty
2125 }
2126 }
2127 }
2128
2137 public static function getAvailableSubstitKey($mode = 'formemail', $object = null)
2138 {
2139 global $langs;
2140
2141 $tmparray = array();
2142 if ($mode == 'formemail' || $mode == 'formemailwithlines' || $mode == 'formemailforlines') {
2143 $parameters = array('mode' => $mode);
2144 $tmparray = getCommonSubstitutionArray($langs, 2, null, $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 if ($mode == 'formwithlines') {
2148 $tmparray['__LINES__'] = '__LINES__'; // Will be set by the get_form function
2149 }
2150 if ($mode == 'formforlines') {
2151 $tmparray['__QUANTITY__'] = '__QUANTITY__'; // Will be set by the get_form function
2152 }
2153 }
2154
2155 if ($mode == 'emailing') {
2156 $parameters = array('mode' => $mode);
2157 $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
2158 complete_substitutions_array($tmparray, $langs, null, $parameters);
2159
2160 // For mass emailing, we have different keys specific to the data into tagerts list
2161 $tmparray['__ID__'] = 'IdRecord';
2162 $tmparray['__THIRDPARTY_CUSTOMER_CODE__'] = 'CustomerCode';
2163 $tmparray['__EMAIL__'] = 'EMailRecipient';
2164 $tmparray['__LASTNAME__'] = 'Lastname';
2165 $tmparray['__FIRSTNAME__'] = 'Firstname';
2166 $tmparray['__MAILTOEMAIL__'] = 'TagMailtoEmail';
2167 $tmparray['__OTHER1__'] = 'Other1';
2168 $tmparray['__OTHER2__'] = 'Other2';
2169 $tmparray['__OTHER3__'] = 'Other3';
2170 $tmparray['__OTHER4__'] = 'Other4';
2171 $tmparray['__OTHER5__'] = 'Other5';
2172 $tmparray['__CHECK_READ__'] = $langs->trans('TagCheckMail');
2173 $tmparray['__UNSUBSCRIBE__'] = $langs->trans('TagUnsubscribe');
2174 $tmparray['__UNSUBSCRIBE_URL__'] = $langs->trans('TagUnsubscribe').' (URL)';
2175
2176 $onlinepaymentenabled = 0;
2177 if (isModEnabled('paypal')) {
2178 $onlinepaymentenabled++;
2179 }
2180 if (isModEnabled('paybox')) {
2181 $onlinepaymentenabled++;
2182 }
2183 if (isModEnabled('stripe')) {
2184 $onlinepaymentenabled++;
2185 }
2186 if ($onlinepaymentenabled && getDolGlobalString('PAYMENT_SECURITY_TOKEN')) {
2187 $tmparray['__SECUREKEYPAYMENT__'] = getDolGlobalString('PAYMENT_SECURITY_TOKEN');
2188 if (getDolGlobalString('PAYMENT_SECURITY_TOKEN_UNIQUE')) {
2189 if (isModEnabled('member')) {
2190 $tmparray['__SECUREKEYPAYMENT_MEMBER__'] = 'SecureKeyPAYMENTUniquePerMember';
2191 }
2192 if (isModEnabled('don')) {
2193 $tmparray['__SECUREKEYPAYMENT_DONATION__'] = 'SecureKeyPAYMENTUniquePerDonation';
2194 }
2195 if (isModEnabled('invoice')) {
2196 $tmparray['__SECUREKEYPAYMENT_INVOICE__'] = 'SecureKeyPAYMENTUniquePerInvoice';
2197 }
2198 if (isModEnabled('order')) {
2199 $tmparray['__SECUREKEYPAYMENT_ORDER__'] = 'SecureKeyPAYMENTUniquePerOrder';
2200 }
2201 if (isModEnabled('contract')) {
2202 $tmparray['__SECUREKEYPAYMENT_CONTRACTLINE__'] = 'SecureKeyPAYMENTUniquePerContractLine';
2203 }
2204
2205 //Online payment link
2206 if (isModEnabled('member')) {
2207 $tmparray['__ONLINEPAYMENTLINK_MEMBER__'] = 'OnlinePaymentLinkUniquePerMember';
2208 }
2209 if (isModEnabled('don')) {
2210 $tmparray['__ONLINEPAYMENTLINK_DONATION__'] = 'OnlinePaymentLinkUniquePerDonation';
2211 }
2212 if (isModEnabled('invoice')) {
2213 $tmparray['__ONLINEPAYMENTLINK_INVOICE__'] = 'OnlinePaymentLinkUniquePerInvoice';
2214 }
2215 if (isModEnabled('order')) {
2216 $tmparray['__ONLINEPAYMENTLINK_ORDER__'] = 'OnlinePaymentLinkUniquePerOrder';
2217 }
2218 if (isModEnabled('contract')) {
2219 $tmparray['__ONLINEPAYMENTLINK_CONTRACTLINE__'] = 'OnlinePaymentLinkUniquePerContractLine';
2220 }
2221 }
2222 } else {
2223 /* No need to show into tooltip help, option is not enabled
2224 $vars['__SECUREKEYPAYMENT__']='';
2225 $vars['__SECUREKEYPAYMENT_MEMBER__']='';
2226 $vars['__SECUREKEYPAYMENT_INVOICE__']='';
2227 $vars['__SECUREKEYPAYMENT_ORDER__']='';
2228 $vars['__SECUREKEYPAYMENT_CONTRACTLINE__']='';
2229 */
2230 }
2231 if (getDolGlobalString('MEMBER_ENABLE_PUBLIC')) {
2232 $tmparray['__PUBLICLINK_NEWMEMBERFORM__'] = 'BlankSubscriptionForm';
2233 }
2234 }
2235
2236 foreach ($tmparray as $key => $val) {
2237 if (empty($val)) {
2238 $tmparray[$key] = $key;
2239 }
2240 }
2241
2242 return $tmparray;
2243 }
2244}
2245
2246
2247require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
2248
2254class ModelMail extends CommonObject
2255{
2259 public $element = 'email_template';
2260
2264 public $table_element = 'c_email_templates';
2265
2266
2267 // BEGIN MODULEBUILDER PROPERTIES
2271 public $fields = array(
2272 "rowid" => array("type" => "integer", "label" => "TechnicalID", 'enabled' => 1, 'position' => 10, 'notnull' => 1, 'visible' => -1,),
2273 "module" => array("type" => "varchar(32)", "label" => "Module", 'enabled' => 1, 'position' => 20, 'notnull' => 0, 'visible' => -1,),
2274 "type_template" => array("type" => "varchar(32)", "label" => "Typetemplate", 'enabled' => 1, 'position' => 25, 'notnull' => 0, 'visible' => -1,),
2275 "lang" => array("type" => "varchar(6)", "label" => "Lang", 'enabled' => 1, 'position' => 30, 'notnull' => 0, 'visible' => -1,),
2276 "private" => array("type" => "smallint(6)", "label" => "Private", 'enabled' => 1, 'position' => 35, 'notnull' => 1, 'visible' => -1,),
2277 "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",),
2278 "datec" => array("type" => "datetime", "label" => "DateCreation", 'enabled' => 1, 'position' => 45, 'notnull' => 0, 'visible' => -1,),
2279 "tms" => array("type" => "timestamp", "label" => "DateModification", 'enabled' => 1, 'position' => 50, 'notnull' => 1, 'visible' => -1,),
2280 "label" => array("type" => "varchar(255)", "label" => "Label", 'enabled' => 1, 'position' => 55, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1, "css" => "minwidth300", "cssview" => "wordbreak", "csslist" => "tdoverflowmax150",),
2281 "position" => array("type" => "smallint(6)", "label" => "Position", 'enabled' => 1, 'position' => 60, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2282 "active" => array("type" => "integer", "label" => "Active", 'enabled' => 1, 'position' => 65, 'notnull' => 1, 'visible' => -1, 'alwayseditable' => 1,),
2283 "topic" => array("type" => "text", "label" => "Topic", 'enabled' => 1, 'position' => 70, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2284 "content" => array("type" => "mediumtext", "label" => "Content", 'enabled' => 1, 'position' => 75, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2285 "content_lines" => array("type" => "text", "label" => "Contentlines", "enabled" => "getDolGlobalString('MAIN_EMAIL_TEMPLATES_FOR_OBJECT_LINES')", 'position' => 80, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2286 "enabled" => array("type" => "varchar(255)", "label" => "Enabled", 'enabled' => 1, 'position' => 85, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2287 "joinfiles" => array("type" => "varchar(255)", "label" => "Joinfiles", 'enabled' => 1, 'position' => 90, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2288 "email_from" => array("type" => "varchar(255)", "label" => "Emailfrom", 'enabled' => 1, 'position' => 95, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2289 "email_to" => array("type" => "varchar(255)", "label" => "Emailto", 'enabled' => 1, 'position' => 100, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2290 "email_tocc" => array("type" => "varchar(255)", "label" => "Emailtocc", 'enabled' => 1, 'position' => 105, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2291 "email_tobcc" => array("type" => "varchar(255)", "label" => "Emailtobcc", 'enabled' => 1, 'position' => 110, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2292 "defaultfortype" => array("type" => "smallint(6)", "label" => "Defaultfortype", 'enabled' => 1, 'position' => 115, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
2293 );
2297 public $rowid;
2301 public $type_template;
2305 public $datec;
2309 public $tms;
2313 public $active;
2317 public $enabled;
2321 public $defaultfortype;
2322
2326 public $id;
2327
2331 public $label;
2332
2336 public $fk_user;
2337
2341 public $private;
2342
2346 public $topic;
2347
2351 public $content;
2355 public $content_lines;
2356
2360 public $lang;
2364 public $joinfiles;
2365
2369 public $email_from;
2373 public $email_to;
2377 public $email_tocc;
2381 public $email_tobcc;
2382
2386 public $module;
2387
2391 public $position;
2392 // END MODULEBUILDER PROPERTIES
2393
2394
2395
2401 public function __construct(DoliDB $db)
2402 {
2403 global $langs;
2404
2405 $this->db = $db;
2406 $this->ismultientitymanaged = 0;
2407 $this->isextrafieldmanaged = 1;
2408
2409 // @phan-suppress-next-line PhanTypeMismatchProperty
2410 if (!getDolGlobalInt('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid']) && !empty($this->fields['ref'])) {
2411 $this->fields['rowid']['visible'] = 0;
2412 }
2413 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
2414 $this->fields['entity']['enabled'] = 0;
2415 }
2416
2417 // Example to show how to set values of fields definition dynamically
2418 /*if ($user->hasRight('test', 'mailtemplate', 'read')) {
2419 $this->fields['myfield']['visible'] = 1;
2420 $this->fields['myfield']['noteditable'] = 0;
2421 }*/
2422
2423 // Unset fields that are disabled
2424 foreach ($this->fields as $key => $val) {
2425 if (isset($val['enabled']) && empty($val['enabled'])) {
2426 unset($this->fields[$key]);
2427 }
2428 }
2429
2430 // Translate some data of arrayofkeyval
2431 if (is_object($langs)) {
2432 foreach ($this->fields as $key => $val) {
2433 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
2434 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
2435 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
2436 }
2437 }
2438 }
2439 }
2440 }
2441
2442
2452 public function fetch($id, $ref = null, $noextrafields = 0, $nolines = 0)
2453 {
2454 // The table llx_c_email_templates has no field ref. The field ref was named "label" instead. So we change the call to fetchCommon.
2455 //$result = $this->fetchCommon($id, $ref, '', $noextrafields);
2456 $result = $this->fetchCommon($id, '', (empty($ref) ? '' : " AND t.label = '".$this->db->escape($ref)."'"), $noextrafields);
2457
2458 if ($result > 0 && !empty($this->table_element_line) && empty($nolines)) {
2459 $this->fetchLines($noextrafields);
2460 }
2461 return $result;
2462 }
2463}
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.