Passed
Pull Request — dev (#8)
by Rafael
58:47
created

Notify::create()   B

Complexity

Conditions 6
Paths 13

Size

Total Lines 40
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 26
nc 13
nop 2
dl 0
loc 40
rs 8.8817
c 0
b 0
f 0
1
<?php
2
3
/* Copyright (C) 2003-2005  Rodolphe Quiedeville        <[email protected]>
4
 * Copyright (C) 2004-2011  Laurent Destailleur         <[email protected]>
5
 * Copyright (C) 2014	    Juanjo Menent		        <[email protected]>
6
 * Copyright (C) 2018 	    Philippe Grand		        <[email protected]>
7
 * Copyright (C) 2021 	    Thibault FOUCART		    <[email protected]>
8
 * Copyright (C) 2022       Anthony Berton     	        <[email protected]>
9
 * Copyright (C) 2023       William Mead                <[email protected]>
10
 * Copyright (C) 2024       Jon Bendtsen                <[email protected]>
11
 * Copyright (C) 2024		MDW							<[email protected]>
12
 * Copyright (C) 2024       Rafael San José             <[email protected]>
13
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 3 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
26
 */
27
28
namespace Dolibarr\Code\Core\Classes;
29
30
use DoliDB;
31
32
/**
33
 *      \file       htdocs/core/class/notify.class.php
34
 *      \ingroup    notification
35
 *      \brief      File of class to manage notifications
36
 */
37
38
39
40
/**
41
 *      Class to manage the table of subscription to notifications
42
 */
43
class Notify
44
{
45
    /**
46
     * @var int ID
47
     */
48
    public $id;
49
50
    /**
51
     * @var DoliDB Database handler.
52
     */
53
    public $db;
54
55
    /**
56
     * @var string type
57
     */
58
    public $type;
59
60
    /**
61
     * @var string threshold
62
     */
63
    public $threshold;
64
65
    /**
66
     * @var string context
67
     */
68
    public $context;
69
70
71
    /**
72
     * @var int     ID of event action that trigger the notification
73
     */
74
    public $event;
75
76
    /**
77
     * @var int     Third-party ID
78
     */
79
    public $socid;
80
81
    /**
82
     * @var int     (Third-party) Contact ID
83
     */
84
    public $contact_id;
85
86
    /**
87
     * @var string fk_user
88
     */
89
    public $fk_user;
90
91
    /**
92
     * @var string email
93
     */
94
    public $email;
95
96
97
    /**
98
     * Date creation record (datec)
99
     *
100
     * @var integer
101
     */
102
    public $datec;
103
104
    /**
105
     * Date modified record (datem)
106
     *
107
     * @var integer
108
     */
109
    public $datem;
110
111
    /**
112
     * @var string Error code (or message)
113
     */
114
    public $error = '';
115
116
    /**
117
     * @var string[] Error codes (or messages)
118
     */
119
    public $errors = array();
120
121
    public $author;
122
    public $ref;
123
    public $date;
124
    public $duree;
125
    public $note;
126
127
    /**
128
     * @var int Project ID
129
     */
130
    public $fk_project;
131
132
    // This codes actions are defined into table llx_notify_def
133
    public static $arrayofnotifsupported = array(
134
        'BILL_CANCEL',
135
        'BILL_VALIDATE',
136
        'BILL_PAYED',
137
        'ORDER_CANCEL',
138
        'ORDER_CREATE',
139
        'ORDER_VALIDATE',
140
        'ORDER_CLOSE',
141
        'PROPAL_VALIDATE',
142
        'PROPAL_CLOSE_SIGNED',
143
        'PROPAL_CLOSE_REFUSED',
144
        'FICHINTER_VALIDATE',
145
        'FICHINTER_CLOSE',
146
        'FICHINTER_ADD_CONTACT',
147
        'ORDER_SUPPLIER_CANCEL',
148
        'ORDER_SUPPLIER_VALIDATE',
149
        'ORDER_SUPPLIER_APPROVE',
150
        'ORDER_SUPPLIER_SUBMIT',
151
        'ORDER_SUPPLIER_REFUSE',
152
        'SHIPPING_VALIDATE',
153
        'EXPENSE_REPORT_VALIDATE',
154
        'EXPENSE_REPORT_APPROVE',
155
        'HOLIDAY_VALIDATE',
156
        'HOLIDAY_APPROVE',
157
        'ACTION_CREATE'
158
    );
159
160
    /**
161
     *  Constructor
162
     *
163
     *  @param      DoliDB      $db     Database handler
164
     */
165
    public function __construct($db)
166
    {
167
        $this->db = $db;
168
    }
169
170
171
    /**
172
     *  Return message that say how many notification (and to which email) will occurs on requested event.
173
     *  This is to show confirmation messages before event is recorded.
174
     *
175
     *  @param  string  $action     Id of action in llx_c_action_trigger
176
     *  @param  int     $socid      Id of third party
177
     *  @param  Object  $object     Object the notification is about
178
     *  @return string              Message
179
     */
180
    public function confirmMessage($action, $socid, $object)
181
    {
182
        global $langs;
183
        $langs->load("mails");
184
185
        // Get full list of all notifications subscribed for $action, $socid and $object
186
        $listofnotiftodo = $this->getNotificationsArray($action, $socid, $object, 0);
187
188
        if (getDolGlobalString('NOTIFICATION_EMAIL_DISABLE_CONFIRM_MESSAGE_USER')) {
189
            foreach ($listofnotiftodo as $val) {
190
                if ($val['type'] == 'touser') {
191
                    unset($listofnotiftodo[$val['email']]);
192
                    //$listofnotiftodo = array_merge($listofnotiftodo);
193
                }
194
            }
195
        }
196
        if (getDolGlobalString('NOTIFICATION_EMAIL_DISABLE_CONFIRM_MESSAGE_CONTACT')) {
197
            foreach ($listofnotiftodo as $val) {
198
                if ($val['type'] == 'tocontact') {
199
                    unset($listofnotiftodo[$val['email']]);
200
                    //$listofnotiftodo = array_merge($listofnotiftodo);
201
                }
202
            }
203
        }
204
        if (getDolGlobalString('NOTIFICATION_EMAIL_DISABLE_CONFIRM_MESSAGE_FIX')) {
205
            foreach ($listofnotiftodo as $val) {
206
                if ($val['type'] == 'tofixedemail') {
207
                    unset($listofnotiftodo[$val['email']]);
208
                    //$listofnotiftodo = array_merge($listofnotiftodo);
209
                }
210
            }
211
        }
212
213
        $texte = '';
214
        $nb = -1;
215
        if (is_array($listofnotiftodo)) {
216
            $nb = count($listofnotiftodo);
217
        }
218
        if ($nb < 0) {
219
            $texte = img_object($langs->trans("Notifications"), 'email', 'class="pictofixedwidth"') . $langs->trans("ErrorFailedToGetListOfNotificationsToSend");
220
        } elseif ($nb == 0) {
221
            $texte = img_object($langs->trans("Notifications"), 'email', 'class="pictofixedwidth"') . $langs->trans("NoNotificationsWillBeSent");
222
        } elseif ($nb == 1) {
223
            $texte = img_object($langs->trans("Notifications"), 'email', 'class="pictofixedwidth"') . $langs->trans("ANotificationsWillBeSent");
224
        } else { // Always >= 2 if ($nb >= 2) {
225
            $texte = img_object($langs->trans("Notifications"), 'email', 'class="pictofixedwidth"') . $langs->trans("SomeNotificationsWillBeSent", $nb);
226
        }
227
228
        if (is_array($listofnotiftodo)) {
229
            $i = 0;
230
            foreach ($listofnotiftodo as $val) {
231
                if ($i) {
232
                    $texte .= ', ';
233
                } else {
234
                    $texte .= ' (';
235
                }
236
                if ($val['isemailvalid']) {
237
                    $texte .= $val['email'];
238
                } else {
239
                    $texte .= $val['emaildesc'];
240
                }
241
                $i++;
242
            }
243
            if ($i) {
244
                $texte .= ')';
245
            }
246
        }
247
248
        return $texte;
249
    }
250
251
    /**
252
     *  Delete a notification from database
253
     *
254
     *  @param      User|null   $user       User deleting
255
     *  @return     int                     Return integer <0 if KO, >0 if OK
256
     */
257
    public function delete(User $user = null)
258
    {
259
        $error = 0;
260
261
        dol_syslog(get_class($this) . "::delete " . $this->id, LOG_DEBUG);
262
263
        $this->db->begin();
264
265
        if (!$error) {
266
            $sql = "DELETE FROM " . MAIN_DB_PREFIX . "notify_def";
267
            $sql .= " WHERE rowid = " . ((int) $this->id);
268
269
            if (!$this->db->query($sql)) {
270
                $error++;
271
                $this->errors[] = $this->db->lasterror();
272
            }
273
        }
274
275
        if (!$error) {
276
            $this->db->commit();
277
            return 1;
278
        } else {
279
            $this->db->rollback();
280
            return -1 * $error;
281
        }
282
    }
283
284
    /**
285
     * Create notification information record.
286
     *
287
     * @param   User|null   $user       User
288
     * @param   int         $notrigger  1=Disable triggers
289
     * @return  int                     Return integer <0 if KO, > 0 if OK (ID of newly created company notification information)
290
     */
291
    public function create(User $user = null, $notrigger = 0)
292
    {
293
        $now = dol_now();
294
295
        $error = 0;
296
297
        // Check parameters
298
        if (empty($this->socid)) {
299
            $this->error = 'BadValueForParameter';
300
            $this->errors[] = $this->error;
301
            return -1;
302
        }
303
304
        if (empty($this->datec)) {
305
            $this->datec = $now;
306
        }
307
308
        $this->db->begin();
309
310
        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "notify_def (fk_soc, fk_action, fk_contact, type, datec)";
311
        $sql .= " VALUES (" . ((int) $this->socid) . ", " . ((int) $this->event) . ", " . ((int) $this->contact_id) . ",";
312
        $sql .= "'" . $this->db->escape($this->type) . "', '" . $this->db->idate($this->datec) . "')";
313
314
        $resql = $this->db->query($sql);
315
        if ($resql) {
316
            if ($this->db->affected_rows($resql)) {
317
                $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . "notify_def");
318
            }
319
        } else {
320
            $error++;
321
            $this->error = $this->db->lasterror();
322
            $this->errors[] = $this->error;
323
        }
324
325
        if (!$error) {
326
            $this->db->commit();
327
            return $this->id;
328
        } else {
329
            $this->db->rollback();
330
            return -1;
331
        }
332
    }
333
334
    /**
335
     *  Load record from database
336
     *
337
     *  @param  int     $id         Id of record
338
     *  @param  int     $socid      Id of company. If this is filled, function will return only records belonging to this thirdparty
339
     *  @param  string  $type       If id of company filled, we say if we want record of this type only
340
     *  @return int                 Return integer <0 if KO, >0 if OK
341
     */
342
    public function fetch($id, $socid = 0, $type = 'email')
343
    {
344
        if (empty($id) && empty($socid)) {
345
            return -1;
346
        }
347
348
        $sql = "SELECT rowid, fk_action as event, fk_soc as socid, fk_contact as contact_id, type, datec, tms as datem";
349
        $sql .= " FROM " . MAIN_DB_PREFIX . "notify_def";
350
351
        if ($id) {
352
            $sql .= " WHERE rowid = " . ((int) $id);
353
        } elseif ($socid > 0) {
354
            $sql .= " WHERE fk_soc  = " . ((int) $socid);
355
            if ($type) {
356
                $sql .= " AND type = '" . $this->db->escape($type) . "'";
357
            }
358
        }
359
360
        $resql = $this->db->query($sql);
361
        if ($resql) {
362
            if ($this->db->num_rows($resql)) {
363
                $obj = $this->db->fetch_object($resql);
364
365
                $this->id = $obj->rowid;
366
                $this->type = $obj->type;
367
                $this->event = $obj->event;
368
                $this->socid = $obj->socid;
369
                $this->contact_id = $obj->contact_id;
370
                $this->fk_user = $obj->fk_user;
371
                $this->email = $obj->email;
372
                $this->threshold = $obj->threshold;
373
                $this->context  = $obj->context;
374
                $this->datec = $this->db->jdate($obj->datec);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->db->jdate($obj->datec) can also be of type string. However, the property $datec is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
375
                $this->datem = $this->db->jdate($obj->datem);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->db->jdate($obj->datem) can also be of type string. However, the property $datem is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
376
            }
377
            $this->db->free($resql);
378
379
            return 1;
380
        } else {
381
            dol_print_error($this->db);
382
            return -1;
383
        }
384
    }
385
386
    /**
387
     *  Update record in database
388
     *
389
     *  @param  User|null   $user        Object user
390
     *  @param  int         $notrigger   1=Disable triggers
391
     *  @return int                      Return integer <=0 if KO, >0 if OK
392
     */
393
    public function update(User $user = null, $notrigger = -1)
394
    {
395
        global $langs;
396
397
        $error = 0;
398
399
        if (!$this->id) {
400
            return -1;
401
        }
402
403
        $this->db->begin();
404
405
        $sql = "UPDATE " . MAIN_DB_PREFIX . "notify_def SET";
406
        $sql .= " type = '" . $this->db->escape($this->type) . "'";
407
        // $sql .= ",fk_user = ".((int) $this->fk_user);
408
        // $sql .= ",email = '".$this->db->escape($this->email)."'";
409
        // $sql .= ",threshold = '".$this->db->escape($this->threshold)."'";
410
        // $sql .= ",context = '".$this->db->escape($this->context)."'";
411
        $sql .= ",fk_soc = " . ((int) $this->socid);
412
        $sql .= ",fk_action = " . ((int) $this->event);
413
        $sql .= ",fk_contact = " . ((int) $this->contact_id);
414
        $sql .= " WHERE rowid = " . ((int) $this->id);
415
416
        $result = $this->db->query($sql);
417
        if (!$result) {
418
            $error++;
419
            if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
420
                $this->error = $langs->trans('ErrorDuplicateField');
421
            } else {
422
                $this->error = $this->db->lasterror();
423
            }
424
            $this->errors[] = $this->error;
425
        }
426
427
        if (!$error) {
428
            $this->db->commit();
429
            return 1;
430
        } else {
431
            $this->db->rollback();
432
            return -1;
433
        }
434
    }
435
436
    /**
437
     * Return number of notifications activated, for all or a given action code (and third party)
438
     *
439
     * @param   string  $notifcode      Code of action in llx_c_action_trigger (new usage) or Id of action in llx_c_action_trigger (old usage)
440
     * @param   int     $socid          Id of third party or 0 for all thirdparties or -1 for no thirdparties
441
     * @param   Object  $object         Object the notification is about (need it to check threshold value of some notifications)
442
     * @param   int     $userid         Id of user or 0 for all users or -1 for no users
443
     * @param   array   $scope          Scope where to search
444
     * @return  array|int               Return integer <0 if KO, array of notifications to send if OK
445
     */
446
    public function getNotificationsArray($notifcode, $socid = 0, $object = null, $userid = 0, $scope = array('thirdparty', 'user', 'global'))
447
    {
448
        global $conf, $user;
449
450
        $error = 0;
451
        $resarray = array();
452
453
        $valueforthreshold = 0;
454
        if (is_object($object)) {
455
            $valueforthreshold = $object->total_ht;
456
        }
457
458
        $sqlnotifcode = '';
459
        if ($notifcode) {
460
            if (is_numeric($notifcode)) {
461
                $sqlnotifcode = " AND n.fk_action = " . ((int) $notifcode); // Old usage
462
            } else {
463
                $sqlnotifcode = " AND a.code = '" . $this->db->escape($notifcode) . "'"; // New usage
464
            }
465
        }
466
467
        // Subscription per contact
468
        if (!$error) {
469
            if ($socid >= 0 && in_array('thirdparty', $scope)) {
470
                $sql = "SELECT a.code, c.email, c.rowid, c.statut as status";
471
                $sql .= " FROM " . $this->db->prefix() . "notify_def as n,";
472
                $sql .= " " . $this->db->prefix() . "socpeople as c,";
473
474
                $sql .= " " . $this->db->prefix() . "c_action_trigger as a,";
475
                $sql .= " " . $this->db->prefix() . "societe as s";
476
                $sql .= " WHERE n.fk_contact = c.rowid";
477
                $sql .= " AND a.rowid = n.fk_action";
478
                $sql .= " AND n.fk_soc = s.rowid";
479
                $sql .= $sqlnotifcode;
480
                $sql .= " AND s.entity IN (" . getEntity('societe') . ")";
481
                if ($socid > 0) {
482
                    $sql .= " AND s.rowid = " . ((int) $socid);
483
                }
484
485
                dol_syslog(__METHOD__ . " " . $notifcode . ", " . $socid, LOG_DEBUG);
486
487
                $resql = $this->db->query($sql);
488
                if ($resql) {
489
                    $num = $this->db->num_rows($resql);
490
                    $i = 0;
491
                    while ($i < $num) {
492
                        $obj = $this->db->fetch_object($resql);
493
                        // we want to notify only if contact is enable
494
                        if ($obj && $obj->status ==  1) {
495
                            $newval2 = trim($obj->email);
496
                            $isvalid = isValidEmail($newval2);
497
                            if (empty($resarray[$newval2])) {
498
                                $resarray[$newval2] = array('type' => 'tocontact', 'code' => trim($obj->code), 'emaildesc' => 'Contact id ' . $obj->rowid, 'email' => $newval2, 'contactid' => $obj->rowid, 'isemailvalid' => $isvalid);
499
                            }
500
                        }
501
                        $i++;
502
                    }
503
                } else {
504
                    $error++;
505
                    $this->error = $this->db->lasterror();
506
                }
507
            }
508
        }
509
510
        // Subscription per user
511
        if (!$error) {
512
            if ($userid >= 0 && in_array('user', $scope)) {
513
                $sql = "SELECT a.code, c.email, c.rowid";
514
                $sql .= " FROM " . $this->db->prefix() . "notify_def as n,";
515
                $sql .= " " . $this->db->prefix() . "user as c,";
516
                $sql .= " " . $this->db->prefix() . "c_action_trigger as a";
517
                $sql .= " WHERE n.fk_user = c.rowid";
518
                $sql .= " AND a.rowid = n.fk_action";
519
                $sql .= $sqlnotifcode;
520
                $sql .= " AND c.entity IN (" . getEntity('user') . ")";
521
                if ($userid > 0) {
522
                    $sql .= " AND c.rowid = " . ((int) $userid);
523
                }
524
525
                dol_syslog(__METHOD__ . " " . $notifcode . ", " . $socid, LOG_DEBUG);
526
527
                $resql = $this->db->query($sql);
528
                if ($resql) {
529
                    $num = $this->db->num_rows($resql);
530
                    $i = 0;
531
                    while ($i < $num) {
532
                        $obj = $this->db->fetch_object($resql);
533
                        if ($obj) {
534
                            $newval2 = trim($obj->email);
535
                            $isvalid = isValidEmail($newval2);
536
                            if (empty($resarray[$newval2])) {
537
                                $resarray[$newval2] = array('type' => 'touser', 'code' => trim($obj->code), 'emaildesc' => 'User id ' . $obj->rowid, 'email' => $newval2, 'userid' => $obj->rowid, 'isemailvalid' => $isvalid);
538
                            }
539
                        }
540
                        $i++;
541
                    }
542
                } else {
543
                    $error++;
544
                    $this->error = $this->db->lasterror();
545
                }
546
            }
547
        }
548
549
        // Subscription global
550
        if (!$error) {
551
            if (in_array('global', $scope)) {
552
                // List of notifications enabled for fixed email
553
                foreach ($conf->global as $key => $val) {
554
                    if ($notifcode) {
555
                        if ($val == '' || !preg_match('/^NOTIFICATION_FIXEDEMAIL_' . $notifcode . '_THRESHOLD_HIGHER_(.*)$/', $key, $reg)) {
556
                            continue;
557
                        }
558
                    } else {
559
                        if ($val == '' || !preg_match('/^NOTIFICATION_FIXEDEMAIL_.*_THRESHOLD_HIGHER_(.*)$/', $key, $reg)) {
560
                            continue;
561
                        }
562
                    }
563
564
                    $threshold = (float) $reg[1];
565
                    if ($valueforthreshold < $threshold) {
566
                        continue;
567
                    }
568
569
                    $tmpemail = explode(',', $val);
570
                    foreach ($tmpemail as $key2 => $val2) {
571
                        $newval2 = trim($val2);
572
                        if ($newval2 == '__SUPERVISOREMAIL__') {
573
                            if ($user->fk_user > 0) {
574
                                $tmpuser = new User($this->db);
575
                                $tmpuser->fetch($user->fk_user);
576
                                if ($tmpuser->email) {
577
                                    $newval2 = trim($tmpuser->email);
578
                                } else {
579
                                    $newval2 = '';
580
                                }
581
                            } else {
582
                                $newval2 = '';
583
                            }
584
                        }
585
                        if ($newval2) {
586
                            $isvalid = isValidEmail($newval2, 0);
587
                            if (empty($resarray[$newval2])) {
588
                                $resarray[$newval2] = array('type' => 'tofixedemail', 'code' => trim($key), 'emaildesc' => trim($val2), 'email' => $newval2, 'isemailvalid' => $isvalid);
589
                            }
590
                        }
591
                    }
592
                }
593
            }
594
        }
595
596
        if ($error) {
597
            return -1;
598
        }
599
600
        //var_dump($resarray);
601
        return $resarray;
602
    }
603
604
    /**
605
     *  Check if notification are active for couple action/company.
606
     *  If yes, send mail and save trace into llx_notify.
607
     *
608
     *  @param  string  $notifcode          Code of action in llx_c_action_trigger (new usage) or Id of action in llx_c_action_trigger (old usage)
609
     *  @param  Object  $object             Object the notification deals on
610
     *  @param  array   $filename_list      List of files to attach (full path of filename on file system)
611
     *  @param  array   $mimetype_list      List of MIME type of attached files
612
     *  @param  array   $mimefilename_list  List of attached file name in message
613
     *  @return int                         Return integer <0 if KO, or number of changes if OK
614
     */
615
    public function send($notifcode, $object, $filename_list = array(), $mimetype_list = array(), $mimefilename_list = array())
616
    {
617
        global $user, $conf, $langs, $mysoc;
618
        global $hookmanager;
619
        global $dolibarr_main_url_root;
620
        global $action;
621
622
        // Complete the array Notify::$arrayofnotifsupported
623
        if (!is_object($hookmanager)) {
624
            $hookmanager = new HookManager($this->db);
625
        }
626
        $hookmanager->initHooks(array('notification'));
627
628
        $parameters = array('notifcode' => $notifcode);
629
        $reshook = $hookmanager->executeHooks('notifsupported', $parameters, $object, $action);
630
        if (empty($reshook)) {
631
            if (!empty($hookmanager->resArray['arrayofnotifsupported'])) {
632
                Notify::$arrayofnotifsupported = array_merge(Notify::$arrayofnotifsupported, $hookmanager->resArray['arrayofnotifsupported']);
633
            }
634
        }
635
636
        // If the trigger code is not managed by the Notification module
637
        if (!in_array($notifcode, Notify::$arrayofnotifsupported)) {
638
            return 0;
639
        }
640
641
        include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php';
642
643
        dol_syslog(get_class($this) . "::send notifcode=" . $notifcode . ", object id=" . $object->id);
644
645
        $langs->load("other");
646
647
        // Define $urlwithroot
648
        $urlwithouturlroot = preg_replace('/' . preg_quote(DOL_URL_ROOT, '/') . '$/i', '', trim($dolibarr_main_url_root));
649
        $urlwithroot = $urlwithouturlroot . DOL_URL_ROOT; // This is to use external domain name found into config file
650
        //$urlwithroot=DOL_MAIN_URL_ROOT;                       // This is to use same domain name than current
651
652
        // Define some vars
653
        $application = 'Dolibarr';
654
        if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
655
            $application = getDolGlobalString('MAIN_APPLICATION_TITLE');
656
        }
657
        $from = getDolGlobalString('NOTIFICATION_EMAIL_FROM');
658
        $object_type = '';
659
        $link = '';
660
        $num = 0;
661
        $error = 0;
662
663
        $oldref = (empty($object->oldref) ? $object->ref : $object->oldref);
664
        $newref = (empty($object->newref) ? $object->ref : $object->newref);
665
666
        $sql = '';
667
668
        // Check notification per third party
669
        if (!empty($object->socid) && $object->socid > 0) {
670
            $sql .= "SELECT 'tocontactid' as type_target, c.email, c.rowid as cid, c.lastname, c.firstname, c.default_lang,";
671
            $sql .= " a.rowid as adid, a.label, a.code, n.rowid, n.threshold, n.context, n.type";
672
            $sql .= " FROM " . $this->db->prefix() . "socpeople as c,";
673
            $sql .= " " . $this->db->prefix() . "c_action_trigger as a,";
674
            $sql .= " " . $this->db->prefix() . "notify_def as n,";
675
            $sql .= " " . $this->db->prefix() . "societe as s";
676
            $sql .= " WHERE n.fk_contact = c.rowid AND a.rowid = n.fk_action";
677
            $sql .= " AND n.fk_soc = s.rowid";
678
            $sql .= " AND c.statut = 1";
679
            if (is_numeric($notifcode)) {
680
                $sql .= " AND n.fk_action = " . ((int) $notifcode); // Old usage
681
            } else {
682
                $sql .= " AND a.code = '" . $this->db->escape($notifcode) . "'"; // New usage
683
            }
684
            $sql .= " AND s.rowid = " . ((int) $object->socid);
685
686
            $sql .= "\nUNION\n";
687
        }
688
689
        // Check notification per user
690
        $sql .= "SELECT 'touserid' as type_target, c.email, c.rowid as cid, c.lastname, c.firstname, c.lang as default_lang,";
691
        $sql .= " a.rowid as adid, a.label, a.code, n.rowid, n.threshold, n.context, n.type";
692
        $sql .= " FROM " . $this->db->prefix() . "user as c,";
693
        $sql .= " " . $this->db->prefix() . "c_action_trigger as a,";
694
        $sql .= " " . $this->db->prefix() . "notify_def as n";
695
        $sql .= " WHERE n.fk_user = c.rowid AND a.rowid = n.fk_action";
696
        $sql .= " AND c.statut = 1";
697
        if (is_numeric($notifcode)) {
698
            $sql .= " AND n.fk_action = " . ((int) $notifcode); // Old usage
699
        } else {
700
            $sql .= " AND a.code = '" . $this->db->escape($notifcode) . "'"; // New usage
701
        }
702
703
        // Check notification fixed
704
        // TODO Move part found after, into a sql here
705
706
707
        // Loop on all notifications enabled
708
        $result = $this->db->query($sql);
709
        if ($result) {
710
            $num = $this->db->num_rows($result);
711
            $projtitle = '';
712
            if (is_object($object->project) || $object->fetch_project() > 0) {
713
                $projtitle = '(' . $object->project->title . ')';
714
            }
715
716
            if ($num > 0) {
717
                $i = 0;
718
                while ($i < $num && !$error) {  // For each notification couple defined (third party/actioncode)
719
                    $obj = $this->db->fetch_object($result);
720
721
                    $sendto = dolGetFirstLastname($obj->firstname, $obj->lastname) . " <" . $obj->email . ">";
722
                    $notifcodedefid = $obj->adid;
723
                    $trackid = '';
724
                    if ($obj->type_target == 'tocontactid') {
725
                        $trackid = 'ctc' . $obj->cid;
726
                    }
727
                    if ($obj->type_target == 'touserid') {
728
                        $trackid = 'use' . $obj->cid;
729
                    }
730
731
                    if (dol_strlen($obj->email)) {
732
                        // Set output language
733
                        $outputlangs = $langs;
734
                        if ($obj->default_lang && $obj->default_lang != $langs->defaultlang) {
735
                            $outputlangs = new Translate('', $conf);
736
                            $outputlangs->setDefaultLang($obj->default_lang);
737
                            $outputlangs->loadLangs(array("main", "other"));
738
                        }
739
740
                        $appli = $mysoc->name;
741
742
                        $subject = '[' . $appli . '] ' . $outputlangs->transnoentitiesnoconv("DolibarrNotification") . ($projtitle ? ' ' . $projtitle : '');
743
744
                        switch ($notifcode) {
745
                            case 'BILL_CANCEL':
746
                                $link = '<a href="' . $urlwithroot . '/compta/facture/card.php?facid=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
747
                                $dir_output = $conf->facture->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'invoice');
748
                                $object_type = 'facture';
749
                                $mesg = $outputlangs->transnoentitiesnoconv("EMailTextInvoiceCanceled", $link);
750
                                break;
751
                            case 'BILL_VALIDATE':
752
                                $link = '<a href="' . $urlwithroot . '/compta/facture/card.php?facid=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
753
                                $dir_output = $conf->facture->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'invoice');
754
                                $object_type = 'facture';
755
                                $mesg = $outputlangs->transnoentitiesnoconv("EMailTextInvoiceValidated", $link);
756
                                break;
757
                            case 'BILL_PAYED':
758
                                $link = '<a href="' . $urlwithroot . '/compta/facture/card.php?facid=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
759
                                $dir_output = $conf->facture->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'invoice');
760
                                $object_type = 'facture';
761
                                $mesg = $outputlangs->transnoentitiesnoconv("EMailTextInvoicePayed", $link);
762
                                break;
763
                            case 'ORDER_CANCEL':
764
                                $link = '<a href="' . $urlwithroot . '/commande/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
765
                                $dir_output = $conf->commande->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'commande');
766
                                $object_type = 'order';
767
                                $mesg = $outputlangs->transnoentitiesnoconv("EMailTextOrderCanceled", $link);
768
                                break;
769
                            case 'ORDER_VALIDATE':
770
                                $link = '<a href="' . $urlwithroot . '/commande/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
771
                                $dir_output = $conf->commande->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'commande');
772
                                $object_type = 'order';
773
                                $mesg = $outputlangs->transnoentitiesnoconv("EMailTextOrderValidated", $link);
774
                                break;
775
                            case 'ORDER_CLOSE':
776
                                $link = '<a href="' . $urlwithroot . '/commande/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
777
                                $dir_output = $conf->commande->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'commande');
778
                                $object_type = 'order';
779
                                $labeltouse = getDolGlobalString('ORDER_CLOSE_TEMPLATE');
780
                                $mesg = $outputlangs->transnoentitiesnoconv("EMailTextOrderClose", $link);
781
                                break;
782
                            case 'PROPAL_VALIDATE':
783
                                $link = '<a href="' . $urlwithroot . '/comm/propal/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
784
                                $dir_output = $conf->propal->multidir_output[$object->entity] . "/" . get_exdir(0, 0, 0, 1, $object, 'propal');
785
                                $object_type = 'propal';
786
                                $mesg = $outputlangs->transnoentitiesnoconv("EMailTextProposalValidated", $link);
787
                                break;
788
                            case 'PROPAL_CLOSE_REFUSED':
789
                                $link = '<a href="' . $urlwithroot . '/comm/propal/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
790
                                $dir_output = $conf->propal->multidir_output[$object->entity] . "/" . get_exdir(0, 0, 0, 1, $object, 'propal');
791
                                $object_type = 'propal';
792
                                $labeltouse = getDolGlobalString('PROPAL_CLOSE_REFUSED_TEMPLATE');
793
                                $mesg = $outputlangs->transnoentitiesnoconv("EMailTextProposalClosedRefused", $link);
794
                                if (!empty($object->context['closedfromonlinesignature'])) {
795
                                    $mesg .= ' - From online page';
796
                                }
797
                                break;
798
                            case 'PROPAL_CLOSE_SIGNED':
799
                                $link = '<a href="' . $urlwithroot . '/comm/propal/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
800
                                $dir_output = $conf->propal->multidir_output[$object->entity] . "/" . get_exdir(0, 0, 0, 1, $object, 'propal');
801
                                $object_type = 'propal';
802
                                $mesg = $outputlangs->transnoentitiesnoconv("EMailTextProposalClosedSigned", $link);
803
                                if (!empty($object->context['closedfromonlinesignature'])) {
804
                                    $mesg .= ' - From online page';
805
                                }
806
                                break;
807
                            case 'FICHINTER_ADD_CONTACT':
808
                                $link = '<a href="' . $urlwithroot . '/fichinter/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
809
                                $dir_output = $conf->ficheinter->dir_output;
810
                                $object_type = 'ficheinter';
811
                                $mesg = $outputlangs->transnoentitiesnoconv("EMailTextInterventionAddedContact", $link);
812
                                break;
813
                            case 'FICHINTER_VALIDATE':
814
                                $link = '<a href="' . $urlwithroot . '/fichinter/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
815
                                $dir_output = $conf->ficheinter->dir_output;
816
                                $object_type = 'ficheinter';
817
                                $mesg = $outputlangs->transnoentitiesnoconv("EMailTextInterventionValidated", $link);
818
                                break;
819
                            case 'FICHINTER_CLOSE':
820
                                $link = '<a href="' . $urlwithroot . '/fichinter/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
821
                                $dir_output = $conf->ficheinter->dir_output;
822
                                $object_type = 'ficheinter';
823
                                $mesg = $outputlangs->transnoentitiesnoconv("EMailTextInterventionClosed", $link);
824
                                break;
825
                            case 'ORDER_SUPPLIER_VALIDATE':
826
                                $link = '<a href="' . $urlwithroot . '/fourn/commande/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
827
                                $dir_output = $conf->fournisseur->commande->multidir_output[$object->entity] . "/" . get_exdir(0, 0, 0, 1, $object);
828
                                $object_type = 'order_supplier';
829
                                $labeltouse = isset($conf->global->ORDER_SUPPLIER_VALIDATE_TEMPLATE) ? $conf->global->ORDER_SUPPLIER_VALIDATE_TEMPLATE : '';
830
                                $mesg = $outputlangs->transnoentitiesnoconv("Hello") . ",\n\n";
831
                                $mesg .= $outputlangs->transnoentitiesnoconv("EMailTextSupplierOrderValidatedBy", $link, $user->getFullName($outputlangs));
832
                                $mesg .= "\n\n" . $outputlangs->transnoentitiesnoconv("Sincerely") . ".\n\n";
833
                                break;
834
                            case 'ORDER_SUPPLIER_CANCEL':
835
                                $link = '<a href="' . $urlwithroot . '/fourn/commande/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
836
                                $dir_output = $conf->fournisseur->commande->multidir_output[$object->entity] . "/" . get_exdir(0, 0, 0, 1, $object);
837
                                $object_type = 'order_supplier';
838
                                $mesg = $outputlangs->transnoentitiesnoconv("Hello") . ",\n\n";
839
                                $mesg .= $outputlangs->transnoentitiesnoconv("EMailTextSupplierOrderCanceledBy", $link, $user->getFullName($outputlangs));
840
                                $mesg .= "\n\n" . $outputlangs->transnoentitiesnoconv("Sincerely") . ".\n\n";
841
                                break;
842
                            case 'ORDER_SUPPLIER_APPROVE':
843
                                $link = '<a href="' . $urlwithroot . '/fourn/commande/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
844
                                $dir_output = $conf->fournisseur->commande->multidir_output[$object->entity] . "/" . get_exdir(0, 0, 0, 1, $object);
845
                                $object_type = 'order_supplier';
846
                                $labeltouse = isset($conf->global->ORDER_SUPPLIER_APPROVE_TEMPLATE) ? $conf->global->ORDER_SUPPLIER_APPROVE_TEMPLATE : '';
847
                                $mesg = $outputlangs->transnoentitiesnoconv("Hello") . ",\n\n";
848
                                $mesg .= $outputlangs->transnoentitiesnoconv("EMailTextSupplierOrderApprovedBy", $link, $user->getFullName($outputlangs));
849
                                $mesg .= "\n\n" . $outputlangs->transnoentitiesnoconv("Sincerely") . ".\n\n";
850
                                break;
851
                            case 'ORDER_SUPPLIER_SUBMIT':
852
                                $link = '<a href="' . $urlwithroot . '/fourn/commande/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
853
                                $dir_output = $conf->fournisseur->commande->multidir_output[$object->entity] . "/" . get_exdir(0, 0, 0, 1, $object);
854
                                $object_type = 'order_supplier';
855
                                $mesg = $outputlangs->transnoentitiesnoconv("Hello") . ",\n\n";
856
                                $mesg .= $outputlangs->transnoentitiesnoconv("EMailTextSupplierOrderSubmittedBy", $link, $user->getFullName($outputlangs));
857
                                $mesg .= "\n\n" . $outputlangs->transnoentitiesnoconv("Sincerely") . ".\n\n";
858
                                break;
859
                            case 'ORDER_SUPPLIER_REFUSE':
860
                                $link = '<a href="' . $urlwithroot . '/fourn/commande/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
861
                                $dir_output = $conf->fournisseur->commande->multidir_output[$object->entity] . "/" . get_exdir(0, 0, 0, 1, $object);
862
                                $object_type = 'order_supplier';
863
                                $labeltouse = isset($conf->global->ORDER_SUPPLIER_REFUSE_TEMPLATE) ? $conf->global->ORDER_SUPPLIER_REFUSE_TEMPLATE : '';
864
                                $mesg = $outputlangs->transnoentitiesnoconv("Hello") . ",\n\n";
865
                                $mesg .= $outputlangs->transnoentitiesnoconv("EMailTextSupplierOrderRefusedBy", $link, $user->getFullName($outputlangs));
866
                                $mesg .= "\n\n" . $outputlangs->transnoentitiesnoconv("Sincerely") . ".\n\n";
867
                                break;
868
                            case 'SHIPPING_VALIDATE':
869
                                $link = '<a href="' . $urlwithroot . '/expedition/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
870
                                $dir_output = $conf->expedition->dir_output . "/sending/" . get_exdir(0, 0, 0, 1, $object, 'shipment');
871
                                $object_type = 'shipping';
872
                                $mesg = $outputlangs->transnoentitiesnoconv("EMailTextExpeditionValidated", $link);
873
                                break;
874
                            case 'EXPENSE_REPORT_VALIDATE':
875
                                $link = '<a href="' . $urlwithroot . '/expensereport/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
876
                                $dir_output = $conf->expensereport->dir_output;
877
                                $object_type = 'expensereport';
878
                                $mesg = $outputlangs->transnoentitiesnoconv("EMailTextExpenseReportValidated", $link);
879
                                break;
880
                            case 'EXPENSE_REPORT_APPROVE':
881
                                $link = '<a href="' . $urlwithroot . '/expensereport/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
882
                                $dir_output = $conf->expensereport->dir_output;
883
                                $object_type = 'expensereport';
884
                                $mesg = $outputlangs->transnoentitiesnoconv("EMailTextExpenseReportApproved", $link);
885
                                break;
886
                            case 'HOLIDAY_VALIDATE':
887
                                $link = '<a href="' . $urlwithroot . '/holiday/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
888
                                $dir_output = $conf->holiday->dir_output;
889
                                $object_type = 'holiday';
890
                                $mesg = $outputlangs->transnoentitiesnoconv("EMailTextHolidayValidated", $link);
891
                                break;
892
                            case 'HOLIDAY_APPROVE':
893
                                $link = '<a href="' . $urlwithroot . '/holiday/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
894
                                $dir_output = $conf->holiday->dir_output;
895
                                $object_type = 'holiday';
896
                                $mesg = $outputlangs->transnoentitiesnoconv("EMailTextHolidayApproved", $link);
897
                                break;
898
                            case 'ACTION_CREATE':
899
                                $link = '<a href="' . $urlwithroot . '/comm/action/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
900
                                $dir_output = $conf->agenda->dir_output;
901
                                $object_type = 'action';
902
                                $mesg = $outputlangs->transnoentitiesnoconv("EMailTextActionAdded", $link);
903
                                break;
904
                            default:
905
                                $object_type = $object->element;
906
                                $dir_output = $conf->$object_type->multidir_output[$object->entity ? $object->entity : $conf->entity] . "/" . get_exdir(0, 0, 0, 1, $object, $object_type);
907
                                $template = $notifcode . '_TEMPLATE';
908
                                $mesg = $outputlangs->transnoentitiesnoconv('Notify_' . $notifcode) . ' ' . $newref . ' ' . $dir_output;
909
                                break;
910
                        }
911
912
                        $formmail = new FormMail($this->db);
913
                        $arraydefaultmessage = null;
914
915
                        $template = $notifcode . '_TEMPLATE';
916
                        $labeltouse = getDolGlobalString($template);
917
                        if (!empty($labeltouse)) {
918
                            $arraydefaultmessage = $formmail->getEMailTemplate($this->db, $object_type . '_send', $user, $outputlangs, 0, 1, $labeltouse);
919
                        }
920
                        if (!empty($labeltouse) && is_object($arraydefaultmessage) && $arraydefaultmessage->id > 0) {
921
                            $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, null, $object);
922
                            complete_substitutions_array($substitutionarray, $outputlangs, $object);
923
                            $subject = make_substitutions($arraydefaultmessage->topic, $substitutionarray, $outputlangs);
924
                            $message = make_substitutions($arraydefaultmessage->content, $substitutionarray, $outputlangs);
925
                        } else {
926
                            $message = $outputlangs->transnoentities("YouReceiveMailBecauseOfNotification", $application, $mysoc->name) . "\n";
927
                            $message .= $outputlangs->transnoentities("YouReceiveMailBecauseOfNotification2", $application, $mysoc->name) . "\n";
928
                            $message .= "\n";
929
                            $message .= $mesg;
930
                        }
931
932
                        $ref = dol_sanitizeFileName($newref);
933
                        $pdf_path = $dir_output . "/" . $ref . ".pdf";
934
                        if (!dol_is_file($pdf_path) || (is_object($arraydefaultmessage) && $arraydefaultmessage->id > 0 && !$arraydefaultmessage->joinfiles)) {
935
                            // We can't add PDF as it is not generated yet.
936
                            $filepdf = '';
937
                        } else {
938
                            $filepdf = $pdf_path;
939
                            $filename_list[] = $filepdf;
940
                            $mimetype_list[] = mime_content_type($filepdf);
941
                            $mimefilename_list[] = $ref . ".pdf";
942
                        }
943
944
                        $labeltouse = !empty($labeltouse) ? $labeltouse : '';
945
946
                        // Replace keyword __SUPERVISOREMAIL__
947
                        if (preg_match('/__SUPERVISOREMAIL__/', $sendto)) {
948
                            $newval = '';
949
                            if ($user->fk_user > 0) {
950
                                $supervisoruser = new User($this->db);
951
                                $supervisoruser->fetch($user->fk_user);
952
                                if ($supervisoruser->email) {
953
                                    $newval = trim(dolGetFirstLastname($supervisoruser->firstname, $supervisoruser->lastname) . ' <' . $supervisoruser->email . '>');
954
                                }
955
                            }
956
                            dol_syslog("Replace the __SUPERVISOREMAIL__ key into recipient email string with " . $newval);
957
                            $sendto = preg_replace('/__SUPERVISOREMAIL__/', $newval, $sendto);
958
                            $sendto = preg_replace('/,\s*,/', ',', $sendto); // in some case you can have $sendto like "email, __SUPERVISOREMAIL__ , otheremail" then you have "email,  , othermail" and it's not valid
959
                            $sendto = preg_replace('/^[\s,]+/', '', $sendto); // Clean start of string
960
                            $sendto = preg_replace('/[\s,]+$/', '', $sendto); // Clean end of string
961
                        }
962
963
                        $parameters = array('notifcode' => $notifcode, 'sendto' => $sendto, 'from' => $from, 'file' => $filename_list, 'mimefile' => $mimetype_list, 'filename' => $mimefilename_list, 'outputlangs' => $outputlangs, 'labeltouse' => $labeltouse);
964
                        if (!isset($action)) {
965
                            $action = '';
966
                        }
967
968
                        $reshook = $hookmanager->executeHooks('formatNotificationMessage', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
969
                        if (empty($reshook)) {
970
                            if (!empty($hookmanager->resArray['files'])) {
971
                                $filename_list = $hookmanager->resArray['files']['file'];
972
                                $mimetype_list = $hookmanager->resArray['files']['mimefile'];
973
                                $mimefilename_list = $hookmanager->resArray['files']['filename'];
974
                            }
975
                            if (!empty($hookmanager->resArray['subject'])) {
976
                                $subject .= $hookmanager->resArray['subject'];
977
                            }
978
                            if (!empty($hookmanager->resArray['message'])) {
979
                                $message .= $hookmanager->resArray['message'];
980
                            }
981
                        }
982
983
                        $mailfile = new CMailFile(
984
                            $subject,
985
                            $sendto,
986
                            $from,
987
                            $message,
988
                            $filename_list,
989
                            $mimetype_list,
990
                            $mimefilename_list,
991
                            '',
992
                            '',
993
                            0,
994
                            -1,
995
                            '',
996
                            '',
997
                            $trackid,
998
                            '',
999
                            'notification'
1000
                        );
1001
1002
                        if ($mailfile->sendfile()) {
1003
                            if ($obj->type_target == 'touserid') {
1004
                                $sql = "INSERT INTO " . $this->db->prefix() . "notify (daten, fk_action, fk_soc, fk_user, type, objet_type, type_target, objet_id, email)";
1005
                                $sql .= " VALUES ('" . $this->db->idate(dol_now()) . "', " . ((int) $notifcodedefid) . ", " . ($object->socid > 0 ? ((int) $object->socid) : 'null') . ", " . ((int) $obj->cid) . ", '" . $this->db->escape($obj->type) . "', '" . $this->db->escape($object_type) . "', '" . $this->db->escape($obj->type_target) . "', " . ((int) $object->id) . ", '" . $this->db->escape($obj->email) . "')";
1006
                            } else {
1007
                                $sql = "INSERT INTO " . $this->db->prefix() . "notify (daten, fk_action, fk_soc, fk_contact, type, objet_type, type_target, objet_id, email)";
1008
                                $sql .= " VALUES ('" . $this->db->idate(dol_now()) . "', " . ((int) $notifcodedefid) . ", " . ($object->socid > 0 ? ((int) $object->socid) : 'null') . ", " . ((int) $obj->cid) . ", '" . $this->db->escape($obj->type) . "', '" . $this->db->escape($object_type) . "', '" . $this->db->escape($obj->type_target) . "', " . ((int) $object->id) . ", '" . $this->db->escape($obj->email) . "')";
1009
                            }
1010
                            if (!$this->db->query($sql)) {
1011
                                dol_print_error($this->db);
1012
                            }
1013
                        } else {
1014
                            $error++;
1015
                            $this->errors[] = $mailfile->error;
1016
                        }
1017
                    } else {
1018
                        dol_syslog("No notification sent for " . $sendto . " because email is empty");
1019
                    }
1020
                    $i++;
1021
                }
1022
            } else {
1023
                dol_syslog("No notification to thirdparty sent, nothing into notification setup for the thirdparty socid = " . (empty($object->socid) ? '' : $object->socid));
1024
            }
1025
        } else {
1026
            $error++;
1027
            $this->errors[] = $this->db->lasterror();
1028
            dol_syslog("Failed to get list of notification to send " . $this->db->lasterror(), LOG_ERR);
1029
            return -1;
1030
        }
1031
1032
        // Check notification using fixed email
1033
        // TODO Move vars NOTIFICATION_FIXEDEMAIL into table llx_notify_def and inclulde the case into previous loop of sql result
1034
        if (!$error) {
1035
            foreach ($conf->global as $key => $val) {
1036
                $reg = array();
1037
                if ($val == '' || !preg_match('/^NOTIFICATION_FIXEDEMAIL_' . $notifcode . '_THRESHOLD_HIGHER_(.*)$/', $key, $reg)) {
1038
                    continue;
1039
                }
1040
1041
                $sendto = $val;
1042
1043
                $threshold = (float) $reg[1];
1044
                if (!empty($object->total_ht) && $object->total_ht <= $threshold) {
1045
                    dol_syslog("A notification is requested for notifcode = " . $notifcode . " but amount = " . $object->total_ht . " so lower than threshold = " . $threshold . ". We discard this notification");
1046
                    continue;
1047
                }
1048
1049
                $notifcodedefid = dol_getIdFromCode($this->db, $notifcode, 'c_action_trigger', 'code', 'rowid');
1050
                if ($notifcodedefid <= 0) {
1051
                    dol_print_error($this->db, 'Failed to get id from code');
1052
                }
1053
                $trackid = '';
1054
1055
                $object_type = '';
1056
                $link = '';
1057
                $num++;
1058
1059
                $appli = $mysoc->name;
1060
1061
                $subject = '[' . $appli . '] ' . $langs->transnoentitiesnoconv("DolibarrNotification") . ($projtitle ? ' ' . $projtitle : '');
1062
1063
                switch ($notifcode) {
1064
                    case 'BILL_VALIDATE':
1065
                        $link = '<a href="' . $urlwithroot . '/compta/facture/card.php?facid=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1066
                        $dir_output = $conf->facture->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'invoice');
1067
                        $object_type = 'facture';
1068
                        $mesg = $langs->transnoentitiesnoconv("EMailTextInvoiceValidated", $link);
1069
                        break;
1070
                    case 'BILL_PAYED':
1071
                        $link = '<a href="' . $urlwithroot . '/compta/facture/card.php?facid=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1072
                        $dir_output = $conf->facture->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'invoice');
1073
                        $object_type = 'facture';
1074
                        $mesg = $langs->transnoentitiesnoconv("EMailTextInvoicePayed", $link);
1075
                        break;
1076
                    case 'ORDER_VALIDATE':
1077
                        $link = '<a href="' . $urlwithroot . '/commande/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1078
                        $dir_output = $conf->commande->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'commande');
1079
                        $object_type = 'order';
1080
                        $mesg = $langs->transnoentitiesnoconv("EMailTextOrderValidated", $link);
1081
                        break;
1082
                    case 'ORDER_CLOSE':
1083
                        $link = '<a href="' . $urlwithroot . '/commande/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1084
                        $dir_output = $conf->commande->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'commande');
1085
                        $object_type = 'order';
1086
                        $mesg = $langs->transnoentitiesnoconv("EMailTextOrderClose", $link);
1087
                        break;
1088
                    case 'PROPAL_VALIDATE':
1089
                        $link = '<a href="' . $urlwithroot . '/comm/propal/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1090
                        $dir_output = $conf->propal->multidir_output[$object->entity] . "/" . get_exdir(0, 0, 0, 1, $object, 'propal');
1091
                        $object_type = 'propal';
1092
                        $mesg = $langs->transnoentitiesnoconv("EMailTextProposalValidated", $link);
1093
                        break;
1094
                    case 'PROPAL_CLOSE_SIGNED':
1095
                        $link = '<a href="' . $urlwithroot . '/comm/propal/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1096
                        $dir_output = $conf->propal->multidir_output[$object->entity] . "/" . get_exdir(0, 0, 0, 1, $object, 'propal');
1097
                        $object_type = 'propal';
1098
                        $mesg = $langs->transnoentitiesnoconv("EMailTextProposalClosedSigned", $link);
1099
                        break;
1100
                    case 'FICHINTER_ADD_CONTACT':
1101
                        $link = '<a href="' . $urlwithroot . '/fichinter/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1102
                        $dir_output = $conf->ficheinter->dir_output;
1103
                        $object_type = 'ficheinter';
1104
                        $mesg = $langs->transnoentitiesnoconv("EMailTextInterventionAddedContact", $link);
1105
                        break;
1106
                    case 'FICHINTER_VALIDATE':
1107
                        $link = '<a href="' . $urlwithroot . '/fichinter/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1108
                        $dir_output = $conf->facture->dir_output;
1109
                        $object_type = 'ficheinter';
1110
                        $mesg = $langs->transnoentitiesnoconv("EMailTextInterventionValidated", $link);
1111
                        break;
1112
                    case 'FICHINTER_CLOSE':
1113
                        $link = '<a href="' . $urlwithroot . '/fichinter/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1114
                        $dir_output = $conf->facture->dir_output;
1115
                        $object_type = 'ficheinter';
1116
                        $mesg = $langs->transnoentitiesnoconv("EMailTextInterventionClosed", $link);
1117
                        break;
1118
                    case 'ORDER_SUPPLIER_CANCEL':
1119
                        $link = '<a href="' . $urlwithroot . '/fourn/commande/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1120
                        $dir_output = $conf->fournisseur->commande->multidir_output[$object->entity] . "/" . get_exdir(0, 0, 0, 1, $object);
1121
                        $object_type = 'order_supplier';
1122
                        $mesg = $langs->transnoentitiesnoconv("Hello") . ",\n\n";
1123
                        $mesg .= $langs->transnoentitiesnoconv("EMailTextSupplierOrderCanceledBy", $link, $user->getFullName($langs));
1124
                        $mesg .= "\n\n" . $langs->transnoentitiesnoconv("Sincerely") . ".\n\n";
1125
                        break;
1126
                    case 'ORDER_SUPPLIER_VALIDATE':
1127
                        $link = '<a href="' . $urlwithroot . '/fourn/commande/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1128
                        $dir_output = $conf->fournisseur->commande->multidir_output[$object->entity] . "/" . get_exdir(0, 0, 0, 1, $object);
1129
                        $object_type = 'order_supplier';
1130
                        $mesg = $langs->transnoentitiesnoconv("Hello") . ",\n\n";
1131
                        $mesg .= $langs->transnoentitiesnoconv("EMailTextSupplierOrderValidatedBy", $link, $user->getFullName($langs));
1132
                        $mesg .= "\n\n" . $langs->transnoentitiesnoconv("Sincerely") . ".\n\n";
1133
                        break;
1134
                    case 'ORDER_SUPPLIER_APPROVE':
1135
                        $link = '<a href="' . $urlwithroot . '/fourn/commande/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1136
                        $dir_output = $conf->fournisseur->commande->multidir_output[$object->entity] . "/" . get_exdir(0, 0, 0, 1, $object);
1137
                        $object_type = 'order_supplier';
1138
                        $mesg = $langs->transnoentitiesnoconv("Hello") . ",\n\n";
1139
                        $mesg .= $langs->transnoentitiesnoconv("EMailTextSupplierOrderApprovedBy", $link, $user->getFullName($langs));
1140
                        $mesg .= "\n\n" . $langs->transnoentitiesnoconv("Sincerely") . ".\n\n";
1141
                        break;
1142
                    case 'ORDER_SUPPLIER_SUBMIT':
1143
                        $link = '<a href="' . $urlwithroot . '/fourn/commande/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1144
                        $dir_output = $conf->fournisseur->commande->multidir_output[$object->entity] . "/" . get_exdir(0, 0, 0, 1, $object);
1145
                        $object_type = 'order_supplier';
1146
                        $mesg = $langs->transnoentitiesnoconv("Hello") . ",\n\n";
1147
                        $mesg .= $langs->transnoentitiesnoconv("EMailTextSupplierOrderSubmittedBy", $link, $user->getFullName($langs));
1148
                        $mesg .= "\n\n" . $langs->transnoentitiesnoconv("Sincerely") . ".\n\n";
1149
                        break;
1150
                    case 'ORDER_SUPPLIER_REFUSE':
1151
                        $link = '<a href="' . $urlwithroot . '/fourn/commande/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1152
                        $dir_output = $conf->fournisseur->commande->multidir_output[$object->entity] . "/" . get_exdir(0, 0, 0, 1, $object);
1153
                        $object_type = 'order_supplier';
1154
                        $mesg = $langs->transnoentitiesnoconv("Hello") . ",\n\n";
1155
                        $mesg .= $langs->transnoentitiesnoconv("EMailTextSupplierOrderRefusedBy", $link, $user->getFullName($langs));
1156
                        $mesg .= "\n\n" . $langs->transnoentitiesnoconv("Sincerely") . ".\n\n";
1157
                        break;
1158
                    case 'SHIPPING_VALIDATE':
1159
                        $link = '<a href="' . $urlwithroot . '/expedition/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1160
                        $dir_output = $conf->expedition->dir_output . "/sending/" . get_exdir(0, 0, 0, 1, $object, 'shipment');
1161
                        $object_type = 'order_supplier';
1162
                        $mesg = $langs->transnoentitiesnoconv("EMailTextExpeditionValidated", $link);
1163
                        break;
1164
                    case 'EXPENSE_REPORT_VALIDATE':
1165
                        $link = '<a href="' . $urlwithroot . '/expensereport/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1166
                        $dir_output = $conf->expensereport->dir_output;
1167
                        $object_type = 'expensereport';
1168
                        $mesg = $langs->transnoentitiesnoconv("EMailTextExpenseReportValidated", $link);
1169
                        break;
1170
                    case 'EXPENSE_REPORT_APPROVE':
1171
                        $link = '<a href="' . $urlwithroot . '/expensereport/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1172
                        $dir_output = $conf->expensereport->dir_output;
1173
                        $object_type = 'expensereport';
1174
                        $mesg = $langs->transnoentitiesnoconv("EMailTextExpenseReportApproved", $link);
1175
                        break;
1176
                    case 'HOLIDAY_VALIDATE':
1177
                        $link = '<a href="' . $urlwithroot . '/holiday/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1178
                        $dir_output = $conf->holiday->dir_output;
1179
                        $object_type = 'holiday';
1180
                        $mesg = $langs->transnoentitiesnoconv("EMailTextHolidayValidated", $link);
1181
                        break;
1182
                    case 'HOLIDAY_APPROVE':
1183
                        $link = '<a href="' . $urlwithroot . '/holiday/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1184
                        $dir_output = $conf->holiday->dir_output;
1185
                        $object_type = 'holiday';
1186
                        $mesg = $langs->transnoentitiesnoconv("EMailTextHolidayApproved", $link);
1187
                        break;
1188
                    case 'ACTION_CREATE':
1189
                        $link = '<a href="' . $urlwithroot . '/comm/action/card.php?id=' . $object->id . '&entity=' . $object->entity . '">' . $newref . '</a>';
1190
                        $dir_output = $conf->agenda->dir_output;
1191
                        $object_type = 'action';
1192
                        $mesg = $langs->transnoentitiesnoconv("EMailTextActionAdded", $link);
1193
                        break;
1194
                    default:
1195
                        $object_type = $object->element;
1196
                        $dir_output = $conf->$object_type->multidir_output[$object->entity ? $object->entity : $conf->entity] . "/" . get_exdir(0, 0, 0, 1, $object, $object_type);
1197
                        $mesg = $langs->transnoentitiesnoconv('Notify_' . $notifcode) . ' ' . $newref;
1198
                        break;
1199
                }
1200
                $ref = dol_sanitizeFileName($newref);
1201
                $pdf_path = $dir_output . "/" . $ref . "/" . $ref . ".pdf";
1202
                if (!dol_is_file($pdf_path)) {
1203
                    // We can't add PDF as it is not generated yet.
1204
                    $filepdf = '';
1205
                } else {
1206
                    $filepdf = $pdf_path;
1207
                    $filename_list[] = $pdf_path;
1208
                    $mimetype_list[] = mime_content_type($filepdf);
1209
                    $mimefilename_list[] = $ref . ".pdf";
1210
                }
1211
1212
                // Set output language
1213
                $outputlangs = $langs;
1214
1215
                // if an e-mail template is configured for this notification code (for instance 'SHIPPING_VALIDATE_TEMPLATE', ...),
1216
                // we fetch this template by its label. Otherwise, a default message content will be sent.
1217
                $mailTemplateLabel = getDolGlobalString($notifcode . '_TEMPLATE');
1218
                $emailTemplate = null;
1219
                if (!empty($mailTemplateLabel)) {
1220
                    $formmail = new FormMail($this->db);
1221
                    $emailTemplate = $formmail->getEMailTemplate($this->db, $object_type . '_send', $user, $outputlangs, 0, 1, $mailTemplateLabel);
1222
                }
1223
                if (!empty($mailTemplateLabel) && is_object($emailTemplate) && $emailTemplate->id > 0) {
1224
                    if (property_exists($object, 'thirdparty') && $object->thirdparty instanceof Societe && $object->thirdparty->default_lang && $object->thirdparty->default_lang != $langs->defaultlang) {
1225
                        $outputlangs = new Translate('', $conf);
1226
                        $outputlangs->setDefaultLang($object->thirdparty->default_lang);
1227
                        $outputlangs->loadLangs(array('main', 'other'));
1228
                    }
1229
                    $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, null, $object);
1230
                    complete_substitutions_array($substitutionarray, $outputlangs, $object);
1231
                    $subject = make_substitutions($emailTemplate->topic, $substitutionarray, $outputlangs);
1232
                    $message = make_substitutions($emailTemplate->content, $substitutionarray, $outputlangs);
1233
                } else {
1234
                    $message = '';
1235
                    $message .= $outputlangs->transnoentities("YouReceiveMailBecauseOfNotification2", $application, $mysoc->name) . "\n";
1236
                    $message .= "\n";
1237
                    $message .= $mesg;
1238
1239
                    $message = nl2br($message);
1240
                }
1241
1242
                // Replace keyword __SUPERVISOREMAIL__
1243
                if (preg_match('/__SUPERVISOREMAIL__/', $sendto)) {
1244
                    $newval = '';
1245
                    if ($user->fk_user > 0) {
1246
                        $supervisoruser = new User($this->db);
1247
                        $supervisoruser->fetch($user->fk_user);
1248
                        if ($supervisoruser->email) {
1249
                            $newval = trim(dolGetFirstLastname($supervisoruser->firstname, $supervisoruser->lastname) . ' <' . $supervisoruser->email . '>');
1250
                        }
1251
                    }
1252
                    dol_syslog("Replace the __SUPERVISOREMAIL__ key into recipient email string with " . $newval);
1253
                    $sendto = preg_replace('/__SUPERVISOREMAIL__/', $newval, $sendto);
1254
                    $sendto = preg_replace('/,\s*,/', ',', $sendto); // in some case you can have $sendto like "email, __SUPERVISOREMAIL__ , otheremail" then you have "email,  , othermail" and it's not valid
1255
                    $sendto = preg_replace('/^[\s,]+/', '', $sendto); // Clean start of string
1256
                    $sendto = preg_replace('/[\s,]+$/', '', $sendto); // Clean end of string
1257
                }
1258
1259
                if ($sendto) {
1260
                    $parameters = array('notifcode' => $notifcode, 'sendto' => $sendto, 'from' => $from, 'file' => $filename_list, 'mimefile' => $mimetype_list, 'filename' => $mimefilename_list, 'subject' => &$subject, 'message' => &$message);
1261
                    $reshook = $hookmanager->executeHooks('formatNotificationMessage', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
1262
                    if (empty($reshook)) {
1263
                        if (!empty($hookmanager->resArray['files'])) {
1264
                            $filename_list = $hookmanager->resArray['files']['file'];
1265
                            $mimetype_list = $hookmanager->resArray['files']['mimefile'];
1266
                            $mimefilename_list = $hookmanager->resArray['files']['filename'];
1267
                        }
1268
                        if (!empty($hookmanager->resArray['subject'])) {
1269
                            $subject .= $hookmanager->resArray['subject'];
1270
                        }
1271
                        if (!empty($hookmanager->resArray['message'])) {
1272
                            $message .= $hookmanager->resArray['message'];
1273
                        }
1274
                    }
1275
                    $mailfile = new CMailFile(
1276
                        $subject,
1277
                        $sendto,
1278
                        $from,
1279
                        $message,
1280
                        $filename_list,
1281
                        $mimetype_list,
1282
                        $mimefilename_list,
1283
                        '',
1284
                        '',
1285
                        0,
1286
                        1,
1287
                        '',
1288
                        $trackid,
1289
                        '',
1290
                        '',
1291
                        'notification'
1292
                    );
1293
1294
                    if ($mailfile->sendfile()) {
1295
                        $sql = "INSERT INTO " . $this->db->prefix() . "notify (daten, fk_action, fk_soc, fk_contact, type, type_target, objet_type, objet_id, email)";
1296
                        $sql .= " VALUES ('" . $this->db->idate(dol_now()) . "', " . ((int) $notifcodedefid) . ", " . ($object->socid > 0 ? ((int) $object->socid) : 'null') . ", null, 'email', 'tofixedemail', '" . $this->db->escape($object_type) . "', " . ((int) $object->id) . ", '" . $this->db->escape($sendto) . "')";
1297
                        if (!$this->db->query($sql)) {
1298
                            dol_print_error($this->db);
1299
                        }
1300
                    } else {
1301
                        $error++;
1302
                        $this->errors[] = $mailfile->error;
1303
                    }
1304
                }
1305
            }
1306
        }
1307
1308
        if (!$error) {
1309
            return $num;
1310
        } else {
1311
            return -1 * $error;
1312
        }
1313
    }
1314
}
1315