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