dolibarr 21.0.0-alpha
html.formmail.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2005-2012 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2010-2011 Juanjo Menent <jmenent@2byte.es>
5 * Copyright (C) 2015-2017 Marcos García <marcosgdf@gmail.com>
6 * Copyright (C) 2015-2017 Nicolas ZABOURI <info@inovea-conseil.com>
7 * Copyright (C) 2018-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).")";
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 $validpaymentmethod = array();
1000 if (empty($this->substit['__REF__'])) { // @phan-suppress-current-line PhanTypeMismatchProperty
1001 $paymenturl = '';
1002 } else {
1003 // Set the online payment url link into __ONLINE_PAYMENT_URL__ key
1004 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
1005 $langs->loadLangs(array('paypal', 'other'));
1006 $typeforonlinepayment = 'free';
1007 if ($this->param["models"] == 'order' || $this->param["models"] == 'order_send') {
1008 $typeforonlinepayment = 'order'; // TODO use detection on something else than template
1009 }
1010 if ($this->param["models"] == 'invoice' || $this->param["models"] == 'facture_send') {
1011 $typeforonlinepayment = 'invoice'; // TODO use detection on something else than template
1012 }
1013 if ($this->param["models"] == 'member') {
1014 $typeforonlinepayment = 'member'; // TODO use detection on something else than template
1015 }
1016 $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $this->substit['__REF__']);
1017 $paymenturl = $url;
1018
1019 $validpaymentmethod = getValidOnlinePaymentMethods('');
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 } else {
1027 $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = '';
1028 $this->substit['__ONLINE_PAYMENT_URL__'] = '';
1029 }
1030
1031 $this->substit['__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__'] = '';
1032
1033 // Generate the string with the template for lines repeated and filled for each line
1034 $lines = '';
1035 $defaultlines = $arraydefaultmessage->content_lines;
1036 if (isset($defaultlines)) {
1037 foreach ($this->substit_lines as $lineid => $substit_line) {
1038 $lines .= make_substitutions($defaultlines, $substit_line)."\n";
1039 }
1040 }
1041 $this->substit['__LINES__'] = $lines;
1042
1043 $defaultmessage = str_replace('\n', "\n", $defaultmessage);
1044
1045 // Deal with format differences between message and some substitution variables (text / HTML)
1046 $atleastonecomponentishtml = 0;
1047 if (strpos($defaultmessage, '__USER_SIGNATURE__') !== false && dol_textishtml($this->substit['__USER_SIGNATURE__'])) {
1048 $atleastonecomponentishtml++;
1049 }
1050 if (strpos($defaultmessage, '__SENDEREMAIL_SIGNATURE__') !== false && dol_textishtml($this->substit['__SENDEREMAIL_SIGNATURE__'])) {
1051 $atleastonecomponentishtml++;
1052 }
1053 if (strpos($defaultmessage, '__ONLINE_PAYMENT_TEXT_AND_URL__') !== false && dol_textishtml($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'])) {
1054 $atleastonecomponentishtml++;
1055 }
1056 if (strpos($defaultmessage, '__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__') !== false && dol_textishtml($this->substit['__ONLINE_INTERVIEW_SCHEDULER_TEXT_AND_URL__'])) {
1057 $atleastonecomponentishtml++;
1058 }
1059 if (dol_textishtml($defaultmessage)) {
1060 $atleastonecomponentishtml++;
1061 }
1062 if ($atleastonecomponentishtml) {
1063 if (!dol_textishtml($this->substit['__USER_SIGNATURE__'])) {
1064 $this->substit['__USER_SIGNATURE__'] = dol_nl2br($this->substit['__USER_SIGNATURE__']);
1065 }
1066 if (!dol_textishtml($this->substit['__SENDEREMAIL_SIGNATURE__'])) {
1067 $this->substit['__SENDEREMAIL_SIGNATURE__'] = dol_nl2br($this->substit['__SENDEREMAIL_SIGNATURE__']);
1068 }
1069 if (!dol_textishtml($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'])) {
1070 $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = dol_nl2br($this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__']);
1071 }
1072 if (!dol_textishtml($defaultmessage)) {
1073 $defaultmessage = dol_nl2br($defaultmessage);
1074 }
1075 }
1076
1077 if (GETPOSTISSET("message") && !GETPOST('modelselected')) {
1078 $defaultmessage = GETPOST("message", "restricthtml");
1079 } else {
1080 $defaultmessage = make_substitutions($defaultmessage, $this->substit);
1081 // Clean first \n and br (to avoid empty line when CONTACTCIVNAME is empty)
1082 $defaultmessage = preg_replace("/^(<br>)+/", "", $defaultmessage);
1083 $defaultmessage = preg_replace("/^\n+/", "", $defaultmessage);
1084 }
1085
1086 $out .= '<tr>';
1087 $out .= '<td class="tdtop">';
1088 $out .= $form->textwithpicto($langs->trans('MailText'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltipfrombody');
1089 $out .= '</td>';
1090 $out .= '<td class="tdtop">';
1091
1092 $formmail = $this;
1093 $showlinktolayout = ($formmail->withfckeditor && getDolGlobalInt('MAIN_EMAIL_USE_LAYOUT')) ? $formmail->withlayout : '';
1094 $showlinktolayoutlabel = $langs->trans("FillMessageWithALayout");
1095 $showlinktoai = ($formmail->withaiprompt && isModEnabled('ai')) ? 'textgenerationemail' : '';
1096 $showlinktoailabel = $langs->trans("FillMessageWithAIContent");
1097 $formatforouput = '';
1098 $htmlname = 'message';
1099
1100 // Fill $out
1101 include DOL_DOCUMENT_ROOT.'/core/tpl/formlayoutai.tpl.php';
1102
1103 $out .= '</td>';
1104 $out .= '</tr>';
1105
1106 $out .= '<tr>';
1107 $out .= '<td colspan="2">';
1108 if ($this->withbodyreadonly) {
1109 $out .= nl2br($defaultmessage);
1110 $out .= '<input type="hidden" id="message" name="message" disabled value="'.$defaultmessage.'" />';
1111 } else {
1112 if (!isset($this->ckeditortoolbar)) {
1113 $this->ckeditortoolbar = 'dolibarr_mailings';
1114 }
1115
1116 // Editor wysiwyg
1117 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1118 if ($this->withfckeditor == -1) {
1119 if (getDolGlobalString('FCKEDITOR_ENABLE_MAIL')) {
1120 $this->withfckeditor = 1;
1121 } else {
1122 $this->withfckeditor = 0;
1123 }
1124 }
1125
1126 $doleditor = new DolEditor('message', $defaultmessage, '', 280, $this->ckeditortoolbar, 'In', true, true, $this->withfckeditor, 8, '95%');
1127 $out .= $doleditor->Create(1);
1128 }
1129 $out .= "</td></tr>\n";
1130 }
1131
1132 $out .= '</table>'."\n";
1133
1134 if ($this->withform == 1 || $this->withform == -1) {
1135 $out .= '<div class="center">';
1136 $out .= '<input type="submit" class="button button-add" id="sendmail" name="sendmail" value="'.$langs->trans("SendMail").'"';
1137 // Add a javascript test to avoid to forget to submit file before sending email
1138 if ($this->withfile == 2 && $conf->use_javascript_ajax) {
1139 $out .= ' onClick="if (document.mailform.addedfile.value != \'\') { alert(\''.dol_escape_js($langs->trans("FileWasNotUploaded")).'\'); return false; } else { return true; }"';
1140 }
1141 $out .= ' />';
1142 if ($this->withcancel) {
1143 $out .= '<input class="button button-cancel" type="submit" id="cancel" name="cancel" value="'.$langs->trans("Cancel").'" />';
1144 }
1145 $out .= '</div>'."\n";
1146 }
1147
1148 if ($this->withform == 1) {
1149 $out .= '</form>'."\n";
1150 }
1151
1152 // Disable enter key if option MAIN_MAILFORM_DISABLE_ENTERKEY is set
1153 if (getDolGlobalString('MAIN_MAILFORM_DISABLE_ENTERKEY')) {
1154 $out .= '<script nonce="'.getNonce().'" type="text/javascript">';
1155 $out .= 'jQuery(document).ready(function () {';
1156 $out .= ' $(document).on("keypress", \'#mailform\', function (e) { /* Note this is called at every key pressed ! */
1157 var code = e.keyCode || e.which;
1158 if (code == 13) {
1159 console.log("Enter was intercepted and blocked");
1160 e.preventDefault();
1161 return false;
1162 }
1163 });';
1164 $out .= ' })';
1165 $out .= '</script>';
1166 }
1167
1168 $out .= "<!-- End form mail -->\n";
1169
1170 return $out;
1171 }
1172 }
1173
1179 public function getHtmlForTo()
1180 {
1181 global $langs, $form;
1182 $out = '<tr><td class="fieldrequired">';
1183 if ($this->withtofree) {
1184 $out .= $form->textwithpicto($langs->trans("MailTo"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"));
1185 } else {
1186 $out .= $langs->trans("MailTo");
1187 }
1188 $out .= '</td><td>';
1189 if ($this->withtoreadonly) {
1190 if (!empty($this->toname) && !empty($this->tomail)) {
1191 $out .= '<input type="hidden" id="toname" name="toname" value="'.$this->toname.'" />';
1192 $out .= '<input type="hidden" id="tomail" name="tomail" value="'.$this->tomail.'" />';
1193 if ($this->totype == 'thirdparty') {
1194 $soc = new Societe($this->db);
1195 $soc->fetch($this->toid);
1196 $out .= $soc->getNomUrl(1);
1197 } elseif ($this->totype == 'contact') {
1198 $contact = new Contact($this->db);
1199 $contact->fetch($this->toid);
1200 $out .= $contact->getNomUrl(1);
1201 } else {
1202 $out .= $this->toname;
1203 }
1204 $out .= ' &lt;'.$this->tomail.'&gt;';
1205 if ($this->withtofree) {
1206 $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) : "").'" />';
1207 }
1208 } else {
1209 // Note withto may be a text like 'AllRecipientSelected'
1210 $out .= (!is_array($this->withto) && !is_numeric($this->withto)) ? $this->withto : "";
1211 }
1212 } else {
1213 // The free input of email
1214 if (!empty($this->withtofree)) {
1215 $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) : "")).'" />';
1216 }
1217 // The select combo
1218 if (!empty($this->withto) && is_array($this->withto)) {
1219 if (!empty($this->withtofree)) {
1220 $out .= " ".$langs->trans("and")."/".$langs->trans("or")." ";
1221 }
1222
1223 $tmparray = $this->withto;
1224 foreach ($tmparray as $key => $val) {
1225 if (is_array($val)) {
1226 $label = $val['label'];
1227 } else {
1228 $label = $val;
1229 }
1230
1231 $tmparray[$key] = array();
1232 $tmparray[$key]['id'] = $key;
1233
1234 $tmparray[$key]['label'] = $label;
1235 $tmparray[$key]['label'] = str_replace(array('<', '>'), array('(', ')'), $tmparray[$key]['label']);
1236 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
1237 $tmparray[$key]['label'] = dol_htmlentities($tmparray[$key]['label'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', true);
1238
1239 $tmparray[$key]['labelhtml'] = $label;
1240 $tmparray[$key]['labelhtml'] = str_replace(array('&lt;', '<', '&gt;', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $tmparray[$key]['labelhtml']);
1241 $tmparray[$key]['labelhtml'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('<span class="opacitymedium">(', ')</span>'), $tmparray[$key]['labelhtml']);
1242 }
1243
1244 $withtoselected = GETPOST("receiver", 'array'); // Array of selected value
1245 if (!getDolGlobalInt('MAIN_MAIL_NO_WITH_TO_SELECTED')) {
1246 if (empty($withtoselected) && count($tmparray) == 1 && GETPOST('action', 'aZ09') == 'presend') {
1247 $withtoselected = array_keys($tmparray);
1248 }
1249 }
1250
1251 $out .= $form->multiselectarray("receiver", $tmparray, $withtoselected, 0, 0, 'inline-block minwidth500', 0, 0);
1252 }
1253 }
1254 $out .= "</td></tr>\n";
1255 return $out;
1256 }
1257
1263 public function getHtmlForCc()
1264 {
1265 global $langs, $form;
1266 $out = '<tr><td>';
1267 $out .= $form->textwithpicto($langs->trans("MailCC"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"));
1268 $out .= '</td><td>';
1269 if ($this->withtoccreadonly) {
1270 $out .= (!is_array($this->withtocc) && !is_numeric($this->withtocc)) ? $this->withtocc : "";
1271 } else {
1272 $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 : '')).'" />';
1273 if (!empty($this->withtocc) && is_array($this->withtocc)) {
1274 $out .= " ".$langs->trans("and")."/".$langs->trans("or")." ";
1275
1276 $tmparray = $this->withtocc;
1277 foreach ($tmparray as $key => $val) {
1278 if (is_array($val)) {
1279 $label = $val['label'];
1280 } else {
1281 $label = $val;
1282 }
1283
1284 $tmparray[$key] = array();
1285 $tmparray[$key]['id'] = $key;
1286
1287 $tmparray[$key]['label'] = $label;
1288 $tmparray[$key]['label'] = str_replace(array('<', '>'), array('(', ')'), $tmparray[$key]['label']);
1289 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
1290 $tmparray[$key]['label'] = dol_htmlentities($tmparray[$key]['label'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', true);
1291
1292 $tmparray[$key]['labelhtml'] = $label;
1293 $tmparray[$key]['labelhtml'] = str_replace(array('&lt;', '<', '&gt;', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $tmparray[$key]['labelhtml']);
1294 $tmparray[$key]['labelhtml'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('<span class="opacitymedium">(', ')</span>'), $tmparray[$key]['labelhtml']);
1295 }
1296
1297 $withtoccselected = GETPOST("receivercc", 'array'); // Array of selected value
1298
1299 $out .= $form->multiselectarray("receivercc", $tmparray, $withtoccselected, 0, 0, 'inline-block minwidth500', 0, 0);
1300 }
1301 }
1302 $out .= "</td></tr>\n";
1303 return $out;
1304 }
1305
1312 public function getHtmlForWithCcc()
1313 {
1314 global $langs, $form;
1315
1316 $out = '<tr><td>';
1317 $out .= $form->textwithpicto($langs->trans("MailCCC"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"));
1318 $out .= '</td><td>';
1319 if (!empty($this->withtocccreadonly)) {
1320 $out .= (!is_array($this->withtoccc) && !is_numeric($this->withtoccc)) ? $this->withtoccc : "";
1321 } else {
1322 $out .= '<input class="minwidth200" id="sendtoccc" name="sendtoccc" value="'.(GETPOSTISSET("sendtoccc") ? GETPOST("sendtoccc", "alpha") : ((!is_array($this->withtoccc) && !is_numeric($this->withtoccc)) ? $this->withtoccc : '')).'" />';
1323 if (!empty($this->withtoccc) && is_array($this->withtoccc)) {
1324 $out .= " ".$langs->trans("and")."/".$langs->trans("or")." ";
1325
1326 $tmparray = $this->withtoccc;
1327 foreach ($tmparray as $key => $val) {
1328 if (is_array($val)) {
1329 $label = $val['label'];
1330 } else {
1331 $label = $val;
1332 }
1333 $tmparray[$key] = array();
1334 $tmparray[$key]['id'] = $key;
1335
1336 $tmparray[$key]['label'] = $label;
1337 $tmparray[$key]['label'] = str_replace(array('<', '>'), array('(', ')'), $tmparray[$key]['label']);
1338 // multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
1339 $tmparray[$key]['label'] = dol_htmlentities($tmparray[$key]['label'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', true);
1340
1341 $tmparray[$key]['labelhtml'] = $label;
1342 $tmparray[$key]['labelhtml'] = str_replace(array('&lt;', '<', '&gt;', '>'), array('__LTCHAR__', '__LTCHAR__', '__GTCHAR__', '__GTCHAR__'), $tmparray[$key]['labelhtml']);
1343 $tmparray[$key]['labelhtml'] = str_replace(array('__LTCHAR__', '__GTCHAR__'), array('<span class="opacitymedium">(', ')</span>'), $tmparray[$key]['labelhtml']);
1344 }
1345
1346 $withtocccselected = GETPOST("receiverccc", 'array'); // Array of selected value
1347
1348 $out .= $form->multiselectarray("receiverccc", $tmparray, $withtocccselected, 0, 0, 'inline-block minwidth500', 0, 0);
1349 }
1350 }
1351
1352 $showinfobcc = '';
1353 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_PROPOSAL_TO') && !empty($this->param['models']) && $this->param['models'] == 'propal_send') {
1354 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_PROPOSAL_TO');
1355 }
1356 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_ORDER_TO') && !empty($this->param['models']) && $this->param['models'] == 'order_send') {
1357 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_ORDER_TO');
1358 }
1359 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_INVOICE_TO') && !empty($this->param['models']) && $this->param['models'] == 'facture_send') {
1360 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_INVOICE_TO');
1361 }
1362 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_PROPOSAL_TO') && !empty($this->param['models']) && $this->param['models'] == 'supplier_proposal_send') {
1363 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_PROPOSAL_TO');
1364 }
1365 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_ORDER_TO') && !empty($this->param['models']) && $this->param['models'] == 'order_supplier_send') {
1366 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_ORDER_TO');
1367 }
1368 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_INVOICE_TO') && !empty($this->param['models']) && $this->param['models'] == 'invoice_supplier_send') {
1369 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SUPPLIER_INVOICE_TO');
1370 }
1371 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.
1372 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_PROJECT_TO');
1373 }
1374 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_SHIPMENT_TO') && !empty($this->param['models']) && $this->param['models'] == 'shipping_send') {
1375 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_SHIPMENT_TO');
1376 }
1377 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_RECEPTION_TO') && !empty($this->param['models']) && $this->param['models'] == 'reception_send') {
1378 $showinfobcc = getDolGlobalString('MAIN_MAIL_AUTOCOPY_RECEPTION_TO');
1379 }
1380 if ($showinfobcc) {
1381 $out .= ' + '.$showinfobcc;
1382 }
1383 $out .= "</td></tr>\n";
1384 return $out;
1385 }
1386
1392 public function getHtmlForWithErrorsTo()
1393 {
1394 global $langs;
1395
1396 //if (! $this->errorstomail) $this->errorstomail=$this->frommail;
1397 $errorstomail = getDolGlobalString('MAIN_MAIL_ERRORS_TO', (!empty($this->errorstomail) ? $this->errorstomail : ''));
1398 if ($this->witherrorstoreadonly) {
1399 $out = '<tr><td>'.$langs->trans("MailErrorsTo").'</td><td>';
1400 $out .= '<input type="hidden" id="errorstomail" name="errorstomail" value="'.$errorstomail.'" />';
1401 $out .= $errorstomail;
1402 $out .= "</td></tr>\n";
1403 } else {
1404 $out = '<tr><td>'.$langs->trans("MailErrorsTo").'</td><td>';
1405 $out .= '<input class="minwidth200" id="errorstomail" name="errorstomail" value="'.$errorstomail.'" />';
1406 $out .= "</td></tr>\n";
1407 }
1408 return $out;
1409 }
1410
1416 public function getHtmlForDeliveryreceipt()
1417 {
1418 global $langs;
1419
1420 $out = '<tr><td><label for="deliveryreceipt">'.$langs->trans("DeliveryReceipt").'</label></td><td>';
1421
1422 if (!empty($this->withdeliveryreceiptreadonly)) {
1423 $out .= yn($this->withdeliveryreceipt);
1424 } else {
1425 $defaultvaluefordeliveryreceipt = 0;
1426 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_PROPAL') && !empty($this->param['models']) && $this->param['models'] == 'propal_send') {
1427 $defaultvaluefordeliveryreceipt = 1;
1428 }
1429 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_SUPPLIER_PROPOSAL') && !empty($this->param['models']) && $this->param['models'] == 'supplier_proposal_send') {
1430 $defaultvaluefordeliveryreceipt = 1;
1431 }
1432 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_ORDER') && !empty($this->param['models']) && $this->param['models'] == 'order_send') {
1433 $defaultvaluefordeliveryreceipt = 1;
1434 }
1435 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_INVOICE') && !empty($this->param['models']) && $this->param['models'] == 'facture_send') {
1436 $defaultvaluefordeliveryreceipt = 1;
1437 }
1438 if (getDolGlobalString('MAIL_FORCE_DELIVERY_RECEIPT_SUPPLIER_ORDER') && !empty($this->param['models']) && $this->param['models'] == 'order_supplier_send') {
1439 $defaultvaluefordeliveryreceipt = 1;
1440 }
1441 //$out .= $form->selectyesno('deliveryreceipt', (GETPOSTISSET("deliveryreceipt") ? GETPOST("deliveryreceipt") : $defaultvaluefordeliveryreceipt), 1);
1442 $out .= '<input type="checkbox" id="deliveryreceipt" name="deliveryreceipt" value="1"'.((GETPOSTISSET("deliveryreceipt") ? GETPOST("deliveryreceipt") : $defaultvaluefordeliveryreceipt) ? ' checked="checked"' : '').'>';
1443 }
1444 $out .= "</td></tr>\n";
1445 return $out;
1446 }
1447
1455 public function getHtmlForTopic($arraydefaultmessage, $helpforsubstitution)
1456 {
1457 global $langs, $form;
1458
1459 $defaulttopic = GETPOST('subject', 'restricthtml');
1460
1461 if (!GETPOST('modelselected', 'alpha') || GETPOST('modelmailselected') != '-1') {
1462 if ($arraydefaultmessage && $arraydefaultmessage->topic) {
1463 $defaulttopic = $arraydefaultmessage->topic;
1464 } elseif (!is_numeric($this->withtopic)) {
1465 $defaulttopic = $this->withtopic;
1466 }
1467 }
1468
1469 $defaulttopic = make_substitutions($defaulttopic, $this->substit);
1470
1471 $out = '<tr>';
1472 $out .= '<td class="fieldrequired">';
1473 $out .= $form->textwithpicto($langs->trans('MailTopic'), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltipfromtopic');
1474 $out .= '</td>';
1475 $out .= '<td>';
1476 if ($this->withtopicreadonly) {
1477 $out .= $defaulttopic;
1478 $out .= '<input type="hidden" class="quatrevingtpercent" id="subject" name="subject" value="'.$defaulttopic.'" />';
1479 } else {
1480 $out .= '<input type="text" class="quatrevingtpercent" id="subject" name="subject" value="'.((GETPOSTISSET("subject") && !GETPOST('modelselected')) ? GETPOST("subject") : ($defaulttopic ? $defaulttopic : '')).'" />';
1481 }
1482 $out .= "</td></tr>\n";
1483 return $out;
1484 }
1485
1494 public function getSectionForAIPrompt($function = 'textgeneration', $format = '', $htmlContent = 'message')
1495 {
1496 global $langs;
1497
1498 $langs->load("other");
1499
1500 $htmlContent = preg_replace('/[^a-z0-9_]/', '', $htmlContent);
1501
1502 $out = '<div id="ai_input'.$htmlContent.'" class="hidden paddingtop paddingbottom">';
1503 $out .= '<input type="text" class="quatrevingtpercent" id="ai_instructions'.$htmlContent.'" name="instruction" placeholder="'.$langs->trans("EnterYourAIPromptHere").'..." />';
1504 $out .= '<input id="generate_button'.$htmlContent.'" type="button" class="button smallpaddingimp" value="'.$langs->trans('Generate').'"/>';
1505 $out .= '<div id="ai_status_message'.$htmlContent.'" class="fieldrequired hideobject marginrightonly margintoponly">';
1506 $out .= '<i class="fa fa-spinner fa-spin fa-2x fa-fw valignmiddle marginrightonly"></i>'.$langs->trans("AIProcessingPleaseWait", getDolGlobalString('AI_API_SERVICE', 'chatgpt'));
1507 $out .= '</div>';
1508
1509 if ($function == 'imagegeneration') {
1510 $out .= '<div id="ai_image_result" class="margintoponly"></div>'; // Div for displaying the generated image
1511 }
1512
1513 $out .= "</div>\n";
1514
1515 $out .= "<script type='text/javascript'>
1516 $(document).ready(function() {
1517 // for keydown
1518 $('#ai_instructions".$htmlContent."').keydown(function(event) {
1519 if (event.keyCode === 13) {
1520 event.preventDefault();
1521 $('#generate_button".$htmlContent."').click();
1522 }
1523 });
1524
1525 $('#generate_button".$htmlContent."').click(function() {
1526 console.log('We click on generate_button".$htmlContent." ai button');
1527
1528 var instructions = $('#ai_instructions".$htmlContent."').val();
1529 var timeoutfinished = 0;
1530 var apicallfinished = 0;
1531
1532 $('#ai_status_message".$htmlContent."').show();
1533 $('.icon-container .loader').show();
1534 setTimeout(function() {
1535 timeoutfinished = 1;
1536 if (apicallfinished) {
1537 $('#ai_status_message".$htmlContent."').hide();
1538 }
1539 }, 2000);
1540
1541 if ('".$function."' === 'imagegeneration') {
1542 // Handle image generation request
1543 $.ajax({
1544 url: '". DOL_URL_ROOT."/ai/ajax/generate_content.php?token=".currentToken()."',
1545 type: 'POST',
1546 contentType: 'application/json',
1547 data: JSON.stringify({
1548 'format': '".dol_escape_js($format)."', /* the format for output */
1549 'function': '".dol_escape_js($function)."', /* the AI feature to call */
1550 'instructions': instructions, /* the prompt string */
1551 }),
1552 success: function(response) {
1553 console.log('Received image URL: '+response);
1554 // Assuming response is the URL of the generated image
1555 var imageUrl = response;
1556 $('#ai_image_result').html('<img src=\"' + imageUrl + '\" alt=\"Generated Image\" />');
1557
1558 // Clear the input field
1559 $('#ai_instructions').val('');
1560
1561 apicallfinished = 1;
1562 if (timeoutfinished) {
1563 $('#ai_status_message').hide();
1564 }
1565 },
1566 error: function(xhr, status, error) {
1567 alert(error);
1568 console.error('error ajax', status, error);
1569 $('#ai_status_message').hide();
1570 }
1571 });
1572 } else {
1573
1574 // set editor in readonly
1575 if (CKEDITOR.instances.".$htmlContent.") {
1576 CKEDITOR.instances.".$htmlContent.".setReadOnly(1);
1577 }
1578
1579 $.ajax({
1580 url: '". DOL_URL_ROOT."/ai/ajax/generate_content.php?token=".currentToken()."',
1581 type: 'POST',
1582 contentType: 'application/json',
1583 data: JSON.stringify({
1584 'format': '".dol_escape_js($format)."', /* the format for output */
1585 'function': '".dol_escape_js($function)."', /* the AI feature to call */
1586 'instructions': instructions, /* the prompt string */
1587 }),
1588 success: function(response) {
1589 console.log('Add response into field \'#".$htmlContent."\': '+response);
1590
1591 jQuery('#".$htmlContent."').val(response); // If #htmlcontent is a input name or textarea
1592 jQuery('#".$htmlContent."').html(response); // If #htmlContent is a div
1593 //jQuery('#".$htmlContent."preview').val(response);
1594
1595 if (CKEDITOR.instances) {
1596 var editorInstance = CKEDITOR.instances.".$htmlContent.";
1597 if (editorInstance) {
1598 editorInstance.setReadOnly(0);
1599 editorInstance.setData(response);
1600 }
1601 //var editorInstancepreview = CKEDITOR.instances.".$htmlContent."preview;
1602 //if (editorInstancepreview) {
1603 // editorInstancepreview.setData(response);
1604 //}
1605 }
1606
1607 // remove readonly
1608 $('#ai_instructions".$htmlContent."').val('');
1609
1610 apicallfinished = 1;
1611 if (timeoutfinished) {
1612 $('#ai_status_message".$htmlContent."').hide();
1613 }
1614 },
1615 error: function(xhr, status, error) {
1616 alert(error);
1617 console.error('error ajax', status, error);
1618 $('#ai_status_message".$htmlContent."').hide();
1619 }
1620
1621 });
1622 });
1623 });
1624 </script>
1625 ";
1626 return $out;
1627 }
1628
1636 public function getModelEmailTemplate($htmlContent = 'message', $showlinktolayout = 'email')
1637 {
1638 global $websitepage, $langs;
1639
1640 require_once DOL_DOCUMENT_ROOT.'/core/lib/emaillayout.lib.php';
1641 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1642 require_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php';
1643
1644 // Fetch blogs
1645 $websitepage = new WebsitePage($this->db);
1646 $arrayofblogs = $websitepage->fetchAll('', 'DESC', 'date_creation', 0, 0, array('type_container' => 'blogpost'));
1647
1648 $out = '<div id="template-selector" class="email-layout-container hidden" style="display:none;">';
1649
1650 // Define list of email layouts to use
1651 $layouts = array(
1652 'empty' => 'empty',
1653 );
1654 // Search available layouts on disk
1655 $arrayoflayoutemplates = dol_dir_list(DOL_DOCUMENT_ROOT.'/install/doctemplates/maillayout/', 'files', 0, '\.html$');
1656 foreach ($arrayoflayoutemplates as $layouttemplatefile) {
1657 $layoutname = preg_replace('/\.html$/i', '', $layouttemplatefile['name']);
1658
1659 // Exclude some layouts for some use cases
1660 if ($layoutname == 'news' && !in_array($showlinktolayout, array('emailing', 'websitepage'))) {
1661 continue;
1662 }
1663 if ($layoutname == 'products' && !in_array($showlinktolayout, array('emailing', 'websitepage'))) {
1664 continue;
1665 }
1666
1667 $layouts[$layoutname] = ucfirst($layoutname);
1668 }
1669 //}
1670 // TODO Add a hook to allow to complete the list
1671
1672 foreach ($layouts as $layout => $templateFunction) {
1673 $contentHtml = getHtmlOfLayout($layout);
1674
1675 $out .= '<div class="template-option" data-template="'.$layout.'" data-content="'.htmlentities($contentHtml).'">';
1676 $out .= '<img class="maillayout" alt="'.$layout.'" src="'.DOL_URL_ROOT.'/theme/common/maillayout/'.$layout.'.png" />';
1677 $out .= '<span class="template-option-text">'.$langs->trans($templateFunction).'</span>';
1678 $out .= '</div>';
1679 }
1680 $out .= '</div>';
1681
1682 // Prepare the array for multiselect
1683 $blogArray = array();
1684 if (!empty($arrayofblogs)) {
1685 foreach ($arrayofblogs as $blog) {
1686 $blogArray[$blog->id] = substr(htmlentities($blog->title), 0, 30);
1687 }
1688 }
1689
1690 // Use the multiselect array function to create the dropdown
1691 $out .= '<div id="post-dropdown-container" class="email-layout-container hidden" style="display:none;">';
1692 $out .= '<label for="blogpost-select">Select Posts: </label>';
1693 $out .= self::multiselectarray('blogpost-select', $blogArray);
1694 $out .= '</div>';
1695
1696 $out .= '<script type="text/javascript">
1697 $(document).ready(function() {
1698 $(".template-option").click(function() {
1699 var template = $(this).data("template");
1700 var subject = jQuery("#subject").val();
1701 var fromtype = jQuery("#fromtype").val();
1702 var sendto = jQuery("#sendto").val();
1703 var sendtocc = jQuery("#sendtocc").val();
1704 var sendtoccc = jQuery("#sendtoccc").val();
1705
1706 console.log("We choose a layout for email template=" + template + ", subject="+subject);
1707
1708 console.log("We choose a layout for email template " + template);
1709
1710 $(".template-option").removeClass("selected");
1711 $(this).addClass("selected");
1712
1713 var subject = $("#sujet").val();
1714
1715 var contentHtml = $(this).data("content");
1716 contentHtml = contentHtml.replace(/__SUBJECT__/g, subject);
1717
1718 if (template === "news") {
1719 $("#post-dropdown-container").show();
1720 console.log("Displaying dropdown for news template");
1721 } else {
1722 $("#post-dropdown-container").hide();
1723
1724 var csrfToken = "' .newToken().'";
1725 $.ajax({
1726 type: "POST",
1727 url: "'.DOL_URL_ROOT.'/core/ajax/mailtemplate.php",
1728 data: {
1729 template: template,
1730 subject: subject,
1731 fromtype: fromtype,
1732 sendto: sendto,
1733 sendtocc: sendtocc,
1734 sendtoccc: sendtoccc,
1735 content: contentHtml,
1736 selectedPosts: "[]",
1737 token: csrfToken
1738 },
1739 success: function(response) {
1740 jQuery("#'.$htmlContent.'").val(response);
1741 var editorInstance = CKEDITOR.instances["'.$htmlContent.'"];
1742 if (editorInstance) {
1743 editorInstance.setData(response);
1744 }
1745 },
1746 error: function(xhr, status, error) {
1747 console.error("An error occurred: " + xhr.responseText);
1748 }
1749 });
1750 }
1751 });
1752
1753 $("#blogpost-select").change(function() {
1754 var selectedIds = $(this).val();
1755 var contentHtml = $(".template-option.selected").data("content");
1756
1757 updateSelectedPostsContent(contentHtml, selectedIds);
1758 });
1759
1760 function updateSelectedPostsContent(contentHtml, selectedIds) {
1761 var csrfToken = "' .newToken().'";
1762 $.ajax({
1763 type: "POST",
1764 url: "/core/ajax/getnews.php",
1765 data: {
1766 selectedIds: JSON.stringify(selectedIds),
1767 token : csrfToken
1768 },
1769 success: function(response) {
1770 var selectedPosts = JSON.parse(response);
1771 var subject = $("#sujet").val();
1772
1773 contentHtml = contentHtml.replace(/__SUBJECT__/g, subject);
1774
1775 $.ajax({
1776 type: "POST",
1777 url: "/core/ajax/mailtemplate.php",
1778 data: {
1779 content: contentHtml,
1780 selectedPosts: selectedIds.join(","),
1781 token: csrfToken
1782 },
1783 success: function(response) {
1784 jQuery("#'.$htmlContent.'").val(response);
1785 var editorInstance = CKEDITOR.instances["'.$htmlContent.'"];
1786 if (editorInstance) {
1787 editorInstance.setData(response);
1788 }
1789 },
1790 error: function(xhr, status, error) {
1791 console.error("An error occurred: " + xhr.responseText);
1792 }
1793 });
1794 },
1795 error: function(xhr, status, error) {
1796 console.error("An error occurred: " + xhr.responseText);
1797 }
1798 });
1799 }
1800 });
1801 </script>';
1802
1803 return $out;
1804 }
1805
1823 public function getEMailTemplate($dbs, $type_template, $user, $outputlangs, $id = 0, $active = 1, $label = '', $defaultfortype = -1)
1824 {
1825 global $conf;
1826
1827 if ($id == -2 && empty($label)) {
1828 $this->error = 'LabelIsMandatoryWhenIdIs-2or-3';
1829 return -1;
1830 }
1831
1832 $ret = new ModelMail($dbs);
1833
1834 $languagetosearch = (is_object($outputlangs) ? $outputlangs->defaultlang : '');
1835 // Define $languagetosearchmain to fall back on main language (for example to get 'es_ES' for 'es_MX')
1836 $tmparray = explode('_', $languagetosearch);
1837 $languagetosearchmain = $tmparray[0].'_'.strtoupper($tmparray[0]);
1838 if ($languagetosearchmain == $languagetosearch) {
1839 $languagetosearchmain = '';
1840 }
1841
1842 $sql = "SELECT rowid, entity, module, label, type_template, topic, email_from, joinfiles, content, content_lines, lang, email_from, email_to, email_tocc, email_tobcc";
1843 $sql .= " FROM ".$dbs->prefix().'c_email_templates';
1844 $sql .= " WHERE (type_template = '".$dbs->escape($type_template)."' OR type_template = 'all')";
1845 $sql .= " AND entity IN (".getEntity('c_email_templates').")";
1846 $sql .= " AND (private = 0 OR fk_user = ".((int) $user->id).")"; // Get all public or private owned
1847 if ($active >= 0) {
1848 $sql .= " AND active = ".((int) $active);
1849 }
1850 if ($defaultfortype >= 0) {
1851 $sql .= " AND defaultfortype = ".((int) $defaultfortype);
1852 }
1853 if ($label) {
1854 $sql .= " AND label = '".$dbs->escape($label)."'";
1855 }
1856 if (!($id > 0) && $languagetosearch) {
1857 $sql .= " AND (lang = '".$dbs->escape($languagetosearch)."'".($languagetosearchmain ? " OR lang = '".$dbs->escape($languagetosearchmain)."'" : "")." OR lang IS NULL OR lang = '')";
1858 }
1859 if ($id > 0) {
1860 $sql .= " AND rowid = ".(int) $id;
1861 }
1862 if ($id == -1) {
1863 $sql .= " AND position = 0";
1864 }
1865 $sql .= " AND entity IN(".getEntity('c_email_templates', 1).")";
1866 if ($languagetosearch) {
1867 $sql .= $dbs->order("position,lang,label", "ASC,DESC,ASC"); // We want line with lang set first, then with lang null or ''
1868 } else {
1869 $sql .= $dbs->order("position,lang,label", "ASC,ASC,ASC"); // If no language provided, we give priority to lang not defined
1870 }
1871 //$sql .= $dbs->plimit(1);
1872 //print $sql;
1873
1874 $resql = $dbs->query($sql);
1875 if (!$resql) {
1876 dol_print_error($dbs);
1877 return -1;
1878 }
1879
1880 // Get first found
1881 while (1) {
1882 $obj = $dbs->fetch_object($resql);
1883
1884 if ($obj) {
1885 // If template is for a module, check module is enabled; if not, take next template
1886 if ($obj->module) {
1887 $tempmodulekey = $obj->module;
1888 if (empty($conf->$tempmodulekey) || !isModEnabled($tempmodulekey)) {
1889 continue;
1890 }
1891 }
1892
1893 // If a record was found
1894 $ret->id = $obj->rowid;
1895 $ret->module = $obj->module;
1896 $ret->label = $obj->label;
1897 $ret->lang = $obj->lang;
1898 $ret->topic = $obj->topic;
1899 $ret->content = $obj->content;
1900 $ret->content_lines = $obj->content_lines;
1901 $ret->joinfiles = $obj->joinfiles;
1902 $ret->email_from = $obj->email_from;
1903
1904 break;
1905 } else {
1906 // If no record found
1907 if ($id == -2) {
1908 // Not found with the provided label
1909 return -1;
1910 } else {
1911 // If there is no template at all
1912 $defaultmessage = '';
1913
1914 if ($type_template == 'body') {
1915 // Special case to use this->withbody as content
1916 $defaultmessage = $this->withbody;
1917 } elseif ($type_template == 'facture_send') {
1918 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendInvoice");
1919 } elseif ($type_template == 'facture_relance') {
1920 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendInvoiceReminder");
1921 } elseif ($type_template == 'propal_send') {
1922 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendProposal");
1923 } elseif ($type_template == 'supplier_proposal_send') {
1924 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendSupplierProposal");
1925 } elseif ($type_template == 'order_send') {
1926 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendOrder");
1927 } elseif ($type_template == 'order_supplier_send') {
1928 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendSupplierOrder");
1929 } elseif ($type_template == 'invoice_supplier_send') {
1930 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendSupplierInvoice");
1931 } elseif ($type_template == 'shipping_send') {
1932 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendShipping");
1933 } elseif ($type_template == 'fichinter_send') {
1934 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendFichInter");
1935 } elseif ($type_template == 'actioncomm_send') {
1936 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendActionComm");
1937 } elseif (!empty($type_template)) {
1938 $defaultmessage = $outputlangs->transnoentities("PredefinedMailContentGeneric");
1939 }
1940
1941 $ret->label = 'default';
1942 $ret->lang = $outputlangs->defaultlang;
1943 $ret->topic = '';
1944 $ret->joinfiles = 1;
1945 $ret->content = $defaultmessage;
1946 $ret->content_lines = '';
1947
1948 break;
1949 }
1950 }
1951 }
1952
1953 $dbs->free($resql);
1954
1955 return $ret;
1956 }
1957
1967 public function isEMailTemplate($type_template, $user, $outputlangs)
1968 {
1969 $sql = "SELECT label, topic, content, lang";
1970 $sql .= " FROM ".$this->db->prefix().'c_email_templates';
1971 $sql .= " WHERE type_template='".$this->db->escape($type_template)."'";
1972 $sql .= " AND entity IN (".getEntity('c_email_templates').")";
1973 $sql .= " AND (fk_user is NULL or fk_user = 0 or fk_user = ".((int) $user->id).")";
1974 if (is_object($outputlangs)) {
1975 $sql .= " AND (lang = '".$this->db->escape($outputlangs->defaultlang)."' OR lang IS NULL OR lang = '')";
1976 }
1977 $sql .= $this->db->order("lang,label", "ASC");
1978 //print $sql;
1979
1980 $resql = $this->db->query($sql);
1981 if ($resql) {
1982 $num = $this->db->num_rows($resql);
1983 $this->db->free($resql);
1984 return $num;
1985 } else {
1986 $this->error = get_class($this).' '.__METHOD__.' ERROR:'.$this->db->lasterror();
1987 return -1;
1988 }
1989 }
1990
2001 public function fetchAllEMailTemplate($type_template, $user, $outputlangs, $active = 1)
2002 {
2003 global $db, $conf;
2004
2005 $sql = "SELECT rowid, module, label, topic, content, content_lines, lang, fk_user, private, position";
2006 $sql .= " FROM ".$this->db->prefix().'c_email_templates';
2007 $sql .= " WHERE type_template IN ('".$this->db->escape($type_template)."', 'all')";
2008 $sql .= " AND entity IN (".getEntity('c_email_templates').")";
2009 $sql .= " AND (private = 0 OR fk_user = ".((int) $user->id).")"; // See all public templates or templates I own.
2010 if ($active >= 0) {
2011 $sql .= " AND active = ".((int) $active);
2012 }
2013 //if (is_object($outputlangs)) $sql.= " AND (lang = '".$this->db->escape($outputlangs->defaultlang)."' OR lang IS NULL OR lang = '')"; // Return all languages
2014 $sql .= $this->db->order("position,lang,label", "ASC");
2015 //print $sql;
2016
2017 $resql = $this->db->query($sql);
2018 if ($resql) {
2019 $num = $this->db->num_rows($resql);
2020 $this->lines_model = array();
2021 while ($obj = $this->db->fetch_object($resql)) {
2022 // If template is for a module, check module is enabled.
2023 if ($obj->module) {
2024 $tempmodulekey = $obj->module;
2025 if (empty($conf->$tempmodulekey) || !isModEnabled($tempmodulekey)) {
2026 continue;
2027 }
2028 }
2029
2030 $line = new ModelMail($db);
2031 $line->id = $obj->rowid;
2032 $line->label = $obj->label;
2033 $line->lang = $obj->lang;
2034 $line->fk_user = $obj->fk_user;
2035 $line->private = $obj->private;
2036 $line->position = $obj->position;
2037 $line->topic = $obj->topic;
2038 $line->content = $obj->content;
2039 $line->content_lines = $obj->content_lines;
2040
2041 $this->lines_model[] = $line;
2042 }
2043 $this->db->free($resql);
2044 return $num;
2045 } else {
2046 $this->error = get_class($this).' '.__METHOD__.' ERROR:'.$this->db->lasterror();
2047 return -1;
2048 }
2049 }
2050
2051
2052
2061 public function setSubstitFromObject($object, $outputlangs)
2062 {
2063 global $extrafields;
2064
2065 $parameters = array();
2066 $tmparray = getCommonSubstitutionArray($outputlangs, 0, null, $object);
2067 complete_substitutions_array($tmparray, $outputlangs, null, $parameters);
2068
2069 $this->substit = $tmparray;
2070
2071 // Fill substit_lines with each object lines content
2072 if (is_array($object->lines)) {
2073 foreach ($object->lines as $line) {
2074 $substit_line = array(
2075 '__PRODUCT_REF__' => isset($line->product_ref) ? $line->product_ref : '',
2076 '__PRODUCT_LABEL__' => isset($line->product_label) ? $line->product_label : '',
2077 '__PRODUCT_DESCRIPTION__' => isset($line->product_desc) ? $line->product_desc : '',
2078 '__LABEL__' => isset($line->label) ? $line->label : '',
2079 '__DESCRIPTION__' => isset($line->desc) ? $line->desc : '',
2080 '__DATE_START_YMD__' => dol_print_date($line->date_start, 'day', false, $outputlangs),
2081 '__DATE_END_YMD__' => dol_print_date($line->date_end, 'day', false, $outputlangs),
2082 '__QUANTITY__' => $line->qty,
2083 '__SUBPRICE__' => price($line->subprice),
2084 '__AMOUNT__' => price($line->total_ttc),
2085 '__AMOUNT_EXCL_TAX__' => price($line->total_ht)
2086 );
2087
2088 // Create dynamic tags for __PRODUCT_EXTRAFIELD_FIELD__
2089 if (!empty($line->fk_product)) {
2090 if (!is_object($extrafields)) {
2091 $extrafields = new ExtraFields($this->db);
2092 }
2093 $product = new Product($this->db);
2094 $product->fetch($line->fk_product, '', '', 1);
2095 $product->fetch_optionals();
2096
2097 $extrafields->fetch_name_optionals_label($product->table_element, true);
2098
2099 if (!empty($extrafields->attributes[$product->table_element]['label']) && is_array($extrafields->attributes[$product->table_element]['label']) && count($extrafields->attributes[$product->table_element]['label']) > 0) {
2100 foreach ($extrafields->attributes[$product->table_element]['label'] as $key => $label) {
2101 $substit_line['__PRODUCT_EXTRAFIELD_'.strtoupper($key).'__'] = isset($product->array_options['options_'.$key]) ? $product->array_options['options_'.$key] : '';
2102 }
2103 }
2104 }
2105
2106 $this->substit_lines[$line->id] = $substit_line; // @phan-suppress-current-line PhanTypeMismatchProperty
2107 }
2108 }
2109 }
2110
2119 public static function getAvailableSubstitKey($mode = 'formemail', $object = null)
2120 {
2121 global $langs;
2122
2123 $tmparray = array();
2124 if ($mode == 'formemail' || $mode == 'formemailwithlines' || $mode == 'formemailforlines') {
2125 $parameters = array('mode' => $mode);
2126 $tmparray = getCommonSubstitutionArray($langs, 2, null, $object); // Note: On email templated edition, this is null because it is related to all type of objects
2127 complete_substitutions_array($tmparray, $langs, null, $parameters);
2128
2129 if ($mode == 'formwithlines') {
2130 $tmparray['__LINES__'] = '__LINES__'; // Will be set by the get_form function
2131 }
2132 if ($mode == 'formforlines') {
2133 $tmparray['__QUANTITY__'] = '__QUANTITY__'; // Will be set by the get_form function
2134 }
2135 }
2136
2137 if ($mode == 'emailing') {
2138 $parameters = array('mode' => $mode);
2139 $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
2140 complete_substitutions_array($tmparray, $langs, null, $parameters);
2141
2142 // For mass emailing, we have different keys specific to the data into tagerts list
2143 $tmparray['__ID__'] = 'IdRecord';
2144 $tmparray['__THIRDPARTY_CUSTOMER_CODE__'] = 'CustomerCode';
2145 $tmparray['__EMAIL__'] = 'EMailRecipient';
2146 $tmparray['__LASTNAME__'] = 'Lastname';
2147 $tmparray['__FIRSTNAME__'] = 'Firstname';
2148 $tmparray['__MAILTOEMAIL__'] = 'TagMailtoEmail';
2149 $tmparray['__OTHER1__'] = 'Other1';
2150 $tmparray['__OTHER2__'] = 'Other2';
2151 $tmparray['__OTHER3__'] = 'Other3';
2152 $tmparray['__OTHER4__'] = 'Other4';
2153 $tmparray['__OTHER5__'] = 'Other5';
2154 $tmparray['__CHECK_READ__'] = $langs->trans('TagCheckMail');
2155 $tmparray['__UNSUBSCRIBE__'] = $langs->trans('TagUnsubscribe');
2156 $tmparray['__UNSUBSCRIBE_URL__'] = $langs->trans('TagUnsubscribe').' (URL)';
2157
2158 $onlinepaymentenabled = 0;
2159 if (isModEnabled('paypal')) {
2160 $onlinepaymentenabled++;
2161 }
2162 if (isModEnabled('paybox')) {
2163 $onlinepaymentenabled++;
2164 }
2165 if (isModEnabled('stripe')) {
2166 $onlinepaymentenabled++;
2167 }
2168 if ($onlinepaymentenabled && getDolGlobalString('PAYMENT_SECURITY_TOKEN')) {
2169 $tmparray['__SECUREKEYPAYMENT__'] = getDolGlobalString('PAYMENT_SECURITY_TOKEN');
2170 if (getDolGlobalString('PAYMENT_SECURITY_TOKEN_UNIQUE')) {
2171 if (isModEnabled('member')) {
2172 $tmparray['__SECUREKEYPAYMENT_MEMBER__'] = 'SecureKeyPAYMENTUniquePerMember';
2173 }
2174 if (isModEnabled('don')) {
2175 $tmparray['__SECUREKEYPAYMENT_DONATION__'] = 'SecureKeyPAYMENTUniquePerDonation';
2176 }
2177 if (isModEnabled('invoice')) {
2178 $tmparray['__SECUREKEYPAYMENT_INVOICE__'] = 'SecureKeyPAYMENTUniquePerInvoice';
2179 }
2180 if (isModEnabled('order')) {
2181 $tmparray['__SECUREKEYPAYMENT_ORDER__'] = 'SecureKeyPAYMENTUniquePerOrder';
2182 }
2183 if (isModEnabled('contract')) {
2184 $tmparray['__SECUREKEYPAYMENT_CONTRACTLINE__'] = 'SecureKeyPAYMENTUniquePerContractLine';
2185 }
2186
2187 //Online payment link
2188 if (isModEnabled('member')) {
2189 $tmparray['__ONLINEPAYMENTLINK_MEMBER__'] = 'OnlinePaymentLinkUniquePerMember';
2190 }
2191 if (isModEnabled('don')) {
2192 $tmparray['__ONLINEPAYMENTLINK_DONATION__'] = 'OnlinePaymentLinkUniquePerDonation';
2193 }
2194 if (isModEnabled('invoice')) {
2195 $tmparray['__ONLINEPAYMENTLINK_INVOICE__'] = 'OnlinePaymentLinkUniquePerInvoice';
2196 }
2197 if (isModEnabled('order')) {
2198 $tmparray['__ONLINEPAYMENTLINK_ORDER__'] = 'OnlinePaymentLinkUniquePerOrder';
2199 }
2200 if (isModEnabled('contract')) {
2201 $tmparray['__ONLINEPAYMENTLINK_CONTRACTLINE__'] = 'OnlinePaymentLinkUniquePerContractLine';
2202 }
2203 }
2204 } else {
2205 /* No need to show into tooltip help, option is not enabled
2206 $vars['__SECUREKEYPAYMENT__']='';
2207 $vars['__SECUREKEYPAYMENT_MEMBER__']='';
2208 $vars['__SECUREKEYPAYMENT_INVOICE__']='';
2209 $vars['__SECUREKEYPAYMENT_ORDER__']='';
2210 $vars['__SECUREKEYPAYMENT_CONTRACTLINE__']='';
2211 */
2212 }
2213 if (getDolGlobalString('MEMBER_ENABLE_PUBLIC')) {
2214 $tmparray['__PUBLICLINK_NEWMEMBERFORM__'] = 'BlankSubscriptionForm';
2215 }
2216 }
2217
2218 foreach ($tmparray as $key => $val) {
2219 if (empty($val)) {
2220 $tmparray[$key] = $key;
2221 }
2222 }
2223
2224 return $tmparray;
2225 }
2226}
2227
2228
2229require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
2230
2236class ModelMail extends CommonObject
2237{
2241 public $element = 'email_template';
2242
2246 public $table_element = 'c_email_templates';
2247
2248
2249 // BEGIN MODULEBUILDER PROPERTIES
2253 public $fields = array(
2254 "rowid" => array("type" => "integer", "label" => "TechnicalID", "enabled" => "1", 'position' => 10, 'notnull' => 1, "visible" => "-1",),
2255 "module" => array("type" => "varchar(32)", "label" => "Module", "enabled" => "1", 'position' => 20, 'notnull' => 0, "visible" => "-1",),
2256 "type_template" => array("type" => "varchar(32)", "label" => "Typetemplate", "enabled" => "1", 'position' => 25, 'notnull' => 0, "visible" => "-1",),
2257 "lang" => array("type" => "varchar(6)", "label" => "Lang", "enabled" => "1", 'position' => 30, 'notnull' => 0, "visible" => "-1",),
2258 "private" => array("type" => "smallint(6)", "label" => "Private", "enabled" => "1", 'position' => 35, 'notnull' => 1, "visible" => "-1",),
2259 "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",),
2260 "datec" => array("type" => "datetime", "label" => "DateCreation", "enabled" => "1", 'position' => 45, 'notnull' => 0, "visible" => "-1",),
2261 "tms" => array("type" => "timestamp", "label" => "DateModification", "enabled" => "1", 'position' => 50, 'notnull' => 1, "visible" => "-1",),
2262 "label" => array("type" => "varchar(255)", "label" => "Label", "enabled" => "1", 'position' => 55, 'notnull' => 0, "visible" => "-1", "alwayseditable" => "1", "css" => "minwidth300", "cssview" => "wordbreak", "csslist" => "tdoverflowmax150",),
2263 "position" => array("type" => "smallint(6)", "label" => "Position", "enabled" => "1", 'position' => 60, 'notnull' => 0, "visible" => "-1", "alwayseditable" => "1",),
2264 "active" => array("type" => "integer", "label" => "Active", "enabled" => "1", 'position' => 65, 'notnull' => 1, "visible" => "-1", "alwayseditable" => "1",),
2265 "topic" => array("type" => "text", "label" => "Topic", "enabled" => "1", 'position' => 70, 'notnull' => 0, "visible" => "-1", "alwayseditable" => "1",),
2266 "content" => array("type" => "mediumtext", "label" => "Content", "enabled" => "1", 'position' => 75, 'notnull' => 0, "visible" => "-1", "alwayseditable" => "1",),
2267 "content_lines" => array("type" => "text", "label" => "Contentlines", "enabled" => "getDolGlobalString('MAIN_EMAIL_TEMPLATES_FOR_OBJECT_LINES')", 'position' => 80, 'notnull' => 0, "visible" => "-1", "alwayseditable" => "1",),
2268 "enabled" => array("type" => "varchar(255)", "label" => "Enabled", "enabled" => "1", 'position' => 85, 'notnull' => 0, "visible" => "-1", "alwayseditable" => "1",),
2269 "joinfiles" => array("type" => "varchar(255)", "label" => "Joinfiles", "enabled" => "1", 'position' => 90, 'notnull' => 0, "visible" => "-1", "alwayseditable" => "1",),
2270 "email_from" => array("type" => "varchar(255)", "label" => "Emailfrom", "enabled" => "1", 'position' => 95, 'notnull' => 0, "visible" => "-1", "alwayseditable" => "1",),
2271 "email_to" => array("type" => "varchar(255)", "label" => "Emailto", "enabled" => "1", 'position' => 100, 'notnull' => 0, "visible" => "-1", "alwayseditable" => "1",),
2272 "email_tocc" => array("type" => "varchar(255)", "label" => "Emailtocc", "enabled" => "1", 'position' => 105, 'notnull' => 0, "visible" => "-1", "alwayseditable" => "1",),
2273 "email_tobcc" => array("type" => "varchar(255)", "label" => "Emailtobcc", "enabled" => "1", 'position' => 110, 'notnull' => 0, "visible" => "-1", "alwayseditable" => "1",),
2274 "defaultfortype" => array("type" => "smallint(6)", "label" => "Defaultfortype", "enabled" => "1", 'position' => 115, 'notnull' => 0, "visible" => "-1", "alwayseditable" => "1",),
2275 );
2279 public $rowid;
2283 public $type_template;
2287 public $datec;
2291 public $tms;
2295 public $active;
2299 public $enabled;
2303 public $defaultfortype;
2304
2308 public $id;
2309
2313 public $label;
2314
2318 public $fk_user;
2319
2323 public $private;
2324
2328 public $topic;
2329
2333 public $content;
2337 public $content_lines;
2338
2342 public $lang;
2346 public $joinfiles;
2347
2351 public $email_from;
2355 public $email_to;
2359 public $email_tocc;
2363 public $email_tobcc;
2364
2368 public $module;
2369
2373 public $position;
2374 // END MODULEBUILDER PROPERTIES
2375
2376
2377
2383 public function __construct(DoliDB $db)
2384 {
2385 global $langs;
2386
2387 $this->db = $db;
2388 $this->ismultientitymanaged = 0;
2389 $this->isextrafieldmanaged = 1;
2390
2391 // @phan-suppress-next-line PhanTypeMismatchProperty
2392 if (!getDolGlobalInt('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid']) && !empty($this->fields['ref'])) {
2393 $this->fields['rowid']['visible'] = 0;
2394 }
2395 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
2396 $this->fields['entity']['enabled'] = 0;
2397 }
2398
2399 // Example to show how to set values of fields definition dynamically
2400 /*if ($user->hasRight('test', 'mailtemplate', 'read')) {
2401 $this->fields['myfield']['visible'] = 1;
2402 $this->fields['myfield']['noteditable'] = 0;
2403 }*/
2404
2405 // Unset fields that are disabled
2406 foreach ($this->fields as $key => $val) {
2407 if (isset($val['enabled']) && empty($val['enabled'])) {
2408 unset($this->fields[$key]);
2409 }
2410 }
2411
2412 // Translate some data of arrayofkeyval
2413 if (is_object($langs)) {
2414 foreach ($this->fields as $key => $val) {
2415 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
2416 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
2417 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
2418 }
2419 }
2420 }
2421 }
2422 }
2423
2424
2434 public function fetch($id, $ref = null, $noextrafields = 0, $nolines = 0)
2435 {
2436 $result = $this->fetchCommon($id, $ref, '', $noextrafields);
2437 if ($result > 0 && !empty($this->table_element_line) && empty($nolines)) {
2438 $this->fetchLines($noextrafields);
2439 }
2440 return $result;
2441 }
2442}
print $object position
Definition edit.php:195
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:162
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)
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.
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
$conf db user
Active Directory does not allow anonymous connections.
Definition repair.php:141
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:137
getMaxFileSizeArray()
Return the max allowed for file upload.